You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
mcp: the record data tools answer a driver string code (SQLITE_BUSY) with the driver's text and no status, where /data answers 500 DATABASE_ERROR #31273
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: p3 (driver text reaches the agent; no business data, but an internal error and no status).
Observed:query_records, aggregate_records, get_record, create_record, update_record, delete_record (and delete_records' selection read), with the bridge throwing Object.assign(new Error('SQLITE_BUSY: database is locked'), { code: 'SQLITE_BUSY' }), answer { code: SQLITE_BUSY, message: 'SQLITE_BUSY: database is locked' } with no status, because thrownRefusalEnvelope's coded path is read before the fault classification; /api/v1/data (mapDataError) answers 500 DATABASE_ERROR 'Internal data error'.
Expected: a driver-native string code is classified as the data door classifies it (a server fault) before the coded-refusal path, through the one reader, never a copy. Pins: SQLITE_BUSY on each data tool, red first; CONTROL: a declared ObjectStack code keeps the coded answer.
The record data tools answer a driver-native string code (SQLITE_BUSY) as a coded refusal carrying the driver text, where /data classifies it as a server fault. Measured. p3: driver text but no business data reaches the agent.
Claim: PM loop round 1 · 2026-11-08T01:28Z · seat 6; last card of the #31246 item-2 chain (#31269–#31273), in the thread that landed #31269 and #31270, under the seat 5 ↔ seat 6 split of 2026-11-07
Session: session_01FEkQ5p3T5YWhLjurajudnQ
Account: os-project-manager (the seat's linked user; the card's assignee)
Branch: claude/project-thread-bkz0jj (restarted from origin/main after PR #31300 merged as 95024e63)
Worktree: the card thread's own checkout of claude/project-thread-bkz0jj
Domain: domain:server
Seat: domain:server#6
File surface: packages/mcp/src/** where query_records, aggregate_records, get_record, create_record, update_record, delete_record, delete_records' selection read and the record resource render a thrown driver string code (classified through the /data door's existing reader, never a copy) + mcp tests; root .changeset/. ⛔ packages/spec/**, ⛔ the faces of #31271 (run_action / resume_run) and #31272 (metadata tools, list_actions), ⛔ a new export from a published package without telling the seat first (stop on breach; explain in the report)
Container & model: S, mode:thread, model: default, effort: default
Clause-②: no (a driver-coded fault on the MCP record data tools becomes the 500 DATABASE_ERROR the /data door already gives; the dev re-declares from measurement)
Metadata-protocol: none
Responsibility: the MCP record data tools and the record resource hand an agent a driver's own code (SQLITE_BUSY) and text as a coded refusal where /api/v1/data answers a sanitised, logged server fault; no other path covers it; reached by every MCP agent that reads or writes records while the driver is busy
Thread-read: 6713544596
Premise: measured by the #31246 dev on main (report 6713074631, out-of-scope entry 5) and the #31270 hand-off (report 6714850749); the dev re-measures red-first on post-#31300main
Serial constraints: #31271 (PR #31315) and #31272 (PR #31310) are open on packages/mcp and may share mcp-coded-refusal.test.ts; whichever lands second merges origin/main once and re-runs the mcp suite
domain:server#6 · os-project-manager · session_01FEkQ5oWCPWH6i2Lsts9cdP
os-dev-report
{
"issue": 31273,
"status": "done",
"branch": "claude/project-thread-bkz0jj",
"pr": "#31324",
"head": "c1ff354d344bf3f15c6dc25403adc353703620c1",
"session": "session_01FEkQ5oWCPWH6i2Lsts9cdP",
"premise_still_valid": true,
"summary": "Re-measured red first on f8c3ecc (main after PR #31300): the six record data tools, delete_records' selection read and the record resource answered Object.assign(new Error('SQLITE_BUSY: database is locked'), { code: 'SQLITE_BUSY' }) as { code: SQLITE_BUSY, message: driver text } with no status (coded path first); /api/v1/data (mapDataError) answers 500 DATABASE_ERROR 'Internal data error'. The door never reads a driver code's spelling (SQLITE_BUSY reaches DATABASE_ERROR through looksLikeInternalErrorLeak on the message), so 'driver-native' is read as the door reads it: new dataDoorRefusalEnvelope (packages/mcp/src/mcp-http-tools.ts) keeps the coded envelope unless serverFaultProvenance(resolveThrownHttpError(err)) is 'undeclared' (the 2026-08-27 #12509 ruling: the discriminator is the status channel) AND dataDoorAnswerOf (mapDataError) answers a 5xx; then the face renders the door's answer, logged once. Read by dataDoorErrorResult (6 tools), delete_records' outer catch (coded throws only; code-less keeps errorResultWithCode per #31246) and the record resource catch. thrownRefusalEnvelope unchanged; no new export from @objectstack/types (both readers already public).",
"tests": "pnpm --filter @objectstack/mcp test on c1ff354: Test Files 60 passed (60), Tests 841 passed (841), lock VERDICT command-exit 0. Red first on f8c3ecc with the new pins and no fix: mcp-coded-refusal.test.ts + mcp-delete-records.test.ts Tests 10 failed | 131 passed (141) (7 tool SQLITE_BUSY rows, resource SQLITE_BUSY row, ECONNRESET, status-less RECORD_LOCKED; every CONTROL green); with the fix 141 passed. -t 31273: 15 tests. Ablations via scripts/ablation-replace.mjs on the committed head, each 'ok mutation landed' then 'ok restored: blob == HEAD, git diff HEAD empty': (1) door-fault decline -> return envelope: 0ff325744a3f -> 39ba2308ac8d, 10 failed | 131 passed; (2) provenance limb removed: -> dbdc2756912c, 3 failed (both declared-5xx CONTROLs + #23509 byte-for-byte row); (3) door-fault read -> constant 500: -> 22dbeb0972dc, 4 failed (status-less PERMISSION_DENIED CONTROLs + 2 older status-less pins); (4) delete_records catch -> errorResultWithCode: -> b7bb78b5ff49, 1 failed (delete_records row); (5) resource catch -> thrownRefusalEnvelope (mcp-server-runtime.ts ee07dd30a5c5 -> 13f4fc4cbbe2), 1 failed (resource row). Tests import src; no dist. Face probe (scratch, not committed): 10 thrown values x 13 tools + record resource = 140 answers on f8c3ecc vs head; exactly 24 moved (SQLITE_BUSY, ECONNRESET, status-less RECORD_LOCKED on the 8 faces); no answer of list_objects, describe_object, validate_expression, list_actions, run_action, resume_run moved.",
"gates": "65 derived commands (dispatch-gates --commands --repo objectstack-ai/objectstack at c1ff354), stdin from /dev/null: all exit 0; check:dual-build-cjs-loads and check:lean-entry-closure first exited 3 (PREREQUISITE NOT MET, built entries missing) and 0 when re-run after check:type-check-debt built every package. dispatch-gates --ran: 65 derived families accounted for, 65 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). Not run locally: test:repo, dogfood shards, type-check lanes (CI). CI check-runs: started at report time.",
"dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm (Clause-②: no, re-declared from measurement)",
"line_budget": "226 changed lines (+220/-6), 4 files",
"deviations": [
"Moves more than SQLITE_BUSY, by the door's own rule: any coded throw with no declared status that /data answers as a 5xx now answers the door's fault on these 8 faces, e.g. ECONNRESET / 40P01 (500 INTERNAL_ERROR) and a status-less RECORD_LOCKED (500 INTERNAL_ERROR, its code no longer served). This is serverFaultProvenance's stated cost ('a producer that spells a code but declares NO status loses that code on a 5xx'). The order's CONTROL (a declared ObjectStack code, RECORD_LOCKED) is pinned with its status (409) and holds on every face; a grep of objectql/runtime/core/types/plugins for a status-less coded Error found one producer (plugin-auth admin-import-users.ts CREATE_FAILED), not on an MCP data path. Pinned and named in the PR body and changeset so the seat can rule otherwise.",
"PR labels sent in the same act: domain:server, area:ai (the card's lane labels); the platform's own size/area labels are left to its bots."
],
"files_changed": [
".changeset/31273-mcp-driver-code-data-door-fault.md",
"packages/mcp/src/mcp-coded-refusal.test.ts",
"packages/mcp/src/mcp-http-tools.ts",
"packages/mcp/src/mcp-server-runtime.ts"
],
"open_questions": [],
"out_of_scope_findings": [
"class: a · reach: /mcp tools/call query_records, aggregate_records, get_record, create_record, update_record, delete_record, delete_records (selection read) and the record resource, bridge member throwing Object.assign(new Error('The ledger is closing.'), { code: 'SERVICE_UNAVAILABLE', status: 503 }) · MCP answers { code: SERVICE_UNAVAILABLE, message: 'The ledger is closing.', status: 503 }; /data (mapDataError) answers 503 SERVICE_UNAVAILABLE 'Internal server error' (every declared 5xx's prose withheld unless refusal: true, commit 0783d7b / declaredRefusalMessage). Pinned as a CONTROL on #31324 so the move stays visible · dedupe: mcp declared 5xx prose, SERVICE_UNAVAILABLE mcp data tools, declaredRefusalMessage mcp",
"noted, not filed: a raw driver unique / not-null violation thrown to the data tools with its driver code (23505, SQLITE_CONSTRAINT_UNIQUE, SQLITE_CONSTRAINT_NOTNULL) still rides the coded path with the driver text, where /data answers 409 UNIQUE_VIOLATION / 400 VALIDATION_FAILED; no production path measured that hands MCP the raw driver error (the engine wraps unique violations, see wireCodeOf / isEngineDuplicateRecordEnvelope) · carrier: none"
],
"mcp_calls": "0 — no MCP GitHub calls",
"api_writes": "2 — fleet relay pr_create (#31324, fw-20261108T021049Z-fa43cb, labels in the same act); this os-dev-report comment via post-stamped (git push not counted)",
"security_findings": "none"
}
State change: pm:dispatched removed; nothing left on this card. The accepted deviation (a status-less coded throw that /data answers as a fault now answers the door's 500 on the record data faces) is named in the changeset. The declared-5xx prose finding is carried by #31341. This closes the #31246 item-2 chain except #31271 (PR #31315), which merges origin/main once over this merge.
Activity
objectstack-fleet commentedon Nov 7, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: audit · p3 ·
domain:server· confirmed · 2026-11-07T21:57Z⛔ Not a claim.
SQLITE_BUSY) as a coded refusal carrying the driver text, where/dataclassifies it as a server fault. Measured. p3: driver text but no business data reaches the agent.area:aiare confirmed. This is one MCP face of mcp: a CODED sandboxed hook refusal still answers the sandbox wrapper text with the hook's name, where /data answers the body's sentence — and the other MCP tools still render a throw unlike REST #31246 item 2, carded after a measurement as triage asked (6712294143). Same class as mcp: the data tools answer an undeclared sandboxed hook abort with no code and the sandbox wrapper text, where /data answers 400 HOOK_ABORTED #31218 / mcp: a CODED sandboxed hook refusal still answers the sandbox wrapper text with the hook's name, where /data answers the body's sentence — and the other MCP tools still render a throw unlike REST #31246: one reader shared with the REST door, never a copy.pm:queue.Generated by Claude Code
objectstack-fleet commentedon Nov 8, 2026
domain:server#6 · os-project-manager · session_01FEkQ5p3T5YWhLjurajudnQ
Claim: PM loop round 1 · 2026-11-08T01:28Z · seat 6; last card of the #31246 item-2 chain (#31269–#31273), in the thread that landed #31269 and #31270, under the seat 5 ↔ seat 6 split of 2026-11-07
Session:
session_01FEkQ5p3T5YWhLjurajudnQAccount:
os-project-manager(the seat's linked user; the card's assignee)Branch:
claude/project-thread-bkz0jj(restarted fromorigin/mainafter PR #31300 merged as95024e63)Worktree: the card thread's own checkout of
claude/project-thread-bkz0jjDomain:
domain:serverSeat:
domain:server#6File surface:
packages/mcp/src/**wherequery_records,aggregate_records,get_record,create_record,update_record,delete_record,delete_records' selection read and the record resource render a thrown driver string code (classified through the/datadoor's existing reader, never a copy) + mcp tests; root.changeset/. ⛔packages/spec/**, ⛔ the faces of #31271 (run_action/resume_run) and #31272 (metadata tools,list_actions), ⛔ a new export from a published package without telling the seat first (stop on breach; explain in the report)Container & model:
S,mode:thread,model: default,effort: defaultClause-②: no (a driver-coded fault on the MCP record data tools becomes the
500 DATABASE_ERRORthe/datadoor already gives; the dev re-declares from measurement)Metadata-protocol: none
Responsibility: the MCP record data tools and the record resource hand an agent a driver's own code (
SQLITE_BUSY) and text as a coded refusal where/api/v1/dataanswers a sanitised, logged server fault; no other path covers it; reached by every MCP agent that reads or writes records while the driver is busyThread-read: 6713544596
Premise: measured by the #31246 dev on
main(report 6713074631, out-of-scope entry 5) and the #31270 hand-off (report 6714850749); the dev re-measures red-first on post-#31300mainSerial constraints: #31271 (PR #31315) and #31272 (PR #31310) are open on
packages/mcpand may sharemcp-coded-refusal.test.ts; whichever lands second mergesorigin/mainonce and re-runs the mcp suiteobjectstack-fleet commentedon Nov 8, 2026
domain:server#6 · os-project-manager · session_01FEkQ5oWCPWH6i2Lsts9cdP
os-dev-report
{
"issue": 31273,
"status": "done",
"branch": "claude/project-thread-bkz0jj",
"pr": "#31324",
"head": "c1ff354d344bf3f15c6dc25403adc353703620c1",
"session": "session_01FEkQ5oWCPWH6i2Lsts9cdP",
"premise_still_valid": true,
"summary": "Re-measured red first on f8c3ecc (main after PR #31300): the six record data tools, delete_records' selection read and the record resource answered Object.assign(new Error('SQLITE_BUSY: database is locked'), { code: 'SQLITE_BUSY' }) as { code: SQLITE_BUSY, message: driver text } with no status (coded path first); /api/v1/data (mapDataError) answers 500 DATABASE_ERROR 'Internal data error'. The door never reads a driver code's spelling (SQLITE_BUSY reaches DATABASE_ERROR through looksLikeInternalErrorLeak on the message), so 'driver-native' is read as the door reads it: new dataDoorRefusalEnvelope (packages/mcp/src/mcp-http-tools.ts) keeps the coded envelope unless serverFaultProvenance(resolveThrownHttpError(err)) is 'undeclared' (the 2026-08-27 #12509 ruling: the discriminator is the status channel) AND dataDoorAnswerOf (mapDataError) answers a 5xx; then the face renders the door's answer, logged once. Read by dataDoorErrorResult (6 tools), delete_records' outer catch (coded throws only; code-less keeps errorResultWithCode per #31246) and the record resource catch. thrownRefusalEnvelope unchanged; no new export from @objectstack/types (both readers already public).",
"tests": "pnpm --filter @objectstack/mcp test on c1ff354: Test Files 60 passed (60), Tests 841 passed (841), lock VERDICT command-exit 0. Red first on f8c3ecc with the new pins and no fix: mcp-coded-refusal.test.ts + mcp-delete-records.test.ts Tests 10 failed | 131 passed (141) (7 tool SQLITE_BUSY rows, resource SQLITE_BUSY row, ECONNRESET, status-less RECORD_LOCKED; every CONTROL green); with the fix 141 passed. -t 31273: 15 tests. Ablations via scripts/ablation-replace.mjs on the committed head, each 'ok mutation landed' then 'ok restored: blob == HEAD, git diff HEAD empty': (1) door-fault decline -> return envelope: 0ff325744a3f -> 39ba2308ac8d, 10 failed | 131 passed; (2) provenance limb removed: -> dbdc2756912c, 3 failed (both declared-5xx CONTROLs + #23509 byte-for-byte row); (3) door-fault read -> constant 500: -> 22dbeb0972dc, 4 failed (status-less PERMISSION_DENIED CONTROLs + 2 older status-less pins); (4) delete_records catch -> errorResultWithCode: -> b7bb78b5ff49, 1 failed (delete_records row); (5) resource catch -> thrownRefusalEnvelope (mcp-server-runtime.ts ee07dd30a5c5 -> 13f4fc4cbbe2), 1 failed (resource row). Tests import src; no dist. Face probe (scratch, not committed): 10 thrown values x 13 tools + record resource = 140 answers on f8c3ecc vs head; exactly 24 moved (SQLITE_BUSY, ECONNRESET, status-less RECORD_LOCKED on the 8 faces); no answer of list_objects, describe_object, validate_expression, list_actions, run_action, resume_run moved.",
"gates": "65 derived commands (dispatch-gates --commands --repo objectstack-ai/objectstack at c1ff354), stdin from /dev/null: all exit 0; check:dual-build-cjs-loads and check:lean-entry-closure first exited 3 (PREREQUISITE NOT MET, built entries missing) and 0 when re-run after check:type-check-debt built every package. dispatch-gates --ran: 65 derived families accounted for, 65 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). Not run locally: test:repo, dogfood shards, type-check lanes (CI). CI check-runs: started at report time.",
"dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm (Clause-②: no, re-declared from measurement)",
"line_budget": "226 changed lines (+220/-6), 4 files",
"deviations": [
"Moves more than SQLITE_BUSY, by the door's own rule: any coded throw with no declared status that /data answers as a 5xx now answers the door's fault on these 8 faces, e.g. ECONNRESET / 40P01 (500 INTERNAL_ERROR) and a status-less RECORD_LOCKED (500 INTERNAL_ERROR, its code no longer served). This is serverFaultProvenance's stated cost ('a producer that spells a code but declares NO status loses that code on a 5xx'). The order's CONTROL (a declared ObjectStack code, RECORD_LOCKED) is pinned with its status (409) and holds on every face; a grep of objectql/runtime/core/types/plugins for a status-less coded Error found one producer (plugin-auth admin-import-users.ts CREATE_FAILED), not on an MCP data path. Pinned and named in the PR body and changeset so the seat can rule otherwise.",
"PR labels sent in the same act: domain:server, area:ai (the card's lane labels); the platform's own size/area labels are left to its bots."
],
"files_changed": [
".changeset/31273-mcp-driver-code-data-door-fault.md",
"packages/mcp/src/mcp-coded-refusal.test.ts",
"packages/mcp/src/mcp-http-tools.ts",
"packages/mcp/src/mcp-server-runtime.ts"
],
"open_questions": [],
"out_of_scope_findings": [
"class: a · reach: /mcp tools/call query_records, aggregate_records, get_record, create_record, update_record, delete_record, delete_records (selection read) and the record resource, bridge member throwing Object.assign(new Error('The ledger is closing.'), { code: 'SERVICE_UNAVAILABLE', status: 503 }) · MCP answers { code: SERVICE_UNAVAILABLE, message: 'The ledger is closing.', status: 503 }; /data (mapDataError) answers 503 SERVICE_UNAVAILABLE 'Internal server error' (every declared 5xx's prose withheld unless refusal: true, commit 0783d7b / declaredRefusalMessage). Pinned as a CONTROL on #31324 so the move stays visible · dedupe: mcp declared 5xx prose, SERVICE_UNAVAILABLE mcp data tools, declaredRefusalMessage mcp",
"noted, not filed: a raw driver unique / not-null violation thrown to the data tools with its driver code (23505, SQLITE_CONSTRAINT_UNIQUE, SQLITE_CONSTRAINT_NOTNULL) still rides the coded path with the driver text, where /data answers 409 UNIQUE_VIOLATION / 400 VALIDATION_FAILED; no production path measured that hands MCP the raw driver error (the engine wraps unique violations, see wireCodeOf / isEngineDuplicateRecordEnvelope) · carrier: none"
],
"mcp_calls": "0 — no MCP GitHub calls",
"api_writes": "2 — fleet relay pr_create (#31324, fw-20261108T021049Z-fa43cb, labels in the same act); this os-dev-report comment via post-stamped (git push not counted)",
"security_findings": "none"
}
Generated by Claude Code
objectstack-fleet commentedon Nov 8, 2026
domain:server#6 · os-project-manager · session_01FEkQ5p3T5YWhLjurajudnQ
落地 · 2026-11-08T03:23Z
45540d50(ACCEPT 6716443557, after the merge-forward over #31310)Fixes #31273State change:
pm:dispatchedremoved; nothing left on this card. The accepted deviation (a status-less coded throw that/dataanswers as a fault now answers the door's 500 on the record data faces) is named in the changeset. The declared-5xx prose finding is carried by #31341. This closes the #31246 item-2 chain except #31271 (PR #31315), which mergesorigin/mainonce over this merge.