Skip to content

fix(cli): Keep a trailing content brace inside an enrichment marker body - #240

Open
detail-app[bot] wants to merge 1 commit into
devfrom
detail/bug-fix/fix-cli-keep-a-trailing-content-brace-inside-an-en-0fc3d5
Open

fix(cli): Keep a trailing content brace inside an enrichment marker body#240
detail-app[bot] wants to merge 1 commit into
devfrom
detail/bug-fix/fix-cli-keep-a-trailing-content-brace-inside-an-en-0fc3d5

Conversation

@detail-app

@detail-app detail-app Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Detail bug report: View on Detail

Closes #227

Bug

The CLI's enrichment-marker renderer (cli/bin/javachat.js, createEnrichmentMarkerRenderer) found the marker close with heldText.indexOf("}}", 2) — the first }} in the buffer. When a known-token marker body ends in a content } (e.g. {{example:an empty object literal is {}}}}), the body's brace and the marker's real }} form a }}} run. The naive search matched at the body's }, consuming it as part of the close delimiter, so the content } was orphaned onto its own line and the marker's genuine }} leaked as a stray brace later. This is the exact leak the backend's EnrichmentPlaceholderizer.resolveCloseIndexFromBraceRun is written to prevent ("so a trailing content brace remains part of the enrichment body instead of leaking outside the card"). The bug has been present since the renderer was introduced.

Fix

Ported resolveCloseIndexFromBraceRun from the backend into the CLI. When the first }} candidate sits in a run of } characters, the close is resolved to the last }} of the run, so a trailing content brace stays in the rendered body instead of leaking. Zero added buffering — the close is still found by scanning the trailing brace run already in the buffer, preserving the renderer's stream-as-it-arrives property.

Scope matches the issue's recommended minimal fix: the prose }}}-run trigger. Inline-code and fenced-code triggers (where the }} sits inside a tracked code region) are intentionally out of scope — those need the full context-aware port (fence/inline-code tracking plus buffering) and are a separate, larger change.

Testing

  • Two new observable-boundary tests in cli/test/javachat.test.js (real CLI spawned against a fake SSE server, asserting on stdout): a single-event {{example:an empty object literal is {}}}} and a {{example:try (var scope = open()) { doWork(); }}} split across three stream chunks with surrounding prose. Both assert the content brace stays on the Example: line with no orphan }.
  • Negative control: reverting the fix (keeping the tests) makes both new tests fail with the exact orphan-brace output described in the issue; restoring the fix makes them pass — confirming the tests pin the behavior, not the implementation.
  • Routine checks: the full CLI suite passes (45 tests, 0 fail); npm run pack:check reports the expected 4-file package. The CLI package has no lint/format/typecheck step — node --test and pack:check are its gates. The Java lane is unchanged: ./gradlew compileJava compileTestJava and ./gradlew test --tests MarkdownServiceTest pass (35 tests, 0 fail), including the backend's parallel testEnrichmentClosingMarkerPreservesTrailingBrace.
  • The issue's char-by-char reproduction script still orphans at that granularity, as expected: with no buffering, a complete-looking }} arrives before the third } of the run. This is the documented out-of-scope case (requires the full context-aware port with buffering), not a regression of this fix; the committed tests use the real per-SSE-event granularity at which the fix is correct.
  • A live end-to-end smoke against a running backend could not be run. The backend hard-requires a private-gateway OPENAI_API_KEY/OPENAI_BASE_URL (pinned to a specific gateway URL) and pre-ingested Qdrant collections, none of which are provisioned in this environment. Standing up a local Qdrant surfaced a further startup gate requiring an existing indexed collection, and the LLM-gateway secret is unavailable regardless. The issue also notes the model's emission frequency of }-ending marker bodies is not established, so the trigger is not reliably reproducible on demand. The per-SSE-event unit tests are the authoritative verification.

Automatic Fixes PRs can be configured here.

@detail-app
detail-app Bot requested a review from WilliamAGH September 6, 2026 14:00
@detail-app detail-app Bot added the bug Something isn't working label Sep 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Detail Bug] CLI: Enrichment markers ending in '}' render with an orphan brace and leaked '}}'

1 participant