fix(§52.11): E-AUTH-005 no longer over-fires on a multi-file page - #770
fix(§52.11): E-AUTH-005 no longer over-fires on a multi-file page#770bryanmaclee wants to merge 3 commits into
Conversation
This is blocking a downstream consumer right now — with a clean A/Bflint's
A/B on identical source, same machine, same minute
Same One thing that is not a regressionThe 4 warnings on Standing caveat from the PR bodyThe gate still has not been re-run against current 🤖 Generated with Claude Code |
`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>
0dc1b44 to
840eb5a
Compare
Correction — retracting "blocking right now"My previous comment's headline claim is no longer true, and I want that on the record A concurrent flint session landed The port's gate is now exit 0, zero warnings against What survives, and what it's worthThe removal was decided on g8/g9 grounds, not on this PR's — server cells were dropped A consumer routing around a compiler diagnostic is still evidence the diagnostic bites. It is One wording note, not a misunderstanding
To be fair to that session: its own records are precise. Noting it for the rebase note, not as a correction to anyone's understanding. 🤖 Generated with Claude Code |
E-AUTH-005over-fired on a multi-file page: a legitimate<db src=>server context was notrecognised, so every
<var server>in a page file tripped the auth gate.The bug
hasProgramDbAttr(fileAST)searched only the current file's AST for a<program>node carryingdb=. Under the canonical v0.3 multi-file layout (§40.8 / S85 Q2) exactly one<program>exists andit lives in the entry file — page and component files carry none. So the predicate returned
falsefor every page, and the remedy the diagnostic suggests is unreachable:There is no enclosing
<program>to adddb=to. Adding it to<page>does not help either —db=is in the parser's
PAGE_ALLOWED_ATTRSbut not the attribute registry, so it warnsW-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 madeserver-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 wasreading a file-local proxy rather than the normative property.
The change
8e53414bfix(§52.11)—hasServerContext=<program db=>or<db src=>ddeff2c8test(§52.11)— conformance case + unit test for the<db src=>shape840eb5a1docs(facts)— FACTS.md regenerated (derived counts only)Shape 2 delegates to a new
fileHasDbStateContextincodegen/collect.ts, keyed on the sameForm-2 AST shape (
kind:"state",stateType:"db") thatcollectDbScopesuses to build the file'sreal SQL connections — so the predicate agrees with what codegen actually emits rather than restating
it as a parallel list.
hasProgramDbAttrhad exactly one caller; the blast radius is contained.Verification (re-run on the rebased base)
unit+integration+conformance, 1,246 files:22,495 pass, 0 fail. Not bypassed.
467751bbadded.No new upstream case asserts the error in a shape this silences.
auth/auth-005-db-context-negA/B verified to discriminate: firesE-AUTH-005beforethe fix, compiles exit 0 with zero diagnostics after.
a8448ac9: a multi-file page with<var server>compiles exit 0.bun test compiler/tests/are outside the gate (52browser/, needsPlaywright; 2
e2e-render-mapthe runner labels non-gating) and were A/B confirmed identical onthe unmodified base in a worktree.
docs/FACTS.mdwas 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:W-AUTH-001<x server> = []+on mount { @x = load() }(Pattern B)on mountsix lines below<x server> = load()(callable init)§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-005was incidentally limiting the blast radiusof
g-server-cell-init-leaks-const-to-client-reactive-wiring(HIGH, open), and that merging thiswould 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 appclause. That confirmation was subsequently done. The S361 dedup note on thesame page records the result:
So the leak reproduces without
E-AUTH-005firing. It is not gated by this check, this PR does notwiden 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(
isServerOnlyNodenever classifies anisServer===truestate-declas 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/websiteinto scrml (flintthreads/syntax-fm-port), where itblocked every page from declaring a server-authoritative cell. Written 2026-08-23; rebased and
re-verified 2026-08-30.
🤖 Generated with Claude Code