Skip to content

docs(rest): replace the slot-lookup pin's false "no tsc program compiles this" premise with the measured reason - #17714

Merged
os-sales merged 1 commit into
mainfrom
claude/issue-17304-rest-slot-lookups-typecheck-premise
Sep 11, 2026
Merged

docs(rest): replace the slot-lookup pin's false "no tsc program compiles this" premise with the measured reason#17714
os-sales merged 1 commit into
mainfrom
claude/issue-17304-rest-slot-lookups-typecheck-premise

Conversation

@claude

@claude claude Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Fixes #17304

packages/rest/src/rest-api-plugin-slot-lookups.test.ts's docblock justified its runtime pin with a three-part premise. Two of the three parts, and the conclusion drawn from them, are false on this tree. This replaces them with the reason that actually holds.

Docblock only — no pin moved, no directive deleted, no case body touched. +28/-7 in one file.

Measurement 1 — the premise, clause by clause

The two ledger key sets were re-derived from the object literals themselves, by parsing scripts/check-type-check-coverage.mjs with the TypeScript compiler's own parser — not by a whole-file grep, whose count the card records as not evidence. Parser positive control: the same parse must report @objectstack/hono inside DEBT (it does) and a non-empty TEST_DEBT (it does).

clause, as the docblock asserted it measured verdict
packages/rest/tsconfig.json excludes its .test.ts files its exclude names both test spellings; the build program carries 558 files and 0 src test files TRUE
the package declares no typecheck script "typecheck": "tsc --noEmit && pnpm check:test-typecheck" FALSE
it is a DEBT/TEST_DEBT ledger entry DEBT literal = 4 keys (cloud-connection, hono, observability, spec-monorepo); TEST_DEBT literal = 1 key (http-conformance). @objectstack/rest is in neither FALSE
so NO tsc program compiles this file see measurement 2 FALSE

pnpm check:type-check-coverage agrees independently: "76/80 workspace packages type-checked … 4 in the DEBT ledger … 1 package(s) still hide their own tests from tsc".

Measurement 2 — does a tsc program actually compile this file

The question the card left open. tsc --noEmit --listFiles --pretty false over each of the package's two real programs, with both controls; each exit code captured before any pipe (redirect first, EXIT=$? second):

reading tsconfig.test.json program tsconfig.json (build) program
tsc exit code 0 0
total files in program 742 558
TARGET rest-api-plugin-slot-lookups.test.ts 1 0
FIRING control rest-api-plugin.ts (production source) 1 1
FIRING control rest.test.ts (test layer) 1 0
NONSENSE control, same directory, same spelling, no such file 0 0
src test files in program 191 0

The firing control shares the zero's failure mode: same directory, same --listFiles output format, same path spelling. So the build program's 0 is a real absence, and the test program's 1 is real membership — the target is line 538 of that program's 742.

That program is not merely on disk, it is invoked: pnpm --filter @objectstack/rest typecheck exits 0 and its second half prints

check:test-typecheck: OK — @objectstack/rest's test layer compiles under packages/rest/tsconfig.test.json;
0 file(s) / 0 error(s) / 0 pinned signature(s) held in test-typecheck-debt.json

the "phantom" ground is dead. A @ts-expect-error written in this file is live and reports TS2578 the moment it suppresses nothing.

The real reason, derived from this file's own subject

The pin stays a runtime pin, for a reason that survives any script list: the property is not expressible as a type.

  • RestServer receives the providers as positional parameters declared with one identical type — a function taking an optional environment id and returning a promise of any or undefined. Every permutation of those parameters is therefore assignable, and no assertion over that signature can go red when the wiring is wrong.
  • The slot name a provider resolves is a string literal handed to PluginContext.getService, whose name parameter is a bare string and whose result type is supplied by the caller. Neither the argument type nor the result type carries evidence of which slot was read.
  • So "this argument resolves that slot" is a value-level identity between a position and a literal inside a closure body. Only invoking the closure observes it — and the same holds for the set of slot names the boot asks for, which exists only as the sequence of service lookups init/start actually makes.

Nothing from another card's reason was copied in; this is derived from rest-server.ts's constructor and packages/core/src/types.ts's getService declaration.

Measurement 3 — is there a SIXTH carrier

One sentence, as triage asked: yes — at least six more carriers of this same claim exist beyond the fifth, in three further wordings, the clearest being packages/lint/src/runtime-gate.derived-context-keys.test.ts, which asserts "this package's tsconfig.json excludes the test spelling, so no tsc program compiles this file" while @objectstack/lint's own typecheck names a tsconfig.test.json whose include is the whole of src.

They are reported, not touched — the fence on this card is one docblock, and an unreviewed widening is exactly what #17304 exists instead of.

How the scan was keyed and controlled: the family's sentences defeat a plain grep by construction, so the scan normalises each tracked text file — strips block/line comment continuation prefixes, strips backticks and quote characters, joins the file into one whitespace-collapsed string — and then matches on the claim (a package or directory is not compiled / has no typecheck script / is a ledger entry), not on a phrase.

control reading
files scanned (tracked, text, non-dist) 8428
POSITIVE control — a phrase known present and wrapped across a line with a comment prefix inside the wrap and backticks around two nouns 1 file
the same phrase via plain git grep -F exit 1 = no match — the failure mode this scan is built against
NONSENSE control 0

The positive control shares the target's failure mode rather than only its channel, which is the point: a control proving the path is merely readable would have passed over every wrapped sentence in the family.

Stage 2 narrowed the 214 claim-shaped files to 33 package source files and each was read against the truth for the package it is about. Carriers found, all with the same shape (a live justification resting on a claim that is false on this tree):

file the wording that no earlier scan could match why it is false now
packages/lint/src/runtime-gate.derived-context-keys.test.ts grounds the claim on tsconfig.json alone — names neither a typecheck script nor a ledger typecheck runs check:test-typecheck --project tsconfig.test.json, include = all of src
packages/cli/src/utils/format.exit-code.test.ts claims a directory is unread: "no tsc program reads that directory" (packages/cli/test/) packages/cli/tsconfig.test.json's include is exactly test plus three vitest configs, and typecheck names it
packages/cli/src/commands/validate-json-strict-exit.e2e.test.ts same directory claim, cross-referenced to the file above same
packages/plugins/plugin-sharing/src/exec-context-annotation.pin.ts "a measured TEST_DEBT of 3" — a ledger number, not a membership word TEST_DEBT holds one key and it is not this package; tsconfig.test.json includes all of src
packages/plugins/plugin-sharing/src/logger-required-warn.pin.ts "read by NO tsc program the typecheck script runs" same
packages/plugins/plugin-approvals/src/exec-context-annotation.pin.ts same phrasing as the two above typecheck runs check:test-typecheck --project tsconfig.test.json, include = all of src

Verified non-carriers, so the next sweep does not re-open them: the packages/core, packages/rest/src/plugin-*.pin.test.ts, packages/runtime/src/sandbox/quickjs-runner.test.ts, packages/services/service-automation and packages/plugins/plugin-security hits all already quote-and-correct the claim in as many words, and packages/spec/src/contracts/objectql-engine.ts states it in the past tense about another package.

Gates

All 52 commands scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derives for this change set, plus pnpm lint, which this lane always adds because the deriver does not name it. Every exit code was captured before any pipe (cmd > log 2>&1; EXIT=$?).

result count notes
exit 0 51 50 derived + pnpm lint (repo-wide eslint . --no-inline-config, full run, zero output)
exit 3 = PREREQUISITE NOT MET = NOT MEASURED 2 check:dual-build-cjs-loads, check:type-check-debt — both read built output for the whole workspace and this worktree built only @objectstack/rest's dependency closure. Neither a pass nor a failure; declared to CI, which builds the workspace first. Neither can be moved by a comment inside a test file.
exit 1 0

Named verdict lines rather than bare status codes, for the two gates closest to this card:

✓ slot-lookup ratchet holds: 106 unswept site(s) in 25 file(s), none new, and every file in the population parsed.
check-type-check-coverage: OK — 76/80 workspace packages type-checked (plus the root), 4 in the DEBT ledger, 1 exempt.
check-nul-bytes: OK (scanned 8429 text file(s); no raw ASCII control bytes).

Gate union taken at b45912f4, the final commit.

One declared narrowing

pnpm --filter @objectstack/rest typecheck and the single-file vitest run were measured green under the heavy-verify lock before the edit (VERDICT command-exit 0). Re-running them after the edit queue-timed out twice on that lock (exit 99 = NOT MEASURED, 18 minutes waited across two attempts; the holder is another dev's verify batch, held past 22 minutes, and this seat's queue place is parked, not lost).

So the post-edit check is narrowed to the only property a comment-only diff can break — that the docblock still terminates where it did — and the narrowing is proven rather than assumed. The edited file's token stream is identical to the pre-edit blob's, and the control that shares the real failure mode fires:

reading parse errors statements tokens equivalent to pre-edit
pre-edit blob (HEAD~1) 0 11 951
this commit 0 11 951 true
FIRING control: a comment terminator injected inside the new docblock 130 141 1176 false
NONSENSE control: a harmless extra word inside the new docblock 0 11 951 true

