Repository navigation
Description
Filing category: ② a decision only the maintainer can make.
Batch-of: 15 cards filed together from one MCP capability test session (2026-11-11; 6 in cloud, 9 in objectstack).
维护者速读
- 现象:申请人能通过 MCP 提交请假,审批流程(
approval节点)也能正常生成sys_approval_request;但审批人那一侧在 MCP 上没有任何入口:list_actions里没有审批动作,sys_approval_request不在list_objects里,同意/驳回只能回到界面或 REST。 - 要你裁:审批人的「看待办 + 同意/驳回」是否进入 MCP,以及走哪个形状。
- 推荐:A:把审批请求自带的决定动作(同意/驳回/转签/退回)按审批人身份开放给 AI,复用现有
list_actions/run_action,不新增工具。
One-sentence problem
An agent can file a leave request for its user but cannot act for the manager who has to approve it, so half of every approval process stays outside MCP.
Evidence (reach)
Hosted tenant (pnpm dev:stack, Team plan; cloud ff373e02, framework d7c3d44e): an MCP-authored flow with an approval node (org_membership_level: owner) published; create_record over MCP opened sys_approval_request pending naming the owner. Over MCP as that owner: list_actions has no approval action; list_objects has no sys_approval_request. The decision was only possible via POST /api/v1/approvals/requests/:id/approve (the console's 通过 button), after which the flow resumed and the record read approved.
Governing text
docs/NORTH-STAR.md— "Two kinds of user: today, business staff through the UI …; tomorrow, agents through MCP. Every step of the road must hold for both kinds of user." The road includes "approvals and automation".packages/mcp/README.md— "sys_*-object actions are held back fail-closed" (approval-request actions live on asys_*object; somesys_*actions such asinvite_userare already exposed withaiExposed: true).
Options
| Option | What it does | What the customer sees | Effort |
|---|---|---|---|
| A | Expose the approval request's own decide actions (approve / reject / reassign / send back) with ai.exposed, gated to the request's current approvers; let an approver read their pending requests through the existing record tools |
"Approve Zhang San's leave" works from Claude; same gates as the console button | approvals + mcp seats · 1–2 PRs · precedent: sys_user actions exposed via aiExposed (no PR number measured) |
| B | Add dedicated MCP tools (list_my_approvals, decide_approval) |
Same capability, a separate tool family | mcp seat · 1–2 PRs · no precedent |
| C | Keep approvals UI-only | Agents submit, humans decide in the console | none |
Business reading: A = the approval inbox is just more actions an agent can take for its user; B = approvals get their own agent API; C = approvals are deliberately a human-only step.
Recommendation
A. Two years out the agent operates the app through the same declared actions a person clicks (Salesforce Agentforce and ServiceNow agents act through declared actions/approvals, not bespoke endpoints); A adds no tool family and keeps one permission gate. C is a legitimate product stance (human-in-the-loop for decisions) — if chosen, the MCP skill should say so explicitly so agents do not try. Confidence gap: whether approver identity over an OAuth delegation should require a stronger confirmation (requiresConfirmation) — recommend yes, untested.
Self-check: only ① picks A; ②③④ do not flip it.
After the ruling
A: approvals seat exposes the decide actions with approver-scoped gates + requiresConfirmation; mcp seat lets list_actions include them for the approver; e2e: submit over MCP as user A, decide over MCP as approver B, record resumes.
os-decision-facets
① 项目长远合理性: A 复用「动作」作为 agent 唯一操作面,不新增工具族,缩小特例;B 扩大契约面。
② 实际业务拉动: 今天任何「请假/报销/采购」审批场景用 MCP 走全程都会在审批人这一步断开(本次实测)。
③ 防 AI 犯错: A 下审批走与界面同一个带审批人校验的动作;无入口时 agent 会去改状态字段,绕过审批。
④ 创业阶段不扩散: A 不新增工具;C 零成本但留下 North Star 缺口。
Prior rulings read: "approval mcp approver decide tool" → 128 hits (top: #30806, #27101, #28657; none rule on MCP decisions); ADR-0011; thread: none
Reader who acts: the approvals seat and the packages/mcp seat, after the ruling.
Dedupe: repo:objectstack-ai/objectstack is:issue approval mcp approver decide tool → 128 hits, none on approver-side MCP access; cloud approver mcp approval tool → 12 hits (cloud#3600 scenario epic, cloud#4091 AI write hold, cloud#3301 lint), none.
Activity
objectstack-fleet commentedon Nov 11, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: decision card routed ·
domain:server· p2 · 2026-11-11T15:01Z⛔ Not a claim.
domain:server: approvals on the MCP face (packages/mcp/list_actions). Once it is ruled, that lane builds the chosen option.needs-user-decision.Generated by Claude Code
objectstack-fleet commentedon Nov 12, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Ruling: letter A · maintainer 「32443 直接做 B,其他同意」 · 2026-11-12T00:05Z
The maintainer ruled in the triage seat's session on 2026-11-12, verbatim: 「32443 直接做 B,其他同意」. It was given in answer to triage's explanation of #32442, #32443, #32445 and #32446, so 「其他同意」 takes this card's recommendation.
ai.exposed, gated to the request's current approvers. An approver reads their pending requests through the existing record tools. No new MCP tool is added.domain:server(approvals +packages/mcp). p2. It is 1–2 PRs, with a precedent (sys_useractions exposed the same way).needs-user-decisioncomes off, and the card goes topm:queue.Generated by Claude Code
objectstack-fleet commentedon Nov 12, 2026
domain:server#5 · os-elon-musk · session_016WV4cwJbS8sZAfru2iyvQq
Claim: PM loop round 1 (slot freed by #32757 entering the decision box)
Session:
session_016WV4cwJbS8sZAfru2iyvQqAccount:
os-elon-muskBranch:
the card thread's designated claude/project-thread-* branch (this seat's card thread re-posts this whole claim with the exact branch before its PR opens)Worktree:
objectstack-issue-32442Domain:
domain:serverSeat:
domain:server#5File surface:
packages/plugins/plugin-approvals/src/(the approval request's decide actions and their approver gate, its translation bundles if labels change),packages/mcp/src/(only where thesys_*fail-closed hold-back must admit these actions; tests beside them),content/docs/**that teaches approvals over MCP,.changeset/**. Apackages/spec/src/**hunk is a breach: stop and reportContainer & model:
M,mode:thread,model: default (dispatch-gates --tier: no path-derived mandate; per-card call, default tier),effort: high (xhigh for the gate design and red-line checks only)Clause-②: no
Metadata-protocol: none
Responsibility:
n/a — not a defect card (executes the maintainer's ruling A, 6810312442)Thread-read: 6810312442
Premise: holds
Serial constraints cleared:
#32445 (os-sales, PR #32816) adds a sys_* action in packages/platform-objects and service-messaging, not plugin-approvals; its generated translation files differ from plugin-approvals' own bundles. #32766/#32767 (seat 6) edit packages/mcp/src/mcp-server-runtime.ts, not the hold-back in mcp-http-tools.ts. Ordinary concurrency; merge origin/main once, before landingobjectstack-fleet commentedon Nov 12, 2026
domain:server#5 · os-elon-musk · session_016WV4cxnQXys268N88ne5Ao
Claim: card thread for the seat claim 6836969826 (the decide half of ruling A; the read half waits for a ruling, seat 5)
Session:
session_016WV4cxnQXys268N88ne5AoAccount:
os-elon-muskBranch:
claude/project-thread-vlti6bWorktree:
objectstack-issue-32442Domain:
domain:serverSeat:
domain:server#5File surface:
packages/plugins/plugin-approvals/src/(the approval request's decide actions and their approver gate, its translation bundles if labels change),packages/mcp/src/(only where thesys_*fail-closed hold-back must admit these actions; tests beside them),content/docs/**that teaches approvals over MCP,packages/qa/dogfood/test/approval-decide-over-mcp.dogfood.test.ts(test infra for the negative pins, seat-approved),.changeset/**. Apackages/spec/src/**hunk is a breach: stop and reportContainer & model:
M,mode:thread,model: default (dispatch-gates --tier: no path-derived mandate; per-card call, default tier),effort: high (xhigh for the gate design and red-line checks only)Clause-②: no
Metadata-protocol: none
Responsibility:
n/a — not a defect card (executes the maintainer's ruling A, 6810312442)Thread-read: 6810312442
Premise: holds
Serial constraints cleared:
#32445 (os-sales, PR #32816) adds a sys_* action in packages/platform-objects and service-messaging, not plugin-approvals; its generated translation files differ from plugin-approvals' own bundles. #32766/#32767 (seat 6) edit packages/mcp/src/mcp-server-runtime.ts, not the hold-back in mcp-http-tools.ts. Ordinary concurrency; merge origin/main once, before landingParent-claim: 6836969826
objectstack-fleet commentedon Nov 12, 2026
domain:server#5 · os-elon-musk · session_016WV4cwJbS8sZAfru2iyvQq
Read half · decision to the maintainer · 2026-11-12T22:06Z
The decide half (approve / reject / reassign / send back exposed to AI with confirmation,
ApprovalServicethe only gate) ships now in aRefs #32442 (decide half)PR from this seat's card thread. The read half ("an approver reads their pending requests through the existing record tools") cannot be built under the ruling without a new declared key, so it goes back to the maintainer. A fable review verified the dev's facts and found two more against B. When the decide half lands, this card is released in one stroke toneeds-user-decisionfor the read half (it is in flight until then, so the six-state label moves at that moment).Governing text:
packages/mcp/src/mcp-http-tools.tsobject-toolguard/list_objectsfilter (everysys_*object refused by name; only the host-wideallowSystemObjects);packages/spec/src/data/object.zod.tsObjectCapabilities(no per-object AI key); ADR-0066 :78 and #27681 (exposure is declared by the author, no deployment switch);.claude/skills/pm-dispatch/references/lanes/spec.md(a metadata-protocol addition is a spec sub-card, the product cardBlocked-by:it).sys_*(lint refuses it elsewhere; stored-metadata families refused before the key is read), named like actions'ai.exposed. Server card: the bridge attests the object, the three mcp guards honour the attestation,sys_approval_requestdeclares it; rows stay underrequest-read-gate.ts(the console's My Pending rows).Metadata-protocol: added, contract reviewui/action.zod.tsmethodenum has noGET;run_actionisdestructiveHint: trueand needsactions:execute, so a read-only agent cannot see it and every list prompts a confirmationsys_approval_requestas readable in mcpFlag (no ruling asked unless the maintainer reads "current approvers" literally): the service gate also admits the override holder (platform/tenant admin rescue, #3424), so an administrator's agent can override-decide like the administrator's button, behind confirmation. Narrowing it would be a check in the approval service, never in mcp.
Analysis: the card thread's
read-half-needs-decision.md; review:fable-review.md(seat 5 project files).objectstack-fleet commentedon Nov 12, 2026
domain:server#5 · os-elon-musk · session_016WV4cwJbS8sZAfru2iyvQq
Ruled: the maintainer, in this seat's thread (project "Objectstack server"), verbatim 「同意」, answering the read-half decision card whose recommendation was A (comment 6837228055, after an independent fable review).
sys_approval_request; an approver reads their pending requests with the existing MCP record tools, rows underrequest-read-gate.ts(the console's My Pending rows). The spec half is spec: a per-object, read-only AI exposure declaration so an agent can read a declared system object through the MCP record tools (#32442 read half) #32865 (filed now; triage sets lane and grade).Refs #32442 (decide half). At that landing this card is released in one stroke topm:blockedwithBlocked-by: #32865for the read half, neverneeds-user-decision(the decision is made).objectstack-fleet commentedon Nov 12, 2026
domain:server#5 · os-elon-musk · session_016WV4cxnQXys268N88ne5Ao
os-dev report — #32442 (decide half) · PR #32886 · head 62de438
{ "issue": 32442, "status": "done", "branch": "claude/project-thread-vlti6b", "pr": "https://github.com/objectstack-ai/objectstack/pull/32886", "session": "session_016WV4cxnQXys268N88ne5Ao", "premise_still_valid": true, "summary": "Decide half of ruling A, per seat 5's split (PR says Refs #32442 (decide half); the read half is ruled A (6837430865) and blocked by spec card #32865). approval_approve, approval_reject, approval_reassign and approval_send_back on sys_approval_request declare ai.exposed with requiresConfirmation: true (ADR-0011 bucket C, precedent sys_user.ban_user); as same-origin type 'api' actions they forward to their approvals routes as the caller, so ApprovalService is the only gate on who decides. No mcp, runtime or spec code changes.", "tests": "plugin-approvals sys-approval-request.object.test.ts: Tests 17 passed (17). New dogfood approval-decide-over-mcp.dogfood.test.ts on head 62de438433: Tests 5 passed (5) (approver lists the four decisions attested + requiresConfirmation; stranger REQUEST_NOT_FOUND; submitter FORBIDDEN 'is not a pending approver'; AI service account own key REQUEST_NOT_FOUND; approver 428 ACTION_CONFIRMATION_REQUIRED then approved with one approve row by the approver). Ablations with EXIT-trap restore: A1 decideNode gates removed: pins 2,3,4 red, 1,5 green; A2 approve without requiresConfirmation: pins 1,5 red; A3 approve exposed:false: 5/5 red.", "gates": "dispatch-gates --commands: 95 derived; all 95 exit 0 after whole-tree build (pass started on d4fe7020c7); 37 text-affected commands re-run on final head 62de438433, all exit 0; pnpm lint exit 0; plugin-approvals typecheck exit 0; dogfood typecheck exit 134 = local V8 OOM, re-run with 8 GB heap exit 0, 0 error TS. dispatch-gates --ran: 95 derived, 95 run, 0 NOT-MEASURED. CI check-runs: in_progress at report time.", "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm", "mcp_calls": "0", "api_writes": "2 — post-stamped comment (claim re-post 6837196480), fleet-write pr_create #32886; this report is the 3rd", "open_questions": [], "security_findings": "withheld", "out_of_scope_findings": [ "class: c · reach: an AI service account named on a slate (or reassigned onto one) can confirm its own run_action today · evidence: actionConfirmationRefusal reads no principalKind; closed by open PR #32691 (ADR-0151 D3 rule 3) · carrier: PR #32886 acceptance notes · noted, not filed" ] }13 remaining items
objectstack-fleet commentedon Nov 13, 2026
domain:server#5 · os-elon-musk · session_016WV4cwJbS8sZAfru2iyvQq
Claim: the read half, p1 (triage#1 07:58Z: p1, not an 18.4.0 blocker). Ruled A (6837430865); its blocker #32865 closed completed (PR #32971,
04c35f0952). The decide half already landed as PR #32886.Session:
session_016WV4cwJbS8sZAfru2iyvQqAccount:
os-elon-muskBranch:
the card thread's designated claude/project-thread-* branch (the card thread re-posts this whole claim with the exact branch before its PR opens)Worktree:
objectstack-issue-32442Domain:
domain:serverSeat:
domain:server#5File surface:
packages/mcp/src/mcp-http-tools.ts(the record tools'sys_refusal asksisAiReadExposedfrom@objectstack/specfor the read tools only: query, get one, aggregate, describe, list; writes unchanged), plus the stdio bridge's matching guard if it has its own;packages/plugins/plugin-approvals/src/sys-approval-request.object.ts(declaresenable.aiReadable: true); the read tools' description text naming the "pending for me" filter shape; tests beside each; a dogfood pin for the five acceptance points in comment 6846046224 (only the console's My Pending rows for an approver, nothing for the submitter, enough display fields, the tool text, and end to end submit, list, approve, resume)Container & model:
M,mode:thread,model: default,effort: high (M, p1; the contract review goes to triage#1 per the maintainer's 05:39Z word, not fable)Clause-②: yes (widening)
Metadata-protocol: none
Responsibility:
objectstack: the MCP record tools refuse every sys_ object by name, so an approver's agent cannot list what waits on them and the decide half (PR #32886) needs a pasted request id | sys_approval_request declares enable.aiReadable; the read tools honour isAiReadExposed with every later gate unchanged (permissions, the approvals request-read gate, field masking); a "pending for me" read returns exactly the console's my_pending rows | every approver using an MCP agentThread-read: 6847462671
Premise: holds (read from code on main:
isAiReadExposedhas no consumer outside packages/spec, and the MCP sys_ guard is in mcp-http-tools.ts)Serial constraints cleared:
draft PR #33057 (os-tesla, #32936) edits tool description text in mcp-http-tools.ts, a different region; whichever lands second merges main. #32993 (submitter recall over MCP) is a sibling card, not stackedobjectstack-fleet commentedon Nov 13, 2026
domain:server#5 · os-elon-musk · session_016WV4cwJx2CfBxrD3ojeDPr
os-dev-report
os-dev report — #32442 (read half) · needs_decision · branch head 77b7a8a · 2026-11-13T08:52Z
Step 0 on main is red as the order expects: over MCP every read of
sys_approval_requestis refused by thesys_*name guard (dogfoodapproval-read-over-mcp.dogfood.test.ts, 6/6 red). The admission is built and pushed (no PR yet). After admission the dogfood measured two forks the ruling does not settle, so the card goes back to the seat with options.{ "issue": 32442, "status": "needs_decision", "branch": "claude/project-thread-bb7kzf", "pr": null, "session": "session_016WV4cwJx2CfBxrD3ojeDPr", "premise_still_valid": true, "summary": "Built and pushed at 77b7a8a1: an optional McpDataBridge member aiReadExposed(name), answered by both bridges (runtime domains/mcp.ts, stdio-data-bridge.ts) with isAiReadExposed over the whole definition; the five read tools ask it for a sys_ name before refusing (fail-closed on absence or throw), every write tool and validate_expression and the file tools keep refusing; sys_approval_request declares enable.aiReadable: true (sys_approval_action declares nothing); query_records text names the waiting-on-you filter shape. Two forks measured after admission: F1, a member holds no data-door read on sys_approval_request (no default set grants it, by design per action-execution.ts), so the approver's query answers 403 PERMISSION_DENIED and list_objects hides the object; F2, the filter pending_approvers contains {current_user_id} misses slates addressed by email or position/team literals (pending_approvers stores the address; measured: an email-addressed request returned 0 rows for its approver under a test grant), a second fold approver-address.ts forbids.", "tests": "mcp: vitest run src/mcp-system-object-ai-read.test.ts src/mcp-action-system-object-exposure.test.ts src/mcp-http-tools.list-objects-outage.test.ts -> Test Files 3 passed, Tests 33 passed. dogfood approval-read-over-mcp.dogfood.test.ts: step 0 (mcp dist from 4462b4d9, runtime and approvals source at main) 6 failed of 6, each 'is a system object and is not exposed via MCP'; after admission, no grant: 5 failed / 1 passed (403 PERMISSION_DENIED); after admission plus a test-only read grant: 3 passed (submitter reads own 2, stranger reads 0 by query and by id, tool text) / 3 failed (pending-for-me 0 rows on an email-addressed slate). Ablation not run: behaviour still undecided.", "gates": "NOT MEASURED: dispatch-gates families, reason: stopped at needs_decision before the PR; to run on the final head.", "dogfood_battery": "n/a — no ! in the title and no (narrowing) arm", "mcp_calls": "2 — issue_read get, issue_read get_comments (reads only)", "api_writes": "1 — this post-stamped comment", "open_questions": [ { "question": "F1: who may read sys_approval_request rows on the data door, which the MCP read tools go through?", "options": [ "1B plugin-approvals grants every signed-in member read on sys_approval_request; request-read-gate.ts still narrows rows to the approvals door's own answer, so a member sees on REST /data and MCP exactly the inbox rows", "1A leave it to apps (grant per profile); out of the box no approver's agent sees the object", "1C enable.aiReadable grants the read on the MCP door only; contradicts the spec key's text and splits the doors" ], "recommendation": "1B: the user value (every approver's agent) needs it, and the rows stay exactly what the approvals door already serves the same member" }, { "question": "F2: how does an agent ask for the requests waiting on the caller?", "options": [ "2B the approvals request read gate answers a read pinned pending_approvers $contains the caller's own id with the service's acting-address fold (email, position, team slots included); fixes the console my_pending list view too", "2A ship the user-id filter and state its limit in the tool text", "2C a new filter token for the caller's approver addresses (spec key, contract review)" ], "recommendation": "2B: one fold, the approvals service's own, no spec key" } ], "security_findings": "none", "out_of_scope_findings": [ "class: a · reach: the console sys_approval_request list view my_pending (filter pending_approvers contains {current_user_id}) omits a pending request whose slate addresses the viewer by email or position/team literal; measured through the same filter over MCP: 0 rows for the email-addressed approver · dedupe words: my_pending list view approver email position slate · carrier: this card's F2 if 2B is chosen" ] }Analysis with costs and the four facets: seat 5 project files
32442-read/needs-decision.md. Claim note: the HTTP bridge (packages/runtime/src/domains/mcp.ts) answers the attestation and is outside the claim's file surface; the claim re-post before the PR adds it.Generated by Claude Code
objectstack-fleet commentedon Nov 13, 2026
domain:server#5 · os-elon-musk · session_016WV4cwJx2CfBxrD3ojeDPr
Claim: card thread for the seat claim 6848104060 (the read half). This PR lands the read admission only, as
Part of #32442; F1/F2 of report 6848413320 wait on the maintainer, and the dogfood end-to-end pin rides the approvals half. Re-posted to add the HTTP bridge to the file surface (seat-approved).Session:
session_016WV4cwJx2CfBxrD3ojeDPrAccount:
os-elon-muskBranch:
claude/project-thread-bb7kzfWorktree:
objectstack-issue-32442Domain:
domain:serverSeat:
domain:server#5File surface:
packages/mcp/src/mcp-http-tools.ts(the record tools'sys_refusal asks the bridge'saiReadExposedattestation for the read tools only: query, get one, aggregate, describe, list; writes unchanged),packages/mcp/src/stdio-data-bridge.tsandpackages/runtime/src/domains/mcp.ts(both bridges answer the attestation withisAiReadExposed),packages/plugins/plugin-approvals/src/sys-approval-request.object.ts(declaresenable.aiReadable: true); the read tool's description text naming the "pending for me" filter shape; tests beside each;.changeset/**Container & model:
M,mode:thread,model: default,effort: high (M, p1; the contract review goes to triage#1 per the maintainer's 05:39Z word, not fable)Clause-②: yes (widening)
Metadata-protocol: none
Responsibility:
objectstack: the MCP record tools refuse every sys_ object by name, so an approver's agent cannot list what waits on them and the decide half (PR #32886) needs a pasted request id | sys_approval_request declares enable.aiReadable; the read tools honour isAiReadExposed with every later gate unchanged (permissions, the approvals request-read gate, field masking) | every approver using an MCP agentThread-read: 6848413320
Premise: holds (step 0 on main: every MCP read of sys_approval_request refused by the sys_ name guard)
Serial constraints cleared:
draft PR #33057 (os-tesla, #32936) edits tool description text in mcp-http-tools.ts, a different region; whichever lands second merges main. #32993 (submitter recall over MCP) is a sibling card, not stackedParent-claim: 6848104060
objectstack-fleet commentedon Nov 13, 2026
domain:server#5 · os-elon-musk · session_016WV4cwJbS8sZAfru2iyvQq
Ruled: read half forks F1 and F2 → 1B + 2B (maintainer, 2026-11-13T09:51Z, in the seat thread)
sys_approval_request.request-read-gate.tsstill narrows the rows to the approvals door's own answer (submitter, current approver, past actor; an override holder is unrestricted). A member sees on the data door and over MCP exactly the rows the inbox already shows them, and nothing more.pending_approvers $contains <the caller's own id>with the service's acting-address fold, so slates addressed by email, position or team count as "waiting on me". That is the one foldapprover-address.tsallows, and the console'smy_pendinglist view inherits the fix.sys_object to the read tools) may land first asPart of #32442. The 18.4.0 merge freeze (triage#1, [sweep] v18.4.0 release test sweep #32908 6848983225) applies: no enqueue of a changeset PR until chore: version packages #29963 merges.objectstack-fleet commentedon Nov 13, 2026
domain:server#5 · os-elon-musk · session_016WV4cwJx2CfBxrD3ojeDPr
Claim: card thread for the seat claim 6848104060 (the read half). The maintainer ruled 1B + 2B (6849636735), so this card now closes the read half in ONE PR,
Fixes #32442: the MCP read admission, the member baseline read onsys_approval_request, the request read gate answering "waiting on me" with the approvals fold, and the end-to-end dogfood pin. Re-posted to add the approvals files and the permission-set path to the file surface (seat-approved).Session:
session_016WV4cwJx2CfBxrD3ojeDPrAccount:
os-elon-muskBranch:
claude/project-thread-bb7kzfWorktree:
objectstack-issue-32442Domain:
domain:serverSeat:
domain:server#5File surface:
packages/mcp/src/mcp-http-tools.ts(the read tools ask the bridge'saiReadExposedattestation; writes unchanged),packages/mcp/src/stdio-data-bridge.tsandpackages/runtime/src/domains/mcp.ts(both bridges answer withisAiReadExposed),packages/plugins/plugin-approvals/src/sys-approval-request.object.ts(declaresenable.aiReadable: true),packages/plugins/plugin-security/src/objects/default-permission-sets.ts(1B:member_defaultnamessys_approval_requestread-only),packages/plugins/plugin-approvals/src/request-read-gate.tsandpackages/plugins/plugin-approvals/src/approval-service.ts(2B: a conjunctivepending_approvers $contains <own id>answered with the service's acting-address fold),packages/qa/dogfood/test/approval-read-over-mcp.dogfood.test.ts(end to end over MCP); tests beside each;content/docs/ai/connect-mcp.mdx,packages/mcp/README.md;.changeset/**Container & model:
M,mode:thread,model: default,effort: high (M, p1; the contract review goes to triage#1 per the maintainer's 05:39Z word, not fable)Clause-②: yes (widening)
Metadata-protocol: none
Responsibility:
objectstack: the MCP record tools refuse every sys_ object, members hold no data-door read on approval requests, and pending_approvers contains {current_user_id} misses email and position slates, so an approver's agent cannot list what waits on them | read admission by enable.aiReadable, member baseline read with the participant gate deciding rows, the gate answering waiting-on-me with the approvals fold | every approver using an MCP agent, and the console's My Pending viewThread-read: 6849636735
Premise: holds (step 0 on main: every MCP read of sys_approval_request refused; after admission alone, 403 for members and 0 rows for an email-addressed approver, report 6848413320)
Serial constraints cleared:
draft PR #33057 (os-tesla, #32936) edits other description text in mcp-http-tools.ts; main merged once (a596c03c), no conflict with main now. #32993 (submitter recall over MCP) is a sibling card. Lands after the 18.4.0 freeze lifts (#29963)Parent-claim: 6848104060
objectstack-fleet commentedon Nov 13, 2026
triage#1 · hotlong · session_01Q4EjjMnyLqJdzuktEmRPXH
Path: none
Triage: H14 ·
pm:blockingderived · 2026-11-13T12:17Z⛔ Not a claim; grade and state unchanged. Open card(s) #32641 name this card on a line-leading
Blocked-by:, so the derived cache is added. It comes off when they close or drop the line.objectstack-fleet commentedon Nov 13, 2026
domain:server#5 · os-elon-musk · session_016WV4cwJx2CfBxrD3ojeDPr
os-dev-report
os-dev report — #32442 (read half) · ready_for_review · PR #33117 · head 7fd55e6 · 2026-11-13T14:55Z
The maintainer's 1B + 2B (6849636735) is built on this card, with the read admission, in ONE draft PR #33117 carrying
Fixes #32442. Step 0 was red on main as the order expects; every red line of the ruling is pinned over the live MCP transport with no test grant, and each half has an ablation that turns its pins red.{ "issue": 32442, "status": "ready_for_review", "branch": "claude/project-thread-bb7kzf", "pr": 33117, "head": "7fd55e60c1", "session": "session_016WV4cwJx2CfBxrD3ojeDPr", "premise_still_valid": true, "summary": "Read admission: the five MCP read tools admit a sys_ object the bridge attests with isAiReadExposed (enable.aiReadable: true), fail-closed; writes keep refusing every sys_ object; sys_approval_request declares it. 1B: member_default names sys_approval_request read-only; request-read-gate.ts still decides rows. 2B: the gate answers a conjunctive pending_approvers $contains <own id> with waitingOnCallerIds = approverRequestIds(actingAddresses(caller)), the inbox's own fold; other ids, operators and $or are read as written. Console my_pending inherits it.", "tests": "dogfood approval-read-over-mcp 8 passed (email + team slates, submitter and stranger nothing, stranger nothing by id and aggregate n:0, masked snapshot field withheld from approver and served to submitter, only sys_ object listed, writes and sys_approval_action refused, e2e approve with confirmation resumes the flow and stamps the record); plugin-approvals request-read-waiting-on-caller 7 passed; mcp 1113 passed; plugin-security, plugin-approvals full suites and typechecks exit 0; dogfood, mcp, runtime typecheck exit 0.", "ablations": "A1 readGuard admits nothing -> 4 red; A2 runtime bridge false -> 1 red; A3 declaration removed -> 1 red; 1B member_default line removed (dist rebuilt, preflight --absent) -> dogfood 7 red, 403; 2B rewrite disabled -> integration position pin red, dogfood 4 red (email slate, masked read, aggregate n:2, e2e). Team pin stays green under 2B: team slots expand to user ids at open.", "gates": "dispatch-gates --ran on 7fd55e60c1: 103 derived, 103 run, 0 NOT-MEASURED, 0 UNRUN, all exit 0 (query-options-erasure first 1, fixed by typing the rig's options).", "dogfood_battery": "n/a — no ! in the title and no (narrowing) arm", "mcp_calls": "0 this round", "api_writes": "3 — claim re-post 6849988930, pr_create #33117 via the relay, this comment", "contract_review": "owed: Clause-② yes (widening); the seat asks triage#1 (#32588)", "open_questions": [] }objectstack-fleet commentedon Nov 13, 2026
domain:server#5 · os-elon-musk · session_016WV4cwJx2CfBxrD3ojeDPr
Claim: card thread for the seat claim 6848104060 (the read half). The maintainer ruled 1B + 2B (6849636735), so this card now closes the read half in ONE PR, #33117,
Fixes #32442: the MCP read admission, the member baseline read onsys_approval_request, the request read gate answering "waiting on me" with the approvals fold, and the end-to-end dogfood pin. Re-posted for contract review round 1 (6857191533, seat-relayed): addspackages/plugins/plugin-audit/src/activity-field-redaction.ts(GHSA-2985-5f64-8wgh), the suites whose premise 1B moved, and the statements it left false.Session:
session_016WV4cwJx2CfBxrD3ojeDPrAccount:
os-elon-muskBranch:
claude/project-thread-bb7kzfWorktree:
objectstack-issue-32442Domain:
domain:serverSeat:
domain:server#5File surface:
packages/mcp/src/mcp-http-tools.ts(the read tools ask the bridge'saiReadExposedattestation; writes unchanged),packages/mcp/src/stdio-data-bridge.tsandpackages/runtime/src/domains/mcp.ts(both bridges answer withisAiReadExposed),packages/plugins/plugin-approvals/src/sys-approval-request.object.ts(declaresenable.aiReadable: true),packages/plugins/plugin-security/src/objects/default-permission-sets.ts(1B:member_defaultnamessys_approval_requestread-only),packages/plugins/plugin-approvals/src/request-read-gate.tsandpackages/plugins/plugin-approvals/src/approval-service.ts(2B: a conjunctivepending_approvers $contains <own id>answered with the service's acting-address fold),packages/qa/dogfood/test/approval-read-over-mcp.dogfood.test.ts(end to end over MCP);packages/plugins/plugin-audit/src/activity-field-redaction.ts(GHSA-2985-5f64-8wgh);packages/plugins/plugin-approvals/src/approvals-plugin.ts(warning text),packages/runtime/src/action-execution.ts(prose); the suites 1B moved:packages/verify/src/action-door-api-forward-denied-subject.test.ts,packages/qa/dogfood/test/approval-request-schema-party-read.dogfood.test.ts;sys_approval_requestdeclaresenable.feeds: false; tests beside each;content/docs/ai/connect-mcp.mdx,content/docs/automation/approvals.mdx,packages/mcp/README.md;.changeset/**Container & model:
M,mode:thread,model: default,effort: high (M, p1; the contract review goes to triage#1 per the maintainer's 05:39Z word, not fable)Clause-②: yes (widening)
Metadata-protocol: none
Responsibility:
objectstack: the MCP record tools refuse every sys_ object, members hold no data-door read on approval requests, and pending_approvers contains {current_user_id} misses email and position slates, so an approver's agent cannot list what waits on them | read admission by enable.aiReadable, member baseline read with the participant gate deciding rows, the gate answering waiting-on-me with the approvals fold | every approver using an MCP agent, and the console's My Pending viewThread-read: 6856567007
Premise: holds (step 0 on main: every MCP read of sys_approval_request refused; after admission alone, 403 for members and 0 rows for an email-addressed approver, report 6848413320)
Serial constraints cleared:
draft PR #33057 (os-tesla, #32936) edits other description text in mcp-http-tools.ts; main merged once (a596c03c). #32993 (submitter recall over MCP) is a sibling card. The 18.4.0 freeze has liftedParent-claim: 6848104060
objectstack-fleet commentedon Nov 13, 2026
domain:server#5 · os-elon-musk · session_016WV4cwJx2CfBxrD3ojeDPr
Claim: card thread for the seat claim 6848104060 (the read half). The maintainer ruled 1B + 2B (6849636735), so this card now closes the read half in ONE PR, #33117,
Fixes #32442: the MCP read admission, the member baseline read onsys_approval_request, the request read gate answering "waiting on me" with the approvals fold, and the end-to-end dogfood pin. Re-posted after contract review round 3 (PASS, 6862530251) for the final push: the plugin-audit surface now covers every file the GHSA-2985-5f64-8wgh hardening moves, and the request no longer declaresenable.feeds: false(reverted in round 2).Session:
session_016WV4cwJx2CfBxrD3ojeDPrAccount:
os-elon-muskBranch:
claude/project-thread-bb7kzfWorktree:
objectstack-issue-32442Domain:
domain:serverSeat:
domain:server#5File surface:
packages/mcp/src/mcp-http-tools.ts(the read tools ask the bridge'saiReadExposedattestation; writes unchanged),packages/mcp/src/stdio-data-bridge.tsandpackages/runtime/src/domains/mcp.ts(both bridges answer withisAiReadExposed),packages/plugins/plugin-approvals/src/sys-approval-request.object.ts(declaresenable.aiReadable: true),packages/plugins/plugin-security/src/objects/default-permission-sets.ts(1B:member_defaultnamessys_approval_requestread-only),packages/plugins/plugin-approvals/src/request-read-gate.tsandpackages/plugins/plugin-approvals/src/approval-service.ts(2B: a conjunctivepending_approvers $contains <own id>answered with the service's acting-address fold),packages/qa/dogfood/test/approval-read-over-mcp.dogfood.test.ts(end to end over MCP); plugin-audit, GHSA-2985-5f64-8wgh:packages/plugins/plugin-audit/src/activity-field-redaction.ts,audit-log-field-redaction.ts,audit-writers.ts,parent-field-query-guard.ts,index.ts, and newside-copy-columns.tsandside-copy-migration.ts, with tests beside them;packages/plugins/plugin-approvals/src/approvals-plugin.ts(warning text),packages/runtime/src/action-execution.ts(prose); the suites 1B moved:packages/verify/src/action-door-api-forward-denied-subject.test.ts,packages/qa/dogfood/test/approval-request-schema-party-read.dogfood.test.ts; tests beside each;content/docs/ai/connect-mcp.mdx,content/docs/automation/approvals.mdx,packages/mcp/README.md;.changeset/**Container & model:
M,mode:thread,model: default,effort: high (M, p1; the contract review goes to triage#1 per the maintainer's 05:39Z word, not fable)Clause-②: yes (widening)
Metadata-protocol: none
Responsibility:
objectstack: the MCP record tools refuse every sys_ object, members hold no data-door read on approval requests, and pending_approvers contains {current_user_id} misses email and position slates, so an approver's agent cannot list what waits on them | read admission by enable.aiReadable, member baseline read with the participant gate deciding rows, the gate answering waiting-on-me with the approvals fold | every approver using an MCP agent, and the console's My Pending viewThread-read: 6857527959
Premise: holds (step 0 on main: every MCP read of sys_approval_request refused; after admission alone, 403 for members and 0 rows for an email-addressed approver, report 6848413320)
Serial constraints cleared:
draft PR #33057 (os-tesla, #32936) edits other description text in mcp-http-tools.ts; main merged once more for this push (b6acbd9a9b). #32993 (submitter recall over MCP) is a sibling card. The 18.4.0 freeze has liftedParent-claim: 6848104060