Skip to content

Packaged-action disable is unavailable without the automation service — sys_metadata_activation has only one registrant #12359

Description

@claude

Measured on a real boot while root-causing the #7526 parity failure on PR #12348 (booted showcase stack, bootStack(showcaseStack), authenticated as the dev admin):

POST /api/v1/actions/_activation/showcase_task/showcase_mark_done  {"enabled": false}
  -> 503 SERVICE_UNAVAILABLE
     "Cannot disable packaged action 'showcase_mark_done' — no activation ledger is attached to this
      engine (sys_metadata_activation, ADR-0126 §4), so the flip could not be made durable and would
      silently revert on the next restart."

The refusal itself is the DESIGNED behaviour and is working: ADR-0126 §6 wall 3 says a flip that cannot be made durable must not be reported as one, so the door refuses loudly and names the remedy instead of keeping an in-process bit that reverts on restart.

The gap

sys_metadata_activation is declared in packages/platform-objects, but the only thing that REGISTERS it today is the automation service plugin's manifest (registerRunObject, alongside sys_automation_run and sys_flow_dispatch) — because flows were the ledger's first and, until #12348, only consumer. Actions are now a second consumer with a different owner: the consult and the write path live on the ObjectQL engine, which is present in every composition that can execute an action, automation service or not.

So in a deployment that has actions and no automation service, packaged-action disable is unavailable — visibly (503 on the flip, a warn at boot naming the same cause), never silently, but unavailable.

Why it was not fixed inside #12348

Where the shared object gets registered is a decision that reaches beyond the action leg:

  • registering it from ObjectQLPlugin adds an @objectstack/objectql -> @objectstack/platform-objects dependency, which inverts the tiering (platform-objects is a catalog the engine serves);
  • registering it from PlatformObjectsPlugin — where the object is declared, beside SysMigration / SysMigrationJournal / SysSecret — is the natural home, but it would then be registered by two manifests in any deployment that also runs automation, and object ownership is governed (ADR-0029 D7 contributor kinds). Whether that double registration is benign was not measured;
  • doing nothing is defensible for now: most real deployments run automation, and the failure mode is loud.

That is a judgement about the ledger's ownership shared by the flow leg and every future Regime C consumer (ADR-0126 §8 pre-charts tool, skill, position), so it is filed rather than decided inside an implementation card.

Reproducing

packages/qa/dogfood boots exactly this composition. bootStack(showcaseStack) + a POST to the activation door reproduces the 503 in about 25 seconds.

Refs: PR #12348 · #12160 · #12296 (the flow leg that registers the object today) · ADR-0126 §4/§6 · ADR-0029 D7


Generated by Claude Code

Activity

  1. os-support-ai commented on Aug 26, 2026

    @os-support-ai
    Collaborator

    Maintainer ruling recorded (2026-08-26, live PM chat, session session_01KWRU3s15AJz7PGW7a7wdCh). The decision was presented as three options with four-axis analysis; the maintainer ruled, verbatim: 「同意」 — to the recommended package:

    1. Option B: registration follows the declaration — sys_metadata_activation registration moves (not: is added a second time) from the automation service's manifest to PlatformObjectsPlugin, beside SysMigration/SysSecret. Single owner; every composition that carries platform-objects gets the ledger, so action disable works without the automation service, and every future Regime C consumer (tool, skill, …) inherits the fix for free.
    2. Bundling: this fix, Two implementations of the ADR-0126 §4 activation-ledger row contract (flow + action) — consolidate onto one #12350 (consolidate the two row-contract implementations) and Ledger convergence: registration home + one store implementation + permission-set convergence (ADR-0126 §4/§8, maintainer-ruled bundle) #12159 (L8 permission-set convergence) are one "ledger convergence" card — Ledger convergence: registration home + one store implementation + permission-set convergence (ADR-0126 §4/§8, maintainer-ruled bundle) #12159 is being rewritten as that card and this issue will be closed by its PR.

    Scope boundary this ruling does NOT decide: where the shared store code lives (a module-import question, #12350's analysis names @objectstack/core as the likely home) is independent of where registration lives (a composition/boot question, ruled here) — the convergence card carries both, each on its own grounds.

    Label needs-user-decision removed; work chartered on #12159.


    Generated by Claude Code

  2. added a commit that references this issue on Oct 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions