Skip to content

continuity(S395): the ~ ruling banked — limb (c) queued where the probe can see it, and the enforcement that should have caught the contradiction - #820

Merged
bryanmaclee merged 2 commits into
mainfrom
continuity/s395-tilde-ruling
Sep 2, 2026
Merged

continuity(S395): the ~ ruling banked — limb (c) queued where the probe can see it, and the enforcement that should have caught the contradiction#820
bryanmaclee merged 2 commits into
mainfrom
continuity/s395-tilde-ruling

Conversation

@bryanmaclee

Copy link
Copy Markdown
Owner

Continuity-only — no compiler source touched. The fix arc itself is dispatched separately.

The ruling

bryan, user-voice S395 — "lets look at ~" then "your rec". Limb (a) RATIFIED: §17.6.2 governs an if-as-expression arm body. A bare expression statement inside an arm is a side effect — it does not initialize ~, does not rebind the tilde context, does not touch the arm's result; only lift or the §17.6.10 sugar designates it.

Per the S276/S130 durable the terse ratification adopted the full text it answered — "(a) now, with (c) named as the question behind it" — so limb (c) is banked, not closed.

What the reading found

§17.6.2 and §32.2 are in direct conflict about the same three lines. §32.2 ("an expression statement whose value is not bound to any identifier SHALL initialize ~") plus §32.3's exactly-once rule makes { note("a") lift "pos" } an E-TILDE-002. §17.6.2 calls the same statement a side effect. The compiler implements neither — it mints a fresh tilde and rebinds the context, so the lift writes the wrong variable and the binding is silently null.

The dispatched arc owes both halves — codegen and the §32.2 arm-body carve-out with a Rule 4b provenance line — because a codegen-only landing leaves the contradiction standing in the text.

⛑ New HIGH — the enforcement doesn't fire

g-tilde-lin-enforcement-does-not-fire-on-spec-own-examples. Six probes on merged main, all exit 0, all zero E-TILDE: §32.5's verbatim ${ process(~) }; ~ read with no init; double-init without consumption; init never consumed at scope exit; double-init in a function body; and §17.6.6's partial-if example that SPEC says the compiler SHALL diagnose.

Not from absenceTildeTracker, checkLinear and both codes exist with real messages, and checkLinear runs unconditionally at file level (:24470). Cause not traced, and the entry says so rather than guessing: hasNonLiftTildeConsumer gates only loop-body elision, so the obvious explanation is ruled out without a replacement offered.

That silence is the point — it's why two normative sections could contradict each other for as long as both have existed without anyone noticing. The S322 re-examination test in its purest form: a normative SHALL delivered by a state-scanning tracker pass, retrofit rather than by construction, producing exactly the hole that predicts.

⛑ And I banked dpa-040 in a form the probe could not read

I wrote the full ## [dpa-040] section into dpa-queue.md — the right file, per the S319 drain-path rule — and dpa-debt.ts still reported 39 items / 2 UNRUN. The probe reads the status table, not the per-item sections; the script's own header says reading the per-item status: lines instead "would reproduce the exact obligation/probe mismatch this file exists to close." Adding the table row moved it to 40 / 3 UNRUN.

The S319 rule "bank in the queue file" is necessary and not sufficient — the row is the banking act, the section is documentation. Self-inflicted, same base §10 class as the rest of this session, and caught only because the probe was run rather than assumed.

dpa-040

Should an arm body be a ~ context boundary in its own right (§32.4, beside ${} contexts and function bodies)? Under it the conflict cannot recur by construction rather than by carve-out. Constraints recorded so the DD can't drift: ~-as-lin is not on the table (the boundary set is the question); adding a boundary is the LIMIT direction but is semantics-changed and owes a measured migration; and corpus-zero is blast radius only, never demand evidence (bryan, S346).

🤖 Generated with Claude Code

https://claude.ai/code/session_019eHiNS6uvnGPFz55fzinNJ

…robe can see it, and the enforcement that should have caught the contradiction

THE RULING (bryan, user-voice S395: "lets look at ~" then "your rec"). Limb (a) RATIFIED:
§17.6.2 governs an if-as-expression arm body — a bare expression statement inside an arm
is a SIDE EFFECT. It does not initialize `~`, does not rebind the tilde context, does not
touch the arm's result; only `lift` or the §17.6.10 sugar designates it. Per S276/S130 the
terse ratification adopted the FULL text it answered — "(a) now, with (c) named as the
question behind it" — so limb (c) is BANKED, NOT CLOSED.

