Skip to content

runtime publish gate: the snapshot collection set is hand-listed in five places and only one of them can go red #13390

Description

@claude

Observation

The set of collections the runtime publish gate carries in a per-write snapshot is written down in four places, and only two of them are held to each other by the compiler:

site file guard today
RuntimeStackContext packages/lint/src/runtime-gate.ts the declaration
CONTEXT_STACK_KEYS packages/lint/src/runtime-gate.ts satisfies readonly (keyof RuntimeStackContext)[] — validity, not completeness
NAME_KEYED_STACK_KEYS packages/lint/src/runtime-gate.ts none
CLOSURE_CONTEXT_KEY_BY_TYPE packages/metadata-protocol/src/runtime-authoring-gate.ts a satisfies clause over a record keyed by RuntimeStackContext keys — validity, not completeness

NAME_KEYED_STACK_KEYS is the one with no guard at all, and it carries a real invariant: a collection that the CONTEXT fills and that some write type maps into (TYPE_TO_STACK_KEY) must be name-keyed, or a finding's path is a positional index into an in-memory snapshot the caller has never seen and cannot enumerate — the defect #10064 fixed for objects / permissions / books.

The invariant is currently satisfied. What is missing is anything that keeps it satisfied: the correct membership is derivable (CONTEXT_STACK_KEYS intersected with the values of TYPE_TO_STACK_KEY), and the list is hand-maintained instead.

How it surfaced

While adding the pages collection for the page-view mount work, pages had to be added to CONTEXT_STACK_KEYS, to NAME_KEYED_STACK_KEYS, to TOP_LEVEL_INDEX's alternation, to CLOSURE_CONTEXT_KEY_BY_TYPE, and to a hand-listed accumulator literal in packages/metadata-protocol/src/protocol.ts. Only the last of those five announced itself — it was the one the compiler could see, and only after the accumulator was retyped as a mapped type over RuntimePendingDeclarations. The other four were found by reading, and NAME_KEYED_STACK_KEYS in particular would have gone unnoticed: forgetting it produces correct-looking findings with paths the caller cannot resolve, and no test or gate would have gone red.

TOP_LEVEL_INDEX (a regex alternation of the same names) is a fifth spelling of the same set, one line below NAME_KEYED_STACK_KEYS.

Suggested direction (not a decision)

Derive NAME_KEYED_STACK_KEYS and TOP_LEVEL_INDEX from CONTEXT_STACK_KEYS and TYPE_TO_STACK_KEY rather than listing them, so the invariant holds by construction; keep the hand-written list only where a deliberate exception needs stating, and state it there. Nothing in this repo is wrong today — this is about what the next widening costs.

Filed unassigned from the #13216 dispatch; not fixed there, because the fix is a refactor of a seam that card only widens by one key.


Generated by Claude Code


Generated by Claude Code

Metadata

Metadata

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions