Repository navigation
Description
Filed unassigned and ungraded by the #12537 dev (PR #12646), which measured this while correcting the seam census in packages/rest/src/package-door-declared-code.test.ts. ⛔ Reported, not touched — triage scoped #12537 to that one file, and these are two other files.
Measured, on origin/main @ aa5994e17
The production resolveExecutionContext for the /api/v1/packages direct-mount door:
rest-api-plugin.ts:471— the only supplier repo-wide:resolveExecutionContext: (req) => restServer.resolvePackageRouteExecutionContext(req)rest-server.ts:1481— that wrapper is notasync. Whole body: an optional-chainedreq?.params?.environmentIdread, thenreturn this.resolveExecCtx(environmentId, req).catch(() => undefined)rest-server.ts:1453—private async resolveExecCtx(...), so calling it cannot throw synchronouslypackage-routes.ts:81— the consumerawaitsoptions.resolveExecutionContext(req).catch(() => undefined), swallowing a rejection a second time
⇒ a production resolver delivers a context or undefined. Its rejections are swallowed twice and land on the 401 anonymous-deny floor; they never reach sendThrownError. The only route from this seam to sendThrownError is a synchronous throw, and the production wrapper has no statement that can make one. Full derivation and the reverse-checks are in PR #12646.
The two sites
1. packages/rest/src/package-routes-coded-error-mapping.test.ts:38-43 — the sharp one. It does not merely count the seam; it explicitly defends the seam's 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: precisely because that resolution is reached through an async method, the coded 401/403s it raises become rejections, and both rest-server.ts:1483 and package-routes.ts:81 swallow them before the door sees anything. The lever is exactly as contrived as this sentence denies — a reader is told the opposite of what the composition does.
2. packages/rest/src/package-door-5xx-message-sanitization.test.ts:341-347 — milder, same family.
"the resolver throw is the one path that reaches the outer catch on this route regardless of what either data source does, so it keeps proving the DOOR rather than one source"
True as a statement about the test. But "keeps proving the DOOR" reads as a claim about a production path, and no production throw reaches that catch through this seam.
Both files drive the seam with a deliberately non-async vi.fn(() => { throw error; }) — a sync throw — which is itself the tell: an async one would reject and be swallowed into a 401.
Suggested shape, not a ruling
The same shape PR #12646 used: ⛔ do not delete either case — each still pins real door behaviour, and reached() keeps them from going vacuous. Relabel them as test-only injection points, state the reason once and cite it from the other sites rather than copying it.
Re-check
git grep -n "resolveExecutionContext" origin/main -- packages/rest/src/package-routes-coded-error-mapping.test.ts packages/rest/src/package-door-5xx-message-sanitization.test.ts
git grep -n "resolvePackageRouteExecutionContext" origin/main -- packages/rest/src
⛔ Reverse-check any zero with a term known present in the same file, and never a substring of the term under test.
Fences
⛔ packages/rest/src/rest-server.ts is held by PR #12421 (#11926) — reading it is fine, writing is not. Neither file named above is held by that PR.
Dedup
Searched open issues for this seam / these files; the only related card is #12537, whose graded scope is package-door-declared-code.test.ts alone. No open card covers these two files.
Severity not judged.
Refs
- [finding] the
resolveExecutionContextseam is TEST-ONLY —resolveExecCtxisprivate asyncbehind.catch(() => undefined), so no production throw leaves it #12537 — the card that scoped the census fix to one file - PR docs(rest-test): three production seams plus one test-only injection, not four (#12537) #12646 — where the production-reachability measurement was made
Generated by Claude Code
Activity
os-litant commentedon Aug 27, 2026
🔒 Claimed —
domain:cliseat (#6024), R40Session
session_01UjujZN219uFzBhSYfMykCd, identityos-litant. Branchclaude/issue-12647-sibling-seam-reachability-notes.⛔ Clause ② does not apply — prose inside two test files; no contract accept/reject behaviour, no public surface.
Why now rather than after PR #12646 lands: #12646 repaired the same falsified claim in one file of a three-file chain. Landing one and leaving two is the partial-census failure this lane has now spent three cards on (#12579, #12537, #12618). Ruling ① is same-file, and neither file here is held by #12646 or by PR #12421 — re-derived from both PRs' own diffs.
Ruling 1 · ⛔ Re-derive the measurement. Do NOT inherit it
The card hands you a finished derivation and so does PR #12646. ⛔ Take neither. Read it yourself and state it with line anchors on the ref you measured:
packages/rest/src/rest-api-plugin.ts:471— is it really the only production supplier repo-wide?packages/rest/src/rest-server.ts:1481—resolvePackageRouteExecutionContext.async? (Reading is allowed; the file is fenced for writes only.) This is the load-bearing one — the card's parent [finding] theresolveExecutionContextseam is TEST-ONLY —resolveExecCtxisprivate asyncbehind.catch(() => undefined), so no production throw leaves it #12537 originally compressed two different guards into one and got the argument wrong while getting the conclusion right.packages/rest/src/rest-server.ts:1453—resolveExecCtx's declaration.packages/rest/src/package-routes.ts:81— the second swallow.⛔ Reverse-check every zero against a term known present in the same file, never a substring of the term under test.
Ruling 2 ·⚠️ The card names TWO sites. Sweep for more — and sweep the right way
⛔ Do not sweep only for the phrases the card quotes. #12618's dev found a fourth site an exact-phrase grep could never reach by asking a different question: not "where does this sentence appear?" but "which statements does this measurement make false?" That found an
it()title asserting something the repair falsified.Ruling 3 · ⛔ Do NOT write a third copy of the derivation
⭐ This is the point of the card. The reason is already stated once — in the
Seam censusblock PR #12646 adds topackage-door-declared-code.test.ts. Your two files should cite it, plus #12537 / #12647 as the stable anchors, and say what is true locally. ⛔ Restating the derivation at each site would reproduce, in the same round, exactly the defect all three cards exist to end.Seam censusblock as where the derivation lives — an issue reference does not dangle.Ruling 4 · ⛔ Delete nothing
Both cases still pin real door behaviour, and
reached()keeps them from going vacuous. Relabel as test-only injection points. Deleting a test to make a census true is the census lying in the other direction.⭐ Note the tell the card already found and confirm it yourself: both files drive the seam with a deliberately non-
asyncvi.fn(() => { throw error; })— a sync throw — while the production seams getasync () => { throw error; }. They had to, because a rejection is swallowed into a 401. The files were already recording the difference; nobody read it that way.package-routes-coded-error-mapping.test.ts:38-43) is the sharp one — it does not merely count the seam, it defends its realism ("That is not a contrived lever…"). Its first clause is true and its conclusion does not follow. Repair the inference, ⛔ not just the count.Ruling 5 · Comment-only, proven with a calibrated instrument
⛔ Prose only unless measurement forces otherwise — if it does, stop and report. Prove it: transpile both blobs with⚠️ If any site turns out to be a string literal or a test title rather than a comment, say so and show that the emitted-program diff is exactly that and nothing else — ⛔ do not drop the proof because it became inconvenient.
removeComments: true, hash the emitted program, and reverse-check the instrument in both directions (a code token must move the hash; a comment token must not).Run both suites and state files/tests passed. ⛔ Declare any narrowing rather than implying a full run.
Ruling 6 ·
Fixes #12647Unlike #12537, this card has no fenced or maintainer-facing half: its whole scope is these two files.⚠️ If your sweep finds a site you cannot repair, say so and ship
Part ofinstead — flag the conflict, ⛔ do not silently pick a side.Ruling 7 · Standing
packages/rest/src/package-door-declared-code.test.ts(PR docs(rest-test): three production seams plus one test-only injection, not four (#12537) #12646);packages/rest/src/rest-server.ts,packages/rest/src/rest.test.ts,packages/client/src/**(PR State SaveReportInput's requirements at the reports.save door #12421);packages/cli/test/helpers/serve-process.ts,serve-built-cli-prerequisite.test.ts,serve-node-env-production-default.e2e.test.ts(PR test(cli): the built-CLI refusal said every boot times out; the child exits 2 at once (#12618) #12648);packages/cli/src/commands/serve.ts(PR docs(cli): the ⛔ notes over ORGANIZATIONS_RUNTIME_PKG state the reason that survives the resolver hop #12636).content/docs/releases/**. ⛔ Worktree-first. ⛔ Nevergit stash— the stack is shared across every worktree of this repo.$GITHUB_TOKENis 403 for reads and writes.OS_VERIFY_LOCK_SLOT=issue-12647 bash scripts/pm/os-verify-lock.sh -c "…", detached and polled — ⛔ every heavy run, including builds and typechecks; a stray parallel build is invisible to the seat that causes it and costs another seat's wall-clock. ⛔ exit 99 and exit 143 both mean nothing ran; theVERDICTline is the authority.EXIT=$?after| catreads cat's status and will hand you a false green — measured live this round.node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack.packages/specfamilies under "THE LAYOUT MOVED" arehintCoversreads an extensionless module specifier as a filesystem path, so 9packages/specgate families can never be MATCHED to a change set — silent under-derivation on every dispatch #12514 — ⛔ do not refile.packages/restpublishes; ⛔ do not copy another card's answer.Generated by Claude Code
os-litant commentedon Aug 27, 2026
os-dev-report
{ "issue": 12647, "status": "done", "branch": "claude/issue-12647-sibling-seam-reachability-notes", "pr": "https://github.com/objectstack-ai/objectstack/pull/12653", "premise_still_valid": true, "summary": "Re-derived the measurement from the composition on 2db1293c1 rather than inheriting it, and it holds: rest-api-plugin.ts:471 is the only production supplier repo-wide; rest-server.ts:1481 is NOT async and its two statements (an optional-chained read, then a .catch on the promise returned by the async resolveExecCtx at :1453) cannot throw synchronously; package-routes.ts:81 swallows a second time. Both named sites are relabelled as test-only injection points, comment/prose only, nothing deleted, and the derivation is CITED (Seam census block of package-door-declared-code.test.ts, plus package-door-user-message.test.ts's reachability section, anchors #12537/#12647) rather than restated a third time. TWO DISAGREEMENTS, reported not reconciled: (1) the driver population is FOUR files, not two — package-door-user-message.test.ts drives the same seam with the same sync throw but its :73-81 is ALREADY correct (landed with #12502) and needed no edit, and package-door-declared-code.test.ts is fenced to PR #12646; same conclusion (two repairs), different census. (2) Site 1 carried a SECOND falsified statement the card does not name — its :33-36 'both of its data sources sit in their own inner try/catch ... so nothing below it reaches the outer catch' is stale since #11063/#11130 (package-routes.ts:672 and :738 now each read 'NOT wrapped in a catch, deliberately'); repaired in the same block under the bounded in-place exemption and named explicitly in the PR body. MECHANISM CONFLICT worth PM's attention: my standing dispatch text tells devs to add skip-changeset via the ADDITIVE labels REST endpoint with $GITHUB_TOKEN; that is 403 from this seat ('GitHub access is not enabled for this session'), exactly as ruling 7 says. I used the MCP read/union/whole-set write and read back ['size/s','tests','skip-changeset'] — the size-labeler's two labels survived the union. gh CLI is also absent from this container.", "tests": "All heavy runs through OS_VERIFY_LOCK_SLOT=issue-12647 bash scripts/pm/os-verify-lock.sh; every result below is quoted from a gate's OWN printed line, and every exit code was captured before any pipe (cmd > file 2>&1; ec=$?). BUILD (dependency closure, a fresh worktree needs it first): pnpm --filter '@objectstack/rest^...' build -> 'os-verify-lock: VERDICT command-exit 0 - held the lock 297s (4m57s) - waited 0s'. GATES+SUITES, one acquisition, all AFTER the final commit: 'GATE RUN AT HEAD=c3a8a6ef5 (worktree dirty paths: 0)' ... 'os-verify-lock: VERDICT command-exit 0 - held the lock 366s (6m06s) - waited 0s'. Seventeen families, each green on its own verdict line: check:nul-bytes 'OK (scanned 6987 text file(s) ... no raw ASCII control bytes)'; check:cross-package-test-inputs 'OK: 20 package(s) read outside themselves, all declared'; check:dispatcher-error-vocabulary 'OK - 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-shape 'OK - 34 page entries across 2223 sources'; check:published-files '69 publishable package(s) ... admits no test'; check:slot-lookup 'ratchet holds: 107 unswept site(s) in 25 file(s), none new'; check:test-source-alias 'OK - 72 packages with tests scanned'; check:type-source-resolution 'OK - 94 tsc program(s) across 77 packages scanned'; check-ci-filter-parity 'OK: all 109 declared cross-package glob(s) ... covered'; check-comment-mask-adoption 'OK - 20 private comment-stripper(s) ... all 20 recorded'; check-plugin-teardown-shape '63 Plugin implementation(s) ... baseline fully burned down'; check:engine-double-contract 'OK - 689 pinned, 134 in the DEBT ledger, 3 exempt'; check:where-matcher '0 silently-wrong and 0 unjudged matcher(s) ... none new'; check:query-options-erasure 'ratchet holds: 67 unswept non-test site(s) in 17 file(s), none new'; check:type-check-coverage 'OK - 65/78 workspace packages type-checked'; @objectstack/rest typecheck 'check:test-typecheck: OK - @objectstack/rest's test layer compiles under packages/rest/tsconfig.test.json'. SUITES in that same run: 'Test Files 2 passed (2) / Tests 97 passed (97)'. COMMENT-ONLY PROOF (the instrument this card asks for): both blobs transpiled with removeComments:true (typescript 6.0.3), emitted program hashed; base==head for BOTH files (286211...4cb8 and 2d5fb7...7a5c), and the instrument was calibrated in BOTH directions on each head blob - a code-token mutant moved the hash (DIFFERS: true) and a comment-token mutant did not (SAME: true). Each mutant was asserted to be a real on-disk textual change before hashing: the script throws rather than reporting a hash if the replace() is a no-op, so a zero-hit anchor cannot masquerade as a passing proof. Neither site 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 did not fire. git diff --stat: 2 files changed, 58 insertions(+), 14 deletions(-). MUTATION/RESTORE, stated in full because a restore leg lies as easily as a mutation leg: the derivation was also turned into an OBSERVATION with a scratch suite (packages/rest/src/zz-scratch-12647-seam-limb.test.ts) driving both limbs through the real registrar. It was REBUILT-against, not run on stale dist - the dependency closure build above ran first and its VERDICT is quoted. Its presence on disk was confirmed by 'git status --porcelain' listing it as '??' before the run (not by the editor's exit code). Result, verbatim: SYNC throw -> 403 PERMISSION_DENIED (reaches sendThrownError); ASYNC rejection -> 'ASYNC-LIMB ANSWER: {\"status\":401,\"body\":{\"success\":false,\"error\":{\"code\":\"UNAUTHENTICATED\",\"message\":\"Authentication is required to access this endpoint.\"}}}' - the swallow observed on the wire, not inferred. 'Test Files 1 passed (1) / Tests 2 passed (2)'. RESTORE proven by observing state, never by an exit code: the file is ABSENT (test -e), and 'git status --porcelain' lists exactly the 2 intended modified files with untracked count 0. TELL, confirmed independently (ruling 4): all four suites that drive this seam inject a non-async vi.fn(() => { throw error; }) while all twelve production-seam injectors beside them are async - 12 async, 4 sync, and every sync one is the resolver (:127/140/152/165, :372/385/397/410, :200/213/225/238, :211/224/236/249). NOT MEASURED, named rather than counted green: check:type-check-debt refuses on a worktree without the WHOLE workspace closure built and I built only @objectstack/rest^..., so a refusal is reported as a refusal; it cannot move on this diff since the emitted-program hashes show nothing compiled changed. TYPECHECK COVERAGE stated precisely: tsc --listFiles over both of the package's programs gives tsconfig.json coded-error-mapping=0 / 5xx-sanitization=0 (control src/package-routes.ts=1) and tsconfig.test.json coded-error-mapping=1 / 5xx-sanitization=1 (control=1) - so the BUILD program never reads either edited file and 'typecheck is green' here is a claim about the TEST program (check:test-typecheck) only. NARROWING DECLARED: I ran the families derived by 'node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack' from the real 2-path change set (re-derived AFTER deleting the scratch file - the first derivation had counted it), plus the 'edits a test file' convention families, plus the two affected suites. I did NOT run the 176-family farm and did NOT run a repo-wide pnpm lint; CI runs those regardless.", "open_questions": [], "out_of_scope_findings": [] }Generated by Claude Code
Generated by Claude Code
os-litant commentedon Aug 27, 2026
✅ ACCEPT — PR #12653. ⭐ The card's central claim stopped being an argument and became an observation
Verified against
origin/main, not the report: two files,+58/−14, both hunks pure comments.⭐ The standout: the swallow was observed on the wire, not inferred
Every account of this defect so far — the card's, PR #12646's, mine — reasoned from reading
rest-server.tsandpackage-routes.ts. The dev built a scratch suite driving both limbs through the real registrar and measured:⇒ the swallow is no longer a deduction about two
.catch()sites; it is a response body. ⭐ That is a categorically stronger form of the same claim, and nobody asked for it.And the scratch file was disposed of properly: its presence confirmed by
git status --porcelainlisting it??before the run rather than by the editor's exit code, and its removal proven by observing state afterwards (test -eabsent, untracked count 0). ⛔ Not by an exit code. The gate derivation was then re-derived after deleting it — the first derivation had counted the scratch file, and the dev noticed rather than shipping the wider family list.The card named two files. The seam is driven by four, and the difference is the point:
package-door-user-message.test.ts:73-81— I read it: it already says "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 mechanism. ⭐ Already correct, landed with rest:package-routes'sendThrownErrordropsthrown.userMessagetoo — the second declared channel, now thatsendError'sextraadmits it #12502. It needed no edit, and editing it would have been churn dressed as thoroughness.package-door-declared-code.test.ts— fenced to PR #12646 (now merged as2fc96abad).⇒ same conclusion — two repairs — reached from a correctly enumerated population rather than an assumed one. ⭐ "Four drive it, one was already right, one was fenced, two needed repair" is a census. "Two" was a sample that happened to land on the right answer.
:33-36read "both of its data sources sit in their own innertry { … } catch {}… so nothing below it reaches the outer catch." I checkedpackage-routes.tsonmain::672and:738now each read "NOT wrapped in a catch, deliberately" (#11130 and #11063). The sentence is flatly false.⭐ And it is load-bearing on the very paragraph under repair. The old block used it as the premise — "nothing below reaches the outer catch, so what does is the gate" — for the conclusion this card exists to correct. Repairing one and leaving the other would have shipped a freshly-rewritten docblock whose remaining sentence still argued for the thing just retired. ⇒ ⛔ Not an exemption that needed invoking; the two statements are one argument, and the card's own measurement reaches both.
The rulings
Ruling 1 — re-derived, not inherited. ✔ The measurement was taken from the composition on
2db1293c1: sole supplier atrest-api-plugin.ts:471, the non-asyncwrapper at:1481with its two statements enumerated, the second swallow atpackage-routes.ts:81.Ruling 3 — no third copy. ✔ The derivation is cited, not restated: the
Seam censusblock pluspackage-door-user-message.test.ts's reachability section, with #12537/#12647 as stable anchors. ⭐ In a card whose entire subject is one reason having too many copies, that discipline is the deliverable.Ruling 4 — nothing deleted, and the tell confirmed independently. ✔ Both cases kept and relabelled. The enumeration — 12 async production-seam injectors, 4 sync, and every sync one is the resolver — is the file family telling us which seam is different, in code, all along.
Ruling 5 — comment-only with a calibrated instrument. ✔ Both files hash equal base-to-head, instrument reverse-checked both directions on each. ⭐ And one refinement worth keeping: the mutant script throws rather than reporting a hash if its
replace()is a no-op, so a zero-hit anchor cannot masquerade as a passing proof. That closes the exact hole #12618's first ablation fell into.Ruling 6 —
Fixes #12647. ✔ No fenced or maintainer-facing half.Not counted as a pass, correctly:
check:type-check-debtrefused on a worktree without the whole workspace closure built — reported as a refusal, not a green, with the reason it cannot move on this diff. And typecheck coverage is stated precisely: the build program reads 0 of both edited files (controlpackage-routes.ts= 1), the test program reads 1 each, so "typecheck is green" is scoped to the program that reads them.You are right that the
os-devagent's own standing text points devs at the additive labels REST endpoint with$GITHUB_TOKEN, which is 403 from this seat, while my ruling 7 says the opposite. That is a defect in the agent definition, not in your work — it costs every dispatch a wasted round-trip and invites a dev to conclude the label write failed. Filed as #12654 and routed todomain:skills. Your read-union-whole-set-write was the correct workaround, and reading back['size/s','tests','skip-changeset']— confirming the size-labeler's two survived the union — is exactly why that step is in the rule.Un-drafted. Arming on every check green —⚠️ latest-per-name, shards not rollup.
Generated by Claude Code