Skip to content

fix(§17.6.2): the value-form sugar binds its result at a binding site — was always null - #815

Merged
bryanmaclee merged 2 commits into
mainfrom
fix/s395-value-form-sugar-land
Sep 2, 2026
Merged

fix(§17.6.2): the value-form sugar binds its result at a binding site — was always null#815
bryanmaclee merged 2 commits into
mainfrom
fix/s395-value-form-sugar-land

Conversation

@bryanmaclee

Copy link
Copy Markdown
Owner

bryan, user-voice S395: "seems ok not to have a trailing else". The ruling settled the no-else direction; verifying it surfaced that the sugar itself never worked in the bound position at all.

The defect

SPEC §17.6.2 is normative: "A branch body that is exactly one expression SHALL be equivalent to { lift <expression> }." That held in the markup-interpolation path and was never implemented at a binding site:

const label = if (@n > 0) { "pos" } else { "neg" }

compiled at exit 0 with zero diagnostics and emitted a fresh shadowed let _scrml_tilde_4 = "pos" inside each arm, never writing the outer result var — so label was always null. Silent-wrong. The explicit-lift twin was the control and was correct.

The fix

New _emitValueFormSugarArm + 3 call sites; tildeVar threaded through emitIfExprAltChain. It shares the leaf predicate _blockTailIsValueExpr with the §18.5 match block-arm redirect (same root question — "is this a value?") but not the shape rule: §18.5 is tail-of-many, §17.6.1's grammar is exactly-one ('{' expression '}'). Sharing the shape test would have widened §17.6 beyond its grammar.

Verification

  • Bite, both directions, by file copy (never git stashrefs/stash is shared across worktrees): base let _scrml_tilde_4 = "pos"; → build _scrml_tilde_3 = "pos";. PA-reproduced independently of the agent.
  • Direction is semantics-changed — the class the gates are weakest against — so it owes a measured differential: 2 of 7408 artifacts change, both named, both the new conformance cases. Zero pre-existing corpus files change.
  • The zero is explained, not assumed: PA-verified census finds exactly 5 bound-position sites in the whole corpus, all in samples/compilation-tests/gauntlet-s19-phase2-control-flow/, and all 5 write the explicit lift form.
  • ctrl-023 / ctrl-024 fail on base, pass on head — genuine regression guards, not dormant fixtures. Whole-suite base-vs-head: 0 new failures.
  • S239 adversarial pass run PA-side (the dev agent cannot invoke it in-agent): 3 findings, all LOW, none blocking, two pre-existing and adjacent. Filed separately, not fixed here.

Not widened, deliberately

The derived-cell binding const <label> = if (…) still fails loud with E-CODEGEN-INVALID-LOGIC, for both the sugar and the explicit-lift form. §17.6.3 names only const / let binding sites, so a derived state cell is an unspecified shape currently failing in the safe direction. Making it work is a widening and is bryan's ruling. (Asymmetry recorded: const <label> = match @level { … } in a derived cell does work and ships as a conformance case.)

provenance: spec:§17.6.2 — conformance restoration toward an existing normative sentence, not a widening.

Agent branch: worktree-agent-af4227ae4f7a528e9 @ 8202c10c. Its progress.md crash-anchor was relocated out of the repo root into docs/changes/s395-value-form-sugar-bound/.

🤖 Generated with Claude Code

https://claude.ai/code/session_019eHiNS6uvnGPFz55fzinNJ

… — was always null

bryan, user-voice S395: "seems ok not to have a trailing else". The ruling settled the
no-else direction; verifying it surfaced that the sugar itself never worked in the
bound position at all.

THE DEFECT. SPEC §17.6.2 is normative: "A branch body that is exactly one expression
SHALL be equivalent to { lift <expression> }." That held in the markup-interpolation
path and was never implemented at a binding site. A local

    const label = if (@n > 0) { "pos" } else { "neg" }

compiled at exit 0 with zero diagnostics and emitted a FRESH shadowed
`let _scrml_tilde_4 = "pos"` inside each arm, never writing the outer result var —
so `label` was ALWAYS null. Silent-wrong. The explicit-`lift` twin was the control
and was correct.

THE FIX. New `_emitValueFormSugarArm` helper + 3 call sites; `tildeVar` threaded
through `emitIfExprAltChain`. It shares the leaf predicate `_blockTailIsValueExpr`
with the §18.5 match block-arm redirect (same root question: "is this a value?") but
NOT the shape rule — §18.5 is tail-of-many, §17.6.1's grammar is exactly-one
(`'{' expression '}'`). Sharing the shape test would have widened §17.6 to a rule its
grammar does not sanction. The `length === 1` test matches the working interpolation
twin `_soleBareExprValue`.

Two guards are load-bearing and measured, not assumed: `{ @acc += 1 }` arrives as a
bare-expr carrying an `assign` node. Without `_blockTailIsValueExpr` the redirect would
hijack a statement as the arm value AND bypass the §51.11 machine-write interception.

