fix(cli): stamp the manifest identity block in the os create example scaffold - #14821

Draft
os-trump wants to merge 2 commits into
mainfrom
claude/issue-14705-create-template-manifest
Draft

fix(cli): stamp the manifest identity block in the os create example scaffold#14821
os-trump wants to merge 2 commits into
mainfrom
claude/issue-14705-create-template-manifest

Conversation

@os-trump

Copy link
Copy Markdown
Collaborator

Fixes#14705

What was wrong, re-verified on origin/main

os create example [name] wrote an objectstack.config.ts whose manifest:
block was name, version, description — nothing else
(packages/cli/src/commands/create.ts:130, confirmed at merge base 8f9ef6f7c8).
ManifestSchema requires id and type; namespace — the mandatory prefix of
every object name, and therefore each object's table name and REST path — was
absent too. defineStack refuses that, so the project a documented command had
just 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:

defineStack validation failed (2 issues):
x manifest.id: Required property 'id' is missing.
x manifest.type: Invalid value ''. Did you mean one of: 'ui', 'app'?

Every factual claim in the card holds. init.ts's three templates all stamp
id / namespace / type / engines.protocol; create's example template
is the one scaffold that had drifted. One clarification, not a correction:
create's plugin template emits no objectstack.config.ts at all — it
scaffolds a Plugin object in src/index.ts — so example is the only
create template ManifestSchema governs.

What changed

packages/cli/src/commands/create.ts (+19/-3) — the example template now
stamps what os init stamps: id: 'com.example.NAMESPACE', namespace,
type: 'app' and engines: { protocol: '^PROTOCOL_MAJOR' }, alongside the
version / name / description it already carried. The namespace comes from
init's own exported sanitizeNamespace, and the protocol range from the same
PROTOCOL_MAJOR constant init stamps, so the two scaffolders cannot answer
differently 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) — the
pin the card asks for. It sweeps both scaffolders: every init and create
template that emits an objectstack.config.ts is rendered through its own
emitter (configContent + writeTemplateSrcFiles for init; the .ts entries
of the files map for create), written to a throwaway directory under the
package's git-ignored tmp/, loaded back through bundle-require — the same
loader scaffold-validate.ts uses — and its manifest parsed through the real
ManifestSchema. Nothing is hand-copied: the population is derived from the two
template maps, so a template added later is swept the day it is added.

The standalone ManifestSchema parse is not redundant with the defineStack
call above it. ObjectStackDefinitionSchema.manifest is .optional(), so a
template that drops the block entirely, or one that calls
defineStack(config, { strict: false }), loads green at that door and ships a
project with no id, namespace or type. The header states both.

.changeset/create-scaffold-manifest-identity.mdpatch for
@objectstack/cli.

File face

.changeset/create-scaffold-manifest-identity.md +37
packages/cli/src/commands/create.ts +19 -3
packages/cli/test/scaffold-manifest-schema.test.ts +223

Three files. packages/spec is untouched — the honest fix needed no schema
change; the scaffold was simply not declaring what the schema has always
required.

Measurements — all at 1a30e47e09, this PR's head

Reverse verification (three legs, one script, trap ... EXIT INT TERM).
Committed first, so the restore leg's reference (HEAD) already carried the fix.

legtreeresult
1fixedTest Files 5 passed (5) · Tests 43 passed (43)
2create.ts reverted to origin/mainTests 1 failed | 5 passed (6) — the single failure is create:example, with the diagnostic quoted above
3restoredblob hash back to 779e4fecfd, git diff HEAD empty

Mutation proved on disk, not by exit code: HEAD_BLOB=779e4fecfd... vs
MUT_BLOB=f706bb2199... (differ, non-empty), and the mutated file's
sanitizeNamespace / PROTOCOL_MAJOR occurrence counts both dropped to 0.
Restore proved the same way — the hash returned to HEAD_BLOB and the diff is
empty. The ablation direction is a plain red, and only in the scaffold the card
names: the three init scaffolds stayed green through both legs, so the pin is
specific 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.ts

Typecheck.pnpm --filter @objectstack/cli typecheck exit 0 (script echoed
tsc --noEmit, so not a zero-match pass). --listFiles says what that covers
and what it does not: src/commands/create.ts is in the program (1 hit); the
new test file is not (0 hits) — this package's tsconfig.json is
include: ["src"], which is why it carries a TEST_DEBT entry. So that green
says nothing about the new test, and the ratchet is measured separately below.

ESLint.pnpm lint — the whole repo, eslint . --no-inline-config — exit
0. No narrowing claimed and none needed.

Gate families.node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack
derives 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 test log and there is none locally. CI passes
    the path on every invocation.
  • node scripts/pm/check-half-states.mjs — exit 3, PREREQUISITE NOT MET: it
    needs repo-scoped REST egress this container does not have.
  • pnpm check:type-check-debt (--re-measure) — killed by the 10-minute
    foreground ceiling mid-sweep; it re-runs tsc across 10 ledger packages.
    Substituted with a targeted measurement of the same quantity: a probe
    config extending this package's own tsconfig.json with
    include: ["src", "test"] reports 144 errors — exactly the frozen
    TEST_DEBT['@objectstack/cli'].errors of 144 — and zero of them are in
    scaffold-manifest-schema.test.ts. The new test file therefore cannot push
    the ratchet up. The probe config was deleted; it is not in the diff.

pnpm check:i18n, check:i18n-coverage and check:dual-build-cjs-loads each
refused 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 create is untouched as a command. Not removed, not deprecated, not
    redirected at os init, and it does not call init internally. Whether two
    scaffolders should coexist is a CLI-surface decision and is not this PR's.
    Fixing the template forecloses nothing there.
  • packages/spec is untouched. No schema change was needed or made.
  • create's plugin template is untouched. It emits no package manifest,
    so ManifestSchema has nothing to say about it, and pretending otherwise
    would have put a surface in the sweep that the schema does not govern.
  • The scaffold's package.json / tsconfig.json are 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

…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
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/cli, touching 1 documentable anchor(s).

4 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/deployment/cli.mdx(via os create (command, read off packages/cli/src/commands/create.ts))
  • content/docs/plugins/index.mdx(via os create (command, read off packages/cli/src/commands/create.ts))
  • content/docs/protocol/kernel/index.mdx(via os create (command, read off packages/cli/src/commands/create.ts))
  • content/docs/protocol/kernel/plugin-spec.mdx(via os create (command, read off packages/cli/src/commands/create.ts))
What this run could not see
  • 1 anchor(s) matched too much of the corpus to be a work list: objectstack.config.ts (literal, 32 pages)
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 22 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 5a5336b399db2ef18dd4700f97d579a328197ddapackageMentionDocs.

Which tree this was computed on

This run read content/docs from 1b77c4b5450e40755f2b69dc665a2a026eaa9604 — the merge of head 1a30e47e0915a10a4beaa9459402843c46690165 into base 5a5336b399db2ef18dd4700f97d579a328197dda, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# 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

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 5a5336b399db2ef18dd4700f97d579a328197dda → pass the list as
args.docs, on the commit named under Which tree this was computed on.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/mteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

os create template manifest fails ManifestSchema — the scaffold in packages/cli/src/commands/create.ts declares neither id nor type

2 participants

@os-trump@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

