CANP-WP-0002 T02: registry-scoped identity and namespace ownership

Section 17 already defined what a registry does when the same id@version is
republished; nothing defined what a *consumer* does. That is where namespace
conflict actually bites — in the catalog, after installing from two
registries.

Identity is now registry-scoped: an id names a package within a registry, the
way a path names a file within a repository. A local-first format with no
signing, no federation and no central authority cannot enforce global
uniqueness, and an unenforceable guarantee is worse than none — it invites
consumers to conflate two packages that merely share a name. A qualified
`<registry>:<id>` reference distinguishes them, and `:` is now barred from ids
so the separator stays available.

Installing the same id from two registries is therefore not a conflict. The
catalog is namespaced by registry and keeps both.

Ownership is registry policy, not package data. An optional `registry.yaml`
names a registry and records namespace claims. Those claims are explicitly
descriptive — a filesystem registry cannot authenticate a publisher, and
`publish` says so rather than implying it checked. Keeping the claim out of
packages leaves artifacts free of unverifiable assertions of authority, and
means package semantics do not change when a hosted registry appears later.

Spec: 3.2 (registry-scoped identity, qualified references), 17 (immutability
scoped to a registry), 20.1 and 20.2 (new), 18 (registry-manifest
validation), 21 (qualified references, reserved `local` name).

Reference CLI: parse_reference, check_registry_name, read_registry_manifest,
registry_name, namespace_policy; registry_package_path and
catalog_package_path split; resolve_installed reports ambiguity and returns
the source registry; iter_catalog; `add --as`; closed-namespace warning on
publish. Tests 11 -> 21.

The catalog layout changed. An existing catalog is detected and reported with
instructions rather than failing as "package not found". Signing, trust
scoring and federation remain non-goals and were not touched.

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:
tegwick 2026-09-06 01:14:54 +02:00
parent 4a8422e1aa
commit ea70a59610
6 changed files with 533 additions and 45 deletions

View file

@ -117,7 +117,7 @@ Delivered:
```task
id: CANP-WP-0002-T02
status: todo
status: done
priority: high
state_hub_task_id: "a52cd41e-2bcc-50ee-96a1-d645a06df922"
```
@ -126,12 +126,54 @@ 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).
**Sharpened during the work.** § 17 already said what a *registry* does on
collision; nothing said what a *consumer* does. That is where the conflict
actually bites — in the catalog, after installing from two registries.
**Decisions (operator, 2026-09-06):**
- *Identity is registry-scoped.* An id names a package within a registry, the
way a path names a file within a repository. The same id from two registries
may be two different packages. A local-first format with no signing, no
federation and no central authority cannot enforce global uniqueness, and an
unenforceable guarantee is worse than none — it invites consumers to
conflate two packages that merely share a name. A qualified
`<registry>:<id>` reference distinguishes them.
- *Ownership is registry policy.* An optional `registry.yaml` names the
registry and records namespace claims (`owner`, `policy: open | closed`).
Packages never assert who owns their namespace, keeping unverifiable
authority claims out of artifacts (§ 19) and leaving package semantics
unchanged when a filesystem registry is later replaced by a hosted one.
- *Installing the same id from two registries is allowed, not a conflict.* The
catalog is namespaced by registry, so both are retained. This follows from
registry-scoped identity rather than working around it: two packages that
merely share a name were never in conflict to begin with.
Delivered:
1. § 3.2 gains "Identity is registry-scoped" — the reasoning, the qualified
reference form, and a ban on `:` in ids so the separator stays available.
A tool finding one id in several registries MUST report the ambiguity.
2. § 17 scopes immutability to a registry, consistent with identity.
3. § 20.1 (new) specifies the optional `registry.yaml`: `format`, `name`,
`description`, `namespaces`. Claims are explicitly descriptive — a
filesystem registry cannot authenticate a publisher. A bare directory
remains a valid registry, named by its basename.
4. § 20.2 (new) requires consumers to keep registries distinct and documents
the reference catalog layout.
5. § 18 gains registry-manifest validation; § 21 documents qualified
references and the reserved `local` registry name.
6. `reference/canned_prompts.py`: `parse_reference`, `check_registry_name`,
`read_registry_manifest`, `registry_name`, `namespace_policy`, split
`registry_package_path` / `catalog_package_path`, a `resolve_installed`
that reports ambiguity and returns the source registry, `iter_catalog`,
`--as` on `add`, a publish-time warning on closed namespaces, and a
specific error for the pre-registry-scoped catalog layout. Tests 11 → 21.
**Migration note:** the catalog layout changed. An existing catalog from
before this change is detected and reported with instructions rather than
failing as "package not found". Signing, trust scoring and federation remain
non-goals and were not touched.
## Prompt composition and inheritance