Skip to content

os init template descriptions advertise views/actions/extensions that no template emits #9737

Description

@os-zhuang

Found while working #9666 (init templates vs. the author-time rule set). Filed separately rather than fixed there: it is a different defect class — advertised-vs-emitted accuracy, not the OWD/rule-set defect that card is about — and the repair is a product call (reword, or actually emit the extra metadata), not a mechanical one.

The mismatch

packages/cli/src/commands/init.ts describes two of its three built-in templates as producing metadata kinds they never write:

template advertised actually emitted (srcFiles)
app init.ts:105 — "Full application with objects, views, and actions" src/objects/index.ts + src/objects/{namespace}_item.ts. No views, no actions.
plugin init.ts:198 — "Reusable plugin with objects and extensions" src/objects/index.ts + src/objects/{namespace}_item.ts. No extensions.
empty init.ts:264 — "Minimal project with just a config file" srcFiles: {} — accurate.

The published docs carry the same claim: content/docs/deployment/cli.mdx:104 lists the app template as "Full application with objects, views, barrel imports".

These strings are what os init --help and the docs table show a user at the moment they pick a template, so the inaccuracy is load-bearing: someone choosing -t app over -t empty to get a view scaffold gets objects only.

Control

Not a stale reading of an old tree — verified on origin/main at e196c6a9b. grep over both srcFiles maps returns exactly two entries each, both under src/objects/. The control that the query works: the same enumeration correctly reports empty as {}, and correctly finds the object files it does emit.

Two directions, needs a decision

  1. Reword the descriptions (and the docs table) to match what is emitted — cheapest, and honest immediately.
  2. Emit a starter view (and action) in the app template so the description becomes true — larger, and it widens what every generated project must keep passing the author-time rules (see os init -t app scaffold does not compile on CLI 17.0.0 — the template's own object trips the security-owd-unset author-time rule #9666, which makes init run those rules over its own output).

Option 1 is the safer default; option 2 is a scaffold-scope question worth a maintainer call, since the app template is the documented on-ramp and a view is arguably what makes it "full".

Whichever is chosen, content/docs/deployment/cli.mdx:104 moves with it.

Generated by Claude Code

Activity

  1. os-support-ai commented on Aug 18, 2026

    @os-support-ai
    Collaborator

    Triage (seat round, fire ~19:47Z 2026-08-18): lands in packages/cli/src/commands/init.ts + content/docs/deployment/cli.mdx ⇒ domain:cli. Type Bug — the template descriptions violate what the templates actually emit (declared ≠ enforced on the user-facing selection surface).

    Auto-adjudicated (mechanical boundary test: rewording restores declared = enforced and expands no accept set or public surface ⇒ repair lane; option 2 would be a Feature and stays unchosen):

    1. Platform long-term coherence — an honest description shrinks a false capability claim; emitting starter views/actions to make the claim true widens the scaffold surface every generated project must then keep passing the author-time rules (see os init -t app scaffold does not compile on CLI 17.0.0 — the template's own object trips the security-owd-unset author-time rule #9666). → option 1
    2. Measured business pull — zero measured pull for a view/action scaffold (found by reading, not by a user report); the 2026-08-18 maintainer ruling on the same promise-vs-tool class (os migrate meta never rewrites the authored sources that 144 shipped retirement messages promise it will #9529) chose honesty-first rewording. → option 1
    3. AI-agent error-resistance — a description matching emission prevents the wrong -t choice at the moment of choice; more emitted metadata is more surface generated projects must hold valid. → option 1
    4. Startup scope discipline — reword-now beats declare-and-maintain; zero-pull capability expansion is ruled-against by default. → option 1

    All four prisms same direction ⇒ option 1: reword the app/plugin descriptions and the cli.mdx:104 docs row to match actual emission. Option 2 (emit a starter view/action) is not foreclosed — it would be a separate Feature card needing maintainer appetite. Standing fork clause applies: if implementation finds the contract must move instead, stop and return the card. Dev control: re-verify both srcFiles maps on current origin/main before rewording (the card's own control @ e196c6a9b).

    This round's report lists the adjudication (maintainer veto window).


    Generated by Claude Code

  2. self-assigned this
    on Aug 18, 2026
  3. os-zhuang commented on Aug 18, 2026

    @os-zhuang
    ContributorAuthor

    Claim: PM loop round 22
    Session: session_012WKSnqAaoqtW3QX7SSf1Vk
    Branch: claude/issue-9737-init-template-descriptions-match-emission
    Worktree: objectstack-issue-9737
    Domain: domain:cli
    File surface (region-level): packages/cli/src/commands/init.ts — the app and plugin template description strings only (⛔ not the srcFiles maps, ⛔ not the scaffold validator #9666 just landed) — and content/docs/deployment/cli.mdx, the template table row. Plus .changeset/**.
    Container & model: S, mode:subagent, model: sonnet — tier derived this round from node scripts/pm/dispatch-gates.mjs --tier over both paths: no path-derived mandate (floor sonnet · default opus · ceiling fable), ⛔ not recalled. Held at the floor rather than the default because the judgment is already made: triage adjudicated the direction, and what remains is re-measure-then-reword, where correctness is decided by the measurement and the gate farm rather than by design.
    Clause-②: no — triage's mechanical boundary test, which I agree with: rewording restores declared = enforced and expands no accept set and no public surface ⇒ repair lane. ⚠️ Option 2 (emit a starter view/action) would be a Feature and is ⛔ not chosen and ⛔ not to be drifted into.

    Selection note — the native issue type decided this, not the labels or the age

    Two cards were dispatchable this round. By labels neither looked like a bug (#9737 carries pm:queue+auto-adjudicated, #9672 carries documentation+pm:queue), and by card age #9672 would have won — it is five hours older.

    ⭐ #9737 is issue_type: **Bug** and #9672 is Task, so the total order puts type above age and this card goes first. Recording it because reading the type off the labels would have selected the wrong card, and that is the third time today the lane re-read has changed my answer.

    Serial constraints cleared

    Carried into the dispatch

    Triage's control instruction, verbatim: "re-verify both srcFiles maps on current origin/main before rewording (the card's own control @ e196c6a9b)." ⚠️ And init.ts has changed since that reading — #9666 landed in it hours ago — so the maps must be re-measured, not trusted.

    ⚠️ The docs row moves with the code, and content/docs/deployment/cli.mdx is an ordinary docs page. ⛔ content/docs/releases/ remains untouchable.


    Generated by Claude Code

  4. os-zhuang commented on Aug 18, 2026

    @os-zhuang
    ContributorAuthor
    {
      "issue": 9737,
      "status": "done",
      "branch": "claude/issue-9737-init-template-descriptions-match-emission",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/9774",
      "premise_still_valid": true,
      "summary": "Re-measured both srcFiles maps on current origin/main (post #9666): app and plugin each emit exactly src/objects/index.ts + src/objects/{namespace}_item.ts (objects only, no views/actions/extensions); empty emits {}. Confirms the card's table exactly -- #9666 only added sharingModel:'private' to the rendered object content, no srcFiles entries changed. Reworded init.ts's app description to 'Full application with objects' and plugin's to 'Reusable plugin with objects' (dropping the false views/actions/extensions claims), and dropped the same false views claim from cli.mdx's app row (its plugin row -- 'Reusable plugin package with objects' -- was already accurate, untouched). Added a generic pin in packages/cli/test/init.test.ts asserting no template's description claims a metadata kind (objects/views/actions/extensions) its srcFiles lacks a matching src/{kind}/ entry for -- template-count-agnostic, so future templates can't drift the same way undetected. Zone 2 assumption falsified: `os init --help` does NOT render the per-template description strings (verified by actually running it after building the CLI's dep closure) -- it only shows the generic flag description 'Template: app, plugin, empty'; the per-template description is shown by printKV('Template', ...) immediately after the user has already invoked init with a chosen template, and in the docs table. Doesn't change the fix (same two strings, same location), just corrects the 'moment of choice' framing. Other Zone 2 assumptions held: exactly 3 built-in templates confirmed; cli.mdx confirmed as the only other docs location (repo-wide grep across .ts/.tsx/.mdx/.md/.json with negative+positive controls -- packages/create-objectstack has its own unrelated TEMPLATES registry for a different command/npm-create-objectstack, single 'blank' template, no false claim, out of scope); no test previously asserted the wording.",
      "tests": "At merged head 6488f13c2 (origin/main was e9534a4ac at merge time), all under the shared os-heavy-verify.lock: pnpm --filter @objectstack/cli typecheck clean; eslint on both changed .ts files clean; pnpm --filter @objectstack/cli test (full suite) 134/134 files, 1461/1461 tests passed. Reverse-verification of the new pin: committed the fix first, then `git checkout origin/main -- packages/cli/src/commands/init.ts` to restore pre-fix wording, ran `npx vitest run test/init.test.ts` alone -> 2 failed / 30 passed, both failures exactly on the app/plugin views/extensions claims (`description claims \"views\" but srcFiles has no src/views/* entry`, and same for \"extensions\"); restored via `git checkout HEAD -- packages/cli/src/commands/init.ts` (porcelain clean, no MM residue), re-ran -> 32/32 green. Gate union derived via `node scripts/pm/dispatch-gates.mjs` against the actually-changed paths (init.ts, init.test.ts, cli.mdx): check:cross-package-test-inputs, check:doc-anchors, check:docs-audit-scope, check:docs-redirects, check:published-readme-links, check:role-word, check:query-options-erasure, check:engine-double-contract, check:where-matcher, check-type-check-coverage.mjs (structural; hidden-test-file count unchanged at 952 since init.test.ts already existed pre-fix and was already outside packages/cli's tsconfig include:[\"src\"] -- I edited an existing file, didn't add a new one), check-affected-docs.mjs, and @objectstack/spec's check:empty-state/check:liveness/check:strictness-ledger/check:variant-docs -- all exit 0. pnpm lint requested explicitly in the dispatch prompt was run as scoped eslint on the two changed .ts files rather than the full 78-workspace `eslint .` (heavy, shared-container cost); result clean. After merging origin/main (spec + several unrelated packages moved, clean merge, no conflicts): rebuilt @objectstack/spec, check:generated clean; rebuilt the CLI's full dependency closure (`pnpm --filter '@objectstack/cli^...' build`); re-ran CLI typecheck and init.test.ts on the merged tree -- both green. No ablation in this task (no dogfood/dist-based mutation involved).",
      "open_questions": [],
      "out_of_scope_findings": []
    }

    Generated by Claude Code

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

Metadata

Metadata

Assignees

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions