Skip to content

Commit 614da76

Browse files
committed
no-mistakes(test): Regenerate stale agent-context-conformance prompt-skill goldens
1 parent b06be54 commit 614da76

11 files changed

Lines changed: 147 additions & 11 deletions

File tree

‎fixtures/agent-context-conformance/java-kotlin-react-tanstack/expected/.claude/skills/metaobjects-prompts/SKILL.md‎

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,8 @@ drift at build time instead of letting a prompt silently degrade.
166166
`@textRef` is a 2-layer logical reference `group/source` (folder/file,
167167
table/key, collection/document). The prompt text itself **never lives in
168168
metadata** — at runtime a configured **provider** resolves the reference to the
169-
actual Mustache text:
169+
actual template text (Mustache in every port; Python and TypeScript also accept Jinja, see
170+
below):
170171

171172
- a filesystem provider (L1 = folder, L2 = file) — the dev default:
172173
`lobby/welcome` → `<root>/lobby/welcome.mustache`. It is `FilesystemProvider` in every
@@ -181,6 +182,18 @@ actual Mustache text:
181182
Locale, A/B, dynamic, and evolutionary prompt variants all live behind the
182183
provider seam without touching metadata.
183184

185+
**Jinja bodies (Python and TypeScript only, ADR-0061).** A body may be a Jinja file —
186+
`lobby/welcome.jinja` (or `.j2` / `.jinja2`) — instead of `welcome.mustache`; the
187+
`@textRef` does not change, and the metadata never names an engine. Python renders it with
188+
jinja2 (the `metaobjects[jinja]` extra), TypeScript with nunjucks. The same `verify` gate
189+
checks it against the payload, walking the parsed template, and reports what it cannot
190+
settle statically (`user[key]`, a computed include name) as `ERR_TEMPLATE_NOT_STATIC`. Java,
191+
Kotlin and C# refuse a Jinja body with `ERR_TEMPLATE_ENGINE_UNSUPPORTED`, so a model that
192+
must render in those ports keeps Mustache. Prefer Mustache for new templates: it is the
193+
cross-port engine, and its logic-less shape is what pushes conditionals into the payload
194+
(next sections). Jinja is for adopting existing Jinja templates without rewriting them; per
195+
port reference files say how.
196+
184197
## `render()` is deterministic + byte-stable
185198

186199
Rendering is a pure function: `(payload VO, resolved text) → string`. Same inputs,
@@ -244,7 +257,8 @@ against each value of the dimension and snapshot every variant.
244257
## `verify` fails the build on prompt-drift
245258

