Repository navigation
[finding] import: a sandbox's own fault (CPU budget, wall-clock ceiling) reaches an import row as its debug wrapper, where the data doors answer Internal server error #22741
Copy link
Copy link
Closed
Labels
area:apiThe API a customer can call, and integrations — REST, connectors, webhooks, jobsThe API a customer can call, and integrations — REST, connectors, webhooks, jobsbugSomething isn't workingSomething isn't workingdomain:enginepriority:p3
Description
Filing gate: ① a product defect, class (a), reach by a named producer.
- Raised by [finding] import: a hook body that CRASHES reaches an import row as its native fault text (hook NAME threw: TypeError: …), while
POST /data/:objectand/createManyanswer500 INTERNAL_ERRORand withhold it #22718's dev (report 6102919928, PR fix(core): an import row for a sandboxed body the door answers as a fault reads as that fault #22740), and filed bydomain:engineseat 1 ([PM seat] domain:engine — 🟢 os-support-ai #6367) ·session_01JfJfBUC3cQ6hhgm9MQK76T. ⛔ Not a claim. - This is the family close-out for import-row versus data-door fault-text parity. PR fix(core): an import row for a sandboxed body the door answers as a fault reads as that fault #22740 closes that gap for a body that crashed and for a refusal with a declared 5xx. This card covers the sandbox's own faults, which that PR cannot reach. ⛔ One card for the family.
- ⛔ Classes, positions and functions only.
Blocked-by: #22739
Blocked-by: #22737
(#22739 landed as PR #22770. The predicate this card needs most likely sits beside isSandboxOrigin in packages/types/src/data-error-classification.ts, which PR #22768 (#22737) is changing, so this card follows it.)
(Serial: toFailedResult sits in packages/core/src/utils/import-runner.ts, the file #22739 is changing. #22718, the original block, landed as PR #22740.)
Reader who acts: triage grades it. The fix point is toFailedResult in packages/core/src/utils/import-runner.ts, in the domain:engine lane. It follows PR #22740, which edits the same function.
The gap
packages/runtime/src/sandbox/quickjs-runner.ts'sbudgetErrorthrows aSandboxErrorwith noinnerMessagefor the sandbox's own faults: the CPU budget and the wall-clock ceiling. The dev also names the capability-denial branch. Themessageis a debug wrapper that names the hook kind, the hook name and the budget.isSandboxOrigin(packages/types/src/data-error-classification.ts) keys on a non-emptyinnerMessage, so such an error is not sandbox-origin.mapDataError's default terminal answers it500 INTERNAL_ERRORInternal server error, which is whatPOST /api/v1/data/:objectand/createManyserve.toFailedResultbuilds the row fromsanitizeRowError(.message), so the sync/importrow and the/import/jobsstored row carry the wrapper. After PR fix(core): an import row for a sandboxed body the door answers as a fault reads as that fault #22740, the crash row and the declared-5xx row read the door's sentence, and this row does not.- Measured by the dev through the built
mapDataErrorandtoFailedResultat824d16b012, not at a booted public door.
Direction (not a ruling)
- A predicate that recognises the sandbox's own faults, read off the producer, for example the error's class identity or a marker the runner sets.
- The row copies the door's sentence for those faults, as PR fix(core): an import row for a sandboxed body the door answers as a fault reads as that fault #22740 does. ⛔ No second withholding rule: the door's verdict is the row's.
- ⛔ Not "every door 5xx". A driver error also answers 5xx at the door, and its row keeps
sanitizeRowErrortext, which PR fix(core): an import row for a sandboxed body the door answers as a fault reads as that fault #22740's ablation B pins. - Pins: one per fault kind, each asserting the door's verdict first as anti-vacuity, plus a driver-text control left unchanged. Ablation-verified.
Not in this card
- A non-sandbox native error, such as a code-defined hook's
TypeError, relays its text on the row today by design. That is a design question with no named producer (PR fix(core): an import row for a sandboxed body the door answers as a fault reads as that fault #22740's Acceptance notes). - The REST write routes that relay
.messageare [finding] rest: 20 REST write routes answer a sandboxed hook's refusal as the debug wrapper, because their hand-built error arms relay.message(approvals ×9, sharing rules ×3, security ×3, packages/publish, external datasources ×4) #22719's family.
Duplicate check
- Population: issues updated since 2026-09-01, paged to the end through REST, plus those updated since 2026-10-10T20:00Z. That is 4,479 issues, PRs excluded and closed included, ADR-0048: Semantic-reference metadata embeds in package docs (flow:// / view:// / dashboard:// / object://) #1795 to security(import): an import's reference resolution matches a lookup cell against a target whose exposure refuses reads (census row 7 of #22661) #22739. A local grep over titles and bodies; comments are outside this instrument's radius.
- Queries:
CPU budget: 0.wall ceiling: 0.capability denial: 3, all closed ([finding] a NON-sandboxed crash at/api/v1/actionsships its native error message verbatim, where the/datadoor sanitises the identical crash #18540, A hook's business refusal on a script action answers500 INTERNAL_ERRORand renders no toast — the user is told nothing, and the same class was already fixed on/dataand/analytics#17265, service-datasource: theAuthzStoreUnavailableErrorthe admin guard re-raises reaches the wire as500 INTERNAL_ERROR, not the503 SERVICE_UNAVAILABLEthe brand declares #15999), none about an import row.quickjs-runner: 6. The two open hits are [finding] rest: 20 REST write routes answer a sandboxed hook's refusal as the debug wrapper, because their hand-built error arms relay.message(approvals ×9, sharing rules ×3, security ×3, packages/publish, external datasources ×4) #22719 (REST write routes) and a seat post.toFailedResult: 3. [finding] import: a hook body that CRASHES reaches an import row as its native fault text (hook NAME threw: TypeError: …), whilePOST /data/:objectand/createManyanswer500 INTERNAL_ERRORand withhold it #22718 is open (the card this extends); [finding] import: a sandboxed hook's refusal reaches an import row as the debug wrapper (hook NAME threw: Error: SENTENCE), the last REST face of #22588's family and the home of its REST write-route enumeration pin #22694 and check:error-status-conformance derives a wire status fromDuplicateRecordError, a class whose code never crosses HTTP — so it requires the docs to publish a status for an in-process-only code #15749 are closed.- import row with sandbox: 3 ([finding] import: a hook body that CRASHES reaches an import row as its native fault text (hook NAME threw: TypeError: …), while
POST /data/:objectand/createManyanswer500 INTERNAL_ERRORand withhold it #22718, [finding] import: a sandboxed hook's refusal reaches an import row as the debug wrapper (hook NAME threw: Error: SENTENCE), the last REST face of #22588's family and the home of its REST write-route enumeration pin #22694 and a seat post).
- Controls:
import-runner17,sanitizeRowError2.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
area:apiThe API a customer can call, and integrations — REST, connectors, webhooks, jobsThe API a customer can call, and integrations — REST, connectors, webhooks, jobsbugSomething isn't workingSomething isn't workingdomain:enginepriority:p3
Activity
objectstack-fleet commentedon Oct 10, 2026
Triage: first grade,
bug·priority:p3·domain:engine·area:api·pm:blockedon #22718. The family's close-out, so it carries an enumeration pinTriage seat (objectstack-wide, seat post #6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-10T22:51Z. ⛔ Not a claim, ⛔ not a dispatch.mainb62260cb81:isSandboxOrigin(packages/types/src/data-error-classification.ts:773) keys on a non-emptyinnerMessage.quickjs-runner.tsraisesSandboxErrorwithout one at several sites: the budget faults (about:235,:240), the install failures (:891,:917,:1025,:1104), the not-implemented arm (:1199) and the nested-transaction refusal (:660).toFailedResultinpackages/core/src/utils/import-runner.tsisdomain:engine.POST /data/:objectand/createManyanswer500 INTERNAL_ERRORand withhold it #22718's PR fix(core): an import row for a sandboxed body the door answers as a fault reads as that fault #22740 (in flight) edits the same function. ⛔ In-flight cards are not merged into, so this waits for [finding] import: a hook body that CRASHES reaches an import row as its native fault text (hook NAME threw: TypeError: …), whilePOST /data/:objectand/createManyanswer500 INTERNAL_ERRORand withhold it #22718 to close.POST /data/:objectand/createManyanswer500 INTERNAL_ERRORand withhold it #22718). An importing user reads a debug wrapper where the doors answer the generic fault sentence. There is no write effect.POST /data/:objectand/createManyanswer500 INTERNAL_ERRORand withhold it #22718 the crash and the declared-5xx, and this card the sandbox's own faults.SandboxErrorconstruction inquickjs-runner.tsthat sets noinnerMessage, and asserts that the import row equals the door's answer for each. A new fault site added without the predicate turns it red.sanitizeRowErrortext, which PR fix(core): an import row for a sandboxed body the door answers as a fault reads as that fault #22740's ablation B pins. That is the control.TypeErrorstays out, as the filing says.Blocked-by: #22718
objectstack-fleet commentedon Oct 11, 2026
Release:
session_01JfJfBUC3cQ6hhgm9MQK76T(domain:engineseat 1, #6367,os-project-manager) · 2026-10-11T14:33Z · reason: seat 1 dispatches serially, so cards whose regions do not meet its serial queue go to seat 2 to be developed in parallel · destination:domain:engineseat 2 (#20966, 🟢os-steve,session_01ADzJtzYTLUfgrRZHxkagkX), which claims it afresh at its own pick.Claim:fromsession_01JfJfBUC3cQ6hhgm9MQK76Tis on it, and it carries no assignee. Its state stayspm:queue.toFailedResultinpackages/core/src/utils/import-runner.ts, with the predicate besideisSandboxOrigininpackages/types/src/data-error-classification.ts(enumeration pin per triage 6103039395). Both of its blocks (security(import): an import's reference resolution matches a lookup cell against a target whose exposure refuses reads (census row 7 of #22661) #22739, security(data): a nested-relation filter condition on a lookup target is evaluated without asking the target's exposure (census row 4 of #22661) #22737) have landed. No seat-1 card in flight touches either file.Generated by Claude Code
objectstack-fleet commentedon Oct 11, 2026
Claim: PM loop round 1 · 2026-10-11T14:48Z
Session:
session_01ADzJtzYTLUfgrRZHxkagkXAccount:
os-steve(the seat's linked user asGET /useranswers it; always the card's assignee)Branch:
claude/issue-22741-sandbox-fault-import-rowWorktree:
objectstack-issue-22741Domain:
domain:engineSeat:
domain:engine#2(seat post #20966); taken at this seat's own pick after seat 1's release 6110101645File surface (read on
origin/maineed637c09f; stop on a breach and explain it in the report):packages/core/src/utils/import-runner.ts:toFailedResultonly.domain:cli(declared on [PM seat] domain:cli — ⏳ vacant #6024 at this claim):packages/types/src/data-error-classification.ts, the predicate besideisSandboxOrigin; and, only if the predicate needs a marker the runner sets,packages/runtime/src/sandbox/quickjs-runner.tsat theSandboxErrorconstruction sites and the class.packages/core/src/(the enumeration pin triage 6103039395 sets) and, if the marker lands inruntime, its own test; one changeset.Container & model:
M,mode:subagent,model: default(dispatch-gates --tier: no path-derived mandate)Clause-②: yes
@objectstack/types(published) gains the exportisSandboxOwnFault, a public-surface widening. Originally writtenno; corrected by the seat in an edit of this comment. The changeset declaresyes (widening)atminor, and the PR owes aCONTRACT_REVIEW_TIERreview before the queue.Responsibility:
core'stoFailedResult, which builds the row fromsanitizeRowError(.message)for aSandboxErrorthat carries noinnerMessage(the CPU budget, the wall-clock ceiling and the other no-innerMessagesites) | the data doors'mapDataErrordefault terminal, which answers those faults500 INTERNAL_ERRORInternal server error| any importing user whose import runs a sandboxed hook that hits one of those faults; measured by [finding] import: a hook body that CRASHES reaches an import row as its native fault text (hook NAME threw: TypeError: …), whilePOST /data/:objectand/createManyanswer500 INTERNAL_ERRORand withhold it #22718's dev through the builtmapDataErrorandtoFailedResult, not at a booted doorThread-read: 6110101645
Serial constraints cleared: [finding] import: a hook body that CRASHES reaches an import row as its native fault text (hook NAME threw: TypeError: …), while
POST /data/:objectand/createManyanswer500 INTERNAL_ERRORand withhold it #22718 (PR fix(core): an import row for a sandboxed body the door answers as a fault reads as that fault #22740,d7b26df5b5) and both blocks, security(import): an import's reference resolution matches a lookup cell against a target whose exposure refuses reads (census row 7 of #22661) #22739 (c74d843997) and security(data): a nested-relation filter condition on a lookup target is evaluated without asking the target's exposure (census row 4 of #22661) #22737 (ec7c7e0637), have landed. None of the 11 open PRs touchesimport-runner.ts,data-error-classification.tsorquickjs-runner.ts(PR fix(objectql): an aborting after* hook rolls its write back on the default write door #22819 touches one sandbox integration test only). Seat 1's in-flight objectql: anafterInserthook withonError: 'abort'(the default) that throws rejects the write, but the row stays stored —HookSchema.onErrorsays abort rolls the transaction back, and a plain write opens none #22782, data: under a search, a paged list'stotalis a page-local estimate (offset + page + 1), and the console shows it as the record count ("26 records" for 300 matches) #22790 and security(datasource): the boot's datasource restore reads stored datasource rows with no environment predicate, so a legacy organization-scoped row is loaded and served though #15206's reads are environment-only #22835 are disjoint. This seat's feat(spec,objectql,cli): the template install mode — a package copied once into the environment ledger, fully editable, refused on shared-database multi-tenant postures (ADR-0131 D6) #15213 S1 is disjoint; its security(auth): the identity import handsrunImporta protocol withoutgetMetaItem, so its reference cells skip the target's exposure ask (census row 9 of #22661) #22800 readsimport-runner.tsand does not edit it.objectstack-fleet commentedon Oct 11, 2026
os-dev-report
{ "issue": 22741, "status": "done", "branch": "claude/issue-22741-sandbox-fault-import-row", "pr": "https://github.com/objectstack-ai/objectstack/pull/22867", "session": "session_01ADzJtzYTLUfgrRZHxkagkX (subagent: the parent seat PM session, per the harness Claude-Session line)", "premise_still_valid": true, "summary": "Premise held, measured through the REAL QuickJSScriptRunner at eed637c09f into the real mapDataError and runImport (scratch test, deleted): CPU budget, wall-clock ceiling, api.read denial, log denial and a missing ctx.api method each throw a SandboxError (name 'SandboxError', innerMessage undefined); the create door answers 500 INTERNAL_ERROR 'Internal server error' and the row relayed the runner's text. Fix: isSandboxOwnFault(error) in packages/types/src/data-error-classification.ts beside isSandboxOrigin (name === 'SandboxError' and no non-empty innerMessage, both read off the producer's declared contract; recognised by name because runtime depends on core, as isEngineDuplicateRecordEnvelope does), and toFailedResult takes the door's sentence when (isSandboxOrigin || isSandboxOwnFault) and the door answers 5xx, the PR #22740 rule unchanged; no runner marker, packages/runtime untouched. The enumeration pin (packages/core/src/utils/import-runner-sandbox-fault-row.test.ts, core repo project) parses quickjs-runner.ts with the TypeScript compiler: 15 fault sites (9 single-arg constructions + 6 throwSandboxFault calls), the 2 relays held exact, per-kind floors, the producer class name read from source, 4 relayed nested-crash constructions, and controls (driver text, same text on a plain Error, a code hook's native TypeError). Not in this card: the door answers 404 OBJECT_NOT_FOUND for a sandbox fault text naming the requested object (finding below); the row does not copy a 4xx.", "tests": "HEAD bb09729a0a (branch merged with origin/main 55382dc02a); dependency closure built first: pnpm --filter '@objectstack/core...' build, VERDICT command-exit 0. (1) pnpm --filter @objectstack/core exec vitest run --project local --project repo --maxWorkers=2: Test Files 100 passed (100), Tests 2451 passed (2451). (2) pnpm --filter @objectstack/types exec vitest run --project local --project repo --maxWorkers=2: Test Files 28 passed (28), Tests 765 passed (765). (3) pnpm --filter @objectstack/types typecheck exit 0; pnpm --filter @objectstack/core typecheck exit 0 (check:test-typecheck OK, 4 file(s) / 4 pinned signature(s) held; the new test adds none). (4) New file alone: Tests 25 passed (25). Ablation, all from committed HEAD 2180c575bf through node scripts/ablation-replace.mjs (anchor hit x1 then x0, blob changed, restore proven blob == HEAD and git diff HEAD empty), command pnpm --filter @objectstack/core exec vitest run --project repo --maxWorkers=2 src/utils/import-runner-sandbox-fault-row.test.ts: A toFailedResult drops '|| isSandboxOwnFault(err)' gives Tests 20 failed | 5 passed (all 15 sites, batched path, 4 relays red; census and 4 controls green); B isSandboxOwnFault body 'return false && ...' gives 20 failed | 5 passed; C producer this.name = 'SandboxFault' in quickjs-runner.ts gives 20 failed | 5 passed; D a new unrenderable site (:660 with an interpolation of txState.depth) gives 1 failed | 23 passed, the census naming 'quickjs-runner.ts:660: no sample for the interpolation txState.depth'. No dist on these paths: the test imports ./import-runner relatively, core vitest aliases @objectstack/types to src, the runner is read from disk. Gates: 66 derived on bb09729a0a, all exit 0 (field gates); dispatch-gates --ran: 66 derived, 66 run, 0 NOT-MEASURED (derived zero). Lint narrowing: eslint --no-inline-config --format json over the 3 changed .ts files: 3 files, 0 errors, 0 warnings; population read from ESLint (isPathIgnored false, calculateConfigForFile yields rules for all 3); type-aware linting not enabled (parserOptions.project null for all 3, eslint.config.mjs states it) so untouched files' verdicts cannot move; repo-wide pnpm lint declared to CI. CI: in_progress at PR open, not waited on.", "mcp_calls": "0", "api_writes": "2 relay strokes from this session, each one REST POST /repos/objectstack-ai/objectstack/dispatches executed by fleet-write.yml as objectstack-fleet[bot]: (1) pr_create = POST /repos/objectstack-ai/objectstack/pulls (draft, PR #22867, body read back byte-identical 11398/11398) + POST /repos/objectstack-ai/objectstack/issues/22867/assignees [os-steve]; (2) this os-dev-report = POST /repos/objectstack-ai/objectstack/issues/22741/comments via scripts/pm/post-stamped.mjs. Plus 5 git push of the branch (not REST). Zero label writes (none named by the dispatch; skip-changeset does not apply). Reads only otherwise: GET issue 22741 + its comments, GET pulls/22867.", "open_questions": [], "out_of_scope_findings": [ "class: a · reach: named producer: quickjs-runner.ts capability gate text from throwSandboxFault (:1173) 'capability api.read not granted to hook H (called ctx.api.object(OBJ).find)', and the missing-method site (:1199) 'ctx.api.object(OBJ).find not implemented', measured through the REAL QuickJSScriptRunner at eed637c09f into mapDataError(err, 'mz_locked'), the classification POST /api/v1/data/:object serves · evidence: when the fault text names the requested object, classifyDataError's looksLikeUnknownObject limb (the quoted object name plus the substring 'not') answers 404 OBJECT_NOT_FOUND \"Object 'mz_locked' is not registered\" for a sandbox capability denial or missing method, where the producer's own contract (a SandboxError with no innerMessage is a fault, 500) and every other site answer 500 INTERNAL_ERROR; the import row (this PR) keeps its own text there because it copies only a 5xx · dedupe words: looksLikeUnknownObject, OBJECT_NOT_FOUND capability denial, 'is not registered' sandbox fault, unknown-object heuristic" ], "gates": [ { "command": "node scripts/check-adr-0087-registration.mjs --base origin/main", "exit": 0 }, { "command": "node scripts/check-adr-0087-registration.mjs --self-test", "exit": 0 }, { "command": "node scripts/check-changeset-no-major.mjs --base origin/main", "exit": 0 }, { "command": "node scripts/check-changeset-no-major.mjs --self-test", "exit": 0 }, { "command": "node scripts/check-ci-filter-parity.mjs", "exit": 0 }, { "command": "node scripts/check-closing-keyword-parity.mjs", "exit": 0 }, { "command": "node scripts/check-closing-keyword-parity.mjs --self-test", "exit": 0 }, { "command": "node scripts/check-comment-mask-adoption.mjs", "exit": 0 }, { "command": "node scripts/check-comment-mask-adoption.mjs --self-test", "exit": 0 }, { "command": "node scripts/check-comment-mask-corpus.mjs", "exit": 0 }, { "command": "node scripts/check-dev-prereqs.mjs --self-test", "exit": 0 }, { "command": "node scripts/check-dts-emitted.mjs --self-test", "exit": 0 }, { "command": "node scripts/check-empty-changeset.mjs --base origin/main", "exit": 0 }, { "command": "node scripts/check-empty-changeset.mjs --self-test", "exit": 0 }, { "command": "node scripts/check-issue-citations.mjs", "exit": 0 }, { "command": "node scripts/check-keyed-text-bounds.mjs", "exit": 0 }, { "command": "node scripts/check-keyed-text-bounds.mjs --self-test", "exit": 0 }, { "command": "node scripts/check-platform-object-tenancy-census.mjs", "exit": 0 }, { "command": "node scripts/check-platform-object-tenancy-census.mjs --self-test", "exit": 0 }, { "command": "node scripts/check-plugin-teardown-shape.mjs", "exit": 0 }, { "command": "node scripts/check-plugin-teardown-shape.mjs --self-test", "exit": 0 }, { "command": "node scripts/check-registry-log-declared.mjs", "exit": 0 }, { "command": "node scripts/check-registry-log-declared.mjs --self-test", "exit": 0 }, { "command": "node scripts/check-rest-log-spy-declared.mjs", "exit": 0 }, { "command": "node scripts/check-rest-log-spy-declared.mjs --self-test", "exit": 0 }, { "command": "node scripts/check-system-context-census.mjs", "exit": 0 }, { "command": "node scripts/check-system-context-census.mjs --self-test", "exit": 0 }, { "command": "node scripts/check-undeclared-dep-imports.mjs", "exit": 0 }, { "command": "node scripts/check-undeclared-dep-imports.mjs --self-test", "exit": 0 }, { "command": "node scripts/docs-audit/check-affected-docs.mjs", "exit": 0 }, { "command": "node scripts/docs-audit/check-drift-comment.mjs", "exit": 0 }, { "command": "node scripts/pm/release-rehearsal-clone.mjs --self-test", "exit": 0 }, { "command": "node scripts/release-pending-publish.mjs --self-test", "exit": 0 }, { "command": "pnpm --filter @objectstack/spec run check:duration-unit-keys", "exit": 0 }, { "command": "pnpm check:changeset-gate-self-tests", "exit": 0 }, { "command": "pnpm check:cross-package-test-inputs", "exit": 0 }, { "command": "pnpm check:dispatcher-error-vocabulary", "exit": 0 }, { "command": "pnpm check:doc-authoring", "exit": 0 }, { "command": "pnpm check:driver-memory-census", "exit": 0 }, { "command": "pnpm check:dts-closure", "exit": 0 }, { "command": "pnpm check:dual-build-cjs-loads", "exit": 0, "note": "first run exit 3 (PREREQUISITE NOT MET, not measured: no dist); re-run green on the same HEAD after check:type-check-debt built the repo" }, { "command": "pnpm check:engine-double-contract", "exit": 0 }, { "command": "pnpm check:error-code-casing", "exit": 0 }, { "command": "pnpm check:error-status-conformance", "exit": 0 }, { "command": "pnpm check:gitlink-declared", "exit": 0 }, { "command": "pnpm check:issue-citations", "exit": 0 }, { "command": "pnpm check:kernel-hook-pairs", "exit": 0 }, { "command": "pnpm check:lean-entry-closure", "exit": 0, "note": "first run exit 3 (PREREQUISITE NOT MET, not measured: no dist); re-run green on the same HEAD after check:type-check-debt built the repo" }, { "command": "pnpm check:logger-receiver-detach", "exit": 0 }, { "command": "pnpm check:nul-bytes", "exit": 0 }, { "command": "pnpm check:objectql-double-limit", "exit": 0 }, { "command": "pnpm check:objectui-changeset", "exit": 0 }, { "command": "pnpm check:org-identifier", "exit": 0 }, { "command": "pnpm check:page-declaration-shape", "exit": 0 }, { "command": "pnpm check:pm-changeset-deadline-census", "exit": 0 }, { "command": "pnpm check:published-files", "exit": 0 }, { "command": "pnpm check:query-options-erasure", "exit": 0 }, { "command": "pnpm check:refd-timer-probe", "exit": 0 }, { "command": "pnpm check:slot-lookup", "exit": 0 }, { "command": "pnpm check:sourcemap-no-sources-content", "exit": 0 }, { "command": "pnpm check:test-source-alias", "exit": 0 }, { "command": "pnpm check:tier-file-adoption", "exit": 0 }, { "command": "pnpm check:type-check-coverage", "exit": 0 }, { "command": "pnpm check:type-check-debt", "exit": 0 }, { "command": "pnpm check:watch-hint-literal", "exit": 0 }, { "command": "pnpm check:where-matcher", "exit": 0 } ], "line_budget": "420 changed lines (+417 / -3) across 5 files, 0 generated; GitHub PR #22867 reports additions 417, deletions 3, changed_files 5", "deviations": [ "packages/core/vitest.repo-tests.json gained one line (the new test file). It is outside the literal three-file surface; it is the core repo vitest project membership list, which a test reading outside its package must join (check:cross-package-test-inputs holds it equal to its scan; core already declares the packages/**/*.ts radius in turbo.json). Judged part of \"tests\", flagged here rather than stopped on.", "Mechanism assumption 1 falsified in part: isSandboxOrigin is not module-private; the file's trailing export block exports it and @objectstack/types re-exports it (core already imported it). Assumption 4 measured true: runtime depends on core (packages/runtime/package.json), so the predicate reads the producer's declared name rather than instanceof; no runner marker was needed, so packages/runtime is untouched.", "Assumption 3 re-enumerated: 17 lines = 15 constructions + 2 in doc comments; no-innerMessage population is 9 literal constructions + 2 relays (:432, :1524) + 6 throwSandboxFault calls, wider than triage's 8 (adds :1553 marshal, the capability denials, ctx.api unavailable).", "Attribution conflict, reported not resolved by imitation: the harness reminder asks for a model-named Co-Authored-By trailer and a robot-emoji PR footer; AGENTS.md and the role file require the model-free pair (Claude-Session + Co-authored-by: Claude) and the session-URL footer, which were used.", "The premise measurement placed a temporary scratch test in packages/runtime/src/sandbox (zz-measure-22741.test.ts) to reach the real runner with vitest aliases; it was deleted before the first commit and never staged.", "check:type-check-debt ran a full unlocked turbo build of every package as its own prerequisite step (about 17 minutes of shared-box time); that build is also what let check:dual-build-cjs-loads and check:lean-entry-closure be measured.", "Ablations ran at 2180c575bf, before the merge of origin/main; the merge (bb09729a0a) touched none of the mutated or tested files.", "Public surface: @objectstack/types gains one export, isSandboxOwnFault(error: unknown): boolean, measured on built dist/index.d.ts (declaration and export list) and dist/index.d.mts; the PR body carries Clause-②: no as copied from the claim, for the seat to settle; changeset is patch for core and types per the dispatch." ], "files_changed": [ "packages/types/src/data-error-classification.ts", "packages/core/src/utils/import-runner.ts", "packages/core/src/utils/import-runner-sandbox-fault-row.test.ts", "packages/core/vitest.repo-tests.json", ".changeset/22741-sandbox-fault-import-row.md" ], "cleanup": "worktree ../objectstack-issue-22741: node_modules removed and git worktree remove run right after this comment posts; no dev server or monitor was started" }Generated by Claude Code
objectstack-fleet commentedon Oct 11, 2026
os-dev-report
{ "issue": 22741, "status": "done", "round": "patch round 1; supersedes os-dev-report 6111286788", "branch": "claude/issue-22741-sandbox-fault-import-row", "pr": "https://github.com/objectstack-ai/objectstack/pull/22867", "head": "23a4a8a83f", "session": "session_01ADzJtzYTLUfgrRZHxkagkX (subagent: the parent seat PM session, per the harness Claude-Session line)", "premise_still_valid": true, "summary": "Patch round 1, as the seat settled it: .changeset/22741-sandbox-fault-import-row.md now carries the declaration line 'Clause-②: yes (widening)' and grades '@objectstack/types': minor ('@objectstack/core' stays patch). That is the one commit 23a4a8a83f on top of bb09729a0a (+3 / -1, the changeset only), pushed. The worktree was recreated from origin/claude/issue-22741-sandbox-fault-import-row (bb09729a0a, unchanged on the remote) and removed again after this report. No code, test or PR-body edit. origin/main was not merged in (the round said nothing else). The level axis was driven offline both ways: with the body's old line 2 and with 'Clause-②: yes (widening)'. Both are green, and the second reads '@objectstack/types: minor' as accounting for the widening. The seat's rewrite of line 2 was already on the PR at read-back.", "tests": "Changeset gates on 23a4a8a83f: node scripts/check-changeset-no-major.mjs --base origin/main exit 0 ('no major bump'; the local LEVEL AXIS is not applicable since there is no pull_request payload). Driven offline with --event built from the PR body: the current body (then 'Clause-②: no') exit 0, and line 2 rewritten to 'Clause-②: yes (widening)' exit 0, with 'LEVEL AXIS: this PR declares clause-② yes (widening) ... @objectstack/types: minor (.changeset/22741-sandbox-fault-import-row.md) ... the declared widening is accounted for'. node scripts/check-adr-0087-registration.mjs --base origin/main exit 0 ('adds no declared-breaking changeset (1 non-breaking changeset(s) seen)'). node scripts/check-empty-changeset.mjs --base origin/main exit 0. pnpm check:changeset-gate-self-tests exit 0 (170 + 463 + 401 assertions). Re-derived union: dispatch-gates --commands on 23a4a8a83f gives the same 66 families as round 1 (diff empty), all 66 exit 0 (field gates; check:type-check-debt ran first and rebuilt from the turbo cache, so check:dual-build-cjs-loads, check:lean-entry-closure, check:dts-closure, check:published-files and check:sourcemap-no-sources-content all measured, none exit 3). dispatch-gates --ran: 66 derived, 66 run, 0 NOT-MEASURED (derived zero). Not re-run: the core and types suites, the typechecks and the ablations. This round's diff is one .changeset markdown file, which is no test's input. Round 1's readings stand at bb09729a0a: core 100 files / 2451 tests, types 28 / 765, both typechecks exit 0, ablations A/B/C at 20 failed / 5 passed and D at 1 failed / 23 passed from 2180c575bf.", "mcp_calls": "0", "api_writes": "This round: 1 relay stroke, REST POST /repos/objectstack-ai/objectstack/dispatches executed as objectstack-fleet[bot]: this os-dev-report = POST /repos/objectstack-ai/objectstack/issues/22741/comments via scripts/pm/post-stamped.mjs. Plus 1 git push (not REST). No PR-body edit, no label write. Reads only otherwise: GET pulls/22867 (twice). Round 1, for the record: 2 strokes (pr_create + assignees; report comment 6111286788) and 5 git push.", "open_questions": [], "out_of_scope_findings": [ "carrier: the seat. The round-1 class (a) finding (the door 404 OBJECT_NOT_FOUND for a sandbox fault text naming the requested object) is filed by the seat as #22868. Nothing new this round." ], "pr_body_sentences_now_false": [ "Acceptance notes, 'Public surface' bullet. Its last two sentences, 'The `Clause-②` line is copied from the claim. The seat settles it.', become: 'The seat settled the line as `Clause-②: yes (widening)`. The changeset declares it too and takes `minor` for `@objectstack/types`; `@objectstack/core` stays `patch`.'", "Tests section, 'Gates' bullet. Append: 'Re-run on `23a4a8a83f` (the changeset commit): the same 66 families, all exit 0, none exit 3; `--ran` 66 derived, 66 run, 0 NOT-MEASURED.' The opening line 'All on HEAD `bb09729a0a` …' stays true for the suites it lists: the new commit touches only the changeset, so they were not re-run." ], "gates": [ { "command": "pnpm check:type-check-debt", "exit": 0 }, { "command": "node scripts/check-adr-0087-registration.mjs --base origin/main", "exit": 0 }, { "command": "node scripts/check-adr-0087-registration.mjs --self-test", "exit": 0 }, { "command": "node scripts/check-changeset-no-major.mjs --base origin/main", "exit": 0 }, { "command": "node scripts/check-changeset-no-major.mjs --self-test", "exit": 0 }, { "command": "node scripts/check-ci-filter-parity.mjs", "exit": 0 }, { "command": "node scripts/check-closing-keyword-parity.mjs", "exit": 0 }, { "command": "node scripts/check-closing-keyword-parity.mjs --self-test", "exit": 0 }, { "command": "node scripts/check-comment-mask-adoption.mjs", "exit": 0 }, { "command": "node scripts/check-comment-mask-adoption.mjs --self-test", "exit": 0 }, { "command": "node scripts/check-comment-mask-corpus.mjs", "exit": 0 }, { "command": "node scripts/check-dev-prereqs.mjs --self-test", "exit": 0 }, { "command": "node scripts/check-dts-emitted.mjs --self-test", "exit": 0 }, { "command": "node scripts/check-empty-changeset.mjs --base origin/main", "exit": 0 }, { "command": "node scripts/check-empty-changeset.mjs --self-test", "exit": 0 }, { "command": "node scripts/check-issue-citations.mjs", "exit": 0 }, { "command": "node scripts/check-keyed-text-bounds.mjs", "exit": 0 }, { "command": "node scripts/check-keyed-text-bounds.mjs --self-test", "exit": 0 }, { "command": "node scripts/check-platform-object-tenancy-census.mjs", "exit": 0 }, { "command": "node scripts/check-platform-object-tenancy-census.mjs --self-test", "exit": 0 }, { "command": "node scripts/check-plugin-teardown-shape.mjs", "exit": 0 }, { "command": "node scripts/check-plugin-teardown-shape.mjs --self-test", "exit": 0 }, { "command": "node scripts/check-registry-log-declared.mjs", "exit": 0 }, { "command": "node scripts/check-registry-log-declared.mjs --self-test", "exit": 0 }, { "command": "node scripts/check-rest-log-spy-declared.mjs", "exit": 0 }, { "command": "node scripts/check-rest-log-spy-declared.mjs --self-test", "exit": 0 }, { "command": "node scripts/check-system-context-census.mjs", "exit": 0 }, { "command": "node scripts/check-system-context-census.mjs --self-test", "exit": 0 }, { "command": "node scripts/check-undeclared-dep-imports.mjs", "exit": 0 }, { "command": "node scripts/check-undeclared-dep-imports.mjs --self-test", "exit": 0 }, { "command": "node scripts/docs-audit/check-affected-docs.mjs", "exit": 0 }, { "command": "node scripts/docs-audit/check-drift-comment.mjs", "exit": 0 }, { "command": "node scripts/pm/release-rehearsal-clone.mjs --self-test", "exit": 0 }, { "command": "node scripts/release-pending-publish.mjs --self-test", "exit": 0 }, { "command": "pnpm --filter @objectstack/spec run check:duration-unit-keys", "exit": 0 }, { "command": "pnpm check:changeset-gate-self-tests", "exit": 0 }, { "command": "pnpm check:cross-package-test-inputs", "exit": 0 }, { "command": "pnpm check:dispatcher-error-vocabulary", "exit": 0 }, { "command": "pnpm check:doc-authoring", "exit": 0 }, { "command": "pnpm check:driver-memory-census", "exit": 0 }, { "command": "pnpm check:dts-closure", "exit": 0 }, { "command": "pnpm check:dual-build-cjs-loads", "exit": 0 }, { "command": "pnpm check:engine-double-contract", "exit": 0 }, { "command": "pnpm check:error-code-casing", "exit": 0 }, { "command": "pnpm check:error-status-conformance", "exit": 0 }, { "command": "pnpm check:gitlink-declared", "exit": 0 }, { "command": "pnpm check:issue-citations", "exit": 0 }, { "command": "pnpm check:kernel-hook-pairs", "exit": 0 }, { "command": "pnpm check:lean-entry-closure", "exit": 0 }, { "command": "pnpm check:logger-receiver-detach", "exit": 0 }, { "command": "pnpm check:nul-bytes", "exit": 0 }, { "command": "pnpm check:objectql-double-limit", "exit": 0 }, { "command": "pnpm check:objectui-changeset", "exit": 0 }, { "command": "pnpm check:org-identifier", "exit": 0 }, { "command": "pnpm check:page-declaration-shape", "exit": 0 }, { "command": "pnpm check:pm-changeset-deadline-census", "exit": 0 }, { "command": "pnpm check:published-files", "exit": 0 }, { "command": "pnpm check:query-options-erasure", "exit": 0 }, { "command": "pnpm check:refd-timer-probe", "exit": 0 }, { "command": "pnpm check:slot-lookup", "exit": 0 }, { "command": "pnpm check:sourcemap-no-sources-content", "exit": 0 }, { "command": "pnpm check:test-source-alias", "exit": 0 }, { "command": "pnpm check:tier-file-adoption", "exit": 0 }, { "command": "pnpm check:type-check-coverage", "exit": 0 }, { "command": "pnpm check:watch-hint-literal", "exit": 0 }, { "command": "pnpm check:where-matcher", "exit": 0 } ], "line_budget": "422 changed lines (+419 / -3) across 5 files, 0 generated, on head 23a4a8a83f; GitHub PR #22867 reports additions 419, deletions 3, changed_files 5. This round alone: +3 / -1 in the changeset.", "deviations": [ "dispatch-gates printed STALE TREE: origin/main 8532783f65 is 2 commits past the merge base 55382dc02, and scripts/cross-package-test-inputs.mjs changed in that range. So the 66-family derivation, and the gates that read that file, read this branch's copy. Not merged, because the round asked for nothing beyond the changeset; CI runs the merged ref.", "The four named changeset gates and the offline --event level-axis runs were made on the commit BEFORE the push (the round lists push second). The re-derived 66-gate union ran after the push, on the same head 23a4a8a83f.", "Carried from round 1 and still true: packages/core/vitest.repo-tests.json is in the diff as test wiring; commit trailers and PR footer follow AGENTS.md rather than the harness reminder's model-named forms." ], "files_changed": [ ".changeset/22741-sandbox-fault-import-row.md (this round)", "packages/types/src/data-error-classification.ts", "packages/core/src/utils/import-runner.ts", "packages/core/src/utils/import-runner-sandbox-fault-row.test.ts", "packages/core/vitest.repo-tests.json" ], "cleanup": "worktree ../objectstack-issue-22741 recreated for this round; node_modules removed and git worktree remove run right after this comment posts; no dev server or monitor started; the gate runner exited (done marker written)" }Generated by Claude Code
objectstack-fleet commentedon Oct 11, 2026
✅ ACCEPT: PR #22867 at
23a4a8a83fdomain:engineseat 2 (#20966) ·os-steve·session_01ADzJtzYTLUfgrRZHxkagkX· 2026-10-11T17:38Z. Claim 6110232592; reports 6111286788 and 6111682179 (patch round 1). Checked on GitHub, not taken from the reports.main; line 1Fixes #22741is the body's only closing keyword; line 2Clause-②: yes (widening). Assigneeos-steve.check-governed-merges --pr 22867: 0 of 5 paths; 422 lines ≤ 3000). Nothing undercontent/docs/releases/.packages/runtimeuntouched;packages/core/vitest.repo-tests.jsongains the new test's line (test wiring, accepted).@objectstack/typesminor(one new export,isSandboxOwnFault, on the published.entry),@objectstack/corepatch. Its four sentences on what the row did, what the predicate answers and what stays (codeIMPORT_ROW_FAILED, driver and code-hook text) match the diff.isSandboxOwnFault(nameSandboxError, no non-emptyinnerMessage), read off the producer besideisSandboxOrigin;toFailedResultcopies the door's sentence for either predicate when the door answers 5xx. No second withholding rule; driver text unchanged.quickjs-runner.ts(15 sites, per-kind floors, relays census); ablations A–C each 20 failed / 5 passed and D 1 failed (census names the line), restore proven; core 2451 and types 765 tests green; 66 gate families, all exit 0,--ran66/66.23a4a8a83f: 41 success, 7 skipped, 0 failed; all seven required contextssuccess.CONTRACT_REVIEW_TIER, isolated reviewer, read-only).Clause-②line corrected fromnotoyesby measurement (the claim provided for it);vitest.repo-tests.jsonwiring.Landing: ready and auto-merge through the queue in this act.
objectstack-fleet commentedon Oct 11, 2026
Landed: PR #22867 →
6d5191e697·domain:engineseat 2 ·session_01ADzJtzYTLUfgrRZHxkagkX· 2026-10-11T18:03Z6d5191e6975f4b270994fb8cd3246ba13abe5476(one parent). ACCEPT 6111800982; contract review PASS 6111794064.main: the four source and changeset paths are byte-identical to the accepted head23a4a8a83f;export function isSandboxOwnFaultand its use intoFailedResultare onorigin/main.completedby the PR'sFixes #22741;pm:dispatchedcomes off in this act.domain:engine,area:apiandbugstay.