# RFC 0177: v2 registry, packs, and the extension tail — the absent-ceiling rule, a parallel `registry/v2/` tree, the peer-dependency alias table generated from the declaration file, one signing scheme, the vendor hatch on every pack-authored document, and the chain / form / connection decisions three gap tables deferred

> Source: https://openwop.dev/rfcs/0177-v2-registry-packs-and-extension-tail.html · OpenWOP, the open-source protocol for multi-agent workflow orchestration. CC BY 4.0.

| Field             | Value                                                           |
| ----------------- | --------------------------------------------------------------- |
| **RFC**           | 0177                                                            |
| **Title**         | v2 registry, packs, and the extension tail: a v2 host reads an absent `engines.openwop` ceiling as `<2.0.0` and refuses with `pack_engine_unsupported` at install, on every publication path including a mirror; `registry/v2/` is a parallel published tree of re-signed manifests (a signed overlay is rejected: signatures authorize by namespace and the mirror path re-derives the signer at ingest); the peer-dependency identifier is the C.2 declaration-file key and `pack_peer_dependency_undefined` reads against that file, with a generated alias table for the four grammars in the wild and a scheduled removal; the 13 manifest schemas re-`$id` under `/spec/v2/` with the RFC 0138 hatch on every pack-authored document (RFC 0138 G4 decided); `signing.method`'s two conventions that sign different bytes become one `signing.scheme`; `publicKeyRef` and `kind`-absent are gone; the registry is versioned by tree and its `endpoints` map is the negotiation; provider-id precedence (RFC 0095 UQ4) is decided as fail-closed conflict with a qualified form; form-content packs reuse the edge-condition operator set and `i18n.md`'s localized string; chains pin exact versions (WCP2), children are reference-counted (WCP5), and the portable parameter deferral (WCP4) is a named v2.x follow-up |
| **Status**        | `Accepted`                                                        |
| **Author(s)**     | David Tufts (@davidscotttufts)                                  |
| **Created**       | 2026-09-03                                                      |
| **Updated**       | 2026-09-28 — Class 3 correction (#1706): the pack scenarios no longer gate on `packs`, which advertises registry resolution only (`docs/COMPATIBILITY-CORRECTIONS-LOG.md`). · 2026-09-03 (`Draft → Active` in the filing PR. **Comment window waived** under `GOVERNANCE.md` §"Sole-steward operation" and logged in `MAINTAINERS.md`; RFC 0001 §5 cross-org rule not yet active; RFC 0147 §A.6 overridden and named in the parent, RFC 0167 (pack trust path and signing). Adversarial review recorded below.) · 2026-09-03 (filed) · 2026-09-18 (`Active → Accepted`). **Evidence tier: tier-1 AND tier-2 — both required.** This is the only v2 child no single host witnesses: `provider-conflict` is `executed-pass` on `myndhyve` build `commit:46917218d19f`, suite **2.1.7** (five of the 79 scenario files applicable at major 2 were not yet in that suite and have no row), both claimed profiles certified. and `inapplicable` on the reference host, while the pack-manifest ids are `executed-pass` on `openwop-host-v2-reference` build `commit:87cb8a007d05`, suite 2.4.2, `witnessSha256 9217e347b85f…`, signed `v2-reference-3`, all three profiles certified. **Stated plainly:** that host is tier-1 by `GOVERNANCE.md` §"Acceptance evidence tiers" (a reference host in `openwop-examples`), but it is run from the pinned example and its bundle's `discovery.url` is `http://127.0.0.1:3838` — it is not a host that serves traffic, and this acceptance does not call it deployed. and `inapplicable` on MyndHyve. Neither bundle alone satisfies the falsifiability table. |
| **Affects**       | **Part of: RFC 0167 — child C10.** v2 (Phase 3): `spec/v2/core/packs.md` (NEW: the ceiling rule, install-time refusal, the alias table, one scheme), `schemas/v2/*-manifest.schema.json` × 13 (`$id` under `/spec/v2/`; hatch on `agent-manifest` and `prompt-template`; `signing.scheme`; `keyId` only; `kind` required), `openwop-registry` `registry/v2/` tree with regenerated index, SBOMs and signatures and a `.well-known/openwop-registry.json` `endpoints` map naming both trees, `spec/v2/peer-dependency-aliases.json` generated by `check-declaration.mjs` from the 282 published manifests, `spec/v2/core/connection-packs.md` (precedence), `spec/v2/core/form-content-packs.md` (`when`, localized strings), `spec/v2/core/workflow-chain-packs.md` (exact pins, reference counting); v1.x (this PR): `spec/v1/migrations.json` rows `openwop.migration.C10.1`–`C10.15`; codemods `openwop.codemod.pack-manifest-v2` (C10.1, C10.6, C10.7, C10.8), `openwop.codemod.node-pack-ui-hints` (C10.2), `openwop.codemod.workflow-definition-v2` (C10.3); deprecation rows `engines-absent-ceiling`, `pack-peer-dependency-aliases`, `manifest-signing-method`, `connection-provider-version-precedence` (`proposed`) |
| **Compatibility** | `breaking` (v2). In v1.x this PR changes no wire shape; rows, codemods and register entries only |
| **Supersedes**    | — (amends RFC 0095 §B.6 clause 6, RFC 0133 §Unresolved 2, RFC 0137 G1/G3, RFC 0138 §Out of scope for v2) |
| **Superseded by** | —                                                               |

## Summary

156 packs, 282 published versions, each a signed quad (manifest, SBOM, detached Ed25519 signature, tarball). 136 versions pin `<2.0.0`; 146 have no ceiling; none declares anything else — so under any honest rule every published version refuses on a v2 host and the re-publish wave is total, not optional. 280 of 282 use the deprecated `publicKeyRef`; 280 declare `method: manual` and 2 `ed25519`, which the schema calls synonymous and the verifier treats as signatures over different bytes; `build-index` defaults to the convention almost nobody uses. `peerDependencies` is an open string map with no reference to the capability vocabulary, which is how `host.fs`/`fs` and `host.queueBus`/`queueBus` both got signed into the tree, next to a third grammar (`openwop.agents.memoryBackends`) and facet paths used as identifiers. The registry validates every pack against a vendored copy of the node-pack schema that lacks the very hatch RFC 0138 added, and it is unpinned. Two of the 13 manifest schemas still forbid the vendor field `host-extensions.md` requires them to carry. Three gap tables hold decisions about chain pinning, child ownership, conditional visibility, i18n and provider-id precedence that this RFC makes.

## Motivation

- **The ceiling.** `engines.openwop` over 282 manifests: `>=1.0.0` 145, `>=1.0.0 <2.0.0` 86, `>=1.1.0 <2.0.0` 47, `>=1.1 <2.0.0` 3 (a two-segment grammar the others do not use), `>=1.1.0` 1. Every byte is under a detached signature; nothing can be edited in place. `node-pack-manifest.schema.json` `engines.openwop` is a free string with an example, and `additionalProperties: true` on the block.
- **Three trust paths, one file that none of them would read.** Canonical publication is a PR wave (`writeApi.supported: false`, `publishMethod: "github-pull-request"`); `verify-signatures.mjs:135–142` authorizes by `signingKeys[].permittedNamespaces`; MyndHyve runs its own `PUT /v1/packs/…` registry keyed on `publicKeyRef` (`routes/packs.ts:22–30`) and a super-admin mirror that re-derives `signedByKeyId` at ingest (`routes/openwopMirror.ts`). A `compatibility-overlay.json` would need five per-namespace signatures and would still be invisible to the mirror.
- **Two conventions, one word.** `registry-version-manifest.schema.json:132` — "`manual` and `ed25519` both denote a detached Ed25519 signature over canonical-JSON pack.json (synonymous in practice)"; `registry/scripts/verify-signatures.mjs:150–171` — `ed25519` signs the whole gzipped tarball, `manual` signs `pack.json` inside it; `build-index.mjs:190` defaults to `'ed25519'` while 280 of 282 say `manual`. Axiom 2, inside the trust path.
- **Identifiers.** `node-pack-manifest.schema.json:102–108` `peerDependencies: { additionalProperties: string }` — no enum, no pattern, no `$ref`. In the tree: `aiProviders` 67, `host.agentRuntime` 41, `openwop.agents.memoryBackends` 11, `host.fs` 2 / `fs` 1, `host.queueBus` 2 / `queueBus` 1, `host.aiEnvelope.await`, `aiProviders.imageGeneration`, `aiProviders.videoGeneration`. `agent-manifest.schema.json:58` offers `host.workspace` as an example of a legitimate requirement; `host-capabilities.md:2186–2188` reserves it and requires rejection with `pack_peer_dependency_undefined`. RFC 0169 §B.1–§B.2: the declaration file is the identifier and `check-declaration.mjs` fails on a peer-dependency key it does not name.
- **The hatch.** RFC 0138 §Out of scope (`:92`) and §Unresolved 4 (`:176`) defer `agent-manifest` and `prompt-template` "to their owners"; `agent-manifest` is `$ref`'d from `node-pack-manifest.schema.json:134`, so a pack that may carry `x-` at its root may not carry it in its own `agents[]`. The registry's vendored `node-pack-manifest.schema.json` (`openwop-registry/schemas/`, 7 of 13 drifted, no `CORPUS_TAG`, `check-vendored-sync.mjs` on `main`) has `additionalProperties: false` at `:320` and `:641` with no `patternProperties` — the registry rejects the field the protocol requires it to carry (H34 class).
- **Prefix and `$id`.** `.well-known/openwop-registry.json` `endpoints`: five of six carry `/v1/`, `publicKey` does not; `endpointAliases._note` already tells clients to consult `endpoints`. The 13 schema `$id`s are under `/spec/v1/` and immutable (RFC 0172 row C5.7); the version manifests themselves carry no `$id` (the charter's "every manifest `$id`s on `spec/v1`" is true of the schemas).
- **Three gap tables.** `connection-packs.md:277` UQ4 (two packs claiming `github`; the scenario `connection-provider-resolution` never tests two claimants; 12 connection packs published); `form-content-packs.md:180–184` G1 (a second expression language), G3 (no i18n), R1 (no reference host; one pack published); `workflow-chain-packs.md:508–512` WCP2 (135 of 282 versions are chains), WCP4, WCP5 (= RFC 0133 §Unresolved 2, whose siblings were resolved by persisting the resolved version in the ownership record).
- **Register state.** `openwop.migration.C10.1` is a `rename` with `codemod: null` — §G.1 fails the moment this child is Active unless it has one; `kind` is absent on 131 of 282 manifests while `index.json` carries it; `deprecations.json` has 32 rows where the umbrella prose says 26 (the six newer rows are RFC 0172/0174/0178's).

## Proposal

### §A. The ceiling and the tree

**§A.1 Absent ceiling reads `<2.0.0`.** A v2 host evaluating `engines.openwop` MUST treat a range with no upper bound as bounded by `<2.0.0` and MUST refuse to install a version whose range does not admit the host's protocol major with `pack_engine_unsupported` (a registered error; `pack_runtime_requirement_unmet` stays for runtime, not protocol). The check runs at **install**, on every publication path — the canonical registry, a vendor registry's write API, and a mirror ingest — so a registry-side artifact cannot be bypassed. A v2 manifest MUST declare an explicit upper bound; the schema enforces the grammar (three-segment, `>=` lower, `<` upper).

**§A.2 `registry/v2/`.** The registry publishes a parallel tree `registry/v2/packs/<name>/-/<version>.{json,sbom.json,sig,tgz}` of re-signed manifests produced by the same `build-pack-tarball.mjs --signed` path (`:312`, Ed25519 over canonical JSON) with SBOMs regenerated, index regenerated, and `signing.scheme` explicit. A signed `compatibility-overlay.json` is **rejected**: `verify-signatures.mjs` authorizes by namespace, so one overlay cannot cover five namespaces, and the mirror path would never read it. The v1 tree is served read-only through Phase 5.

**§A.3 The registry's prefix.** The registry is a static tree and cannot negotiate by header; it is **versioned by tree** — the C.5 rule permits one mechanism, not both. `.well-known/openwop-registry.json` `endpoints` gains the `/v2/` templates beside the `/v1/` ones and is the negotiation: clients MUST resolve paths through `endpoints`; `publicKey` stays unversioned by design (keys are not protocol-versioned) and the map's note says so.

### §B. Identifiers

**§B.1** The pack peer-dependency identifier **is** the C.2 declaration-file key (RFC 0169 §B.1: root key ≡ peer-dependency identifier ≡ section anchor). `pack_peer_dependency_undefined` is raised for a key the declaration file does not name — the hardcoded prose list at `host-capabilities.md:2184–2186` is retired with it; `host.workspace` is `workspace` (RFC 0169 §B.3). Facet paths (`aiProviders.imageGeneration`, `host.aiEnvelope.await`, `multiAgent.executionModel.verifier`) are not identifiers: a pack requires a family and names facets in `peerDependenciesMeta.<family>.facets[]`.

**§B.2 The alias table.** `spec/v2/peer-dependency-aliases.json` is generated by running `check-declaration.mjs` over every published manifest; each unresolvable key becomes a row `{ alias, family, facets?, removalTrigger }`. At filing the guaranteed rows are `host.fs → fs`, `host.queueBus → queueBus` (the dotted twins), `openwop.agents.memoryBackends → agents.memoryBackends`, `host.workspace → workspace`, and the three facet paths; `aiProviders` (67) and `host.agentRuntime` (41) follow C.2's rename of those two keys. A v2 host MAY resolve an alias through the table through the overlap and MUST NOT after v1 end-of-support (`removalTrigger: v1-end-of-support`).

### §C. The manifest schema family

**§C.1** The 13 schemas re-`$id` under `https://openwop.dev/spec/v2/`; the v1 `$id`s are immutable and served read-only (RFC 0172 C5.7). **§C.2 The hatch.** `^(x-|vendor\.)` patternProperties on every **pack-authored** document: the ten that have it, plus `agent-manifest` and `prompt-template` (RFC 0138 G4 decided: same treatment; the `$ref` boundary at `node-pack-manifest.schema.json:134` no longer stops the hatch). `pack-lockfile` (host-generated) and `security-advisory` (registry-authored) stay closed; `prompt-ref` is a leaf. **§C.3 One scheme.** `signing.method` is deleted; `signing.scheme` is required with the single value `ed25519-canonical-json` (the `manual` convention: a detached 64-byte Ed25519 signature over the canonical-JSON `pack.json` inside a deterministic tarball); the tarball-bytes convention is retired with the two packs that use it re-signed in `registry/v2/`; `build-index` has no default. **§C.4** `publicKeyRef` is deleted (`keyId` only; row C10.1 with a codemod). **§C.5** `kind` is required on every version manifest (the 131 absent are `node`; the codemod writes it). **§C.6** The registry's vendored schemas are pinned (RFC 0176 §E.1) and re-synced from the tag before any v2 publication; the drift that dropped the hatch is closed in that sync.

### §D. Provider-id precedence (RFC 0095 UQ4)

**§D.1** A `provider.id` is unique per host. When an installed pack and a built-in, or two installed packs, define the same bare id the host MUST refuse the later registration with `connection_provider_conflict` — the version-based precedence in `connection-packs.md` clause 6 (`:86–94`) is deleted (Axiom 2: a rule that picks silently by version is two names for one thing). A connector MAY name a provider by its qualified form `<packName>#<id>` to disambiguate; a bare id resolves only when exactly one definition exists. Built-ins are the host's own pack for this rule.

### §E. Chain, form, and content packs — reuse, do not mint

**§E.1 Chains.** A chain reference MUST pin an exact version per referenced `typeId` (`core.ai.callPrompt@1.0.0`); ranges are a v2.x additive follow-up (WCP2 decided). **§E.2** Co-registered children are reference-counted by deterministic child id and deleted when the last parent is deleted; the ownership record persists the resolved version (RFC 0133 §Unresolved 1's mechanism) and is a C.9 store (WCP5 / RFC 0133 G5 decided). **§E.3** The `{{params.*}}` portable deferral stays forbidden in v2.0; the follow-up additive RFC is named as G4 with the variable-binding recipe from `workflow-chain-packs.md:512` (WCP4 decided as "not in v2.0", a decision with an owner). **§E.4 Forms.** Conditional visibility uses the edge-condition operator set (`when: <EdgeCondition>` on a field; no second expression language — RFC 0137 G1); `label`/`title`/`description` are `i18n.md` localized strings (G3); `minLength`/`min`/`max`/`pattern` are added (G2). **§E.5** The five `format` values stay the core set (G4 stands).

### §F. The MyndHyve cohort and the wave

38 `vendor.myndhyve.*` packs / 40 versions, all `>=1.0.0 <2.0.0`, are re-published under `myndhyve-internal-1` into `registry/v2/` in Phase 4 with the host; the mirror and the `PUT` API apply §A.1 at install. The core wave (109 packs) is a scripted operation on the existing generators (`gen-*-packs.mjs`, `build-pack-tarball.mjs`) and lands in Phase 3 as the registry's evidence.

## Migration table

| Row | Kind | v1 | v2 | Codemod | Persisted data |
| --- | --- | --- | --- | --- | --- |
| `openwop.migration.C10.1` | rename | `signing.publicKeyRef` | `signing.keyId` | `openwop.codemod.pack-manifest-v2` (refuses when both are present and differ) | never-upgraded (re-signed in `registry/v2/`) |
| `openwop.migration.C10.2` | rename | `x-openwop-form.credentialProvider` (node config ui hint) | `provider` | `openwop.codemod.node-pack-ui-hints` | never-upgraded |
| `openwop.migration.C10.3` | rename | workflow definition `config.outputArtifactType` / `config.chatCard` | `node.artifactType` / `node.chatCard` | `openwop.codemod.workflow-definition-v2` | translated |
| `openwop.migration.C10.4` | behavior | `engines.openwop` free string; absent ceiling read as open | absent ceiling ⇒ `<2.0.0`; `pack_engine_unsupported` at install on every path; explicit upper bound required | — (the codemod refuses a manifest with no v2-satisfiable range; the author declares) | never-upgraded |
| `openwop.migration.C10.5` | add | one tree `registry/v1/` | `registry/v2/` parallel tree; `endpoints` names both | — | never-upgraded |
| `openwop.migration.C10.6` | rename | four peer-dependency grammars (`host.*` dotted, bare, `openwop.*`, facet paths) | declaration-file keys; `peerDependenciesMeta.<family>.facets[]`; alias table with `v1-end-of-support` removal | `openwop.codemod.pack-manifest-v2` | never-upgraded |
| `openwop.migration.C10.7` | unify | `signing.method: manual \| ed25519 \| sigstore` (two byte conventions) | `signing.scheme: ed25519-canonical-json` | `openwop.codemod.pack-manifest-v2` (refuses `ed25519`-over-tarball and `sigstore`: a re-sign, not a rewrite) | never-upgraded |
| `openwop.migration.C10.8` | require | `kind` absent ≡ `node` (131 of 282) | `kind` required | `openwop.codemod.pack-manifest-v2` | never-upgraded |
| `openwop.migration.C10.9` | behavior | 13 schema `$id`s under `/spec/v1/`; hatch on 10 | `$id`s under `/spec/v2/`; hatch on every pack-authored document | — | not-persisted |
| `openwop.migration.C10.10` | behavior | clause 6 version precedence | `connection_provider_conflict` fail-closed; `<packName>#<id>` qualified form | — | not-persisted |
| `openwop.migration.C10.11` | add | none | form-content `when: <EdgeCondition>`, localized strings, `minLength`/`min`/`max`/`pattern` | — | not-persisted |
| `openwop.migration.C10.12` | require | chain reference pin RECOMMENDED | exact version per `typeId` MUST | — | unchanged (135 chain manifests already pin) |
| `openwop.migration.C10.13` | behavior | child ownership lifecycle open (WCP5) | reference-counted by deterministic id; ownership record persists the resolved version | — | unchanged |
| `openwop.migration.C10.14` | behavior | registry `/v1/` on five of six endpoints | versioned by tree; `endpoints` is the negotiation; `publicKey` unversioned by design | — | not-persisted |
| `openwop.migration.C10.15` | require | registry vendored schemas unpinned, 7 of 13 drifted | pinned to a tag; re-synced before any v2 publication | — | not-persisted |

## Persisted-data disposition

| Store | v1 artifact | Disposition |
| --- | --- | --- |
| `registry/v1/packs/**` (282 manifests, SBOMs, signatures, tarballs) | signed quads | never-upgraded; served read-only through Phase 5 |
| `registry/v2/packs/**` | — | new; re-signed by the same keys under `signingKeys[].permittedNamespaces` |
| `registry/v1/index.json`, `.well-known/openwop-registry.json` | index; endpoints map | index unchanged; the map gains the `/v2/` templates |
| MyndHyve internal registry catalog (`PUT` API + mirror ingest) | packs keyed on `publicKeyRef` | never-upgraded; §A.1 applied at install in Phase 4 |
| Host-side installed-pack records and lockfiles (`pack-lockfile`) | installed v1 manifests | unchanged; a v2 host re-evaluates §A.1 at next install, not retroactively |
| Chain ownership records (RFC 0133) | resolved child versions | unchanged; §E.2 makes the record normative |
| Workflow definitions with `config.outputArtifactType` / `config.chatCard` | deprecated bag entries | translated by `openwop.codemod.workflow-definition-v2` on export; read through the definition adapter |

## Compatibility

`breaking` (v2). This PR changes no v1.x wire shape.

## Conformance

v2 scenarios (suite 2.0.0): `manifest-ceiling-refused` (gated on the seams-profile install path; §A.1 binds at install on every path, not on `packs`: an unbounded and a `<2.0.0` manifest are both refused with `pack_engine_unsupported`; a `>=2.0.0 <3.0.0` one installs), `peer-dependency-declared` (gated: an undeclared key is refused with `pack_peer_dependency_undefined`; an alias resolves through the overlap), `manifest-hatch-carried` (an `x-` field inside `agents[]` and `prompts[]` is ignored, not rejected), `one-signing-scheme` (registry corpus gate: every `registry/v2/` manifest declares the scheme and verifies), `provider-conflict` (gated on `connections.packsSupported`: two claimants fail closed; the qualified form resolves), `chain-pin-exact` (a ranged reference is refused at register), `form-when-reuses-edge-conditions` (gated on `forms`: the `when` grammar is the edge-condition grammar). *(Corrected 2026-09-28, Class 3, #1706: these read "gated on `packs`". `packs` advertises registry resolution, which a host installing only local packs correctly omits.)*

### Falsifiability — one row per normative requirement

| Requirement | Observable | Who can cause the condition | Verdict |
| --- | --- | --- | --- |
| §A.1 unbounded/`<2.0.0` refused at install | `pack_engine_unsupported` — `openwop.requirement.0177.manifest-ceiling-refused` | the suite, gated on the seams-profile install path; §A.1 binds at install on every path, not on `packs` *(corrected 2026-09-28, #1706)* | witnessable — gated |
| §A.2 `registry/v2/` verifies under the same keys | registry gate | the registry's `registry-check.sh` | witnessable — unaided (corpus) |
| §A.3 `endpoints` names both trees | the well-known registry document | the suite, unaided | witnessable — unaided |
| §B.1 undeclared key refused; facet paths not identifiers | `pack_peer_dependency_undefined` — `openwop.requirement.0177.peer-dependency-declared` | the suite, gated on the seams-profile install path; the rule binds at install on every path, not on `packs` *(corrected 2026-09-28, #1706)* | witnessable — gated |
| §B.2 alias table generated, not hand-kept | `check-declaration.mjs` over the manifests — `openwop.requirement.0169.declaration-parity` | the corpus gate | witnessable — unaided (corpus) |
| §C.2 hatch on `agents[]`/`prompts[]` | install accepts the `x-` field — `openwop.requirement.0177.manifest-hatch-carried` | the suite, gated on the seams-profile install path; the rule binds at install on every path, not on `packs` *(corrected 2026-09-28, #1706)* | witnessable — gated |
| §C.3–§C.5 one scheme, `keyId`, `kind` | schema + registry gate — `openwop.requirement.0177.one-signing-scheme` | the corpus gate | witnessable — unaided (corpus) |
| §D.1 conflict fails closed | `connection_provider_conflict` — `openwop.requirement.0177.provider-conflict` | the suite via the RFC 0095 `install`/`resolve` seams | seam-gated |
| §E.1 exact pin | refusal at register — `openwop.requirement.0177.chain-pin-exact`, and `…chain-pin-exact.external-range-refused` for the EXTERNAL `subChainRef` branch, whose `version` the schema types as a semver *range* and therefore cannot refuse | the suite, gated on `workflowChainPacks` | witnessable — gated (the sibling-string legs are satisfied by schema validation alone, so this row reads **host-enforced** only for bundles cut on suite 2.4.1 or later) |
| §E.2 reference counting | host-side lifecycle | the suite via the chain seams | seam-gated |
| §E.4 `when` is the edge-condition grammar | schema + a form pack fixture — `openwop.requirement.0177.form-when-reuses-edge-conditions` | the suite, gated on `forms` (no reference host: `host-pending`) | witnessable — gated |

## Adversarial review

1. **Refusing 100% of published versions on a v2 host is a cliff, not a migration.** Disposition: it is the honest reading of immutable data; the wave is scripted on generators that already exist; `registry/v2/` lands in Phase 3 as the registry's own evidence before any host cuts; the v1 tree keeps serving v1 hosts.
2. **A signed overlay is cheaper than re-signing 282 quads.** Disposition: rejected on two facts — signatures authorize by namespace (five overlays, five keys) and the mirror path re-derives the signer at ingest and would never consult it; §A.1's install-time check is what makes the rule wire-observable regardless of which registry served the pack.
3. **Deleting `method` breaks the two `ed25519`-over-tarball packs.** Disposition: they are re-signed in `registry/v2/` under the one scheme; the codemod refuses them rather than relabeling a signature over different bytes.
4. **Facet paths as identifiers were legitimate under RFC 0105.** Disposition: RFC 0169 §B.3 already decided the `aiProviders.*` pair; `peerDependenciesMeta.<family>.facets[]` keeps the expressiveness with one identifier grammar.
5. **The registry is "versioned by tree" while the protocol is "by header" — that is the both C.5 forbids.** Disposition: C.5 forbids both mechanisms on one surface; the registry has no request handler to read a header and uses one mechanism (tree), the protocol uses one (header); the `endpoints` map is the indirection both share.
6. **Fail-closed provider conflict breaks a host that legitimately ships a built-in `github` and installs the community pack.** Disposition: the host names its built-in `<hostPack>#github` or does not install the conflicting pack; silent precedence by version is the Axiom 2 failure UQ4 asked about; the qualified form is the disambiguation.
7. **WCP4 is "decided" by deferring.** Disposition: the decision is that v2.0 keeps the expansion-time MUST; the follow-up is registered as G4 with the recipe and an owner, which is what the three gap tables lacked.
8. **The registry's vendored schema drift is a registry bug, not a protocol rule.** Disposition: it is both; §C.6 and RFC 0176 §E.1 make the pin a MUST so the H34 class cannot recur in the repository that gates publication.

## Alternatives considered

1. Read an absent ceiling as open (v2-compatible). Rejected: 146 versions would install on a host whose capability names they no longer match.
2. A signed `compatibility-overlay.json`. Rejected: §A.2, adversarial review 2.
3. Keep `method` with `manual` and `ed25519` documented as different. Rejected: Axiom 2; one scheme, one set of bytes.
4. Scoped provider ids everywhere (`core.github`, `community.x.github`). Rejected: renames 12 published connection packs for a conflict that fail-closed plus a qualified form already prevents.

## Unresolved questions

1. Whether `registry/v2/` should carry only versions re-published by their authors or also steward re-signs of `core.openwop.*` under `openwop-team-1`. Recommended: steward re-signs for `core.*` and `vendor.openwop*`; vendor cohorts re-publish themselves.

## Implementation notes (non-normative)

The alias table's first generation is a dry run of `check-declaration.mjs` over `registry/v1/packs/**/-/*.json` once `spec/v2/declaration.json` exists (Phase 3, RFC 0169). `build-index.mjs:190`'s default is removed in the same registry PR that adds `registry/v2/`.

## Acceptance criteria

- [x] `Draft → Active`: RFC text; rows `C10.1`–`C10.15`; three codemods with fixtures; four deprecation rows with detectors; ledger row; adversarial review. (This PR.)
- [x] `Active → Accepted` (Phase 3): `spec/v2/core/packs.md`; the 13 v2 schemas; `registry/v2/` with the core wave and a green `registry-check.sh`; `spec/v2/peer-dependency-aliases.json` generated; the seven scenarios; the registry's schemas pinned. — evidence: `registry-check.sh` green over 156 packs, 191 v2 and 282 v1 version manifests each signed by a key the registry permits for its namespace. **The registry's pin was bumped to `v2.4.3` before this box was ticked** (openwop-registry#67): it stood at `v2.4.1`, and ticking a "schemas pinned" clause against a two-release-stale pin would have claimed something unchecked. **`reason:` the openwop-app clause is dropped from the tick.** All three ids it names record `inapplicable` there — "host does not advertise conformance.seamsProfile: openwop-conformance-seams-v2" — the mounted-vs-built distinction `GOVERNANCE.md` draws, same as RFC 0176. **This child is also the one that genuinely needs BOTH certified bundles:** `openwop.requirement.0177.provider-conflict` is `executed-pass` on MyndHyve ONLY — the reference host records `inapplicable`, it does not advertise the connections profile — while the ceiling, hatch, peer-dependency and chain-pin ids are `executed-pass` on the reference host. Disclosed: `form-when-reuses-edge-conditions` is `inapplicable` on all three with a stated reason, and its falsifiability verdict declares `host-pending`, so RFC 0174 §B.1's second branch accounts for it rather than a pass.

## References

- `spec/v1/node-packs.md` §`engines`, §`x-openwop-form`; `spec/v1/host-capabilities.md` §"Reserved-but-undocumented surfaces"; `spec/v1/connection-packs.md` §Manifest clause 6, UQ4; `spec/v1/form-content-packs.md` §Open spec gaps; `spec/v1/workflow-chain-packs.md` §Open spec gaps; `spec/v1/registry-operations.md`
- RFC 0095 §B.6; RFC 0107; RFC 0133 §Unresolved; RFC 0137; RFC 0138 §Out of scope, §Unresolved 4; RFC 0167 §C/§F; RFC 0169 §B; RFC 0172 §A.2, C5.7; RFC 0176 §E.1
- `openwop-registry`: `registry/.well-known/openwop-registry.json`, `registry/scripts/verify-signatures.mjs:130–186`, `registry/scripts/build-index.mjs:190`, `scripts/build-pack-tarball.mjs:312`, `scripts/registry-check.sh`, `scripts/check-vendored-sync.mjs:17–18`