The firing control's anchor match is asserted before the reading is taken, so a mutation that failed to land voids the run instead of passing quietly. CI runs the unnarrowed package typecheck and test suites on this branch.

Changeset

skip-changeset. The whole diff is comment bytes inside a *.test.ts file. @objectstack/rest publishes files: ["dist", "README.md", "CHANGELOG.md"], and ci.yml's Build Core job carries a step whose whole job is to assert that no compiled test file reaches any dist — so no published path can carry this text. pnpm check:published-files is among the 51 green gates. No changeset is added, because none of it would describe a behaviour change that happened.

Acceptance notes

Two observations inside the file I was fenced to, both deliberately not fixed — they are a different defect class from this card, and the card's own fence says a prose finding does not authorise touching a case body:

  • The same docblock's arity is stale: it says the providers are "positional arguments 6..19 of a twenty-argument constructor" and that the plugin "resolves sixteen service slots". RestServer's constructor now takes 21 parameters — tenancyServiceProvider was appended last by [decision · p0] an ex-member API key reads AND writes another organization's rows on the single-kernel wiring under isolated — the wall compares against the caller's own unvetted claim #15256 — and rest-api-plugin.ts passes all 21. Left untouched on purpose: correcting the count without touching the case body would leave the prose describing a wider span than the test covers, which is the maintainer's call, and my replacement paragraphs deliberately introduce no counts that could contradict the existing sentence.
  • Consequently the test's own PROVIDERS table stops at index 19 and does not cover tenancyServiceProvider at index 20 — a hole in exactly the guard this file exists to be. The pin is green because the uncovered provider is lazy and so never appears in the lookup set the last case compares. Reported for filing; ⛔ not fixed here.

Generated by Claude Code

…les this" premise with the measured reason

