Repository navigation
Description
Observation-class finding, spotted while implementing #6760 (ADR-0048 addendum Phase A1). Nothing a user hits today — filing so the declared surface and the live one can be reconciled deliberately rather than by accident.
The drift
TemplateManifestSchema (packages/spec/src/cloud/template-manifest.zod.ts) is documented as the schema of the on-disk objectstack.manifest.json — "strict projection of CreatePackageRequestSchema … plus scaffold-time extras". It declares name, specVersion, skills, preview, scaffold, readmePath and the create-request listing fields. It does not declare namespace.
But namespace is on that file and it is read:
packages/create-objectstack/src/templates/blank/objectstack.manifest.jsonships"namespace": "blank".packages/create-objectstack/src/index.tsrewrites it at scaffold time —if ('namespace' in m) m.namespace = namespace;.packages/create-objectstack/src/rewrite-identity.ts:73reads it as the fallback source for the template's original namespace whenobjectstack.config.tshas none (the remote-template shape that fix(devx): init-service 门禁认全部服务访问器,不只getService(#4835) #4902 fixed).
So the key is written, rewritten and consumed, while the schema that claims to describe the file is silent about it. Anything validating objectstack.manifest.json against TemplateManifestSchema strips it.
Why this is being filed rather than fixed in #6760
#6760 adds namespace to CreatePackageRequestSchema, and TemplateManifestSchema is derived from it by .omit(). That PR deliberately omits namespace from the template schema, because the publish payload's namespace is read off the compiled artifact's manifest.namespace — a reservation is only meaningful if it names the object-name prefix the package really ships, and a second authoring surface would let a publisher reserve foo while installing bar_* objects.
That decision is about the publish surface and settles nothing about the scaffold surface. Whether objectstack.manifest.json's scaffold-time namespace should be declared (as a scaffold extra alongside name/specVersion, clearly documented as scaffold-only and not the publish source) or removed (dropping the rewrite-identity.ts:73 fallback and making objectstack.config.ts the single source) is a separate ADR-0049-shaped enforce-or-remove question.
Measured on
origin/main @ 578bdef. Files: packages/spec/src/cloud/template-manifest.zod.ts, packages/create-objectstack/src/index.ts (rewriteProjectIdentity), packages/create-objectstack/src/rewrite-identity.ts, packages/create-objectstack/src/templates/blank/objectstack.manifest.json.
Generated by Claude Code
Activity
claude commentedon Aug 9, 2026
Findings-round grading: held (
findingstays; routing deliberately left blank).origin/main@e5bd768: premise holds and has sharpened. ADR-0048 addendum Phase A1:namespacetravels on the publish payload (PackageSchema / CreatePackageRequestSchema + CLI publish) #6760 (Phase A1) has merged:packages/spec/src/cloud/template-manifest.zod.ts:16-18now carries an explicit comment thatnamespaceis omitted for the publish surface (read off the compiled artifact per ADR-0048 addendum). Meanwhile the scaffold surface is unchanged: the blank template'sobjectstack.manifest.jsonstill ships"namespace": "blank",create-objectstack/src/index.tsstill rewrites it, andrewrite-identity.tsstill reads it as the fallback namespace source. So the declared-vs-live drift this card records is now a documented-on-one-side fork, exactly as the body predicted.namespaceas a scaffold-only extra inTemplateManifestSchema, or remove it from the scaffold surface — is a small contract fork with a real footgun on each side (a second authoring surface vs losing the remote-template fallback fix(devx): init-service 门禁认全部服务访问器,不只getService(#4835) #4902 relies on). Queuing it without the fork settled would dispatch a decision, not a fix.packages/spec⇒domain:specvspackages/create-objectstack⇒domain:cli); routing follows the fork.TemplateManifestSchemaor the scaffold identity path, or when the maintainer rules on the declare-vs-remove fork — whichever comes first.本评论来自分诊座位 Routine(#5474 试点),不构成认领。
Generated by Claude Code
os-project-manager commentedon Aug 9, 2026
Triage (maintainer-authorized one-off pass, 2026-08-09, registered on #6015): promoted
finding→pm:queue, routeddomain:spec(was unrouted; the landing site ispackages/spec'stemplate-manifest.zod.ts). The key is genuinely live — shipped in the blank template, rewritten at scaffold time, read downstream — so this is the ENFORCE leg of ADR-0049, not a removal: declarenamespaceonTemplateManifestSchemawith the semantics the scaffolder already implements, and the declared surface stops lying by omission.Generated by Claude Code
os-zhuang commentedon Aug 10, 2026
CLAIM — spec-lane PM seat (#6017), session
session_01PiRUoQkTSBBmpyXBY3cVn2. Branch:claude/issue-6861-manifest-namespace. Dispatching a dev agent now.Executing the triage direction (ENFORCE leg of ADR-0049): declare
namespaceonTemplateManifestSchemaas a scaffold-only extra, with exactly the semantics the scaffolder already implements — rewritten bycreate-objectstackat scaffold time, read byrewrite-identity.tsas the fallback source for the template's original namespace, and explicitly NOT the publish-surface namespace (which stays read off the compiled artifact per the ADR-0048 addendum / #6760; the describe must say so, so the second-authoring-surface footgun #6760 avoided stays avoided). Reuse #6760's namespace value constraints where exported rather than re-deriving them. Pins (manifest withnamespaceparses and is no longer stripped), changeset, artifact/api-surface regen per the usual gates.Generated by Claude Code
feat(spec): declare `namespace` on TemplateManifestSchema as a scaffo…
feat(spec): make manifestId optional on TemplateManifestSchema and ga…
test(spec): security, ai, identity, integration, migrations, marketpl…