Skip to content

fix(§52.11): E-AUTH-005 no longer over-fires on a multi-file page - #770

Open
bryanmaclee wants to merge 3 commits into
mainfrom
fix/e-auth-005-multifile-page-server-context
Open

fix(§52.11): E-AUTH-005 no longer over-fires on a multi-file page#770
bryanmaclee wants to merge 3 commits into
mainfrom
fix/e-auth-005-multifile-page-server-context

Conversation

@bryanmaclee

@bryanmaclee bryanmaclee commented Aug 30, 2026

Copy link
Copy Markdown
Owner

E-AUTH-005 over-fired on a multi-file page: a legitimate <db src=> server context was not
recognised, so every <var server> in a page file tripped the auth gate.

Updated 2026-08-30 — REBASED onto current main (a8448ac9) and re-verified. An earlier
version of this description said the branch was based on a0e30329, was 125 commits behind, had
an open docs/FACTS.md conflict, and had not been re-gated. All four are now resolved; the
commit SHAs below are the rebased ones.

The bug

hasProgramDbAttr(fileAST) searched only the current file's AST for a <program> node carrying
db=. Under the canonical v0.3 multi-file layout (§40.8 / S85 Q2) exactly one <program> exists and
it lives in the entry file — page and component files carry none. So the predicate returned
false for every page, and the remedy the diagnostic suggests is unreachable:

error [E-AUTH-005]: 'server @shows' declared in a client-only context. Server-authoritative
variables require a server context. Add db= to the enclosing <program> or move the declaration.

There is no enclosing <program> to add db= to. Adding it to <page> does not help either — db=
is in the parser's PAGE_ALLOWED_ATTRS but not the attribute registry, so it warns W-ATTR-001
("not recognized… has no compile-time effect") and does not satisfy the check. All three diagnostics
fire on the same six lines.

Since §52.4.2 pt 5 makes <var server> the only route to an SSR-prerendered cell, this made
server-rendered page data structurally unavailable to every multi-file app.

Why it is a spec deviation, not a judgment call

§52.11 states the trigger as a declaration "inside a client-only component (a component with no
server context)"
. A page with a <db src=> block manifestly has a server context. The check was
reading a file-local proxy rather than the normative property.

The change

commit what
8e53414b fix(§52.11)hasServerContext = <program db=> or <db src=>
ddeff2c8 test(§52.11) — conformance case + unit test for the <db src=> shape
840eb5a1 docs(facts) — FACTS.md regenerated (derived counts only)

Shape 2 delegates to a new fileHasDbStateContext in codegen/collect.ts, keyed on the same
Form-2 AST shape
(kind:"state", stateType:"db") that collectDbScopes uses to build the file's
real SQL connections — so the predicate agrees with what codegen actually emits rather than restating
it as a parallel list. hasProgramDbAttr had exactly one caller; the blast radius is contained.

Verification (re-run on the rebased base)

  • Pre-commit gate green on every commitunit + integration + conformance, 1,246 files:
    22,495 pass, 0 fail. Not bypassed.
  • 43 auth tests pass on the rebased base, alongside the E-AUTH-005 coverage 467751bb added.
    No new upstream case asserts the error in a shape this silences.
  • New case auth/auth-005-db-context-neg A/B verified to discriminate: fires E-AUTH-005 before
    the fix, compiles exit 0 with zero diagnostics after.
  • Behavioural re-check on a8448ac9: a multi-file page with <var server> compiles exit 0.
  • Failures in a broader bun test compiler/tests/ are outside the gate (52 browser/, needs
    Playwright; 2 e2e-render-map the runner labels non-gating) and were A/B confirmed identical on
    the unmodified base
    in a worktree.
  • docs/FACTS.md was resolved by regenerating, not hand-merging. Delta is exactly this branch:
    +67 lines of compiler source, +1 conformance case.

What this does NOT do

It removes the false rejection only. The declaration now compiles; the data is still not
server-rendered. Measured on the fixed compiler against a seeded DB — both shapes leave the SSR
payload empty and emit no __mountHydrate, though §8.11 says one SHALL be emitted:

shape W-AUTH-001 SSR payload
<x server> = [] + on mount { @x = load() } (Pattern B) fires, with the on mount six lines below empty
<x server> = load() (callable init) silent — correctly classified empty

§52.4.2 pt 5's SSR pre-render emission appears simply unimplemented, consistent with
examples/18-state-authority.scrml's own header ("scaffold-only"; Tier 1 not end-to-end "either").
Separate, larger surface — not addressed here.

The g9 interaction — checked, and it does NOT block this

An earlier revision of this body argued that E-AUTH-005 was incidentally limiting the blast radius
of g-server-cell-init-leaks-const-to-client-reactive-wiring (HIGH, open), and that merging this
would remove that barrier. That was wrong, and it was wrong off a superseded caveat. Retracting it
here rather than leaving it to argue against a correct fix.

The quoted caveat is the S300-era text, including its own needs confirmation in a fully server-contexted app clause. That confirmation was subsequently done. The S361 dedup note on the
same page records the result:

Both re-verified LIVE on HEAD S361 (a <apiKey server> = API_SECRET ships the secret value into
the client reactive store, no E-AUTH-005 on the confidentiality axis).

So the leak reproduces without E-AUTH-005 firing. It is not gated by this check, this PR does not
widen its reach, and the two do not need to land together. The S361 note also dedups it against
g-server-cell-init-leaks-const-to-client-reactive-wiring's twin — one defect, one root
(isServerOnlyNode never classifies an isServer===true state-decl as server-only,
emit-reactive-wiring.ts:504) — to be co-resolved on its own lane, independently of this.

Reading the S300 caveat without its S361 answer is the corpus-staleness failure in miniature: the
caveat is still on the page, still phrased as open, and the sentence that closes it is 7,000 lines
further down.

Provenance

Surfaced by a 1:1 port of syntaxfm/website into scrml (flint threads/syntax-fm-port), where it
blocked every page from declaring a server-authoritative cell. Written 2026-08-23; rebased and
re-verified 2026-08-30.

🤖 Generated with Claude Code

@bryanmaclee

Copy link
Copy Markdown
Owner Author

This is blocking a downstream consumer right now — with a clean A/B

flint's syntax-fm-port thread gates on scrml compile src/. That gate was exit 0 at
flint's 2026-08-30 wrap (06:46). The global scrml install was rebuilt from main at 07:26.
The gate is now exit 1, on this exact diagnostic:

error [E-AUTH-005]: 'server @shows' declared in a client-only context.
  --> src/pages/shows.scrml:36:7
     36 |       <shows server> = fetchShows()
  stage: TS

src/pages/shows.scrml is a page in a multi-file program — precisely the over-fire shape
this PR fixes.

A/B on identical source, same machine, same minute

compiler errors warnings exit
main @ a8448ac9 (installed) 1E-AUTH-005 4 1
this branch @ 0dc1b449 (worktree) 0 0 0

Same src/, no edits between runs. The fix branch compiles the port clean in 172.7ms, 5 files.

One thing that is not a regression

The 4 warnings on main are all W-TYPE-031-UNPROVEN, a diagnostic class introduced after
this branch's base by 43eea9aa (feat(§7.5/§14.7): the asIs/unknown split). That is new
information working as designed, and it is flint's to act on — not a defect in this PR and not
an argument for merging it. Flagging it so the zero-warning column above isn't misread as this
branch being better; it is only older.

Standing caveat from the PR body

The gate still has not been re-run against current main — the A/B above tests this
branch's compiler as-is, not a rebase. The docs/FACTS.md conflict wants a regenerate.

🤖 Generated with Claude Code

https://claude.ai/code/session_01PtVTCRUDLQAE6rEVBG8Swo

bryanmaclee and others added 3 commits August 30, 2026 08:51
`hasProgramDbAttr(fileAST)` searches only the CURRENT file's AST for a
`<program>` node carrying `db=`. Under the canonical v0.3 multi-file layout
(§40.8 / S85 Q2) exactly one `<program>` exists and it lives in the ENTRY
file — page and component files carry none. So the predicate returned false
for every page, and every `<var server>` in a multi-file page fired
E-AUTH-005, with a remedy ("add db= to the enclosing <program>") that the
layout makes unreachable.

SPEC §52.11 states the trigger as a declaration "inside a client-only
component (a component with no server context)". A page with a `<db src=>`
block manifestly HAS a server context, so the check was reading a
file-local proxy rather than the normative property.

Adds `fileHasDbStateContext` to codegen/collect.ts — keyed on the same
Form-2 AST shape (`kind:"state"`, `stateType:"db"`) that `collectDbScopes`
uses to build the file's real SQL connections, so the predicate agrees with
what codegen emits rather than restating it. `hasServerContext` is now the
disjunction of the two shapes and is what the check consults.

Scope: contained. `hasProgramDbAttr` had exactly one caller.

Surfaced by the syntaxfm/website port (flint/threads/syntax-fm-port), where
it blocked every page from declaring a server-authoritative cell. NOTE: this
removes the false rejection only — §52.4.2 pt 5 SSR pre-render of such cells
is a separate, still-unimplemented surface; a fixed page compiles but its
data is still not in the SSR payload.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Adds the third shape to the AUTH-005 coverage. auth-005-pos (no server
context -> fires) and auth-005-neg (`<program db=>` -> silent) both exercise
single-file `<program>` shapes; neither would catch a regression to a
`<program>`-only search, which is exactly the bug dfe1763 fixed.

  conformance/cases/auth/auth-005-db-context-neg/ — a file with NO <program>
  at all but WITH a <db src=> block. Verified to discriminate: fires
  E-AUTH-005 on a0e3032, compiles exit 0 with zero diagnostics on the fix.

  compiler/tests/conformance/conf-AUTH-005.test.js — the matching unit test,
  plus a header note correcting the stale "hasProgramDbAttr" reference and a
  stale line number.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Derived counts only, per the pre-push generated-docs gate:
  live compiler source  241,956 -> 242,023 lines (collect.ts + type-system.ts)
  conformance cases     883 -> 884 (auth/auth-005-db-context-neg)

Test-file count is unchanged — conf-AUTH-005.test.js was extended, not added.
SPEC.md untouched, so regen-spec-index.ts reports 0 rows updated.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@bryanmaclee
bryanmaclee force-pushed the fix/e-auth-005-multifile-page-server-context branch from 0dc1b44 to 840eb5a Compare August 30, 2026 14:55
@bryanmaclee

bryanmaclee commented Aug 30, 2026

Copy link
Copy Markdown
Owner Author

Correction — retracting "blocking right now"

My previous comment's headline claim is no longer true, and I want that on the record
rather than sitting there misleading a reviewer.

A concurrent flint session landed ed582bc at 08:57 today — after I ran that A/B and after
I posted it. It removed <var server> from every page in the port:

// CLIENT-LOCAL, deliberately.  `<shows server>` buys nothing today
// (g8: no SSR emission) and costs something real (g9: a server cell's
// initialiser ships into the client bundle).
<shows> = []

The port's gate is now exit 0, zero warnings against main's compiler. Nothing is
blocked. Retract the urgency; the measurement itself stands — it was accurate on the
source as it stood when I ran it, and that source shape no longer exists.

What survives, and what it's worth

The removal was decided on g8/g9 grounds, not on this PR's — server cells were dropped
because SSR pre-render is unimplemented and a server cell's initialiser ships client-side.
E-AUTH-005 was not the reason. So this remains a real over-fire with a real fix and no
upstream equivalent — but it is now unblocking nobody, and should be prioritised as an
ordinary correctness fix rather than anything urgent. Merge it, defer it, or close it on its
own merits.

A consumer routing around a compiler diagnostic is still evidence the diagnostic bites. It is
not evidence anyone is waiting.

One wording note, not a misunderstanding

ed582bc's commit message compresses this to "g7 … is FIXED upstream in scrml dfe17636",
which reads as merged. It isn't — dfe17636 is this PR's head commit.

To be fair to that session: its own records are precise. progress.md states "Our fix is NOT
merged
git merge-base --is-ancestor dfe17636 main says NO. It is 125 commits behind and will
need a rebase", and flags 467751bb on main as possible rebase overlap worth checking first. The
source comment carries the same qualification. Only the commit-message shorthand and one
✅ FIXED UPSTREAM badge in gaps.md read stronger than the facts behind them.

Noting it for the rebase note, not as a correction to anyone's understanding.

🤖 Generated with Claude Code

https://claude.ai/code/session_01PtVTCRUDLQAE6rEVBG8Swo

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