Uh oh!
There was an error while loading. Please reload this page.
fix(cli): stamp the manifest identity block in the os create example scaffold - #14821
fix(cli): stamp the manifest identity block in the os create example scaffold#14821os-trump wants to merge 2 commits into
os create example scaffold#14821Conversation
…e scaffold `os create example <name>` emitted an `objectstack.config.ts` whose manifest declared only `name`, `version` and `description`. `ManifestSchema` requires `id` and `type`, and `namespace` decides every object's table name and REST path — so `defineStack` threw and the freshly scaffolded project refused on its first run. The template now stamps `id`, `namespace` (via `init`'s own `sanitizeNamespace`), `type: 'app'` and `engines.protocol` from `PROTOCOL_MAJOR`, matching what the three `os init` templates stamp. A new pin renders every `init` and `create` template that emits an `objectstack.config.ts`, loads it back, and parses its `manifest` through the real `ManifestSchema`. The population is derived from the two template maps, so a later template is swept without editing the test. `os create` is not removed, deprecated, or redirected at `os init`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
The manifest sweep wrote only `objectstack.config.ts`, so the two `os init` templates whose config imports `./src/objects` failed to resolve and were reported as refusing to load. Each scaffold now emits through its own emitter — `writeTemplateSrcFiles` for `init`, the `.ts` entries of the `files` map for `create`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
📓 Docs Drift CheckThis PR changes 1 package(s): 4 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
What this run could not see
Coarse fallback — 22 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 1b77c4b5450e40755f2b69dc665a2a026eaa9604 && git checkout 1b77c4b5450e40755f2b69dc665a2a026eaa9604
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 5a5336b399db2ef18dd4700f97d579a328197dda 1a30e47e0915a10a4beaa9459402843c46690165 && git checkout -B drift-repro 5a5336b399db2ef18dd4700f97d579a328197dda && git merge --no-ff 1a30e47e0915a10a4beaa9459402843c46690165
node scripts/docs-audit/affected-docs.mjs --json 5a5336b399db2ef18dd4700f97d579a328197dda
|
Fixes#14705
What was wrong, re-verified on
origin/mainos create example [name]wrote anobjectstack.config.tswhosemanifest:block was
name,version,description— nothing else(
packages/cli/src/commands/create.ts:130, confirmed at merge base8f9ef6f7c8).ManifestSchemarequiresidandtype;namespace— the mandatory prefix ofevery object name, and therefore each object's table name and REST path — was
absent too.
defineStackrefuses that, so the project a documented command hadjust created failed on its first run, before the author wrote a line.
The ablation leg below reproduces the reported measurement verbatim, through the
real schema:
Every factual claim in the card holds.
init.ts's three templates all stampid/namespace/type/engines.protocol;create'sexampletemplateis the one scaffold that had drifted. One clarification, not a correction:
create'splugintemplate emits noobjectstack.config.tsat all — itscaffolds a
Pluginobject insrc/index.ts— soexampleis the onlycreatetemplateManifestSchemagoverns.What changed
packages/cli/src/commands/create.ts(+19/-3) — theexampletemplate nowstamps what
os initstamps:id: 'com.example.NAMESPACE',namespace,type: 'app'andengines: { protocol: '^PROTOCOL_MAJOR' }, alongside theversion/name/descriptionit already carried. The namespace comes frominit's own exportedsanitizeNamespace, and the protocol range from the samePROTOCOL_MAJORconstantinitstamps, so the two scaffolders cannot answerdifferently for the same input. The shipped comment explaining the protocol
range is copied from
init's template, which is already pinned self-contained(no monorepo-only reference, and its docs link resolves).
packages/cli/test/scaffold-manifest-schema.test.ts(new, 223 lines) — thepin the card asks for. It sweeps both scaffolders: every
initandcreatetemplate that emits an
objectstack.config.tsis rendered through its ownemitter (
configContent+writeTemplateSrcFilesforinit; the.tsentriesof the
filesmap forcreate), written to a throwaway directory under thepackage's git-ignored
tmp/, loaded back throughbundle-require— the sameloader
scaffold-validate.tsuses — and itsmanifestparsed through the realManifestSchema. Nothing is hand-copied: the population is derived from the twotemplate maps, so a template added later is swept the day it is added.
The standalone
ManifestSchemaparse is not redundant with thedefineStackcall above it.
ObjectStackDefinitionSchema.manifestis.optional(), so atemplate that drops the block entirely, or one that calls
defineStack(config, { strict: false }), loads green at that door and ships aproject with no id, namespace or type. The header states both.
.changeset/create-scaffold-manifest-identity.md—patchfor@objectstack/cli.File face
Three files.
packages/specis untouched — the honest fix needed no schemachange; the scaffold was simply not declaring what the schema has always
required.
Measurements — all at
1a30e47e09, this PR's headReverse verification (three legs, one script,
trap ... EXIT INT TERM).Committed first, so the restore leg's reference (
HEAD) already carried the fix.Test Files 5 passed (5)·Tests 43 passed (43)create.tsreverted toorigin/mainTests 1 failed | 5 passed (6)— the single failure iscreate:example, with the diagnostic quoted above779e4fecfd,git diff HEADemptyMutation proved on disk, not by exit code:
HEAD_BLOB=779e4fecfd...vsMUT_BLOB=f706bb2199...(differ, non-empty), and the mutated file'ssanitizeNamespace/PROTOCOL_MAJORoccurrence counts both dropped to 0.Restore proved the same way — the hash returned to
HEAD_BLOBand the diff isempty. The ablation direction is a plain red, and only in the scaffold the card
names: the three
initscaffolds stayed green through both legs, so the pin isspecific rather than a blanket refusal.
Suite run (under the shared verify lock):
pnpm --filter @objectstack/cli exec vitest run --project unit --maxWorkers=2 test/scaffold-manifest-schema.test.ts test/create.test.ts test/init-scaffold-authoring-rules.test.ts test/init-template-comments-self-contained.test.ts test/commands.test.tsTypecheck.
pnpm --filter @objectstack/cli typecheckexit 0 (script echoedtsc --noEmit, so not a zero-match pass).--listFilessays what that coversand what it does not:
src/commands/create.tsis in the program (1 hit); thenew test file is not (0 hits) — this package's
tsconfig.jsonisinclude: ["src"], which is why it carries aTEST_DEBTentry. So that greensays nothing about the new test, and the ratchet is measured separately below.
ESLint.
pnpm lint— the whole repo,eslint . --no-inline-config— exit0. No narrowing claimed and none needed.
Gate families.
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstackderives 37 for this diff (35 by path + 6 by change kind, 4 shared). Harvested
with
--commands, re-run whole at this head: 34 green, 3 NOT MEASURED —recorded as such, not as passes and not as reds:
node scripts/check-test-completeness.mjs— exit 3,PREREQUISITE NOT MET:it grades a saved
turbo run testlog and there is none locally. CI passesthe path on every invocation.
node scripts/pm/check-half-states.mjs— exit 3,PREREQUISITE NOT MET: itneeds repo-scoped REST egress this container does not have.
pnpm check:type-check-debt(--re-measure) — killed by the 10-minuteforeground ceiling mid-sweep; it re-runs
tscacross 10 ledger packages.Substituted with a targeted measurement of the same quantity: a probe
config extending this package's own
tsconfig.jsonwithinclude: ["src", "test"]reports 144 errors — exactly the frozenTEST_DEBT['@objectstack/cli'].errorsof 144 — and zero of them are inscaffold-manifest-schema.test.ts. The new test file therefore cannot pushthe ratchet up. The probe config was deleted; it is not in the diff.
pnpm check:i18n,check:i18n-coverageandcheck:dual-build-cjs-loadseachrefused on an unbuilt closure at first and were re-run green once the workspace
build caught up; the green readings above are the ones taken at this head.
What I deliberately did NOT do
os createis untouched as a command. Not removed, not deprecated, notredirected at
os init, and it does not callinitinternally. Whether twoscaffolders should coexist is a CLI-surface decision and is not this PR's.
Fixing the template forecloses nothing there.
packages/specis untouched. No schema change was needed or made.create'splugintemplate is untouched. It emits no package manifest,so
ManifestSchemahas nothing to say about it, and pretending otherwisewould have put a surface in the sweep that the schema does not govern.
package.json/tsconfig.jsonare not emitted by the pin.They are monorepo-relative (
workspace:*,extends: '../../tsconfig.json')and resolve to nothing from a throwaway directory, and neither can change what
the manifest declares. The test header records this and why.
Draft, per dispatch. Not flipped ready, no auto-merge armed.
🤖 Generated with Claude Code
https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
Generated by Claude Code
Generated by Claude Code