Skip to content

meta: GET /meta/object serves which packaged actions are switched off beside the item, and the disabled-action refusal reads as a plain sentence #27842

Closed

Description

@objectstack-fleet

director#1 · os-bill · session_01Utp6CbNFJEooRTBtezEt7

Filing gate: (a) a reachable defect, the serve half of #27504, split out by a maintainer ruling (③: the maintainer's word 「同意」, 2026-10-30T01:35Z, on the brief recommending this split; the ruling comment of record is 6512814276 on #27504, letter B). reach: the public metadata read GET /api/v1/meta/object/:name (and the GET /api/v1/meta/object list) on a deployment whose administrator switched a packaged action off in Setup › Packaged automation: the read serves the action in actions[] with nothing beside it saying it is off, while POST /api/v1/actions/... for the same action is refused 409 ACTION_DISABLED. Measured by the 18.3.0 release-candidate walkthrough on examples/app-showcase (#27504, showcase_mark_done on showcase_task, framework main @ c4c515ad). Reader who acts: the domain:spec seat (lane fixed by the ruling); triage grades the level. ⛔ Not a claim.

Unblocks: #27504 (the console half: hide the button from this key; stays domain:ui, seat 4).
Ruling-ref: #27504 (comment) (letter B).

What happens

  • A packaged action switched off in the sys_metadata_activation ledger (ADR-0126 §4, §8 item 2) is refused at both dispatch doors with the sentence describeDisabled() builds in packages/objectql/src/action-activation.ts:297-303: it names the ledger table and an ADR section, and is what an end user reads in a red toast.
  • The metadata reads that every client builds its action buttons from (GET /meta/object/:name, GET /meta/object) carry no activation fact at all. The only read of the fact is the generic data list of the ledger object (apiMethods: ['get','list'], packages/platform-objects/src/system/sys-metadata-activation.object.ts:192-197), which the Setup page joins client-side (ui/packages/app-shell/src/views/setup/packagedActions.ts). Every other consumer (the console record page, MCP agents, the SDK) sees the action as live.
  • Removing the action from the served actions[] is not an option (the Setup page lists from it to offer the re-enable switch); rewriting visible / disabled inside the item rides the GET → edit → PUT round trip back into the stored body.

Wanted

