fix(cli): Keep a trailing content brace inside an enrichment marker body - #240
Open
detail-app[bot] wants to merge 1 commit into
Open
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Detail bug report: View on Detail
Closes #227
Bug
The CLI's enrichment-marker renderer (
cli/bin/javachat.js,createEnrichmentMarkerRenderer) found the marker close withheldText.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'sEnrichmentPlaceholderizer.resolveCloseIndexFromBraceRunis 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
resolveCloseIndexFromBraceRunfrom 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
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 theExample:line with no orphan}.npm run pack:checkreports the expected 4-file package. The CLI package has no lint/format/typecheck step —node --testandpack:checkare its gates. The Java lane is unchanged:./gradlew compileJava compileTestJavaand./gradlew test --tests MarkdownServiceTestpass (35 tests, 0 fail), including the backend's paralleltestEnrichmentClosingMarkerPreservesTrailingBrace.}}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.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.