CANP-WP-0002 T05: required versus observed, and typed context dependencies

The answer to the capability question was conditional: keep both fields if
they carry the required/observed distinction, fix the terminology if they do
not. They did not.

Section 9 opened with "records known requirements or observations", mixing
both in one field — `models` was observational ("known to be compatible or
evaluated") while `capabilities` was prescriptive ("expected from the
execution environment"). Section 10 then described dependencies as what a
prompt "expects". Both fields said expected, so the overlap was real
ambiguity rather than redundancy, and the fix is terminology.

`dependencies` now means **required**; `compatibility` means **observed**. A
consumer must not refuse to run a package because its environment is absent
from a compatibility list. The same capability name may legitimately appear in
both: required to run at all, and separately observed to work well on
particular models. `compatibility.aliases` records the same capability under
other names, so a consumer can recognize a requirement its environment labels
differently.

Dependencies now have three kinds, separated by what the format can do about
them: `prompts` it resolves by id and version; `context` names what it does
not package at all; `capabilities` are what the environment must be able to
do. Context entries use `name` rather than `id`, because nothing can look them
up, and `description` is required because nothing else can explain an
unpackaged dependency. A capability takes no version and no
`requirement: generate` — it is not an artifact and cannot be fetched, pinned
or generated. Capability names are free-form kebab-case, validated for shape
and not membership, exactly as tags are.

Section 10.1 also draws the line the format had never stated: an input is
content the caller passes for one use; a context dependency is a standing fact
about the environment.

Spec: 9 rewritten, 9.1 and 10.1 and 10.2 new, 10 reframed, 18 (rules 19-20),
4 updated. Former 10.1/10.2 renumbered to 10.3/10.4 with cross-references.

Reference CLI: validate_capabilities, validate_context_dependencies, and a
`resolve` section listing required capabilities and context under "this tool
cannot verify these" rather than implying it checked. Tests 51 -> 65.

Also drops an invented `session-review` capability from the example package in
favour of an honest `long-context` observation.

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 08:11:13 +02:00
parent 074fd79d53
commit c580bf63c9
8 changed files with 323 additions and 32 deletions

View file

@ -181,7 +181,7 @@ Declares what kind of artifact the package is. Optional; defaults to
| Value | Meaning |
|---|---|
| `template` | A complete prompt, intended to be used on its own |
| `fragment` | A reusable block intended for inclusion in other packages (§ 10.1) |
| `fragment` | A reusable block intended for inclusion in other packages (§ 10.4) |
`type` is advisory. A fragment is a perfectly valid package and MAY be
rendered on its own; the field records the author's intent so that a consumer
@ -233,7 +233,7 @@ output:
compatibility:
capabilities:
- code-analysis
- long-context
models: []
providers: []
@ -242,8 +242,12 @@ dependencies:
- id: context/repository-summary
version: 1.0.0
requirement: generate
context: []
capabilities: []
context:
- name: repository-tree
description: A listing of the repository under review.
requirement: optional
capabilities:
- code-analysis
examples:
- examples/basic.yaml
@ -313,7 +317,7 @@ always produce the same output. A consumer that satisfies a derived default
static fallback `value` when one is declared, and otherwise leaves the
input unresolved.
6. An included input default is satisfied by rendering the included package
(§ 10.2). This is deterministic, so a consumer that can render can satisfy
(§ 10.4). This is deterministic, so a consumer that can render can satisfy
it; one that cannot locate the package uses the static fallback `value`
when declared, and otherwise leaves the input unresolved.
7. Resolution MUST report which values were derived or included, so that a
@ -449,7 +453,7 @@ and draft packages.
#### Included default
A default may instead **include** another package's rendered template as text
(§ 10.2). Unlike a derived default this is deterministic and needs no model,
(§ 10.4). Unlike a derived default this is deterministic and needs no model,
so every implementation that can render can also include:
```yaml
@ -538,13 +542,18 @@ Registries MAY index output format for discovery.
## 9. Compatibility
`compatibility` records known requirements or observations without binding the package to one runtime.
`compatibility` records **observations**, never requirements.
Everything here describes where the package has been seen to work. Nothing here
is a precondition for using it, and a consumer MUST NOT refuse to run a package
because its environment is absent from these lists.
```yaml
compatibility:
capabilities:
- code-analysis
- long-context
aliases:
web-search: [browsing, tool-search]
models:
- example/model-family
providers: []
@ -552,15 +561,43 @@ compatibility:
Semantics:
- `capabilities`: abstract capabilities expected from the execution environment;
- `capabilities`: capabilities the package is known to work well with, whether
or not it requires them;
- `aliases`: the same capability as known by other names, so that a consumer
can recognize a requirement its environment labels differently;
- `models`: model identifiers known to be compatible or evaluated;
- `providers`: provider identifiers when provider-specific behavior matters.
An empty list means "not constrained/unspecified", not "compatible with nothing".
### 9.1 Required versus compatible
Earlier drafts described `compatibility` as recording "requirements or
observations" and `dependencies` as recording what a prompt "expects", so both
appeared to say the same thing about capabilities. They do not, and the
distinction is worth stating in one word each:
| Field | Meaning | Absence means |
|---|---|---|
| `dependencies` | **required** — the package does not work without it | a consumer SHOULD warn or refuse before running |
| `compatibility` | **observed** — the package is known to work with it | nothing; it is information, not a gate |
A capability the prompt cannot function without belongs in
`dependencies.capabilities`. A capability it merely benefits from, or has been
evaluated against, belongs in `compatibility.capabilities`. The same name may
legitimately appear in both: required to run at all, and separately observed to
work well on particular models.
## 10. Dependencies
Dependencies describe external artifacts or capabilities expected by the prompt.
Dependencies describe what a package **requires** in order to work (§ 9.1).
There are three kinds, separated by what CPF can do about them:
| Kind | Names | CPF can resolve it |
|---|---|---|
| `prompts` | other CPF packages | yes — by id and version (§ 10.3) |
| `context` | things CPF does not package | no — the consumer supplies them |
| `capabilities` | what the environment must be able to do | no — the environment either can or cannot |
```yaml
dependencies:
@ -570,13 +607,55 @@ dependencies:
requirement: optional
context:
- id: policy/security
- name: repository-tree
kind: information-space
description: A listing of the repository under review.
requirement: required
capabilities:
- web-search
```
### 10.1 Context dependencies
`context` names something the package needs that CPF neither packages nor
resolves: a live information space, an API, a corpus, a document the caller
supplies. Anything CPF *can* package is a package — a reusable policy or style
block belongs in `prompts` as a `type: fragment` package (§ 3.2), not here.
Entries use `name` rather than `id`, precisely because they are not package
identifiers and nothing can look them up.
| Field | Required | Meaning |
|---|---:|---|
| `name` | yes | What the context is called, in kebab-case |
| `description` | yes | What it is and what it must contain |
| `kind` | no | Free-form hint, e.g. `information-space`, `api`, `document`, `corpus` |
| `requirement` | no | `required` or `optional`; defaults to `required` |
`description` is required because nothing else can explain an unpackaged
dependency. A consumer meeting this entry has only the text to go on, and
INTENT principle 3 puts hidden context at odds with reuse.
A context dependency is not an input. An input is content the caller passes for
one use (§ 6); a context dependency is a standing fact about the environment
the package needs to be run in.
### 10.2 Capability dependencies
`capabilities` lists what the execution environment must be able to do, as
free-form lowercase kebab-case names — validated for shape, not for membership
in any vocabulary, exactly as `tags` are (§ 15). Standardizing model capability
vocabularies remains deferred; no real usage has yet asked for one.
A capability is not an artifact: it cannot be fetched, pinned or generated, so
it takes no version and no `requirement: generate`. It is either present or it
is not. A consumer that knows it lacks a required capability SHOULD say so
before running rather than after.
Where an environment knows the same capability by another name,
`compatibility.aliases` (§ 9) can record the correspondence.
Recommended requirement values:
- `required`
@ -585,7 +664,7 @@ Recommended requirement values:
`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.**
### 10.1 Naming and pinning a dependency
### 10.3 Naming and pinning a dependency
A dependency's `id` MAY be a qualified `<registry>:<id>` reference (§ 3.2).
An unqualified id is resolved by the consumer against whatever registries it
@ -614,7 +693,7 @@ solver: each dependency is selected independently against what is available,
and no consumer is expected to satisfy constraints across a dependency graph.
A single lower bound is a selector, not a constraint system.
### 10.2 Composition
### 10.4 Composition
A package composes another in one of two ways, both expressed as an input
default (§ 6.1) so that composition reuses the resolution machinery rather
@ -736,7 +815,7 @@ Each entry is a single-key mapping, so a check may appear more than once.
`output.criteria` is a list of statements about a good result. Judging them
requires running the prompt and assessing what comes back, which CPF does not
specify and most consumers cannot do. They are **declared, not run** — the
same division as `include` and `derive` in § 10.2, and for the same reason.
same division as `include` and `derive` in § 10.4, and for the same reason.
#### Results are not part of the package
@ -838,13 +917,17 @@ A v0.1 validator SHOULD verify at least:
14. no default declares both `include` and `derive`;
15. every dependency referenced by a composition or derived default declares a
`version`, and that version is a semver literal, `any`, `newest`, or a
`>=` lower bound (§ 10.1);
`>=` lower bound (§ 10.3);
16. inclusion does not form a cycle;
17. every eval file parses and declares a `schema`;
18. an eval declaring `canned-prompts/eval-rubric/v0.1` has a `name`, asserts
something via `render` or `output`, uses only known render checks, and —
when it declares an `example` — names a path listed in the manifest's
`examples`.
`examples`;
19. every `dependencies.context` entry declares a `name` and a `description`,
and a `requirement` of `required` or `optional` if present;
20. capability names in `dependencies.capabilities` and
`compatibility.capabilities` are lowercase kebab-case.
A validator SHOULD additionally warn when a package intended for publication
declares an inline derivation prompt (§ 6.1).