The #23316 shape (registration, PR #23358), as the action twin:

  1. Item read, both doors. A key beside item on GetMetaItemResponseSchema and on GetMetaItemCachedResponseSchema (packages/spec/src/api/protocol.zod.ts, the registration members at L682 and L2318–2331 are the template) naming the packaged actions of this object that are switched off for this deployment. Published by the cached default door too; never part of the ETag, so a read that carries it is never answered 304 (the automation: a stored flow the engine refuses at cold boot is withdrawn with a warn, while the metadata read keeps serving it as status: 'active' — after the v18 upgrade, every refused flow reads as running #23316 trade, stated in the docblock). Present only when a process with an activation ledger answered; absent means "no ledger answered", never "nothing is switched off", so a consumer that sees no key keeps today's behaviour.
  2. List. A name-keyed sibling of items on the object list, the registrations pattern (L326).
  3. The read seam. The metadata protocol reaches the engine's action-activation projection through the kernel service table, the way getFlowRegistration? was declared optional on IAutomationService in @objectstack/spec/contracts (PR fix(automation,metadata-protocol,rest,spec): a stored flow the engine refuses is served beside its verdict, not as running #23358 "The seam"). Which contract carries the member (the ObjectQL / engine contract, where ActionActivation lives) is this card's measurement; metadata-protocol imports nothing from objectql.
  4. The plain sentence. describeDisabled() rewritten for the person who clicked: no tracker number, no system table, no ADR citation (AGENTS.md's runtime-string rule, "the lesson goes into the text"); for example "This action is turned off for this deployment. An administrator can turn it on again under Setup › Packaged automation, or you can use another action." Both dispatch doors keep producing it from the one place; the existing refusal-sentence pins move with it.
  5. Pins and an ablation. A switched-off action appears in the key and item.actions is byte-identical; no key when no ledger is attached; a cached read that carries the key is not answered 304 and the unjudged control still is; the list is keyed by object name; the sentence pins; one ablation on the serve path.
  6. Consumer-package tests (a spec-lane card's standing commitment): metadata-protocol, rest, objectql, runtime; the six regenerated spec artifacts; changeset (@objectstack/spec minor, metadata-protocol / rest / objectql patch); Clause-②: yes (widening) ⇒ CONTRACT_REVIEW_TIER review before queueing.

The exact key name (disabledActions is the triage route's literal spelling), and whether an empty array is served or the key omitted when the ledger holds no row for the object, are the seat's measurement and its contract review, not fixed here.

Dedupe

MCP search_issues on this repo, closed included: packaged action switched off activation state served with action metadata meta object disabledActions hide button → #27504 (the console half, parent of this split), #23316 (the flow twin, closed by PR #23358), #12348 (the activation write door, closed). None is this serve half.

Dedupe words: packaged action activation beside item; disabled actions envelope key meta object; action disabled refusal plain sentence.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: 审批与自动化 | none | P②

    Triage: p1 · domain:spec · area:automation · 2026-10-30T01:54Z

    ⛔ Not a claim.


    Generated by Claude Code

  2. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#4 · marchtian · session_017ihL2fi9zfJhUTubyJYb6V

    Claim: PM loop round 3 · 2026-10-30T03:37Z
    Session: session_017ihL2fi9zfJhUTubyJYb6V
    Account: marchtian
    Branch: claude/issue-27842-disabled-actions-beside-item
    Worktree: objectstack-issue-27842
    Domain: domain:spec
    Seat: domain:spec#4
    Ruling-ref: maintainer ruling 6512814276 on #27504 (letter B, the serve half to domain:spec); triage 6513025554 ("It is Clause-②: yes: the maintainer approves the key in the PR, and a contract review is owed." "⛔ The served actions[] and the stored item body stay as they are … no visible / disabled rewrite." "The disabled-action sentence becomes a plain sentence for the end user, with the code and the ADR reference kept for the log.")
    File surface: packages/spec/src/api/protocol.zod.ts (a key beside item on GetMetaItemResponseSchema / GetMetaItemCachedResponseSchema, a name-keyed sibling of items on the list, after the registration / registrations template at L326, L682, L2318–2331 on 88d60203), one optional read member on the engine-side contract in packages/spec/src/contracts/** (the getFlowRegistration? seam shape), packages/metadata-protocol/src/** (serve beside the item on both doors, never in the ETag), packages/objectql/src/action-activation.ts (describeDisabled() at L298 as a plain sentence; the projection the seam reads), the dispatch doors' refusal pins in packages/rest / packages/runtime as they move, tests in those four packages, regenerated spec artefacts, changesets (@objectstack/spec minor; metadata-protocol / rest / objectql patch). ⛔ no change to served actions[] or the stored item body (stop on breach; explain in the report)
    Container & model: M, mode:subagent, model: TIER_DEFAULT (opus) — the quota-exhaustion exemption (claude-fable-5-1 answered HTTP 429; maintainer 「你没有fable了,使用 opus开发完之后等契约复审」), effort: high
    Clause-②: yes (widening)
    Metadata-protocol: added
    Responsibility: the metadata reads every client builds action buttons from (GET /api/v1/meta/object[/:name]) carry no activation fact, while dispatch refuses a switched-off packaged action 409 ACTION_DISABLED with a sentence naming a system table and an ADR | the #23316 registration-beside-the-item shape (PR #23358) is the path, as the action twin | every console, SDK and MCP consumer on a deployment where an administrator switched a packaged action off (measured on examples/app-showcase, #27504)
    Thread-read: 6513025554
    Premise: holds — on 88d60203 protocol.zod.ts carries registration beside the item (L682, cached door L2326) and registrations on the list (L326) and no activation key; describeDisabled() is at packages/objectql/src/action-activation.ts:298; the seam template getFlowRegistration? is at packages/spec/src/contracts/automation-service.ts:1381
    Serial constraints cleared: draft PR #27713 (#27627) touches packages/spec/src/api/index.ts and adds record-page.zod.ts, so the two PRs share the api barrel and the generated api-surface; whichever lands second merges origin/main and regenerates (scripts/pm/os-regen-merge.sh). No open PR touches protocol.zod.ts, action-activation.ts or the metadata-protocol serve path (open PR file lists read just before this claim)

  3. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#4 · marchtian · session_017ihL2fi9zfJhUTubyJYb6V
    os-dev-report

    {
     "issue": 27842,
     "status": "done",
     "branch": "claude/issue-27842-disabled-actions-beside-item",
     "pr": "https://github.com/objectstack-ai/objectstack/pull/27964",
     "head": "7237921e365096628921e03d89f7bc18d3cb9d85",
     "session": "session_017ihL2fi9zfJhUTubyJYb6V",
     "premise_still_valid": true,
     "summary": "GET /meta/object/:name (protocol door and the cached default REST door) and GET /meta/object serve `disabledActions` beside the item: string[] on the item reads, Record<objectName,string[]> on the list. It is read through the `objectql` service slot for the new optional IObjectQLEngine.getDisabledActions (metadata-protocol imports no objectql). The key is absent when no ledger answered and [] when a ledger answered with nothing off, following `registration`. It is never in the ETag, and a read that carries it is never 304. item.actions is untouched. The ACTION_DISABLED 409 now carries a plain end-user sentence; the code, table and ADR-0126 §8 move to an info log line written in ObjectQL.describeDisabledAction. Key name `disabledActions` awaits the maintainer's approval in the PR (Clause-② yes).",
     "key_name": "disabledActions",
     "empty_vs_absent": "absent = no ledger answered (no objectql service, engine without getDisabledActions, or getDisabledActions() === undefined because no store is attached); [] = a ledger answered and none of this object's actions is off. Measured on `registration`: every served flow gets a verdict once the engine answers, and the list has one entry per listed non-draft item; absence is reserved for 'no engine declares the member'.",
     "tests": "Full suites on the final head, exit codes recorded: spec typecheck 0 / test 0 (756 files, 22483 passed); metadata-protocol 0 / 0 (21854 passed); objectql 0 / 0 (493 files, 9587 passed); rest 0 / 0 (350 files, 6759 passed); runtime test 0 (481 files, 7837 passed), runtime typecheck 1 then 0 (first run TS2307 in organization-ownership-boot-guard.turso-remote.kernel.test.ts, not in the diff: no local driver-turso dist; rerun 0 after building it). Ablation: the item-read spread in metadata-protocol/src/protocol.ts was replaced via ablation-replace and src/protocol.object-disabled-actions.test.ts gave 5 failed / 6 passed (item read and cached cases red, absence controls and list green); restore proven (blob == HEAD, git diff HEAD empty).",
     "gates": "dispatch-gates --commands on the final head 7237921e36: 119 commands, each exit code recorded before any pipe. --ran: '119 derived, 119 run, 0 NOT-MEASURED, 0 UNRUN' (exit 0). First pass: check:skill-examples exit 3 and check:dual-build-cjs-loads exit 3 (PREREQUISITE: missing dist) became 0 after a full package build. check:engine-double-contract exit 1 (RETAINED: the new test's pinned findOne double was not in the ledger) became 0 after --write, which added that single entry, committed as 7237921e36. That commit derived 8 more scripts gates, all exit 0. CI check-runs on 7237921e36 at report time: 9 success, 7 skipped, 18 in progress, 0 failed (not final).",
     "line_budget": "no budget set by the order; diff +1127/-45 across 23 files (dispatch-gates: 1167 changed lines vs the human-merge threshold 3000: under)",
     "files_changed": [
      ".changeset/27842-disabled-actions-beside-item.md +10/-0",
      ".changeset/27842-disabled-actions-served.md +15/-0",
      "content/docs/references/api/protocol.mdx +3/-0",
      "docs/qa/platform-checklist/areas/api-backend.json +9/-3",
      "packages/metadata-protocol/src/protocol-action-activation-reads.ts +102/-0",
      "packages/metadata-protocol/src/protocol.object-disabled-actions.test.ts +244/-0",
      "packages/metadata-protocol/src/protocol.ts +66/-2",
      "packages/objectql/src/action-activation.test.ts +52/-5",
      "packages/objectql/src/action-activation.ts +20/-8",
      "packages/objectql/src/engine.ts +26/-1",
      "packages/objectql/src/protocol-meta-disabled-actions.test.ts +217/-0",
      "packages/qa/dogfood/test/packaged-action-disabled-dispatch-live.dogfood.test.ts +15/-5",
      "packages/qa/dogfood/test/packaged-activation-ledger-reach.dogfood.test.ts +3/-1",
      "packages/rest/src/meta-item-read-routes.ts +18/-3",
      "packages/rest/src/meta-object-cached-disabled-actions.test.ts +131/-0",
      "packages/runtime/src/action-execution.ts +4/-2",
      "packages/runtime/src/domains/action-activation-dispatch.test.ts +30/-12",
      "packages/runtime/src/domains/api-action-forward.test.ts +3/-3",
      "packages/spec/authorable-surface/api.json +3/-0",
      "packages/spec/src/api/meta-item-response-shapes.test.ts +59/-0",
      "packages/spec/src/api/protocol.zod.ts +68/-0",
      "packages/spec/src/contracts/objectql-engine.ts +24/-0",
      "scripts/engine-double-contract.pinned.json +5/-0"
     ],
     "deviations": [
      "The log line (ACTION_DISABLED, action name, sys_metadata_activation, ADR-0126 §8 item 2) is written by ObjectQL.describeDisabledAction rather than by the dispatch domains: HttpDispatcher's deps.logger is not wired, and that method is the one call both doors make on every refusal.",
      "No Fable or other independent review was run, per the order's exception; the PR waits for the seat's contract-review hand-off.",
      "The PR body ends with the order's footer lines and carries no separate '_Generated by …/session_…_' line.",
      "The two dogfood test files edited for the pin sweep were not run locally (they boot example apps; CI's Dogfood gate runs on main after the merge).",
      "scripts/engine-double-contract.pinned.json is in the diff: one ledger entry the gate requires for the new test's findOne double."
     ],
     "pins_flipped": [
      "packages/objectql/src/action-activation.test.ts — the sentence pin (exact plain text, no table/ADR) and the engine pin (equals the projection)",
      "packages/runtime/src/domains/action-activation-dispatch.test.ts — the double now calls ActionActivationProjection.describeDisabled; REST 409 sentence test; MCP door sentence assertion; new fallback test",
      "packages/runtime/src/domains/api-action-forward.test.ts — the double now calls the projection",
      "packages/qa/dogfood/test/packaged-action-disabled-dispatch-live.dogfood.test.ts — expectDisabledSentence helper",
      "packages/qa/dogfood/test/packaged-activation-ledger-reach.dogfood.test.ts — /ACTION_DISABLED|is disabled/ became the code",
      "docs/qa/platform-checklist/areas/api-backend.json — api-backend.packaged-action-disabled-dispatch acceptance[0], revision 9→10 with a history entry"
     ],
     "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm",
     "mcp_calls": "0",
     "api_writes": "2 — relay pr_create (fleet-write dispatch run 41008560946 → POST /repos/objectstack-ai/objectstack/pulls, #27964, draft, no assignees/reviewers/labels), and this os-dev-report comment (POST /repos/objectstack-ai/objectstack/issues/27842/comments via post-stamped). git push is not a REST write.",
     "open_questions": [],
     "out_of_scope_findings": [
      "carrier: seat (domain:spec#4) · noted, not filed · class: none (doc drift, observation) · evidence: docs/qa/platform-checklist/areas/platform-core.json ledger posture note says 'the data-API read IS the only \"what is off here\" surface today'; after #27964 GET /meta/object also answers it · dedupe: platform-core checklist, what is off here, activation ledger surface",
      "carrier: seat (domain:spec#4) · noted, not filed · class: a candidate (misleading end-user copy) · reach: NOT measured, read-only inference · evidence: packages/services/service-automation/src/subflow-guards.ts:50 describeDisabledFlow names sys_metadata_activation and ADR-0126 §7.2 in the FLOW_DISABLED refusal; the automation checklist (negative[3]) deliberately keys on that message · dedupe: FLOW_DISABLED, describeDisabledFlow, plain sentence, flow ledger refusal",
      "carrier: seat contract review on #27964 · noted, not filed · class: none (design trade the card fixes) · evidence: with a ledger attached (every PlatformObjectsPlugin boot), every cached GET /meta/object/:name answers 200, not 304; alternative: fold the switched-off names into the REST validator fingerprint as visibility, runtime-view and audience are folded · dedupe: disabledActions 304, meta object etag, cached door revalidation",
      "carrier: none · noted, not filed · class: none (observation) · evidence: HttpDispatcher domain deps logger appears unwired ((this as any).logger), so domain log lines fall back to console · dedupe: HttpDispatcher logger, deps.logger"
     ]
    }

    Generated by Claude Code

  4. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#4 · marchtian · session_017ihL2fi9zfJhUTubyJYb6V

    Landed · 2026-10-30T10:55Z · PR #27964 merged by the queue at 2026-10-30T10:54Z as 3e0fd7a8f7; the card closed by Fixes. This seat strips pm:dispatched in the same act. Before landing, the maintainer approved the key name and the 304 cost (PR comment 6520565524). The follow-ups are filed: #28044 brings 304s back on object reads by folding the switched-off names into the ETag, and #27966 gives the flow twin's FLOW_DISABLED sentence the same plain shape. The console still has to read disabledActions before buttons hide; that is the UI consumer's work, not this card's.

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