fix(cli): stamp the manifest identity block in the os create example scaffold - #14821

Draft
os-trump wants to merge 2 commits into
mainfrom
claude/issue-14705-create-template-manifest
Draft

fix(cli): stamp the manifest identity block in the os create example scaffold#14821
os-trump wants to merge 2 commits into
mainfrom
claude/issue-14705-create-template-manifest

Conversation

@os-trump

Copy link
Copy Markdown
Collaborator

Fixes#14705

What was wrong, re-verified on origin/main

os create example [name] wrote an objectstack.config.ts whose manifest:
block was name, version, description — nothing else
(packages/cli/src/commands/create.ts:130, confirmed at merge base 8f9ef6f7c8).
ManifestSchema requires id and type; namespace — the mandatory prefix of
every object name, and therefore each object's table name and REST path — was
absent too. defineStack refuses that, so the project a documented command had
just 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:

defineStack validation failed (2 issues):
x manifest.id: Required property 'id' is missing.
x manifest.type: Invalid value ''. Did you mean one of: 'ui', 'app'?

Every factual claim in the card holds. init.ts's three templates all stamp
id / namespace / type / engines.protocol; create's example template
is the one scaffold that had drifted. One clarification, not a correction:
create's plugin template emits no objectstack.config.ts at all — it
scaffolds a Plugin object in src/index.ts — so example is the only
create template ManifestSchema governs.

What changed

packages/cli/src/commands/create.ts (+19/-3) — the example template now
stamps what os init stamps: id: 'com.example.NAMESPACE', namespace,
type: 'app' and engines: { protocol: '^PROTOCOL_MAJOR' }, alongside the
version / name / description it already carried. The namespace comes from
init's own exported sanitizeNamespace, and the protocol range from the same
PROTOCOL_MAJOR constant init stamps, so the two scaffolders cannot answer
differently 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) — the
pin the card asks for. It sweeps both scaffolders: every init and create
template that emits an objectstack.config.ts is rendered through its own
emitter (configContent + writeTemplateSrcFiles for init; the .ts entries
of the files map for create), written to a throwaway directory under the
package's git-ignored tmp/, loaded back through bundle-require — the same
loader scaffold-validate.ts uses — and its manifest parsed through the real
ManifestSchema. Nothing is hand-copied: the population is derived from the two
template maps, so a template added later is swept the day it is added.

The standalone ManifestSchema parse is not redundant with the defineStack
call above it. ObjectStackDefinitionSchema.manifest is .optional(), so a
template that drops the block entirely, or one that calls
defineStack(config, { strict: false }), loads green at that door and ships a
project with no id, namespace or type. The header states both.

.changeset/create-scaffold-manifest-identity.mdpatch for
@objectstack/cli.

File face

.changeset/create-scaffold-manifest-identity.md +37
packages/cli/src/commands/create.ts +19 -3
packages/cli/test/scaffold-manifest-schema.test.ts +223

Three files. packages/spec is untouched — the honest fix needed no schema
change; the scaffold was simply not declaring what the schema has always
required.

Measurements — all at 1a30e47e09, this PR's head

Reverse verification (three legs, one script, trap ... EXIT INT TERM).
Committed first, so the restore leg's reference (HEAD) already carried the fix.

legtreeresult
1fixedTest Files 5 passed (5) · Tests 43 passed (43)
2create.ts reverted to origin/mainTests 1 failed | 5 passed (6) — the single failure is create:example, with the diagnostic quoted above
3restoredblob hash back to 779e4fecfd, git diff HEAD empty

Mutation proved on disk, not by exit code: HEAD_BLOB=779e4fecfd... vs
MUT_BLOB=f706bb2199... (differ, non-empty), and the mutated file's
sanitizeNamespace / PROTOCOL_MAJOR occurrence counts both dropped to 0.
Restore proved the same way — the hash returned to HEAD_BLOB and the diff is
empty. The ablation direction is a plain red, and only in the scaffold the card
names: the three init scaffolds stayed green through both legs, so the pin is
specific 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.ts

Typecheck.pnpm --filter @objectstack/cli typecheck exit 0 (script echoed
tsc --noEmit, so not a zero-match pass). --listFiles says what that covers
and what it does not: src/commands/create.ts is in the program (1 hit); the
new test file is not (0 hits) — this package's tsconfig.json is
include: ["src"], which is why it carries a TEST_DEBT entry. So that green
says nothing about the new test, and the ratchet is measured separately below.

ESLint.pnpm lint — the whole repo, eslint . --no-inline-config — exit
0. No narrowing claimed and none needed.

Gate families.node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack
derives 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 test log and there is none locally. CI passes
    the path on every invocation.
  • node scripts/pm/check-half-states.mjs — exit 3, PREREQUISITE NOT MET: it
    needs repo-scoped REST egress this container does not have.
  • pnpm check:type-check-debt (--re-measure) — killed by the 10-minute
    foreground ceiling mid-sweep; it re-runs tsc across 10 ledger packages.
    Substituted with a targeted measurement of the same quantity: a probe
    config extending this package's own tsconfig.json with
    include: ["src", "test"] reports 144 errors — exactly the frozen
    TEST_DEBT['@objectstack/cli'].errors of 144 — and zero of them are in
    scaffold-manifest-schema.test.ts. The new test file therefore cannot push
    the ratchet up. The probe config was deleted; it is not in the diff.

pnpm check:i18n, check:i18n-coverage and check:dual-build-cjs-loads each
refused 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 create is untouched as a command. Not removed, not deprecated, not
    redirected at os init, and it does not call init internally. Whether two
    scaffolders should coexist is a CLI-surface decision and is not this PR's.
    Fixing the template forecloses nothing there.
  • packages/spec is untouched. No schema change was needed or made.
  • create's plugin template is untouched. It emits no package manifest,
    so ManifestSchema has nothing to say about it, and pretending otherwise
    would have put a surface in the sweep that the schema does not govern.
  • The scaffold's package.json / tsconfig.json are 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

…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
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/cli, touching 1 documentable anchor(s).

4 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/deployment/cli.mdx(via os create (command, read off packages/cli/src/commands/create.ts))
  • content/docs/plugins/index.mdx(via os create (command, read off packages/cli/src/commands/create.ts))
  • content/docs/protocol/kernel/index.mdx(via os create (command, read off packages/cli/src/commands/create.ts))
  • content/docs/protocol/kernel/plugin-spec.mdx(via os create (command, read off packages/cli/src/commands/create.ts))
What this run could not see
  • 1 anchor(s) matched too much of the corpus to be a work list: objectstack.config.ts (literal, 32 pages)
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 22 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 5a5336b399db2ef18dd4700f97d579a328197ddapackageMentionDocs.

Which tree this was computed on

This run read content/docs from 1b77c4b5450e40755f2b69dc665a2a026eaa9604 — the merge of head 1a30e47e0915a10a4beaa9459402843c46690165 into base 5a5336b399db2ef18dd4700f97d579a328197dda, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# 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

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 5a5336b399db2ef18dd4700f97d579a328197dda → pass the list as
args.docs, on the commit named under Which tree this was computed on.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/mteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

os create template manifest fails ManifestSchema — the scaffold in packages/cli/src/commands/create.ts declares neither id nor type

2 participants

@os-trump@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(cli): stamp the manifest identity block in the os create example scaffold - #14821

Draft
os-trump wants to merge 2 commits into
mainfrom
claude/issue-14705-create-template-manifest
Draft

fix(cli): stamp the manifest identity block in the os create example scaffold#14821
os-trump wants to merge 2 commits into
mainfrom
claude/issue-14705-create-template-manifest

Conversation

@os-trump

Copy link
Copy Markdown
Collaborator

Fixes#14705

What was wrong, re-verified on origin/main

os create example [name] wrote an objectstack.config.ts whose manifest:
block was name, version, description — nothing else
(packages/cli/src/commands/create.ts:130, confirmed at merge base 8f9ef6f7c8).
ManifestSchema requires id and type; namespace — the mandatory prefix of
every object name, and therefore each object's table name and REST path — was
absent too. defineStack refuses that, so the project a documented command had
just 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:

defineStack validation failed (2 issues):
x manifest.id: Required property 'id' is missing.
x manifest.type: Invalid value ''. Did you mean one of: 'ui', 'app'?

Every factual claim in the card holds. init.ts's three templates all stamp
id / namespace / type / engines.protocol; create's example template
is the one scaffold that had drifted. One clarification, not a correction:
create's plugin template emits no objectstack.config.ts at all — it
scaffolds a Plugin object in src/index.ts — so example is the only
create template ManifestSchema governs.

What changed

packages/cli/src/commands/create.ts (+19/-3) — the example template now
stamps what os init stamps: id: 'com.example.NAMESPACE', namespace,
type: 'app' and engines: { protocol: '^PROTOCOL_MAJOR' }, alongside the
version / name / description it already carried. The namespace comes from
init's own exported sanitizeNamespace, and the protocol range from the same
PROTOCOL_MAJOR constant init stamps, so the two scaffolders cannot answer
differently 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) — the
pin the card asks for. It sweeps both scaffolders: every init and create
template that emits an objectstack.config.ts is rendered through its own
emitter (configContent + writeTemplateSrcFiles for init; the .ts entries
of the files map for create), written to a throwaway directory under the
package's git-ignored tmp/, loaded back through bundle-require — the same
loader scaffold-validate.ts uses — and its manifest parsed through the real
ManifestSchema. Nothing is hand-copied: the population is derived from the two
template maps, so a template added later is swept the day it is added.

The standalone ManifestSchema parse is not redundant with the defineStack
call above it. ObjectStackDefinitionSchema.manifest is .optional(), so a
template that drops the block entirely, or one that calls
defineStack(config, { strict: false }), loads green at that door and ships a
project with no id, namespace or type. The header states both.

.changeset/create-scaffold-manifest-identity.mdpatch for
@objectstack/cli.

File face

.changeset/create-scaffold-manifest-identity.md +37
packages/cli/src/commands/create.ts +19 -3
packages/cli/test/scaffold-manifest-schema.test.ts +223

Three files. packages/spec is untouched — the honest fix needed no schema
change; the scaffold was simply not declaring what the schema has always
required.

Measurements — all at 1a30e47e09, this PR's head

Reverse verification (three legs, one script, trap ... EXIT INT TERM).
Committed first, so the restore leg's reference (HEAD) already carried the fix.

legtreeresult
1fixedTest Files 5 passed (5) · Tests 43 passed (43)
2create.ts reverted to origin/mainTests 1 failed | 5 passed (6) — the single failure is create:example, with the diagnostic quoted above
3restoredblob hash back to 779e4fecfd, git diff HEAD empty

Mutation proved on disk, not by exit code: HEAD_BLOB=779e4fecfd... vs
MUT_BLOB=f706bb2199... (differ, non-empty), and the mutated file's
sanitizeNamespace / PROTOCOL_MAJOR occurrence counts both dropped to 0.
Restore proved the same way — the hash returned to HEAD_BLOB and the diff is
empty. The ablation direction is a plain red, and only in the scaffold the card
names: the three init scaffolds stayed green through both legs, so the pin is
specific 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.ts

Typecheck.pnpm --filter @objectstack/cli typecheck exit 0 (script echoed
tsc --noEmit, so not a zero-match pass). --listFiles says what that covers
and what it does not: src/commands/create.ts is in the program (1 hit); the
new test file is not (0 hits) — this package's tsconfig.json is
include: ["src"], which is why it carries a TEST_DEBT entry. So that green
says nothing about the new test, and the ratchet is measured separately below.

ESLint.pnpm lint — the whole repo, eslint . --no-inline-config — exit
0. No narrowing claimed and none needed.

Gate families.node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack
derives 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 test log and there is none locally. CI passes
    the path on every invocation.
  • node scripts/pm/check-half-states.mjs — exit 3, PREREQUISITE NOT MET: it
    needs repo-scoped REST egress this container does not have.
  • pnpm check:type-check-debt (--re-measure) — killed by the 10-minute
    foreground ceiling mid-sweep; it re-runs tsc across 10 ledger packages.
    Substituted with a targeted measurement of the same quantity: a probe
    config extending this package's own tsconfig.json with
    include: ["src", "test"] reports 144 errors — exactly the frozen
    TEST_DEBT['@objectstack/cli'].errors of 144 — and zero of them are in
    scaffold-manifest-schema.test.ts. The new test file therefore cannot push
    the ratchet up. The probe config was deleted; it is not in the diff.

pnpm check:i18n, check:i18n-coverage and check:dual-build-cjs-loads each
refused 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 create is untouched as a command. Not removed, not deprecated, not
    redirected at os init, and it does not call init internally. Whether two
    scaffolders should coexist is a CLI-surface decision and is not this PR's.
    Fixing the template forecloses nothing there.
  • packages/spec is untouched. No schema change was needed or made.
  • create's plugin template is untouched. It emits no package manifest,
    so ManifestSchema has nothing to say about it, and pretending otherwise
    would have put a surface in the sweep that the schema does not govern.
  • The scaffold's package.json / tsconfig.json are 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

…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
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/cli, touching 1 documentable anchor(s).

4 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/deployment/cli.mdx(via os create (command, read off packages/cli/src/commands/create.ts))
  • content/docs/plugins/index.mdx(via os create (command, read off packages/cli/src/commands/create.ts))
  • content/docs/protocol/kernel/index.mdx(via os create (command, read off packages/cli/src/commands/create.ts))
  • content/docs/protocol/kernel/plugin-spec.mdx(via os create (command, read off packages/cli/src/commands/create.ts))
What this run could not see
  • 1 anchor(s) matched too much of the corpus to be a work list: objectstack.config.ts (literal, 32 pages)
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 22 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 5a5336b399db2ef18dd4700f97d579a328197ddapackageMentionDocs.

Which tree this was computed on

This run read content/docs from 1b77c4b5450e40755f2b69dc665a2a026eaa9604 — the merge of head 1a30e47e0915a10a4beaa9459402843c46690165 into base 5a5336b399db2ef18dd4700f97d579a328197dda, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# 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

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 5a5336b399db2ef18dd4700f97d579a328197dda → pass the list as
args.docs, on the commit named under Which tree this was computed on.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/mteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

os create template manifest fails ManifestSchema — the scaffold in packages/cli/src/commands/create.ts declares neither id nor type

2 participants

@os-trump@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(cli): stamp the manifest identity block in the os create example scaffold - #14821

Draft
os-trump wants to merge 2 commits into
mainfrom
claude/issue-14705-create-template-manifest
Draft

fix(cli): stamp the manifest identity block in the os create example scaffold#14821
os-trump wants to merge 2 commits into
mainfrom
claude/issue-14705-create-template-manifest

Conversation

@os-trump

Copy link
Copy Markdown
Collaborator

Fixes#14705

What was wrong, re-verified on origin/main

os create example [name] wrote an objectstack.config.ts whose manifest:
block was name, version, description — nothing else
(packages/cli/src/commands/create.ts:130, confirmed at merge base 8f9ef6f7c8).
ManifestSchema requires id and type; namespace — the mandatory prefix of
every object name, and therefore each object's table name and REST path — was
absent too. defineStack refuses that, so the project a documented command had
just 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:

defineStack validation failed (2 issues):
x manifest.id: Required property 'id' is missing.
x manifest.type: Invalid value ''. Did you mean one of: 'ui', 'app'?

Every factual claim in the card holds. init.ts's three templates all stamp
id / namespace / type / engines.protocol; create's example template
is the one scaffold that had drifted. One clarification, not a correction:
create's plugin template emits no objectstack.config.ts at all — it
scaffolds a Plugin object in src/index.ts — so example is the only
create template ManifestSchema governs.

What changed

packages/cli/src/commands/create.ts (+19/-3) — the example template now
stamps what os init stamps: id: 'com.example.NAMESPACE', namespace,
type: 'app' and engines: { protocol: '^PROTOCOL_MAJOR' }, alongside the
version / name / description it already carried. The namespace comes from
init's own exported sanitizeNamespace, and the protocol range from the same
PROTOCOL_MAJOR constant init stamps, so the two scaffolders cannot answer
differently 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) — the
pin the card asks for. It sweeps both scaffolders: every init and create
template that emits an objectstack.config.ts is rendered through its own
emitter (configContent + writeTemplateSrcFiles for init; the .ts entries
of the files map for create), written to a throwaway directory under the
package's git-ignored tmp/, loaded back through bundle-require — the same
loader scaffold-validate.ts uses — and its manifest parsed through the real
ManifestSchema. Nothing is hand-copied: the population is derived from the two
template maps, so a template added later is swept the day it is added.

The standalone ManifestSchema parse is not redundant with the defineStack
call above it. ObjectStackDefinitionSchema.manifest is .optional(), so a
template that drops the block entirely, or one that calls
defineStack(config, { strict: false }), loads green at that door and ships a
project with no id, namespace or type. The header states both.

.changeset/create-scaffold-manifest-identity.mdpatch for
@objectstack/cli.

File face

.changeset/create-scaffold-manifest-identity.md +37
packages/cli/src/commands/create.ts +19 -3
packages/cli/test/scaffold-manifest-schema.test.ts +223

Three files. packages/spec is untouched — the honest fix needed no schema
change; the scaffold was simply not declaring what the schema has always
required.

Measurements — all at 1a30e47e09, this PR's head

Reverse verification (three legs, one script, trap ... EXIT INT TERM).
Committed first, so the restore leg's reference (HEAD) already carried the fix.

legtreeresult
1fixedTest Files 5 passed (5) · Tests 43 passed (43)
2create.ts reverted to origin/mainTests 1 failed | 5 passed (6) — the single failure is create:example, with the diagnostic quoted above
3restoredblob hash back to 779e4fecfd, git diff HEAD empty

Mutation proved on disk, not by exit code: HEAD_BLOB=779e4fecfd... vs
MUT_BLOB=f706bb2199... (differ, non-empty), and the mutated file's
sanitizeNamespace / PROTOCOL_MAJOR occurrence counts both dropped to 0.
Restore proved the same way — the hash returned to HEAD_BLOB and the diff is
empty. The ablation direction is a plain red, and only in the scaffold the card
names: the three init scaffolds stayed green through both legs, so the pin is
specific 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.ts

Typecheck.pnpm --filter @objectstack/cli typecheck exit 0 (script echoed
tsc --noEmit, so not a zero-match pass). --listFiles says what that covers
and what it does not: src/commands/create.ts is in the program (1 hit); the
new test file is not (0 hits) — this package's tsconfig.json is
include: ["src"], which is why it carries a TEST_DEBT entry. So that green
says nothing about the new test, and the ratchet is measured separately below.

ESLint.pnpm lint — the whole repo, eslint . --no-inline-config — exit
0. No narrowing claimed and none needed.

Gate families.node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack
derives 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 test log and there is none locally. CI passes
    the path on every invocation.
  • node scripts/pm/check-half-states.mjs — exit 3, PREREQUISITE NOT MET: it
    needs repo-scoped REST egress this container does not have.
  • pnpm check:type-check-debt (--re-measure) — killed by the 10-minute
    foreground ceiling mid-sweep; it re-runs tsc across 10 ledger packages.
    Substituted with a targeted measurement of the same quantity: a probe
    config extending this package's own tsconfig.json with
    include: ["src", "test"] reports 144 errors — exactly the frozen
    TEST_DEBT['@objectstack/cli'].errors of 144 — and zero of them are in
    scaffold-manifest-schema.test.ts. The new test file therefore cannot push
    the ratchet up. The probe config was deleted; it is not in the diff.

pnpm check:i18n, check:i18n-coverage and check:dual-build-cjs-loads each
refused 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 create is untouched as a command. Not removed, not deprecated, not
    redirected at os init, and it does not call init internally. Whether two
    scaffolders should coexist is a CLI-surface decision and is not this PR's.
    Fixing the template forecloses nothing there.
  • packages/spec is untouched. No schema change was needed or made.
  • create's plugin template is untouched. It emits no package manifest,
    so ManifestSchema has nothing to say about it, and pretending otherwise
    would have put a surface in the sweep that the schema does not govern.
  • The scaffold's package.json / tsconfig.json are 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

…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
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/cli, touching 1 documentable anchor(s).

4 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/deployment/cli.mdx(via os create (command, read off packages/cli/src/commands/create.ts))
  • content/docs/plugins/index.mdx(via os create (command, read off packages/cli/src/commands/create.ts))
  • content/docs/protocol/kernel/index.mdx(via os create (command, read off packages/cli/src/commands/create.ts))
  • content/docs/protocol/kernel/plugin-spec.mdx(via os create (command, read off packages/cli/src/commands/create.ts))
What this run could not see
  • 1 anchor(s) matched too much of the corpus to be a work list: objectstack.config.ts (literal, 32 pages)
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 22 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 5a5336b399db2ef18dd4700f97d579a328197ddapackageMentionDocs.

Which tree this was computed on

This run read content/docs from 1b77c4b5450e40755f2b69dc665a2a026eaa9604 — the merge of head 1a30e47e0915a10a4beaa9459402843c46690165 into base 5a5336b399db2ef18dd4700f97d579a328197dda, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# 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

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 5a5336b399db2ef18dd4700f97d579a328197dda → pass the list as
args.docs, on the commit named under Which tree this was computed on.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/mteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

os create template manifest fails ManifestSchema — the scaffold in packages/cli/src/commands/create.ts declares neither id nor type

2 participants

@os-trump@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

