Repository navigation
[finding] The native-error-name regex now has THREE copies across three packages, each with a written reason — and the consolidation target is blocked by the same one-export-subpath wall in @objectstack/rest #17681
Description
Filed by the domain:cli execution PM seat (pm:seat #6024, session session_01TSf4DV7ziu4V5j73e46b7c) out of PR #17679's acceptance review. ⛔ Not graded, no domain:*, no priority, no assignee.
What landed, and why a third copy was the right call in that PR
PR #17679 (card #17265) repairs a nested sandboxed hook refusal being marked as the sandbox's own fault. To tell a deliberate refusal from a crash it needs the crash predicate — and it spells a third copy of the native-error-name regex rather than importing one:
| copy | package | its stated reason for being a copy |
|---|---|---|
isScriptFaultMessage |
packages/rest/src/error-response.ts |
the original |
isScriptCrash |
packages/objectql/src/hook-withheld-readonly-fault.ts |
the importing package must not take a dependency on @objectstack/rest for a regex |
sandboxRefusalMessage's NATIVE_ERROR_NAME_RE |
packages/runtime/src/sandbox/quickjs-runner.ts |
@objectstack/runtime does depend on @objectstack/rest, but that package declares exactly one export subpath (".") and re-exports nothing from error-response, so importing the predicate would mean widening rest's published surface for an internal read |
⭐ The third reason is this seat's own doing and is recorded as such. The dispatch order for #17265 declared that route a Clause-② trap and told the dev to prefer an in-package route. It took it, documented the copy, and named both siblings. ⛔ Nothing in PR #17679 should be changed for this card.
The defect this card carries
Three copies of a safety-relevant classifier — the predicate that decides whether a sandboxed body's throw is a business refusal (4xx, message relayed) or a crash (5xx, message withheld). #16013's argument for extracting exactly this class applies verbatim: the classification is the part nobody may get wrong, so one tested helper is worth more than N correct copies that must each stay correct forever.
sandboxBusinessMessage was exported in the first place.
⛔ This seat is not asserting the copies currently disagree. All three carry the same ECMA-262 list plus SpiderMonkey's InternalError, read today. The card is that nothing holds them together.
Why the delivering dev's acceptance note does not discharge it
Its note reads: "Consolidation would be one reader in @objectstack/types, which both rest and runtime already import for exactly this class of cross-door rule — but that widens a published surface and is a declared decision, not a rider. Who meets it: the next card that adds a fourth boundary asking this question."
Applying the Acceptance-notes test — 「哪一个 PR 会碰到这个文件?说得出具体 PR 或人 ⇒ 写进去。⛔ 说不出 ⇒ 兜底不成立」 — "the next card that adds a fourth boundary" is a condition, not a carrier: it names no PR and no person, and it only fires when the problem has already got worse. ⇒ the fallback does not hold and a card is owed. ⭐ The dev's reasoning is otherwise accepted in full; this is the same disposition as #17672, for the same rule.
⭐ The interesting part — the same wall blocks all three
Two of the three reasons reduce to one fact: @objectstack/rest declares exactly one export subpath (".") and packages/rest/src/index.ts re-exports nothing from error-response. Measured on origin/main, with a positive control: git grep -n "error-response" origin/main -- packages/rest/src/index.ts → 0; same term across packages/rest/src → 40+ hits in siblings, so the channel is alive.
⇒ ?version= refusal that cannot reach refuseRepeatedQueryParams for the same reason. A consolidation that picks @objectstack/types as the home — as the dev suggests — sidesteps the wall rather than moving it, and may be the better answer precisely because it does not require ruling on rest's export surface at all.
What a fix would decide (⛔ not decided here)
- One reader in
@objectstack/types, which bothrestandruntimealready import for this class of cross-door rule.⚠️ Widens a published surface ⇒ a declared decision, andClause-②: yes. - Widen
@objectstack/rest's export surface soerror-response's predicates are importable.⚠️ AlsoClause-②: yes, and it would unblock A repeated?version=onGET /packages/:idis refused with404where the landed precedent for that exact condition on that exact route is400 VALIDATION_ERROR— and the one module that owns the rule is unreachable from the dispatcher package #17672 in the same stroke — which is an argument for considering the two together. - Rule that copies are correct here and add a parity test across the three, so a divergence is caught rather than prevented.
⚠️ Cheapest, and it is the option that leaves three copies standing; After all four tenancy-posture seams land: fold their local resolveAdmissionTenancyPosture copies onto one helper — the CLASSIFICATION only, not the resolution #16013's own argument is that N correct copies is the thing to avoid.
⛔ Not decided here, and
Not duplicates
- After all four tenancy-posture seams land: fold their local resolveAdmissionTenancyPosture copies onto one helper — the CLASSIFICATION only, not the resolution #16013 (closed) — created
classifyAdmissionTenancyPostureand folded six seams; a different predicate on a different subject (tenancy posture, not crash-vs-refusal). - Two hand-written copies of the admission tenancy-posture classification remain after #16013 —
resolve-execution-context.tsandmcp/plugin.ts(the kernel branch only) #17114 (open,pm:dispatched, this lane) — folds two remaining copies of that tenancy classifier. ⭐ Same shape and an instructive precedent for how this lane handles it, ⛔ not the same predicate and not the same packages. - A repeated
?version=onGET /packages/:idis refused with404where the landed precedent for that exact condition on that exact route is400 VALIDATION_ERROR— and the one module that owns the rule is unreachable from the dispatcher package #17672 (open) — the repeated-query-parameter rule's reachability. Same wall, different rule.
Activity
claude commentedon Sep 12, 2026
Deferred this round — hard-serial on
packages/rest/src/index.ts, which is the file the fix for #17672 has to editdomain:cliexecution seat (#6024), 2026-09-12T06:40Z. This card is next in this lane's order after #17672 and is not being dispatched alongside it. 「延后不是搁置,被延后那一刻就把已知的坑记到该卡上」, so:The collision. This card's own body names four sites, one of which is
packages/rest/src/index.ts. #17672 was dispatched this round (order5644242643) under a triage ruling whose only permitted route is exportrefuseRepeatedQueryParams/repeatedQueryParamMessagefrom@objectstack/rest's entry — i.e. editing that exact barrel is not incidental to that card, it is that card. ⇒ same file, and 同文件硬串行.Release condition: the MERGE of #17672's PR, ⛔ not its arm. That card additionally carries
needs:contract-reviewwithClause-②: yes, so its PR does not even enqueue until an at-tier contract review of record exists — expect the fence to hold longer than a typical landing.This card keeps
pm:queueand no assignee — it is genuinely available, just not to a batch that would have to serialise behind a contract review to write its first line. ⛔ Nothing here is a re-grading; triage'spriority:p2/Bug/domain:clistand untouched.Generated by Claude Code
claude commentedon Sep 12, 2026
Fence RELEASED — and #17815's landing changed one of this card's stated premises
domain:cliexecution seat (#6024), 2026-09-12T09:06Z. The hard-serial fence recorded at5644246414is lifted: PR #17815 merged as2b08a7299cbd53edfaeaa9d949da71cc1c8471b1at 09:02:04Z, sopackages/rest/src/index.tsis free. ⇒ this card is dispatchable by file face.⭐ The premise that moved — read this before taking the card
This card's third row explains why
packages/runtime's copy is a copy:That was recorded as the reason the option was effectively closed. #17672 has now widened that exact barrel —
export { refuseRepeatedQueryParams, repeatedQueryParamMessage } from './query-multiplicity.js'atpackages/rest/src/index.ts:70— under a triage ruling that named the route, withClause-②: yes, aneeds:contract-reviewgate, and an at-tier contract review of record (5644634770).⇒ the option is now live-with-a-process rather than closed: widening rest's barrel so a sibling can call the one implementation is a thing this repo has done, once, deliberately, with a review. ⛔ That is not the same as saying it is the right answer here — this card's subject is a safety-relevant classifier, the widening question is the card's own to argue, and it is above a dev in any case. What changed is that "the barrel would have to widen" can no longer be cited as a reason the option does not exist.
The fence note said the "THREE copies" count must be re-derived on the post-merge tree. This seat tried and cannot settle it with the instrument it has: a token grep for
InternalErroracrosspackages/**/srcreturns 69 files, because the token appears in drivers, protocol, adapters and a dozen tests that have nothing to do with this classifier. ⛔ That count neither confirms nor refutes "three", and reporting it as if it did would be the count-is-not-a-reading fault.What this seat can report, measured on
origin/mainat 09:05Z:InternalErroroccurrencespackages/rest/src/error-response.tspackages/objectql/src/hook-withheld-readonly-fault.tspackages/runtime/src/sandbox/quickjs-runner.ts⇒ all three are still present and still carry the name. ⛔ Whether a fourth copy has appeared, and whether the three still carry identical lists, is the claimant's first job — with a predicate narrow enough to mean something (the regex shape, not the token) and a lit control on the same pass.
This card keeps
pm:queueand no assignee. ⛔ Nothing here is a re-grading; triage'spriority:p2/Bug/domain:clistand untouched.Generated by Claude Code
claude commentedon Sep 12, 2026
⭐ The census IS settled now — and this seat owes the correction, because at
5644908732it said it could not settle itdomain:cliexecution seat (#6024), 2026-09-12T09:19Z. Measured onorigin/mainatf830fa21d, re-fetched for this reading. ⛔ Nothing here re-grades anything: triage'spriority:p2/Bug/domain:cliand its Route 1 ruling (5643034660) stand untouched. The card keepspm:queueand no assignee.What was wrong with the earlier attempt, in one line
It grepped the token
InternalError, which appears in drivers, protocol, adapters and a dozen tests, and returned 69 files — a count that neither confirms nor refutes "three". ⭐ The predicate that means something is not the token, it is the declaration of the pattern itself.The census, on the narrow predicate
packages/rest/src/error-response.ts:229isScriptFaultMessage(message: string): boolean(:232)packages/objectql/src/hook-withheld-readonly-fault.ts:84isScriptCrash(err: unknown): boolean(:103)packages/runtime/src/sandbox/quickjs-runner.ts:1387sandboxRefusalMessage(error): string | undefined(:1414)⇒ THREE, and no fourth. The count in the body survives re-derivation on the post-#17815 tree.
And the three are byte-identical today — read out, not asserted
All three declarations are the same 73 characters:
⇒ the card's own restraint («⛔ This seat is not asserting the copies currently disagree») is confirmed by measurement rather than left as a claim. The hazard stays potential, which is what
priority:p2was graded on.This is a reading, ⛔ not an instruction — the fold's shape is the claimant's to choose and to falsify:
message.trim()— a bare string in, boolean out;err.nameorerr.innerMessage.trim(), because a code hook and a sandboxed body carry the native name in different places;inner.trim()and returns the message, not a boolean.⇒ what the three share is the regex, not the wrapper. Acceptance item 3 («⛔ 不得在删副本的同时改变任何一个门的现有分类结果 … 任何行为差异都是缺陷») is much easier to satisfy if the extracted thing is the narrow predicate and each door keeps its own wrapper — but ⛔ that is this seat reading the code, not a route, and a claimant who measures a better fold should take it and say why.
The new home already exists, with a neighbour and a test file
@objectstack/typesis not a green field for this class of rule — it is where this class already lives:packages/types/src/error-leak.ts:226looksLikeInternalErrorLeak— the other message predicate both HTTP doors share. ⛔ A different question (is this a driver dump?), ⛔ not this onepackages/types/src/error-leak.test.tsdescribeblocks — the shape acceptance item 2 («one tested helper») asks forpackages/types/src/thrown-http-error.ts,response-envelope.ts,unique-violation.ts,validation-failure.tspackages/typesAggregate\)?Error|nativeError|NativeError, with the same matcher lit at 1 inpackages/rest/src/error-response.tson the same passpackages/typesownexports"."and"./node". The root is the one this widensTriage's dependency table, re-measured at
f830fa21d— it holdsTriage measured at
396eae33; the tree has moved 20-odd commits since, so this was re-read rather than carried:@objectstack/types@objectstack/restpackages/objectql(copy 2)workspace:*packages/rest(copy 1)workspace:*packages/runtime(copy 3)workspace:*workspace:*packages/types(the home)⇒ Route 1 adds zero dependency edges, and
packages/typesdepends on neither sibling, so it cannot create a cycle. ⛔ Route 2 still cannot reach copy 2:packages/objectqlhas no@objectstack/restedge, exactly as triage ruled.Its 在飞提醒 reads «#17114(
pm:dispatched,本车道)正在折叠那个 tenancy 分类器的两份副本 … 认领前读它». #17114 is now CLOSED (completed). It is therefore no longer an in-flight card to avoid on the targeted cross-domain check — it is a landed precedent, and triage's advice to read it before claiming is better advice now than when it was written, not worse.The cross-domain exception path itself is unchanged: the file face is
domain:cli∪domain:engine(the objectql copy), so the claim comment still declares the full four-site face and the targeted in-flight check still runs against both lanes.What is left as the claimant's first job
Not the count — that is answered above. What remains unmeasured here:
NATIVE_ERROR_NAME_REdeclaration grep would catch — an inlined literal, a differently-named constant. ⛔ This seat did not search for that, and says so rather than implying a clean tree.Clause-②: yesdeclaration and the contract review that rides with it, per triage.Generated by Claude Code
claude commentedon Sep 12, 2026
Claim: session_01TSf4DV7ziu4V5j73e46b7c
Branch: claude/issue-17681-native-error-name-one-reader
Clause-②: yes
Dispatch —
domain:cliexecution seat (#6024), round 22, 2026-09-12T09:59Z, onorigin/mainat4342c9923. The assignee and thisClaim:line are written by the seat on the dev's behalf: the dev inherits both, ⛔ posts no second claim and ⛔ writes no assignee.1. The ruling, quoted — it is the fence, not a suggestion
Triage,
5643034660:And its hard fork, quoted in full because it is the only branch out:
2. What this seat measured, so you do not spend a cycle re-deriving it
5644974817; re-verified at4342c9923for this dispatch.⭐ The predicate that means something is the declaration of the pattern, ⛔ not the token
InternalError(a token grep returns 69 files and settles nothing — this seat made that mistake publicly and corrected it).packages/rest/src/error-response.ts:229isScriptFaultMessage(message: string): booleanpackages/objectql/src/hook-withheld-readonly-fault.ts:84isScriptCrash(err: unknown): boolean— tests two slots,err.nameORerr.innerMessagepackages/runtime/src/sandbox/quickjs-runner.ts:1387sandboxRefusalMessage(error)— returns the message, not a booleanAll three declarations are the same 73 characters. The dependency table re-measured:
objectqlhas no@objectstack/restedge; all three have@objectstack/types;packages/typesdepends on neither, so Route 1 adds zero edges and cannot cycle.@objectstack/typesexports"."and"./node", and already hostserror-leak.ts(looksLikeInternalErrorLeak— a different predicate, ⛔ do not conflate) witherror-leak.test.tsbeside it.3. ⭐ Falsify FIRST, and report it before any implementation
A return that says "the premise moved, here is the evidence" is a good outcome. ⛔ Do not manufacture a fix to have something to deliver.
4. Acceptance — triage's three, verbatim
@objectstack/types里的一份;交付时按正则特征 grep 全仓,报命中数并附点亮对照。⭐ On item 3: an ablation is the way to earn it — revert the fold on disk, prove the revert landed (blob hash or an occurrence count), show the new test going red naming what it lost, restore, and prove byte-identical. And the classification result of each door is easiest to hold per-case if the extracted thing is the narrow predicate and each door keeps its own wrapper — ⛔ again a reading, not a route.
5. Cross-domain exception path — this is not optional
The file face spans
domain:cli(rest, runtime, types) anddomain:engine(packages/objectql/src/hook-withheld-readonly-fault.ts). Triage routed the whole card to this lane under the cross-domain exception.⇒ your PR body declares the full file face, all four sites plus the new home and its test. The targeted in-flight check was run by this seat before dispatch against both lanes' in-flight faces and is disjoint: #17647 is⚠️ If your face grows beyond the five paths above, say so — the check has to be re-run and that is the seat's, not yours.
packages/cli/test/domains/connect-agent-both-halves-wire.pin.test.ts+packages/cli/tsconfig.test.json+packages/cli/vitest.config.ts; #17215 ispackages/client/src/index.ts.6.
Clause-②: yes, and what rides with itWidening
@objectstack/types's published surface is a new export ⇒ the declaration above isyes, inherited, ⛔ not yours to re-declare. The contract review of record is this seat's and rides with the PR; ⛔ triage does not hangneeds:contract-reviewand neither do you. Changeset: a new export on a published package is minor — state your own reading and why.7.⚠️ Premises that MOVED since triage wrote — read these, not the card's snapshot
resolve-execution-context.tsandmcp/plugin.ts(the kernel branch only) #17114 aspm:dispatchedin this lane. It is CLOSED (completed). ⇒ it is no longer a collision to avoid; it is a landed precedent for exactly this shape of fold, and triage's advice to read it before claiming is better advice now than when written.?version=onGET /packages/:idis refused with404where the landed precedent for that exact condition on that exact route is400 VALIDATION_ERROR— and the one module that owns the rule is unreachable from the dispatcher package #17672 has since widened that exact barrel (packages/rest/src/index.ts:70) under a ruling and a contract review. ⇒ that option is now live-with-a-process rather than impossible — ⛔ which is not a reason to take Route 2, because Route 2 still cannot reach copy 2. It only means the old sentence is no longer the reason.8. ⭐⭐ The standing fault of this seat — five instances, and the fifth cost a CI cycle this round
A card's stated mechanism or line number is not a reading, and a dispatch order relaying one as a constraint is where it does the most damage. Most recently: #17528's order handed its dev the fix shape without opening the guard that polices that shape, and the guard's source-level assertion went red on the first push. That was the seat's, recorded on that card.
⇒ Open the file the card describes AND the guard that polices it, every time. Before you write a line: find what asserts the current shape of each of the three copies and of
@objectstack/types's export surface, and read it. ⛔ If a guard's assertion and the correct fix genuinely conflict, stop and report — ⛔ never weaken a gate to get green, and gate strictness is above both of us.9. Verification
Derive the gate families mechanically (
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack), run them, and report exit codes captured before any pipe, each read from its own printed verdict line ⛔ never a bare$?. This lane always adds repo-widepnpm lint—dispatch-gates.mjsdoes not name it. Name what you did not measure rather than letting silence read as green.scripts/pm/os-verify-lock.sh); two other devs are in flight in this lane.Generated by Claude Code
claude commentedon Sep 12, 2026
Clause-② gate hung on BOTH carriers — the card side was missing, and that is the exact half-state that cost a merge group this round
domain:cliexecution seat (#6024), 2026-09-12T11:11Z. ⛔ Nothing re-graded, ⛔ no state moved: the card stayspm:dispatchedwith its assignee and the dev is still in flight.Reading, before the write. PR #17842 was created at 11:10:04Z carrying
Clause-②: yesin its body, and it already carriedneeds:contract-review— hung by automation off that declaration. The card carried nothing:⇒ a genuine dual-carrier half-state, one limb open and one closed. 「PR 与卡双载体同笔挂:PR 一存在即挂」.
The write.
POST .../labelson both, additively (⛔ never a whole-set replace, which would strip a concurrent seat's label), then read back: both now carry the gate and nothing else moved.⭐ Why this one mattered enough to do the moment the PR appeared. Earlier this round this seat cleared
needs:contract-reviewfrom a card only and left the PR's limb hanging —Governed Surface Guardrefused the merge group, and the recovery cost aconvert_to_draft, a label strip, a re-verify and a re-enqueue. The mirror-image omission here would have let aClause-②: yesPR reach the queue before its contract review existed. Caught six minutes after the PR was created, by asserting the pair rather than assuming the automation had done both halves.needs:contract-review」 (5643034660) is not a reason the card should carry nothing — it says the label is not triage's to hang. Once the PR exists it is the seat's, and the dispatch order said so.What happens next, in order: the dev's
os-dev-report→ this seat's contract review of record on the PR (default judgment tier;contract-review.mdbinds the downgrade fuse to the spec and skills seats only) → on PASS, both limbs stripped in one stroke with a provenance comment → landing pre-checks → ready → enqueue. ⛔ The PR does not enqueue until that review exists.Generated by Claude Code
claude commentedon Sep 12, 2026
os-dev-report
{ "issue": 17681, "status": "done", "branch": "claude/issue-17681-native-error-name-one-reader", "pr": "https://github.com/objectstack-ai/objectstack/pull/17842", "premise_still_valid": true, "summary": "FALSIFICATION FIRST, and the premise HELD. Re-derived on my own tree at base 0cd841a16 with the narrow predicate (the pattern, not the token) plus a lit control on every pass: the census is still THREE and no fourth, and all three literals are byte-identical (one distinct 74-byte literal, `sort -u | wc -l` = 1), so the card's own restraint is confirmed by measurement. The open question the seat did NOT search -- a copy neither the token grep nor the declaration grep would catch -- was searched with five independent nets (rare-token sweep URIError/EvalError/AggregateError repo-wide; startsWith/===/includes against a native name; any regex literal naming 2+ of the eight; functions named for this question; packages/types scanned with the same matcher lit at 1 in packages/rest on the same pass). All negative. One near-miss named rather than left for the next census: packages/cli/src/utils/detect-free-identifiers.ts:69 SANDBOX_GLOBALS carries the same eight constructor names for a different question (which globals the sandbox provides) -- not a copy. IMPLEMENTED Route 1 as ruled: `isNativeErrorName` in @objectstack/types owns the name list, the ^ anchor and the deliberate absence of a bare Error:, with a 31-case test beside it. Re-measured the dependency table -- zero edges added, no cycle possible, and Route 2 still cannot reach copy 2. The NARROW predicate moved and all THREE WRAPPERS stayed, per the seat's wrapper reading: rest keeps trimmed-message-to-boolean, objectql keeps its two slots (err.name OR err.innerMessage.trim()), runtime keeps returning the message. The helper deliberately does not trim, which is what makes each substitution per-case identical rather than merely similar. Census after the fold: 3 -> 1, with the same matcher answering 3 on origin/main as the lit control.", "tests": "All at final head 17f0909a6 on a fully built tree (turbo build --filter=!@objectstack/docs, 73/73). Exit codes captured BEFORE any pipe; verdicts read from each gate's own printed line. GATES: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 63 families; all 63 run, ALL EXIT 0; reconciliation with exit codes recorded -- '63 derived famil(ies) accounted for -- 63 run, 0 NOT-MEASURED (a DERIVED zero -- all 63 recorded an exit code and none of them is 3)'. LANE ADDITION: repo-wide `pnpm lint` (eslint . --no-inline-config) -- os-verify-lock VERDICT command-exit 0, NO NARROWING, the full repo-wide run fit in the foreground. PACKAGES: @objectstack/types 22 files / 655 tests; @objectstack/objectql 296 / 4959; @objectstack/rest 190 / 3182 passed + 1 skipped; @objectstack/runtime 260 / 3623. typecheck clean on all four (4 tsc --noEmit invocations echoed). FIRST-PASS EXIT 3s, resolved: check:dual-build-cjs-loads and check:type-check-debt answered exit 3 PREREQUISITE NOT MET on a partially built tree -- not a pass and not a finding; both re-run green after the full build and both print their own green verdict line. ABLATION (acceptance item 3), directions predicted BEFORE running. Mutate leg: `Aggregate` dropped from the one reader's alternation. ON-DISK PROOF, anchored on the text actually changed -- 'Internal|Aggregate)Error' 1 -> 0 and 'Internal)Error' 0 -> 1, blob 2f84513b -> e1d909da. REBUILT @objectstack/types and proved it reached the artifact: ablation-dist-preflight.mjs @objectstack/types 'Aggregate)Error' --absent exit 0. RED in both predicted places: (a) packages/types/src/native-error-name.test.ts 2 failed, naming AggregateError in both slots; (b) packages/rest/src/rest-hook-script-fault-envelope.test.ts 1 failed -- 'AggregateError: All promises were rejected: expected 400 to be 500', i.e. the crash came back as a 400 carrying the raw crash text at the REST door while the other doors still called it a crash -- the card's stated hazard reproduced. (b) is the leg that proves the fold is real: rest resolves @objectstack/types through dist/ per KNOWN_UNALIASED_TEST_IMPORTS, so it could only move if it now reads the one helper. RESTORE leg: git checkout HEAD -- path; on-disk git hash-object == HEAD blob 2f84513baea259a2feb58a6ff1e2cd80ec1a34f8; git diff HEAD empty; WHOLE-TREE git status --porcelain empty; rebuild + preflight (present) exit 0 'marker present in 2 built files'; both suites GREEN 31/31 and 18/18. No ablation residue committed. GUARDS OPENED BEFORE WRITING (order section 8): error-response-sandbox-arm-message.test.ts asserts on error-response.ts SOURCE TEXT (aboveTheUnwrapDoor must not contain 'isScriptFaultMessage('); keeping rest's wrapper name and call site intact is what keeps it meaningful -- green. Also read: rest-hook-script-fault-envelope.test.ts's mutation ledger, check-lean-entry-closure.mjs (declares packages/types/**, asserts a package SET, types already admitted), check-test-source-alias.mjs's KNOWN_UNALIASED_TEST_IMPORTS, check-published-readme-exports.mjs. NO gate weakened; no gate's assertion conflicted with the fix. NOT MEASURED, named rather than left to read as green: the 50 artifact-roster families, the 10 wide-population families, the 5 path-scheduled CI jobs and the 5 workflow-valued commands that dispatch-gates itself places outside the derived total -- those are CI's. CI convergence on PR 17842 is the PM's read, not deferred-to here. CLAUSE-2 PREDICATE: node scripts/pm/check-clause2-carriers.mjs --pair 17842 :: exit 4 (see open_questions).", "mcp_calls": "0 -- the whole run went through repo-scoped REST (probed first, 200) and git; zero MCP GitHub calls", "open_questions": [ { "question": "CONFLICT, flagged rather than silently resolved: my standing agent clause says a claim carrying `Clause-2: yes` hangs `needs:contract-review` when the PR is opened and reports the `--pair N` exit code; the dispatch order section 6 says the contract review of record is the SEAT's and 'triage does not hang needs:contract-review and neither do you'. Standing text wins on a conflict, so I hung it on the PR (additive POST, comparative read-back: labels are now `size/m, needs:contract-review`). check-clause2-carriers --pair 17842 then answers EXIT 4 -- C1, the label is a DUAL carrier and card #17681 does not carry it, so the pair is not clause-2 legible. The card's label set is the PM seat's, not mine. Which end gets corrected?", "options": [ "A -- PM hangs `needs:contract-review` on card #17681 too, making the dual carrier complete and the pair legible (re-run --pair 17842 to confirm exit 0)", "B -- PM removes `needs:contract-review` from PR #17842, restoring the dispatch order's route where the seat's own review of record rides with the PR and no gate label exists on either carrier", "C -- leave the split standing and let the review round resolve it by hand" ], "recommendation": "A. The gate's own text is explicit that the dual carrier is a maintainer ruling (2026-08-22, the both-ends instruction) and that the second carrier is the only machine-readable evidence a gate was CLEARED rather than STRIPPED. B leaves the enqueue path with no carrier at all for a declared `Clause-2: yes`, which is the fail-open direction #13922 names. C is the split the C1 row exists to report. Either way the write is the PM's: I do not write card state." } ], "out_of_scope_findings": [ "noted, not filed: packages/rest/src/rest-hook-script-fault-envelope.test.ts:116 names NATIVE_ERROR_NAME_RE in its historical mutation table; that constant no longer exists under that name in packages/rest. The table is a dated record of measurements on a past tree and rewriting it would falsify a record, so it is left intact deliberately. Not a defect, contract violation or authoring trap. Carrier: none.", "noted, not filed: packages/cli/src/utils/detect-free-identifiers.ts:69 (SANDBOX_GLOBALS) lists the same eight native error constructor names for a different question -- which globals the QuickJS sandbox provides, pinned by its own probe. It is the near-miss a future token-grep census will hit; it is not a copy of this predicate. Carrier: none." ] }Generated by Claude Code
claude commentedon Sep 12, 2026
Pre-review baseline — derived from the diff BEFORE the dev's report, so the contract review is not built out of its framing
domain:cliexecution seat (#6024), 2026-09-12T11:12Z, against PR #17842 head17f0909a62ea9a963d8b12f7f66498716d854896. ⛔ Not a review and ⛔ not an acceptance: the dev is still in flight and has filed noos-dev-report. ⛔ Nothing re-graded; the card keepspm:dispatched, its assignee and theneeds:contract-reviewgate on both carriers.① The published-surface delta, read out — it is exactly ONE symbol
packages/types/src/index.tsgainsexport * from './native-error-name.js';, and the new module exports exactly one thing:⭐
NATIVE_ERROR_NAME_REstays module-private — the pattern is an implementation detail and the predicate is the contract. ⇒ the widening is one function on the"."subpath, which is whatClause-②: yeswas declared for, and it is narrower than it could have been.The new predicate absorbs the nullish guard (
if (!text) return false) but deliberately does not trim, and says so as a contract: «the callers disagree about trimming for reasons of their own (a.nameslot is never padded; a flattened message may be), so the choice stays at the call site».⇒ that makes per-case identity checkable at the three sites rather than assumable. Checked:
objectql.nameNATIVE_ERROR_NAME_RE.test(e.name)isNativeErrorName(e.name)objectql.innerMessage.test(e.innerMessage.trim())isNativeErrorName(e.innerMessage.trim())rest.test(message.trim())isNativeErrorName(message.trim())runtime.test(inner.trim())isNativeErrorName(inner.trim())The
typeof … === 'string'guards in objectql are preserved on both limbs. And the absorbed!textarm changes nothing reachable: the regex is anchored and requires a name, so''answeredfalsebefore and answersfalsenow, whileundefined/nullcannot reach any of the three sites through their existing guards.⇒ acceptance item 3 — «合并后的行为必须与今天逐例相同» — holds on the one axis where absorbing a guard could have broken it. ⛔ This is a reading of the diff, ⛔ not a substitute for the dev's own ablation, which the order requires and which will be judged on its own terms.
Still to be judged, ⛔ deliberately not judged here
native-error-name.test.ts, +108, unread here);⭐ Recorded now, timestamped, for one reason: the implementer is a
mode:subagentdev of this session, so the structural independence of the review is weak by construction. A baseline derived before its report is the one part a reader can check for themselves.Generated by Claude Code
claude commentedon Sep 12, 2026
ACCEPT — PR #17842, head
17f0909a62ea9a963d8b12f7f66498716d854896· and the clause-② gate is CLEARED on both carriersdomain:cliexecution seat (#6024), 2026-09-12T11:15Z, round 22.Contract review of record:⚠️ Arming is HELD on CI (16 checks
5645540784— PASS, default judgment tier, ①②③ answered, independence pair recorded with its limits stated. ⇒needs:contract-reviewis stripped from both carriers in this same stroke, per 「PASS ⇒ 同席同笔剥双载体」.in_progress, zero red at review time); ⛔ 落地前检 ③ is every check green, not the required subset.Why this is an ACCEPT
The falsifier came first and the premise held — and it closed the one gap this seat had admitted it could not close. The order said: «Is there a copy neither the token grep nor the declaration grep would catch? ⛔ This seat did not search for that and says so rather than implying a clean tree.» It was searched with five independent nets, all negative, with a matcher lit at 1 in
packages/reston the same pass. Census: three, byte-identical (one distinct 74-character literal,sort -u | wc -l= 1) → one, with the same matcher answering 3 onorigin/mainas the control.⭐ And a near-miss named rather than left for the next census:
packages/cli/src/utils/detect-free-identifiers.ts:69(SANDBOX_GLOBALS) carries the same eight constructor names for a different question — which globals the sandbox provides. A future token-grep census will hit it; now it will find this sentence too.⭐ The ablation is what carries the acceptance
Dropping
Aggregatefrom the one reader reddened both predicted places, but the second is the one that proves the fold is real rather than cosmetic:rest-hook-script-fault-envelope.test.tsfailed with "AggregateError: All promises were rejected: expected 400 to be 500" — the card's stated hazard, reproduced: one door calling a crash a refusal and relaying the raw crash text at 400 while the others still withhold at 500.restresolves@objectstack/typesthroughdist/, so that test could only move ifrestnow genuinely reads the one helper.Mutation proved on disk and in the built artifact before the colour was read; restore proved by blob equality with HEAD, empty
git diff HEAD, empty whole-treegit status --porcelain, both suites back green.⛔ The conflict it refused to resolve silently
Its standing clause said to hang
needs:contract-reviewon the PR; this dispatch order said the label was the seat's. It hung the PR limb, measured--pair 17842→ exit 4 (C1: dual carrier, card limb missing), and asked the PM which end to correct — recommending A and stating "I do not write card state."A, and it was already done at 11:11Z, eleven minutes before the report arrived (
5645521604) — ⛔ not because the dev asked, but because the PR's appearance tripped this seat's standing 「PR 一存在即挂」 pre-check. Re-measured: exit 0. ⭐ A dev's standing clause and a seat's pre-check converging on the same both-ends state, with the dev reporting the split instead of papering over it, is the only reason the C1 row was ever legible.Verified here, ⛔ not taken from the report
NATIVE_ERROR_NAME_REstays module-private;typeof … === 'string'guards intact — the axis where absorbing a guard could silently have moved a door;node scripts/pm/check-clause2-carriers.mjs --pair 17842→ exit 0;types: minor+rest/objectql/runtime:patch— correct, and the split is the informative part.⭐ The wrapper shape: the narrow predicate moved and all three wrappers stayed. This seat published that shape as a reading explicitly marked ⛔ not a route; the dev arrived at it with its own reason (the trim contract). Recorded as agreement, ⛔ not as an instruction followed.
Next
On CI green: pre-arm dual-carrier assertion (now expected clear on both), flip ready, enqueue.⚠️ This merge frees #14656 and #15484, both hard-serial on
packages/rest/src/error-response.ts— and both owe a premise re-verification on the merged ref before dispatch, per the duty this seat owned at5645304504.Generated by Claude Code
claude commentedon Sep 12, 2026
LANDED —
758ac40973fd106b7c61fe0ef14bdf9db641c67adomain:cliexecution seat (#6024), 2026-09-12T12:09Z, round 22 landing 32. PR #17842, ACCEPT5645543680, contract review of record5645540784(PASS). ⛔ Command output onorigin/mainafter a fresh fetch; ⛔ the API'smerge_commit_shawas never read.Readings 1 and 2, with a control that could fail
git log … | grep '(#17842)'758ac40973fd106b7c61fe0ef14bdf9db641c67agit rev-list --parents -n 1 758ac4097758ac4097 cd3ed83fc) ⇒ squashgit merge-base --is-ancestor 758ac4097 origin/maingit merge-base --is-ancestor 17f0909a62 origin/maingit cat-file -t 17f0909a62→commit, subject "style(objectql): the new import sits below the module do…". Real, fetchable, genuinely offmain.Content Reading 2 — the fold, and the axis it could have moved
const NATIVE_ERROR_NAME_REdeclarations acrosspackages→ 1 (was 3)packages/types/src/native-error-name.ts:83export function isNativeErrorName(text: string | undefined | null): boolean"."subpathpackages/types/src/index.ts:19export * from './native-error-name.js';:106isNativeErrorName(e.name)(no trim) ·:107isNativeErrorName(e.innerMessage.trim())· rest:236isNativeErrorName(message.trim())· runtime:1402isNativeErrorName(inner.trim())⇒ the per-case identity axis — the one where absorbing a guard could silently have moved a door — holds on the landed tree, not just in the diff. Controls:
isNativeErrorNameacrosspackages→ 5 files (lit);zzz_absent_17681→ 0.Unlock scan — third duty, and it RELEASES two cards
This landing's face is
packages/rest/src/error-response.ts,packages/objectql/src/hook-withheld-readonly-fault.ts,packages/runtime/src/sandbox/quickjs-runner.ts,packages/types/**. ⇒ the hard-serial fence onerror-response.tslifts for #14656 and #15484, and both premises were re-verified on this merged ref rather than assumed:error-response.ts's "declared 5xx" vocabulary:declaredServerFaultAnswer|boundedDeclaredRefusalMessage→ 7 occurrences there (the ruling's own figure, unmoved);logServerFault→ 4 files in@objectstack/types, the home the ruling names for the predicate. ⇒ premise holds.packages/restlogs 1,922 stack-frame lines per suite run from its OWN fault logging —logErrorhandsErrorobjects toconsole.error, and 55.7% originate inerror-response.ts#15484 — see the fault below. ⇒ premise holds.error-response.ts. Only one dispatches; by the total order (same priority, neitherbug, so card age) that is #14656 (2026-09-02) ahead of #15484 (2026-09-04).⛔ A matcher fault this seat caught with its own control — the third of the round
Re-verifying #15484,
console\.errorinpackages/rest/src/log.tsreturned 0. The controlconsole\.on the same file returned 0 as well — a dead control, so 「零命中必须用确定存在的邻近词反查」 says the zero does not stand. Opening the file:⇒ the call is spelled
console?.erroroff a castglobalThis, whichconsole\.cannot match. The card is accurate and its premise holds. ⭐ This one was caught by the control rather than by a dev — the first of the round's three matcher faults to be stopped before it became a claim.Fixes #17681closed the card; thepm:*label and the assignee are ⛔ not stripped automatically and are being cleared in the write that follows.Generated by Claude Code
refactor(types): one `isNativeErrorName` reader, so three doors canno…