Skip to content

docs(rest-test): the resolver seam is a test-only injection point, in both sibling suites (#12647) - #12653

Merged
os-litant merged 1 commit into
mainfrom
claude/issue-12647-sibling-seam-reachability-notes
Aug 27, 2026
Merged

docs(rest-test): the resolver seam is a test-only injection point, in both sibling suites (#12647)#12653
os-litant merged 1 commit into
mainfrom
claude/issue-12647-sibling-seam-reachability-notes

Conversation

@os-litant

@os-litantos-litant commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator

Fixes#12647

Two sibling suites asserted that the /api/v1/packages direct-mount door's
resolveExecutionContext seam is production-reachable. Re-measured here: it is
not. Both sites are relabelled as test-only injection points. No test
removed, no assertion touched, no behaviour changed — comment/prose only, proven
below.

What I measured — re-derived, not inherited

Read from the composition on this branch's base, 2db1293c1. I took neither the
card's derivation nor PR #12646's.

anchormeasurement
rest-api-plugin.ts:471the only production supplier of this option, repo-wide: resolveExecutionContext: (req) => restServer.resolvePackageRouteExecutionContext(req)
rest-server.ts:1481resolvePackageRouteExecutionContext(req: any), declared to return a promise of context-or-undefined — and not async. Whole body is two statements: const environmentId = req?.params?.environmentId ?? undefined; then return this.resolveExecCtx(environmentId, req).catch(() => undefined);
rest-server.ts:1453private async resolveExecCtx(...) — being async, calling it cannot throw synchronously; it returns a promise
package-routes.ts:81the consumer awaits options.resolveExecutionContext(req).catch(() => undefined) — a second swallow

Neither statement in the wrapper can throw synchronously: the first is an
optional-chained read with ?? (safe for any req, null included), and the
second calls an async method and attaches .catch to the promise it returns.
So a production resolver delivers exactly two things — a context, or
undefined. Its rejections are swallowed at rest-server.ts:1483 and again at
package-routes.ts:81, and the request lands on the anonymous-deny 401 floor.

The only supplier zero, reverse-checked.git grep -n resolvePackageRouteExecutionContext
returns one production definition (rest-server.ts:1481) and one production
call site (rest-api-plugin.ts:471); every other hit is a CHANGELOG.md line or
a test comment. Reverse-checked against mountAndRecordDirectRoutes — a term
known present in the same file and not a substring of the term under test —
which returns rest-api-plugin.ts:6 and :463 plus four test callers. The
option value flows only rest-api-plugin.ts:471direct-mount-composition.ts:89
:126 registerPackageRoutes; the composition is a pass-through and declares no
value of its own.

The derivation, turned into an observation

Rather than leave this as an argument, I drove both limbs through the real
registrar with one throwing resolver each and read the wire answer. Scratch test,
run and then deleted — not committed.

✓ SYNC throw (what the suites inject) reaches the outer catch -> 403 PERMISSION_DENIED
✓ ASYNC rejection (what a production resolver could at most produce) is SWALLOWED -> 401 floor
ASYNC-LIMB ANSWER: {"status":401,"body":{"success":false,"error":{
"code":"UNAUTHENTICATED","message":"Authentication is required to access this endpoint."}}}
Test Files 1 passed (1) / Tests 2 passed (2)

The swallow is not inferred from the source shape — it is the answer on the
wire, verbatim.

The tell, confirmed independently

Every one of the four suites that drives this seam injects a non-async
vi.fn(() => { throw error; }), while all twelve production-seam injectors
beside them are async. Twelve async, four sync — and all four sync ones are
the resolver:

package-routes-coded-error-mapping.test.ts :127 async :140 SYNC :152 async :165 async
package-door-5xx-message-sanitization.test.ts :372 async :385 SYNC :397 async :410 async
package-door-user-message.test.ts :200 async :213 SYNC :225 async :238 async
package-door-declared-code.test.ts :211 async :224 SYNC :236 async :249 async

They had to be sync: as measured above, a rejection answers 401 instead of
reaching the catch at all. The files were recording the difference before anyone
read it that way.

The census, re-derived — and it disagrees with the card in both directions

⛔ I did not sweep for the phrases the card quotes. I swept for statements this
measurement makes false
, wrap-tolerantly (grep -rPzo with (?s) over
multi-line spans, so a phrase broken across a line still matches), then read every
seam-mentioning file in packages/rest/src for realism / reachability claims.

The driver population is four files, not two. The card names two. The sweep
found four, and each needed a different disposition:

filedisposition
package-routes-coded-error-mapping.test.tsrepaired here — the sharp one
package-door-5xx-message-sanitization.test.tsrepaired here
package-door-user-message.test.tsalready correct — no edit. Its :73-81 already reads "One seam below is drivable here but NOT production-reachable, and it is named so nobody reads it as evidence of the opposite", with the same async / swallow reasoning. It landed with #12502
package-door-declared-code.test.ts⛔ fenced — PR #12646

So the conclusion matches the card (two files to repair) while the
population does not. That third file is also independent in-tree corroboration
of the measurement, arrived at by a different author on a different card.

A second falsified statement at site 1, which the card does not name. The
same block gave a second reason for driving the gate:

GET /packages is different BY DESIGN: both of its data sources sit in their
own inner try { … } catch {} … so nothing below it reaches the outer catch

That is stale. package-routes.ts now marks the list door's registry read
[#11130] NOT wrapped in a catch, deliberately (:672) and its durable read
[#11063] NOT wrapped in a catch, deliberately (:738) — read in the production
file, not taken from the sibling's prose. Both arms do reach this outer catch
and are pinned in package-list-durable-read-refusal.test.ts and
package-list-registry-read-refusal.test.ts. Repairing only the realism clause
would have left a second false sentence in the paragraph I was correcting, so it
is corrected in the same block and named here rather than left silent. The
sibling file I am also editing already carries the corrected form at :333-339.

Counted and deliberately left alone.package-routes-coded-error-mapping.test.ts:26
"This file pins the four SITES" — is a claim about this file's own four
test seams, which really are four. True as written; a census claim is not
repaired by making it disagree with what the file does. Same for :9 and
:330 in the sibling ("all four handlers" — handlers, not seams).

Sites checked and found NOT falsified, so untouched:
direct-mount-base-follows-apipath.test.ts:229-236,
discovery-advertised-direct-mounts.parity.test.ts:138-145 and
package-envelope.conformance.test.ts:70-74 each say production wires the
resolver here — which is true, and none of them claims a throw from it
arrives anywhere. packages/runtime/src/package-door-error-parity.test.ts makes
no claim about this seam. package-routes.ts:66-70 and :341-349 describe an
absent resolver failing closed, never a failing one.

The repairs

Neither test case is deleted. Both still pin real door behaviour and
reached() keeps them from going vacuous. What changed is what the prose claims
they are evidence of.

Site 1 — package-routes-coded-error-mapping.test.ts:30-43, the sharp one.
It did not merely count the seam; it defended its realism:

That is not a contrived lever — the composition wires it to the RestServer's
own identity/RBAC resolution, which is exactly the kind of code that raises a
coded 401/403.

The first clause is true; the conclusion does not follow, so the inference is
what is repaired, not the count. Precisely because that resolution is reached
through an async method, the coded 401/403s it raises are rejections
swallowed twice, answering 401. The block now says the lever is exactly as
contrived as that sentence denied, quotes the sentence it is retiring so the
correction is legible, and names the case a TEST-ONLY INJECTION POINT.

Site 2 — package-door-5xx-message-sanitization.test.ts:341-347, milder, same
family.
"so it keeps proving the DOOR rather than one source" reads as a claim
about a production path. It is now "exercises the CATCH SITE rather than one
source"
, with the test-only label beside it. The :356 back-reference ("keeps
driving the GATE for the reason above"
) still resolves, now to the corrected
reason.

The derivation is not restated a third time. Both sites cite it — the
Seam census block of package-door-declared-code.test.ts, plus
package-door-user-message.test.ts's reachability section — with #12537 and
#12647 as the stable anchors. Restating it at each site is the exact defect these
cards exist to end.

ℹ️ PR #12646 had not merged when this was written, so per the card the issues
carry the authority and the Seam census block is named as where the derivation
lives. An issue reference does not dangle.

ℹ️ The SITES[].name string 'GET /packages — the capability gate resolver throws'
is unchanged in both files. It is a string literal, not a comment; it is
accurate as it stands (the injected resolver does throw); and changing it would
break the comment-only proof below. Same judgement PR #12646 recorded for the
same string.

Comment-only, proven with an instrument calibrated in both directions

Both blobs transpiled with removeComments: true (typescript 6.0.3), emitted
program hashed. Neither edit turned out to be a string literal or a test title —
both are pure comments (a /** */ docblock and a // block), so Ruling 5's
conditional does not fire.

### packages/rest/src/package-routes-coded-error-mapping.test.ts
base sha256: 286211754f22c5880996db2c9cb5c3f27feca429a6ee4260989b083d1ec14cb8
head sha256: 286211754f22c5880996db2c9cb5c3f27feca429a6ee4260989b083d1ec14cb8
EQUAL (comment-only): true
A) code-token mutant 6b7f23d830f1e6e392be09b6ddf727e455ab020ab8da72b5c24bf486b254374c DIFFERS: true
B) comment-token mutant 286211754f22c5880996db2c9cb5c3f27feca429a6ee4260989b083d1ec14cb8 SAME: true
### packages/rest/src/package-door-5xx-message-sanitization.test.ts
base sha256: 2d5fb72300f5debd36bcdb0d73da1553f6cc10d6e4432f071403613038dc7a5c
head sha256: 2d5fb72300f5debd36bcdb0d73da1553f6cc10d6e4432f071403613038dc7a5c
EQUAL (comment-only): true
A) code-token mutant 35d3494b984629eb293e0f5d56862a7ac808e1f6b54ca5f44032e3fa24f37d62 DIFFERS: true
B) comment-token mutant 2d5fb72300f5debd36bcdb0d73da1553f6cc10d6e4432f071403613038dc7a5c SAME: true
VERDICT: PROVEN comment-only for 2 file(s), instrument calibrated both ways: true

An equality from an uncalibrated instrument is not evidence, so each mutant was
asserted to be a real edit before hashing (a no-op mutation throws rather than
reporting a hash). A code token moves the hash; a comment token does not.
git diff --stat: 2 files changed, 58 insertions(+), 14 deletions(-).

Tests and gates

Every heavy run — builds and typechecks included — went through
scripts/pm/os-verify-lock.sh (slot issue-12647). Every verdict below is the
tool's own printed line. Exit codes were captured before any pipe
(cmd > file 2>&1; ec=$?), never through | tail.

Build — the dependency closure a fresh worktree needs first:
pnpm --filter '@objectstack/rest^...' build
os-verify-lock: VERDICT command-exit 0 · held the lock 297s (4m57s) · waited 0s

Gates and suites, all at the final commit. The whole batch ran in one
acquisition after the last commit, so nothing here is a green measured on a
tree that is no longer HEAD:

GATE RUN AT HEAD=c3a8a6ef5 (worktree dirty paths: 0)
gateits own verdict line
check:nul-bytesOK (scanned 6987 text file(s) … no raw ASCII control bytes)
check:cross-package-test-inputsOK: 20 package(s) read outside themselves, all declared
check:dispatcher-error-vocabularyOK — 21 unregistered code-stamping site(s), all classified
check:objectql-double-limit… none new · baseline key set verified against 2db1293: no files added
check:page-declaration-shapeOK — 34 page entries across 2223 sources … all reach the kernel
check:published-files✓ 69 publishable package(s) … admits no test, test-harness config or build script
check:slot-lookupratchet holds: 107 unswept site(s) in 25 file(s), none new
check:test-source-aliasOK — 72 packages with tests scanned
check:type-source-resolutionOK — 94 tsc program(s) across 77 packages scanned
scripts/check-ci-filter-parity.mjsOK: all 109 declared cross-package glob(s) … covered
scripts/check-comment-mask-adoption.mjsOK — 20 private comment-stripper(s) … all 20 recorded
scripts/check-plugin-teardown-shape.mjs✓ 63 Plugin implementation(s) … baseline fully burned down
check:engine-double-contractOK — 689 pinned, 134 in the DEBT ledger, 3 exempt
check:where-matcher0 silently-wrong and 0 unjudged matcher(s) … none new
check:query-options-erasureratchet holds: 67 unswept non-test site(s) in 17 file(s), none new
check:type-check-coverageOK — 65/78 workspace packages type-checked (plus the root), 13 in the DEBT ledger
@objectstack/resttypecheckcheck:test-typecheck: OK — @objectstack/rest's test layer compiles under packages/rest/tsconfig.test.json

os-verify-lock: VERDICT command-exit 0 · held the lock 366s (6m06s) · waited 0s

The two suites, in that same run:

Test Files 2 passed (2)
Tests 97 passed (97)

⚠️Typecheck coverage, stated precisely rather than implied.--listFiles
over both of the package's tsc programs:

tsconfig.json coded-error-mapping=0 5xx-sanitization=0 (control src/package-routes.ts=1)
tsconfig.test.json coded-error-mapping=1 5xx-sanitization=1 (control src/package-routes.ts=1)

The build program does not read either edited file. The half that does is
check:test-typecheck (tsconfig.test.json), which passed. So "typecheck is
green" here is a claim about the test program, not the build program.

Narrowing, declared — not implied. I ran the families
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack derived
from the real change set (it reported 2 paths, from git itself), plus the
edits a test file convention families, plus the two affected suites. I did
not run the full 176-family farm and did not run a repo-wide pnpm lint.
One family is deliberately NOT MEASURED rather than reported green:
check:type-check-debt refuses on a worktree without the whole workspace
closure built, and I built only @objectstack/rest^...; a refusal is not a pass,
so it is named here instead of quietly counted. It cannot move on this diff
anyway — the emitted-program hashes above show nothing compiled changed. CI runs
the full farm on every pull request regardless, and that result is CI's to report.

No changeset

packages/rest declares files: ["dist","README.md","CHANGELOG.md"]. This diff
is comments inside two src/** test files, which dist does not carry, and the
emitted-program hashes above show that nothing compiled — published or not — can
differ. Nothing ships, so there is no user-visible change to describe. Labelled
skip-changeset.

Scope

⛔ Nothing outside the two named test files was edited.
packages/rest/src/rest-server.ts was read only — it is held by PR #12421.
packages/rest/src/package-door-declared-code.test.ts was read only — held
by PR #12646.

Fixes #12647, not Part of: the sweep found no site it could not repair.
package-door-user-message.test.ts needed none, and the only other driver is
fenced to a PR already repairing it. This card has no fenced or maintainer-facing
half.

⚠️Reported, not reconciled. Two disagreements with the numbers I was handed,
both stated above and neither smoothed over: the driver population is four
files, not two
(same conclusion, different census), and site 1 carried a
second falsified statement
the card does not name (the stale inner-catch
reason at :33-36). Everything else I re-derived — the four line anchors, the
only supplier zero, the double swallow — matched what I was handed, measured on
2db1293c1 rather than the card's aa5994e17.


Generated by Claude Code

… both sibling suites
Both suites asserted that the `/api/v1/packages` door's `resolveExecutionContext`
seam is production-reachable. Re-measured on this tree: it is not. The only
production supplier is `rest-api-plugin.ts:471`, whose wrapper
(`rest-server.ts:1481`) is not `async` and holds no statement that can throw
synchronously; the `async` `resolveExecCtx` it delegates to can only reject, and
that rejection is swallowed at `rest-server.ts:1483` and again at
`package-routes.ts:81`, landing on the 401 anonymous-deny floor.
Comment/prose only — no test removed, no assertion touched, no behaviour
changed. The derivation is cited, not restated a third time.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UjujZN219uFzBhSYfMykCd
@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 fb5a6695ba10a6ba4523a11356c9708ff6ee8452packageMentionDocs.

@os-litantos-litant added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Aug 27, 2026 — with Claude
@os-litant
os-litant marked this pull request as ready for review August 27, 2026 03:37
@os-litant
os-litant added this pull request to the merge queueAug 27, 2026
Merged via the queue into main with commit 085a1d5Aug 27, 2026
40 checks passed
@os-litant
os-litant deleted the claude/issue-12647-sibling-seam-reachability-notes branch August 27, 2026 04:12
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/sskip-changesetPR has no user-facing published change; bypasses the changeset gatetests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[finding] two sibling package-door suites carry the same production-reachability claim about the test-only resolveExecutionContext seam

2 participants

@os-litant@claude