CANP-WP-0003: name the default registry default
Section 20.1 takes a registry's name from its directory basename, so the reference tool's default store at ~/.canned-prompts/registry was named `registry` — giving `registry:practice/thing` as a qualified reference. The workplan had recorded this as reading poorly in one output line. It was understated: the name reaches qualified references, the on-disk catalog layout (catalog/registry/...), and index.yaml rows (registry: registry). Once packages are installed and inclusions recorded, changing it becomes a migration rather than an edit. Renaming the directory to ~/.canned-prompts/default fixes it with no special case in code, nothing written into the user's store, and no second naming mechanism competing with section 20.1's manifest. check_legacy_registry refuses to silently create a fresh empty store beside a populated ~/.canned-prompts/registry — that failure would have been worse than the wart being fixed. It names the exact mv, and the --registry flag for keeping the old store. The check fires only for the default path; an explicit --registry is never second-guessed. Tests 95 -> 99. 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
This commit is contained in:
parent
03826eac4f
commit
e1889b41a1
5 changed files with 87 additions and 7 deletions
|
|
@ -54,7 +54,7 @@ By default the reference tool uses:
|
|||
|
||||
```text
|
||||
~/.canned-prompts/catalog
|
||||
~/.canned-prompts/registry
|
||||
~/.canned-prompts/default # the default registry
|
||||
```
|
||||
|
||||
Override them with:
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ Default locations:
|
|||
|
||||
```text
|
||||
~/.canned-prompts/catalog
|
||||
~/.canned-prompts/registry
|
||||
~/.canned-prompts/default
|
||||
```
|
||||
|
||||
A **registry** stores packages flat, because an id is unambiguous within one
|
||||
|
|
@ -49,12 +49,16 @@ A **catalog** is namespaced by registry, because identity is registry-scoped
|
|||
For example:
|
||||
|
||||
```text
|
||||
~/.canned-prompts/catalog/house/practice/pqrst-estimate/0.1.0/
|
||||
~/.canned-prompts/catalog/local/practice/pqrst-estimate/0.1.0/
|
||||
~/.canned-prompts/catalog/default/practice/pqrst-estimate/1.0.0/
|
||||
~/.canned-prompts/catalog/local/practice/pqrst-estimate/1.0.0/
|
||||
```
|
||||
|
||||
A registry's name comes from its optional `registry.yaml`, and otherwise from
|
||||
its directory basename. `add` takes a package from a path rather than a
|
||||
its directory basename — which is why the default registry directory is called
|
||||
`default` and not `registry`: the basename reaches qualified references,
|
||||
catalog paths and index rows, and `registry:practice/thing` reads poorly. A
|
||||
store left at the old `~/.canned-prompts/registry` is reported with the command
|
||||
to move it, rather than a fresh empty one being created beside it. `add` takes a package from a path rather than a
|
||||
registry, so it files it under `local` (override with `--as`).
|
||||
|
||||
Commands that take an ID accept a bare id or a qualified `<registry>:<id>`.
|
||||
|
|
|
|||
|
|
@ -55,9 +55,30 @@ def default_catalog() -> Path:
|
|||
|
||||
|
||||
def default_registry() -> Path:
|
||||
# Named "default" rather than "registry" because § 20.1 takes a registry's
|
||||
# name from its directory basename, and that name reaches qualified
|
||||
# references, catalog paths and index rows.
|
||||
return home_dir() / "default"
|
||||
|
||||
|
||||
def legacy_registry() -> Path:
|
||||
return home_dir() / "registry"
|
||||
|
||||
|
||||
def check_legacy_registry(registry: Path) -> None:
|
||||
"""Refuse to silently start a fresh default store beside a populated one."""
|
||||
if registry.resolve() != default_registry().resolve():
|
||||
return
|
||||
if registry.exists() or not legacy_registry().is_dir():
|
||||
return
|
||||
raise CannedPromptError(
|
||||
f"the default registry moved from {legacy_registry()} to {registry}, so "
|
||||
f"a registry's basename names it (§ 20.1) rather than reading as "
|
||||
f"'registry:'. Move it:\n mv {legacy_registry()} {registry}\n"
|
||||
f"or keep using the old one explicitly with --registry {legacy_registry()}"
|
||||
)
|
||||
|
||||
|
||||
def read_manifest(package_dir: Path) -> dict[str, Any]:
|
||||
manifest_path = package_dir / "prompt.yaml"
|
||||
if not manifest_path.is_file():
|
||||
|
|
@ -858,6 +879,7 @@ def cmd_publish(args: argparse.Namespace) -> None:
|
|||
src = Path(args.path)
|
||||
manifest = validate_package(src)
|
||||
registry = Path(args.registry).expanduser()
|
||||
check_legacy_registry(registry)
|
||||
name = registry_name(registry) if registry.is_dir() else None
|
||||
|
||||
policy, claim = namespace_policy(registry, manifest["id"]) if registry.is_dir() else ("open", None)
|
||||
|
|
@ -879,6 +901,7 @@ def cmd_publish(args: argparse.Namespace) -> None:
|
|||
|
||||
def cmd_install(args: argparse.Namespace) -> None:
|
||||
registry = Path(args.registry).expanduser()
|
||||
check_legacy_registry(registry)
|
||||
catalog = Path(args.catalog).expanduser()
|
||||
name = registry_name(registry)
|
||||
|
||||
|
|
|
|||
|
|
@ -914,3 +914,31 @@ def test_empty_inclusion_is_not_flagged() -> None:
|
|||
origins={"a": "included from x/empty", "b": "included from x/b"},
|
||||
)
|
||||
assert cp.duplicate_inclusions(resolution) == []
|
||||
|
||||
|
||||
# --- default registry naming (CANP-WP-0003) ---
|
||||
|
||||
def test_default_registry_is_named_default(tmp_path: Path, monkeypatch) -> None:
|
||||
monkeypatch.setenv("CANNED_PROMPTS_HOME", str(tmp_path))
|
||||
assert cp.default_registry().name == "default"
|
||||
|
||||
|
||||
def test_legacy_registry_is_reported_not_ignored(tmp_path: Path, monkeypatch) -> None:
|
||||
"""A fresh empty store beside a populated one would be worse than the wart."""
|
||||
monkeypatch.setenv("CANNED_PROMPTS_HOME", str(tmp_path))
|
||||
(tmp_path / "registry").mkdir()
|
||||
with pytest.raises(cp.CannedPromptError, match="default registry moved"):
|
||||
cp.check_legacy_registry(cp.default_registry())
|
||||
|
||||
|
||||
def test_no_complaint_once_migrated(tmp_path: Path, monkeypatch) -> None:
|
||||
monkeypatch.setenv("CANNED_PROMPTS_HOME", str(tmp_path))
|
||||
(tmp_path / "default").mkdir()
|
||||
(tmp_path / "registry").mkdir()
|
||||
cp.check_legacy_registry(cp.default_registry())
|
||||
|
||||
|
||||
def test_explicit_registry_path_is_never_second_guessed(tmp_path: Path, monkeypatch) -> None:
|
||||
monkeypatch.setenv("CANNED_PROMPTS_HOME", str(tmp_path))
|
||||
(tmp_path / "registry").mkdir()
|
||||
cp.check_legacy_registry(tmp_path / "somewhere-else")
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ type: workplan
|
|||
title: "Default registry name reads as 'registry:'"
|
||||
domain: agents
|
||||
repo: canned-prompts
|
||||
status: proposed
|
||||
status: finished
|
||||
owner: codex
|
||||
topic_slug: practice
|
||||
created: "2026-09-06"
|
||||
|
|
@ -20,7 +20,7 @@ Residual from `CANP-WP-0002` (`origin: residual`, `origin_ref: CANP-WP-0002`).
|
|||
|
||||
```task
|
||||
id: CANP-WP-0003-T01
|
||||
status: todo
|
||||
status: done
|
||||
priority: low
|
||||
state_hub_task_id: "ead2d409-2b80-5f50-9f0f-a397822ba2ae"
|
||||
```
|
||||
|
|
@ -54,3 +54,28 @@ Options worth weighing:
|
|||
`registry.yaml` — already exists and is documented.
|
||||
|
||||
Option 3 is the current state. Pick deliberately rather than by default.
|
||||
|
||||
## Outcome
|
||||
|
||||
**Decision (operator, 2026-09-06): option 2** — rename the default directory to
|
||||
`~/.canned-prompts/default`, so the § 20.1 basename rule produces a good name
|
||||
with no special case, no file written into the user's store, and no second
|
||||
naming mechanism.
|
||||
|
||||
**The cost of deferring had been understated.** The workplan recorded this as
|
||||
reading poorly in one output line. It is not only display: the name reaches
|
||||
qualified references, the on-disk catalog layout (`catalog/registry/...`) and
|
||||
`index.yaml` rows (`registry: registry`). Once packages are installed and
|
||||
inclusions recorded, changing it is a migration rather than an edit — which is
|
||||
an argument for deciding early, not late.
|
||||
|
||||
Delivered:
|
||||
|
||||
- `default_registry()` returns `~/.canned-prompts/default`.
|
||||
- `check_legacy_registry` refuses to silently create a fresh empty store beside
|
||||
a populated `~/.canned-prompts/registry`. It names the exact `mv`, and the
|
||||
`--registry` flag for keeping the old one. Silently starting empty would have
|
||||
been worse than the wart being fixed.
|
||||
- The check fires only for the default path; an explicitly passed `--registry`
|
||||
is never second-guessed.
|
||||
- Docs updated in both READMEs. Tests 95 → 99.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue