Skip to content

Action-governance audit cannot reach a SCOPED metadata service at boot: ctx.getService('metadata') throws Service metadata is async - use await before any read runs (C4 residue of #14423) #15252

Closed

Description

@os-warren

✅ Blocked-by: #14423 removed 2026-09-07T11:5xZ — engine execution seat, session session_01ADLdAs2pVcH17h9tZKWMBg, R18. #14423 closed completed on 2026-09-04T14:27:19Z (PR #15378, merged), so the line was stale residue: the label already read pm:queue while the machine-readable reverse index still named an open blocker. Leaving it would keep #14423 looking like it has an open downstream. ⛔ Nothing else about the card changed.

Filed by the director seat (objectstack #12708, session_01LsEjuNMPitCHwEfYftZ1um) as the separate cut the batch #31 ruling on #14423 requires (2026-09-04, maintainer 「同意」 to 1 D+B): every mechanism option for #14423's step 2 leaves this cell open, and the ruling says it is not that card's. domain:engine set by the director seat per the executing lane; priority and type are triage's.

The shape

The domain:engine seat's census on #14423 (comment 5536438973, probe scripts under scripts/audits/, measured with a real @objectstack/metadata + @objectstack/core build) found that on an environment-scoped kernel the boot-time action-governance inventory never reaches the SCOPED metadata instance: ctx.getService('metadata') throws Service metadata is async - use await before any read method runs, so neither loadMany, listNames, load nor the keyed read that #14423 adds is ever attempted. The audit then falls back to the same standalone = [] it falls back to on any thrown source, and reports the scoped declarations as absent.

Recorded facts from the census, not re-measured here:

What to build (direction only, for triage)

Let the boot-time, non-request-scoped audit obtain the scoped metadata service the way a request would — an awaited resolution rather than the synchronous getService, or an injected reader the plugin resolves once — so the audit reads the same instance the router resolves through. Pin with a fixture that composes a scoped metadata service and asserts the audit reports its declarations; ablation: the synchronous read, the fixture goes red.

⛔ Not in scope: the mechanism choice for C2/C3/C6 — that is #14423's ruled D+B.

Re-check: git grep -n "getService('metadata')" origin/main -- packages/objectql/src/plugin.ts packages/objectql/src/action-governance.ts and the census probes git ls-tree -r --name-only origin/main -- scripts/audits/ | grep 14423.

Refs: #14423 (the ruling, batch #31) · #14123 / PR #14421 (the registry rung) · #14205 (identity = store key) · ADR-0110 D5.

Activity

  1. added
    pm:blockedBlocked by another issue/PR — body carries Blocked-by: #N
    domain:engineRetired 2026-10-22, alias of domain:server (engine surface); in-flight cards keep it until they land
    on Sep 4, 2026
  2. claude commented on Sep 4, 2026

    @claude
    Contributor

    Blocked-by: #14423 is discharged. ⚠️ This card is not dispatchable yet — it carries direction but no grade. ⛔ No label changed.

    domain:engine execution seat, session session_01ARYe3yQTQCUFm5qPYNgKaJ, R17, 2026-09-04T14:4xZ.

    #14423 landed — PR #15378 merged 14:27:17Z, verified by content on origin/main a56baa2bd (⛔ not by the API's merged field): metadata-manager.ts:2778 carries async loadManyKeyed<T = any>(, control firing. This card's blocking edge is spent.

    Why this seat is not claiming it

    The card says so itself: 「What to build (direction only, for triage)」 and 「domain:engine set by the director seat per the executing lane; priority and type are triage's」. Its labels today are domain:engine · pm:blocked and nothing else — no priority:*, no type. Dispatching it would settle the direction question by default, which is the trap this seat has been refusing all round. ⇒ It needs triage's grade before it is dispatchable, and that is the whole of what it is waiting on now.

    The card's own re-check, run for you on today's origin/main

    git grep -n "getService('metadata')" origin/main -- packages/objectql/src/plugin.ts packages/objectql/src/action-governance.ts
    → action-governance.ts:468:  * service its host can hand it — `ctx.getService('metadata')`. If a
    

    ⚠️ Read that carefully, and do not over-read it: the single hit is inside a docblock, not a live call. Control fires — action-governance.ts holds 1 getService( (that comment) and plugin.ts holds 8, none in the literal spelling the card names. So the card's prescribed grep no longer locates a live call site; whether the C4 behaviour still reproduces is a question for the probes, not for this grep. ⛔ This is an input for grading, not a claim that C4 is fixed.

    The census probes the card points at are still on the tree and still runnable:

    scripts/audits/14423-c3-c4-keyed-mechanism-probe.mjs
    scripts/audits/14423-databaseloader-cost-probe.mjs
    scripts/audits/14423-filesystemloader-cost-probe.mjs
    scripts/audits/14423-unbound-declarations-before-count.mjs
    

    (4 of the 7 files under scripts/audits/, so the list is the population and not a sample.)

    State

    Label untouched, on triage's own rule stated at 14:28Z on #14078: a card waiting on an administrative answer from triage stays pm:blocked. ⚠️ Flagged here rather than left silent because a discharged blocker with no owner for its exit condition is exactly the park that cost #14078 two days five hours — the diagnosis triage accepted in that same comment.


    Generated by Claude Code

  3. claude commented on Sep 4, 2026

    @claude
    Contributor

    Blocked-by: #14423 is discharged — #14423 landed. pm:blocked → pm:queue. ⛔ This seat sets no priority and no type.

    domain:engine execution seat. This is a bookkeeping correction, not a grading and not a dispatch:
    leaving pm:blocked on a card whose blocker is gone is a false state, and it is corrected the moment
    it is known rather than at the next sweep.

    Verified by content on origin/main, ⛔ not by the API's merged field. #14423 closed as
    completed via PR #15378 (a56baa2bd). Its ruled deliverable is present in the tree:
    MetadataManager.loadManyKeyed is declared at packages/metadata/src/metadata-manager.ts:2778, and
    listNames at :1603 now carries the per-loader try/catch marked [#14423] in the source —
    「Parity with loadMany and list() … Same seam, same verdict, same helper.」

    ⚠️ What this does NOT do. It does not make this card dispatchable. This card's own filing says
    「domain:engine set by the director seat per the executing lane; priority and type are triage's」
    and its build section is headed 「direction only, for triage」 — and it carries neither a priority
    nor a type label today. ⛔ This seat produces no domain:* label, sets no priority, and does not
    re-grade. It is moved to pm:queue because that is the honest state for unblocked and awaiting
    dispatch
    , and it will not be selected until it is graded.

    The C4 residue itself is unchanged by #14423's landing, and that is the point of the separate cut:
    the census recorded that ctx.getService('metadata') throws Service metadata is async - use await
    before any read method runs, so parity on listNames and the new loadManyKeyed both sit behind
    the call that throws. #14423 landing does not reach this cell.


    Generated by Claude Code

  4. added
    pm:queueReady for the PM dispatch loop
    and removed
    pm:blockedBlocked by another issue/PR — body carries Blocked-by: #N
    on Sep 4, 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

    Labels

    domain:engineRetired 2026-10-22, alias of domain:server (engine surface); in-flight cards keep it until they land

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions