canned-prompts/workplans/CANP-WP-0002-format-open-questions.md

238 lines
10 KiB
Markdown
Raw Normal View History

---
id: CANP-WP-0002
type: workplan
title: "Resolve CPF v0.1 open questions promoted for v0.2"
domain: agents
repo: canned-prompts
status: proposed
owner: codex
topic_slug: practice
created: "2026-09-06"
updated: "2026-09-06"
reviewed_at: "2026-09-06"
reviewed_by: "claude"
context_paths:
- "INTENT.md"
- "CannedPromptFormat-v0.1.md"
- "reference/canned_prompts.py"
- "examples/pqrst-estimate/"
state_hub_workstream_id: "c87c8e27-8b11-5306-b687-86779ef3f1be"
---
# Resolve CPF v0.1 open questions promoted for v0.2
`CannedPromptFormat-v0.1.md` § 23 currently lists twelve items as "experience
should determine". A review of the seed on 2026-09-06 (spec + reference CLI +
`examples/pqrst-estimate`; 3/3 tests pass, full local lifecycle smokes clean)
plus an operator interview promoted five of them from "wait and see" to
"decide, with a stated leaning". This workplan carries those decisions.
Unpromoted § 23 items stay deferred and unchanged: content macros, cryptographic
integrity/signing, model capability vocabularies, run manifests and evidence
formats, deterministic compilation manifests, trust/reputation signals,
federated discovery, richer template syntax.
**Guardrail for every task below:** `INTENT.md` § Deliberate boundary. The
format may *declare* a requirement; it must not specify the resolver, runtime,
or execution engine that satisfies it.
## Optional inputs need defaults
```task
id: CANP-WP-0002-T01
CANP-WP-0002 T01: input defaults, static and derived Closes the gap that made optional inputs unusable: rendering rule 5.1(4) made any unresolved placeholder an error while inputs had no `default`, so an input marked `required: false` and referenced from the template failed every render in which the caller omitted it — including the spec's own section 4 example. Section 10 already carried the derivation mechanism (`requirement: generate`, resolution deliberately undefined), so a derived default needed a binding rather than a new concept: the input's default names a declared prompt dependency. Spec: - 5.1 rewritten as "Resolution and rendering". Resolution may be non-deterministic and must report what it derived; rendering is deterministic and must not derive. A tool that handles only supplied values and static defaults is stated to be conforming. - 6.1 (new) covers both declaration forms. Reference form is preferred, with the reason stated — an inline prompt is anonymous, so unversioned, unprovenanced and un-evaluable — and validators should warn when a published package derives inline. - A derived default may declare a static fallback `value`. Without one the input stays unresolved, which is an error; derivation never silently yields empty content. - 4, 10, 18 (rules 11-13), 19 (two new MUST NOTs), 21 updated accordingly. Reference CLI: - New `resolve` verb reporting the origin of every value. - `Resolution` dataclass and `resolve_inputs`; `resolve_values` kept as a wrapper so existing callers are unaffected. - `render` refuses with a specific error naming underivable inputs rather than substituting empty text. - Tests 3 -> 11. Example package lifecycle re-verified end to end. INTENT.md is unchanged: splitting resolve from render preserves success criterion 4 (deterministic rendering) as written. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Bjefh8NUiEiahN4JLwoSKM Assistant: claude-code Assistant-Model: opus Assistant-Process: 388925@bnt-lap001 Assistant-Session: 3507023f-e0fd-4a1e-9d90-a0d4217d1502
2026-09-06 00:59:20 +02:00
status: done
priority: high
state_hub_task_id: "e49bf036-0aee-5bb2-abbd-3d3f683df298"
```
**Gap found in review.** Rendering rule § 5.1(4) makes any unresolved
placeholder an error, and § 6 gives `inputs` no `default` field. An input
declared `required: false` and referenced from the template therefore makes
`render` fail unless a value is supplied — optional inputs are effectively
unusable. The spec's own § 4 manifest example hits this with
`repository_context`. `reference/canned_prompts.py` is conformant here; the
defect is in the spec.
**Decision (operator, 2026-09-06):** add a `default` field to `inputs`, and
allow that default to be either
- a **static** value, or
- a **derived** default — a prompt that produces the value from available
context.
Unresolved-with-no-default remains an error.
CANP-WP-0002 T01: input defaults, static and derived Closes the gap that made optional inputs unusable: rendering rule 5.1(4) made any unresolved placeholder an error while inputs had no `default`, so an input marked `required: false` and referenced from the template failed every render in which the caller omitted it — including the spec's own section 4 example. Section 10 already carried the derivation mechanism (`requirement: generate`, resolution deliberately undefined), so a derived default needed a binding rather than a new concept: the input's default names a declared prompt dependency. Spec: - 5.1 rewritten as "Resolution and rendering". Resolution may be non-deterministic and must report what it derived; rendering is deterministic and must not derive. A tool that handles only supplied values and static defaults is stated to be conforming. - 6.1 (new) covers both declaration forms. Reference form is preferred, with the reason stated — an inline prompt is anonymous, so unversioned, unprovenanced and un-evaluable — and validators should warn when a published package derives inline. - A derived default may declare a static fallback `value`. Without one the input stays unresolved, which is an error; derivation never silently yields empty content. - 4, 10, 18 (rules 11-13), 19 (two new MUST NOTs), 21 updated accordingly. Reference CLI: - New `resolve` verb reporting the origin of every value. - `Resolution` dataclass and `resolve_inputs`; `resolve_values` kept as a wrapper so existing callers are unaffected. - `render` refuses with a specific error naming underivable inputs rather than substituting empty text. - Tests 3 -> 11. Example package lifecycle re-verified end to end. INTENT.md is unchanged: splitting resolve from render preserves success criterion 4 (deterministic rendering) as written. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Bjefh8NUiEiahN4JLwoSKM Assistant: claude-code Assistant-Model: opus Assistant-Process: 388925@bnt-lap001 Assistant-Session: 3507023f-e0fd-4a1e-9d90-a0d4217d1502
2026-09-06 00:59:20 +02:00
**Design note.** § 10 already carried the derivation mechanism:
`dependencies` accepts `requirement: generate`, defined as "a resolver MAY
satisfy a missing dependency by invoking an appropriate generation process",
with resolution left undefined. A derived default therefore did not need a new
concept, only a binding — the input's default names the dependency, and the
dependency records what may be generated and at which version.
**Follow-up decisions (operator, 2026-09-06):**
- *Both declaration forms are allowed.* A derived default may reference a
declared prompt dependency, or carry an inline `prompt`. The reference form
is preferred and the spec says why (an inline prompt is anonymous —
unversioned, unprovenanced, un-evaluable), and a validator SHOULD warn when a
**published** package derives inline. Inline is for local and draft packages.
- *Error unless static fallback.* A derived default MAY declare a static
`value`. A consumer that does not derive uses it; with no fallback the input
stays unresolved, which is an error. Derivation never silently yields empty
content.
- *Split render from resolve.* Resolution decides values and may be
non-deterministic; rendering substitutes and always is. Rendering MUST NOT
derive. This preserves INTENT success criterion 4 verbatim — no change to
`INTENT.md` was needed.
Work:
CANP-WP-0002 T01: input defaults, static and derived Closes the gap that made optional inputs unusable: rendering rule 5.1(4) made any unresolved placeholder an error while inputs had no `default`, so an input marked `required: false` and referenced from the template failed every render in which the caller omitted it — including the spec's own section 4 example. Section 10 already carried the derivation mechanism (`requirement: generate`, resolution deliberately undefined), so a derived default needed a binding rather than a new concept: the input's default names a declared prompt dependency. Spec: - 5.1 rewritten as "Resolution and rendering". Resolution may be non-deterministic and must report what it derived; rendering is deterministic and must not derive. A tool that handles only supplied values and static defaults is stated to be conforming. - 6.1 (new) covers both declaration forms. Reference form is preferred, with the reason stated — an inline prompt is anonymous, so unversioned, unprovenanced and un-evaluable — and validators should warn when a published package derives inline. - A derived default may declare a static fallback `value`. Without one the input stays unresolved, which is an error; derivation never silently yields empty content. - 4, 10, 18 (rules 11-13), 19 (two new MUST NOTs), 21 updated accordingly. Reference CLI: - New `resolve` verb reporting the origin of every value. - `Resolution` dataclass and `resolve_inputs`; `resolve_values` kept as a wrapper so existing callers are unaffected. - `render` refuses with a specific error naming underivable inputs rather than substituting empty text. - Tests 3 -> 11. Example package lifecycle re-verified end to end. INTENT.md is unchanged: splitting resolve from render preserves success criterion 4 (deterministic rendering) as written. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Bjefh8NUiEiahN4JLwoSKM Assistant: claude-code Assistant-Model: opus Assistant-Process: 388925@bnt-lap001 Assistant-Session: 3507023f-e0fd-4a1e-9d90-a0d4217d1502
2026-09-06 00:59:20 +02:00
Delivered:
1. § 5.1 rewritten as "Resolution and rendering" — six resolution rules and
four rendering rules, with rendering explicitly deterministic and forbidden
from deriving (rule 10). Resolution must report which values were derived
(rule 6). A tool that resolves only supplied values and static defaults is
stated to be conforming.
2. § 6 gains `default` in the field table plus a new § 6.1 covering both
declaration forms, the static fallback, and why the reference form is
preferred.
3. § 4 manifest surface updated: `repository_context` — the field that
demonstrated the original defect — now carries a derived default with a
fallback, backed by a `requirement: generate` prompt dependency.
4. § 10 states the binding between `requirement: generate` and a referenced
derived default.
5. § 18 gains validation rules 1113 and the publish-time inline warning.
6. § 19 gains two MUST NOTs: a derived default's prompt text is not an
instruction addressed to the consuming tool, and derivation must be visible
to the caller.
7. § 21 documents the new `resolve` verb.
8. `reference/canned_prompts.py`: `Resolution` dataclass, `resolve_inputs`
(with `resolve_values` kept as a wrapper), `input_default_kind`,
`prompt_dependency_ids`, `validate_input_default`, a `resolve` command, and
a specific render-time error naming the underivable inputs. Tests: 3 → 11,
all passing. Both READMEs document the split.
## Registry namespaces and ownership
```task
id: CANP-WP-0002-T02
status: todo
priority: high
state_hub_task_id: "a52cd41e-2bcc-50ee-96a1-d645a06df922"
```
An id like `practice/pqrst-estimate` has a namespace prefix with no owner. Two
authors publishing `practice/…` into one registry collide today; `add` and
`publish` only refuse an exact `id@version` that already exists.
Decide, for § 3.2 and § 20: what a namespace means, who may claim one, how a
filesystem registry records the claim, and what a consumer does on conflict.
Leaning: keep v0.1's local-first stance — namespace ownership is a *registry
policy*, declared by the registry rather than by the package — so package
semantics do not change when a hosted registry appears later.
Signing and trust scoring stay out of scope (§ 23, INTENT non-goals).
## Prompt composition and inheritance
```task
id: CANP-WP-0002-T03
status: todo
priority: high
state_hub_task_id: "0505c790-e57e-568c-9c8c-376957c9b08e"
```
Largest gap between `INTENT.md` and the spec. Principle 9 ("composition without
capture") and the `dependencies.prompts` field both promise composition, but
v0.1 defines no mechanism — `dependencies` is a declared field with no
semantics.
CANP-WP-0002 T01: input defaults, static and derived Closes the gap that made optional inputs unusable: rendering rule 5.1(4) made any unresolved placeholder an error while inputs had no `default`, so an input marked `required: false` and referenced from the template failed every render in which the caller omitted it — including the spec's own section 4 example. Section 10 already carried the derivation mechanism (`requirement: generate`, resolution deliberately undefined), so a derived default needed a binding rather than a new concept: the input's default names a declared prompt dependency. Spec: - 5.1 rewritten as "Resolution and rendering". Resolution may be non-deterministic and must report what it derived; rendering is deterministic and must not derive. A tool that handles only supplied values and static defaults is stated to be conforming. - 6.1 (new) covers both declaration forms. Reference form is preferred, with the reason stated — an inline prompt is anonymous, so unversioned, unprovenanced and un-evaluable — and validators should warn when a published package derives inline. - A derived default may declare a static fallback `value`. Without one the input stays unresolved, which is an error; derivation never silently yields empty content. - 4, 10, 18 (rules 11-13), 19 (two new MUST NOTs), 21 updated accordingly. Reference CLI: - New `resolve` verb reporting the origin of every value. - `Resolution` dataclass and `resolve_inputs`; `resolve_values` kept as a wrapper so existing callers are unaffected. - `render` refuses with a specific error naming underivable inputs rather than substituting empty text. - Tests 3 -> 11. Example package lifecycle re-verified end to end. INTENT.md is unchanged: splitting resolve from render preserves success criterion 4 (deterministic rendering) as written. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Bjefh8NUiEiahN4JLwoSKM Assistant: claude-code Assistant-Model: opus Assistant-Process: 388925@bnt-lap001 Assistant-Session: 3507023f-e0fd-4a1e-9d90-a0d4217d1502
2026-09-06 00:59:20 +02:00
T01 has since settled one corner of this: a derived default binds an input to
a prompt dependency declared `requirement: generate`, so package-to-package
reference already exists for that one case. Build on it rather than around it.
Decide what composition means at the *artifact* level: how one package
references another, whether references are includes, extends, or plain
declared prerequisites, and how versions are pinned. Leaning: declaration only
— a package states what it needs, and resolution stays with the consumer, per
the INTENT boundary. Do not introduce range resolution (INTENT non-goal).
## Canonical eval schemas
```task
id: CANP-WP-0002-T04
status: todo
priority: medium
state_hub_task_id: "0daf1097-6599-563f-8965-739cbc874ddf"
```
Cheapest item to pin down. `evals/` is a reserved path and `evals:` is a
manifest list, but § 12 defines no schema, so an eval file is an unvalidated
blob that no tool can act on.
Define a minimal eval-spec schema: identity, what is being asserted, the
fixture it runs against, and how a result is reported. Keep it declarative and
engine-neutral — "universal prompt evaluation" is an explicit INTENT non-goal,
so this specifies the *file*, not an evaluation engine. Extend § 18 to validate
eval files that declare the schema, and add one eval to
`examples/pqrst-estimate` as a worked case.
## Typed context and dependency contracts
```task
id: CANP-WP-0002-T05
status: todo
priority: medium
state_hub_task_id: "5beec7ba-e6c9-58b1-a065-b06aba015034"
```
`dependencies.context` and `dependencies.capabilities` appear in the § 4
manifest surface with no semantics whatsoever in v0.1, and § 9
`compatibility.capabilities` overlaps them without a stated relationship.
Decide: what a context dependency declares, how it differs from an input, how
it relates to `compatibility.capabilities`, and whether capability names are
CANP-WP-0002 T01: input defaults, static and derived Closes the gap that made optional inputs unusable: rendering rule 5.1(4) made any unresolved placeholder an error while inputs had no `default`, so an input marked `required: false` and referenced from the template failed every render in which the caller omitted it — including the spec's own section 4 example. Section 10 already carried the derivation mechanism (`requirement: generate`, resolution deliberately undefined), so a derived default needed a binding rather than a new concept: the input's default names a declared prompt dependency. Spec: - 5.1 rewritten as "Resolution and rendering". Resolution may be non-deterministic and must report what it derived; rendering is deterministic and must not derive. A tool that handles only supplied values and static defaults is stated to be conforming. - 6.1 (new) covers both declaration forms. Reference form is preferred, with the reason stated — an inline prompt is anonymous, so unversioned, unprovenanced and un-evaluable — and validators should warn when a published package derives inline. - A derived default may declare a static fallback `value`. Without one the input stays unresolved, which is an error; derivation never silently yields empty content. - 4, 10, 18 (rules 11-13), 19 (two new MUST NOTs), 21 updated accordingly. Reference CLI: - New `resolve` verb reporting the origin of every value. - `Resolution` dataclass and `resolve_inputs`; `resolve_values` kept as a wrapper so existing callers are unaffected. - `render` refuses with a specific error naming underivable inputs rather than substituting empty text. - Tests 3 -> 11. Example package lifecycle re-verified end to end. INTENT.md is unchanged: splitting resolve from render preserves success criterion 4 (deterministic rendering) as written. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Bjefh8NUiEiahN4JLwoSKM Assistant: claude-code Assistant-Model: opus Assistant-Process: 388925@bnt-lap001 Assistant-Session: 3507023f-e0fd-4a1e-9d90-a0d4217d1502
2026-09-06 00:59:20 +02:00
free strings in v0.2 (model capability vocabularies stay deferred). T01 is now settled and partly answers this: a derived default is a
consumer-resolved context requirement expressed through `dependencies.prompts`
rather than through `dependencies.context`. Decide whether `context` is still a
distinct concept or collapses into the prompt-dependency mechanism.
## Rewrite specification section 23
```task
id: CANP-WP-0002-T06
status: todo
priority: medium
state_hub_task_id: "06032689-fc19-5fcd-a76e-5dbc87d02cd4"
```
After T01T05 land, replace § 23's flat twelve-item list with two sections:
questions **being decided for v0.2** (each with its scoped question and stated
leaning, referencing this workplan) and questions **still deferred** (the eight
unpromoted items listed at the top of this file). Bump the spec status line if
the format revision warrants it.
## Reference implementation conformance fixes
```task
id: CANP-WP-0002-T07
status: todo
priority: low
state_hub_task_id: "f642abe6-8222-5958-88ee-7a53454f2344"
```
Two defects found in the same review, independent of the format questions:
1. **Prerelease versions sort as newest.** `parse_semver` in
`reference/canned_prompts.py` returns `(major, minor, patch, raw_string)`,
so `1.0.0-rc1` and `1.0.0` tie on the numeric fields and then compare as
strings — `"1.0.0-rc1" > "1.0.0"`. `resolve_installed` with no `--version`
therefore selects a prerelease over its own release. Order prerelease below
release, or state in § 17 that v0.1 ignores prerelease ordering.
2. **`copy_immutable` copies everything.** `add`/`publish` use
`shutil.copytree` over the whole source directory, so a stray `.git`,
`.venv`, or scratch file lands in the catalog and registry. § 2 says tools
MUST ignore unknown non-reserved files unless a manifest field references
them. Decide whether packaging is reserved-paths-only or an explicit
ignore list, then align the implementation and § 2.