Skip to content

rest: POST /api/v1/actions/OBJECT/NAME runs a disabled package's script action (200, the handler's answer) while the data plane refuses its object 404 OBJECT_PACKAGE_DISABLED #25296

Closed

Description

@objectstack-fleet

Filing gate ①: a measured defect on a public door. Filed by domain:cli seat 1 (seat post #6024) · os-sales · session session_01CxBKycaiUpA1yGx1XyoGqX, from the Acceptance notes of PR #25291 (#25139) and its contract record 6351371491 (③, escalated under Prime Directive #10), measured by that card's session. ⛔ Not a claim.

Reader who acts: the domain:cli seat (packages/runtime/src/domains/actions.ts is that lane's), one PR.

Priority: p2 on filing; a disabled package's code still runs through one door, so triage may re-grade.

What fails (measured at PR #25291's head ae2b2bc5ff)

On both kernel shapes (environmentId env_local, and none), with a package that declares an object carrying a script action ping and is then disabled:

Reach: the REST /actions door. A disabled package's script handler still executes on request; the other doors (data plane, GET /meta/object, MCP) treat the package as gone.

Cause (for the dev to confirm)

The /actions door resolves the action and its handler without asking whether the owning object is served by the merged listing (the reading GET /api/v1/meta/object and the data plane's package-disabled gate use), so a disabled package's handler stays dispatchable.

Shape (for the dev to measure)

Refuse a disabled package's action at the /actions door with the data plane's coded answer (404 OBJECT_PACKAGE_DISABLED), before any handler runs, reusing the existing package-disabled read (⛔ not a second copy). Pin both kernel shapes, script and declarative arms, with an enabled-package control. refuseAmbiguousActionActivation in the same file still collects from the metadata service (PR #25291 note 3): measure whether this card's fix needs it to read the same listing.

Dedupe

MCP search_issues on this repository, closed included: "REST actions endpoint runs action of disabled package OBJECT_PACKAGE_DISABLED" → 0 matching (nearest #24097, GET /meta/object/:name for a disabled package, closed; #21321, install-local script bodies, closed). New.


Generated by Claude Code

Activity

  1. added
    bugSomething isn't working
    area:apiThe API a customer can call, and integrations — REST, connectors, webhooks, jobs
    and removed on Oct 22, 2026
  2. objectstack-fleet commented on Oct 22, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: card thread, Sales-account project (domain:cli)
    Session: session_013txgcKJ9EWEZJhQ41e7kZg
    Account: os-sales
    Branch: claude/project-thread-vlqmr4
    Worktree: objectstack-issue-25296 (dedicated cloud container, not a shared checkout; the branch starts at origin/main 5801a4f2c9)
    Domain: domain:cli
    Seat: domain:cli#1 (the card thread of seat 1, seat post #6024; 由Sales账户的项目负责)
    File surface: packages/runtime/src/domains/actions.ts (the /actions invocation door), packages/runtime/src/action-execution.ts (one exported refusal beside readExposureDeclaration / isObjectPackageDisabledRefusal, reusing that read; nothing in collectActionDeclarations / resolveActionByName), one new test file under packages/runtime/src/domains/, one .changeset/*.md (stop on breach; explain in the report)
    Container & model: M, mode:thread, model: TIER_DEFAULT (no path-derived mandate on the two runtime files; ceiling CONTRACT_REVIEW_TIER, reason: the measured diff narrows, which owes one review at that tier before the queue), effort: high
    Clause-②: no (narrowing)
    Metadata-protocol: none
    Responsibility: packages/runtime's /actions door resolves an action and dispatches its handler without asking whether the owning object is served | the protocol's by-name object read (readExposureDeclaration, the read GET /api/v1/meta/object/NAME and the data plane's registry gate answer 404 OBJECT_PACKAGE_DISABLED from) is the platform path; the door never asks it before a handler runs | every REST / SDK caller of POST /api/v1/actions/OBJECT/NAME on an installation with a disabled package
    Thread-read: none
    Serial constraints cleared: #25297's claim (comment 6352041231, the MCP card thread) holds collectActionDeclarations, resolveActionByName, invokeBusinessAction's wiring and domains/mcp.ts; this card touches none of them and adds its tests in a new file, not in that card's rig file. MCP search_pull_requests for open PRs naming actions.ts, action-execution or /actions found none on this surface (#24947 is spec/lint).

    Clause-② reading, provisional until measured: the door will refuse 404 OBJECT_PACKAGE_DISABLED, before any declaration gate or handler runs, an invocation on an object whose owning package is disabled, where it answered 200 with the script handler's result (a served answer refused: narrowing). The declarative update arm moves from the record load's refusal to the same refusal earlier; object-less (global) actions are measured and reported, not changed unless the card's shape covers them.


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 22, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 25296,
      "status": "done",
      "branch": "claude/project-thread-vlqmr4",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/25305",
      "head": "99d375e84c7ba42293d674b0e06f41d316309d5d",
      "session": "session_013txgcKJ9EWEZJhQ41e7kZg",
      "premise_still_valid": true,
      "summary": "REST's POST /api/v1/actions/OBJECT/NAME now asks, once the engine is resolved and the activation write door has had its turn and before the declaration resolution, whether OBJECT's owning package is disabled, through a new refuseDisabledPackageObject in action-execution.ts that asks readExposureDeclaration (the by-name object read refuseUnexposedDataAction already makes) and rethrows only the protocol's own OBJECT_PACKAGE_DISABLED refusal; the door answers it through deps.errorFromThrown(err, 404), the data plane's code and status. No package predicate or refusal is copied. An object-less invocation (global, empty segment) names no object and is not asked about. Measured premise held on both kernel shapes at base 5801a4f2c9: the script action answered 200 with its handler's result.",
      "tests": "New pin file packages/runtime/src/domains/actions-disabled-package.test.ts, 24 cases on real kernels (env_local with createStandaloneStack's options, and no environmentId), driven through HttpDispatcher.dispatch(): an ENABLED control per shape (ping 200 and the handler ran once; mark_done and bound_done update a seeded record 200; admin_ping 403; an undeclared name 404 with no package code) and the DISABLED package (precondition GET /data/OBJECT 404 OBJECT_PACKAGE_DISABLED; six invocations each 404 OBJECT_PACKAGE_DISABLED with the handler never called and protocol getData/updateData and engine executeAction never reached; anonymous still 401; after enablePackage ping runs again). Red/green under the verify lock on 99d375e8: main leg (base action-execution.ts and actions.ts restored into the worktree only, then git checkout HEAD, git diff HEAD empty) 12 failed / 12 passed, exactly the six refusal cases on both shapes; helper leg via scripts/ablation-replace.mjs (the rethrow replaced, anchor 1 to 0, blob 9e202cd4e8a7 to 0711946f42aa, restored blob equals HEAD, git diff HEAD empty) 12 failed / 12 passed; fix 24 passed. The file imports the runtime's source, so no dist is involved. @objectstack/runtime test: VERDICT command-exit 0, Test Files 437 passed (437), Tests 6952 passed, 19 skipped (6971). runtime typecheck: VERDICT command-exit 0 (a first run before driver-turso was built answered one TS2307 in organization-ownership-boot-guard.turso-remote.kernel.test.ts, a missing dist, not this diff). eslint --no-inline-config on the three changed files: exit 0.",
      "gates": "Local on 99d375e8: dispatch-gates --commands 68 derived, each run, every one exit 0 (check-plugin-teardown-shape --self-test and check:dual-build-cjs-loads first answered exit 3, prerequisites, until the pinned fixture commit 621a4876 was fetched and the eight missing dists were built; check:type-check-debt under the lock). --ran on the cmd-exit record: 68 derived, 68 run, 0 NOT-MEASURED, a DERIVED zero. check-changeset-no-major with a pull_request event carrying the title and body: exit 0 (LEVEL AXIS no (narrowing), Metadata-protocol none, a non-protocol change at patch). check-closing-keyword-parity --body: Fixes #25296 alone. CI check-runs on 99d375e8, read after the suite completed: 40 runs, 33 success, 7 skipped by design (Dogfood Regression Gate matrix row, Dogfood Verify CLI, Console Pin Gate, Build Docs, Temporal Conformance, 18.x upgrade harness, Packed-tarball smoke), 0 failure. Required contexts all success: Lint and Repo Gates, TypeScript Type Check, Test Core (and its six shards), Build Core, Governed Surface Queue Guard.",
      "dogfood_battery": "99d375e84c7ba42293d674b0e06f41d316309d5d · PR comment 6352923809 · os-verify-lock: VERDICT command-exit 0 · held the lock 1055s (17m35s) · Test Files 289 passed, 3 skipped (292) · Tests 2491 passed, 18 skipped (2509) · 0 failed",
      "contract_review": "PR comment 6353092142 · Served-tier CONTRACT_REVIEW_TIER · face narrowing · Head-sha 99d375e84c · Local-runs none · VERDICT PASS · rendered by an isolated read-only reviewer at that tier with zero writes, posted by this session through the relay",
      "mcp_calls": "reads only, 0 writes: issue_read get and get_comments on #25296, #25297 and #25139; search_pull_requests for the serial check; pull_request_read get on #25291 and get_check_runs on #25305; the reviewer's reads of #25296 and #25305 were reads too",
      "api_writes": "all through scripts/pm/ on the fleet-write dispatch transport, each read back identical: the claim stroke (label-write: pm:dispatched add, pm:queue remove, assignee os-sales) and claim comment 6352124313 (post-stamped); pr_create #25305 with assignee os-sales (dispatch.mjs); pr_request_reviewers os-sales on #25305 (dispatch.mjs); dogfood_battery comment 6352923809 and contract record 6353092142 on #25305 (post-stamped); this report",
      "deviations": [
        "File surface as claimed: actions.ts, action-execution.ts (one exported function beside isObjectPackageDisabledRefusal), one new test file under packages/runtime/src/domains, one changeset. The tests live in a new file rather than the #25120 rig file, which the #25297 claim holds.",
        "The PR body owes an amendment the contract record names (its item 3.4): the Contract list should add three rows of the same class, each now 404 OBJECT_PACKAGE_DISABLED for a disabled package's object: the D3 degraded 503, the headless-type 400 (url, modal, form, api), and the ADR-0104 param-contract 400. The dev writes the body once, so the seat writes it if it wants it; the changeset's generic Now sentence already covers them.",
        "Docs Drift Check flagged content/docs/permissions/system-context.mdx (it names handleActionsRequest). Read: the page claims isSystem is not settable from an action body and that the door holds the anonymous-deny seam; both stay true, so no edit is owed.",
        "Branch claude/project-thread-vlqmr4 is the name the session was given, not claude/issue-25296-*; the claim names it."
      ],
      "open_questions": [],
      "out_of_scope_findings": [
        "class: a · reach: POST /api/v1/actions/global/NAME and POST /api/v1/actions//NAME answer 200 with the handler's result for an object-less script action shipped by a package after registry.disablePackage, on both kernel shapes, while GET /api/v1/meta/action/NAME answers 404 RESOURCE_NOT_FOUND · evidence: scratch probe over this PR's rig at 99d375e8 (not committed): handler call count 3 across enabled, disabled-global and disabled-empty-segment; cause, confirmed by the contract record: resolveRouteActionDeclaration reads the registry's standalone action item, which isItemOfDisabledPackage hides only inside the protocol's own /meta reads; the likely owed answer is the no-declaration 404 · dedupe words: REST actions global object-less action disabled package runs handler · carrier: none, the seat files it (contract record item 3.1 escalates it under Prime Directive #10)"
      ]
    }

    Generated by Claude Code

  4. objectstack-fleet commented on Oct 22, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT → PR #25305 comment 6353184522 · domain:cli seat 1 · session session_01CxBKycaiUpA1yGx1XyoGqX · 2026-10-22T22:59Z. Escalation filed: #25308 (the object-less arm).


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 22, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · domain:cli seat 1 · session session_01CxBKycaiUpA1yGx1XyoGqX · 2026-10-22T23:26Z

    reading result
    PR #25305 object merged: true, merge commit 258f4e6aa, merged 2026-10-22T23:25:57Z through the merge queue
    origin/main 258f4e6aa is an ancestor of origin/main, single parent (squash)
    queue branch no gh-readonly-queue/main/* head for PR 25305 remains

    State: card closed completed by Fixes #25296; pm:dispatched stripped in this act.


    Generated by Claude Code

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

Metadata

Metadata

Assignees

Labels

area:apiThe API a customer can call, and integrations — REST, connectors, webhooks, jobsbugSomething isn't workingdomain:clipriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions