Skip to content

fix(lang): #866 script install corruption via comment-marker misread in single-quoted constants - #885

Merged
jsavin merged 2 commits into
developfrom
fix-866-install-corruption
Aug 11, 2026
Merged

fix(lang): #866 script install corruption via comment-marker misread in single-quoted constants#885
jsavin merged 2 commits into
developfrom
fix-866-install-corruption

Conversation

@jsavin

@jsavin jsavin commented Aug 11, 2026

Copy link
Copy Markdown
Owner

Fix #866 — Install Corruption: Comment-Marker Misread in Single-Quoted Constants

Purpose

This PR fixes cumulative script corruption on script.newScriptObject install. A 0xC7 comment-marker byte inside a single-quoted character constant was misread as a comment start, causing each script install to add one stray brace and rendering the script uncompilable from the first install. The fix restores the 1993-era langcommentdelete semantics this scanner's reimplementation had dropped, and also corrects a sibling closing-delimiter-direction miscount.

Status

TESTED & VERIFIED — Full suite green (2482 tests, 0 failed, 17 baselined, exit 0). Critical test layer script_install_roundtrip.yaml 13/13 passing. The three original red cases verified red-then-green in both directions (fix reverted → red → restored). Corpus of 2,996 scripts: the one live victim repaired and stable; two former compile-hangs resolved. Gate: bar-raiser PASS + security PASS.

Key Changes

/frontier-cli/src/lang/langscan.c (2 commits)

Commit 76b7b8d (core fix):

  • Restored explicit character-constant tracking (inSingleQuote state variable replaces flqcurly boolean)
  • Comment-marker scanner now properly skips bytes inside 'x' delimiters, preventing 0xC7 false positives
  • Fixed sibling brace-balance counter to track closing-delimiter direction correctly
  • Semantically restores the original langcommentdelete behavior from pre-2019

Commit 2b11766 (test & refactor coverage):

  • Added cross-reference test case (character constants in comments)
  • Added two refactor-guard cases (ensures copy-paste correctness on future scanner edits)
  • Extended curly-quote string coverage for UTF-8 boundary validation

Issues Resolved

Fixes: #866

Corrections recorded on: #862, #849 (both had stale analysis due to issue #866 corruption)

Unblocks: #872 (full-wrapper approach now viable)

Follow-ups filed: #877, #878, #880, #881, #882, #883

Investigation Summary

The original issue report's claims about "reinstall destroys large unmodified scripts" and "opcode-0 format assertions" were investigated and refuted. Root causes:

  1. Measurement-harness artifact: MacRoman-encoded source script round-tripped through UTF-8, producing byte-count inflation. The issue's quoted file sizes were exact UTF-8 byte counts, not original sizes.
  2. Stale test-DB corruption: Issue databases/Frontier.root is stale (pre-#621, doubled-brace corruption); source of #866 false diagnosis #877 identified persistent corruption in the test database from prior sessions, which masked the true scope of the problem.

Records on #866, #862, #849 have been corrected with this evidence.

Test Coverage

Related PRs & Issues


https://claude.ai/code/session_01SEFFEgkaQJayd48Y2iuNkx

jsavin added 2 commits August 11, 2026 00:39
langstripstructuremarkers scans each source line to find where a trailing
comment begins, so that a comment marker inside a string literal is not
mistaken for a real comment. It tracked two of UserTalk's three literal
delimiters -- ASCII " and the Mac curly-quote pair (0xD2/0xD3) -- but not
chsinglequote (0x27), which delimits character and string4 constants.

On a line such as

  if s contains 'C' {          (where C is chcomment, 0xC7)

the 0xC7 inside the literal was read as the start of a trailing comment.
commentstart landed mid-literal, so the trailing structural-marker strip
was skipped for the real content and a { survived in the stored node
text. The outline export (oplangtextvisit) then re-emits a { from the
outline LEVEL transition, so the line gained one extra brace per install:

  install 1:  if s contains 'C' { {
  install 2:  if s contains 'C' { { {

The growth is cumulative and unbounded, and the script stops compiling
from the first install onward. This is the same family as #621, which
taught the strip about inline one-line blocks but not the scanner about
single-quote literals.

Both scanners in the function had the gap: the comment-start scan and the
brace-balance counter that decides whether a trailing } is load-bearing.
A brace inside a character constant is not structural, so both now track
all three delimiters. The two-way flqcurly/qcurly boolean is replaced by
an explicit closing-delimiter byte, which extends to three delimiters
without further branching.

Effect on the shipped corpus: a sweep of all 2,996 scripts in
Virgin.root (round-trip each, compile-gated with an installer-
unrepairable negative control) had exactly one script that reinstall
left non-compiling -- suites.commercial.parseAete, an instance of this
exact shape. It is now stable across repeated reinstalls.

Tests: three cases added to script_install_roundtrip.yaml (read-back
byte-equality, reinstall idempotence, and end-to-end execution). Verified
red before the fix and green after; the 8 pre-existing cases in that file
pass throughout. Unit-test result sets are identical to baseline (the
test_callback_infrastructure segfault reproduces unchanged on unmodified
develop and is unrelated).

Note for test authors: the runner writes script files as UTF-8, so a
literal 0xC7 byte in YAML arrives as two bytes and breaks a single-quoted
character constant. These tests use the \xc7 escape, which is ASCII in
the file and decodes to the single byte at runtime.
Follow-up to 76b7b8d, from the bar-raiser verdict. Test-only; no
source changes.

- Fix a stale cross-reference. The three #866 cases were inserted
  between the two #621 cases, so "Same shape as the previous test" in
  the outermost-depth case pointed at the wrong neighbour. It now names
  the depth-1 inline-block case explicitly, which survives reordering.

- Add a brace-balance-counter case. The fix touched two scanners; the
  three #866 cases only name the comment-start scan. This one puts a
  brace inside a character constant on a line that also ends with an
  inline one-line block, so it runs through the counter that decides
  whether a trailing } is load-bearing.

- Add a curly-quote (0xD2/0xD3) string-literal case. That delimiter was
  tracked by both scanners but had no test, and the refactor rewrote how
  the closing delimiter is chosen.

Status of the two new cases, measured rather than assumed: both PASS on
a pre-fix binary built from 76b7b8d~1, so they are regression guards
for the refactor, not reproductions of the bug. Only the three original
#866 cases are red pre-fix (verified through the runner against that
binary: 10 passed / 3 failed). All 13 pass at this commit.

The new cases are ASCII in the yaml and use \xd2 \xd3 \xc7 escapes; the
runner writes script files as UTF-8, so a literal high byte would arrive
as two bytes and break a single-quoted constant.
@jsavin

jsavin commented Aug 11, 2026

Copy link
Copy Markdown
Owner Author

Gate Review: fix-866-install-corruption

Verdict: PASS

Scope: 2 commits (76b7b8d fix + 2b11766 test-only) vs develop 03d7fe1 — Common/source/langscan.c (+50/-22) + tests/integration/test_cases/script_install_roundtrip.yaml (+66/-1). Fixes #866.

The bug (and the false diagnosis it was buried under)

Real defect: langstripstructuremarkers's comment-start scanner and brace-balance counter tracked ASCII double-quote and the MacRoman curly-quote pair but NOT single-quoted character constants. A 0xC7 (comment marker) byte inside 'Ç' was misread as a comment start; the structural strip was skipped; each install added one brace — cumulative, compile failing from install 1. One live corpus victim (suites.commercial.parseAete, now repaired and stable). The fix restores the 1993 langcommentdelete semantics this scanner's reimplementation dropped, and also fixes a sibling closing-direction miscount (quoted { inflating open-count).

The issue's original headline claims were REFUTED with a fingerprint: "reinstall destroys unmodified large scripts" was a harness artifact — MacRoman source round-tripped through UTF-8 (the issue's own quoted sizes are exact UTF-8 byte counts of the true char counts: 56,864+163→57,027; 10,038→10,055). Verified on the actual ced8241-era binaries: byte-identical round-trips, compile true→true. The "opcode-0" report traces to stale databases/Frontier.root (pre-#621 corruption, #877). Records corrected on #866/#862/#849; #872's full-wrapper approach is unblocked.

Tests

Layer Result
Integration (merge record) ✓ FORCED CLEAN REBUILD at 2b11766 with implementer frozen: 2482 total / 2302 passed / 0 failed / 17 baselined, exit 0. (An earlier suite run raced the implementer's A/B binary builds in the same worktree — caught by the bar-raiser, re-measured from scratch; exclusivity rule codified.)
script_install_roundtrip.yaml ✓ 13/13 at final commit; the 3 original #866 cases proven red-then-green BOTH directions (fix reverted → red reproduced → restored)
4-case delimiter matrix ✓ only the single-quote form ever broke; all four idempotent post-fix
Corpus (2,996 scripts) ✓ parseAete repaired; 2 former compile-hangs gone; the 65 cosmetic non-idempotent (#878) and 12 pre-broken (#879 — reclassified: 2 LF-corruption #881, 6 missing headless verbs #882, 3 genuine + 1 deliberate fixture) tracked separately
Unit layer ✓ failure sets byte-identical to baseline

Reviewers

  • bar-raiser ✓ PASS — scanner now matches the real tokenizer (escape alignment proven via parsepopescapesequence's hex-only tails; mutual delimiter exclusion; conservative unterminated behavior); flqcurly→chclose refactor bit-identical for legacy paths; single call site (newScriptObject path); honest test classification (implementer measured its 2 new cases pass PRE-fix — guards for the refactor, not bug reproductions — and said so rather than overclaim). P2s: test cross-ref fixed + 2 coverage cases added in the test round; langcommentdelete-delegation refactor filed as follow-up.
  • security ✓ PASS — parser-differential audit vs the real tokenizer: escape rules agree, memory safety bounded (no over-read on unterminated literals, no attacker-pinnable loop, NUL can't alias delimiters), no fail-closed→fail-open flip (strip is normalization, never a gate). One P2 residual filed (Parser/scanner divergence: CR-spanning single-quote character constants; fail-open, low practical impact #883: CR-spanning single-quote constants — per-line scanner state gap, near-zero occurrence, not a smuggling vector).

Follow-ups filed from this unit

#877 (stale Frontier.root), #878 (65 cosmetic non-idempotent), #879→reclassified (#881 LF corruption — the #855 unblocker; #882 missing headless verbs), #880 (runner UTF-8 trap that caused the false diagnosis), #883 (CR-spanning residual), + scanner-deduplication refactor suggestion.

Stats

  • Files: 2 (+116/-23)
  • Findings: 0 P0; 1 P1 process (suite race — resolved by re-measure + codified rule); 7 P2 (2 fixed in test round, rest filed)
  • Reviewers: 2 of 2 (concurrency not triggered — pure lexer change, no threading surface)

1 similar comment
@jsavin

jsavin commented Aug 11, 2026

Copy link
Copy Markdown
Owner Author

Gate Review: fix-866-install-corruption

Verdict: PASS

Scope: 2 commits (76b7b8d fix + 2b11766 test-only) vs develop 03d7fe1 — Common/source/langscan.c (+50/-22) + tests/integration/test_cases/script_install_roundtrip.yaml (+66/-1). Fixes #866.

The bug (and the false diagnosis it was buried under)

Real defect: langstripstructuremarkers's comment-start scanner and brace-balance counter tracked ASCII double-quote and the MacRoman curly-quote pair but NOT single-quoted character constants. A 0xC7 (comment marker) byte inside 'Ç' was misread as a comment start; the structural strip was skipped; each install added one brace — cumulative, compile failing from install 1. One live corpus victim (suites.commercial.parseAete, now repaired and stable). The fix restores the 1993 langcommentdelete semantics this scanner's reimplementation dropped, and also fixes a sibling closing-direction miscount (quoted { inflating open-count).

The issue's original headline claims were REFUTED with a fingerprint: "reinstall destroys unmodified large scripts" was a harness artifact — MacRoman source round-tripped through UTF-8 (the issue's own quoted sizes are exact UTF-8 byte counts of the true char counts: 56,864+163→57,027; 10,038→10,055). Verified on the actual ced8241-era binaries: byte-identical round-trips, compile true→true. The "opcode-0" report traces to stale databases/Frontier.root (pre-#621 corruption, #877). Records corrected on #866/#862/#849; #872's full-wrapper approach is unblocked.

Tests

Layer Result
Integration (merge record) ✓ FORCED CLEAN REBUILD at 2b11766 with implementer frozen: 2482 total / 2302 passed / 0 failed / 17 baselined, exit 0. (An earlier suite run raced the implementer's A/B binary builds in the same worktree — caught by the bar-raiser, re-measured from scratch; exclusivity rule codified.)
script_install_roundtrip.yaml ✓ 13/13 at final commit; the 3 original #866 cases proven red-then-green BOTH directions (fix reverted → red reproduced → restored)
4-case delimiter matrix ✓ only the single-quote form ever broke; all four idempotent post-fix
Corpus (2,996 scripts) ✓ parseAete repaired; 2 former compile-hangs gone; the 65 cosmetic non-idempotent (#878) and 12 pre-broken (#879 — reclassified: 2 LF-corruption #881, 6 missing headless verbs #882, 3 genuine + 1 deliberate fixture) tracked separately
Unit layer ✓ failure sets byte-identical to baseline

Reviewers

  • bar-raiser ✓ PASS — scanner now matches the real tokenizer (escape alignment proven via parsepopescapesequence's hex-only tails; mutual delimiter exclusion; conservative unterminated behavior); flqcurly→chclose refactor bit-identical for legacy paths; single call site (newScriptObject path); honest test classification (implementer measured its 2 new cases pass PRE-fix — guards for the refactor, not bug reproductions — and said so rather than overclaim). P2s: test cross-ref fixed + 2 coverage cases added in the test round; langcommentdelete-delegation refactor filed as follow-up.
  • security ✓ PASS — parser-differential audit vs the real tokenizer: escape rules agree, memory safety bounded (no over-read on unterminated literals, no attacker-pinnable loop, NUL can't alias delimiters), no fail-closed→fail-open flip (strip is normalization, never a gate). One P2 residual filed (Parser/scanner divergence: CR-spanning single-quote character constants; fail-open, low practical impact #883: CR-spanning single-quote constants — per-line scanner state gap, near-zero occurrence, not a smuggling vector).

Follow-ups filed from this unit

#877 (stale Frontier.root), #878 (65 cosmetic non-idempotent), #879→reclassified (#881 LF corruption — the #855 unblocker; #882 missing headless verbs), #880 (runner UTF-8 trap that caused the false diagnosis), #883 (CR-spanning residual), + scanner-deduplication refactor suggestion.

Stats

  • Files: 2 (+116/-23)
  • Findings: 0 P0; 1 P1 process (suite race — resolved by re-measure + codified rule); 7 P2 (2 fixed in test round, rest filed)
  • Reviewers: 2 of 2 (concurrency not triggered — pure lexer change, no threading surface)

@jsavin
jsavin merged commit 8660748 into develop Aug 11, 2026
@jsavin
jsavin deleted the fix-866-install-corruption branch August 11, 2026 08:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant