Skip to content

MetadataManager.loadManyKeyed lands as a public member with no IMetadataService declaration — its two siblings loadMany? and loadDiagnosed? are declared, and the call site narrows with a local structural type instead #15385

Description

@claude

Follow-up filed by the domain:engine execution seat as the recorded discharge of an open question the #14423 dev raised and correctly refused to answer itself (PR #15378 report; seat answer 5541301933, Q2 = B). ⛔ Nothing is being asked of the engine lane here — this card exists because the surface belongs to another lane and the decision is theirs.

Blocked-by: #14423

What lands, and what does not

PR #15378 (card #14423, ruled D+B by 总监批 #31, comment 5537057614, maintainer verbatim 「同意」) adds a new public member MetadataManager.loadManyKeyed(type) to packages/metadata. The ruling names that landing site explicitly — 「MetadataManager.loadManyKeyed(type) beside loadMany」 — and its enumerated scope for the engine seat does not include packages/spec.

So the member ships undeclared on the contract its two siblings are declared on.

Measured on origin/main @ 638ea042d

IMetadataService is packages/spec/src/contracts/metadata-service.ts:216. Its plural-read family:

member declared? where
loadMany?<T = unknown>(type, options?): Promise<T[]> :675
loadDiagnosed?<T = unknown>(…) :861
loadManyKeyed absent from every file under packages/spec/src/

Negative control fires: the same sweep over packages/spec/src/** returns 13 hits for the two sibling names across 3 files, so the zero for loadManyKeyed is a real absence and not a broken pattern.

This is a position the same interface has been in before, and it was resolved by declaring. loadDiagnosed's own docblock at :832 records it: [#4127 batch 4] Declared alongside {@link loadDiagnosed}, which the same …. The #14423 dev spotted the parallel unprompted and named it in its report.

What the PR does instead, and why that is the right terminal state for the engine lane

The dev hit the lane wall and neither crossed it nor stopped. packages/objectql/src/plugin.ts declares a local structural type beside the single call site, so the lookup stays typed (⛔ not anycheck:slot-lookup stays green), and its docblock names the remedy for whoever takes this card:

packages/spec is a contract surface owned by another lane, and widening it is its own decision with its own review. … the same remedy applies when that lane takes it: delete this and read the contract.

That is a correct terminal state, not a placeholder that rots — but it does mean a published member the contract does not mention, which is the thing worth a card.

Why the engine seat did not fold this into #14423's contract review

The #14423 dev's own option A was to let the Clause-② review that PR already carries cover the declaration too, "since that review is looking at this exact surface anyway". The seat ruled B on three grounds, recorded in full at 5541301933:

  1. The operative ruling enumerates the engine seat's scope and IMetadataService is not in it.
  2. A contract reviewer's PASS on that PR is a review of that diff, not a lane authorization. The reviewer would be approving a widening of packages/spec that the owning lane never saw. Review tier and lane ownership are different permissions; the first does not confer the second.
  3. Seat precedent is to request a pre-authorisation, not assume one — objectql: enforce Field.valueDomain on the write path — refuse a non-member text value with value_domain, add the two authoring-form rows, flip the liveness row (the engine half of #14168) #15161 shipped against a three-file pre-auth the spec seat granted in advance, and a fourth path was reported to that seat as a deviation rather than absorbed (#6017 comment 5539211563).

For triage to weigh — ⛔ not pre-empted here

The shape is not obvious and this seat is deliberately not picking it:

  1. Declare it, loadManyKeyed?<T = unknown>(type: string, options?: Record<string, unknown>): Promise<Array<{ name: string; data: T }>>, alongside its two siblings, and delete the local type in plugin.ts. This is what dispatcher 多个 domain 调用契约里没有的方法 —— #4087 的同类,只是方向相反(契约缺声明,不是调用点乱编) #4127 batch 4 did for loadDiagnosed.
  2. Leave it undeclared on purpose, on the reading that loadManyKeyed is an implementation detail of the action-governance audit rather than a service capability any consumer should reach for — in which case the local structural type is the intended shape and this card closes with one sentence saying so.

⚠️ One input that bears on the choice and is easy to miss: the name loadManyKeyed and its MetadataKeyedItem return type are already published on MetadataLoader. What is new in #15378 is the member on MetadataManager, not the vocabulary — so option 2 is not as strained as it would be for a wholly novel name.

Also note

⚠️ content/docs/kernel/contracts/metadata-service.mdx is not stale today — the engine seat measured it and posted the reading on PR #15378 (5541174192). It is not stale because the dev stopped at the wall. If option 1 is taken, that page has to move with the declaration, and this is the sentence that says so.

⚠️ Timing, so nobody waits: the domain:spec seat (os-justin) posted at 2026-09-04T13:16Z that it takes no new dispatches this shift (maintainer 「当前任务处理完,合并了就下班」). This is very likely a card for the next spec seat.

⛔ No domain:* label applied — that label has a single producer and it is triage.


Generated by Claude Code

Activity

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