Skip to content

fix: strip trailing blanks at printAbove consumer (#194)#195

Merged
xinhuagu merged 1 commit into
mainfrom
fix/issue-194-printabove-trailing-blanks
Mar 9, 2026
Merged

fix: strip trailing blanks at printAbove consumer (#194)#195
xinhuagu merged 1 commit into
mainfrom
fix/issue-194-printabove-trailing-blanks

Conversation

@xinhuagu

@xinhuagu xinhuagu commented Mar 9, 2026

Copy link
Copy Markdown
Owner

Summary

  • Adds text.stripTrailing() at the pendingPrintAbove consumer loop before split("\n", -1)
  • This eliminates trailing blank lines that appear after cron/deferred/background-task output

Why PR #186 wasn't enough

PR #186 added stripTrailing() at each producer site, but:

  1. split("\n", -1) preserves trailing empty strings from any residual \n
  2. Each empty string becomes a printAbove("") → visible blank line
  3. Relying on every producer to strip is fragile — one miss and blanks return

The correct fix is a single defensive strip at the consumer boundary.

Change

// Before
String[] lines = text.split("\n", -1);

// After  
String[] lines = text.stripTrailing().split("\n", -1);

One line, covers all producers.

Closes #194

Summary by CodeRabbit

  • Bug Fixes
    • Fixed unnecessary blank lines appearing above the prompt in terminal output, resulting in cleaner and more polished display.

…lines (#194)

Producer-side stripTrailing() (PR #186) was insufficient — split("\n", -1)
still produces empty entries from any residual trailing newline. Move the
strip to the consumer boundary so all producers are covered defensively.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@qodo-code-review

Copy link
Copy Markdown

Review Summary by Qodo

Move stripTrailing to printAbove consumer for robust blank line removal

🐞 Bug fix

Grey Divider

Walkthroughs

Description
• Move stripTrailing() from producers to consumer boundary
• Eliminates trailing blank lines in printAbove output
• Defensive fix covers all producers with single change
• Simplifies maintenance by centralizing strip logic
Diagram
flowchart LR
  A["Multiple Producers<br/>cron/deferred/background"] -->|"text with trailing newlines"| B["pendingPrintAbove<br/>Consumer Loop"]
  B -->|"stripTrailing()<br/>before split"| C["Split into lines"]
  C -->|"clean lines"| D["printAbove calls"]
Loading

Grey Divider

File Changes

1. aceclaw-cli/src/main/java/dev/aceclaw/cli/TerminalRepl.java 🐞 Bug fix +3/-9

Add stripTrailing at printAbove consumer boundary

• Moved stripTrailing() call from producer sites to consumer boundary in pendingPrintAbove loop
• Updated comment to explain defensive stripping before split("\n", -1) prevents empty string
 entries
• Removed outdated comment about producer-side stripping responsibility
• Single-line fix eliminates trailing blank lines from all producers uniformly

aceclaw-cli/src/main/java/dev/aceclaw/cli/TerminalRepl.java


Grey Divider

Qodo Logo

@qodo-code-review

qodo-code-review Bot commented Mar 9, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider


Remediation recommended

1. stripTrailing drops trailing spaces 🐞 Bug ✓ Correctness
Description
text.stripTrailing() removes all trailing Unicode whitespace, not just newlines; this can alter
printAbove output when the final line intentionally ends with spaces (e.g., whitespace-sensitive
code block output or terminal padding/clearing). The behavior change is user-visible and applies to
all pendingPrintAbove producers (cron/deferred/background completions).
Code

aceclaw-cli/src/main/java/dev/aceclaw/cli/TerminalRepl.java[R441-443]

+                                // Strip trailing blank lines before splitting to avoid
+                                // empty printAbove() calls that produce visible blank lines.
+                                String[] lines = text.stripTrailing().split("\n", -1);
Evidence
The consumer now applies stripTrailing() to every printAbove payload before splitting.
Background-task printAbove payloads can originate from buffered streaming text
(BackgroundOutputBuffer.extractTextContent() concatenates deltas verbatim), and markdown rendering
of code blocks prints literals without trimming trailing spaces—so stripping at the consumer can
modify the rendered content (especially on the last line).

aceclaw-cli/src/main/java/dev/aceclaw/cli/TerminalRepl.java[434-454]
aceclaw-cli/src/main/java/dev/aceclaw/cli/BackgroundOutputBuffer.java[142-160]
aceclaw-cli/src/main/java/dev/aceclaw/cli/TerminalMarkdownRenderer.java[149-166]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`TerminalRepl` now calls `text.stripTrailing()` before splitting printAbove content into lines. In Java, `stripTrailing()` removes *all* trailing Unicode whitespace (spaces/tabs/etc.), not only newline characters. This can change the rendered output if the last line intentionally ends with spaces (e.g., whitespace-sensitive code output).

## Issue Context
The intent is to avoid extra blank lines caused by `split(&quot;\n&quot;, -1)` producing trailing empty strings. We should remove trailing **blank lines** without modifying meaningful trailing spaces on the last non-blank line.

## Fix Focus Areas
- aceclaw-cli/src/main/java/dev/aceclaw/cli/TerminalRepl.java[439-450]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

@coderabbitai

coderabbitai Bot commented Mar 9, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 9ece4060-d6b2-4a61-bbfd-acacd075f643

📥 Commits

Reviewing files that changed from the base of the PR and between 4d13bf3 and c3bc952.

📒 Files selected for processing (1)
  • aceclaw-cli/src/main/java/dev/aceclaw/cli/TerminalRepl.java

📝 Walkthrough

Walkthrough

The TerminalRepl's UI renderer now strips trailing whitespace using stripTrailing() on pending printAbove entries before splitting multi-line text. This prevents empty string entries from generating visible blank lines in terminal output.

Changes

Cohort / File(s) Summary
Terminal Output Cleaning
aceclaw-cli/src/main/java/dev/aceclaw/cli/TerminalRepl.java
Added stripTrailing() call before splitting multi-line text into printAbove entries, eliminating trailing blank lines in cron/deferred output.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~5 minutes

Possibly related PRs

  • PR #186 — Also addresses trailing blank lines in TerminalRepl's printAbove handling, but applies the fix at producer sites rather than the consumer boundary.
🚥 Pre-merge checks | ✅ 5 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: adding stripTrailing() at the printAbove consumer to fix trailing blank lines.
Linked Issues check ✅ Passed The PR directly implements the consumer-side stripTrailing() fix specified in issue #194, addressing the root cause of trailing blank lines.
Out of Scope Changes check ✅ Passed The change is narrowly scoped to the single defensive strip at the printAbove consumer boundary as specified in issue #194, with no unrelated modifications.
Block Major Correctness And Security Risks ✅ Passed The PR safely adds stripTrailing() to remove trailing whitespace before splitting lines, addressing issue #194 without introducing security, concurrency, or data integrity risks.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/issue-194-printabove-trailing-blanks

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@qodo-code-review

Copy link
Copy Markdown

CI Feedback 🧐

A test triggered by this PR failed. Here is an AI-generated analysis of the failure:

Action: pre-merge-check

Failed stage: Pre-merge quality gate [❌]

Failed test name: CandidatePipelineIntegrationTest > killSwitchPreventsPromptInjection()

Failure summary:

The GitHub Action failed during the Gradle preMergeCheck step because the test task
:aceclaw-daemon:continuousLearningSmokeTest failed.
- Gradle reports 13 tests completed, 9 failed,
causing the build to fail with exit code 1.
- The failing tests are assertion failures
(java.lang.AssertionError) in:
- CandidatePipelineIntegrationTest.java at lines 65, 81, 108, 133,
151, 191, 237
- StreamingAgentHandlerCandidateInjectionTest.java at lines 45, 76
- The test report
is available at: aceclaw-daemon/build/reports/tests/continuousLearningSmokeTest/index.html.

Relevant error logs:
1:  ##[group]Runner Image Provisioner
2:  Hosted Compute Agent
...

35:  ssh-strict: true
36:  ssh-user: git
37:  persist-credentials: true
38:  clean: true
39:  sparse-checkout-cone-mode: true
40:  fetch-depth: 1
41:  fetch-tags: false
42:  show-progress: true
43:  lfs: false
44:  submodules: false
45:  set-safe-directory: true
46:  env:
47:  REPLAY_FULL_MODE: false
48:  REPLAY_PROMPTS_PATH: docs/reports/samples/replay-prompts-ci-short.json
49:  REPLAY_SUITE_MIN_PER_CATEGORY: 1
50:  REPLAY_MAX_TOKEN_ESTIMATION_ERROR_RATIO: 0.65
51:  REPLAY_FAIL_ON_LATENCY: false
52:  REPLAY_ENFORCE_ANTI_PATTERN_FP_RATE: false
...

121:  with:
122:  distribution: temurin
123:  java-version: 21
124:  java-package: jdk
125:  check-latest: false
126:  server-id: github
127:  server-username: GITHUB_ACTOR
128:  server-password: GITHUB_TOKEN
129:  overwrite-settings: true
130:  job-status: success
131:  token: ***
132:  env:
133:  REPLAY_FULL_MODE: false
134:  REPLAY_PROMPTS_PATH: docs/reports/samples/replay-prompts-ci-short.json
135:  REPLAY_SUITE_MIN_PER_CATEGORY: 1
136:  REPLAY_MAX_TOKEN_ESTIMATION_ERROR_RATIO: 0.65
137:  REPLAY_FAIL_ON_LATENCY: false
138:  REPLAY_ENFORCE_ANTI_PATTERN_FP_RATE: false
...

163:  add-job-summary: always
164:  add-job-summary-as-pr-comment: never
165:  dependency-graph: disabled
166:  dependency-graph-report-dir: dependency-graph-reports
167:  dependency-graph-continue-on-failure: true
168:  build-scan-publish: false
169:  validate-wrappers: true
170:  allow-snapshot-wrappers: false
171:  gradle-home-cache-strict-match: false
172:  workflow-job-context: null
173:  github-token: ***
174:  env:
175:  REPLAY_FULL_MODE: false
176:  REPLAY_PROMPTS_PATH: docs/reports/samples/replay-prompts-ci-short.json
177:  REPLAY_SUITE_MIN_PER_CATEGORY: 1
178:  REPLAY_MAX_TOKEN_ESTIMATION_ERROR_RATIO: 0.65
179:  REPLAY_FAIL_ON_LATENCY: false
180:  REPLAY_ENFORCE_ANTI_PATTERN_FP_RATE: false
...

236:  [command]/usr/bin/tar -xf /home/runner/work/_temp/feeff3ee-2bb0-400c-998e-afdc448e5543/cache.tzst -P -C /home/runner/work/AceClaw/AceClaw --use-compress-program unzstd
237:  Cache restored successfully
238:  Restored cache entry with key gradle-dependencies-v1-3cfaad3d65a80b3c3594a0f40e020edf to /home/runner/.gradle/caches/modules-*/files-*/*/*/*/* in 3013ms
239:  ##[endgroup]
240:  ##[group]All Gradle Wrapper jars are valid
241:  ✓ Found known Gradle Wrapper JAR files:
242:  b3a875ddc1f044746e1b1a55f645584505f4a10438c1afea9f15e92a7c42ec13 gradle/wrapper/gradle-wrapper.jar
243:  ##[endgroup]
244:  ##[group]Run ./gradlew generateReplayCases -PreplayPromptsInput=docs/reports/samples/replay-prompts-ci-short.json -PreplayCasesOutput=.aceclaw/metrics/continuous-learning/replay-cases.json -PreplayCasesManifestOutput=.aceclaw/metrics/continuous-learning/replay-cases.manifest.json -PreplaySuiteMinPerCategory=1 -PreplayTimeoutMs=180000 -PreplayAutoApprovePermissions=true --no-daemon
245:  �[36;1m./gradlew generateReplayCases -PreplayPromptsInput=docs/reports/samples/replay-prompts-ci-short.json -PreplayCasesOutput=.aceclaw/metrics/continuous-learning/replay-cases.json -PreplayCasesManifestOutput=.aceclaw/metrics/continuous-learning/replay-cases.manifest.json -PreplaySuiteMinPerCategory=1 -PreplayTimeoutMs=180000 -PreplayAutoApprovePermissions=true --no-daemon�[0m
246:  shell: /usr/bin/bash -e {0}
247:  env:
248:  REPLAY_FULL_MODE: false
249:  REPLAY_PROMPTS_PATH: docs/reports/samples/replay-prompts-ci-short.json
250:  REPLAY_SUITE_MIN_PER_CATEGORY: 1
251:  REPLAY_MAX_TOKEN_ESTIMATION_ERROR_RATIO: 0.65
252:  REPLAY_FAIL_ON_LATENCY: false
253:  REPLAY_ENFORCE_ANTI_PATTERN_FP_RATE: false
...

324:  > Task :aceclaw-tools:classes
325:  > Task :aceclaw-tools:jar
326:  > Task :aceclaw-cli:runReplayCases
327:  07:52:54.421 [main] INFO  dev.aceclaw.cli.DaemonStarter - Daemon not running; starting...
328:  07:52:54.445 [main] INFO  dev.aceclaw.cli.DaemonStarter - Daemon process started (PID 2604); logs at /home/runner/.aceclaw/logs/daemon.log
329:  07:52:55.466 [main] DEBUG dev.aceclaw.cli.DaemonConnection - Opened connection to daemon at /home/runner/.aceclaw/aceclaw.sock
330:  07:52:55.466 [main] DEBUG dev.aceclaw.cli.DaemonClient - Control connection established to /home/runner/.aceclaw/aceclaw.sock
331:  07:52:55.469 [main] DEBUG dev.aceclaw.cli.DaemonClient - Disconnected from daemon
332:  07:52:55.469 [main] DEBUG dev.aceclaw.cli.DaemonConnection - Opened connection to daemon at /home/runner/.aceclaw/aceclaw.sock
333:  07:52:55.469 [main] DEBUG dev.aceclaw.cli.DaemonClient - Control connection established to /home/runner/.aceclaw/aceclaw.sock
334:  07:52:55.469 [main] INFO  dev.aceclaw.cli.DaemonStarter - Connected to newly started daemon
335:  07:52:55.483 [main] DEBUG dev.aceclaw.cli.DaemonConnection - Sent request: method=candidate.injection.set, id=1
336:  07:52:55.558 [main] DEBUG dev.aceclaw.cli.DaemonConnection - Sent request: method=session.create, id=2
337:  07:52:55.560 [main] DEBUG dev.aceclaw.cli.DaemonConnection - Opened connection to daemon at /home/runner/.aceclaw/aceclaw.sock
338:  07:52:55.566 [main] DEBUG dev.aceclaw.cli.TaskManager - Submitted task 1 with prompt: List top-level modules and one-line responsibilities.
339:  07:52:56.072 [aceclaw-task-1] DEBUG dev.aceclaw.cli.TaskManager - Task 1 completed with state FAILED
340:  07:52:56.171 [main] DEBUG dev.aceclaw.cli.DaemonConnection - Sent request: method=session.destroy, id=4
341:  07:52:56.180 [main] DEBUG dev.aceclaw.cli.DaemonConnection - Sent request: method=session.create, id=5
342:  07:52:56.181 [main] DEBUG dev.aceclaw.cli.DaemonConnection - Opened connection to daemon at /home/runner/.aceclaw/aceclaw.sock
343:  07:52:56.181 [main] DEBUG dev.aceclaw.cli.TaskManager - Submitted task 1 with prompt: Name the replay quality gate script and one blocked metric e...
344:  07:52:56.322 [aceclaw-task-1] DEBUG dev.aceclaw.cli.TaskManager - Task 1 completed with state FAILED
345:  07:52:56.382 [main] DEBUG dev.aceclaw.cli.DaemonConnection - Sent request: method=session.destroy, id=7
346:  07:52:56.385 [main] DEBUG dev.aceclaw.cli.DaemonConnection - Sent request: method=session.create, id=8
347:  07:52:56.386 [main] DEBUG dev.aceclaw.cli.DaemonConnection - Opened connection to daemon at /home/runner/.aceclaw/aceclaw.sock
348:  07:52:56.386 [main] DEBUG dev.aceclaw.cli.TaskManager - Submitted task 1 with prompt: Summarize permission guardrails in CI in 3 bullets.
349:  07:52:56.535 [aceclaw-task-1] DEBUG dev.aceclaw.cli.TaskManager - Task 1 completed with state FAILED
350:  07:52:56.587 [main] DEBUG dev.aceclaw.cli.DaemonConnection - Sent request: method=session.destroy, id=10
351:  07:52:56.589 [main] DEBUG dev.aceclaw.cli.DaemonConnection - Sent request: method=session.create, id=11
352:  07:52:56.590 [main] DEBUG dev.aceclaw.cli.DaemonConnection - Opened connection to daemon at /home/runner/.aceclaw/aceclaw.sock
353:  07:52:56.590 [main] DEBUG dev.aceclaw.cli.TaskManager - Submitted task 1 with prompt: In one sentence, explain a timeout-safe strategy for reposit...
354:  07:52:56.718 [aceclaw-task-1] DEBUG dev.aceclaw.cli.TaskManager - Task 1 completed with state FAILED
355:  07:52:56.791 [main] DEBUG dev.aceclaw.cli.DaemonConnection - Sent request: method=session.destroy, id=13
356:  07:52:56.792 [main] DEBUG dev.aceclaw.cli.DaemonConnection - Sent request: method=session.create, id=14
357:  07:52:56.793 [main] DEBUG dev.aceclaw.cli.DaemonConnection - Opened connection to daemon at /home/runner/.aceclaw/aceclaw.sock
358:  07:52:56.794 [main] DEBUG dev.aceclaw.cli.TaskManager - Submitted task 1 with prompt: When should replay regression block merge? Answer briefly.
359:  07:52:56.919 [aceclaw-task-1] DEBUG dev.aceclaw.cli.TaskManager - Task 1 completed with state FAILED
360:  07:52:56.995 [main] DEBUG dev.aceclaw.cli.DaemonConnection - Sent request: method=session.destroy, id=16
361:  07:52:56.996 [main] DEBUG dev.aceclaw.cli.DaemonConnection - Sent request: method=candidate.injection.set, id=17
362:  07:52:56.997 [main] DEBUG dev.aceclaw.cli.DaemonConnection - Sent request: method=session.create, id=18
363:  07:52:56.998 [main] DEBUG dev.aceclaw.cli.DaemonConnection - Opened connection to daemon at /home/runner/.aceclaw/aceclaw.sock
364:  07:52:56.998 [main] DEBUG dev.aceclaw.cli.TaskManager - Submitted task 1 with prompt: List top-level modules and one-line responsibilities.
365:  07:52:57.023 [aceclaw-task-1] DEBUG dev.aceclaw.cli.TaskManager - Task 1 completed with state FAILED
366:  07:52:57.099 [main] DEBUG dev.aceclaw.cli.DaemonConnection - Sent request: method=session.destroy, id=20
367:  07:52:57.101 [main] DEBUG dev.aceclaw.cli.DaemonConnection - Sent request: method=session.create, id=21
368:  07:52:57.102 [main] DEBUG dev.aceclaw.cli.DaemonConnection - Opened connection to daemon at /home/runner/.aceclaw/aceclaw.sock
369:  07:52:57.102 [main] DEBUG dev.aceclaw.cli.TaskManager - Submitted task 1 with prompt: Name the replay quality gate script and one blocked metric e...
370:  07:52:57.118 [aceclaw-task-1] DEBUG dev.aceclaw.cli.TaskManager - Task 1 completed with state FAILED
371:  07:52:57.202 [main] DEBUG dev.aceclaw.cli.DaemonConnection - Sent request: method=session.destroy, id=23
372:  07:52:57.204 [main] DEBUG dev.aceclaw.cli.DaemonConnection - Sent request: method=session.create, id=24
373:  07:52:57.205 [main] DEBUG dev.aceclaw.cli.DaemonConnection - Opened connection to daemon at /home/runner/.aceclaw/aceclaw.sock
374:  07:52:57.206 [main] DEBUG dev.aceclaw.cli.TaskManager - Submitted task 1 with prompt: Summarize permission guardrails in CI in 3 bullets.
375:  07:52:57.221 [aceclaw-task-1] DEBUG dev.aceclaw.cli.TaskManager - Task 1 completed with state FAILED
376:  07:52:57.306 [main] DEBUG dev.aceclaw.cli.DaemonConnection - Sent request: method=session.destroy, id=26
377:  07:52:57.308 [main] DEBUG dev.aceclaw.cli.DaemonConnection - Sent request: method=session.create, id=27
378:  07:52:57.309 [main] DEBUG dev.aceclaw.cli.DaemonConnection - Opened connection to daemon at /home/runner/.aceclaw/aceclaw.sock
379:  07:52:57.309 [main] DEBUG dev.aceclaw.cli.TaskManager - Submitted task 1 with prompt: In one sentence, explain a timeout-safe strategy for reposit...
380:  07:52:57.323 [aceclaw-task-1] DEBUG dev.aceclaw.cli.TaskManager - Task 1 completed with state FAILED
381:  07:52:57.409 [main] DEBUG dev.aceclaw.cli.DaemonConnection - Sent request: method=session.destroy, id=29
382:  07:52:57.412 [main] DEBUG dev.aceclaw.cli.DaemonConnection - Sent request: method=session.create, id=30
383:  07:52:57.413 [main] DEBUG dev.aceclaw.cli.DaemonConnection - Opened connection to daemon at /home/runner/.aceclaw/aceclaw.sock
384:  07:52:57.413 [main] DEBUG dev.aceclaw.cli.TaskManager - Submitted task 1 with prompt: When should replay regression block merge? Answer briefly.
385:  07:52:57.428 [aceclaw-task-1] DEBUG dev.aceclaw.cli.TaskManager - Task 1 completed with state FAILED
386:  07:52:57.513 [main] DEBUG dev.aceclaw.cli.DaemonConnection - Sent request: method=session.destroy, id=32
387:  Replay cases manifest written to: .aceclaw/metrics/continuous-learning/replay-cases.manifest.json
388:  Replay cases written to: .aceclaw/metrics/continuous-learning/replay-cases.json
389:  07:52:57.530 [main] DEBUG dev.aceclaw.cli.DaemonClient - Disconnected from daemon
390:  > Task :generateReplayCases
391:  gradle/actions: Writing build results to /home/runner/work/_temp/.gradle-actions/build-results/__run-1773042759295.json
392:  [Incubating] Problems report is available at: file:///home/runner/work/AceClaw/AceClaw/build/reports/problems/problems-report.html
393:  BUILD SUCCESSFUL in 23s
394:  24 actionable tasks: 24 executed
395:  ##[group]Run ./gradlew generateReplayReport -PreplayCasesInput=.aceclaw/metrics/continuous-learning/replay-cases.json -PreplayCasesManifestInput=.aceclaw/metrics/continuous-learning/replay-cases.manifest.json -PreplayAntiPatternFeedbackPath=.aceclaw/metrics/continuous-learning/anti-pattern-gate-feedback.json -PreplayReport=.aceclaw/metrics/continuous-learning/replay-latest.json --no-daemon
396:  �[36;1m./gradlew generateReplayReport -PreplayCasesInput=.aceclaw/metrics/continuous-learning/replay-cases.json -PreplayCasesManifestInput=.aceclaw/metrics/continuous-learning/replay-cases.manifest.json -PreplayAntiPatternFeedbackPath=.aceclaw/metrics/continuous-learning/anti-pattern-gate-feedback.json -PreplayReport=.aceclaw/metrics/continuous-learning/replay-latest.json --no-daemon�[0m
397:  shell: /usr/bin/bash -e {0}
398:  env:
399:  REPLAY_FULL_MODE: false
400:  REPLAY_PROMPTS_PATH: docs/reports/samples/replay-prompts-ci-short.json
401:  REPLAY_SUITE_MIN_PER_CATEGORY: 1
402:  REPLAY_MAX_TOKEN_ESTIMATION_ERROR_RATIO: 0.65
403:  REPLAY_FAIL_ON_LATENCY: false
404:  REPLAY_ENFORCE_ANTI_PATTERN_FP_RATE: false
...

408:  GRADLE_ACTION_ID: gradle/actions/setup-gradle
409:  GRADLE_USER_HOME: /home/runner/.gradle
410:  GRADLE_BUILD_ACTION_SETUP_COMPLETED: true
411:  GRADLE_BUILD_ACTION_CACHE_RESTORED: true
412:  DEVELOCITY_INJECTION_INIT_SCRIPT_NAME: gradle-actions.inject-develocity.init.gradle
413:  DEVELOCITY_INJECTION_CUSTOM_VALUE: gradle-actions
414:  GITHUB_DEPENDENCY_GRAPH_ENABLED: false
415:  ##[endgroup]
416:  To honour the JVM settings for this build a single-use Daemon process will be forked. For more on this, please refer to https://docs.gradle.org/8.14.2/userguide/gradle_daemon.html#sec:disabling_the_daemon in the Gradle documentation.
417:  Daemon will be stopped at the end of the build 
418:  > Task :generateReplayReport
419:  Replay report written to: .aceclaw/metrics/continuous-learning/replay-latest.json
420:  gradle/actions: Writing build results to /home/runner/work/_temp/.gradle-actions/build-results/__run_2-1773042781471.json
421:  BUILD SUCCESSFUL in 7s
422:  1 actionable task: 1 executed
423:  ##[group]Run ./gradlew preMergeCheck -PreplayGateStrict=true -PreplayReport=.aceclaw/metrics/continuous-learning/replay-latest.json -PreplayMaxTokenEstimationErrorRatio=0.65 -PreplayFailOnLatency=false -PreplayEnforceAntiPatternFalsePositiveRate=false -PreplayMaxAntiPatternFalsePositiveRate=0.50 --no-daemon
424:  �[36;1m./gradlew preMergeCheck -PreplayGateStrict=true -PreplayReport=.aceclaw/metrics/continuous-learning/replay-latest.json -PreplayMaxTokenEstimationErrorRatio=0.65 -PreplayFailOnLatency=false -PreplayEnforceAntiPatternFalsePositiveRate=false -PreplayMaxAntiPatternFalsePositiveRate=0.50 --no-daemon�[0m
425:  shell: /usr/bin/bash -e {0}
426:  env:
427:  REPLAY_FULL_MODE: false
428:  REPLAY_PROMPTS_PATH: docs/reports/samples/replay-prompts-ci-short.json
429:  REPLAY_SUITE_MIN_PER_CATEGORY: 1
430:  REPLAY_MAX_TOKEN_ESTIMATION_ERROR_RATIO: 0.65
431:  REPLAY_FAIL_ON_LATENCY: false
432:  REPLAY_ENFORCE_ANTI_PATTERN_FP_RATE: false
...

488:  > Task :aceclaw-llm:processResources NO-SOURCE
489:  > Task :aceclaw-llm:classes UP-TO-DATE
490:  > Task :aceclaw-llm:jar UP-TO-DATE
491:  > Task :aceclaw-mcp:processResources NO-SOURCE
492:  > Task :aceclaw-mcp:classes UP-TO-DATE
493:  > Task :aceclaw-mcp:jar UP-TO-DATE
494:  > Task :aceclaw-memory:processResources NO-SOURCE
495:  > Task :aceclaw-memory:classes UP-TO-DATE
496:  > Task :aceclaw-memory:jar UP-TO-DATE
497:  > Task :aceclaw-security:processResources NO-SOURCE
498:  > Task :aceclaw-security:classes UP-TO-DATE
499:  > Task :aceclaw-security:jar UP-TO-DATE
500:  > Task :aceclaw-tools:processResources UP-TO-DATE
501:  > Task :aceclaw-tools:classes UP-TO-DATE
502:  > Task :aceclaw-tools:jar UP-TO-DATE
503:  > Task :aceclaw-daemon:continuousLearningSmokeTest FAILED
504:  CandidatePipelineIntegrationTest > killSwitchPreventsPromptInjection() FAILED
505:  java.lang.AssertionError at CandidatePipelineIntegrationTest.java:108
506:  13 tests completed, 9 failed
507:  FAILURE: Build failed with an exception.
508:  * What went wrong:
509:  Execution failed for task ':aceclaw-daemon:continuousLearningSmokeTest'.
510:  > There were failing tests. See the report at: file:///home/runner/work/AceClaw/AceClaw/aceclaw-daemon/build/reports/tests/continuousLearningSmokeTest/index.html
511:  * Try:
512:  > Run with --scan to get full insights.
513:  BUILD FAILED in 25s
514:  CandidatePipelineIntegrationTest > promotedCandidateRegressionToDemoted() FAILED
515:  java.lang.AssertionError at CandidatePipelineIntegrationTest.java:81
516:  CandidatePipelineIntegrationTest > shadowCandidateProgressionToPromoted() FAILED
517:  java.lang.AssertionError at CandidatePipelineIntegrationTest.java:65
518:  CandidatePipelineIntegrationTest > promptBudgetCapRespected() FAILED
519:  java.lang.AssertionError at CandidatePipelineIntegrationTest.java:133
520:  CandidatePipelineIntegrationTest > transitionAuditTrailPersisted() FAILED
521:  java.lang.AssertionError at CandidatePipelineIntegrationTest.java:151
522:  CandidatePipelineIntegrationTest > promotedCandidatesAppearInPromptAssembly() FAILED
523:  java.lang.AssertionError at CandidatePipelineIntegrationTest.java:191
524:  CandidatePipelineIntegrationTest > autoPromotionTriggersSkillDraftGeneration() FAILED
525:  java.lang.AssertionError at CandidatePipelineIntegrationTest.java:237
526:  StreamingAgentHandlerCandidateInjectionTest > plannedStyleOutcomeWritebackUpdatesInjectedCandidate() FAILED
527:  java.lang.AssertionError at StreamingAgentHandlerCandidateInjectionTest.java:76
528:  StreamingAgentHandlerCandidateInjectionTest > runtimeKillSwitchDisablesInjectionWithoutRestart() FAILED
529:  java.lang.AssertionError at StreamingAgentHandlerCandidateInjectionTest.java:45
530:  gradle/actions: Writing build results to /home/runner/work/_temp/.gradle-actions/build-results/__run_3-1773042788771.json
531:  [Incubating] Problems report is available at: file:///home/runner/work/AceClaw/AceClaw/build/reports/problems/problems-report.html
532:  25 actionable tasks: 6 executed, 19 up-to-date
533:  ##[error]Process completed with exit code 1.
534:  Post job cleanup.

@xinhuagu

xinhuagu commented Mar 9, 2026

Copy link
Copy Markdown
Owner Author

Response to review feedback

Qodo Bug #1: stripTrailing() drops trailing spaces

False positive. All pendingPrintAbove content is terminal-rendered output (ANSI-styled markdown, cron summaries, background task completions). Trailing spaces on the last line have zero visual meaning in a terminal — they are invisible and immediately overwritten by the cursor. No producer intentionally relies on trailing spaces for layout; all visible alignment uses padRight() on interior lines, not trailing spaces on the final line.

The alternative (replaceAll("\\n+$", "")) would be more surgical but adds regex overhead on every printAbove call for a distinction that has no user-visible effect.

Qodo CI Feedback: CandidatePipelineIntegrationTest failures

Unrelated to this PR. These are pre-existing continuousLearningSmokeTest failures in CandidatePipelineIntegrationTest and StreamingAgentHandlerCandidateInjectionTest — same failures reported on previous PRs (#191, #186). This PR only changes a single line in the printAbove consumer loop and does not touch any candidate/learning code.

@xinhuagu xinhuagu merged commit e0d0b0b into main Mar 9, 2026
4 of 5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix: trailing blank lines still appear in cron/deferred printAbove output

1 participant