WHAT THE READING FOUND. §17.6.2 and §32.2 are in direct conflict about the same three
lines. §32.2 — "an expression statement whose value is not bound to any identifier SHALL
initialize `~`" — plus §32.3's exactly-once rule makes `{ note("a") lift "pos" }` an
E-TILDE-002. §17.6.2 calls the same statement a side effect. The compiler implements
NEITHER: it mints a fresh tilde and rebinds the context, so the `lift` writes the wrong
variable and the binding is silently null. The fix arc is dispatched and owes BOTH halves
— codegen AND the §32.2 arm-body carve-out with a Rule 4b provenance line, in the same
arc, because a codegen-only landing leaves the contradiction standing in the text.

⚑ NEW HIGH — g-tilde-lin-enforcement-does-not-fire-on-spec-own-examples. Six probes on
merged main, all exit 0, all ZERO E-TILDE: §32.5's verbatim `${ process(~) }`; `~` read
with no init; double-init without consumption; init never consumed at scope exit;
double-init in a function body; and §17.6.6's partial-`if` example that SPEC says the
compiler SHALL diagnose. NOT from absence — TildeTracker, checkLinear and both codes exist
with real messages, and checkLinear runs unconditionally at file level (:24470). CAUSE NOT
TRACED, and the entry says so rather than guessing: hasNonLiftTildeConsumer gates only
loop-body elision, so the obvious explanation is ruled out without a replacement offered.

That silence is the point. It is why two normative sections could contradict each other
for as long as both have existed without anyone noticing — and it is the S322
re-examination test in its purest form: a normative SHALL delivered by a state-scanning
tracker pass, retrofit rather than by construction, producing exactly the hole that
predicts.

⚑ AND I BANKED dpa-040 IN A FORM THE PROBE COULD NOT READ. I wrote the full
`## [dpa-040]` section into dpa-queue.md — the right FILE per the S319 drain-path rule —
and `dpa-debt.ts` still reported 39 items / 2 UNRUN. The probe reads the status TABLE, not
the per-item sections; the script's own header says reading the per-item `status:` lines
instead "would reproduce the exact obligation/probe mismatch this file exists to close."
Adding the table row moved it to 40 / 3 UNRUN. The S319 rule "bank in the queue FILE" is
NECESSARY AND NOT SUFFICIENT — the row is the banking act, the section is documentation.
Self-inflicted, same base §10 class as the rest of this session, and caught only because
the probe was RUN rather than assumed.

dpa-040 asks whether an arm body should be a `~` CONTEXT BOUNDARY in its own right (§32.4,
beside `${}` contexts and function bodies) — under which the conflict cannot recur by
construction rather than by carve-out. Constraints recorded so the DD cannot drift:
`~`-as-lin is NOT on the table (the boundary SET is the question); adding a boundary is the
LIMIT direction but is semantics-changed and owes a MEASURED migration; and corpus-zero is
blast radius ONLY, never demand evidence (bryan, S346).
@bryanmaclee
bryanmaclee force-pushed the continuity/s395-tilde-ruling branch from 4bd0e7a to e39b980 Compare September 2, 2026 20:33
…-[2035] concurrently

The cloud `gate` caught this, not me: step 14, the delta-log sequence gate. S396-peter's
#821 and this branch independently appended [2033]-[2035] while both sessions were live,
and a rebase does not reconcile sequence numbers — it just stacks both.

⚑ WHY A DUPLICATE IS NOT COSMETIC: the flogence bridge uses the sequence as a CHECKPOINT
CURSOR, so the second entry to merge is skipped as already-absorbed and DROPS OUT of the
digest entirely. A silent single-entry loss, invisible on both sides.

`delta-lint --fix` renumbers later occurrences in file order — and its own warning is the
load-bearing part: "check by hand that the renumbered side is YOURS — renumbering an entry
another repo has already checkpointed drops it from THAT repo's digest." Checked: peter's
#821 is already MERGED and therefore published, so his [2033]/[2035]/[2036] keep their
numbers and mine moved to [2037]+. The renumbered side is the unpublished one. Correct.

Gate now PASS — 1746 entries, 1737 distinct, max [2039]; the 9 baselined historical
duplicates are unchanged known debt.
@bryanmaclee
bryanmaclee merged commit 38b0636 into main Sep 2, 2026
2 of 3 checks passed
@bryanmaclee
bryanmaclee deleted the continuity/s395-tilde-ruling branch September 2, 2026 20:59
bryanmaclee added a commit that referenced this pull request Sep 3, 2026
…at `/` — one gated path now, not two (#823)

* fix(§52.13): `scrml dev` served a protected document unauthenticated at `/` — one gated path now, not two

Closes g-dev-root-path-fallback-serves-a-protected-document-unauthenticated (HIGH, security).
Ruling 2b (bryan, user-voice S395 "your recs"): limb (b). Ruling to SPLIT the §52.13
case variant into its own arc (bryan, "your rec").

THE LEAK. `scrml dev` served an auth="required" document's rendered content to an
unauthenticated `GET /` whenever the protected document was not named index.html.
PA-reproduced two-sided: entry secure.scrml → `GET /` 200 with SECRET DASHBOARD in the
body; entry index.scrml (the control) → 302 both before and after. The leak reproduced on
BOTH root-resolution paths — the single-input entry candidate and the sorted-readdir scan.

THE FIX IS A DELETION. `registeredProtectedDocs` was read at exactly one place, inside the
gated candidate loop; the `pathname === "/"` branch sat AFTER that loop and returned HTML
from two paths, neither consulting the gate. dev.js:1027 ALREADY folded `/`→/index.html
into the loop's candidates (which is why the index.scrml control gated correctly), so the
defect was an ADDITIONAL ungated branch, not a missing fold. Deleted it; `/`'s candidates
moved into the one gated loop. Two serving paths → one. Net on compiler/src: +94/-61.

⚑ WHAT WAS MEASURED AND THEN NOT SHIPPED. Literal deletion of the root candidates took
`scrml dev app.scrml` from 200 to 404 at `/` — and `/` is the ONLY URL dev prints — while
stranding resolveRootEntryCandidate as dead code still covered by its own tests. Per the
brief's STOP clause the agent measured, refused, and reported instead of shipping it.

⚑ AND WHAT WAS SPLIT BACK OUT, RULED. Making §52.13's case variant filesystem-independent
requires gating on the REQUEST PATH — necessarily a SECOND place that decides protection,
because it cannot know what the resolution loop would pick. Three adversarial rounds found
three distinct divergences (answering for absent documents; hijacking a request the loop
would serve publicly; ignoring candidate resolution priority), each fix converging the
pre-gate toward BEING the loop. That reintroduced the exact shape ruling 2b chose limb (b)
to remove — FORK RULE row 4, "(b) removes a second code path". bryan ruled SPLIT. The
pre-gate is gone, mustExistIn and the {guard, rel} registry value went with it, and the
JSDoc at :214 became true again by reversion rather than by editing.

⚑ THE SPLIT CLOSED A DEV/PROD DIVERGENCE RATHER THAN OPENING ONE, which is stronger than
the ruling claimed: build.js:541 also gates on relative(SERVE_DIR, candidate).toLowerCase()
— the resolved file, not the request path. Dev now matches prod's model exactly.

VERIFICATION.
- Two-sided leak control, PA-run by executing the new tests against base dev.js:
  `GET /` leaked=TRUE at base, 302 on the fix. Not asserted — executed.
- Structural guard PA-verified to BITE: module-wide (so extracting serving into a helper
  cannot make it vacuous), expects exactly 2 `return new Response(injectHotReloadScript(`
  sites with the reason stated for each, and reports "expected 2, received 4" against main.
- commands suite 256 pass / 0 fail — the suite that runs in NO blocking job on any
  platform, which is precisely how a §52.13 assertion sat silently RED on Linux for
  months. Full suite vs base: one removed, zero added; the removed entry is that assertion.
- 9-scenario root-path ordering byte-identical; prod entry re-emitted byte-identical;
  compiler/src diff vs origin/main is dev.js alone.

⚑ A HAZARD IN THE PA'S OWN INSTRUCTION, CAUGHT BY THE AGENT. I directed `test.failing` on
the knowingly-red case-variant test. `.failing` passes when the body fails for ANY reason,
so that would have MASKED A LEAK: if `/SECURE.html` ever returned the markup,
`expect(leaked).toBe(false)` fails and `.failing` swallows it as expected. Split instead
into a HARD test asserting the platform-invariant half (never leaks, whatever status) and
a `.failing` test carrying only the genuinely-unruled STATUS. The durable form, recorded:
a mechanism that makes a red acceptable also makes a red invisible — every time you
suppress a signal, check what else was riding on it.

FILED, NOT FIXED — a new HIGH, PA-verified byte-identical on origin/main so pre-existing:
loadServerRoutes catches an import() failure with console.error + continue, so a
.server.js that fails at module-init never registers its guard and the auth="required"
document is then served IN FULL, unauthenticated (agent-reproduced twice: an appended
throw, and a duplicate-declaration syntax error). This falsifies "fail-open is gone by
construction"; the invariant is narrowed to "every path that RESOLVES a serve-dir document
passes the gate". Fix direction recorded: fail CLOSED on a module-load error — "unknown"
must not resolve to "public".

Base-drift filtered: the agent's branch predates #820/#822, so a wholesale pull would have
reverted docs/changes/s395-runanchored-continue/, known-gaps.md, delta-log.md and
dpa-queue.md. Verified 0 such paths staged.

provenance: ruling:user-voice-scrml.md S395 — "your recs" (limb b) + "your rec" (the split)
Agent branch: worktree-agent-a21f5afd26f7c6d3c @ 7c1fbf86

* chore(facts): regen after the dev-root auth-gate landing
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