From 8376a00a88fa4d0aac0b9541702b89e994fcdcfb Mon Sep 17 00:00:00 2001 From: tegwick Date: Sun, 6 Sep 2026 14:22:45 +0200 Subject: [PATCH] CANP-WP-0002 T06: revision v0.2, and section 23 rewritten MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes the workplan. The format becomes `canned-prompt/v0.2`, and packages declaring v0.1 remain valid — everything added across T01-T05 is additive, so a v0.1 package means exactly what it always meant. That is the MINOR case section 17 itself describes. The spec file loses its version suffix: CannedPromptFormat-v0.1.md becomes CannedPromptFormat.md, with the revision stated inside. One stable path that never breaks a link, and no rename per revision; the version belongs in the `format` string where tools actually read it. Section 23 is rewritten into three parts rather than the planned two. "Settled since v0.1" tables the five resolved questions against where each rule now lives. "Still deferred" carries the eight unpromoted items plus pattern-matching render checks. "Decided against" holds template inheritance alone, because calling it deferred would misdescribe it — reopening it means overturning a decision and answering four recorded objections, not filling a gap. Section 23 also names the two habits the five decisions turned out to share, so later revisions follow them rather than rediscover them: separate the deterministic half from the rest, and a package never asserts what it cannot back. The eval-rubric and registry-manifest schemas keep their own v0.1. They are new in this revision and sit on their own version lines. Reference CLI: ACCEPTED_FORMATS; an unknown revision is rejected naming what is accepted. Tests 78 -> 81. Example packages declare v0.2 and are bumped 0.1.0 -> 0.1.1 and 0.2.0 -> 0.2.1 as section 17 PATCH — metadata corrections with behavior unchanged. Also refreshes section 22's worked example, which had drifted: it showed pqrst-estimate at 0.1.0 with no composition, contradicting the package actually in the repo. It now mirrors the real package and doubles as a composition illustration. CANP-WP-0002 is finished. CANP-WP-0003 carries forward the one residual: the default registry's basename-derived name reads as `registry:`. Co-Authored-By: Claude Opus 5 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 --- ...mptFormat-v0.1.md => CannedPromptFormat.md | 145 +++++++++++++----- README.md | 6 +- SCOPE.md | 19 +-- examples/house-style/README.md | 2 +- examples/house-style/prompt.yaml | 4 +- examples/pqrst-estimate/prompt.yaml | 4 +- reference/canned_prompts.py | 11 +- reference/tests/test_canned_prompts.py | 23 +++ .../CANP-WP-0002-format-open-questions.md | 55 +++++-- .../CANP-WP-0003-registry-naming-residual.md | 54 +++++++ 10 files changed, 258 insertions(+), 65 deletions(-) rename CannedPromptFormat-v0.1.md => CannedPromptFormat.md (87%) create mode 100644 workplans/CANP-WP-0003-registry-naming-residual.md diff --git a/CannedPromptFormat-v0.1.md b/CannedPromptFormat.md similarity index 87% rename from CannedPromptFormat-v0.1.md rename to CannedPromptFormat.md index 44e5f29..802e6b9 100644 --- a/CannedPromptFormat-v0.1.md +++ b/CannedPromptFormat.md @@ -1,8 +1,10 @@ -# Canned Prompt Format v0.1 +# Canned Prompt Format -**Status:** Seed specification / experimental +**Revision:** v0.2 — packages declare `format: canned-prompt/v0.2` +**Status:** Experimental **Project:** `canned-prompts` -**Purpose:** Portable packaging of reusable prompts and prompt templates. +**Purpose:** Portable packaging of reusable prompts and prompt templates. +**Compatibility:** packages declaring `canned-prompt/v0.1` remain valid (§ 3.2). ## 1. Goals @@ -18,7 +20,7 @@ A conforming package should be: - versionable; - extensible with examples, evals, dependencies, and provenance. -CPF v0.1 specifies the **artifact format**. It intentionally does not specify model execution, agent orchestration, dependency resolution, registry transport, or evaluation engines. +CPF specifies the **artifact format**. It intentionally does not specify model execution, agent orchestration, dependency resolution, registry transport, or evaluation engines. ## 2. Package layout @@ -78,7 +80,7 @@ The canonical manifest is UTF-8 YAML named `prompt.yaml`. ### 3.1 Minimal manifest ```yaml -format: canned-prompt/v0.1 +format: canned-prompt/v0.2 id: review/code-review name: Code Review version: 1.0.0 @@ -99,13 +101,20 @@ Required fields are: #### `format` -MUST be exactly: +The current revision is: ```yaml -format: canned-prompt/v0.1 +format: canned-prompt/v0.2 ``` -for this specification. +A package declaring `canned-prompt/v0.1` remains valid and MUST still be +accepted. Everything v0.2 adds is additive — input defaults, composition, the +eval schema, registry manifests — so a v0.1 package means exactly what it +always meant. By § 17's own guidance this is a MINOR revision: new capability, +unchanged contract. + +A consumer MUST reject a `format` it does not recognize rather than guessing at +its meaning. #### `id` @@ -125,7 +134,7 @@ engineering/architecture-review practice/pqrst-estimate ``` -Rules for v0.1: +Rules: - lowercase ASCII is RECOMMENDED; - `/`, `-`, `_`, and `.` MAY be used; @@ -138,7 +147,7 @@ Rules for v0.1: ##### Identity is registry-scoped An `id` names a package **within a registry**, the way a path names a file -within a repository. CPF v0.1 does **not** claim that an id is globally unique: +within a repository. CPF does **not** claim that an id is globally unique: `practice/pqrst-estimate` obtained from two different registries may be two different packages, and a consumer that draws on more than one registry MUST keep track of which registry each package came from. @@ -200,10 +209,10 @@ rendered on its own; the field records the author's intent so that a consumer can warn when a package is used against it — rendering a fragment as a standalone prompt, or including a whole template where a fragment was meant. -## 4. Complete v0.1 manifest surface +## 4. Complete manifest surface ```yaml -format: canned-prompt/v0.1 +format: canned-prompt/v0.2 id: review/code-review name: Code Review version: 1.2.0 @@ -285,7 +294,7 @@ All fields other than the required fields in section 3.1 are optional. ## 5. Prompt template syntax -CPF v0.1 uses deliberately small placeholder semantics: +CPF uses deliberately small placeholder semantics: ```text {{ variable_name }} @@ -337,7 +346,7 @@ always produce the same output. A consumer that satisfies a derived default **Rendering rules:** -8. Values are substituted as text in v0.1. +8. Values are substituted as text. 9. A placeholder with no resolved value is an error. 10. Template evaluation MUST NOT execute arbitrary code. 11. Rendering MUST NOT derive values. A tool offering derivation MUST perform @@ -350,7 +359,7 @@ static defaults only. Such a tool is conforming: it reports an input with an unsatisfied derived default and no static fallback as unresolved, which rule 9 makes an error. -CPF v0.1 does not define conditionals, loops, filters, or functions. Implementations MAY offer richer rendering modes only when explicitly declared by an extension; they MUST NOT silently reinterpret a v0.1 template as executable code. +CPF does not define conditionals, loops, filters, or functions. Implementations MAY offer richer rendering modes only when explicitly declared by an extension; they MUST NOT silently reinterpret a template as executable code. ## 6. Inputs @@ -374,7 +383,7 @@ Fields: | `description` | no | Human-readable explanation | | `default` | no | Value used when the caller supplies none; see § 6.1 | -Recommended v0.1 input types are: +Recommended input types are: - `content` - `text` @@ -382,7 +391,7 @@ Recommended v0.1 input types are: - `path` - `json` -These are descriptive hints in v0.1. A runtime MAY use them for validation or adapters. +These are descriptive hints. A runtime MAY use them for validation or adapters. ### 6.1 Input defaults @@ -674,7 +683,7 @@ Recommended requirement values: - `optional` - `generate` -`generate` means that a resolver MAY satisfy a missing dependency by invoking an appropriate generation process. **CPF v0.1 does not define how generation or dependency resolution works.** +`generate` means that a resolver MAY satisfy a missing dependency by invoking an appropriate generation process. **CPF does not define how generation or dependency resolution works.** ### 10.3 Naming and pinning a dependency @@ -851,7 +860,7 @@ provenance: version: 1.1.0 ``` -The field is descriptive in v0.1. Registries SHOULD preserve provenance when publishing or mirroring packages. +The field is descriptive. Registries SHOULD preserve provenance when publishing or mirroring packages. ## 14. Licensing @@ -923,11 +932,11 @@ This guidance is intentionally advisory because prompt behavior is probabilistic ## 18. Package validation -A v0.1 validator SHOULD verify at least: +A validator SHOULD verify at least: 1. `prompt.yaml` exists and parses as YAML; 2. required manifest fields exist; -3. `format == canned-prompt/v0.1`; +3. `format` names a recognized revision (§ 3.2); 4. `id` is non-empty and contains no path traversal; 5. `version` is non-empty; 6. `template` resolves to a regular file inside the package; @@ -991,7 +1000,7 @@ Implementations SHOULD: ## 20. Registry model -CPF v0.1 does not mandate registry transport. +CPF does not mandate registry transport. A valid registry may be: @@ -1098,7 +1107,7 @@ registry, an id is unambiguous by definition. ## 21. Reference CLI semantics -The v0.1 reference tool uses two stores: +The reference tool uses two stores: - **catalog** — packages locally available for search/show/render; - **registry** — packages available for publish/install. @@ -1143,17 +1152,32 @@ These semantics are illustrative, not mandatory for other implementations. ## 22. Worked example +This is `examples/pqrst-estimate` in the `canned-prompts` repository, abridged. +It composes a shared style fragment, so it also demonstrates § 10.4. + `prompt.yaml`: ```yaml -format: canned-prompt/v0.1 +format: canned-prompt/v0.2 id: practice/pqrst-estimate name: PQRST Estimate -version: 0.1.0 +version: 0.2.1 summary: Estimate how session effort was distributed across PQRST categories. template: prompt.md +dependencies: + prompts: + - id: practice/house-style + version: ">= 0.1.0" + requirement: required + inputs: + - name: house_style + type: content + required: false + default: + include: practice/house-style + - name: session_summary type: content required: true @@ -1166,12 +1190,22 @@ parameters: output: format: markdown +compatibility: + capabilities: [long-context] + +license: MIT + +examples: [examples/basic.yaml] +evals: [evals/quality.yaml] + tags: [retrospective, agentic-coding, pqrst] ``` `prompt.md`: ```markdown +{{ house_style }} + Review the following coding-session summary and estimate the distribution of session effort across PQRST. Percentages must sum to 100%. @@ -1188,21 +1222,60 @@ Session: Include rationale: {{ include_rationale }} ``` -## 23. Open questions for v0.2+ +## 23. Open questions -Experience should determine whether later revisions standardize: +### Settled since v0.1 + +`CANP-WP-0002` promoted five items from "experience will decide" to decisions. +Each is now specified. This table records where the rule lives and what was +chosen, so a later reader can find the reasoning and not just the rule. + +| Question | Decision | Where | +|---|---|---| +| Optional inputs were unusable | `default` on inputs, static or derived; resolution separated from rendering | § 5.1, § 6.1 | +| Registry namespaces and ownership | Identity is registry-scoped; ownership is registry policy, never a package's own claim | § 3.2, § 20.1, § 20.2 | +| Prompt composition and inheritance | Composition by reference in two kinds, `include` and `derive`; no inheritance | § 10.3, § 10.4 | +| Canonical evaluation schemas | One schema, `canned-prompts/eval-rubric/v0.1`; render checks run, output criteria are declared | § 12.1 | +| Typed context and dependency contracts | `dependencies` means required, `compatibility` means observed; `context` names what CPF cannot package | § 9.1, § 10.1, § 10.2 | + +Two habits recur across those decisions, and later revisions should follow them +rather than rediscover them: + +**Separate the deterministic half from the rest.** `include` and `derive`, +render checks and output criteria, resolve and render. Each pair splits at the +same seam: what a tool can do with the package alone, and what needs a model. A +consumer that cannot call a model is never second-class — it does the +deterministic half completely and reports the rest honestly, rather than +guessing or silently producing something incomplete. + +**A package never asserts what it cannot back.** Ownership belongs to the +registry that admits a package, not to the package that would like to claim a +namespace. `compatibility` records observation, never permission. A derived +default is a request to a consumer, not an instruction the package executes. +This is why § 19 can treat a package as content rather than as an actor. + +### Still deferred + +Experience should still determine whether later revisions standardize: -- typed context/dependency contracts; - content macros; -- prompt composition and inheritance; -- registry namespaces and ownership; -- cryptographic integrity/signing; -- canonical evaluation schemas; -- model capability vocabularies; +- cryptographic integrity and signing; +- model capability vocabularies — § 10.2 keeps capability names free-form, + validated for shape and not for membership; - run manifests and evidence formats; - deterministic compilation manifests; -- trust/reputation signals; +- trust and reputation signals; - federated discovery; -- richer template syntax. +- richer template syntax; +- pattern-matching render checks — § 12.1 stops at `contains`, `not_contains` + and `resolves_all` rather than adding a matching language to a format whose + § 5 rests on not having one. -Until practical usage forces these decisions, v0.1 should remain intentionally small. +### Decided against + +Template inheritance (§ 10.4) is not deferred; it was considered and refused. +Reopening it means overturning a decision, not filling a gap, and would have to +answer the four objections recorded there. + +Until practical usage forces these questions, the format should remain +intentionally small. diff --git a/README.md b/README.md index bc9cc1b..71bce90 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ This bundle contains a first project seed for `canned-prompts`: - [`INTENT.md`](INTENT.md) — project mission, boundaries, principles, and success criteria. -- [`CannedPromptFormat-v0.1.md`](CannedPromptFormat-v0.1.md) — experimental package-format specification. +- [`CannedPromptFormat.md`](CannedPromptFormat.md) — the package-format specification, currently revision v0.2. - [`reference/`](reference/) — deliberately small Python CLI implementing the basic lifecycle. - [`examples/pqrst-estimate/`](examples/pqrst-estimate/) — a real package that can be used to exercise the implementation. - [`examples/house-style/`](examples/house-style/) — a `type: fragment` package that `pqrst-estimate` composes. @@ -67,7 +67,7 @@ or command-level `--catalog` / `--registry` options. ## Resolution vs rendering -The format separates the two steps (`CannedPromptFormat-v0.1.md` § 5.1). +The format separates the two steps (`CannedPromptFormat.md` § 5.1). Resolution decides a value for every input and parameter and may be non-deterministic; rendering substitutes those values and always is. An input may declare a default that is either a static value or a *derived* one — a @@ -165,7 +165,7 @@ requires (this tool cannot verify these): ## Registries and identity -An id names a package *within a registry* (`CannedPromptFormat-v0.1.md` +An id names a package *within a registry* (`CannedPromptFormat.md` § 3.2). The same id obtained from two registries may be two different packages, so the catalog keeps them apart and a bare id that matches more than one is reported as ambiguous rather than guessed. Qualify it when you need to: diff --git a/SCOPE.md b/SCOPE.md index 7e9503f..4443956 100644 --- a/SCOPE.md +++ b/SCOPE.md @@ -14,7 +14,7 @@ evidence, and is inspectable before use. See `INTENT.md`. ## In Scope -- `CannedPromptFormat-v0.1.md` — the package-format specification. +- `CannedPromptFormat.md` — the package-format specification (revision v0.2). - `reference/` — a deliberately small Python CLI (`add`, `search`, `show`, `render`, `install`, `publish`) over a filesystem catalog and registry. - `examples/` — real packages that exercise the format and the implementation. @@ -36,12 +36,13 @@ Thin execution adapters are permitted; a general runtime is not. ## Current State -- **Seed / experimental.** Spec v0.1 is written; the reference CLI implements the - full local lifecycle and its 3 tests pass. One example package - (`examples/pqrst-estimate`) round-trips add → search → show → render → publish - → install. -- The reference implementation is spec-conformant on the points it covers; the - known open design questions are tracked in `workplans/CANP-WP-0002-*.md`. +- **Experimental, revision v0.2.** The five open questions promoted from v0.1 + are resolved and specified (`CANP-WP-0002`); what remains deferred is listed + in § 23. Packages declaring `canned-prompt/v0.1` remain valid. +- The reference CLI implements the full local lifecycle across eight verbs and + its 81 tests pass. Two example packages (`practice/pqrst-estimate` and the + `practice/house-style` fragment it composes) round-trip add → search → show → + resolve → render → eval → publish → install. ## Developer Workflow @@ -50,7 +51,7 @@ cd reference python3 -m venv .venv && . .venv/bin/activate pip install -r requirements-dev.txt -python3 -m pytest -q # tests +python3 -m pytest -q # 81 tests CANNED_PROMPTS_HOME=/tmp/cp \ python3 canned_prompts.py add ../examples/pqrst-estimate # smoke ``` @@ -61,6 +62,6 @@ There is no lint or build step yet; `pyproject.toml` declares the ## Getting Oriented - Intent and principles: `INTENT.md` -- Format specification: `CannedPromptFormat-v0.1.md` +- Format specification: `CannedPromptFormat.md` - Agent instructions: `AGENTS.md` - Workplans: `workplans/` diff --git a/examples/house-style/README.md b/examples/house-style/README.md index 3af72b2..ebf3360 100644 --- a/examples/house-style/README.md +++ b/examples/house-style/README.md @@ -21,7 +21,7 @@ inputs: Inclusion is deterministic — the fragment's template is rendered and inlined as text, with no model involved — so the reference CLI performs it during -`resolve`. See `CannedPromptFormat-v0.1.md` § 10.4. +`resolve`. See `CannedPromptFormat.md` § 10.4. Its `tone` parameter is inherited from the including package when that package declares one, and otherwise falls back to the default here. diff --git a/examples/house-style/prompt.yaml b/examples/house-style/prompt.yaml index a55d391..533e6e8 100644 --- a/examples/house-style/prompt.yaml +++ b/examples/house-style/prompt.yaml @@ -1,7 +1,7 @@ -format: canned-prompt/v0.1 +format: canned-prompt/v0.2 id: practice/house-style name: House Style -version: 0.1.0 +version: 0.1.1 summary: > Shared style block for review and estimate prompts: evidence first, no filler, state uncertainty plainly. diff --git a/examples/pqrst-estimate/prompt.yaml b/examples/pqrst-estimate/prompt.yaml index 5e06966..9f08670 100644 --- a/examples/pqrst-estimate/prompt.yaml +++ b/examples/pqrst-estimate/prompt.yaml @@ -1,7 +1,7 @@ -format: canned-prompt/v0.1 +format: canned-prompt/v0.2 id: practice/pqrst-estimate name: PQRST Estimate -version: 0.2.0 +version: 0.2.1 summary: 'Produce a post-session estimate of effort distributed across the PQRST categories for an agentic coding session. diff --git a/reference/canned_prompts.py b/reference/canned_prompts.py index 8bb0eb7..410e75b 100755 --- a/reference/canned_prompts.py +++ b/reference/canned_prompts.py @@ -19,7 +19,9 @@ from typing import Any, Iterable import yaml -FORMAT = "canned-prompt/v0.1" +FORMAT = "canned-prompt/v0.2" +# v0.2 is additive, so a v0.1 package means exactly what it always meant (§ 3.2). +ACCEPTED_FORMATS = ("canned-prompt/v0.2", "canned-prompt/v0.1") REGISTRY_FORMAT = "canned-prompt-registry/v0.1" LOCAL_REGISTRY = "local" REGISTRY_NAME_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._-]*$") @@ -324,8 +326,11 @@ def validate_package(package_dir: Path) -> dict[str, Any]: if missing: raise CannedPromptError("missing required fields: " + ", ".join(missing)) - if manifest["format"] != FORMAT: - raise CannedPromptError(f"unsupported format: {manifest['format']!r}") + if manifest["format"] not in ACCEPTED_FORMATS: + raise CannedPromptError( + f"unsupported format: {manifest['format']!r}; expected one of " + + ", ".join(ACCEPTED_FORMATS) + ) package_id = manifest["id"] if not isinstance(package_id, str) or not package_id.strip(): diff --git a/reference/tests/test_canned_prompts.py b/reference/tests/test_canned_prompts.py index ab0c67a..6a4a26d 100644 --- a/reference/tests/test_canned_prompts.py +++ b/reference/tests/test_canned_prompts.py @@ -762,3 +762,26 @@ def test_copy_refuses_to_overwrite(tmp_path: Path) -> None: cp.copy_package(src, dst, manifest, "package") with pytest.raises(cp.CannedPromptError, match="already exists"): cp.copy_package(src, dst, manifest, "package") + + +# --- format revisions (§ 3.2) --- + +@pytest.mark.parametrize("declared", ["canned-prompt/v0.2", "canned-prompt/v0.1"]) +def test_both_format_revisions_are_accepted(tmp_path: Path, declared) -> None: + """v0.2 is additive, so a v0.1 package means exactly what it always meant.""" + pkg = write_pkg( + tmp_path / "p", + BASE.replace("canned-prompt/v0.1", declared) + + "inputs:\n - name: greeting\n required: false\n default: hi\n", + ) + assert cp.validate_package(pkg)["format"] == declared + + +def test_unknown_format_is_rejected(tmp_path: Path) -> None: + pkg = write_pkg( + tmp_path / "p", + BASE.replace("canned-prompt/v0.1", "canned-prompt/v9.9") + + "inputs:\n - name: greeting\n required: false\n default: hi\n", + ) + with pytest.raises(cp.CannedPromptError, match="unsupported format"): + cp.validate_package(pkg) diff --git a/workplans/CANP-WP-0002-format-open-questions.md b/workplans/CANP-WP-0002-format-open-questions.md index 85b6943..66208ad 100644 --- a/workplans/CANP-WP-0002-format-open-questions.md +++ b/workplans/CANP-WP-0002-format-open-questions.md @@ -4,7 +4,7 @@ type: workplan title: "Resolve CPF v0.1 open questions promoted for v0.2" domain: agents repo: canned-prompts -status: proposed +status: finished owner: codex topic_slug: practice created: "2026-09-06" @@ -13,7 +13,7 @@ reviewed_at: "2026-09-06" reviewed_by: "claude" context_paths: - "INTENT.md" - - "CannedPromptFormat-v0.1.md" + - "CannedPromptFormat.md" - "reference/canned_prompts.py" - "examples/pqrst-estimate/" state_hub_workstream_id: "c87c8e27-8b11-5306-b687-86779ef3f1be" @@ -21,7 +21,7 @@ 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 +`CannedPromptFormat.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 @@ -36,6 +36,11 @@ federated discovery, richer template syntax. format may *declare* a requirement; it must not specify the resolver, runtime, or execution engine that satisfies it. +**Outcome.** All seven tasks are done. The format is now revision v0.2 +(`CannedPromptFormat.md`), the reference CLI covers eight verbs with 81 passing +tests, and § 23 records what was settled, what stays deferred, and what was +decided against. One residual is carried forward as `CANP-WP-0003`. + ## Optional inputs need defaults ```task @@ -373,16 +378,48 @@ what it genuinely has. Illustrations live in the spec; examples stay honest. ```task id: CANP-WP-0002-T06 -status: todo +status: done priority: medium state_hub_task_id: "06032689-fc19-5fcd-a76e-5dbc87d02cd4" ``` -After T01–T05 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. +**Decisions (operator, 2026-09-06):** + +- *Bump to `canned-prompt/v0.2`, accept both.* Everything added is additive, so + a v0.1 package means exactly what it always meant — the MINOR case § 17 + itself describes. Tools accept both strings; new packages declare v0.2. +- *Drop the version from the spec filename.* `CannedPromptFormat-v0.1.md` → + `CannedPromptFormat.md`, with the revision stated in the document. One stable + path that never breaks a link, and no rename per revision; the version lives + in the `format` string, where tools actually read it. + +Delivered: + +1. § 23 rewritten into three parts rather than the planned two. **Settled since + v0.1** tables the five resolved questions against where each rule now lives. + **Still deferred** carries the eight unpromoted items plus pattern-matching + render checks, deferred during T04. **Decided against** holds template + inheritance on its own, because "deferred" would misdescribe it: reopening + it means overturning a decision and answering four recorded objections, not + filling a gap. +2. § 23 also names the two habits the five decisions share, so later revisions + follow them rather than rediscover them: *separate the deterministic half + from the rest*, and *a package never asserts what it cannot back*. +3. Header now carries revision, status and a compatibility line; § 3.2 states + the acceptance rule and why v0.2 is MINOR; § 18 rule 3 checks for a + recognized revision rather than one literal string. +4. Stale "CPF v0.1" phrasings throughout replaced with unversioned wording. The + `canned-prompts/eval-rubric/v0.1` and `canned-prompt-registry/v0.1` schemas + deliberately keep their own v0.1 — they are new in this revision and on + their own version lines. +5. `reference/canned_prompts.py`: `ACCEPTED_FORMATS`; unknown revisions are + rejected with the accepted list. Tests 78 → 81. +6. Example packages declare v0.2, bumped 0.1.0 → 0.1.1 and 0.2.0 → 0.2.1 as + § 17 PATCH — a metadata correction with intended behavior unchanged. + +**Also fixed.** § 22's worked example had drifted: it showed `pqrst-estimate` +at 0.1.0 with no composition, contradicting the package actually in the repo. +It now mirrors the real package and doubles as a § 10.4 illustration. ## Reference implementation conformance fixes diff --git a/workplans/CANP-WP-0003-registry-naming-residual.md b/workplans/CANP-WP-0003-registry-naming-residual.md new file mode 100644 index 0000000..4f99b17 --- /dev/null +++ b/workplans/CANP-WP-0003-registry-naming-residual.md @@ -0,0 +1,54 @@ +--- +id: CANP-WP-0003 +type: workplan +title: "Default registry name reads as 'registry:'" +domain: agents +repo: canned-prompts +status: proposed +owner: codex +topic_slug: practice +created: "2026-09-06" +updated: "2026-09-06" +--- + +# Default registry name reads as `registry:` + +Residual from `CANP-WP-0002` (`origin: residual`, `origin_ref: CANP-WP-0002`). + +## Give the default registry a better name + +```task +id: CANP-WP-0003-T01 +status: todo +priority: low +``` + +`CANP-WP-0002-T02` made a registry's name come from its `registry.yaml`, and +otherwise from its directory basename (§ 20.1). The reference tool's default +registry lives at `~/.canned-prompts/registry`, so its basename-derived name is +`registry`, and every install from it reads: + +```text +installed registry:practice/pqrst-estimate@0.1.0 +``` + +That is honest — it is genuinely what the directory is called — but it reads +poorly, and `registry:` is a confusing qualifier for the one registry most +users will ever see. + +Deliberately not fixed in `CANP-WP-0002`: special-casing the default path to +produce a prettier name would be exactly the kind of magic the § 20.1 rule was +written to avoid, and it was not worth an exception mid-task. + +Options worth weighing: + +1. Write a starter `registry.yaml` when the default registry is first created, + naming it something like `default` or `local-registry`. Uses the documented + mechanism rather than bypassing it; the cost is a tool writing a file into + a store the user may consider theirs. +2. Rename the default directory itself, so the basename is already good. + Changes an existing on-disk layout. +3. Accept it and document it. Zero code, and the escape hatch — add a + `registry.yaml` — already exists and is documented. + +Option 3 is the current state. Pick deliberately rather than by default.