VERIFICATION.
- Bite, both directions, by FILE COPY (never `git stash` — refs/stash is shared across
  worktrees): base `let _scrml_tilde_4 = "pos";` -> build `_scrml_tilde_3 = "pos";`.
  PA-reproduced independently of the agent.
- Direction is `semantics-changed`, the class the gates are weakest against, so it owes
  a MEASURED differential: artifact diffs 2 of 7408, both named, both the new
  conformance cases. ZERO pre-existing corpus files change. The agent's first run was
  contaminated by a source-set race (1912/1913) and was re-run at 1914/1914.
- The zero is explained, not assumed: PA-verified census finds exactly 5 bound-position
  sites in the whole corpus, all in samples/compilation-tests/gauntlet-s19-phase2-
  control-flow/, and all 5 write the explicit `lift` form.
- ctrl-023 and ctrl-024 FAIL on base and PASS on head — genuine regression guards, not
  dormant fixtures. Whole-suite base-vs-head: 0 new failures.
- S239 adversarial pass run PA-side (the dev agent cannot invoke it in-agent):
  3 findings, all LOW, none blocking, two pre-existing and adjacent. Filed, not fixed
  here.

NOT WIDENED, deliberately: the derived-cell binding `const <label> = if (…)` still
fails loud with E-CODEGEN-INVALID-LOGIC for BOTH the sugar and the explicit-`lift`
form. §17.6.3 names only `const`/`let` binding sites, so a derived state cell is an
UNSPECIFIED shape currently failing in the safe direction. Making it work is a widening
and is bryan's ruling. (Asymmetry recorded: `const <label> = match @Level { … }` in a
derived cell DOES work and ships as a conformance case.)

The agent's crash-anchor progress.md was relocated from the repo root into
docs/changes/s395-value-form-sugar-bound/ rather than landing as a root stray.

provenance: spec:§17.6.2 — "A branch body that is exactly one expression SHALL be
equivalent to { lift <expression> }" (conformance restoration, not a widening)

Agent branch: worktree-agent-af4227ae4f7a528e9 @ 8202c10c
@bryanmaclee
bryanmaclee merged commit 908a631 into main Sep 2, 2026
2 of 3 checks passed
@bryanmaclee
bryanmaclee deleted the fix/s395-value-form-sugar-land branch September 2, 2026 11:36
bryanmaclee added a commit that referenced this pull request Sep 2, 2026
…to zero, and a locus that was disjoint from its answer (#816)

GAPS. g-value-form-sugar-in-bound-position-emits-null -> RESOLVED via #815 (908a631),
PA-verified on MERGED main rather than on the branch. Two corrections to that entry as
filed, both from execution:

  (a) Its `locus=searched:` named emit-html.ts, emit-each.ts and emit-control-flow.ts.
      The responsible site was in NONE of the three — it is emit-logic.ts, a FOURTH file,
      reached via the const-decl/let-decl dispatch through `node.ifExpr`. The searched-set
      was not merely incomplete, it was DISJOINT from the answer. Routed to the nav-maps
      per base §5: a locus error that recurs across dispatches is a map gap wearing a
      brief's clothes.
  (b) Its claim "the explicit-`lift` twin is the control and is correct" holds for the
      LOCAL binding only. For a derived cell BOTH forms fail — so anyone building against
      that sentence works from a false control.

TWO NEW ENTRIES, same root as the one #815 closed, which is why #815 is correctly scoped
as one position of a class and not the class:

  - g-bare-expr-in-if-arm-rebinds-tilde-context-corrupting-the-result-var (HIGH,
    PA-reproduced on merged main, SURVIVES #815). Hits the CANONICAL
    `'{' statement* lift-stmt statement* '}'` production. The corpus misses it on a
    technicality — phase2-if-as-expr-intermediate-014.scrml uses a `let`-decl, which does
    not rebind; only a bare EXPRESSION does. RULING OWED.
  - g-nested-if-as-expression-arm-body-binds-null-silently (MED, RELAYED-VERIFIED-BY-
    REVIEWER and labelled as such — not PA-re-executed). Filed as a fail-SILENT direction
    defect, NOT as a missing feature: §17.6.1 makes the shape unspecified, so supporting
    it is a widening and is bryan's.

REVIEW FLOOR: 1 OWED -> 0. Markers for #812, #813, #814, #815. Code-bearing carve-out
rate holds at 2/163 (1%); the 59% all-PR figure is the volume statistic the S319 note
says not to read as a health signal.

REVIEWER-VS-DEV, ADJUDICATED BY EXECUTION. The S239 pass claimed #815 removes a
ReferenceError/implicit-global class. It does for a SUGAR else arm and does NOT for an
explicit-`lift` else arm — and the explicit-`lift` form is the one §17.6.1's canonical
grammar documents. Recorded in the new HIGH rather than accepted as filed.

DRIVE-BY, in a file already open: g-each-value-form-if-markup-fn-call-branch-stringifies
carried `status=resolved` on its marker (with a bite-proven prov= from S392-peter) while
its HEADING still read `open`. A heading-based sweep saw an open entry the field-based
probe saw closed. Heading corrected; no status change. This is the exact divergence base
§2 warns about — and it cuts against the overlay's own "match on the heading, not on
marker adjacency", since S385 measured headings as the LOSSY side.

Counts move HIGH 77 (-1 resolved, +1 new) and MED 200->201, which is the proof the new
entries are machine-visible rather than prose-only.
bryanmaclee added a commit that referenced this pull request Sep 3, 2026
…reen while wrong (#824)

Ran concurrently with S396-peter throughout. Five rulings given, four code arcs landed, the
review floor drained twice to zero, maps refreshed. ONE ARC HELD on a ruling, worktree retained.

⚑ THE SESSION'S REAL OUTPUT IS NOT THE LANDINGS. Nine separate checks read green or
authoritative while being wrong, and every one was caught by RUNNING something rather than
by remembering. Three were my own claims. TWO WERE CAUGHT BY GATES I DID NOT WRITE. Three
were agents' own instruments, found by those agents.

RULINGS
  · the trailing-`else` question — direction stands, and the reported "inverted ruling" was
    MY OWN mis-description: §17.6.4 has always said a missing `else` is valid. I relayed a
    hand-off's framing into the boot report without opening the section.
  · the `~` arm-body question — limb (a) ratified, limb (c) BANKED as dpa-040, not closed.
  · 2a / 2b / 2c — the runAnchored fix (sequenced), the dev-root auth gate (limb b), and the
    tracking-job sequence with its first step folded in.
  · SPLIT the dev-auth arc when its §52.13 half turned out to require a second decider.

LANDED
  #815 the §17.6.2 value-form sugar binds its result at a binding site — it bound null forever.
  #818 a branch-declared function is ROUTED before it is COLLECTED; closing the client half
       alone put a `server fn` BODY into client.js.
  #822 18 conformance assertions read as coverage and checked nothing. ⚑ MY BRIEF WAS WRONG —
       a naive `continue` deletion would have reddened 62 count:0 ABSENCE assertions — and the
       agent deviated with a stated reason. Only 2 of the 18 were covered elsewhere; 16 were
       entirely unguarded.
  #823 `scrml dev` served a protected document unauthenticated at `/`. The fix is a DELETION:
       two serving paths become one.
  #816 #819 #820 continuity + filings; #817 the overdue wrap-6c maps refresh, which corrected
       three premises in my own concurrently-dispatched brief.

⚑ HELD, NOT LANDED — the `~` build, worktree RETAINED at agent-ac264a1015c0da19d @ c2ad6f49.
Four fix rounds, four adversarial passes, 7 SPEC loci reconciled. Blocked on bryan's
revert-vs-press-on for the READ half, whose widening PA-verifiably DELETES A DOM LIFT (base
emits _scrml_lift/createTextNode, the branch pushes into a dead array, exit 0). Resume the
agent; do not re-dispatch.

FINDINGS WORTH CARRYING
  · SUPPRESSING A SIGNAL SUPPRESSES WHATEVER RODE ON IT — three instances, one of them my own
    instruction. The `tracking` job's routine red concealed a REAL §52.13 assertion failing on
    Linux (compiler/tests/commands/ runs in NO blocking job on any platform). A knowingly-red
    assertion placed FIRST in a test turned the four after it into dead code that still read as
    coverage. And I instructed `test.failing` on that test — which passes when the body fails
    for ANY reason, so it would have MASKED A LEAK. The agent's formulation is the keeper:
    a mechanism that makes a red acceptable also makes a red invisible.
  · A FIX THAT NEEDS A SECOND DECIDER IS THE FORK RULE SAYING NO. Three rounds found three
    distinct divergences between the dev pre-gate and the resolution loop; the split then
    CLOSED a dev/prod divergence rather than opening one.
  · A REVIEW FINDING WAS FALSIFIED RATHER THAN FILED — the first time this session verification
    prevented a FABRICATED finding instead of catching a missed one. The corpus IS gated;
    corpus-bridge.test.js reaches it from inside the gated root.
  · TWO SHARED-DOC CONCURRENCY HAZARDS, both caught by machinery: conflicting @generated gap
    counts (resolved by regenerating from the merged population — the union, not a pick), and
    duplicate delta-log sequence numbers with peter (caught by the cloud gate's step 14; a
    duplicate makes the flogence bridge DROP the second entry from the digest).
  · BASE-DRIFT nearly reverted landed work FOUR times.
  · EVERY ONE of the five agent deviations from my instructions this session was correct.

WRAP STEPS: hand-off rewritten (S396-peter's rotated to handOffs/hand-off-282.md, his live items
carried) · changelog block · delta-log [2040]-[2045], sequence gate PASS · review floor 6 OWED
-> 0 · inbox: TWO items deliberately left unarchived because both await bryan (the E-ROUTE-004
fork and the ~11-day-old FSP Initialize deliberation), both summarised in the hand-off · suite
30945 pass / 54 fail — ONE FEWER than base, the §52.13 assertion · worktrees: four landed swept,
one retained · maps refreshed to 2d8dd8c, watermark verified via state.ts not by reading the
file · @generated + facts gates PASS.
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.

1 participant