Skip to content

MCP list_actions lists a deployment-authored action on a packaged object twice, attributing one row to the package's namespace, and refuses its AI face as ambiguous #33029

Closed

Description

@objectstack-fleet

qa#3 · os-tesla · session_01L9qibw6yXcLi9aRRBpPT4W

Reproduction (fresh stock showcase at ee9ad83, admin; reproduced on two fresh boots)

  1. PUT /api/v1/meta/action/qa_ai_gated with no ?package=, body {name:'qa_ai_gated', label:'QA AI gated', objectName:'showcase_task', operation:'update', patch:{progress:50}, execution:'perRecord', ai:{exposed:true, description:'a description of 40+ chars'}} → 200.
  2. GET /api/v1/meta/action lists qa_ai_gated once, with _packageId null.
  3. MCP tools/call list_actions {} with an admin osk_ key returns:
    • two qa_ai_gated rows on showcase_task, one with namespace:"showcase" and one without;
    • refusedFaces[0].face = showcase_task-qa_ai_gated, "derived for 2 actions: … of namespace "showcase"; … authored in this environment".
  4. run_action {actionName:'showcase_task-qa_ai_gated'} → 404 "Action face … names no one action". The bare name and namespace:'showcase' both run it.

Expected: one row with no namespace (the action is environment-authored), and its face resolves. The action was never shipped by com.example.showcase.

Mechanism (read from source, not proven)

The authored action is merged into showcase_task's embedded actions; GET /meta/object/showcase_task lists qa_ai_gated among them. collectActionDeclarations (packages/runtime/src/action-execution.ts:5160-5189) files that embedded copy under declaringPackageOf(action) ?? declaringPackageOf(obj), which is com.example.showcase. The standalone copy's holder is ''. The ADR-0150 D4 dedupe keys on the holder package, so the two copies are not collapsed.

Related, closed: #32437 (list_actions listed one action once per bound object).

QA-source: #33025 · ai.mcp-run-action-exposure-gate · observed beside the clauses

Activity

  1. objectstack-fleet commented on Nov 13, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · hotlong · session_01Q4EjjMnyLqJdzuktEmRPXH

    Path: none

    Triage: first touch → domain:server · p1 · pm:queue · 2026-11-13T05:48Z

    ⛔ Not a claim.

    • Line: an admin authoring an action on a packaged object (a normal authoring act) · MCP list_actions · every listing · measured twice on fresh boots.
    • Grade: p2 (an agent-visible defect: the action is listed twice, one copy attributed to the package namespace it does not belong to). One raise for an MCP wrong answer, since the agent can pick the wrong attribution (rule 8), gives p1. No reach discount: authoring an action is everyday admin work, not a rare configuration act. It is linked under the MCP epic [Epic] MCP: what an agent can read and write on the HTTP MCP door, and answers that agree with the gate #32897.

    Generated by Claude Code

  2. added
    domain:serverDomain lane — seat card indexed by label:pm:seat
    pm:queueReady for the PM dispatch loop
    priority:p1High: required for production / M2
    on Nov 13, 2026
  3. objectstack-fleet commented on Nov 13, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#8 · os-elon-musk · session_016WV4cwqTK71kjQzHae8T5J

    Claim: PM loop round 3 (p1, pm:queue; card ≡ 2 (mod 3); a sub-issue of the tracking epic #32897, which has no seat of its own, taken like #32442 was) · 2026-11-13T06:34Z
    Session: session_016WV4cwqTK71kjQzHae8T5J
    Account: os-elon-musk
    Branch: the card thread's designated claude/project-thread-* branch, written in its whole re-posted claim before the first push
    Worktree: the card thread's own checkout
    Domain: domain:server
    Seat: domain:server#8
    File surface: packages/runtime/src/action-execution.ts (collectActionDeclarations and the ADR-0150 D4 dedupe it feeds) and tests beside it, the MCP list_actions / run_action face resolution in packages/runtime/src/** only where it reads those declarations, content/docs/** where the listing is documented, .changeset/** (stop on breach; explain in the report)
    Container & model: M, mode:thread, model: opus (TIER_DEFAULT unless dispatch-gates.mjs --tier derives more), effort: high
    Clause-②: yes (widening)
    Metadata-protocol: none
    Declaration note: the environment-authored action's face OBJECT-NAME now resolves on run_action (it answered 404 "names no one action"); the duplicate namespaced row leaves list_actions. If the thread measures that the row's removal narrows a published accept set, the re-posted claim says so
    Responsibility: to be measured by the card thread (the card's mechanism is read from source, not proven)
    Thread-read: 6845319147
    Premise: holds in part (measured on origin/main 64c426a: packages/runtime/src/action-execution.ts:5208 files an embedded action under declaringPackageOf(action) ?? declaringPackageOf(obj), so an environment-authored action merged into a packaged object's actions takes the object's package; that this is the second row: NOT MEASURED, the thread's first step)
    Serial constraints cleared: none in this lane names action-execution.ts (PR #33007 merged; #33019's surface is service-automation)

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

    @objectstack-fleet
    ContributorAuthor

    domain:server#8 · os-elon-musk · session_016WV4czLj1eeZBYHELaRH6v

    Claim: PM loop round 3 (p1, pm:queue; card ≡ 2 (mod 3); a sub-issue of the tracking epic #32897, which has no seat of its own, taken like #32442 was) · re-posted by the card thread with its branch · 2026-11-13
    Session: session_016WV4czLj1eeZBYHELaRH6v
    Account: os-elon-musk
    Branch: claude/project-thread-foa4sg
    Parent-claim: 6846046795
    Worktree: the card thread's own checkout
    Domain: domain:server
    Seat: domain:server#8
    File surface: packages/runtime/src/action-execution.ts (collectActionDeclarations, actionDeclaringPackage and one new helper they share), packages/qa/dogfood/test/mcp-list-actions-environment-authored-holder.dogfood.test.ts (new; the order's real-kernel test on the stock showcase, outside the seat's first surface and added here), .changeset/** (stop on breach; explain in the report)
    Container & model: M, mode:thread, model: opus (TIER_DEFAULT unless dispatch-gates.mjs --tier derives more), effort: high
    Clause-②: yes (narrowing)
    Metadata-protocol: none
    Declaration note: widening — the environment-authored action's face OBJECT-NAME now resolves on run_action (it answered 404 "names no one action") and the duplicate namespaced row leaves list_actions. Narrowing, measured and ruled by the seat (direction A): naming the package that ships the object no longer reaches an action the environment authored on it — MCP run_action with that namespace and POST /actions/NAMESPACE/OBJECT/NAME answer 404 where they ran it. Measured not narrowed: an environment-authored flow action whose target names a showcase-shipped flow by bare name runs on REST and MCP before and after.
    Responsibility: the runtime's action collector (holder attribution, ADR-0150 D4), repo objectstack-ai/objectstack | supported paths remain: the action's face, its bare name with objectName, /actions/_env/OBJECT/NAME | measured on the stock showcase over the live MCP transport and the REST actions door
    Thread-read: 6846046795
    Premise: holds (measured on the real kernel at 64c426a: the served object embeds the stored action unstamped with _provenance: 'org', and the collector filed that copy under com.example.showcase)
    Serial constraints cleared: none in this lane names action-execution.ts (PR #33007 merged; #33019's surface is service-automation)

  6. objectstack-fleet commented on Nov 13, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#8 · os-elon-musk · session_016WV4czLj1eeZBYHELaRH6v
    os-dev-report

    {
      "issue": 33029,
      "status": "done",
      "branch": "claude/project-thread-foa4sg",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/33071",
      "session": "session_016WV4czLj1eeZBYHELaRH6v",
      "premise_still_valid": true,
      "summary": "Measured on the real kernel (stock showcase + MCPServerPlugin, admin session): the card reproduces exactly, and the mechanism holds. The registry attaches the environment-authored action into the served object's actions by reference, unstamped and _provenance 'org', and collectActionDeclarations filed that copy under the object's package. The new embeddedActionPackageOf (packages/runtime/src/action-execution.ts) files an unstamped tenant-authored embedded action under no package, in the collector and in actionDeclaringPackage. Result: one row, no namespace, and the face runs. Seat ruled direction A; Clause-②: yes (narrowing) declares three narrowed places: (1) MCP run_action with the object's package namespace 404, (2) POST /actions/NS/OBJECT/NAME 404, (3) a flow action of that kind whose target flow name two packages hold now 409 naming both on face, bare and _env (contract review 6847350544 M1). Head dc67e074.",
      "tests": "New dogfood file packages/qa/dogfood/test/mcp-list-actions-environment-authored-holder.dogfood.test.ts: 8/8 at dc67e074 (card shape, face run, two 404s, 409 two-holder flow, controls: bare + _env, one-holder flow target runs, package-shipped action once under showcase, ?package= action once under its namespace). Ablation 1, whole rule (marker ABLATE_33029, rebuilt, dist preflight present, restored, --absent clean): 5 red, 3 controls green. Ablation 2, the actionDeclaringPackage hunk alone (ABLATE_ADP_33029): 1 red (the 409 pin; the bare REST route answered 200 running the object's package's flow), 7 green. Runtime suite at a5bdc1d4: Test Files 600 passed, Tests 11916 passed / 19 skipped. Runtime typecheck exit 0. MCP #32437 pins (src/mcp-action-tools.test.ts): 25 passed.",
      "gates": "dispatch-gates --commands at dc67e074: 70 families, all run with exit codes recorded; --ran: 68 run, 2 NOT MEASURED (exit 3 prerequisite: check-plugin-teardown-shape --self-test needs an unshallow clone; check:dual-build-cjs-loads needs a whole-tree build), both owned by CI. check-adr-0087-registration --base origin/main exit 0; check-changeset-no-major exit 0; pnpm lint exit 0 (a5bdc1d4). PR check-runs: in progress at report time, not waited on.",
      "dogfood_battery": "a5bdc1d4 · os-verify-lock VERDICT command-exit 0 · Test Files 459 passed / 3 skipped (462) · Tests 3851 passed / 42 skipped (3893) · no failures. Not re-run at dc67e074, whose runtime change is docblocks only.",
      "mcp_calls": "0",
      "api_writes": "4 — relay: comment on #33029 (claim re-post 6846499643), pr_create #33071 (draft, assignee os-elon-musk), issue_patch #33071 body (contract review rework), this comment",
      "open_questions": [],
      "security_findings": "none",
      "out_of_scope_findings": [
        "carrier: none · noted, not filed: an action an administrator writes INLINE in an overlay of a packaged object's body (PUT /meta/object with actions) carries no per-action provenance and is still filed under the object's package; not measured",
        "carrier: none · noted, not filed: packagelessOriginOf classes the surviving embedded env row as the platform's beside another holder; on an object-bound key the first declaration still answers, so no answer moves today (contract review nit)"
      ]
    }

    Generated by Claude Code

  7. objectstack-fleet commented on Nov 13, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#8 · os-elon-musk · session_016WV4cwqTK71kjQzHae8T5J

    Ruling recorded · 2026-11-13T09:52Z: the maintainer agreed to the narrowing in PR #33071. He chose option A, 「同意收窄,按修正落地」, on the seat's decision card. The seat had added the third narrowed place to that card first: a two-holder flow target now answers 409.

    Landing: the contract review passed (6848091352, delta note 6848130782) and CI is green on c4c1aa31. The seat accepts and lands after the 18.4.0 merge freeze lifts (#32908; Version Packages PR #29963).

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

Metadata

Metadata

Assignees

Labels

domain:serverDomain lane — seat card indexed by label:pm:seatpriority:p1High: required for production / M2

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions