From 9b3cb7461c095938c66af15dd7e25fcd6264de3e Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 7 Sep 2026 07:54:01 +0000 Subject: [PATCH 1/2] =?UTF-8?q?docs(spec):=20mark=20PromptTemplate.system/?= =?UTF-8?q?.user=20[EXPERIMENTAL=20=E2=80=94=20not=20enforced]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Under the #15954 ruling (decision batch #56, option B) the template-typed pair is marked, not retired. Both .describe() strings on PromptTemplateSchema now carry the repo's existing [EXPERIMENTAL — not enforced] prefix and state that no runtime renders or executes the template today. The model site is ai/agent.zod.ts (four uses of the identical prefix); the card named ai/knowledge-source.zod.ts, which carries no such marking at all (zero hits for the bare token EXPERIMENTAL, positive control lit). Prose only. .user remains required and .system remains optional — the schema shape is untouched. The ADR-0058 D7 ledger row `template-prompt` records the marking for both positions it covers, and the generated reference page is regenerated with the repo's own tooling. Claude-Session: https://claude.ai/code/session_01T6HeZvT9wdSJD1ZxJb5Eno Co-authored-by: Claude --- .../prompt-template-experimental-marking.md | 34 +++++++++++++++++++ content/docs/references/ai/model-registry.mdx | 8 ++--- .../test/expression-conformance.ledger.ts | 2 +- packages/spec/src/ai/model-registry.zod.ts | 4 +-- 4 files changed, 41 insertions(+), 7 deletions(-) create mode 100644 .changeset/prompt-template-experimental-marking.md diff --git a/.changeset/prompt-template-experimental-marking.md b/.changeset/prompt-template-experimental-marking.md new file mode 100644 index 0000000000..e1f3afff30 --- /dev/null +++ b/.changeset/prompt-template-experimental-marking.md @@ -0,0 +1,34 @@ +--- +"@objectstack/spec": patch +--- + +docs(spec): mark `PromptTemplate.system` / `.user` `[EXPERIMENTAL — not enforced]` (#15954, #16321) + +Prose only. `Clause-②: no` — no accept-set change, no new/narrowed authorable +key, no matrix declaration. Every value that parsed before parses now, and +every value refused before is refused identically. + +Under the #15954 ruling (decision batch #56, option B) the template-typed pair +is **marked, not retired**. Both `.describe()` strings on +`ai/PromptTemplateSchema` now carry the repo's existing +`[EXPERIMENTAL — not enforced]` prefix and state that no runtime renders or +executes the template today: + +```ts +system: TemplateExpressionInputSchema.optional().describe('[EXPERIMENTAL — not enforced] System prompt — supports {{var}} interpolation. No runtime renders or executes the template today.'), +user: TemplateExpressionInputSchema.describe('[EXPERIMENTAL — not enforced] User prompt template — supports {{var}} interpolation. No runtime renders or executes the template today.'), +``` + +**Why an author sees this.** `PromptTemplateSchema` has no consumer outside +`packages/spec`, so the `{{var}}` holes are never interpolated and the declared +`variables` are never checked against them. The ADR-0058 D7 conformance ledger +already recorded that verdict (`template-prompt`, `state: 'experimental'`, +`PARSE ONLY — NO EVALUATOR FOUND`); until now nothing said it at the +declaration, so the generated reference page advertised a capability the +runtime does not deliver. + +**What does NOT change.** `.user` remains **required** and `.system` remains +optional — the schema shape is untouched. Optionalising or retiring a required +key is a parse-breaking change and is deliberately left to its own card. No +tombstone and no ADR-0087 entry is owed: nothing is renamed, retired or +re-typed. diff --git a/content/docs/references/ai/model-registry.mdx b/content/docs/references/ai/model-registry.mdx index 3b3d7a96d8..45f80f0b7f 100644 --- a/content/docs/references/ai/model-registry.mdx +++ b/content/docs/references/ai/model-registry.mdx @@ -171,8 +171,8 @@ const result = ModelCapabilitySchema.parse(data); | **id** | `string` | ✅ | Unique template identifier | | **name** | `string` | ✅ | Template name (snake_case) | | **label** | `string` | ✅ | Display name | -| **system** | `string \| { dialect: 'template'; source?: string; ast?: any; meta?: object }` | optional | System prompt — supports `{{var}}` interpolation | -| **user** | `string \| { dialect: 'template'; source?: string; ast?: any; meta?: object }` | ✅ | User prompt template — supports `{{var}}` interpolation | +| **system** | `string \| { dialect: 'template'; source?: string; ast?: any; meta?: object }` | optional | [EXPERIMENTAL — not enforced] System prompt — supports `{{var}}` interpolation. No runtime renders or executes the template today. | +| **user** | `string \| { dialect: 'template'; source?: string; ast?: any; meta?: object }` | ✅ | [EXPERIMENTAL — not enforced] User prompt template — supports `{{var}}` interpolation. No runtime renders or executes the template today. | | **assistant** | `string` | optional | Assistant message prefix | | **variables** | `{ name: string; type?: Enum<'string' \| 'number' \| 'boolean' \| 'object' \| 'array'>; required?: boolean; defaultValue?: any; … }[]` | optional | Template variables | | **modelId** | `string` | optional | Recommended model ID | @@ -260,8 +260,8 @@ const result = ModelCapabilitySchema.parse(data); | **id** | `string` | ✅ | Unique template identifier | | **name** | `string` | ✅ | Template name (snake_case) | | **label** | `string` | ✅ | Display name | -| **system** | `string \| { dialect: 'template'; source?: string; ast?: any; meta?: object }` | optional | System prompt — supports `{{var}}` interpolation | -| **user** | `string \| { dialect: 'template'; source?: string; ast?: any; meta?: object }` | ✅ | User prompt template — supports `{{var}}` interpolation | +| **system** | `string \| { dialect: 'template'; source?: string; ast?: any; meta?: object }` | optional | [EXPERIMENTAL — not enforced] System prompt — supports `{{var}}` interpolation. No runtime renders or executes the template today. | +| **user** | `string \| { dialect: 'template'; source?: string; ast?: any; meta?: object }` | ✅ | [EXPERIMENTAL — not enforced] User prompt template — supports `{{var}}` interpolation. No runtime renders or executes the template today. | | **assistant** | `string` | optional | Assistant message prefix | | **variables** | `{ name: string; type?: Enum<'string' \| 'number' \| 'boolean' \| 'object' \| 'array'>; required?: boolean; defaultValue?: any; … }[]` | optional | Template variables | | **modelId** | `string` | optional | Recommended model ID | diff --git a/packages/qa/dogfood/test/expression-conformance.ledger.ts b/packages/qa/dogfood/test/expression-conformance.ledger.ts index 0ce30ac240..0994f6828a 100644 --- a/packages/qa/dogfood/test/expression-conformance.ledger.ts +++ b/packages/qa/dogfood/test/expression-conformance.ledger.ts @@ -382,7 +382,7 @@ export const EXPRESSION_SURFACE: ExprSurface[] = [ 'ai/model-registry.zod.ts:PromptTemplateSchema.system', 'ai/model-registry.zod.ts:PromptTemplateSchema.user', ], - note: 'EXPERIMENTAL — declared prompt templates with no runtime evaluator (ADR-0049). Ownership was checked before classifying rather than assumed: the card that appeared to own these keys is closed as completed, and its delivered diff (`d355c361157`) touched exactly one file, `skills/objectstack-ai/SKILL.md` — it corrected a prose clause that called these keys CEL, and never owned a ledger row. No open card owns them.', + note: 'EXPERIMENTAL — declared prompt templates with no runtime evaluator (ADR-0049), and MARKED as such at the declaration under the #15954 ruling (decision batch #56, option B: this pair is marked, NOT retired). Both positions this row covers — `PromptTemplateSchema.system` and `PromptTemplateSchema.user` — now carry the `[EXPERIMENTAL — not enforced]` prefix in their own `.describe()`, stating that no runtime renders or executes the template today, so an author reading the generated reference page gets the same verdict this row records instead of having to find this ledger. The marking is PROSE ONLY: `.user` remains REQUIRED (no `.optional()`) and `.system` keeps the `.optional()` it already had — optionalising or retiring a required key is parse-breaking and is its own card. Ownership was checked before classifying rather than assumed: the card that appeared to own these keys is closed as completed, and its delivered diff (`d355c361157`) touched exactly one file, `skills/objectstack-ai/SKILL.md` — it corrected a prose clause that called these keys CEL, and never owned a ledger row. No open card owns them.', }, { id: 'template-title-format', diff --git a/packages/spec/src/ai/model-registry.zod.ts b/packages/spec/src/ai/model-registry.zod.ts index cc44195c6d..11128d5562 100644 --- a/packages/spec/src/ai/model-registry.zod.ts +++ b/packages/spec/src/ai/model-registry.zod.ts @@ -118,8 +118,8 @@ export const PromptTemplateSchema = lazySchema(() => z.object({ label: z.string().describe('Display name'), /** Template Content */ - system: TemplateExpressionInputSchema.optional().describe('System prompt — supports {{var}} interpolation'), - user: TemplateExpressionInputSchema.describe('User prompt template — supports {{var}} interpolation'), + system: TemplateExpressionInputSchema.optional().describe('[EXPERIMENTAL — not enforced] System prompt — supports {{var}} interpolation. No runtime renders or executes the template today.'), + user: TemplateExpressionInputSchema.describe('[EXPERIMENTAL — not enforced] User prompt template — supports {{var}} interpolation. No runtime renders or executes the template today.'), assistant: z.string().optional().describe('Assistant message prefix'), /** Variables */ From f6ddb40574fbbbd0eb9d0232c8d3562eb96b2204 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 7 Sep 2026 10:02:11 +0000 Subject: [PATCH 2/2] fix(dogfood): move the D7 template-prompt row's tracker ids out of its runtime string MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `check:doc-authoring`'s cross-package prose-id leg reds on a tracker id inside a non-test string under packages/: the ledger `note` is runtime prose that reaches authors, operators and generated surfaces, none of whom can resolve one. The ruling id and its decision-batch number now live in an adjacent `//` comment — the gate's own prescribed remedy; ADR-0049 stays in the string as a customer-resolvable reference. No baseline entry: that file is maintainer-only and shrink-only. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01T6HeZvT9wdSJD1ZxJb5Eno --- packages/qa/dogfood/test/expression-conformance.ledger.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/qa/dogfood/test/expression-conformance.ledger.ts b/packages/qa/dogfood/test/expression-conformance.ledger.ts index 0994f6828a..86035776cf 100644 --- a/packages/qa/dogfood/test/expression-conformance.ledger.ts +++ b/packages/qa/dogfood/test/expression-conformance.ledger.ts @@ -382,7 +382,9 @@ export const EXPRESSION_SURFACE: ExprSurface[] = [ 'ai/model-registry.zod.ts:PromptTemplateSchema.system', 'ai/model-registry.zod.ts:PromptTemplateSchema.user', ], - note: 'EXPERIMENTAL — declared prompt templates with no runtime evaluator (ADR-0049), and MARKED as such at the declaration under the #15954 ruling (decision batch #56, option B: this pair is marked, NOT retired). Both positions this row covers — `PromptTemplateSchema.system` and `PromptTemplateSchema.user` — now carry the `[EXPERIMENTAL — not enforced]` prefix in their own `.describe()`, stating that no runtime renders or executes the template today, so an author reading the generated reference page gets the same verdict this row records instead of having to find this ledger. The marking is PROSE ONLY: `.user` remains REQUIRED (no `.optional()`) and `.system` keeps the `.optional()` it already had — optionalising or retiring a required key is parse-breaking and is its own card. Ownership was checked before classifying rather than assumed: the card that appeared to own these keys is closed as completed, and its delivered diff (`d355c361157`) touched exactly one file, `skills/objectstack-ai/SKILL.md` — it corrected a prose clause that called these keys CEL, and never owned a ledger row. No open card owns them.', + // Ruling: #15954 (decision batch #56, option B for the template family). The tracker ids live + // here, not in the string: `note` is runtime prose (check:doc-authoring, cross-package prose-id leg). + note: 'EXPERIMENTAL — declared prompt templates with no runtime evaluator (ADR-0049), and MARKED as such at the declaration under the marking ruling (option B: this pair is marked, NOT retired). Both positions this row covers — `PromptTemplateSchema.system` and `PromptTemplateSchema.user` — now carry the `[EXPERIMENTAL — not enforced]` prefix in their own `.describe()`, stating that no runtime renders or executes the template today, so an author reading the generated reference page gets the same verdict this row records instead of having to find this ledger. The marking is PROSE ONLY: `.user` remains REQUIRED (no `.optional()`) and `.system` keeps the `.optional()` it already had — optionalising or retiring a required key is parse-breaking and is its own card. Ownership was checked before classifying rather than assumed: the card that appeared to own these keys is closed as completed, and its delivered diff (`d355c361157`) touched exactly one file, `skills/objectstack-ai/SKILL.md` — it corrected a prose clause that called these keys CEL, and never owned a ledger row. No open card owns them.', }, { id: 'template-title-format',