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

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. 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

  2. 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

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

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions