fix: stop trailing comment parsing from spanning visible prose - #1070
fix: stop trailing comment parsing from spanning visible prose#1070dwin-gharibi wants to merge 9 commits into
Conversation
…m spanning visible prose
…s bug pf trailing html comment parsing
…d for clawsweeper for fixed bug
There was a problem hiding this comment.
Pull request overview
Fixes trailingHtmlComments so it can’t fabricate a “comment” that spans visible prose when a stray --> appears outside of an actual HTML comment, ensuring durable ClawSweeper markers remain safely recoverable from published review bodies.
Changes:
- Harden
trailingHtmlCommentsby rejecting backward-paired<!-- ... -->candidates unless the opener’s first-->is the terminator being matched. - Add targeted regression/property tests covering the stray-terminator-in-prose case and a realistic mid-body review-history marker layout.
- Add a Crabbox/Node 24 proof contract + scripts under
docs/proof/to demonstrate well-formedness, boundedness, and no-loss behavior.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| src/review-comment-markers.ts | Adds an interior-terminator guard so backward pairing can’t bridge across prose. |
| test/review-comment-markers.test.ts | Adds regression and property-guard tests for well-formed trailing comment extraction. |
| docs/proof/trailing-html-comment-parsing/run-proof.sh | Container proof runner that builds, compiles a pre-fix baseline, and runs proof + focused tests. |
| docs/proof/trailing-html-comment-parsing/run-proof.mjs | Proof script asserting well-formed, bounded, and no-loss claims against dist/. |
| docs/proof/trailing-html-comment-parsing/README.md | Documents the proof contract, claims, fixtures, and expected outputs. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
Codex review: needs real behavior proof before merge. Reviewed August 19, 2026, 2:14 AM ET / 06:14 UTC. ClawSweeper reviewWhat this changesThe branch adds a first-terminator guard to durable review-marker parsing, regression tests, and a Crabbox proof package. Merge readiness⛔ Blocked until stronger real behavior proof is added - 6 items remain Keep open: current main still has the unbounded parser pairing, and the code fix is narrow, but the current-head proof command cannot run as documented. Priority: P3 Review scores
Verification
How this fits togetherRendered ClawSweeper review comments contain durable HTML markers and optional review-history prose. Recovery code scans the final contiguous marker block to restore review state and labels. flowchart LR
A[GitHub review comment] --> B[Rendered review history]
B --> C[Trailing marker parser]
C --> D{Contiguous comments?}
D --> E[Durable review markers]
E --> F[Review state and labels]
Before merge
Findings
Agent review detailsSecurityNeeds attention: The added proof runner introduces a registry-backed package-manager bootstrap outside locked dependency resolution. Review metrics
Root-cause clusterRelationship: Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. Merge-risk optionsMaintainer options:
Technical reviewBest possible solution: Retain the parser guard and focused tests, then make the proof invocation stage and clean up its pre-fix input deterministically, use a trusted bootstrap path, and publish a redacted trace tied to the current head. Do we have a high-confidence way to reproduce the issue? Yes, source-reproducible: current main can pair an earlier opener with visible prose ending in Is this the best way to solve the issue? Yes for the parser itself: the first-terminator guard is the narrowest correction, but its proof package needs repair before it demonstrates the current head. Full review comments:
Overall correctness: patch is incorrect AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 02c930c53d1c. LabelsLabel justifications:
EvidenceSecurity concerns:
What I checked:
Likely related people:
Rank-up movesOptional improvements that raise the rating; they are not merge blockers.
Rating scale
Overall follows the weaker of proof and patch quality. Workflow
HistoryReview history (25 earlier review cycles; latest 8 shown)
|
…proof tests and rerunning it fixing problems
Closes #1069.
What Problem This Solves
Fixes an issue where
trailingHtmlCommentscould return an "HTML comment" thatspans visible prose. It scans backward from the end of a comment body, pairing each
-->with the nearest preceding<!--, without checking that the two actuallydelimit one comment. A stray
-->in prose therefore bridges back to an earlieropener and swallows everything between them — including any real ClawSweeper marker
in that span.
This is the parser that recovers ClawSweeper's durable state markers from its own
published comment, so a swallowed marker is no longer independently recoverable.
-->is not exotic in these bodies: Mermaid flowchart edges are literallyA --> B,and ClawSweeper renders a Mermaid architecture diagram in its own reviews.
Honest severity — please read before rating
I could not construct a body from the real renderer that triggers this, and I
tried hard. The trigger needs all three of:
<!--to bridge back to;-->after it;Four realistic bodies — a Mermaid diagram in a closed fence, the same with an
unclosed fence, prose ending in an arrow, and a table cell ending in an arrow — all
parse correctly even before this change, because condition 1 is missing: the
durable comment's only mid-body opener is the
<!-- clawsweeper-review-history -->marker, and
</details>always follows it before any trailing prose.Both consumers are also fail-safe today, which I verified rather than assumed:
clawsweeper-review-comment-state.tsanchors both ends with[^>]*, so an entrycontaining
>fails to match and the marker is ignored;review-recovery-label-backfill.tsuses a start-anchored matcher and scans thewhole entry for
name=value, but itscanonicalcheck is strictly anchored, so ablob makes the recovery label be retained rather than wrongly cleared.
So this is a latent parser defect, currently safe by accident of its consumers'
regexes rather than by design — not a live incident. I would not rate it above
P3. The reason it is still worth fixing: the backfill harvests attributes from the
entire entry with a loose matcher, so if a blob ever satisfies its
canonicalcheck— one regex refactor away — prose-derived attributes become authoritative for a
label-clearing decision.
I am flagging this rather than dressing it up, because a reviewer reading only the
"swallows real markers" framing would over-rate it.
Why This Change Was Made
An HTML comment ends at its first
-->. The pairing never verified that, so thefix rejects a candidate unless the opener's first terminator is the one being
matched:
Anything else means prose lies between them, so the trailing block has ended. That
makes the function honor its own documented contract — "the final contiguous
comment block", which is the name of its oldest test.
One behavior note, stated plainly: for the defect input, the earlier marker is now
not returned at all rather than returned inside a malformed blob. That is
correct — prose separates it from the trailing block — and it was unusable either
way, since every consumer regex rejected the blob.
Non-goals: no change to marker syntax, attribute parsing,
neutralizeReviewControlMarkers, or any consumer regex.User Impact
No observable change in normal operation — by design, since no realistic body
reaches the defect today. The parser now cannot emit a malformed entry, which
removes a latent hazard for the recovery-label lane.
No configuration change, no migration, no data-contract change.
OpenClaw Bay: not affected. No status, lifecycle, or telemetry shape Bay renders
changes. No Bay update or Bay proof is needed.
Release note:
fix: stop trailing comment parsing from spanning visible prose.No
CHANGELOG.mdedit is included — happy to add one if this repo's release policywants it.
Evidence
Diff
Plus a new proof package under
docs/proof/trailing-html-comment-parsing/.Focused tests
node --test test/review-comment-markers.test.ts→ 6/6 pass (3 pre-existing + 3 new).Consumer suites (
review-recovery-label-backfill,review-placeholder-recovery)are green and unchanged: 40/40 across all three files in-container.
New cases:
-->in prose never merges an earlier marker into a blob;<details>review-history marker cannot be bridged into by later prose — therealistic shape, built from what
renderReviewHistorySectionactually emits;<!--, closeswith
-->, and holds exactly one terminator.Red/green
Reverted only
src/review-comment-markers.ts, rebuilt, re-ran:All 3 pre-existing assertions pass in both directions.
Real Behavior Proof
Claim. Every entry returned is a single well-formed comment, the mid-body
review-history marker is never bridged into, and clean bodies parse exactly as
before.
Exercised surface.
dist/review-comment-markers.js.Scenario / fixture. Three claims:
<!-- clawsweeper-review-history -->marker stays out of thetrailing block while the durable review marker is still recovered.
compiled from the base commit inside the lease. This is the claim that
matters: a stricter parser must not make a previously-recoverable marker
unrecoverable. If that build is unavailable the claim reports SKIPPED and
fails.
Fixtures are shaped like real renderer output — a Mermaid
flowchart(edge syntax-->), a<details>review-history block with its own marker, then the trailingblock.
Command and environment. Node 24 in a Docker-backed Crabbox
local-containerlease:
crabbox run \ --provider local-container \ --local-container-image node:24 \ --no-hydrate \ --timing-json \ --artifact-glob '.artifacts/trailing-html-comment-proof/**' \ --script docs/proof/trailing-html-comment-parsing/run-proof.shlocal-container(Docker/OrbStack)0.15.0node:24@sha256:934240a162082fd8b8a2f90cd5114446443f1eba1c5378f6687167ca405e6584v24.19.0(satisfiesengines.node >= 24)cbx_035d141014da(violet-crab)run_236711b279b6.crabbox/runs/run_236711b279b6/run_236711b279b6-artifacts.tgz0Observed result. In-container: 19/19 proof checks PASS, focused suites
40/40, exit 0. The lease verified the guard on both sides (
post-fix: 1 interior-terminator check,pre-fix: 0) before running the claims.All seven clean bodies: identical to pre-fix.
An environment failure this proof caught. The first lease run failed during
build: TypeScript 7 dispatches to a platform-native binary published as an optional
dependency, and
@typescript/typescript-linux-arm64was missing afterpnpm install --frozen-lockfile, sotsccould not start. It surfaced far from itscause. The script now checks for the platform package explicitly, fetches it if
absent, and fails with a clear message otherwise — the retry shows
NOTE: … missing after install; fetching it explicitlyfollowed by a clean build.Recording it because the same trap will hit any future arm64 lease.
Artifact / trace.
docs/proof/trailing-html-comment-parsing/holdsrun-proof.sh,run-proof.mjs, and the contract README. The lease artifact tarballholds
proof-output.txt,focused-tests.txt,install.log,build.log, andprefix-build.log.Limits. Covers the trailing-block scan only. Claim 3 covers seven clean bodies,
not an exhaustive enumeration; the new pairing rule matches the HTML spec, so
divergence is confined to inputs where prose sits between an opener and the matched
terminator — exactly the defect. No live GitHub comment is published or read.
Repository test suite status
The proof and focused suites run on Node 24 inside the Crabbox lease recorded above
(
40/40in-container). The note below concerns only the full suite on the macOS host.comment-webhook.test.tspasses 25/25, three runs in a row in isolation onthis branch;
dist/repair/comment-webhook.jsshowsreview-comment-markersis not reachable from it.Green on this branch:
local-containerproofpnpm run build:allpnpm run format:checkpnpm run lint