Skip to content

docs(rest): the ?type= diagnostics comment describes today's tree, and names the inner gate it sits above - #15619

Merged
os-litant merged 2 commits into
mainfrom
claude/issue-15034-diagnostics-gate-comment
Sep 5, 2026
Merged

docs(rest): the ?type= diagnostics comment describes today's tree, and names the inner gate it sits above#15619
os-litant merged 2 commits into
mainfrom
claude/issue-15034-diagnostics-gate-comment

Conversation

@os-litant

@os-litant os-litant commented Sep 5, 2026

Copy link
Copy Markdown
Collaborator

Fixes #15034

Comments only. No observable behaviour moves, on either branch of the design question — the whole diff is comment text, proven mechanically below.

The design question, answered: KEEP — defence in depth

The card's first unit of work is a deliberate answer, not a merge resolution. Answered from two measurements rather than a preference, and the two point in opposite directions — which is the finding.

1. The VALUE is redundant, and measured to be

Both applications fold the identical string through the identical map:

  • the door folds with canonicalMetaUrlType(diagnosticsType);
  • getMetaItems folds with canonicalizeMetaRequestTypecanonicalMetaTypethe same canonicalMetaUrlType, one statement before its own gate.

getMetaDiagnostics sets targetTypes = [request.type] on the ?type= arm and passes that same raw segment down, so f(t, f(t, o)) === f(t, o) and the inner application is the algebraic no-op. There is no path reachable from this arm that hands the inner gate a type the door has not already folded.

Ablation M1 — swap the door's predicate for a raw diagnosticsCtx?.tenantId. Predicted direction stated first: stays green, because the inner gate re-folds.

### AFTER: removed-text count = 0, marker count = 1
### MUTATION CONFIRMED ON DISK
 Test Files  1 passed (1)
      Tests  30 passed (30)

Green. The door-side predicate buys nothing at runtime today.

2. But the two gates are not in the same TRUST DOMAIN — and that is why it stays

getMetaDiagnostics is not a member of MetadataProtocol — not required, not optional (packages/spec/src/api/protocol.zod.ts, the interface declares getMetaItems / getMetaItem / saveMetaItem plus a list of optional members; this is on neither list). That is exactly why the door reaches it through the (p as any) cast and answers 501 NOT_IMPLEMENTED when a kernel does not implement it, and why packages/client documents it as "501s on kernels without getMetaDiagnostics".

The inner gate belongs to ONE implementation of an UNDECLARED extension. The door-side predicate sits on the REST boundary and holds for every RestProtocol a host can mount. Delete it and a REST door's tenant scope becomes a function of which kernel is mounted.

⭐ And the sharpest part: no pin can see that happen, because the harness boots the bundled implementation — M1 is the proof. So the DELETE branch is worse than the card's cost asymmetry estimated: it is not merely "owes one more pin", it is "owes a pin that cannot be written in this package".

The comment now carries this reason, per the acceptance criterion for the KEEP branch. No pin change owed.

Which site is which — established here, by symbol

The card and the routing notes cite two different anchors and they are two different things. Measured on the merged ref ba426b0f091, unedited:

site line on origin/main what it is
diagnosticsOrganizationId = organizationIdForMetaRead( :4808 the ?type= computation
// getMetaItems applies NO registry gate of its own: :4757 the falsified comment — THIS CARD
// organizationIdForMetaRead(canonicalMetaUrlType( :5536 ⚠️ a different doorGET /meta/:type/:name/references

Triage's verified anchor for "the comment" was :5531, which on today's ref is :5536the references door, not this card's site. Both sites quote the same string and both assert the same falsified clause, which is how they came to be conflated. The site this card is about is :4757.

Inner gates re-verified on my own merged ref: packages/metadata-protocol/src/protocol.ts:6958 (plural, #14683) and :7583 (singular overlay read, #14908).

This call site sits above exactly ONE of them, not two. getMetaDiagnostics only ever calls getMetaItems; the singular getMetaItem gate is under the by-name read door and this arm never reaches it. The comment says so.

The harness is corrected too, because M1 falsified it as well

packages/rest/src/rest-server-meta-read-org-scope.test.ts — the file the card's acceptance criteria name as the ready-made harness — carried the same falsified sentence in its header, plus an ablation recipe that M1 measured false:

Swap organizationIdForMetaRead for a raw ctx?.tenantId at the call site and that assertion, and only it, turns red.

It does not turn red. Same fate as #14677's ablation B, for the same reason. Its inline PREDICTED DIRECTION note said the same thing and is corrected with it.

Ablation M2 — what the file does still discriminate: drop the organization the ?type= arm passes. Predicted red, and red:

 Test Files  1 failed (1)
      Tests  6 failed | 24 passed (30)
       × view: the org-scoped item is counted
       × dashboard: the org-scoped item is counted
       × report: the org-scoped item is counted
       × translation: the org-scoped item is counted
       × email_template: the org-scoped item is counted
       × a plural URL spelling is folded before the scope decision, not after

Taken in scope under the bounded in-place rule, all four conditions checked: same defect class and the same sentence; mechanical, with M1 as the pinning evidence; 33/33 open PR heads measured, 0 hits on this file or on rest-server.ts (git, against each head's own merge-base — extends the dispatch note's rest-server.ts-only scan); same gate family, no new verification surface.

Ablation hygiene

Both legs: predicted direction stated before running · mutation proven on disk by counting both the removed text and an injected marker (a zero-hit edit would have exited 0 and read as a clean run) · restored under a trap with absolute paths · restore proven by blob-hash equality against the HEAD blob and an empty git diff HEAD, empty hash treated as failure:

HEAD blob: 31d5b24f5256516fc39861e565cfbef36bbb03d9
work blob: 31d5b24f5256516fc39861e565cfbef36bbb03d9
RESTORE OK: blob hashes equal
--- git diff HEAD (must be empty) ---
(end)

Resolution path, stated: packages/rest's vitest config aliases only plugin-hono-server and service-datasource, so @objectstack/metadata-protocol resolves through dist/ — registered in KNOWN_UNALIASED_TEST_IMPORTS under @objectstack/rest. A source-only mutation of the inner gate would have measured nothing, so the closure was built first and the artifact checked before any reading: grep -c over packages/metadata-protocol/dist/index.js returns 2 occurrences of organizationIdForMetaRead(request.type, request.organizationId) — both inner gates live in the artifact the suite actually resolves. The mutated file itself (rest-server.ts) is source-resolved through a relative import, so no rebuild was owed for the mutation legs. typecheck is on the other axis — its tsconfig paths redirects the same specifier to source.

Verification

Union re-derived from the real changed paths with scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack on a tree the tool does not call stale (the first derivation reported STALE TREE, 4 commits behind; fast-forwarded to ba426b0f091 and re-derived). 31 families run; the ratchet families re-run after that round's final commit, at d993d6c1e42, all exit 0. (The repair round below re-derives and re-runs on the new head — that sentence describes the first round only.)

check:nul-bytes  check:doc-authoring  check:route-envelope  check:slot-lookup
check:objectql-double-limit  check:engine-double-contract  check:test-source-alias
check:type-source-resolution  check:authz-resolver  check:error-code-casing
check:filter-alias-parity  check:cross-package-test-inputs  check:keyed-text-bounds
check:undeclared-dep-imports  check:comment-mask-corpus  check:comment-mask-adoption
check:org-identifier  check:tenant-chokepoint  check:single-claim-paths
check:published-files  check:where-matcher  check:page-declaration-shape
check:logger-receiver-detach  check:error-status-conformance  check:overlay-whitelist-table
check:stack-collection-maps  check:console-injection  check:dispatcher-error-vocabulary
check:closing-keyword-parity  check:reference-carrier-shape

Artifact-roster families were run rather than read as cleared: check:error-code-casing and check:filter-alias-parity both score silent for every card, and both are green here.

pnpm --filter @objectstack/rest test        179 files / 3058 tests passed
pnpm --filter @objectstack/rest typecheck   tsc --noEmit + check:test-typecheck OK

⚠️ typecheck coverage was verified, not assumed: packages/rest/tsconfig.json excludes **/*.test.ts, so tsc --noEmit alone says nothing about the harness edit. --listFiles confirms rest-server.ts is in the tsc program (1 hit) and rest-server-meta-read-org-scope.test.ts is in the tsconfig.test.json program (1 hit).

No observable behaviour moves — mechanically checked, not asserted: every added and removed line in this diff is a comment line.

git diff -U0 | grep -E '^[+-]' | grep -vE '^(\+\+\+|---)' \
  | grep -vE '^[+-]\s*//' | grep -vE '^[+-]\s*$'
(no output)

Repair round — the census gate's line anchors

The first push was red on one required context, Lint & Repo Gates, and on one gate inside it: check-system-context-census. Its --self-test leg passed; the corpus leg reported 10 problems, all on packages/rest/src/rest-server.ts — five [anchor-is-not-a-read-site] (4972, 6386, 6634, 7065, 7258) and five [site-without-a-row] (5016, 6430, 6678, 7109, 7302), pairing at a uniform +44.

Cause. content/docs/permissions/system-context.mdx row 50 anchors that file by line number, and this PR's comment adds a net 44 lines above every isSystem read site in it — hunks +7, +25 and +12, all above :4755. Every citation below the insertion rotted by exactly 44.

That it is a pure shift was verified against the tree, not inferred from the log. The whole census JSON, re-derived at the merge base and at this head, differs in exactly five line fields, each +44:

json line 539:   4972  →  5016
json line 546:   6386  →  6430
json line 553:   6634  →  6678
json line 560:   7065  →  7109
json line 567:   7258  →  7302
(every other byte of the census JSON identical)

Nothing else moved — same sites in the same order, same receivers, same package and file lists, same text counts. No elevation read site arrived or vanished. (Line-content identity alone would not have shown this: four of the five lines are the same string, so the census diff is the load-bearing evidence, not the sed -n comparison.)

Repair: the gate's own --fix, never a hand-edited line number.

node scripts/check-system-context-census.mjs --fix
  re-anchored content/docs/permissions/system-context.mdx:161  `rest-server.ts:4972` -> `rest-server.ts:5016`
  re-anchored content/docs/permissions/system-context.mdx:161  `:6386` -> `:6430`
  re-anchored content/docs/permissions/system-context.mdx:161  `:6634` -> `:6678`
  re-anchored content/docs/permissions/system-context.mdx:161  `:7065` -> `:7109`
  re-anchored content/docs/permissions/system-context.mdx:161  `:7258` -> `:7302`
check-system-context-census --fix: 5 anchor(s) rewritten

--fix REFUSED ZERO files. Per the gate's header that sentence is the whole point: the refusal is the gate's only signal that a site arrived or vanished, so a clean rewrite is what separates a pure re-anchor from a population change that merely happened to be shifted at the same time. The diff is one table row, five numbers, nothing else.

Gate exit code: 1 before, 0 after. Both legs green after the repair:

node scripts/check-system-context-census.mjs --self-test   exit 0  (all cases passed)
node scripts/check-system-context-census.mjs               exit 0
  OK — 106 elevation read sites in 20 packages across 45 files, all anchored;
       140 anchors resolve, 27 declared non-read.

Union re-derived and re-run on the repair head (a8cfb760115). The first derivation again reported STALE TREE (5 commits behind origin/main, 3 of the gate-deriving scripts changed in that range), so the family list was re-derived a second time from a tree at origin/main carrying this change set. Both derivations agree: 73 runnable families, 62 matched by path. All 73 exit 0 at a8cfb760115, exit codes captured after redirection, never through a pipe.

Six needed a second pass and none was a finding:

A standing tax on this file, worth knowing before the next edit

system-context.mdx cites packages/rest/src/rest-server.ts at eight absolute line numbers — :1553, :1582, :1585 and row 50's five. The file is 12,864 lines, so any diff that changes the line count above :7302 — comments included — rots at least one citation and reds this gate. It has happened before: the gate's own header records rest-server.ts displaced +3/+11 by a merge, and a sibling file's shift "cost a patch round". The repair is one command, not a hand-written row, provided the diff neither adds nor removes an isSystem read site; if it does, --fix refuses by design and a human writes the row.

Changeset

skip-changeset, applied at PR-open time. The rule is .github/workflows/pr-automation.yml, Check Changeset step, route 2 — "it releases nothing". This diff is comment text plus a test file plus a docs line-number re-anchor: no public surface, no behaviour, nothing a consumer can observe. changeset-check carries no paths filter, so it does not skip for this diff on its own; the label is the mechanism. Confirmed still applied on the repair head, and the Check Changeset run reports skipped.

Fences honoured

packages/spec read only · packages/rest/src/error-response.ts untouched (single writer, #14704, held by PR #15452) · content/docs/releases/ untouched · protocol.ts untouched — the enumeration finding below is filed, not edited, and PR #15592 is open on that file. The repair round's only new path is content/docs/permissions/system-context.mdx, which is hand-written docs and not a governed surface.


Generated by Claude Code

…d names the inner gate it sits above

The call-site comment beside `GET /meta/diagnostics`'s `?type=` arm asserted
that `getMetaItems` applies no registry gate of its own, so the scope of a
sweep is decided at the door, per type, by the caller. That was measured and
true when it was written. #14683 put `organizationIdForMetaRead(request.type,
request.organizationId)` inside `getMetaItems`, after the canonical fold, and
the sentence has been false since.

The design question the card opens — is the door-side predicate defence in
depth, or is it now redundant? — is answered KEEP, from two measurements
rather than a preference:

  * the VALUE is redundant. Both sites fold the identical string through the
    identical map (`canonicalMetaUrlType` at the door; the same function
    inside `getMetaItems` via `canonicalizeMetaRequestType` ->
    `canonicalMetaType`), so `f(t, f(t, o)) === f(t, o)`. Measured: swapping
    the door's predicate for a raw `diagnosticsCtx?.tenantId` leaves
    rest-server-meta-read-org-scope.test.ts 30/30 green.
  * but the two gates are not in the same TRUST DOMAIN. `getMetaDiagnostics`
    is not a member of `MetadataProtocol` — not required, not optional — which
    is why the door reaches it through `(p as any)` and 501s when it is
    absent. The inner gate therefore belongs to one implementation of an
    undeclared extension, while the door-side predicate holds for every
    `RestProtocol` a host can mount.

Comments only; no observable behaviour moves, on either branch.

The harness the card names is corrected in the same pass: its header carried
the same falsified sentence and an ablation recipe ("swap the predicate for a
raw ctx?.tenantId and that assertion, and only it, turns red") that no longer
discriminates. Measured 30/30 green under that mutation, and 6 failed / 24
passed under the mutation that drops the organization -- which is what the
file does still pin.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D47qPfEWVPmhguWgBZCi5N
@github-actions github-actions Bot added the size/m label Sep 5, 2026
@os-litant os-litant added skip-changeset PR has no user-facing published change; bypasses the changeset gate and removed size/m labels Sep 5, 2026 — with Claude
@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

⚠️ 1 changed file(s) yielded no anchor (packages/rest/src/rest-server.ts), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files. Nothing else in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 1 changed package(s)).

What this run could not see
  • 1 changed file(s) yielded no anchor (packages/rest/src/rest-server.ts) — pages documenting those are invisible to this run
  • 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 — 13 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 de69b540e25ded7edf63ea1792ba330b53502ccbpackageMentionDocs.

Copy link
Copy Markdown
Collaborator Author

⛔ Correction — this PR is RED, and my ACCEPT did not say so

I posted the ACCEPT for this PR on #15034 (5547984485) on the substance of the diff. I did not read the check runs when I wrote it. They say:

Lint & Repo Gates — conclusion: failure
run 33932171620 · job 101212845620 · completed 2026-09-05T00:12:38Z

The ACCEPT stands on substance — the comment text, the KEEP ruling on the inner gate, and the comments-only verification are unaffected. What was wrong was the implication that the PR was therefore ready. It is not, and it has not been since before I reviewed it. ⛔ It has not been flipped ready and has not been enqueued.

The failure, read from the log

check-system-context-census — its --self-test leg passed; the corpus leg did not:

check-system-context-census: 10 problem(s) over 140 anchors and 106 census sites.

All ten are in packages/rest/src/rest-server.ts:

[anchor-is-not-a-read-site]  4972  6386  6634  7065  7258
[site-without-a-row]         5016  6430  6678  7109  7302

Pair them in order: +44 on every pair, counts equal at five and five. So the reading is a uniform line shift — this PR's added comment lines pushed the elevation-read sites down, and content/docs/permissions/system-context.mdx anchors this file by line number.

The gate names its own remedy, and its self-test proves it distinguishes the two cases (FIX: a pure shift is rewritten vs FIX: a population change is REFUSED, never guessed):

pure line rot is repaired by `node scripts/check-system-context-census.mjs --fix`

A repair is dispatched. ⚠️ The +44 reading is arithmetic on a log, not a measurement — the dispatch is instructed to test it against the tree and to trust the gate's refusal over my hypothesis if the two disagree.

⭐ What this seat got wrong, generalised

I verified that both changed files' diffs were comments-only and treated that as evidence the change was inert. It is not:

A comments-only diff is not a no-op. It moves every line beneath it, and anything that cites this file by line number rots by exactly that many lines.

This repository anchors documentation into rest-server.ts by line number, so "comments only" and "cannot break a gate" are unrelated claims. I had measured the first and asserted the second.

This is the sixth time this seat has carried a claim about a PR's colour that it did not re-read. The rule I had already written — "parked, green, awaiting tier" is THREE claims, and the middle one is a CI reading with a timestamp — is correct and I did not apply it here. The one thing that went right is that the re-read happened before an enqueue, not after.

⚠️ Standing consequence for packages/rest/src/rest-server.ts

If the shift reading holds, any diff that inserts or deletes lines above ~line 4972 of this 7,000-line file reds this gate — comment-only diffs included. Four queued cards sit on this file (#14366, #14378, #14503, #14674). This goes into the brief for every one of them.


Generated by Claude Code

… after the +44 comment shift

The `?type=` diagnostics comment added 44 lines above every `isSystem` read site
in `packages/rest/src/rest-server.ts`, and row 50 of the system-context census
anchors that file by line number, so all five citations rotted by exactly 44.

Repaired with the gate's own `node scripts/check-system-context-census.mjs --fix`,
which REFUSED ZERO files: per-file the page's distinct anchor count still equalled
the lines the file offers, so the rewrite is a pure shift, not a guessed mapping.

Verified rather than assumed: the full census JSON at the merge-base and at this
head differs in exactly five `line` fields, each +44 -- same sites, same order,
same receivers, same text counts. No elevation read site arrived or vanished.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D47qPfEWVPmhguWgBZCi5N
@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation labels Sep 5, 2026
@os-litant
os-litant marked this pull request as ready for review September 5, 2026 01:04
@os-litant
os-litant enabled auto-merge September 5, 2026 01:04

Copy link
Copy Markdown
Collaborator Author

Green. Flipped ready and enqueued.

All 37 check runs completed, every one success or skipped. Lint & Repo Gates success at 2026-09-05T00:57:21Z — read from the check runs just now, not carried forward. Head a8cfb760115.

⭐ The +44 hypothesis held, and it was tested properly

I handed the repair a hypothesis derived from arithmetic on a log and told it to trust the gate over me. It tested rather than adopted, and the way it tested is the part worth keeping:

the full census JSON re-derived at merge-base ba426b0f091 and at head differs in EXACTLY five line fields, each +44, and in nothing else (same sites, order, receivers, package/file lists, text counts)

⭐ And the reason that was necessary rather than pedantic:

Line-content identity alone was insufficient evidence because four of the five lines are the same string.

Comparing the content at each anchor would have looked like a match no matter which of the four it landed on. Comparing the whole census structure is what actually proves no elevation read site arrived or vanished. --fix then rewrote 5 anchors and refused zero files; the delivered diff is one table row, five numbers.

The comment diff this PR was accepted for is untouched.

⚠️ The standing consequence for packages/rest/src/rest-server.ts is CONFIRMED

The PR's comment adds a net +44 lines above every isSystem read site (hunks +7, +25, +12, all above :4755), and content/docs/permissions/system-context.mdx row 50 anchors that file by absolute line number.

Any diff that inserts or removes lines high in this 7,000-line file reds check-system-context-census — comment-only diffs included. This is now in the brief for all four cards queued behind this file (#14366, #14378, #14503, #14674), together with the remedy (node scripts/check-system-context-census.mjs --fix) so it arrives as planned work rather than as a surprise at CI time.

On merge this releases the hard serial on rest-server.ts, which is what those four cards have been waiting on.

Gate union — a STALE TREE catch worth noting

dispatch-gates reported STALE TREE (5 commits behind origin/main, with 3 gate-deriving scripts changed there), so the family list was re-derived from a tree at origin/main. Both derivations agreed at 73 runnable families / 62 matched by path, and all 73 exit 0. Six needed a built closure first (four PREREQUISITE NOT MET exit 3, one exit 1 for the same unbuilt reason) and pass after the build — ⛔ recorded as what they were, not as passes.

One gate's exit 1 was proven not ours — see the next comment thread on #15446.


Generated by Claude Code

@os-litant
os-litant added this pull request to the merge queue Sep 5, 2026
Merged via the queue into main with commit abf9101 Sep 5, 2026
39 checks passed
@os-litant
os-litant deleted the claude/issue-15034-diagnostics-gate-comment branch September 5, 2026 01:32
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 skip-changeset PR has no user-facing published change; bypasses the changeset gate tests

Projects

None yet

2 participants