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.

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