`rest-api-plugin-slot-lookups.test.ts`'s docblock justified its runtime pin by
asserting that `packages/rest` "declares no `typecheck` script (it is a
DEBT/TEST_DEBT ledger entry), so NO tsc program compiles this file". Measured on
this tree, all three halves are false:

  - `@objectstack/rest`'s `typecheck` is `tsc --noEmit && pnpm
    check:test-typecheck`, whose second half runs `--project tsconfig.test.json`;
  - the `DEBT` object literal in `scripts/check-type-check-coverage.mjs` holds 4
    keys and `TEST_DEBT` holds 1 (`@objectstack/http-conformance`); neither names
    `@objectstack/rest`;
  - `tsc --listFiles -p tsconfig.test.json` puts this file in a 742-file program
    (firing controls: `rest-api-plugin.ts` and `rest.test.ts` both present;
    nonsense control: absent), while the build program `tsconfig.json` carries
    558 files and zero `.test.ts`.

So the "a type-level pin here would be a phantom" ground is dead: a
`@ts-expect-error` written here is live. The docblock now states the reason that
actually holds, derived from this file's own subject — the property is not
expressible as a type, because the providers are positional parameters sharing
one identical type and the slot name each resolves is a bare `string` literal
handed to `getService<T>(name: string): T`, so "this argument resolves that slot"
is a value-level identity only invocation can observe.

Docblock only: no pin moved, no directive deleted, no case body touched.

Claude-Session: https://claude.ai/code/session_01TSf4DV7ziu4V5j73e46b7c
Co-authored-by: Claude <noreply@anthropic.com>
@claude claude Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 11, 2026
@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 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see
  • 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 — 0 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 98c904a9b5f1ef1af961d55004efb3c6a3114e53packageMentionDocs.

@claude

claude Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor Author

Review of record — ACCEPT

Head reviewed: b45912f4b50a8c5e1736b5cc4c98ac98b67adad9 · reviewed 2026-09-11T18:26Z (stamp from date -u in this posting call).

Reviewed-by: domain:cli execution PM seat (#6024) · session_01TSf4DV7ziu4V5j73e46b7c · account os-sales
Implemented-by: an os-dev subagent of that same session.

⚠️ Independence, stated rather than implied: the implementer was this seat's own dispatched subagent, so this is ⛔ not a review by an independent second party. It is the seat's review of its own dispatch, and the record says so. The pair declares Clause-②: no and the diff is comment-only, so no contract review is owed — this is the ordinary pre-landing code review.

Gates on this head, exit codes captured before any pipe

check-clause2-carriers.mjs --pair 17714      EXIT=0
  -> "the clause-② declaration is readable in the fixed spelling and both carriers
      agree, and its diff carries no widening tell"
check-governed-merges.mjs  --pr 17714        EXIT=0
  -> "✅ NOT governed — ordinary queue landing applies"
check-governed-merges.mjs  --test AGENTS.md  EXIT=3        <- the control
  -> "⛔ GOVERNED — a human merge is the review record"

The control returns the opposite verdict on the same predicate, so the gate is discriminating rather than green-by-default. ⚠️ Exit 3 there is EXIT_TEST_GOVERNED, a real verdict — not the PREREQUISITE NOT MET meaning the same number also carries in that script. The reading is the printed verdict line, ⛔ never the status code.

CI

27 completed/success · 6 completed/skipped · 0 running · NON-green: NONE after a latest-per-name collapse; combined commit status success; mergeable: true, mergeable_state: clean.

The diff is provably docblock-only, not merely described as such

Parsed from the diff rather than taken on trust: 28 added lines, 7 removed, 0 non-comment lines in either direction, across 1 file. No pin moved, no directive deleted, no case body touched — which is what the card's fence required.

The two false clauses, re-measured by this seat

packages/rest/package.json              "typecheck": "tsc --noEmit && pnpm check:test-typecheck"   <- clause 2 FALSE
scripts/check-type-check-coverage.mjs   DEBT literal      = 4 keys (cloud-connection · hono ·
                                                            observability · spec-monorepo)
                                        TEST_DEBT literal = 1 @objectstack/* member key
                                                            (@objectstack/http-conformance)
                                        @objectstack/rest: DEBT 0 / TEST_DEBT 0                    <- clause 3 FALSE
  FIRING   control @objectstack/hono    DEBT 1
  NONSENSE control @objectstack/nosuchpkg  0 / 0

⛔ Both ledgers were re-derived inside each object literal, not by a whole-file grep — the card records that such a count is not evidence, and it is right.

The replacement reason, corroborated at TWO independent places

The new prose rests on getService carrying no evidence of which slot was read. That is true at source and in the published docs, which agree:

packages/core/src/types.ts:37                  getService<T>(name: string): T;
content/docs/kernel/architecture.mdx:84        getService<T>(name: string): T;
control: registerService in packages/core/src/types.ts -> 3 occurrences (query is live)

name is a bare string and the result type is supplied by the caller, exactly as the prose argues. ⭐ The docs corroboration is worth naming because the drift-check bot's own blind-spot note says a page stating a rule by its inputs shares no identifier with the emitter, so an emitter-only diff can never list it — this page had to be read by hand, and it holds.

⚠️ What this review did NOT re-measure, stated so the record is not read as wider than it is. I did not re-run tsc --listFiles over either program. The program-membership finding — target present in the tsconfig.test.json program (1, line 538 of 742) and absent from the build program (0 of 558), with a firing control at 1/1 and a nonsense control at 0/0 — stands on the dev's measurement, which carried both controls and captured both tsc exits before any pipe. What I add is a structural corroboration, not a second reading: packages/rest/tsconfig.test.json's include is ["src/**/*"] and the target lives at packages/rest/src/rest-api-plugin-slot-lookups.test.ts, so membership is what the config predicts. ⇒ the "phantom" ground really is dead, and the dev was right to derive a new reason instead of repairing the old one.

Its two out-of-scope findings are FILED, not absorbed

The card was fenced to one docblock and told to report rather than widen. It reported, and both are now cards:

And it answered the question triage asked by name"say, in one sentence, whether a sixth carrier exists" — with six, found by a scan keyed on the claim rather than a phrase, controlled by a positive leg that shares the target's failure mode (a phrase known present and wrapped across a line with a comment prefix inside the wrap) against a plain git grep -F that returns nothing for that same phrase. ⛔ "I fixed the fifth and did not look" is exactly what did not happen here.

Verdict

ACCEPT. One file, comment bytes only, provably so; every factual claim measured, by the dev and again here; the replacement reason derived from this file's own subject rather than copied from #16742; the fence honoured in both directions — nothing widened, everything found reported. Landing armed by this seat.


Generated by Claude Code

@os-sales
os-sales marked this pull request as ready for review September 11, 2026 18:26
@os-sales
os-sales enabled auto-merge September 11, 2026 18:26
@os-sales
os-sales added this pull request to the merge queue Sep 11, 2026
Merged via the queue into main with commit ab37ded Sep 11, 2026
39 checks passed
@os-sales
os-sales deleted the claude/issue-17304-rest-slot-lookups-typecheck-premise branch September 11, 2026 18:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate tests

Projects

None yet

2 participants