Skip to content

checklist: re-point ai.mcp-run-action-exposure-gate acceptance[4] and step 6 — they still pin the wholesale sys_* refusal that rulings on #27681 and #27900 replaced #29892

Closed

Description

@objectstack-fleet

domain:devx#1 · os-warren · session_01JQwxbZtZMhQkARKJtViA9U

Filing gate: ① a stale clause, a QA run clause fail (ai.mcp-run-action-exposure-gate acceptance[4]) whose red line needs an owner (checklist-test §5, "过期规格"). It failed the same way in wave 4 (#28942) and was parked on the 18.3.0 anchor #27377, which has since closed with the re-point not made, so it is red again at wave 5.
Business reason: the item is the MCP door's release evidence that an agent cannot run actions it should not reach. While acceptance[4] asserts a refusal the product no longer makes, every sweep reports this P1 item FAIL although the gate holds as ruled, and the one real defect it found (#28943) is buried under a permanent red row.
Reader who acts: the domain:devx lane that owns docs/qa/platform-checklist/areas/ai.json (one item revision, node scripts/check-platform-checklist.mjs green).
Duplicate search (incl. closed): mcp-run-action-exposure-gate re-point → 8 hits; none is a re-point card (wave 4 parked it on #27377 instead of carding).

Disposition: stale spec. Since maintainer ruling 6513869839 on #27681 (letter B) and the ADR-0011 addendum (ruling 6523087116 on #27900, amended by 6540309323), a sys_* action is listed and run over MCP when the action itself declares ai.exposed. Code: systemObjectActionExposureError (packages/runtime/src/action-execution.ts) and isListableAction (packages/mcp/src/mcp-http-tools.ts). Item revision 6 kept acceptance[4] as "system objects are refused wholesale".

Measured at 589049b0 (2 fresh stock boots, MCP Streamable HTTP on /api/v1/mcp)

Revise (areas/ai.json, item mcp-run-action-exposure-gate)

  • acceptance[4]: a sys_* action with no ai block is refused in either current spelling with zero side effects, and an ai.exposed system action passes this guard (and meets the next gate);
  • step 6: name a non-exposed action (create_api_key), since "any sys_* action name" can pick an exposed one;
  • acceptance[1].verify: "the snapshot is the one exposed action" no longer holds (37 listed on stock, 38 with qa_ai_gated); entries marked unavailable are part of the contract.

QA-source: #29890 · ai.mcp-run-action-exposure-gate · acceptance[4]

Activity

  1. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: first-touch audit · p1 · domain:devx · pm:queue · 2026-11-03T10:55Z

    ⛔ Not a claim.


    Generated by Claude Code

  2. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:devx#2 · marchtian · session_017ihL2gLghEqeDKTbDTC7Zd

    Claim: PM loop round 3
    Session: session_017ihL2gLghEqeDKTbDTC7Zd
    Account: marchtian
    Branch: claude/issue-29892-mcp-exposure-gate-repoint
    Worktree: objectstack-issue-29892
    Domain: domain:devx
    Seat: domain:devx#2
    File surface: docs/qa/platform-checklist/areas/ai.json (item ai.mcp-run-action-exposure-gate), plus FOLLOW-UPS.md / coverage.json where the checklist procedure requires
    Container & model: M, mode:subagent, model: default tier, effort: high
    Clause-②: no
    Metadata-protocol: none
    Responsibility: acceptance[4] and step 6 still pin the wholesale sys_* refusal that rulings 6513869839 (#27681) and 6523087116 / 6540309323 (#27900) replaced, so this P1 release-evidence item reads FAIL on every sweep
    Thread-read: 6601854076
    Premise: holds
    Serial constraints cleared: no open PR from this seat touches platform-checklist/areas/ai.json at claim time

  3. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:devx#2 · marchtian · session_017ihL2gLghEqeDKTbDTC7Zd
    os-dev-report

    {
      "issue": 29892,
      "status": "done",
      "branch": "claude/issue-29892-mcp-exposure-gate-repoint",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/29931",
      "head": "dd6816240090d905cc5b2efa6252eeed352db65f",
      "session": "session_017ihL2gLghEqeDKTbDTC7Zd",
      "premise_still_valid": true,
      "gates": {
        "platform_checklist": "node scripts/check-platform-checklist.mjs :: exit 0 at dd68162400 ('check-platform-checklist: OK — 16 areas, 359 items'; symbol anchors 1137/1147 resolved, base a04e9d76 read 1134/1144: the three new source anchors all resolve)",
        "derived": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack at dd68162400: 16 commands, each exit 0 — check-adr-links (+ --self-test), check-closing-keyword-parity (+ --self-test), check-comment-mask-corpus, ci/plan-test-core-shards --self-test, lint check:doc-formula-expressions, check:ci-filter-parity, check:cross-package-test-inputs, check:doc-authoring, check:driver-memory-census, check:gitlink-declared, check:nul-bytes, check:platform-checklist, check:refd-timer-probe, check:watch-hint-literal. check:doc-formula-expressions first exited 3 (PREREQUISITE NOT MET: @objectstack/formula and @objectstack/lint unbuilt); after turbo build of those two (lock VERDICT command-exit 0) it exited 0",
        "ran_reconciliation": "dispatch-gates --ran with exit codes recorded: 16 derived, 16 run, 0 NOT-MEASURED, 0 UNRUN (a DERIVED zero)",
        "not_local": "type-check lanes, Plan Test Core shards step, the 53 roster families, 11 wide-population families: CI's, NOT MEASURED locally; PR check-runs not yet concluded at report time",
        "changeset": "none — docs only; skip-changeset rode pr_create and reads back on the PR",
        "merge_origin_main": "merged once before pr_create: origin/main had not moved past a04e9d76c1 (ls-remote confirms)"
      },
      "deviations": [
        "title re-pointed too: it said 'refuses system objects', the retired wholesale refusal; now 'admits a system-object action only on its own ai.exposed'",
        "acceptance[1].verify re-pointed too: it called showcase_portfolio_snapshot 'the one exposed action', true only under the retired refusal. It now says the listing also carries the ai-exposed sys_* identity actions and that an unavailable entry is listed by contract. The clause text is unchanged, and the permitted-half reasoning still holds (no sys_* action declares requiredPermissions)",
        "fixtures.requires[4] added (appended, so no index shifts) to stage acceptance[4]'s exposed half: a probe API key plus the admin's session token as the MCP bearer",
        "source gained three symbol anchors (systemObjectActionExposureError, isListableAction, sys-api-key.object.ts#revoke_api_key)",
        "the new clause was not run live: behaviour is derived from source and unit pins at a04e9d76, plus the card's own stock-boot reading at 589049b0"
      ],
      "files_changed": ["docs/qa/platform-checklist/areas/ai.json (item ai.mcp-run-action-exposure-gate, revision 6 to 7; +15/-10)"],
      "claims": [
        {
          "re_point": "acceptance[4]: a sys_* action passes the MCP system-object guard only on its own ai.exposed. REFUSED half: create_api_key on sys_api_key, absent from list_actions, refused in both live spellings, no key created. EXPOSED half: revoke_api_key, listed with aiExposed true and run under the admin session token with confirm true, ok true and the key revoked",
          "evidence": "packages/runtime/src/action-execution.ts L141-158 systemObjectActionExposureError (returns null only on action?.ai?.exposed === true at L154; refusal text L156; the stored-metadata family stays refused L148-153), called in invokeBusinessAction L4260-4261; packages/mcp/src/mcp-http-tools.ts L395-397 isListableAction, refusal text L399-404, list filter L1483, run_action pre-screen L1585-1590; runtime listing asks the same predicate at packages/runtime/src/domains/mcp.ts L863. Pins run on this tree: packages/mcp/src/mcp-action-system-object-exposure.test.ts 8/8 passed (L82 lists attested and hides unattested; L98 refuses unattested with no bridge run; L120 admits attested), packages/runtime/src/mcp-system-object-action-exposure.test.ts 11/11 passed (L133 refuses unflagged sys_*; L144 yields to ai.exposed true only; L152 listing; L171 run_action refusal with no dispatch; L187 flagged runs through every gate). Dogfood corroboration (read, not run): packages/qa/dogfood/test/mcp-system-object-action-exposure.dogfood.test.ts L233-249 and L344-350 pin both spellings on impersonate_user. Fixture: packages/platform-objects/src/identity/sys-api-key.object.ts create_api_key L100 has no ai block; revoke_api_key L142 has ai.exposed with requiresConfirmation true"
        },
        {
          "re_point": "steps[6]: names create_api_key (refused, with and without objectName, sys_api_key count read before and after) and revoke_api_key (listed and run with confirm true under the session bearer, key re-read)",
          "evidence": "'any sys_* action name' can now pick one of the 36 exposed ones: git grep counts 36 'exposed: true' blocks under packages/platform-objects/src at a04e9d76, and the card read 37 list_actions entries on a stock boot at 589049b0"
        },
        {
          "re_point": "strength kept: the clause still requires a sys_* action that does not declare ai.exposed to be refused with zero side effects, and names both halves. The verify names both FAIL shapes (an undeclared sys_* action listed or run; an exposed one refused with a system-object text)",
          "evidence": "acceptance[4].clause and .verify in the diff"
        },
        {
          "re_point": "negative[1] (the list/run agreement that found #28943) left intact; the clause's verify points to it for the osk_ unavailable case instead of scoring that case itself",
          "evidence": "negative[] unchanged in the diff"
        }
      ],
      "mcp_calls": "0",
      "api_writes": "2 relay strokes, each a POST /repos/objectstack-ai/objectstack/dispatches executed by fleet-write as objectstack-fleet[bot]: (1) pr_create, run 41645689870 success = POST /repos/objectstack-ai/objectstack/pulls (draft) + POST /repos/objectstack-ai/objectstack/issues/29931/labels [skip-changeset]; body read back 7138 bytes sent and stored, identical; no assignees, no reviewers; (2) this comment through post-stamped.mjs = POST /repos/objectstack-ai/objectstack/issues/29892/comments. Plus one git push of the branch (not a REST write)",
      "security_findings": "withheld",
      "out_of_scope_findings": [
        "carrier: none · noted, not filed: fixtures.requires[0] still says 'the showcase's ONE ai-exposed action'. That is true of app-authored actions and was left as is; acceptance[1].verify now says the listing carries the sys_* exposed actions too",
        "carrier: none · noted, not filed: the guard's third spelling, for the stored-metadata family ('…stores metadata bodies and is never exposed via MCP'), is outside this clause, which names sys_api_key only"
      ]
    }
  4. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:devx#2 · marchtian · session_017ihL2gLghEqeDKTbDTC7Zd

    Landed · domain:devx#2 · 2026-11-03T13:57Z

    PR #29931 merged as 242665f105, and the card closed on its Fixes.

    The seat releases the card: pm:dispatched comes off, and the worktree and branch are removed.

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

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions