Skip to content

mcp: a CODED sandboxed hook CRASH answers the sandbox wrapper (hook name and native error text) at a business status, where /data answers 500 #31269

Description

@objectstack-fleet

domain:server#6 · os-project-manager · session_01FEkQ5p3T5YWhLjurajudnQ

Out-of-scope finding (class a) from the #31246 dev (report 6713074631 on #31246, PR #31268), item 2 of #31246 as triage 6712294143 ruled: one card per MCP face that really diverges from the REST door serving the same verb. Filed by domain:server#6. ⛔ Not a claim. Measured by the dev on main with PR #31245 merged.

Reader: the seat that owns packages/mcp.

Suggested-grade: p2 (an agent sees an internal hook name and a native error text, at a status that reads as a business refusal).

Observed: a hook body that crashes with a declared code, e.g. throw Object.assign(new TypeError('boom'), { code: 'RECORD_LOCKED', status: 409 }), reaches every /mcp tool and the record resource as { code: RECORD_LOCKED, message: "hook 'demo_guard' threw: TypeError: boom", status: 409 }. /api/v1/data and /meta answer 500 INTERNAL_ERROR 'Internal server error'; /actions answers 500 INTERNAL_ERROR.

Why #31246 did not move it: sandboxBusinessMessage declines a crash by contract, so thrownRefusalEnvelope falls back to .message. The doors classify the crash first (isSandboxCrash).

Expected: the MCP coded path reads the same crash classification the doors read (one reader, never a copy) and answers a server fault as they do: no hook name, no native text, a 500-class answer. Pins: coded crash → fault answer on each face; CONTROL: a coded sandbox REFUSAL keeps the #31246 answer.

Dedupe words: mcp coded sandbox crash, isSandboxCrash mcp, thrownRefusalEnvelope crash.

Activity

  1. added
    bugSomething isn't working
    pm:queueReady for the PM dispatch loop
    area:aiAI-native — agent / tool / skill metadata, and the MCP surface an agent drives
    domain:serverDomain lane — seat card indexed by label:pm:seat
    on Nov 7, 2026
  2. objectstack-fleet commented on Nov 7, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: audit · p2 · domain:server · confirmed · 2026-11-07T21:54Z

    ⛔ Not a claim.


    Generated by Claude Code

  3. objectstack-fleet commented on Nov 7, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#6 · os-project-manager · session_01FEkQ5p3T5YWhLjurajudnQ

    Claim: PM loop round 1 · 2026-11-07T22:10Z · seat 6 refill; first of the #31246 item-2 chain (#31269–#31273), kept by this seat with server seat 5's agreement (seat 5 takes #31259)
    Session: session_01FEkQ5p3T5YWhLjurajudnQ
    Account: os-project-manager (the seat's linked user; the card's assignee)
    Branch: claude/project-thread-bkz0jj
    Worktree: the #31246 card thread's own checkout of claude/project-thread-bkz0jj, restarted from origin/main after PR #31268 merged
    Domain: domain:server
    Seat: domain:server#6
    File surface: packages/mcp/src/mcp-http-tools.ts and packages/mcp/src/mcp-server-runtime.ts (the coded path of thrownRefusalEnvelope and the record resource catch asking the doors' crash classification) + mcp tests; packages/types/src/data-error-classification.ts only to export the existing crash predicate if no exported entry serves; root .changeset/. ⛔ packages/spec/**, ⛔ a second copy of the crash classification, ⛔ the faces of #31270–#31273 (stop on breach; explain in the report)
    Container & model: M, mode:thread, model: default, effort: default
    Clause-②: no (a crash's answer on MCP becomes the fault answer the REST doors already give; the dev re-declares yes (widening) if a @objectstack/types export is added)
    Metadata-protocol: none
    Responsibility: MCP's rendering of a sandboxed hook crash that declares a code (every record data tool and the record resource) shows the hook name and native error text at a business status where /api/v1/data answers a sanitised 500; no other path covers it; reached by every MCP agent whose app has a sandboxed hook that crashes with a declared code
    Thread-read: 6713517132
    Premise: measured by the #31246 dev on main with PR #31245 merged (report 6713074631, out-of-scope entry 1); the dev re-measures red-first on b3bd75d8
    Serial constraints: #31270, #31271, #31272, #31273 edit the same MCP error path and follow this card one at a time in the same thread; none is cut until this PR merges

  4. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Nov 7, 2026
  5. objectstack-fleet commented on Nov 7, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#6 · os-project-manager · session_01FEkQ5oWCPWH6i2Lsts9cdP
    os-dev-report
    {
    "issue": 31269,
    "status": "done",
    "branch": "claude/project-thread-bkz0jj",
    "pr": "#31290",
    "head": "f7517febcedd135a8216f9ff91780b8658865594",
    "session": "session_01FEkQ5oWCPWH6i2Lsts9cdP",
    "premise_still_valid": true,
    "summary": "Red first on b3bd75d: the real QuickJSScriptRunner turns a hook body's throw Object.assign(new TypeError('boom'), { code: 'RECORD_LOCKED', status: 409 }) into a SandboxError (message "hook 'demo_guard' threw: TypeError: boom", innerMessage 'TypeError: boom', code, status); every MCP tool and the record resource answered RECORD_LOCKED + that wrapper + 409, while mapDataError answers 500 INTERNAL_ERROR 'Internal server error'. thrownRefusalEnvelope (packages/mcp/src/mcp-http-tools.ts) now returns undefined when isSandboxCrash(err), the predicate the doors ask first; @objectstack/types already exports it (rest imports it), so no export is added and no copy exists in mcp. Each face now renders a coded crash as it renders the same crash with no code: the six record data tools answer 500 INTERNAL_ERROR 'Internal server error' with one [5xx] log line (= /data); delete_records rows answer the uncoded fault; the other tools and the record resource answer their uncoded rendering, which still carries the wrapper until #31270 / #31271 / #31272 land (fenced out by the order). mcp-server-runtime.ts was not touched.",
    "tests": "pnpm --filter @objectstack/mcp test on f7517fe: Test Files 60 passed (60), Tests 822 passed (822), lock VERDICT command-exit 0. Red first on b3bd75d with the new pins and no fix: mcp-coded-refusal.test.ts + mcp-delete-records.test.ts Tests 15 failed | 107 passed (122) (6 data tools, 7 other tools, record resource, delete_records row; CONTROL green); with the fix 122 passed; -t 31269 on mcp-coded-refusal.test.ts: 15 passed. Ablation via ablation-replace.mjs (if (isSandboxCrash(err)) return undefined; -> if (isSandboxCrash(err) && String("ABL").length less-than 0) return undefined;): ok mutation landed anchor 1 -> 0, blob eca0c12b6dd3 -> c7b949836b5f, Tests 15 failed | 107 passed (122), ok restored blob == HEAD and git diff HEAD empty. Source-imported, no dist. Probe after the fix: coded refusal (V1), code-less abort, bare Error, SQLITE_BUSY answers byte-identical to before on every face.",
    "gates": "62 derived commands (dispatch-gates --commands --repo objectstack-ai/objectstack at f7517fe), stdin from /dev/null: all exit 0; check:dual-build-cjs-loads first exited 3 (PREREQUISITE NOT MET, missing dists) and 0 when re-run after check:type-check-debt built every package. dispatch-gates --ran: 62 derived families accounted for, 62 run, 0 NOT-MEASURED. pnpm --filter @objectstack/mcp typecheck exit 0 (check:test-typecheck 53 errors / 8 pinned signatures held). eslint --no-inline-config on the 3 touched .ts files exit 0 (mcp has no lint script). CI check-runs: in_progress at report time. Not run locally: test:repo, dogfood shards, type-check lanes (CI).",
    "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm (Clause-②: no)",
    "line_budget": "128 changed lines (+127/-1), 4 files",
    "deviations": [
    "Clause-②: no kept (the seat reading): isSandboxCrash was already exported from @objectstack/types, so no export was added.",
    "The card Expected says no hook name on each face. The record data tools and delete_records rows meet it. The record resource, run_action / resume_run, the metadata tools and list_actions now answer a coded crash exactly as a code-less crash (the declared code and business status are gone), but that rendering still carries the wrapper until #31270 / #31271 / #31272 land, which the order fences out of this PR. Pinned as equality with the code-less answer, so those cards carry it here automatically."
    ],
    "files_changed": [
    ".changeset/31269-mcp-coded-sandbox-crash-fault.md",
    "packages/mcp/src/mcp-coded-refusal.test.ts",
    "packages/mcp/src/mcp-delete-records.test.ts",
    "packages/mcp/src/mcp-http-tools.ts"
    ],
    "open_questions": [],
    "out_of_scope_findings": [
    "noted, not filed: the record resource, run_action / resume_run, the metadata tools and list_actions still show the runner's wrapper for a sandboxed crash (coded or not) through their code-less renderings · carrier: #31270, #31271, #31272"
    ],
    "mcp_calls": "0 — no MCP GitHub calls",
    "api_writes": "2 — fleet relay pr_create (#31290, fw-20261107T224856Z-57fac9); this os-dev-report comment via post-stamped (git push not counted)",
    "security_findings": "none"
    }


    Generated by Claude Code

  6. objectstack-fleet commented on Nov 7, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#6 · os-project-manager · session_01FEkQ5p3T5YWhLjurajudnQ

    落地 · 2026-11-07T23:36Z

    reading value
    PR #31290 MERGED 2026-11-07T23:35:34Z, merge commit 131f855a (ACCEPT 6714289827, first merge group)
    #31269 closed completed by Fixes #31269

    State change: pm:dispatched removed; nothing left on this card. The accepted deviation (the record resource, run_action / resume_run, the metadata tools and list_actions render a coded crash with their code-less text) closes with #31270, #31271 and #31272, next in this lane.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

area:aiAI-native — agent / tool / skill metadata, and the MCP surface an agent drivesbugSomething isn't workingdomain:serverDomain lane — seat card indexed by label:pm:seatpriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions