Compare commits

..

3 commits

Author SHA1 Message Date
0300c5b142 Name the SCOPE-block mistake in compose warnings (REUSE-WP-0020-T03)
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 2s
ci / validate-registry (push) Successful in 1m20s
Build and Publish Container Image / build-and-push (push) Successful in 34s
An index row with no id now says whether it looks like a SCOPE.md capability
block, instead of leaving the author to work out why their repo contributes
nothing to the federated index. That confusion is invisible without a
diagnostic: the row is valid YAML, the file parses, and the member just
silently disappears.

Swept all 61 federation sources with --refresh: evidence-binder is the only
affected member. The other ten zero-count repos are genuine empty scaffolds.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 03:23:29 +02:00
9d015d4604 Record T07 done and the SCOPE-block root cause of T03
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 03:22:01 +02:00
823ce9e120 Add standard SCOPE.md sections and capability blocks (REUSE-WP-0020-T07)
Clears the hub scope check's C5b/C5c warnings: Relevant When, Not Relevant
When, How It Fits, Terminology, Related / Overlapping, and Provided
Capabilities were all missing, along with any fenced capability block.

The Terminology section calls out something this workplan ran into for real:
the fenced `capability` blocks in SCOPE.md (type/title/description/keywords)
look like index rows in registry/indexes/capabilities.yaml but are a different
shape and are not validated. evidence-binder copied the SCOPE block shape into
its index, which is why it had no `id` and broke federation composition.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 03:21:45 +02:00
5 changed files with 197 additions and 5 deletions

113
SCOPE.md
View file

@ -34,6 +34,119 @@ for reuse within this product boundary.
- Own unrelated adjacent systems or make irreversible operational decisions - Own unrelated adjacent systems or make irreversible operational decisions
without human approval. without human approval.
## Relevant When
- Deciding whether a capability already exists before planning or building one
(`reuse-surface plan-check`).
- Registering a new capability so it becomes visible for reuse.
- Promoting a capability along the D/A/C/R maturity axes with evidence.
- Comparing candidate capabilities by maturity, scope, relations, and consumer
guidance.
- Detecting overlap or duplication between capabilities across repos.
- Adding a sibling repo to the federation, or debugging why its index does not
appear in the federated view.
- Recording or interpreting reuse telemetry as R-axis evidence.
---
## Not Relevant When
- Hosting, running, or operating the capabilities themselves — the registry
describes capabilities, it does not execute them.
- Looking for a package registry, service catalog, issue tracker, or project
management system. Those are different tools with different guarantees.
- Judging internal code quality. Maturity here is about discovery and delivery,
not about how the implementation is written.
- Deploying the hub. The Kubernetes release lives in `railiance-apps`
(`charts/reuse-surface/`); this repo owns the image and the deploy guide only.
- Routing credentials. See `.claude/rules/credential-routing.md` — ops-warden
issues SSH certificates, OpenBao holds secrets.
---
## How It Fits
`reuse-surface` sits between planning and implementation. A workplan or intent
is checked against the federated index before work starts; the verdict is
reuse, extend, or new. Capabilities registered by sibling repos flow in through
federation, and observed reuse flows back as maturity evidence.
- **Upstream:** each sibling repo publishes `registry/indexes/capabilities.yaml`
from its own checkout. The repo owns its entries; this registry never edits
them.
- **Here:** the federation composer merges member indexes into
`registry/indexes/federated.yaml`, and the hosted hub serves the same view at
`GET /v1/federated`.
- **Downstream:** humans and agents query the index, the CLI, or the hub before
building. `plan-check --record-outcome` returns telemetry that feeds the
R axis.
State Hub is the coordination layer, not the registry: workplans and decisions
live there, capability descriptions live here.
---
## Terminology
| Term | Meaning |
|---|---|
| **Capability** | A reusable unit of function, described by a registry entry. Not a package, not a service — either can implement one. |
| **Maturity vector** | `D / A / C / R` — Discovery, Availability, Consumability, Reliability. See `specs/CapabilityMaturityStandard.md`. |
| **Registry entry** | Markdown with YAML front matter under `registry/capabilities/`, validated against `schemas/capability.schema.yaml`. |
| **Index** | `registry/indexes/capabilities.yaml` — one row per entry, the discovery surface for this repo. |
| **Federated index** | The composed view across all member repos. |
| **Member / source** | A repo registered in `registry/federation/sources.yaml` or on the hub. |
| **Hub** | The hosted service at `https://reuse.coulomb.social` that composes and serves the federated index. |
| **Promotion** | Raising a maturity axis, backed by evidence and recorded in `promotion_history`. |
**Note on two similar formats.** The fenced `capability` blocks in a repo's
`SCOPE.md` (`type` / `title` / `description` / `keywords`) are *not* the same
shape as index rows in `registry/indexes/capabilities.yaml`
(`id` / `name` / `summary` / `vector` / `domain` / `status` / `owner` / `path` /
`tags` / `consumption_modes`). SCOPE blocks are a prose-level advertisement;
index rows are validated registry data and require an `id`. Copying one shape
into the other is a real and observed failure mode — it silently breaks
federation for that member.
---
## Related / Overlapping
| Repo / system | Relationship |
|---|---|
| **State Hub** (`~/state-hub`) | Coordination read model: workplans, tasks, decisions, progress. Complementary — it tracks *work*, this tracks *capabilities*. |
| **railiance-apps** | Owns the Kubernetes release for the hub (`charts/reuse-surface/`, RAILIANCE-WP-0007). Deploys what this repo builds. |
| **ops-warden** | Credential and access routing. Explicitly out of scope here. |
| **Sibling domain repos** | Federation members. Each owns its own entries and index; this repo owns only composition and the standard. |
| **Package registries** (PyPI, npm, OCI) | Distribute artifacts. This registry describes capabilities and may reference artifacts, but does not host them. |
---
## Provided Capabilities
```capability
type: registry
title: Capability registration and maturity assessment
description: Register capabilities as validated Markdown entries with D/A/C/R maturity vectors, promotion history, and evidence, so they become discoverable and comparable for planning and implementation reuse.
keywords: [registry, capability, maturity, discovery, promotion, reuse, governance]
```
```capability
type: service
title: Capability index federation
description: Compose capability indexes published by many repos into one federated view, served locally by CLI and in production by a hosted hub with webhook-driven refresh and staleness visibility.
keywords: [federation, index, compose, hub, webhook, capabilities, cross-repo]
```
```capability
type: tooling
title: Pre-build reuse check
description: Match a draft workplan or free-text intent against the federated capability index and return a reuse, extend, or new verdict, bridging a new verdict to a State Hub capability request and recording the outcome as reuse telemetry.
keywords: [plan-check, reuse, verdict, planning, telemetry, capability-request]
```
---
## What Is Possible Now ## What Is Possible Now
The MVP registry foundation, CLI tooling (REUSE-WP-0003), federation stack The MVP registry foundation, CLI tooling (REUSE-WP-0003), federation stack

View file

@ -74,7 +74,7 @@
| task | REUSE-WP-0020-T02 | done | — | workplans/REUSE-WP-0020-coulombcore-retirement-cutover.md | | task | REUSE-WP-0020-T02 | done | — | workplans/REUSE-WP-0020-coulombcore-retirement-cutover.md |
| task | REUSE-WP-0020-T03 | wait | — | workplans/REUSE-WP-0020-coulombcore-retirement-cutover.md | | task | REUSE-WP-0020-T03 | wait | — | workplans/REUSE-WP-0020-coulombcore-retirement-cutover.md |
| task | REUSE-WP-0020-T04 | wait | — | workplans/REUSE-WP-0020-coulombcore-retirement-cutover.md | | task | REUSE-WP-0020-T04 | wait | — | workplans/REUSE-WP-0020-coulombcore-retirement-cutover.md |
| task | REUSE-WP-0020-T05 | progress | — | workplans/REUSE-WP-0020-coulombcore-retirement-cutover.md | | task | REUSE-WP-0020-T05 | done | — | workplans/REUSE-WP-0020-coulombcore-retirement-cutover.md |
| task | REUSE-WP-0020-T06 | todo | — | workplans/REUSE-WP-0020-coulombcore-retirement-cutover.md | | task | REUSE-WP-0020-T06 | todo | — | workplans/REUSE-WP-0020-coulombcore-retirement-cutover.md |
| task | REUSE-WP-0020-T07 | todo | — | workplans/REUSE-WP-0020-coulombcore-retirement-cutover.md | | task | REUSE-WP-0020-T07 | todo | — | workplans/REUSE-WP-0020-coulombcore-retirement-cutover.md |
| task | REUSE-WP-0020-T08 | done | — | workplans/REUSE-WP-0020-coulombcore-retirement-cutover.md | | task | REUSE-WP-0020-T08 | done | — | workplans/REUSE-WP-0020-coulombcore-retirement-cutover.md |

View file

@ -183,6 +183,26 @@ def resolve_source_index_path(
return _write_remote_cache(source["repo"], url, content, cache_dir), warnings return _write_remote_cache(source["repo"], url, content, cache_dir), warnings
SCOPE_BLOCK_KEYS = {"type", "title", "description", "keywords"}
def _shape_hint(item: dict[str, Any]) -> str:
"""Name the likely mistake when an index row has no id.
The fenced `capability` blocks in a repo's SCOPE.md use
type/title/description/keywords, which is close enough to an index row to
be copied into one by mistake — and then the member silently contributes
nothing. Say so instead of leaving the author to guess.
"""
if SCOPE_BLOCK_KEYS & set(item):
return (
" — looks like a SCOPE.md capability block"
" (type/title/description/keywords); an index row needs"
" id/name/summary/vector/domain/status/owner/path"
)
return ""
def _read_index_entries( def _read_index_entries(
index_path: Path, repo: str index_path: Path, repo: str
) -> tuple[list[Any], list[str]]: ) -> tuple[list[Any], list[str]]:
@ -234,7 +254,10 @@ def compose_federated_index(
continue continue
cap_id = item.get("id") cap_id = item.get("id")
if not cap_id: if not cap_id:
warnings.append(f"{source['repo']}: capability #{position} has no id, skipped") warnings.append(
f"{source['repo']}: capability #{position} has no id, skipped"
f"{_shape_hint(item)}"
)
continue continue
if cap_id in seen_ids: if cap_id in seen_ids:
warnings.append( warnings.append(

View file

@ -283,3 +283,33 @@ def test_malformed_source_still_listed_with_zero_count(tmp_path, monkeypatch):
) )
remote = next(s for s in federated["sources"] if s["repo"] == "remote-repo") remote = next(s for s in federated["sources"] if s["repo"] == "remote-repo")
assert remote["count"] == 0 assert remote["count"] == 0
def test_scope_shaped_row_names_the_mistake(tmp_path, monkeypatch):
"""A SCOPE.md capability block copied into an index should say so."""
body = """
version: 1
domain: helix_forge
capabilities:
- type: library
title: Evidence-to-target binding
description: Links evidence items to structured targets.
keywords: [evidence, binding]
"""
_, warnings = _compose_with_remote_body(body, tmp_path, monkeypatch)
hint = next(w for w in warnings if "remote-repo" in w)
assert "SCOPE.md capability block" in hint
assert "id/name/summary" in hint
def test_plain_missing_id_gets_no_scope_hint(tmp_path, monkeypatch):
body = """
version: 1
capabilities:
- name: Has a name but no id
summary: Something
"""
_, warnings = _compose_with_remote_body(body, tmp_path, monkeypatch)
hint = next(w for w in warnings if "remote-repo" in w)
assert "has no id" in hint
assert "SCOPE.md" not in hint

View file

@ -290,16 +290,42 @@ Two smaller production inconsistencies found while verifying T01:
```task ```task
id: REUSE-WP-0020-T07 id: REUSE-WP-0020-T07
status: todo status: done
priority: low priority: low
``` ```
Unrelated to the retirement, recorded so it is not lost. The hub's repo scope Unrelated to the retirement, recorded so it is not lost. The hub's repo scope
check reports `C5b`/`C5c` warnings: `SCOPE.md` is missing the standard H2 check reported `C5b`/`C5c` warnings: `SCOPE.md` was missing the standard H2
sections *Relevant When*, *Not Relevant When*, *How It Fits*, *Terminology*, sections *Relevant When*, *Not Relevant When*, *How It Fits*, *Terminology*,
*Related / Overlapping*, *Provided Capabilities*, and carries no fenced *Related / Overlapping*, *Provided Capabilities*, and carried no fenced
capability block. capability block.
**Done 2026-08-21** (`823ce9e`). All six sections added plus three `capability`
blocks.
Writing this section surfaced the **root cause of T03**. The fenced `capability`
blocks that belong in `SCOPE.md` use `type` / `title` / `description` /
`keywords` — which is *exactly* the shape `evidence-binder` put in its
`registry/indexes/capabilities.yaml`, where the required shape is `id` / `name`
/ `summary` / `vector` / `domain` / `status` / `owner` / `path` / `tags` /
`consumption_modes`. They did not invent a broken format; they copied a valid
one from the wrong place.
That makes it a systemic trap rather than a one-off mistake, so the Terminology
section now documents the distinction explicitly, and the compose warning now
names it:
```
evidence-binder: capability #0 has no id, skipped — looks like a SCOPE.md
capability block (type/title/description/keywords); an index row needs
id/name/summary/vector/domain/status/owner/path
```
**Federation swept 2026-08-21.** Composed all 61 sources with `--refresh`:
`evidence-binder` is the **only** affected member. The other ten zero-count
repos are genuine empty scaffolds and produced no warnings, so the confusion has
not spread.
## Fix Wall-Clock Rot In The Plan-Check Test Suite ## Fix Wall-Clock Rot In The Plan-Check Test Suite
```task ```task