Uh oh!
There was an error while loading. Please reload this page.
fix(cli): make os init's rendered template comments self-contained - #11192
Conversation
packages/cli/src/commands/init.ts renders its templates as string literals and writes them into the user's project. Five of those literals carried ADR identifiers (ADR-0087, ADR-0090 D1) addressed to a reader with this monorepo open; a project scaffolded by `os init` ships no docs/adr/, so the identifier named something unfollowable. Rewrite each self-contained, keeping the rationale, and link the same public docs routes #10324 verified for create-objectstack: - protocol range -> https://objectstack.ai/docs/upgrading - org-wide default -> https://objectstack.ai/docs/permissions/sharing-rules Add a pin that renders every TEMPLATES entry through init's own emitter (configContent / writeTemplateSrcFiles) and scans the rendered output -- not the source file -- so it cannot be confused by init.ts's own ordinary source comments that legitimately cite ADRs and issue numbers. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bmVFqoQPq63zhKrxdYG1r
…n a comment mention The pin's docblock backtick-quoted a scripts/*.mjs path, which the cross-package-test-inputs gate's literal collector reads the same as a real quoted specifier. Reword to match the established convention (no scripts/ prefix, no quoting) instead of widening the package's declared turbo glob for a path nothing actually reads. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bmVFqoQPq63zhKrxdYG1r
📓 Docs Drift CheckThis PR changes 1 package(s): 3 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 1 release-owned page(s) also name something this change touched. These are read-only:
What this run could not seeCoarse fallback — 23 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 95e7c43afd9569e64662d6de74e282a56a5e19a7 && git checkout 95e7c43afd9569e64662d6de74e282a56a5e19a7
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 2b5a7ce59b57231e6702e63b876ae335a8e71f24 6ff5a4345d4794a1eb14804eea73b46818894195 && git checkout -B drift-repro 2b5a7ce59b57231e6702e63b876ae335a8e71f24 && git merge --no-ff 6ff5a4345d4794a1eb14804eea73b46818894195
node scripts/docs-audit/affected-docs.mjs --json 2b5a7ce59b57231e6702e63b876ae335a8e71f24
|
Uh oh!
There was an error while loading. Please reload this page.
Fixes#11023
Premise check
Re-measured at
origin/mainbefore editing: the card's line numbers had drifted (as the claim comment already flagged), but the mechanism was intact. Located by text, confirmed at:// Protocol major this app is authored against (ADR-0087 load-time check).:397// Org-wide default (OWD): who can see records they do NOT own. ADR-0090 D1:433// Protocol major this plugin is authored against (ADR-0087 load-time check).:477// Org-wide default (OWD): who can see records they do NOT own. ADR-0090 D1:499// Protocol major this app is authored against (ADR-0087 load-time check).:540:488's (now:572)#10499is confirmed to be an ordinary in-repo JSDoc comment onprintCreatedFilesSummary— outside everyconfigContent/srcFilesfunction, so it never reachesfs.writeFileSyncand does not ship. Premise holds in full.The ships-vs-source boundary
init.tswrites to the user's project through exactly two paths:template.configContent(name, namespace)→objectstack.config.ts, andwriteTemplateSrcFiles(template.srcFiles, ...)→ everything undersrc/. Both are called fromTEMPLATES[key]. Anything inside those functions' template-literal bodies ships; anything outside them (helper functions, their own JSDoc, module-level comments) isinit.ts's own source and never leaves this repo. All five hits sit inside theapp/plugin/emptyconfigContent/srcFilesbodies; the#10499JSDoc does not.The fix
Rewrote each comment self-contained, keeping the rationale, using the wording #10324 settled on:
https://objectstack.ai/docs/upgradinghttps://objectstack.ai/docs/permissions/sharing-rulesBoth routes verified to resolve against
content/docsbefore committing (content/docs/upgrading.mdx,content/docs/permissions/sharing-rules.mdxboth exist) and re-asserted by the pin's own assertion 3.The pin
packages/cli/test/init-template-comments-self-contained.test.ts. Per the card's own warning, the population is template literals rendered byinit.ts, not the source file — a wholesale grep ofinit.tswould also match its legitimate own comments (e.g. the#10499JSDoc) and report on the wrong population. The pin reaches the real population directly: it callstemplate.configContent(...)andwriteTemplateSrcFiles(...)— the exact functionsinit's command handler calls — and writes them to real files in a throwaway dir, exactly mirroringinit-scaffold-authoring-rules.test.ts's existinggenerate()pattern. It then scans only what those functions produced.Two-sided, matching #10324's shape:
MONOREPO_ONLY(ADR id / bare issue / script path / package path), reused verbatim fromstarter-comments-self-contained.test.ts.content/docsthe way Fumadocs routes it.Vacuity guards throughout: a template-count / file-presence check before assertion 1, a non-empty object-file-list check before assertion 2, and a non-zero-URL-count check before assertion 3 (so an extractor that silently stopped matching would fail loud instead of vacuously passing).
Reverse-verification performed: committed the fix, then
git checkout origin/main -- packages/cli/src/commands/init.tsto restore the pre-fix text on top of the new pin. Result: 9 of 15 cases went red, each for the intended reason — assertion 1 caught all 5 ADR identifiers by name (app,plugin,emptyconfigs + both OWD object files), assertion 2 correctly failed to find the new wording, and assertion 3's own non-vacuity guard reported "no canonical docs URLs found" (there weren't any pre-fix). Thengit checkout HEAD -- packages/cli/src/commands/init.tsrestored the fix (git status --porcelainclean against HEAD), and the full 15/15 green again.Real-thing verification: built the CLI and ran the
initcommand for real against a temp directory, with--no-install, once per built-in template (app, plugin, empty). Swept the generated projects on disk with the sameMONOREPO_ONLYpattern set — zero matches — and confirmed both docs URLs appear verbatim in the generated files (5 occurrences total, matching the 5 original hits).Gate verdicts (derived via
node scripts/pm/dispatch-gates.mjsat commit6ff5a4345d)pnpm --filter @objectstack/cli test—Test Files 160 passed (160),Tests 1757 passed (1757)(full package suite); pin file alone re-verified at final HEAD:Test Files 3 passed (3),Tests 76 passed (76).pnpm --filter @objectstack/cli typecheck— clean (tsc --noEmit, no output).pnpm --filter @objectstack/cli build— clean.pnpm check:cross-package-test-inputs—OK: 13 package(s) read outside themselves, all declared, and turbo.json hashes every declared glob.(Note: an earlier draft of the pin's docblock backtick-quoted ascripts/*.mjspath in prose; the gate's literal collector reads a backtick-quoted path the same as a real specifier. Reworded to match the established convention — noscripts/prefix, no quoting — rather than widening the package's declared turbo glob for a path nothing reads.)pnpm check:slot-lookup—slot-lookup ratchet holds: 107 unswept site(s) in 25 file(s), none new.pnpm check:test-source-alias—check-test-source-alias OK.pnpm check:type-source-resolution—check-type-source-resolution OK.node scripts/check-ci-filter-parity.mjs—OK: all 86 declared cross-package glob(s) ... covered.node scripts/check-cross-package-test-inputs.mjs— same OK as above (root-level invocation).node scripts/check-plugin-teardown-shape.mjs—0 known-unreached, SHRINK-ONLY, baseline fully burned down.node scripts/docs-audit/check-affected-docs.mjs— self-test + scan both clean (exit 0).pnpm check:query-options-erasure—ratchet holds ... none new.pnpm check:engine-double-contract—OK: 384 pinned, 133 in the DEBT ledger, 2 exempt(no new doubles from this PR).pnpm check:where-matcher—0 silently-wrong and 0 unjudged matcher(s) ... none new.pnpm check:type-check-coverage/pnpm check:type-check-debt— required a full workspace-closure build first (pnpm exec turbo run build --filter='./packages/*' --filter='./packages/*/*', ~5m24s); re-measured clean:check-type-check-coverage --re-measure: OK — 33 ledger entr(ies) re-measured ... none above its recorded number.check:changeset-gate-self-tests,check:objectui-changesetself-tests all pass;check-adr-0087-registration: this PR adds no declared-breaking changeset;check-changeset-no-major: This diff introduces no major bump;check-empty-changeset: No empty-frontmatter changeset introduced.All commands run through
scripts/pm/os-verify-lock.sh.Out of scope
Nothing found outside this card's surface during this pass.
Generated by Claude Code