Skip to content

The shipped blank template's objectstack.manifest.json does not validate against TemplateManifestSchema — it declares no manifestId #7319

Description

@os-zhuang

Observation-class finding, spotted while implementing #6861 (PR #7317). Nothing a user hits today — filing so the second declared-vs-live drift on this file is recorded rather than rediscovered.

The drift

TemplateManifestSchema (packages/spec/src/cloud/template-manifest.zod.ts) is documented as the schema of the on-disk objectstack.manifest.json, and the bundled blank template's manifest declares it as its $schema:

{
  "$schema": "https://schemas.objectstack.dev/template-manifest.json",
  "name": "blank",
  "namespace": "blank",
  "specVersion": "^6.0.0",
  "displayName": "Blank Starter",
  ...
}

But the file does not satisfy that schema. TemplateManifestSchema inherits manifestId from CreatePackageRequestSchema as required, and the manifest declares none. Measured on origin/main @ 3e8e669c0:

blank template manifest parses? false
issues: [
 {
  "expected": "string",
  "code": "invalid_type",
  "path": ["manifestId"],
  "message": "Invalid input: expected string, received undefined"
 }
]

That is the only complaint — manifestId is the whole of the gap.

Why nothing breaks today

Nothing validates objectstack.manifest.json against the schema on any live path:

  • create-objectstack reads and rewrites the file as raw JSON; it does not depend on @objectstack/spec at all (deps are chalk, commander, tar).
  • packages/cli/src/commands/package/publish.ts also reads it as raw JSON (tryLoadTemplateManifest), pulling manifestId with a ?? deriveManifestId(...) fallback when absent — which is exactly why the missing key has never surfaced.

So the schema and the shipped file disagree, and no gate is positioned to notice.

Not fixed in #6861 / PR #7317

That issue is scoped to namespace, and this is a different key with a different resolution space. There is a real fork here and it should be settled deliberately rather than by whoever touches the file next:

  • Give the blank template a manifestId (e.g. dev.objectstack.blank), making the shipped file conform — but the scaffolder currently derives the id per project, so a template-level literal has to mean something.
  • Make manifestId optional on TemplateManifestSchema — the on-disk descriptor is a template source tree, not a publish request, and the id is derived at publish time by deriveManifestId. This matches how the key is actually used.
  • Add a gate that parses every shipped objectstack.manifest.json against the schema, so the two cannot drift again — the check that would have caught both this and objectstack.manifest.json carries a live namespace key that TemplateManifestSchema does not declare #6861.

Worth noting the third option is the one that makes the class of bug unrepeatable, and that the $schema line on the file is currently an unverified claim.

Measured on

origin/main @ 3e8e669c0. Files: packages/create-objectstack/src/templates/blank/objectstack.manifest.json, packages/spec/src/cloud/template-manifest.zod.ts, packages/spec/src/cloud/package.zod.ts (CreatePackageRequestSchema.manifestId), packages/cli/src/commands/package/publish.ts.


Generated by Claude Code

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions