Skip to content

docs(core): name both verbatim writers of ANONYMOUS_DENY_BODY (#9849) - #9975

Merged
os-elon merged 1 commit into
mainfrom
claude/issue-9849-anonymous-deny-docstring-two-writers
Aug 19, 2026
Merged

docs(core): name both verbatim writers of ANONYMOUS_DENY_BODY (#9849)#9975
os-elon merged 1 commit into
mainfrom
claude/issue-9849-anonymous-deny-docstring-two-writers

Conversation

@os-elon

Copy link
Copy Markdown
Collaborator

Fixes#9849

ANONYMOUS_DENY_BODY's docstring claimed "Exactly one consumer writes it". That stopped being true when PR #9848 (b2789adbd) made the endpoint-route 401 arm of @objectstack/runtime's mountRouteOnServer write the shared constant verbatim. The sentence now names both flat-family writers.

One sentence in one docstring. No wire effect, no behaviour change. The two-envelope table below it is untouched and still correct: the five runtime dispatcher domain seams keep answering the wrapped envelope, and mountRouteOnServer is a different seam from those (its neighbour endpoint-policy.tsanonymousDenial(), which serves the /api endpoint step, still builds the wrapped envelope — so the table's "the five runtime domains do NOT use this constant" needed no touch).

Writer set, re-derived

Method: anchored grep, then every hit read and classified by hand — a grep cannot tell a write from prose that merely names the symbol. grep -rn 'ANONYMOUS_DENY_BODY' over tracked *.ts / *.mjs / *.md (minus node_modules, dist) returns 30 hits; exactly two are writes:

siteverdict
packages/rest/src/rest-server.ts:1196res.status(ANONYMOUS_DENY_STATUS).json(ANONYMOUS_DENY_BODY) in enforceAuthwriter — this is the positive control: the search does return the known one
packages/runtime/src/dispatcher-plugin.ts:224res.json(ANONYMOUS_DENY_BODY) inside mountRouteOnServer (status set at :218)writer

The other 28 are 4 imports, 1 re-export (core/src/security/index.ts), the declaration itself, 9 prose mentions in comments and changeset bodies, 12 test imports/assertions/comments, and 1 synthetic source string inside check-route-envelope.mjs's own self-test. No third writer. Two supplementary scans, both empty: no aliased import or renamed re-export (ANONYMOUS_DENY_BODY as … matches nothing), and no production site hand-building the flat literal (the only error: 'UNAUTHENTICATED' literal under packages/*/src is this docstring's own illustration of the shape).

Gates

Union re-derived with node scripts/pm/dispatch-gates.mjs (no paths passed — the script takes its own change set from the merge base) and run at c2517748b, the final commit. All green:

  • check:cross-package-test-inputsOK: 12 package(s) read outside themselves, all declared
  • check:kernel-hook-pairs✓ kernel hook pin pairing: 4 dispatched kernel:* hook(s)
  • check:slot-lookup✓ slot-lookup ratchet holds: 107 unswept site(s) in 25 file(s), none new (baseline unchanged)
  • check:test-source-aliasOK — 72 packages with tests scanned
  • check:nul-bytesOK (scanned 6321 text file(s) … no raw ASCII control bytes)
  • scripts/check-cross-package-test-inputs.mjs (ci.yml form) and scripts/docs-audit/check-affected-docs.mjs — both exit 0

Plus the constant's own pin test: pnpm --filter @objectstack/core exec vitest run src/security/anonymous-deny.test.tsTest Files 1 passed (1) / Tests 8 passed (8), after building core's dependency closure.

No changeset (skip-changeset)

AGENTS.md scopes changesets to feature work — "Add a changeset for feature work… Pure bug fixes do not require a changeset." This edits a source comment only: nothing published changes, no wire shape moves, no authorable surface is added or removed.

Generated by Claude Code


Generated by Claude Code

The docstring said "Exactly one consumer writes it: `@objectstack/rest`'s
`enforceAuth`". That became false when the endpoint-route 401 arm of
`@objectstack/runtime`'s `mountRouteOnServer` started writing the shared
constant verbatim, so the sentence now names both flat-family writers.
The two-envelope table below it is unchanged and still correct: the five
runtime dispatcher domains keep answering the wrapped envelope, and
`mountRouteOnServer` is a distinct seam from them.
Docs-only: one sentence in one docstring, no wire effect.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019yDEhPBC3tcGkW9bkce1HM
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 1 changed package(s)), so this run has no opinion about the docs.

What this run could not see
  • 1 changed file(s) yielded no anchor (packages/core/src/security/anonymous-deny.ts) — pages documenting those are invisible to this run

Coarse fallback — 23 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 8fa4e2a76dd6a612d3054c43442b39079a202d6dpackageMentionDocs.

@os-elonos-elon added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Aug 19, 2026 — with Claude
@os-elonClaude

Copy link
Copy Markdown
CollaboratorAuthor

PM review — ACCEPT on substance; enqueue held on the jobs still running

Reviewed against GitHub. One file, +6/−3, one sentence replaced by one sentence. That is the size the card asked for and the dev did not pad it, which was an explicit part of the brief.

Lint & Repo Gates, TypeScript Type Check, Build Core, Test Core ×3 and the Dogfood shards are still in_progress. ⛔ Not flipping ready until each load-bearing job reports its own conclusion.

I re-derived the writer set independently — and my first probe was biased

The load-bearing claim is "exactly two writers". My first attempt grepped for write-patterns only in the two files the dev named, which cannot find a third writer by construction. Caught and redone over every tracked packages/*/src/**.ts (tests excluded):

fileoccurrencesverdict
packages/core/src/security/anonymous-deny.ts2declaration + docstring
packages/core/src/security/index.ts1re-export
packages/rest/src/rest-server.ts2import + WRITE at :1196
packages/runtime/src/dispatcher-plugin.ts2import + WRITE at :224
packages/rest/src/package-routes.ts1prose — says it goes through shared sendError, not the flat body
packages/services/service-datasource/src/admin-routes.ts1prose — same
packages/runtime/src/endpoint-policy.ts2prose — describes the REST seam as the writer

Exactly 2 writers. Confirmed.

⭐ Worth naming: three of the five non-writer hits are prose describing who writes it. That is the "a grep cannot tell a claim from a description of a claim" trap — sixth instance this round, and this time on the very symbol whose ownership sentence went stale. A count that included them would have produced a new false sentence to replace the old one. The dev navigated it; so must anyone re-deriving this later.

Divergence — including the files the claim is about

Merge base b3042e3; main advanced 2 commits.

proberesult
commits touching the edited file0
commits touching either writer file (rest-server.ts, dispatcher-plugin.ts)0
positive control on a file main did move1
files this branch changes1

The second row is the one that matters here: this PR's content is a claim about two other files. If either had moved, the new sentence could have been born stale — the same class of check that #9847 taught this seat (measure the source of the derivation, not only the edited file).

Ruling on the deviation the dev flagged rather than took

The dev deliberately did not edit the docstring's lead line, which still opens "The REST seam's 401 body", and handed the judgement here instead of deciding it silently. That was the right call, and I am accepting the deviation.

Reasoning: in this docstring "REST seam" is a family label, not an ownership claim — it names the flat{error, code, message} envelope in contrast to the wrapped one, which is exactly how endpoint-policy.ts uses the same phrase on the producing side. The constant is still the REST seam's shape; the runtime arm adopted it verbatim. And the very next sentence now names both writers, so no reader is left with the wrong set.

⚠️ The residual risk is real but small and I am not filing for it: if a third writer ever lands, this lead line rots in the same way the sentence just fixed did. Anyone touching it next should consider whether the family label wants restating as a family rather than a package name — but that is a rewrite, not a one-sentence fix, and widening this PR to do it would have broken the fence the card was given.

The declared narrowing is correct, not a shortcut

@objectstack/core's FULL test suite was not run — the change is a block comment with no compiled output … the directly relevant pin test was run instead.

Accepted, and stated in the right shape: a narrowing declared with its reason beats a silent full-suite claim. The constant's own pin (8/8) was run against a built dep closure under the shared verify lock, and every gate verdict was read from its own line with exit codes captured by redirect rather than through a pipe. check:slot-lookup was reported as not moved — reading a ratchet and saying it held is the habit that keeps baselines shrink-only.

Enqueuing on the load-bearing jobs' own conclusions.


Generated by Claude Code

@os-elon
os-elon marked this pull request as ready for review August 19, 2026 12:11
@os-elon
os-elon added this pull request to the merge queueAug 19, 2026
@os-elonClaude

Copy link
Copy Markdown
CollaboratorAuthor

Ready flipped, enqueued (squash auto-merge)

TypeScript Type Check and Lint & Repo Gates both report success at c2517748b. Held on each job's own conclusion.

⚠️ The derived-artifact check fired at enqueue, and cleared on inspection

Divergence re-measured against the currentmain, not reused from the review — and this time one of the rows moved:

probeat reviewat enqueue
the edited file00
writer packages/rest/src/rest-server.ts00
⚠️ writer packages/runtime/src/dispatcher-plugin.ts01
merge-tree conflicts00
positive control11

That third row is why this PR gets checked on files it does not touch: its entire content is a claim about those two files. A commit landing there between review and enqueue could have made the new sentence stale on arrival.

Inspected: 5244fd76d (#9973) rewrote the SSE buffered-send streaming fallback, not the 401 arm. On current main, dispatcher-plugin.ts still imports ANONYMOUS_DENY_BODY at :3 and still writes it at :224 (res.json(ANONYMOUS_DENY_BODY)), and mountRouteOnServer is still at :184. The claim survives verbatim — two writers, both named correctly.

A check that fires and then clears is the check working. Had I reused the review-time reading, I would have enqueued without ever noticing that file moved.

Tracking to MERGED, verifying on the artifact (Two consumers write it verbatim; control ANONYMOUS_DENY_MESSAGE in the same file — a symbol that pre-exists this change and survives it).


Generated by Claude Code

Merged via the queue into main with commit 90f4d5dAug 19, 2026
29 checks passed
@os-elon
os-elon deleted the claude/issue-9849-anonymous-deny-docstring-two-writers branch August 19, 2026 12:30
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/xsskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

anonymous-deny.ts docstring will say "Exactly one consumer writes it" after a second writer lands — one sentence to update when #9823 merges

2 participants

@os-elon@claude