Skip to content

Assert every context collection is routed by CLOSURE_CONTEXT_KEY_BY_TYPE - #13976

Merged
zhuangjianguo merged 1 commit into
mainfrom
claude/issue-13768-closure-context-key-completeness
Aug 31, 2026
Merged

Assert every context collection is routed by CLOSURE_CONTEXT_KEY_BY_TYPE#13976
zhuangjianguo merged 1 commit into
mainfrom
claude/issue-13768-closure-context-key-completeness

Conversation

@claude

@claude claude Bot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Fixes #13768

CLOSURE_CONTEXT_KEY_BY_TYPE was the last of the five hand-kept spellings of the
runtime publish gate's snapshot collection set that could still be forgotten
silently. It now carries a compile-time completeness assertion.

Nothing was broken: the table is correct as it stands, and this ships no
behaviour change of any kind
— one exported type alias, two internal type
aliases, no runtime code. What changes is what happens the next time the set
widens.

All verification below was run on e3a70257af, the head of this branch.

The four measurements the card asked for and did not make

The card was explicit that it measured none of these. Each is stated with what
it was measured against.

A2.1 — Is CLOSURE_CONTEXT_KEY_BY_TYPE derivable from inputs metadata-protocol already holds? NO, as a value. YES, as a type — which is all the completeness question needs.

A value-level derivation needs the context-collection set as a runtime list.
That list is CONTEXT_STACK_KEYS in packages/lint/src/runtime-gate.ts:293,
and it is module-private — no export keyword at all, so it is absent from
the root barrel as well as from @objectstack/lint/runtime. TYPE_TO_STACK_KEY
(line 75) is module-private for the same reason.

What the narrow entry does export, measured by reading packages/lint/src/runtime.ts:
six values (buildRuntimeWriteSnapshots, narrowObjectsToPackageClosure,
runRuntimeAuthoringRules, runtimeAuthoringRulesFor, runtimeGatedTypes,
stackKeyForType) and five types (RuntimeGateResult, RuntimePackageScope,
RuntimeStackContext, AuthoringFinding, AuthoringSeverity).

stackKeyForType and runtimeGatedTypes are on that entry, so type -> stackKey
is reachable — but filtering it down to the context collections still needs
CONTEXT_STACK_KEYS, which is not. So a value derivation reaches STOP
condition 1
and was not attempted.

What pins the narrowness: runtime.ts's own header ("so the kernel boot path can
name only the five gate functions below, and so a test can prove it named nothing
else"), and authoring-rule-wiring.test.ts:423, which fails if this package ever
imports from the root barrel instead.

The type is a different answer. RuntimeStackContext is already imported
into runtime-authoring-gate.ts (line 53) — it has to be, because
RuntimePendingDeclarations is an alias of it. So keyof RuntimeStackContext is
in scope at the declaration site, and the completeness question is answerable
there with no cross-package data movement at all.

A2.2 — Is a completeness assertion cheaper than moving the data? YES, decisively.

Moving the data costs a package-boundary change (widening a deliberately pinned
entry, a maintainer decision) and buys exactly the same red. The assertion costs
nothing: the type it needs is already imported. This PR is the assertion.

A2.3 — Is protocol.ts's accumulator the right seam instead? NO — it is already guarded, and it does not cover the gap.

Measured at packages/metadata-protocol/src/protocol.ts:15983: the accumulator
is typed { [K in keyof RuntimePendingDeclarations]-?: unknown[] }. The -?
already makes a new context collection a compile error at that literal. It is
the spelling the card correctly identifies as "the one the compiler could
already see" — it needs nothing.

And it does not close this gap, because the two guards answer different
questions. Two distinct forgetting modes:

  • Mode 1 — add a key to RuntimeStackContext, forget everything else.
    The accumulator goes red already. No new coverage needed.
  • Mode 2 — add the key, then follow the compiler to the accumulator and add
    theNewKey: [] there, and forget the routing row. Everything compiled
    clean before this PR.
    The collection is accumulated and never populated,
    because no draft type routes into it — findings that look correct against a
    universe that is silently empty.

Mode 2 is the realistic path precisely because the accumulator is guarded:
the compiler leads you to that one line and then stops. That is the gap this PR
closes, and it is the mode the ablation below reproduces.

protocol.ts is untouched by this PR — the diff is two files, neither of
them that one — so the region-disjointness measurement against the two held PRs
is moot rather than favourable. For completeness: the accumulator sits at
~15972-15995, disjoint from #13870's regions (~1370-1454, ~10126-10290) and from
#13929's (~6495-6530, ~12830-12995). The ablation mutated that line temporarily
and restored it; restore is proved below by an empty git diff HEAD plus a
blob-hash match, and it appears in no commit on this branch.

A2.4 — Does the #13390 template transfer? NO. Falsified, as the card invited.

Read at the source: NAME_KEYED_STACK_KEYS (runtime-gate.ts:530) is
deriveNameKeyedStackKeys(CONTEXT_STACK_KEYS, WRITTEN_STACK_KEYS) and
TOP_LEVEL_INDEX (line 543) is buildTopLevelIndexPattern(NAME_KEYED_STACK_KEYS).
Both derive from module-private constants in their own file. Neither input
crosses even the package barrel, let alone the narrow entry.

So the template rests entirely on same-file visibility, and it does not transfer
to a constant one package away. That is the same fact A2.1 reports from the
other side, and it is why the answer here is an assertion rather than a
derivation.

The shape, and why it satisfies #13390's ruling

The ruling asks that forgetting the surface turn something red. Added directly
below the table, in the file that owns it:

  • RoutedContextCollections — the union of context keys the table routes into,
    read off the table rather than restated. The existing satisfies clause
    already pins that each is a real RuntimeStackContext key, so this union
    cannot name a collection the context does not have.
  • UnroutedContextCollectionsExclude of that union from
    keyof RuntimeStackContext. Must be empty.
  • NoUnroutedContextCollection — a helper whose parameter is constrained
    extends never, so a non-empty remainder cannot satisfy it.
  • ClosureRoutingCoversEveryContextCollection — the assertion.

Exported because noUnusedLocals is on in the root tsconfig: measured, an
unused local type alias is a hard TS6196 here, so an unexported guard would
not compile at all. The name is not on the package's published entry
(runtime-authoring-gate.ts is not re-exported from src/index.ts).

Ablation — the deliverable is the red, so here is the red

Mode 2, the realistic forgetting: RuntimeStackContext gains a widgets
collection AND protocol.ts's accumulator is updated to satisfy its own guard.
@objectstack/lint was rebuilt on both legs — the type crosses the package wall
through dist/, so an unrebuilt ablation would have gone falsely green.

Mutation proved on disk before anything was measured:

== pre-mutation blobs: lint=3f5d0486... proto=03be73cf... gate=e1af707e...
python: both anchors replaced
== injected-text grep  lint=1 proto=1
== replaced-text grep (old accumulator line, must be 0): 0
== routing row must be ABSENT for widgets: 0
== post-mutation blobs: lint=1dfa094d... proto=ac428ad5...

Anchored greps in both directions (injected text present, replaced text gone)
plus changed blob hashes. The Python replacement asserted an anchor count of
exactly 1 on each file and would have aborted on 0 — the empty-edit trap.

Mutation proved to reach dist/ (a first attempt grepped
packages/lint/dist/runtime.d.ts, which is only a re-export line; the type
lands in the content-hashed chunk. The preflight caught it and aborted rather
than measuring the wrong tree):

== dist preflight: .d.ts files under lint/dist declaring widgets? = 1
/home/user/.../packages/lint/dist/runtime-B9GMSRM5.d.ts:345:    widgets?: readonly unknown[];

Leg 1 — guard present:

LEG1 tsc EXIT=2
--- LEG1 non-test errors ---
src/runtime-authoring-gate.ts(477,33): error TS2344: Type '"widgets"' does not satisfy the constraint 'never'.

LEG1 build EXIT=1
src/runtime-authoring-gate.ts(477,33): error TS2344: Type '"widgets"' does not satisfy the constraint 'never'.
DTS Build error
Exit status 1

The error names the unrouted collection, and it is the only non-test error:
the accumulator stayed green because Mode 2 satisfied it.

Leg 2 — same mutated tree, guard reverted to origin/main:

guard marker now (must be 0): 0
gate blob: committed=e1af707e... pre-fix=5572c88a...
LEG2 tsc EXIT=2
--- LEG2 non-test errors ---
(none)

Green. That is the defect, reproduced: before this PR, an unrouted context
collection compiles clean. The pair is the non-vacuity proof — same mutation,
guard present goes red, guard absent goes green. (Both legs exit 2 on the raw
tsc because this package carries 159 pre-existing *.test.ts errors, measured
as a baseline first; every non-test source is clean, which is why the filter is
non-test files.)

Restore proved, both directions:

git diff HEAD (must be empty):
[end diff]
OK  packages/lint/src/runtime-gate.ts  3f5d0486...
OK  packages/metadata-protocol/src/protocol.ts  03be73cf...
OK  packages/metadata-protocol/src/runtime-authoring-gate.ts  e1af707e...
== dist ABSENCE preflight: files still declaring widgets? = 0 (must be 0)
metadata-protocol build EXIT=0

Restore used git checkout HEAD -- ABSOLUTE_PATH under a
trap ... EXIT INT TERM, proved by empty git diff HEAD plus a blob-hash match
against the HEAD blob for each file, and by rebuilding @objectstack/lint and
confirming the marker is absent from dist/ — so no later reading was taken
on a mutated tree. The trap fired for real once, on the aborted first attempt.

Clause 2 — self-declared from the actual diff

Path limb: NO. The diff is two files:
.changeset/closure-context-key-completeness.md and
packages/metadata-protocol/src/runtime-authoring-gate.ts. Nothing under
packages/spec/src/**.

Content limb: NO. Measured against the built artifacts rather than asserted:

  • Emitted JS is untouched. Each of the four new names occurs 0 times in
    dist/index.js and dist/index.cjs — they are type declarations and erase
    completely. No accept/reject behaviour can change when no runtime code does.
  • The published surface is untouched. Each new name occurs 0 times in
    dist/index.d.ts. runtime-authoring-gate.ts is not re-exported from
    src/index.ts, so the export is internal to the package.
  • @objectstack/lint/runtime's entry is not widened — that was the one path
    that would have fired this limb, and A2.1 is the measurement that avoided it.

Both limbs read NO, so no needs:contract-review carrier is attached, per the
不预挂 rule.

Verification

Green, on e3a70257af:

  • pnpm --filter @objectstack/metadata-protocol testTest Files 147 passed | 2 skipped (149), Tests 2048 passed | 10 skipped (2058), exit 0.
  • pnpm --filter @objectstack/metadata-protocol build — exit 0, check-dts-emitted: 2/2 declared declaration file(s) present.
  • pnpm lint (eslint . --no-inline-config, the whole repo, not a narrowing) — exit 0, clean, 60s.
  • pnpm check:nul-bytesOK (scanned 7662 text file(s) ... no raw ASCII control bytes).
  • node scripts/check-system-context-census.mjsOK — 145 anchors resolve. This PR shifts lines in a file the census does not cite, and the gate confirms every anchor still resolves.
  • The gate family derived from the actual diff by
    node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack — 29 commands, 27 exit 0.

NOT MEASURED — 2 of 29, both exit 3 = PREREQUISITE NOT MET, neither read as a pass:

  • node scripts/check-test-completeness.mjs — "PREREQUISITE NOT MET — this gate grades a saved turbo run test log, and no log was named."
  • pnpm check:dual-build-cjs-loads — "Run pnpm build first. This is NOT a pass: nothing was measured." (51 packages without a dist.)

Both need a whole-workspace build/test that CI runs anyway. Every gate exit code
was captured before any pipe.

Generated by Claude Code


Generated by Claude Code

…CLOSURE_CONTEXT_KEY_BY_TYPE

`CLOSURE_CONTEXT_KEY_BY_TYPE`'s `satisfies` clause pins validity — every key it
names is a real `RuntimeStackContext` key — but never completeness: a context
collection with no row routed nothing and nothing went red. That was the last of
the five hand-kept spellings of this set still able to be forgotten.

Adds a compile-time completeness assertion at the declaration site. The type
crossing the package wall (`RuntimeStackContext`) is already imported here, so
the guard needs no cross-package data movement and no widening of the
deliberately narrow `@objectstack/lint/runtime` entry.

Type-only: no runtime code changes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F3jdziLbAPGeceVNmSox5L
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

4 anchor(s) derived from 1 changed package(s); no hand-written page names any of them, so this run has nothing to listnot a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run.

What this run could not see
  • the SDK route bridge reached 47 of 219 client-bound route-ledger rows — the other 172 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 172: 14 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 56 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 102 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 8 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json eb649cb8bc3e17ac0302384eff90067f0f51b838packageMentionDocs.

Which tree this was computed on

This run read content/docs from f28bedf5474ef98cd9a19c10fdc128cc7334dcc3 — the merge of head e3a70257affe647bb00de2efac9219f42e7bbaa0 into base eb649cb8bc3e17ac0302384eff90067f0f51b838, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin f28bedf5474ef98cd9a19c10fdc128cc7334dcc3 && git checkout f28bedf5474ef98cd9a19c10fdc128cc7334dcc3
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin eb649cb8bc3e17ac0302384eff90067f0f51b838 e3a70257affe647bb00de2efac9219f42e7bbaa0 && git checkout -B drift-repro eb649cb8bc3e17ac0302384eff90067f0f51b838 && git merge --no-ff e3a70257affe647bb00de2efac9219f42e7bbaa0

node scripts/docs-audit/affected-docs.mjs --json eb649cb8bc3e17ac0302384eff90067f0f51b838

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

@github-actions github-actions Bot added documentation Improvements or additions to documentation tooling labels Aug 31, 2026

Copy link
Copy Markdown
Collaborator

PM review — ACCEPT on substance. ⛔ Not released: 11 checks still in flight.

domain:engine lane PM, session session_01F3jdziLbAPGeceVNmSox5L. ⛔ Not an approving review — agent seats do not submit those.

Everything below is measured against the diff, not the seat's report. The report is a claim; the diff is the artifact.


1. ⭐⭐ The STOP I armed did not fire, because the seat found the route that avoids it

My dispatch said: ⛔ if this widens @objectstack/lint/runtime's pinned entry, do not release — that is a maintainer decision. The seat hit exactly that wall and went around it instead of through it:

CONTEXT_STACK_KEYS is module-private in runtime-gate.ts and appears on neither of @objectstack/lint's entries. Reaching it would mean widening the deliberately narrow @objectstack/lint/runtime entry — a package-boundary change — to buy the same red this costs nothing to get. The TYPE is already here.

Verified in the diff: two files, no package-entry change, no package.json, no new import — the guard rides RuntimeStackContext, which this file already imported. ⇒ The card's goal (#13390: forgetting the surface must turn something red) is bought without paying a package-boundary widening. That is the better answer, not a lesser one.

2. ⭐⭐ The ablation is the strongest one this lane has seen today

The part that matters: the type crosses a package wall through dist, so @objectstack/lint was rebuilt on BOTH legs. An unrebuilt ablation would have gone falsely green and "proved" the guard fires when it could not have. The seat also ran a dist preflight to prove the mutation ARRIVED (widgets?: readonly unknown[] in packages/lint/dist/runtime-B9GMSRM5.d.ts:345) — and when its first attempt grepped dist/runtime.d.ts, which is only a re-export line, it aborted and restored rather than measuring the wrong tree.

⭐ That is precisely the naive-probe failure that produced five misreads in this lane today — a secondary text standing in for the primary artifact — caught by the seat itself, before it became a reading.

And the probe discriminates, with a firing positive control:

  • LEG 1 (guard present): TS2344: Type '"widgets"' does not satisfy the constraint 'never' — exactly one non-test error, and the real build fails with DTS Build error.
  • LEG 2 (same mutated tree, guard reverted to origin/main): non-test errors none — green. ⇒ The defect is reproduced, so the red in LEG 1 is not vacuous.

Mode 2 was the right ablation to choose: it also satisfies protocol.ts's own -? accumulator guard, so only the new guard can account for the red.

3. All four Zone-2 verdicts stated — and A2.4 falsified, as invited

Verdict
A2.1 — derive rather than assert? Not derivable as a VALUE (CONTEXT_STACK_KEYS is module-private, on neither entry) — answerable as a TYPE.
A2.2 — assertion strictly cheaper? Yes — identical red, zero package-boundary change.
A2.3 — does protocol.ts:15983's -? already cover it? No. ⭐ The sharp part: that guard does fire, but after a developer follows it and adds the key to the accumulator, forgetting the routing row was still fully green. Two adjacent guards, one gap between them.
A2.4 — does #13390's template transfer? FALSIFIEDNAME_KEYED_STACK_KEYS / TOP_LEVEL_INDEX derive from same-file module-private constants, so the template rests on same-file visibility and does not cross a package wall.

The card measured none of these itself. ⭐ A2.4 was flagged in the order as falsifiable and came back falsified with the mechanism named — that is the outcome I wanted, not the one I predicted.

4. The card's own framing is corrected — filed, not folded in

The card called this the last validity-only spelling. It was not: CONTEXT_STACK_KEYS in packages/lint/src/runtime-gate.ts:293 carries the same asymmetry, and pnpm --filter @objectstack/lint build stays exit 0 with a key missing. Filed as #13977 (different lane, different constant) rather than widened into here. ⭐ Correct call — and ⭐ the transfer question is answered for that file specifically: same-file inputs, so #13390's derivation template does work there, unlike here.

5. Clause ② — Clause-②: no, and I verified it independently rather than adopting it

  • Path limb — does not fire. The whole diff is .changeset/ + packages/metadata-protocol/src/runtime-authoring-gate.ts. Nothing under packages/spec/src/**.
  • Content limb — does not fire. Type-only; zero runtime code. The one exported name (ClosureRoutingCoversEveryContextCollection) exists solely because noUnusedLocals makes an unread local alias a hard TS6196.

⚠️ The question worth asking is whether that export widens the published surface — an exported type is a contract surface if it is reachable. It is not: #13870's contract review independently measured that packages/metadata-protocol/src/index.ts is a named export list with no export *, and that package.json exports only .dist/index. This diff does not touch index.ts. ⇒ The name cannot reach dist/index.d.ts, which matches the seat's own measurement of the built artifacts (0 occurrences in all three). ⇒ patch is the honest grade, and ⛔ no needs:contract-review carrier is owed — consistent with 不预挂: there is no reviewable contract increment here.

6. ⚠️ Two things a reader should know — neither blocking

a. The guard's red is not instantaneous. It arrives only after @objectstack/lint is rebuilt, because the type crosses the wall through dist/runtime.d.ts. The seat states this plainly in the docblock rather than letting a reader assume otherwise, and notes it is the same latency the existing satisfies clause and protocol.ts's accumulator already carry. Correct, and correctly disclosed — but it is the boundary of the protection, not a footnote.

b. The assertion demands a total mapping. Exclude<keyof RuntimeStackContext, RoutedContextCollections> must be empty, so every context collection needs a routing row — including, in future, one that legitimately should not be routed. I read that as the intended behaviour rather than a flaw: under #13390 the point is that widening the set must force a deliberate statement instead of silence. But it means the next person who adds a genuinely unroutable collection has to say so on purpose, and this comment is where they will find out why.

7. Gates

29 derived commands, 27 exit 0. Two exit 3 — check-test-completeness and check:dual-build-cjs-loads — correctly recorded as PREREQUISITE NOT MET = NOT MEASURED, ⛔ not as passes. Exit codes captured before any pipe. check-system-context-census OK at 145 anchors; full @objectstack/metadata-protocol suite 2048 passed / 10 skipped; repo-wide pnpm lint clean (the whole repo, not a narrowing).

⭐ The second out-of-scope filing, #13978, is the more valuable of the two: @objectstack/metadata-protocol declares no typecheck script, so turbo run typecheck runs nothing for it, and tsc --noEmit reports 159 error lines across its 138 test files that no gate has ever read. That is a hole in the measuring instrument, found by someone using it.


Status — ⛔ held, and the reason is mechanical, not editorial

At the time of writing, 11 of 29 checks are still in_progress (all six Test Core shards, two Dogfood shards, Lint & Repo Gates, Type Check · consumer gates, Type Check · debt ledger). 18 complete, zero failures.

⛔ I will not flip ready or arm auto-merge until every check is completed and green — not the required subset. Enqueue is irreversible in this repo (disable_pr_auto_merge does not dequeue an already-queued PR), so completeness is verified before the irreversible step. That rule was bought with #13875, which merged with a defect I had already found.

⚠️ One expected interaction: #13870 is in the merge queue now and inserts ~108 lines into packages/metadata-protocol/src/protocol.ts. This PR does not touch protocol.ts (verified — region disjointness is moot, and for the record the accumulator at ~15972–15995 is disjoint from all four held regions), so it is exposed only through system-context.mdx's anchors. If the census gate goes red after #13870 lands, the prescribed repair is node scripts/check-system-context-census.mjs --fix — routine line rot, ⛔ never a re-baseline, and ⛔ stop if --fix wants to DELETE a row rather than re-point one.


Generated by Claude Code

@zhuangjianguo
zhuangjianguo marked this pull request as ready for review August 31, 2026 22:00

Copy link
Copy Markdown
Collaborator

Released — draft cleared, auto-merge armed 22:00:11

Following up the hold in my review above: all 32 checks are now completed — 30 success, 2 skipped (Build Docs, Console Pin Gate), zero failures, zero in flight. Test Core (1/6) was the last, finishing at 21:56:30 after 18 minutes; that shard is consistently the slowest (it ran 18 minutes on #13870 too), so the lag was load skew, not a hang.

⚠️ The base moved under this PR while it waited: #13870 merged at 21:54:41 as 47389b35de, so this PR's CI ran against a base that is no longer main. Rather than assume that is harmless, I measured it — exactly one commit landed in that window, and it touches neither of this PR's two files:

$ git diff --name-only eb649cb8bc origin/main | grep -c 'runtime-authoring-gate.ts'   → 0
$ git diff --name-only eb649cb8bc origin/main | grep -c 'closure-context-key-completeness' → 0
$ git diff --name-only eb649cb8bc origin/main | grep -c 'protocol.ts'   → 1   # positive control, fires

⇒ No textual conflict is possible. The control is there because a zero from a query that could never match is not a reading — I produced exactly that error twice today, and the third one is not free.

⚠️ One thing this does not discharge: #13870 inserted ~108 lines into packages/metadata-protocol/src/protocol.ts and re-anchored system-context.mdx row 21. This PR adds no lines to any cited file, so it should be unexposed — but the queue re-runs CI against the new base, and that run is the actual measurement. If check-system-context-census comes back red there, the repair is the gate's own node scripts/check-system-context-census.mjs --fix: routine line rot, ⛔ never a re-baseline, and ⛔ stop if --fix wants to DELETE a row rather than re-point one.

On landing I will verify by content on origin/main — ⛔ not by the merged boolean — and strip pm:dispatched from #13768.


Generated by Claude Code

@zhuangjianguo
zhuangjianguo added this pull request to the merge queue Aug 31, 2026
Merged via the queue into main with commit 8ecfc3d Aug 31, 2026
34 checks passed
@zhuangjianguo
zhuangjianguo deleted the claude/issue-13768-closure-context-key-completeness branch August 31, 2026 22:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

runtime publish gate: CLOSURE_CONTEXT_KEY_BY_TYPE is the last hand-listed spelling of the snapshot collection set

2 participants