Skip to content

Six independent enumerations of the stack-collection set, none answerable to stack.zod.ts — one is mis-aimed and two still list retired kinds #6242

Description

@hotlong

Found while running the read-only two-repo coverage audit for #6234 / #2657. Not fixed there (audit card, no code PR). Filed unassigned.

All line numbers are origin/main @ 8e2bbba24f76d56daad166b6b776c69d8c3ac0dc.

The shape

ObjectStackDefinitionSchema (packages/spec/src/stack.zod.ts) is the source of truth for which collections a stack may declare. Six other places re-enumerate that same set, each hand-maintained, and nothing compares any of them to the schema or to each other. They have drifted independently:

# enumeration site observed drift
1 ObjectStackDefinitionSchema packages/spec/src/stack.zod.ts — (the source of truth)
2 PLURAL_TO_SINGULAR / MAP_SUPPORTED_FIELDS packages/spec/src/shared/metadata-collection.zod.ts:80, :110 carries ragPipelinesrag_pipeline; stack.zod.ts declares no ragPipelines
3 metadataArrayKeys (generic registration) packages/objectql/src/engine.ts:2283, duplicated at :2459 lists workflows, approvals, roles, profiles, policies, ragPipelines — none of which stack.zod.ts declares (ADR-0019 / ADR-0020 / ADR-0088 / ADR-0090 retirements)
4 ARTIFACT_FIELD_TO_TYPE packages/metadata/src/plugin.ts:60 see "the concrete part" below
5 MetadataCategoryEnum packages/spec/src/kernel/package-artifact.zod.ts:49 lists retired triggers and workflows; omits ~12 live collections (hooks, mappings, docs, books, jobs, positions, sharingRules, webhooks, connectors, emailTemplates, datasources, capabilities)
6 STACK_COLLECTION_COVERAGE examples/app-showcase/src/coverage.ts:181 tracks 3 of ~9 non-kind collections, and — unlike its sibling KIND_COVERAGE — is not ratcheted against anything

The concrete part — ARTIFACT_FIELD_TO_TYPE

Two distinct problems in packages/metadata/src/plugin.ts:60-93:

(a) data: 'dataset' is mis-aimed. The stack key data: is the seed collection (stack.zod.ts:510z.array(SeedSchema); the runtime reads it as seeds at packages/runtime/src/app-plugin.ts:927). It is mapped here to 'dataset', which since ADR-0021 is the analytics semantic layer kind — the exact collision the registry entry warns about in prose (metadata-plugin.zod.ts:620: "NOTE: distinct from the (analytics-bound) dataset name").

Honest scoping: this entry is provably inert today, not a live mis-registration. SeedSchema is a strictObject with no name key (packages/spec/src/data/seed.zod.ts:33), and the ingest loop skips any item without one (plugin.ts:667-674, if (!name) continue;) — the file's own comment at :718 says so: "seeds under data have no name". So it is a dead entry aimed at the wrong kind, which would begin mis-registering the day either side moves.

(b) Five live collections are absent from the mapdatasets, jobs, datasources, translations, capabilities. This is exactly the regression class that packages/metadata/src/plugin.test.ts:114-121 pins for docs:

a compiled artifact carries package docs in a top-level docs: DocSchema[] array. The artifact loader registers only the metadata fields enumerated in ARTIFACT_FIELD_TO_TYPE; docs was omitted, so the bundle's docs were silently dropped and GET /meta/doc returned an empty list even though the package shipped docs.

For four of the five, AppPlugin handles the functional consumption directly off the bundle (app-plugin.ts:503 datasources, :825 jobs, :927 seeds, :1421 translations), so this is not a boot breakage — the gap is that they never register as metadata items, so under bootstrap: 'artifact-only' (edge / serverless / immutable-image, metadata-plugin.zod.ts:505-511) GET /meta/job, /meta/translation, /meta/datasource and /meta/dataset would answer empty for a package that ships them. datasets has no AppPlugin handling at all in that path. Not measured on a real artifact-only boot — that verification is part of the fix, not of this filing.

Why file it as one issue

Each row above looks like a one-line typo in isolation, and each has been fixed one-line-at-a-time before (docs in ARTIFACT_FIELD_TO_TYPE, rolespositions in the same map, capabilities in metadataArrayKeys — every one of those carries a "this key was missing and it silently dropped X" comment today). The cause is structural: KIND_COVERAGE is answerable to DEFAULT_METADATA_TYPE_REGISTRY and fails CI when a kind is added without an entry (examples/app-showcase/test/coverage.test.ts:96-104), and the liveness ledger is answerable to the same registry (packages/spec/scripts/liveness/check-liveness.mts:145-153). The collection-key maps have no such gate. A check that compares each of these six against stack.zod.ts — declared-here-not-there and there-not-here, with an explicit waiver list for the deliberate omissions (views has no name, data seeds key by object, translations is a record) — would have caught all of the above and every future instance.

Relevance to in-flight work

Directly relevant to #2657: promoting any declared collection to a registered metadata kind means hand-editing several of these maps, with no gate to catch a miss. PR #5312 (api) had to touch them by hand.

Suggested scope

  1. A scripts/check-stack-collection-maps.mjs-style gate comparing all six against stack.zod.ts, with a named-waiver list carrying a reason per exemption (the KIND_COVERAGE / liveness-ratchet pattern).
  2. Fix the drift the gate then reports — including deciding whether data: should map to seed, be removed, or stay waived.

Filed per AGENTS.md Prime Directive #10 while auditing for #6234. Not assigned; no PR.

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