You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Found while implementing #14162 (PR #14240). Filed rather than worked around there: widening a spec surface is not a loader's decision.
The fact
ArtifactPackageEntrySchema (packages/spec/src/stack.zod.ts, landed by #14161) wraps the package body as manifest: ManifestSchema. ManifestSchema.objects is z.array(z.string()) — glob patterns, the authoring-time shape.
What actually reaches the ADR-0130 load path is an assembled payload whose objects are object definitions: AppPlugin flattens an artifact into { ...bundle.manifest, ...bundle } before calling manifest.register(), and ObjectQL.registerApp iterates those bodies as definitions.
So a full parse of a real artifact entry refuses it. Measured on cfa99f3d against the landed schema:
The entry schema therefore describes the authoring-time manifest, while the key it was added for (packages[] on ObjectStackDefinitionSchema) is read at load time, where the body has a different shape. One schema is being asked to describe two different lifecycle stages of the same noun.
Why it matters
Any consumer that reaches for the obvious ArtifactPackageEntrySchema.safeParse(entry) as its gate will refuse exactly the artifacts the path exists to register — and it will look correct while doing so, because the schema is the surface's one declaration and the refusal names a real key.
PR #14240 works within it deliberately and narrowly: it applies the schema as a gate on the wrapper only (issues at the entry root or on manifest itself), and hands registerApp the caller's original body rather than a parsed clone. That is written down in the module header with this measurement, so the next reader does not discover it again. But it is a local accommodation of a surface-level mismatch, and the accommodation is the kind of thing that quietly becomes convention if the surface is never revisited.
What the decision is
Not obvious, hence a card rather than a patch. Roughly:
B. Give the assembled/registered form its own declaration, so both stages are describable and a load-time consumer has something correct to parse against.
C. Widen ManifestSchema.objects to accept both spellings — cheapest to write, and the one that most deserves scrutiny: a union that accepts both stages makes neither stage checkable, which is the tolerance-at-the-consumer shape this repo generally refuses.
No packages[]-shaped artifact is produced anywhere yet, so nothing is broken in the field today and there is time to decide this properly rather than under a deadline.
Found while implementing #14162 (PR #14240). Filed rather than worked around there: widening a spec surface is not a loader's decision.
The fact
ArtifactPackageEntrySchema(packages/spec/src/stack.zod.ts, landed by #14161) wraps the package body asmanifest: ManifestSchema.ManifestSchema.objectsisz.array(z.string())— glob patterns, the authoring-time shape.What actually reaches the ADR-0130 load path is an assembled payload whose
objectsare object definitions:AppPluginflattens an artifact into{ ...bundle.manifest, ...bundle }before callingmanifest.register(), andObjectQL.registerAppiterates those bodies as definitions.So a full parse of a real artifact entry refuses it. Measured on
cfa99f3dagainst the landed schema:The entry schema therefore describes the authoring-time manifest, while the key it was added for (
packages[]onObjectStackDefinitionSchema) is read at load time, where the body has a different shape. One schema is being asked to describe two different lifecycle stages of the same noun.Why it matters
Any consumer that reaches for the obvious
ArtifactPackageEntrySchema.safeParse(entry)as its gate will refuse exactly the artifacts the path exists to register — and it will look correct while doing so, because the schema is the surface's one declaration and the refusal names a real key.PR #14240 works within it deliberately and narrowly: it applies the schema as a gate on the wrapper only (issues at the entry root or on
manifestitself), and handsregisterAppthe caller's original body rather than a parsed clone. That is written down in the module header with this measurement, so the next reader does not discover it again. But it is a local accommodation of a surface-level mismatch, and the accommodation is the kind of thing that quietly becomes convention if the surface is never revisited.What the decision is
Not obvious, hence a card rather than a patch. Roughly:
ManifestSchema.objectsto accept both spellings — cheapest to write, and the one that most deserves scrutiny: a union that accepts both stages makes neither stage checkable, which is the tolerance-at-the-consumer shape this repo generally refuses.No
packages[]-shaped artifact is produced anywhere yet, so nothing is broken in the field today and there is time to decide this properly rather than under a deadline.