docs(spec): name the real policy-gate runtime symbols in the publish-gate consumer table - #13046
Merged
Merged
Conversation
…gate table The consumer table in endpoint-publish-gate.ts named cacheControlHeader and endpointRateLimiterRegistry. Neither is a symbol: endpoint-policy.ts declares computeCacheControl and createEndpointRateLimiterRegistry. Comment-only.
Contributor
📓 Docs Drift Check
What this run could not see
Coarse fallback — 126 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): |
os-trump
marked this pull request as ready for review
August 29, 2026 01:18
os-trump
enabled auto-merge
August 29, 2026 01:18
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #13040
The consumer table in
packages/spec/src/api/endpoint-publish-gate.tsmaps each publish gate to the runtime that enforces the same refusal. Its policy row named two symbols that do not exist: both were renamed inpackages/runtime/src/endpoint-policy.tsand the table was never updated. The cost is a reader (human or AI) grepping either name, finding nothing, and concluding the enforcement is missing — exactly backwards, since the enforcement is real and green.The two corrections
packages/runtime/src/endpoint-policy.tscacheControlHeadercomputeCacheControl—export function, line 252endpointRateLimiterRegistrycreateEndpointRateLimiterRegistry—export function, line 130Both real symbols were re-verified by reading the file at this PR's base commit
8cb96ec41before anything was written.Repo-wide occurrence counts for the two phantom spellings, measured on that base and again on this branch:
packages/cacheControlHeaderendpointRateLimiterRegistryThe card measured these at
9ee2dcfbdas 2 and 1; the second number moved because PR #13039 landed in between. The one remaining hit in each case is now the same line —packages/spec/liveness/api.json:139— where that PR rewrote the ledger note to narrate this exact rename, and so quotes both old spellings as history. Those are prose about a rename, not pointers to a symbol. With this change the docblock row is no longer among them, and the two phantom names have no surviving live pointer anywhere in the tree.The rest of the table was swept and is accurate
Every other symbol and path the table names was checked against this tree rather than assumed. No third stale name was found, so this PR corrects two names and no more.
planEndpointTarget—packages/runtime/src/endpoint-executor.tsexport function, line 221mappingDeclarationRejection—packages/runtime/src/api-mapping.tsexport function, line 250normalizeEndpointPath—packages/metadata/src/endpoint-matcher.tsdocs/adr/0121-declarative-endpoint-routing-namespace-and-channel-split.md, both sections presentThe
normalizeEndpointPathrow is the one that could have been misread as a fourth defect, so it is worth stating why it is not. The symbol is declared inpackages/spec/src/api/endpoint.zod.tsand only re-exported by the file the row names. But the column is "runtime counterpart",endpoint-matcher.tscarriesexport { normalizeEndpointPath }on line 148, and a reader grepping that name in that file finds it. The defect class this card is about is a grep that comes back empty; this one does not, so the row stays as written. Structural changes to the table were out of scope either way.Verifying mechanically that the diff is comment-only
Two independent methods, following the batch-1 precedent in #12955.
Method 1 — every changed line is a block-comment continuation.
git diff -U0reports one hunk,@@ -31 +31 @@, and the changed-line census is two lines (one removed, one added). Both match^[+-] \*, and the count of changed lines that do not match is zero:Method 2 — the compiler agrees. Method 1 is textual: a line that starts with an asterisk is not proof it is a comment. So both versions of the file were transpiled with the workspace TypeScript under
removeComments: trueand the emitted code compared byte for byte. The compiler, not a regex, decides what a comment is:The check guards against its own vacuous case: identical inputs would emit identically too, so it exits non-zero with
INCONCLUSIVEwhen the two raw sources match. Here they differ and the stripped emits do not, which is the whole claim.Changeset: measured against the gate's own convention
The
Check Changesetgate in.github/workflows/pr-automation.ymlhas no path-based skip list. Its job-level condition declares exactly two exemptions, and both mean "this PR declares no release of its own": theskip-changesetlabel, and the Changesets release PR (changeset-release/mainpushed by the bot). So a comment-only edit underpackages/spec/srcowes the gate something — it is not silently exempt because of where the file lives.Which of the two routes applies is settled by the gate family's own prose rather than by preference.
lint.ymlstates the prescription directly — a PR that "releases nothing" takes the label — andscripts/check-empty-changeset.mjsshuts the third route by rejecting any empty-frontmatter changeset a PR newly introduces (#5471), with the measurement that an empty changeset buys nothing the label does not and uniquely risks stalling a release.This PR releases nothing, and that is measured rather than argued: the comment-stripped emit above is byte-identical, so no consumer-observable behaviour moves; and no generated artifact carries this docblock (zero hits for its prose across
packages/spec/api-surface/,authorable-surface*andcontent/docs/).check:docsconfirms it from the other side, reporting231 generated files in sync with packages/specafter the edit. So the route is theskip-changesetlabel, applied to this PR, and no.changeset/*.mdfile — leaving the declared file surface at exactly one file.Gates
Family derived from the real change set, not from a hand-written list:
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack(exit 0; repo assertion holds against this checkout'sorigin; change set1 path — packages/spec/src/api/endpoint-publish-gate.ts). It named 26 families, and all 26 were run at final commit94ee55c85. Exit codes were captured before any pipe.All 26 green. Representative verdict lines, quoted from the gates themselves:
check:docs—231 generated files in sync with packages/speccheck:authorable-surface—authorable-defaults/ verified against upstream 8cb96ec41b34 — 1246 default(s) unchangedcheck:liveness—every governed-type property at the walk's one-level granularity is classified, every registered type is governed or explicitly pending, no ledger row outlives its propertycheck:nul-bytes—OK (scanned 7245 text file(s) -- 7245 tracked, 0 untracked-not-ignored; skipped 7 binary; no raw ASCII control bytes)check:doc-formula-expressions—22 record-scoped formula example(s) across 425 files / 1453 TS blocks judged cleanTwo of the 26 first came back as unmet preconditions rather than findings, and are reported honestly as such:
check:doc-formula-expressionsexited 1 withPREREQUISITE NOT MET — @objectstack/formula is not built, then again for@objectstack/lint. Both packages were built and the gate then ran for real and passed. The reading above is from that real run.check-dev-prereqs.mjsexits 1 withThe workspace is not built — 1 unmet precondition, not a list of problems(66 of 67 packages have nodist/in this fresh worktree; only the@objectstack/specclosure,formulaandlintwere built here). Its own text says nothing was measured, so this is recorded as NOT MEASURED, not as a red gate. A full 67-package build was deliberately not run for it: the box is shared and the turbo cache is cold here, and CI checks out fresh and builds anyway. The one leg of that gate which reads this PR's package — thepackages/spec/distcontent hash — is satisfied, the spec build having printedpackages/spec/dist/.build-input-hash.Also run:
pnpm --filter @objectstack/spec typecheck(exit 0,tsc --noEmitplus the scripts and test-layer legs). Its green is not taken on faith —tsc --noEmit --listFilesproves the edited file is in that program,packages/spec/src/api/endpoint-publish-gate.ts, 1 match among 906 files.No ablation is owed here and none was invented. Ablation proves a guard can fail; this PR adds no guard and moves no code, and the comment-only proof above is the evidence that fits the change.
Contract
Clause ② — PATH leg is hit: the file is under
packages/spec/src/**, the contract surface, so this PR carriesneeds:contract-reviewand the seat reviews it at PASS.CONTENT is comment-only with zero behaviour movement. That is not a description of intent, it is the measurement in the section above: the comment-stripped emit is byte-identical between base and head. No schema, no export, no accept/reject behaviour, and no authorable surface moves —
check:authorable-surfacereports 1246 defaults unchanged against upstream, andcheck:docsreports all 231 generated files in sync.On the disposition
The card left two shapes open and the dispatch ruled option 1 — correct the two names. Option 2, a doc-comment
path#symbolconvention plus a resolver lint that would cover the whole class, is not attempted here, on the card's own #11457 caution: it is a new gate with an unmeasured false-positive population, and that measurement is its own piece of work rather than a rider on a two-word correction. The class-level question stays with the board's finding stream; this PR restores the table's truth and claims nothing about the next rename.Generated by Claude Code