docs(spec): state the template dialect's real placeholder contract - #16416
docs(spec): state the template dialect's real placeholder contract#16416huangyiirene wants to merge 2 commits into
Conversation
`TemplateExpressionInputSchema`'s docblock illustrated the `template`
dialect with `{{var}}` interpolation, which reads as a declared grammar.
It is not one: the schema judges the dialect tag and non-emptiness and
nothing else, and the accepted placeholder spelling belongs to whichever
renderer consumes the slot.
Measured on this tree, the two spellings are not interchangeable
everywhere, so "they are equivalent" would be imprecise in the other
direction:
- `@objectstack/formula`'s registered `templateEngine`, the messaging
renderer, the email plugin and the i18n adapters match `{{var}}` only.
- The `titleFormat` renderers accept both and normalize `{{var}}` down
to `{var}` first, which is why single-brace `titleFormat` values are
legal by construction.
Docblock and `.describe()` prose only. No schema, export or accept-set
movement.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T6HeZvT9wdSJD1ZxJb5Eno
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T6HeZvT9wdSJD1ZxJb5Eno
📓 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 see
Coarse fallback — 130 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 c571422663e29158457aef5c19f1a23c2307be51 && git checkout c571422663e29158457aef5c19f1a23c2307be51
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin dff0bdd3ac51df2653e1bd7beb7f2b3ca0fa58c3 760ca754d39c621f373617346006e8745a8437e2 && git checkout -B drift-repro dff0bdd3ac51df2653e1bd7beb7f2b3ca0fa58c3 && git merge --no-ff 760ca754d39c621f373617346006e8745a8437e2
node scripts/docs-audit/affected-docs.mjs --json dff0bdd3ac51df2653e1bd7beb7f2b3ca0fa58c3
|
|
PM — the deviation from the dispatch wording is endorsed, and the dispatch was wrong. Stating that plainly, because the audit trail should not read as a dev freelancing. My claim comment on #15947 (5562036736) instructed: reword the example so it says Why my instruction was wrong. It is true of
That docblock introduces the dialect for notification bodies and prompt templates, not just object titles. My wording would have replaced one imprecise claim with a broader and more expensive one — an author reading it would have been told single-brace works in an email template, where it does not. The error is mine and it has a name: triage measured one renderer's behaviour, and I restated it as a property of the dialect. The dev measured the rest of the population and wrote the per-renderer truth instead. That is the correct handling of a PM instruction that does not survive contact with a measurement — and it is why the dispatch said to report rather than absorb a disagreement. Also endorsed: the one-line scope widening. The identical claim sits in the same file's Landing: flipping to ready and arming auto-merge. Clause ② is Two pieces of method worth naming, since they are what made this report trustworthy: If Generated by Claude Code |
Fixes #15947
Docs-only. Rewords one imprecise prose example in
packages/spec, on the reading in triage comment 5556793638 rather than on the card body.What the card claimed, and what is actually there
The card reported a declared-vs-enforced contradiction: spec declares a
{{var}}template grammar, the only implementation reads single-brace{field}. Re-measured onmainatfd75728bc6, that premise does not hold.TemplateExpressionInputSchemaistypedExpressionStringArm('template')unioned with adialect: 'template'envelope. It judges the dialect tag and non-emptiness and nothing else — and the same docblock already said so one clause later: "No template syntax is judged at parse time." There is no declared accept-set for an implementation to contradict.packages/spec/src/shared/typed-expression-envelope-dialect.test.ts:64pins that directly, passing the stringnot a template {{{through asunjudged.So the entire defect is that the docblock introduced the dialect as "anything with
{{var}}interpolation", which reads as a grammar. It is not one.Why the fix is not "the two spellings are equivalent"
The prescription this started from was to say
{{var}}and{var}are equivalent and normalised by the implementation. Measured across this tree that is true oftitleFormatand false of every othertemplate-typed slot — so writing it into a docblock that names notification bodies and prompt templates in the same sentence would have replaced one imprecise claim with a more expensive one.templatedialect engine —@objectstack/formula'stemplateEngine, registered atpackages/formula/src/registry.ts:44,HOLE_REattemplate-engine.ts:31{{var}}onlyservice-messaging/src/template-renderer.ts:39, emailplugin-email/src/template-engine.ts:34, i18nservice-i18n/src/file-i18n-adapter.ts:77{{var}}onlytitleFormat— objectuirecord-title.ts:173, objectstackmetadata-protocol/src/protocol.ts:11402{{var}}normalised down to{var}firstThat is also the real reason the in-repo single-brace
titleFormatauthors are fine: they sit on the one render path that takes both. The new prose says exactly that, and no more.The diff
packages/spec/src/shared/expression.zod.ts— theTemplateExpressionInputSchemadocblock (the card's anchor), plus thetemplaterow of the## Dialectstable in the module header, which carried the identical claim 260 lines above and publishes into the same reference page. Leaving it would have left the file disagreeing with itself.packages/spec/src/data/object.zod.ts— thetitleFormatdescribe(), the one slot where both spellings really do work.content/docs/references/**— regenerated, never hand-edited (check:generated --fix; exactly one artifact was proved stale)..changeset/— patch, see below.Not touched:
TemplateExpressionInputSchema's judging logic, any accept-set, any export, any of the in-repo authors,content/docs/releases/.Changeset: patch, not
skip-changesetskip-changesetis for a diff that publishes nothing from a released package. Both edited strings publish:packages/spec/dist/expression.zod-CJCppEJk.d.ts:247describe()reachespackages/spec/dist/index.jsanddist/index.mjs@objectstack/spectherefore ships changed bytes, and takes apatch. Nothing breaking, so no ADR-0087 marker is owed —check:adr-0087-registrationandcheck:changeset-no-majorare green.Verification
pnpm --filter @objectstack/spec test— 482 files, 13102 tests, exit 0.packages/spec/src/shared/expression-dialect-docs.pin.test.tspins the## Dialectstable against theExpressionDialectenum; its own scope note says rewording a cell is free and adding or dropping a row is not, which is exactly what this diff respects. Run by name alongsidetyped-expression-envelope-dialect.test.ts: 2 files, 39 tests, exit 0 — including the pin's anti-vacuity assertion, which proves the reworded row still parses.pnpm --filter @objectstack/spec typecheck— exit 0.pnpm --filter @objectstack/spec check:generated— all 15 generated artifacts up to date.node scripts/pm/dispatch-gates.mjs --commandsfor this change set: 90 measured green.pnpm check:dual-build-cjs-loadsreports PREREQUISITE NOT MET — it reads built output for packages this worktree has nodist/for (hono, account, setup, studio and others), so it needs the repo-wide build and is left to CI. Four others (check:doc-formula-expressions,check:doc-security-posture,check:skill-examples,check:docs-transcript-drift) reported the same prerequisite on first run and are green after building the lint and client-react closures.pnpm lint(eslint . --no-inline-config, whole repo, not narrowed) — exit 0 in 58s at760ca754d3.Generated by Claude Code