246259
For every template, the verify step resolves the text, parses each `{{...}}`
247-
reference, and checks it exists on the payload VO. If the text references
260+
reference (Mustache, or a Jinja body in Python and TypeScript), and checks it exists on the
261+
payload VO. If the text references
248262
`{{authorName}}` but the payload only has `displayName`, **the build fails.** This
249263
is the prompt-vs-payload drift gate — run it in CI. It walks both `template.prompt`
250264
and `template.output` nodes the same way (both RENDER; only the direction of what comes

‎fixtures/agent-context-conformance/java-kotlin-react-tanstack/expected/.claude/skills/metaobjects-prompts/references/java.md‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,3 +148,9 @@ JUnit test in the Maven `test` phase to fail the build on prompt/payload drift.
148148
`metaobjects:verify` codegen-drift goal additionally catches a stale committed
149149
parser. The emitted parser imports Jackson (`com.fasterxml.jackson`), normally
150150
already on a Spring Boot classpath.
151+
152+
**Mustache only (ADR-0061).** Jinja bodies are a Python and TypeScript engine. A ref whose
153+
only body is a `.jinja` / `.j2` / `.jinja2` file is refused here with
154+
`ERR_TEMPLATE_ENGINE_UNSUPPORTED` (by the filesystem provider, and as a drift line by
155+
`verify`), rather than reported as missing. Keep templates the JVM ports render in
156+
Mustache.

‎fixtures/agent-context-conformance/java-kotlin-react-tanstack/expected/.claude/skills/metaobjects-prompts/references/kotlin.md‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,3 +166,9 @@ resolve against the payload — empty list = no drift. Assert it is empty in a J
166166
test in the Maven `test` phase to fail the build on prompt/payload drift. The
167167
`metaobjects:verify` codegen-drift goal additionally catches a stale committed
168168
parser.
169+
170+
**Mustache only (ADR-0061).** Jinja bodies are a Python and TypeScript engine. A ref whose
171+
only body is a `.jinja` / `.j2` / `.jinja2` file is refused here with
172+
`ERR_TEMPLATE_ENGINE_UNSUPPORTED` (by the filesystem provider, and as a drift line by
173+
`verify`), rather than reported as missing. Keep templates the JVM ports render in
174+
Mustache.

‎fixtures/agent-context-conformance/java-react/expected/.claude/skills/metaobjects-prompts/SKILL.md‎

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,8 @@ drift at build time instead of letting a prompt silently degrade.
166166
`@textRef` is a 2-layer logical reference `group/source` (folder/file,
167167
table/key, collection/document). The prompt text itself **never lives in
168168
metadata** — at runtime a configured **provider** resolves the reference to the
169-
actual Mustache text:
169+
actual template text (Mustache in every port; Python and TypeScript also accept Jinja, see
170+
below):
170171

171172
- a filesystem provider (L1 = folder, L2 = file) — the dev default:
172173
`lobby/welcome` → `<root>/lobby/welcome.mustache`. It is `FilesystemProvider` in every
@@ -181,6 +182,18 @@ actual Mustache text:
181182
Locale, A/B, dynamic, and evolutionary prompt variants all live behind the
182183
provider seam without touching metadata.
183184

185+
**Jinja bodies (Python and TypeScript only, ADR-0061).** A body may be a Jinja file —
186+
`lobby/welcome.jinja` (or `.j2` / `.jinja2`) — instead of `welcome.mustache`; the
187+
`@textRef` does not change, and the metadata never names an engine. Python renders it with
188+
jinja2 (the `metaobjects[jinja]` extra), TypeScript with nunjucks. The same `verify` gate
189+
checks it against the payload, walking the parsed template, and reports what it cannot
190+
settle statically (`user[key]`, a computed include name) as `ERR_TEMPLATE_NOT_STATIC`. Java,
191+
Kotlin and C# refuse a Jinja body with `ERR_TEMPLATE_ENGINE_UNSUPPORTED`, so a model that
192+
must render in those ports keeps Mustache. Prefer Mustache for new templates: it is the
193+
cross-port engine, and its logic-less shape is what pushes conditionals into the payload
194+
(next sections). Jinja is for adopting existing Jinja templates without rewriting them; per
195+
port reference files say how.
196+
184197
## `render()` is deterministic + byte-stable
185198

186199
Rendering is a pure function: `(payload VO, resolved text) → string`. Same inputs,
@@ -244,7 +257,8 @@ against each value of the dimension and snapshot every variant.
244257
## `verify` fails the build on prompt-drift
245258

246259
For every template, the verify step resolves the text, parses each `{{...}}`
247-
reference, and checks it exists on the payload VO. If the text references
260+
reference (Mustache, or a Jinja body in Python and TypeScript), and checks it exists on the
261+
payload VO. If the text references
248262
`{{authorName}}` but the payload only has `displayName`, **the build fails.** This
249263
is the prompt-vs-payload drift gate — run it in CI. It walks both `template.prompt`
250264
and `template.output` nodes the same way (both RENDER; only the direction of what comes

‎fixtures/agent-context-conformance/java-react/expected/.claude/skills/metaobjects-prompts/references/java.md‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,3 +148,9 @@ JUnit test in the Maven `test` phase to fail the build on prompt/payload drift.
148148
`metaobjects:verify` codegen-drift goal additionally catches a stale committed
149149
parser. The emitted parser imports Jackson (`com.fasterxml.jackson`), normally
150150
already on a Spring Boot classpath.
151+
152+
**Mustache only (ADR-0061).** Jinja bodies are a Python and TypeScript engine. A ref whose
153+
only body is a `.jinja` / `.j2` / `.jinja2` file is refused here with
154+
`ERR_TEMPLATE_ENGINE_UNSUPPORTED` (by the filesystem provider, and as a drift line by
155+
`verify`), rather than reported as missing. Keep templates the JVM ports render in
156+
Mustache.

‎fixtures/agent-context-conformance/python/expected/.claude/skills/metaobjects-prompts/SKILL.md‎

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,8 @@ drift at build time instead of letting a prompt silently degrade.
166166
`@textRef` is a 2-layer logical reference `group/source` (folder/file,
167167
table/key, collection/document). The prompt text itself **never lives in
168168
metadata** — at runtime a configured **provider** resolves the reference to the
169-
actual Mustache text:
169+
actual template text (Mustache in every port; Python and TypeScript also accept Jinja, see
170+
below):
170171

171172
- a filesystem provider (L1 = folder, L2 = file) — the dev default:
172173
`lobby/welcome` → `<root>/lobby/welcome.mustache`. It is `FilesystemProvider` in every
@@ -181,6 +182,18 @@ actual Mustache text:
181182
Locale, A/B, dynamic, and evolutionary prompt variants all live behind the
182183
provider seam without touching metadata.
183184

185+
**Jinja bodies (Python and TypeScript only, ADR-0061).** A body may be a Jinja file —
186+
`lobby/welcome.jinja` (or `.j2` / `.jinja2`) — instead of `welcome.mustache`; the
187+
`@textRef` does not change, and the metadata never names an engine. Python renders it with
188+
jinja2 (the `metaobjects[jinja]` extra), TypeScript with nunjucks. The same `verify` gate
189+
checks it against the payload, walking the parsed template, and reports what it cannot
190+
settle statically (`user[key]`, a computed include name) as `ERR_TEMPLATE_NOT_STATIC`. Java,
191+
Kotlin and C# refuse a Jinja body with `ERR_TEMPLATE_ENGINE_UNSUPPORTED`, so a model that
192+
must render in those ports keeps Mustache. Prefer Mustache for new templates: it is the
193+
cross-port engine, and its logic-less shape is what pushes conditionals into the payload
194+
(next sections). Jinja is for adopting existing Jinja templates without rewriting them; per
195+
port reference files say how.
196+
184197
## `render()` is deterministic + byte-stable
185198

186199
Rendering is a pure function: `(payload VO, resolved text) → string`. Same inputs,
@@ -244,7 +257,8 @@ against each value of the dimension and snapshot every variant.
244257
## `verify` fails the build on prompt-drift
245258

246259
For every template, the verify step resolves the text, parses each `{{...}}`
247-
reference, and checks it exists on the payload VO. If the text references
260+
reference (Mustache, or a Jinja body in Python and TypeScript), and checks it exists on the
261+
payload VO. If the text references
248262
`{{authorName}}` but the payload only has `displayName`, **the build fails.** This
249263
is the prompt-vs-payload drift gate — run it in CI. It walks both `template.prompt`
250264
and `template.output` nodes the same way (both RENDER; only the direction of what comes

‎fixtures/agent-context-conformance/python/expected/.claude/skills/metaobjects-prompts/references/python.md‎

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ silently drift.
1818
- Recommended LLM caller (bring-your-own)
1919
- Consumer dependency
2020
- Drift gate
21+
- Jinja templates
2122

2223
## Wire the generators
2324

@@ -188,4 +189,27 @@ required_slots=None, required_tags=None) -> list[VerifyError]` walks a Mustache
188189
template's tokens against the payload field tree — each `{{...}}` reference that
189190
doesn't resolve yields a `VerifyError` (empty list = no drift). Assert it is empty in a
190191
pytest test to fail the build on prompt/payload drift; `metaobjects verify`
191-
additionally catches a stale committed parser.
192+
additionally catches a stale committed parser. Pass `engine="jinja"` to check a Jinja body.
193+
194+
## Jinja templates
195+
196+
Existing Jinja prompt templates adopt the gate as they are (ADR-0061). Install the extra,
197+
`pip install "metaobjects[jinja]"`, and keep the file as `<group>/<source>.jinja` (or `.j2`,
198+
`.jinja2`) under the template root; `@textRef` stays `group/source`. `FilesystemProvider`
199+
reads `.mustache` first, then the Jinja extensions, and `engine_of(ref)` reports which one it
200+
found; `render` and `metaobjects verify` pick the engine from it. For an
201+
`InMemoryProvider`, pass `InMemoryProvider(templates, engine="jinja")`, or pass `engine="jinja"`
202+
to `RenderRequest` / `verify` directly.
203+
204+
- `verify` walks the parsed jinja2 template: paths per segment, `for` targets bound to element
205+
fields, `set` / macro parameters as locals, filter arguments, and literal `include` /
206+
`import` / `extends` through the provider. `ERR_TEMPLATE_NOT_STATIC` marks what it cannot
207+
settle; `ERR_TEMPLATE_SYNTAX` a body that does not parse.
208+
- The generated render helper over a Jinja body passes `engine="jinja"` and the payload field
209+
tree (`verify=[PayloadField(...)]`) to `render`, so a body that drifted after the build is
210+
refused at runtime with `RenderError("render verify failed: ERR_… (path)")`.
211+
- A Pydantic payload renders as its JSON-mode dump, as with Mustache. Printed values follow
212+
the Mustache renderer: `true` / `false`, a whole float as an integer, `None` as empty.
213+
- To render the same in TypeScript (nunjucks), stay inside the shared vocabulary in
214+
`fixtures/jinja-render-conformance/`: test a list with `| length`, avoid `{% with %}`,
215+
Python methods and printing whole lists or dicts.

‎fixtures/agent-context-conformance/ts-react-tanstack/expected/.claude/skills/metaobjects-prompts/SKILL.md‎

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,8 @@ drift at build time instead of letting a prompt silently degrade.
166166
`@textRef` is a 2-layer logical reference `group/source` (folder/file,
167167
table/key, collection/document). The prompt text itself **never lives in
168168
metadata** — at runtime a configured **provider** resolves the reference to the
169-
actual Mustache text:
169+
actual template text (Mustache in every port; Python and TypeScript also accept Jinja, see
170+
below):
170171

171172
- a filesystem provider (L1 = folder, L2 = file) — the dev default:
172173
`lobby/welcome` → `<root>/lobby/welcome.mustache`. It is `FilesystemProvider` in every
@@ -181,6 +182,18 @@ actual Mustache text:
181182
Locale, A/B, dynamic, and evolutionary prompt variants all live behind the
182183
provider seam without touching metadata.
183184

185+
**Jinja bodies (Python and TypeScript only, ADR-0061).** A body may be a Jinja file —
186+
`lobby/welcome.jinja` (or `.j2` / `.jinja2`) — instead of `welcome.mustache`; the
187+
`@textRef` does not change, and the metadata never names an engine. Python renders it with
188+
jinja2 (the `metaobjects[jinja]` extra), TypeScript with nunjucks. The same `verify` gate
189+
checks it against the payload, walking the parsed template, and reports what it cannot
190+
settle statically (`user[key]`, a computed include name) as `ERR_TEMPLATE_NOT_STATIC`. Java,
191+
Kotlin and C# refuse a Jinja body with `ERR_TEMPLATE_ENGINE_UNSUPPORTED`, so a model that
192+
must render in those ports keeps Mustache. Prefer Mustache for new templates: it is the
193+
cross-port engine, and its logic-less shape is what pushes conditionals into the payload
194+
(next sections). Jinja is for adopting existing Jinja templates without rewriting them; per
195+
port reference files say how.
196+
184197
## `render()` is deterministic + byte-stable
185198

186199
Rendering is a pure function: `(payload VO, resolved text) → string`. Same inputs,
@@ -244,7 +257,8 @@ against each value of the dimension and snapshot every variant.
244257
## `verify` fails the build on prompt-drift
245258

246259
For every template, the verify step resolves the text, parses each `{{...}}`
247-
reference, and checks it exists on the payload VO. If the text references
260+
reference (Mustache, or a Jinja body in Python and TypeScript), and checks it exists on the
261+
payload VO. If the text references
248262
`{{authorName}}` but the payload only has `displayName`, **the build fails.** This
249263
is the prompt-vs-payload drift gate — run it in CI. It walks both `template.prompt`
250264
and `template.output` nodes the same way (both RENDER; only the direction of what comes

‎fixtures/agent-context-conformance/ts-react-tanstack/expected/.claude/skills/metaobjects-prompts/references/typescript.md‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,18 @@ error in every port. The emitted parser imports `zod`;
219219
it's usually already a dependency (Drizzle / `runtime-ts` lean on it), else
220220
`npm i zod`.
221221

222+
**Jinja bodies (ADR-0061).** A body may be `<group>/<source>.jinja` (or `.j2`, `.jinja2`)
223+
instead of `.mustache`; `@textRef` does not change. `@metaobjectsdev/render` renders it with
224+
nunjucks (a dependency of the package, nothing to install) and `meta verify` checks it the same
225+
way, walking the parsed template; it names the `.jinja` file and line on a drift.
226+
`FilesystemProvider.engineOf(ref)` reports the engine of the file it found; for an
227+
`InMemoryProvider` pass `new InMemoryProvider(map, { engine: "jinja" })`, or pass
228+
`engine: "jinja"` to `render` / `verify`. A generated `render<Name>()` helper over a Jinja body
229+
passes `engine: "jinja"`, so it renders as Jinja through any runtime provider, and the
230+
runtime check runs on it as on a Mustache body. What the check cannot settle statically is
231+
`ERR_TEMPLATE_NOT_STATIC`. nunjucks treats an empty list as true (jinja2 does not), so test a
232+
list with `{% if items | length %}` when the same template must render in Python.
233+
222234
## See which fields a template consumes
223235

224236
List `docsFile()` in `generators` and run `meta gen` to emit the model surface to the

‎fixtures/agent-context-conformance/ts-requirements/expected/.claude/skills/metaobjects-prompts/SKILL.md‎

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,8 @@ drift at build time instead of letting a prompt silently degrade.
166166
`@textRef` is a 2-layer logical reference `group/source` (folder/file,
167167
table/key, collection/document). The prompt text itself **never lives in
168168
metadata** — at runtime a configured **provider** resolves the reference to the
169-
actual Mustache text:
169+
actual template text (Mustache in every port; Python and TypeScript also accept Jinja, see
170+
below):
170171

171172
- a filesystem provider (L1 = folder, L2 = file) — the dev default:
172173
`lobby/welcome` → `<root>/lobby/welcome.mustache`. It is `FilesystemProvider` in every
@@ -181,6 +182,18 @@ actual Mustache text:
181182
Locale, A/B, dynamic, and evolutionary prompt variants all live behind the
182183
provider seam without touching metadata.
183184

185+
**Jinja bodies (Python and TypeScript only, ADR-0061).** A body may be a Jinja file —
186+
`lobby/welcome.jinja` (or `.j2` / `.jinja2`) — instead of `welcome.mustache`; the
187+
`@textRef` does not change, and the metadata never names an engine. Python renders it with
188+
jinja2 (the `metaobjects[jinja]` extra), TypeScript with nunjucks. The same `verify` gate
189+
checks it against the payload, walking the parsed template, and reports what it cannot
190+
settle statically (`user[key]`, a computed include name) as `ERR_TEMPLATE_NOT_STATIC`. Java,
191+
Kotlin and C# refuse a Jinja body with `ERR_TEMPLATE_ENGINE_UNSUPPORTED`, so a model that
192+
must render in those ports keeps Mustache. Prefer Mustache for new templates: it is the
193+
cross-port engine, and its logic-less shape is what pushes conditionals into the payload
194+
(next sections). Jinja is for adopting existing Jinja templates without rewriting them; per
195+
port reference files say how.
196+
184197
## `render()` is deterministic + byte-stable
185198

186199
Rendering is a pure function: `(payload VO, resolved text) → string`. Same inputs,
@@ -244,7 +257,8 @@ against each value of the dimension and snapshot every variant.
244257
## `verify` fails the build on prompt-drift
245258

246259
For every template, the verify step resolves the text, parses each `{{...}}`
247-
reference, and checks it exists on the payload VO. If the text references
260+
reference (Mustache, or a Jinja body in Python and TypeScript), and checks it exists on the
261+
payload VO. If the text references
248262
`{{authorName}}` but the payload only has `displayName`, **the build fails.** This
249263
is the prompt-vs-payload drift gate — run it in CI. It walks both `template.prompt`
250264
and `template.output` nodes the same way (both RENDER; only the direction of what comes

0 commit comments

Comments
 (0)