fix(cli): stamp the manifest identity block in the os create example scaffold - #14821

Draft
os-trump wants to merge 2 commits into
mainfrom
claude/issue-14705-create-template-manifest
Draft

fix(cli): stamp the manifest identity block in the os create example scaffold#14821
os-trump wants to merge 2 commits into
mainfrom
claude/issue-14705-create-template-manifest

Conversation

@os-trump

Copy link
Copy Markdown
Collaborator

Fixes#14705

What was wrong, re-verified on origin/main

os create example [name] wrote an objectstack.config.ts whose manifest:
block was name, version, description — nothing else
(packages/cli/src/commands/create.ts:130, confirmed at merge base 8f9ef6f7c8).
ManifestSchema requires id and type; namespace — the mandatory prefix of
every object name, and therefore each object's table name and REST path — was
absent too. defineStack refuses that, so the project a documented command had
just 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:

defineStack validation failed (2 issues):
x manifest.id: Required property 'id' is missing.
x manifest.type: Invalid value ''. Did you mean one of: 'ui', 'app'?

Every factual claim in the card holds. init.ts's three templates all stamp
id / namespace / type / engines.protocol; create's example template
is the one scaffold that had drifted. One clarification, not a correction:
create's plugin template emits no objectstack.config.ts at all — it
scaffolds a Plugin object in src/index.ts — so example is the only
create template ManifestSchema governs.

What changed

packages/cli/src/commands/create.ts (+19/-3) — the example template now
stamps what os init stamps: id: 'com.example.NAMESPACE', namespace,
type: 'app' and engines: { protocol: '^PROTOCOL_MAJOR' }, alongside the
version / name / description it already carried. The namespace comes from
init's own exported sanitizeNamespace, and the protocol range from the same
PROTOCOL_MAJOR constant init stamps, so the two scaffolders cannot answer
differently 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) — the
pin the card asks for. It sweeps both scaffolders: every init and create
template that emits an objectstack.config.ts is rendered through its own
emitter (configContent + writeTemplateSrcFiles for init; the .ts entries
of the files map for create), written to a throwaway directory under the
package's git-ignored tmp/, loaded back through bundle-require — the same
loader scaffold-validate.ts uses — and its manifest parsed through the real
ManifestSchema. Nothing is hand-copied: the population is derived from the two
template maps, so a template added later is swept the day it is added.

The standalone ManifestSchema parse is not redundant with the defineStack
call above it. ObjectStackDefinitionSchema.manifest is .optional(), so a
template that drops the block entirely, or one that calls
defineStack(config, { strict: false }), loads green at that door and ships a
project with no id, namespace or type. The header states both.

.changeset/create-scaffold-manifest-identity.mdpatch for
@objectstack/cli.

File face

.changeset/create-scaffold-manifest-identity.md +37
packages/cli/src/commands/create.ts +19 -3
packages/cli/test/scaffold-manifest-schema.test.ts +223

Three files. packages/spec is untouched — the honest fix needed no schema
change; the scaffold was simply not declaring what the schema has always
required.

Measurements — all at 1a30e47e09, this PR's head

Reverse verification (three legs, one script, trap ... EXIT INT TERM).
Committed first, so the restore leg's reference (HEAD) already carried the fix.

legtreeresult
1fixedTest Files 5 passed (5) · Tests 43 passed (43)
2create.ts reverted to origin/mainTests 1 failed | 5 passed (6) — the single failure is create:example, with the diagnostic quoted above
3restoredblob hash back to 779e4fecfd, git diff HEAD empty

Mutation proved on disk, not by exit code: HEAD_BLOB=779e4fecfd... vs
MUT_BLOB=f706bb2199... (differ, non-empty), and the mutated file's
sanitizeNamespace / PROTOCOL_MAJOR occurrence counts both dropped to 0.
Restore proved the same way — the hash returned to HEAD_BLOB and the diff is
empty. The ablation direction is a plain red, and only in the scaffold the card
names: the three init scaffolds stayed green through both legs, so the pin is
specific 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.ts

Typecheck.pnpm --filter @objectstack/cli typecheck exit 0 (script echoed
tsc --noEmit, so not a zero-match pass). --listFiles says what that covers
and what it does not: src/commands/create.ts is in the program (1 hit); the
new test file is not (0 hits) — this package's tsconfig.json is
include: ["src"], which is why it carries a TEST_DEBT entry. So that green
says nothing about the new test, and the ratchet is measured separately below.

ESLint.pnpm lint — the whole repo, eslint . --no-inline-config — exit
0. No narrowing claimed and none needed.

Gate families.node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack
derives 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 test log and there is none locally. CI passes
    the path on every invocation.
  • node scripts/pm/check-half-states.mjs — exit 3, PREREQUISITE NOT MET: it
    needs repo-scoped REST egress this container does not have.
  • pnpm check:type-check-debt (--re-measure) — killed by the 10-minute
    foreground ceiling mid-sweep; it re-runs tsc across 10 ledger packages.
    Substituted with a targeted measurement of the same quantity: a probe
    config extending this package's own tsconfig.json with
    include: ["src", "test"] reports 144 errors — exactly the frozen
    TEST_DEBT['@objectstack/cli'].errors of 144 — and zero of them are in
    scaffold-manifest-schema.test.ts. The new test file therefore cannot push
    the ratchet up. The probe config was deleted; it is not in the diff.

pnpm check:i18n, check:i18n-coverage and check:dual-build-cjs-loads each
refused 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 create is untouched as a command. Not removed, not deprecated, not
    redirected at os init, and it does not call init internally. Whether two
    scaffolders should coexist is a CLI-surface decision and is not this PR's.
    Fixing the template forecloses nothing there.
  • packages/spec is untouched. No schema change was needed or made.
  • create's plugin template is untouched. It emits no package manifest,
    so ManifestSchema has nothing to say about it, and pretending otherwise
    would have put a surface in the sweep that the schema does not govern.
  • The scaffold's package.json / tsconfig.json are 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

…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
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/cli, touching 1 documentable anchor(s).

4 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/deployment/cli.mdx(via os create (command, read off packages/cli/src/commands/create.ts))
  • content/docs/plugins/index.mdx(via os create (command, read off packages/cli/src/commands/create.ts))
  • content/docs/protocol/kernel/index.mdx(via os create (command, read off packages/cli/src/commands/create.ts))
  • content/docs/protocol/kernel/plugin-spec.mdx(via os create (command, read off packages/cli/src/commands/create.ts))
What this run could not see
  • 1 anchor(s) matched too much of the corpus to be a work list: objectstack.config.ts (literal, 32 pages)
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 22 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 5a5336b399db2ef18dd4700f97d579a328197ddapackageMentionDocs.

Which tree this was computed on

This run read content/docs from 1b77c4b5450e40755f2b69dc665a2a026eaa9604 — the merge of head 1a30e47e0915a10a4beaa9459402843c46690165 into base 5a5336b399db2ef18dd4700f97d579a328197dda, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# 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

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 5a5336b399db2ef18dd4700f97d579a328197dda → pass the list as
args.docs, on the commit named under Which tree this was computed on.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/mteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

os create template manifest fails ManifestSchema — the scaffold in packages/cli/src/commands/create.ts declares neither id nor type

2 participants

@os-trump@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(cli): stamp the manifest identity block in the os create example scaffold - #14821

Draft
os-trump wants to merge 2 commits into
mainfrom
claude/issue-14705-create-template-manifest
Draft

fix(cli): stamp the manifest identity block in the os create example scaffold#14821
os-trump wants to merge 2 commits into
mainfrom
claude/issue-14705-create-template-manifest

Conversation

@os-trump

Copy link
Copy Markdown
Collaborator

Fixes#14705

What was wrong, re-verified on origin/main

os create example [name] wrote an objectstack.config.ts whose manifest:
block was name, version, description — nothing else
(packages/cli/src/commands/create.ts:130, confirmed at merge base 8f9ef6f7c8).
ManifestSchema requires id and type; namespace — the mandatory prefix of
every object name, and therefore each object's table name and REST path — was
absent too. defineStack refuses that, so the project a documented command had
just 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:

defineStack validation failed (2 issues):
x manifest.id: Required property 'id' is missing.
x manifest.type: Invalid value ''. Did you mean one of: 'ui', 'app'?

Every factual claim in the card holds. init.ts's three templates all stamp
id / namespace / type / engines.protocol; create's example template
is the one scaffold that had drifted. One clarification, not a correction:
create's plugin template emits no objectstack.config.ts at all — it
scaffolds a Plugin object in src/index.ts — so example is the only
create template ManifestSchema governs.

What changed

packages/cli/src/commands/create.ts (+19/-3) — the example template now
stamps what os init stamps: id: 'com.example.NAMESPACE', namespace,
type: 'app' and engines: { protocol: '^PROTOCOL_MAJOR' }, alongside the
version / name / description it already carried. The namespace comes from
init's own exported sanitizeNamespace, and the protocol range from the same
PROTOCOL_MAJOR constant init stamps, so the two scaffolders cannot answer
differently 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) — the
pin the card asks for. It sweeps both scaffolders: every init and create
template that emits an objectstack.config.ts is rendered through its own
emitter (configContent + writeTemplateSrcFiles for init; the .ts entries
of the files map for create), written to a throwaway directory under the
package's git-ignored tmp/, loaded back through bundle-require — the same
loader scaffold-validate.ts uses — and its manifest parsed through the real
ManifestSchema. Nothing is hand-copied: the population is derived from the two
template maps, so a template added later is swept the day it is added.

The standalone ManifestSchema parse is not redundant with the defineStack
call above it. ObjectStackDefinitionSchema.manifest is .optional(), so a
template that drops the block entirely, or one that calls
defineStack(config, { strict: false }), loads green at that door and ships a
project with no id, namespace or type. The header states both.

.changeset/create-scaffold-manifest-identity.mdpatch for
@objectstack/cli.

File face

.changeset/create-scaffold-manifest-identity.md +37
packages/cli/src/commands/create.ts +19 -3
packages/cli/test/scaffold-manifest-schema.test.ts +223

Three files. packages/spec is untouched — the honest fix needed no schema
change; the scaffold was simply not declaring what the schema has always
required.

Measurements — all at 1a30e47e09, this PR's head

Reverse verification (three legs, one script, trap ... EXIT INT TERM).
Committed first, so the restore leg's reference (HEAD) already carried the fix.

legtreeresult
1fixedTest Files 5 passed (5) · Tests 43 passed (43)
2create.ts reverted to origin/mainTests 1 failed | 5 passed (6) — the single failure is create:example, with the diagnostic quoted above
3restoredblob hash back to 779e4fecfd, git diff HEAD empty

Mutation proved on disk, not by exit code: HEAD_BLOB=779e4fecfd... vs
MUT_BLOB=f706bb2199... (differ, non-empty), and the mutated file's
sanitizeNamespace / PROTOCOL_MAJOR occurrence counts both dropped to 0.
Restore proved the same way — the hash returned to HEAD_BLOB and the diff is
empty. The ablation direction is a plain red, and only in the scaffold the card
names: the three init scaffolds stayed green through both legs, so the pin is
specific 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.ts

Typecheck.pnpm --filter @objectstack/cli typecheck exit 0 (script echoed
tsc --noEmit, so not a zero-match pass). --listFiles says what that covers
and what it does not: src/commands/create.ts is in the program (1 hit); the
new test file is not (0 hits) — this package's tsconfig.json is
include: ["src"], which is why it carries a TEST_DEBT entry. So that green
says nothing about the new test, and the ratchet is measured separately below.

ESLint.pnpm lint — the whole repo, eslint . --no-inline-config — exit
0. No narrowing claimed and none needed.

Gate families.node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack
derives 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 test log and there is none locally. CI passes
    the path on every invocation.
  • node scripts/pm/check-half-states.mjs — exit 3, PREREQUISITE NOT MET: it
    needs repo-scoped REST egress this container does not have.
  • pnpm check:type-check-debt (--re-measure) — killed by the 10-minute
    foreground ceiling mid-sweep; it re-runs tsc across 10 ledger packages.
    Substituted with a targeted measurement of the same quantity: a probe
    config extending this package's own tsconfig.json with
    include: ["src", "test"] reports 144 errors — exactly the frozen
    TEST_DEBT['@objectstack/cli'].errors of 144 — and zero of them are in
    scaffold-manifest-schema.test.ts. The new test file therefore cannot push
    the ratchet up. The probe config was deleted; it is not in the diff.

pnpm check:i18n, check:i18n-coverage and check:dual-build-cjs-loads each
refused 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 create is untouched as a command. Not removed, not deprecated, not
    redirected at os init, and it does not call init internally. Whether two
    scaffolders should coexist is a CLI-surface decision and is not this PR's.
    Fixing the template forecloses nothing there.
  • packages/spec is untouched. No schema change was needed or made.
  • create's plugin template is untouched. It emits no package manifest,
    so ManifestSchema has nothing to say about it, and pretending otherwise
    would have put a surface in the sweep that the schema does not govern.
  • The scaffold's package.json / tsconfig.json are 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

…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
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/cli, touching 1 documentable anchor(s).

4 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/deployment/cli.mdx(via os create (command, read off packages/cli/src/commands/create.ts))
  • content/docs/plugins/index.mdx(via os create (command, read off packages/cli/src/commands/create.ts))
  • content/docs/protocol/kernel/index.mdx(via os create (command, read off packages/cli/src/commands/create.ts))
  • content/docs/protocol/kernel/plugin-spec.mdx(via os create (command, read off packages/cli/src/commands/create.ts))
What this run could not see
  • 1 anchor(s) matched too much of the corpus to be a work list: objectstack.config.ts (literal, 32 pages)
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 22 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 5a5336b399db2ef18dd4700f97d579a328197ddapackageMentionDocs.

Which tree this was computed on

This run read content/docs from 1b77c4b5450e40755f2b69dc665a2a026eaa9604 — the merge of head 1a30e47e0915a10a4beaa9459402843c46690165 into base 5a5336b399db2ef18dd4700f97d579a328197dda, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# 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

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 5a5336b399db2ef18dd4700f97d579a328197dda → pass the list as
args.docs, on the commit named under Which tree this was computed on.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/mteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

os create template manifest fails ManifestSchema — the scaffold in packages/cli/src/commands/create.ts declares neither id nor type

2 participants

@os-trump@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(cli): stamp the manifest identity block in the os create example scaffold - #14821

Draft
os-trump wants to merge 2 commits into
mainfrom
claude/issue-14705-create-template-manifest
Draft

fix(cli): stamp the manifest identity block in the os create example scaffold#14821
os-trump wants to merge 2 commits into
mainfrom
claude/issue-14705-create-template-manifest

Conversation

@os-trump

Copy link
Copy Markdown
Collaborator

Fixes#14705

What was wrong, re-verified on origin/main

os create example [name] wrote an objectstack.config.ts whose manifest:
block was name, version, description — nothing else
(packages/cli/src/commands/create.ts:130, confirmed at merge base 8f9ef6f7c8).
ManifestSchema requires id and type; namespace — the mandatory prefix of
every object name, and therefore each object's table name and REST path — was
absent too. defineStack refuses that, so the project a documented command had
just 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:

defineStack validation failed (2 issues):
x manifest.id: Required property 'id' is missing.
x manifest.type: Invalid value ''. Did you mean one of: 'ui', 'app'?

Every factual claim in the card holds. init.ts's three templates all stamp
id / namespace / type / engines.protocol; create's example template
is the one scaffold that had drifted. One clarification, not a correction:
create's plugin template emits no objectstack.config.ts at all — it
scaffolds a Plugin object in src/index.ts — so example is the only
create template ManifestSchema governs.

What changed

packages/cli/src/commands/create.ts (+19/-3) — the example template now
stamps what os init stamps: id: 'com.example.NAMESPACE', namespace,
type: 'app' and engines: { protocol: '^PROTOCOL_MAJOR' }, alongside the
version / name / description it already carried. The namespace comes from
init's own exported sanitizeNamespace, and the protocol range from the same
PROTOCOL_MAJOR constant init stamps, so the two scaffolders cannot answer
differently 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) — the
pin the card asks for. It sweeps both scaffolders: every init and create
template that emits an objectstack.config.ts is rendered through its own
emitter (configContent + writeTemplateSrcFiles for init; the .ts entries
of the files map for create), written to a throwaway directory under the
package's git-ignored tmp/, loaded back through bundle-require — the same
loader scaffold-validate.ts uses — and its manifest parsed through the real
ManifestSchema. Nothing is hand-copied: the population is derived from the two
template maps, so a template added later is swept the day it is added.

The standalone ManifestSchema parse is not redundant with the defineStack
call above it. ObjectStackDefinitionSchema.manifest is .optional(), so a
template that drops the block entirely, or one that calls
defineStack(config, { strict: false }), loads green at that door and ships a
project with no id, namespace or type. The header states both.

.changeset/create-scaffold-manifest-identity.mdpatch for
@objectstack/cli.

File face

.changeset/create-scaffold-manifest-identity.md +37
packages/cli/src/commands/create.ts +19 -3
packages/cli/test/scaffold-manifest-schema.test.ts +223

Three files. packages/spec is untouched — the honest fix needed no schema
change; the scaffold was simply not declaring what the schema has always
required.

Measurements — all at 1a30e47e09, this PR's head

Reverse verification (three legs, one script, trap ... EXIT INT TERM).
Committed first, so the restore leg's reference (HEAD) already carried the fix.

legtreeresult
1fixedTest Files 5 passed (5) · Tests 43 passed (43)
2create.ts reverted to origin/mainTests 1 failed | 5 passed (6) — the single failure is create:example, with the diagnostic quoted above
3restoredblob hash back to 779e4fecfd, git diff HEAD empty

Mutation proved on disk, not by exit code: HEAD_BLOB=779e4fecfd... vs
MUT_BLOB=f706bb2199... (differ, non-empty), and the mutated file's
sanitizeNamespace / PROTOCOL_MAJOR occurrence counts both dropped to 0.
Restore proved the same way — the hash returned to HEAD_BLOB and the diff is
empty. The ablation direction is a plain red, and only in the scaffold the card
names: the three init scaffolds stayed green through both legs, so the pin is
specific 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.ts

Typecheck.pnpm --filter @objectstack/cli typecheck exit 0 (script echoed
tsc --noEmit, so not a zero-match pass). --listFiles says what that covers
and what it does not: src/commands/create.ts is in the program (1 hit); the
new test file is not (0 hits) — this package's tsconfig.json is
include: ["src"], which is why it carries a TEST_DEBT entry. So that green
says nothing about the new test, and the ratchet is measured separately below.

ESLint.pnpm lint — the whole repo, eslint . --no-inline-config — exit
0. No narrowing claimed and none needed.

Gate families.node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack
derives 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 test log and there is none locally. CI passes
    the path on every invocation.
  • node scripts/pm/check-half-states.mjs — exit 3, PREREQUISITE NOT MET: it
    needs repo-scoped REST egress this container does not have.
  • pnpm check:type-check-debt (--re-measure) — killed by the 10-minute
    foreground ceiling mid-sweep; it re-runs tsc across 10 ledger packages.
    Substituted with a targeted measurement of the same quantity: a probe
    config extending this package's own tsconfig.json with
    include: ["src", "test"] reports 144 errors — exactly the frozen
    TEST_DEBT['@objectstack/cli'].errors of 144 — and zero of them are in
    scaffold-manifest-schema.test.ts. The new test file therefore cannot push
    the ratchet up. The probe config was deleted; it is not in the diff.

pnpm check:i18n, check:i18n-coverage and check:dual-build-cjs-loads each
refused 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 create is untouched as a command. Not removed, not deprecated, not
    redirected at os init, and it does not call init internally. Whether two
    scaffolders should coexist is a CLI-surface decision and is not this PR's.
    Fixing the template forecloses nothing there.
  • packages/spec is untouched. No schema change was needed or made.
  • create's plugin template is untouched. It emits no package manifest,
    so ManifestSchema has nothing to say about it, and pretending otherwise
    would have put a surface in the sweep that the schema does not govern.
  • The scaffold's package.json / tsconfig.json are 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

…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
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/cli, touching 1 documentable anchor(s).

4 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/deployment/cli.mdx(via os create (command, read off packages/cli/src/commands/create.ts))
  • content/docs/plugins/index.mdx(via os create (command, read off packages/cli/src/commands/create.ts))
  • content/docs/protocol/kernel/index.mdx(via os create (command, read off packages/cli/src/commands/create.ts))
  • content/docs/protocol/kernel/plugin-spec.mdx(via os create (command, read off packages/cli/src/commands/create.ts))
What this run could not see
  • 1 anchor(s) matched too much of the corpus to be a work list: objectstack.config.ts (literal, 32 pages)
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 22 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 5a5336b399db2ef18dd4700f97d579a328197ddapackageMentionDocs.

Which tree this was computed on

This run read content/docs from 1b77c4b5450e40755f2b69dc665a2a026eaa9604 — the merge of head 1a30e47e0915a10a4beaa9459402843c46690165 into base 5a5336b399db2ef18dd4700f97d579a328197dda, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# 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

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 5a5336b399db2ef18dd4700f97d579a328197dda → pass the list as
args.docs, on the commit named under Which tree this was computed on.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/mteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

os create template manifest fails ManifestSchema — the scaffold in packages/cli/src/commands/create.ts declares neither id nor type

2 participants

@os-trump@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

fix(cli): stamp the manifest identity block in the os create example scaffold - #14821

Draft
os-trump wants to merge 2 commits into
mainfrom
claude/issue-14705-create-template-manifest
Draft

fix(cli): stamp the manifest identity block in the os create example scaffold#14821
os-trump wants to merge 2 commits into
mainfrom
claude/issue-14705-create-template-manifest

Conversation

@os-trump

Copy link
Copy Markdown
Collaborator

Fixes#14705

What was wrong, re-verified on origin/main

os create example [name] wrote an objectstack.config.ts whose manifest:
block was name, version, description — nothing else
(packages/cli/src/commands/create.ts:130, confirmed at merge base 8f9ef6f7c8).
ManifestSchema requires id and type; namespace — the mandatory prefix of
every object name, and therefore each object's table name and REST path — was
absent too. defineStack refuses that, so the project a documented command had
just 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:

defineStack validation failed (2 issues):
x manifest.id: Required property 'id' is missing.
x manifest.type: Invalid value ''. Did you mean one of: 'ui', 'app'?

Every factual claim in the card holds. init.ts's three templates all stamp
id / namespace / type / engines.protocol; create's example template
is the one scaffold that had drifted. One clarification, not a correction:
create's plugin template emits no objectstack.config.ts at all — it
scaffolds a Plugin object in src/index.ts — so example is the only
create template ManifestSchema governs.

What changed

packages/cli/src/commands/create.ts (+19/-3) — the example template now
stamps what os init stamps: id: 'com.example.NAMESPACE', namespace,
type: 'app' and engines: { protocol: '^PROTOCOL_MAJOR' }, alongside the
version / name / description it already carried. The namespace comes from
init's own exported sanitizeNamespace, and the protocol range from the same
PROTOCOL_MAJOR constant init stamps, so the two scaffolders cannot answer
differently 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) — the
pin the card asks for. It sweeps both scaffolders: every init and create
template that emits an objectstack.config.ts is rendered through its own
emitter (configContent + writeTemplateSrcFiles for init; the .ts entries
of the files map for create), written to a throwaway directory under the
package's git-ignored tmp/, loaded back through bundle-require — the same
loader scaffold-validate.ts uses — and its manifest parsed through the real
ManifestSchema. Nothing is hand-copied: the population is derived from the two
template maps, so a template added later is swept the day it is added.

The standalone ManifestSchema parse is not redundant with the defineStack
call above it. ObjectStackDefinitionSchema.manifest is .optional(), so a
template that drops the block entirely, or one that calls
defineStack(config, { strict: false }), loads green at that door and ships a
project with no id, namespace or type. The header states both.

.changeset/create-scaffold-manifest-identity.mdpatch for
@objectstack/cli.

File face

.changeset/create-scaffold-manifest-identity.md +37
packages/cli/src/commands/create.ts +19 -3
packages/cli/test/scaffold-manifest-schema.test.ts +223

Three files. packages/spec is untouched — the honest fix needed no schema
change; the scaffold was simply not declaring what the schema has always
required.

Measurements — all at 1a30e47e09, this PR's head

Reverse verification (three legs, one script, trap ... EXIT INT TERM).
Committed first, so the restore leg's reference (HEAD) already carried the fix.

legtreeresult
1fixedTest Files 5 passed (5) · Tests 43 passed (43)
2create.ts reverted to origin/mainTests 1 failed | 5 passed (6) — the single failure is create:example, with the diagnostic quoted above
3restoredblob hash back to 779e4fecfd, git diff HEAD empty

Mutation proved on disk, not by exit code: HEAD_BLOB=779e4fecfd... vs
MUT_BLOB=f706bb2199... (differ, non-empty), and the mutated file's
sanitizeNamespace / PROTOCOL_MAJOR occurrence counts both dropped to 0.
Restore proved the same way — the hash returned to HEAD_BLOB and the diff is
empty. The ablation direction is a plain red, and only in the scaffold the card
names: the three init scaffolds stayed green through both legs, so the pin is
specific 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.ts

Typecheck.pnpm --filter @objectstack/cli typecheck exit 0 (script echoed
tsc --noEmit, so not a zero-match pass). --listFiles says what that covers
and what it does not: src/commands/create.ts is in the program (1 hit); the
new test file is not (0 hits) — this package's tsconfig.json is
include: ["src"], which is why it carries a TEST_DEBT entry. So that green
says nothing about the new test, and the ratchet is measured separately below.

ESLint.pnpm lint — the whole repo, eslint . --no-inline-config — exit
0. No narrowing claimed and none needed.

Gate families.node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack
derives 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 test log and there is none locally. CI passes
    the path on every invocation.
  • node scripts/pm/check-half-states.mjs — exit 3, PREREQUISITE NOT MET: it
    needs repo-scoped REST egress this container does not have.
  • pnpm check:type-check-debt (--re-measure) — killed by the 10-minute
    foreground ceiling mid-sweep; it re-runs tsc across 10 ledger packages.
    Substituted with a targeted measurement of the same quantity: a probe
    config extending this package's own tsconfig.json with
    include: ["src", "test"] reports 144 errors — exactly the frozen
    TEST_DEBT['@objectstack/cli'].errors of 144 — and zero of them are in
    scaffold-manifest-schema.test.ts. The new test file therefore cannot push
    the ratchet up. The probe config was deleted; it is not in the diff.

pnpm check:i18n, check:i18n-coverage and check:dual-build-cjs-loads each
refused 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 create is untouched as a command. Not removed, not deprecated, not
    redirected at os init, and it does not call init internally. Whether two
    scaffolders should coexist is a CLI-surface decision and is not this PR's.
    Fixing the template forecloses nothing there.
  • packages/spec is untouched. No schema change was needed or made.
  • create's plugin template is untouched. It emits no package manifest,
    so ManifestSchema has nothing to say about it, and pretending otherwise
    would have put a surface in the sweep that the schema does not govern.
  • The scaffold's package.json / tsconfig.json are 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

…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
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/cli, touching 1 documentable anchor(s).

4 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/deployment/cli.mdx(via os create (command, read off packages/cli/src/commands/create.ts))
  • content/docs/plugins/index.mdx(via os create (command, read off packages/cli/src/commands/create.ts))
  • content/docs/protocol/kernel/index.mdx(via os create (command, read off packages/cli/src/commands/create.ts))
  • content/docs/protocol/kernel/plugin-spec.mdx(via os create (command, read off packages/cli/src/commands/create.ts))
What this run could not see
  • 1 anchor(s) matched too much of the corpus to be a work list: objectstack.config.ts (literal, 32 pages)
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 22 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 5a5336b399db2ef18dd4700f97d579a328197ddapackageMentionDocs.

Which tree this was computed on

This run read content/docs from 1b77c4b5450e40755f2b69dc665a2a026eaa9604 — the merge of head 1a30e47e0915a10a4beaa9459402843c46690165 into base 5a5336b399db2ef18dd4700f97d579a328197dda, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# 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

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 5a5336b399db2ef18dd4700f97d579a328197dda → pass the list as
args.docs, on the commit named under Which tree this was computed on.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/mteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

os create template manifest fails ManifestSchema — the scaffold in packages/cli/src/commands/create.ts declares neither id nor type

2 participants

@os-trump@claude