# RFC 0175: v2 transports and embedded protocols — gRPC demoted or generated, the legacy A2A and MCP profiles gone, negotiation authenticated with a minimum-version policy, the interop threat model written

> Source: https://openwop.dev/rfcs/0175-v2-transports-and-embedded-protocols.html · OpenWOP, the open-source protocol for multi-agent workflow orchestration. CC BY 4.0.

| Field             | Value                                                           |
| ----------------- | --------------------------------------------------------------- |
| **RFC**           | 0175                                                            |
| **Title**         | v2 transports and embedded protocols: `grpc-transport.md` leaves `core/` for `spec/v2/ext/grpc-transport/` with `witness: unwitnessable` and `adoption: none` unless the proto is generated from the C.2 declaration file and the suite gains a client (decided: demoted); `supportedTransports` is deleted — A2A and MCP are compositions with first-class blocks, not transports; the `a2a-0.3-legacy` and `mcp-2025-06-18-legacy` profiles are absent from the v2 tree at the cut with the adopter inventories recorded as measured (one dual-era host each); version negotiation on both embedded protocols is authenticated, carries an advertised minimum-version policy and a refresh SLA (RFC 0147 R10), and emits a content-free `negotiation.decided` event (RFC 0152/0153 G7); MRTR rounds get a normative ceiling (RFC 0153 G9); the `auth-required` projection under durable tasks is decided (RFC 0100 UQ4); `SECURITY/threat-model-interop.md` is written (RFC 0152/0153 G8) |
| **Status**        | `Accepted`                                                        |
| **Author(s)**     | David Tufts (@davidscotttufts)                                  |
| **Created**       | 2026-09-03                                                      |
| **Updated**       | 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 (identity and authorization at the peer boundary). Adversarial review recorded below.) · 2026-09-03 (filed) · 2026-09-18 (`Active → Accepted`). **Evidence tier: tier-1 — steward-verified, single witness.** Witness: `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. NOT corroborated: neither production host advertises the `a2a` or `mcp` facet, so both record `inapplicable` with that reason on the facet-dependent ids and neither can witness this child today. · 2026-09-23 (**evidence correction, Status unchanged**: one acceptance row — `openwop.requirement.0175.negotiation-authenticated.mcp` — was measured vacuously, and §D.1's authentication clause turns out to be unexercised on every committed bundle. The defect is the suite's and the host posture's, not a host defect. See §"Evidence correction (2026-09-23)".) |
| **Affects**       | **Part of: RFC 0167 — child C8.** v2 (Phase 3): `spec/v2/ext/grpc-transport/` (demoted; `api/grpc/openwop.proto` retired from `api/v2/` unless generated), `schemas/v2/capabilities.schema.json` (`supportedTransports` removed; `a2a`/`mcp` facets with `versions[]`/`revisions[]`, `preferredVersion`, `minimumVersion`, `refreshedAt`; `-legacy` profile patterns removed; `mcp.mrtr.maxRounds`), `spec/v2/core/interop.md` (NEW: negotiation, minimum-version policy, refresh SLA, the audit event), `schemas/v2/run-event.schema.json` (`negotiation.decided`), NEW `SECURITY/threat-model-interop.md`; the suite's dual-era A2A peer and MCP server lose their legacy halves; v1.x (this PR): `spec/v1/migrations.json` rows `openwop.migration.C8.1`–`C8.8`; the RFC 0152/0153 registers gain the G7/G8/G9 rows that existed only in the spec docs; codemod `openwop.codemod.discovery-document-v2` extended (legacy ids and `supportedTransports`); deprecation row `supported-transports-field` (`proposed`); `grpc-transport.md:202`'s stale "in flight" sentence corrected (editorial) |
| **Compatibility** | `breaking` (v2). In v1.x this PR changes no wire shape; two registers gain rows their own spec docs already carried, and one stale forward reference is corrected |
| **Supersedes**    | — (RFC 0094 §H, 0100, 0152, 0153 remain the v1 authorities; the legacy-window dates they set stand) |
| **Superseded by** | —                                                               |

## Summary

`grpc-transport.md` is Stable with six MUSTs, a proto that calls itself abridged and defers its own messages to a v1.x that never came, no client in the suite, and zero advertisers — Axiom 1's exact failure. `supportedTransports` lists one baseline, one real transport nobody serves, and two embedded protocols that have richer first-class blocks; nothing reads its `mcp` or `a2a` members. The legacy A2A 0.3 and MCP 2025-06-18 profiles have dated sunsets (2027-03-12, 2027-08-12), one dual-era advertiser each, and removal recorded as "a v2 change." Version negotiation on both protocols is fail-closed only for an already-authenticated request, has no minimum-version policy in normative text, no refresh SLA, no audit event, and no threat model; its only witness is a seam a production host never mounts. v2 demotes gRPC, deletes `supportedTransports`, removes the legacy profiles at the cut, makes negotiation authenticated with an advertised floor, a refresh SLA, a ceiling on MRTR rounds and a content-free audit event, and writes the threat model both Stable documents cite.

## Motivation

- `grpc-transport.md:3` Stable; `api/grpc/openwop.proto:14–20, 68–72` "abridged … deferred to v1.x … a future v1.x minor expands every Struct"; `conformance/src/scenarios/grpc-transport.test.ts:5` "SHAPE-ONLY by design … the suite ships no gRPC client"; `grpc-transport.md:202` still says RFC 0094 is "in flight"; `extensions.json:662` `draft`, `witnessable-gated` on a scenario that dials nothing; no `grpc` in INTEROP-MATRIX.
- `capabilities.schema.json:370` `supportedTransports: ["rest","mcp","a2a","grpc"]`; `profiles.md:86/102` read only `rest`; `a2a-integration.md:3` and `mcp-integration.md:3` describe compositions, not transports; `a2a` carries its own transport list inside its block (G4) and `mcp.serverMount.transports` is its own enum.
- Legacy windows: `a2a-integration.md:333` (2027-03-12; "Removal of the 0.3 code path from the corpus is a v2 change"), `mcp-integration.md:251` (2027-08-12; same); RFC 0152 G1 / 0153 G1 measured: one dual-era advertiser each (openwop-app), no reference host advertises versions; the `-legacy` suffix is baked into both `profiles` item patterns (`capabilities.schema.json:2908, 3400`), so removal is a pattern change; `mcp-integration.md:316` lists the legacy-profile scenarios the cut deletes.
- Negotiation: `a2a-integration.md:341` and `mcp-integration.md:260` — "for an authenticated request the default is fail-closed"; the exchange itself is not required to be authenticated; "minimum-version policy" exists only as a mitigation phrase in RFC 0152/0153 R1; the refresh SLA is RFC 0147 R10, unwritten; the audit event is RFC 0152/0153 G7 (`authorization.decided` as carrier, no dedicated type); `host-sample-test-seams.md:954` — the wire toward a peer is "what no black-box request to the host's own API can observe," so both R1 rows are `blocked` on every host.
- `mcp-integration.md:283` "the host MUST bound the number of rounds (host policy)" — a MUST with no number (G9). RFC 0100 UQ4 — `auth-required` in the persisted `A2ATaskState` enum for the reverse direction, never emitted forward.
- `SECURITY/threat-model-interop.md` does not exist; `a2a-integration.md:509` and `mcp-integration.md:331` (G8) cite it; the G7/G8/G9 rows live only in the spec docs — the RFC registers stop at G7 and G5.

## Proposal

### §A. gRPC

**§A.1** `grpc-transport.md` moves to `spec/v2/ext/grpc-transport/` with header `witness: unwitnessable` (the suite ships no client) and `adoption: none`; its six MUSTs become SHOULDs of the extension; `api/grpc/openwop.proto` is retired from the canonical API set (`api/v2/` carries OpenAPI and AsyncAPI only) and kept under `ext/grpc-transport/openwop.proto` as a non-normative sketch. **If** a Phase 3 contributor generates the proto from the C.2 declaration file and lands a suite client, the extension re-enters `core/` by a v2.x additive RFC — the door is named, not left ajar. The `capabilities.grpc` block is removed from the closed root (an unwitnessable family may not be advertised, RFC 0169 §A.1); `grpc-transport.md:202`'s "in flight" sentence is corrected now (editorial).

### §B. `supportedTransports` is deleted

**§B.1** REST is the wire; there is no transport advertisement. A2A and MCP are **compositions** advertised by their own facets (`a2a.versions[]`, `a2a.preferredVersion`, `a2a.minimumVersion`, `a2a.profiles[]` without `-legacy`; `mcp.revisions[]`, `mcp.preferredVersion`, `mcp.minimumRevision`, `mcp.features[]`, `mcp.serverMount.transports[]`). RFC 0172 §B axes 11–12 are these facets.

### §C. Legacy profiles gone at the cut

**§C.1** `a2a-0.3-legacy` and `mcp-2025-06-18-legacy` do not exist in the v2 tree: the `profiles[]` item patterns lose the `(-legacy)?` alternative; the legacy code paths (`a2a-integration.md` §0.3 mapping, `mcp-integration.md` live-callback bridges) are absent from `spec/v2/`; the suite's dual-era A2A peer and MCP server lose their legacy halves; the four `mcp-server-*` legacy scenarios are deleted. The v1 sunset dates (2027-03-12, 2027-08-12) stand for the v1 tree through Phase 5. **§C.2** The adopter inventories (RFC 0152 G1, 0153 G1) are closed as measured: one dual-era advertiser (openwop-app), no reference host; a third-party inventory is not obtainable and the RFCs say so. **§C.3** The header-less card rule (`a2a-integration.md:349`) becomes unconditional: a v2 host serves the card of `preferredVersion` when no `A2A-Version` header is present.

### §D. Negotiation is a protocol

**§D.1** A version-negotiation exchange on either embedded protocol MUST be **authenticated**: the peer identity is the C.3 Subject of the caller (or the host's own outbound identity), and an unauthenticated negotiation MUST NOT lower the version below `preferredVersion`. **§D.2** A host advertises `minimumVersion` (A2A) / `minimumRevision` (MCP); a negotiation that would land below the floor MUST fail closed (`interop_version_unsupported`, RFC 0152 §B's code, registered in C.4's `errors.json`) whether or not a policy permits explicit downgrade above the floor. **§D.3** Every negotiation outcome — including the fail-closed one — emits **`negotiation.decided`** (new v2 event type: `{ protocol: a2a | mcp, peer: <origin digest>, requested, negotiated | null, outcome: accepted | downgraded | refused, reason }`, content-free), replacing the `authorization.decided` carrier RFC 0152/0153 G7 recommended. **§D.4** Refresh SLA (RFC 0147 R10): a host MUST re-evaluate its advertised `versions[]` / `revisions[]` against the upstream registry within an advertised `refreshedAt` window not exceeding 90 days; an advertisement older than its window is non-conformant. **§D.5** The silent-downgrade invariants (`a2a-version-no-silent-downgrade`, `mcp-version-no-silent-downgrade`) are witnessed by the `negotiation.decided` event on the host's own event log — a normative surface — rather than only by the §22/§23 invoke seams; the seams stay in the C.1 seams profile for the wire-capture leg.

### §E. MRTR and the durable-task projection

**§E.1** `mcp.mrtr.maxRounds` (integer, 1–16, advertised) is the ceiling; the host MUST refuse a further `input_required` round beyond it (`mcp_mrtr_rounds_exceeded`, registered in `errors.json`); RFC 0153 G9 closes. The `requestState` MUSTs (`mcp-integration.md:290–291`) carry over unchanged. **§E.2** RFC 0100 UQ4: `auth-required` stays in the persisted `A2ATaskState` enum for the reverse direction; the forward projection never emits it in v2 either — v2 has no `auth` interrupt kind, and inventing one here would be C.4's business; recorded as decided, not deferred (RFC 0152 G9 closes as "not in v2.0").

### §F. The threat model

**§F.1** `SECURITY/threat-model-interop.md` is written with the sibling template (§1–§8): downgrade, card/runtime drift, cross-tenant lookup through a peer, artifact leakage across the boundary, the anonymous end-user actor (RFC 0165 §B.6), and negotiation replay; its §5 invariants are the two silent-downgrade rows plus `interop-negotiation-authenticated`, `interop-minimum-version-enforced`, `interop-peer-no-authority-escalation` (already registered) — entering `invariants.yaml` with their tests in Phase 3 (RFC 0167 §C rule). RFC 0152 G8 and 0153 G8 close when the file exists.

## Migration table

| Row | Kind | v1 | v2 | Codemod | Persisted data |
| --- | --- | --- | --- | --- | --- |
| `openwop.migration.C8.1` | remove | `a2a-0.3-legacy` / `mcp-2025-06-18-legacy` profiles and the `(-legacy)?` patterns | none | `openwop.codemod.discovery-document-v2` (strips the ids and the legacy version when `preferredVersion` is not legacy; refuses when it is) | not-persisted |
| `openwop.migration.C8.2` | remove | `supportedTransports[]` | none — REST is the wire; A2A/MCP are facets | `openwop.codemod.discovery-document-v2` | not-persisted |
| `openwop.migration.C8.3` | remove | `capabilities.grpc` block; `grpc-transport.md` in core | `spec/v2/ext/grpc-transport/` (`unwitnessable`, `adoption: none`); block not advertisable | `openwop.codemod.discovery-document-v2` (drops the block) | not-persisted |
| `openwop.migration.C8.4` | add | none | `a2a.minimumVersion`, `mcp.minimumRevision`, `refreshedAt` | — | not-persisted |
| `openwop.migration.C8.5` | add | `authorization.decided` as the recommended carrier | `negotiation.decided` event type | — (a new event; v1 logs carry none) | not-persisted |
| `openwop.migration.C8.6` | behavior | negotiation fail-closed only for authenticated requests; no floor; no SLA | authenticated exchange, floor, 90-day refresh SLA | — | not-persisted |
| `openwop.migration.C8.7` | add | "the host MUST bound the number of rounds (host policy)" | `mcp.mrtr.maxRounds` + `mcp_mrtr_rounds_exceeded` | — | not-persisted |
| `openwop.migration.C8.8` | behavior | `auth-required` never emitted forward; UQ4 open | decided: stays reverse-only; no v2 `auth` interrupt kind | — | unchanged (persisted `A2ATaskState` rows keep the enum member) |

## Persisted-data disposition

| Store | v1 artifact | Disposition |
| --- | --- | --- |
| Persisted A2A task state (openwop-app) | `A2ATaskState.state` incl. `auth-required` | unchanged |
| Event logs | no negotiation events under v1 | not-persisted (new type from the cut) |
| Discovery documents | legacy profile ids, `supportedTransports`, `grpc` block | not-persisted; the codemod rewrites a captured document |
| Suite fixtures (dual-era peer/server) | legacy halves | removed with suite 2.0.0 (C.1) |

## Compatibility

`breaking` (v2). This PR changes no v1.x wire shape. The RFC 0152/0153 register additions copy rows that already exist in the spec documents' own gap tables (register drift, RFC 0174 §C); the `grpc-transport.md:202` correction is editorial (RFC 0094 is Accepted).

## Conformance

v2 scenarios (suite 2.0.0): `no-transport-advertisement` (unaided: `supportedTransports` and `grpc` absent), `legacy-profiles-absent` (unaided: no `-legacy` id validates), `negotiation-decided-emitted` (gated on `a2a`/`mcp`: the host's own event log carries `negotiation.decided` for a peer exchange driven through the seams profile), `minimum-version-refused` (gated: a peer offering below the floor is refused with `interop_version_unsupported` and the event says `refused`), `negotiation-authenticated` (gated: an unauthenticated exchange cannot lower the version), `refresh-sla` (unaided: `refreshedAt` within the window), `mrtr-rounds-ceiling` (gated on `mcp`: round `maxRounds + 1` refused), `threat-model-template` (corpus, shared with C.6).

### Falsifiability — one row per normative requirement

| Requirement | Observable | Who can cause the condition | Verdict |
| --- | --- | --- | --- |
| §A.1 no `grpc` block; ext header declares class | discovery + corpus — `openwop.requirement.0175.no-transport-advertisement` | the suite, unaided; the corpus gate | witnessable — unaided |
| §B.1 no `supportedTransports` | discovery — `openwop.requirement.0175.no-transport-advertisement` | the suite, unaided | witnessable — unaided |
| §C.1 no `-legacy` id | discovery schema — `openwop.requirement.0175.legacy-profiles-absent` | the suite, unaided | witnessable — unaided |
| §D.1 unauthenticated exchange cannot downgrade | event log + peer capture — `openwop.requirement.0175.negotiation-authenticated` | the suite via the C.1 seams profile | seam-gated |
| §D.2 floor refused | `interop_version_unsupported` + event — `openwop.requirement.0175.minimum-version-refused` | the suite via the seams profile | seam-gated |
| §D.3 `negotiation.decided` on every outcome | the host's event log — `openwop.requirement.0175.negotiation-decided-emitted` | the suite, gated on `a2a`/`mcp` (the exchange is driven through the seam, the event is read on the normative surface) | witnessable — gated |
| §D.4 refresh SLA | `refreshedAt` — `openwop.requirement.0175.refresh-sla` | the suite, unaided | witnessable — unaided |
| §E.1 MRTR ceiling | refusal at `maxRounds + 1` — `openwop.requirement.0175.mrtr-rounds-ceiling` | the suite's fake MCP server, gated | witnessable — gated |
| §F.1 threat model present with the template | corpus gate | the corpus gate | witnessable — unaided (corpus) |

## Adversarial review

1. **Demoting gRPC to `unwitnessable` while a `grpc` block exists in the schema contradicts RFC 0169 §A.1.** Disposition: the block is removed from the v2 root (row C8.3); a demoted extension is documented, not advertised.
2. **Deleting `supportedTransports` removes the one field that let a client learn REST is served.** Disposition: REST is the wire by definition (`grpc-transport.md:3` already says "REST + SSE remains the REQUIRED wire surface"); a field that can only say `rest` says nothing.
3. **Removing the `-legacy` pattern before 2027-03-12 / 2027-08-12 breaks the v1 promise.** Disposition: it does not — the v1 tree keeps the profiles and the dates through Phase 5; only `spec/v2/` lacks them, and a v2 host that still speaks A2A 0.3 does so as a non-advertised private behavior, which is what "removed from the corpus" means.
4. **Authenticated negotiation is unwitnessable without the invoke seams.** Disposition: the *exchange* is driven through the C.1 seams profile, but the *record* (`negotiation.decided`) lands on the host's own event log, a normative surface; §D.3's leg is `witnessable — gated`, §D.1/§D.2's peer-capture legs stay honestly `seam-gated`.
5. **A 90-day refresh SLA is arbitrary.** Disposition: it is the shortest window both upstreams' own lifecycle policies exceed (A2A/MCP twelve-month deprecation minimums); recorded as G1 for re-measurement at the first refresh.
6. **RFC 0100 UQ4 is "decided" by not deciding.** Disposition: the decision is that v2.0 has no `auth` interrupt kind; a future additive RFC may add one; the enum member stays for reverse-direction fidelity; RFC 0152 G9 closes as "not in v2.0", which is a decision with a date.
7. **The RFC 0152/0153 registers lack the G7–G9 rows the charter cites.** Disposition: copied into the registers in this PR with the spec-doc rows as their sources (RFC 0174 §C register-drift rule); the spec docs' tables are retired into `gaps.json` in Phase 3 (RFC 0174 §E.3).

## Alternatives considered

1. Generate the proto now and keep gRPC in core. Rejected: no client, no advertiser, and the declaration file (C.2) does not exist until Phase 3; the door is named in §A.1.
2. Keep `supportedTransports` as `["rest"]`. Rejected: Axiom 2 — a field with one legal value is an alias for its own absence.
3. Keep the legacy profiles through the v1 dates in `spec/v2/`. Rejected: the dates are v1's; v2 starts without the code paths, as both RFCs already say.
4. Do nothing. Rejected: two Stable documents cite a threat model that does not exist.

## Unresolved questions

1. Whether `negotiation.decided` should carry the peer origin in clear or as a digest. Recommended: digest (content-free audit, RFC 0128 purpose label rides separately).

## Implementation notes (non-normative)

openwop-app advertises both eras of both protocols today and drops the legacy halves in Phase 4; MyndHyve advertises neither A2A nor MCP versions and has no obligation under §D. The suite's fake peer and server (`a2a-fake-peer.ts`, `mcp-fake-server.ts`) are the `negotiation-decided-emitted` drivers.

## Acceptance criteria

- [x] `Draft → Active`: RFC text; rows `C8.1`–`C8.8`; the discovery codemod extended with fixtures; RFC 0152/0153 register rows G7–G9 added; `grpc-transport.md:202` corrected; deprecation row `supported-transports-field`; ledger row; adversarial review. (This PR.)
- [x] `Active → Accepted` (Phase 3): `spec/v2/ext/grpc-transport/`; the facets and patterns in `schemas/v2/capabilities.schema.json`; `spec/v2/core/interop.md`; `negotiation.decided` in the v2 event registry; `SECURITY/threat-model-interop.md`; the eight scenarios in suite 2.0.0. — evidence: the corpus half is present and green. **`reason:` the openwop-app clause is dropped from the tick and recorded here instead, because three of its four ids cannot be witnessed on that host by construction.** openwop-app advertises neither the `a2a` nor the `mcp` facet, so: `refresh-sla` records `inapplicable` — "host advertises neither a2a nor mcp — no refreshedAt to check"; `legacy-profiles-absent` records `inapplicable` for the same reason on the leg that needs a facet; and `negotiation-decided-emitted` has **no row at all**. Only `no-transport-advertisement` is `executed-pass` there (and on all three bundles). MyndHyve records the identical `inapplicable` reasons — it advertises neither facet either. All eight §D/§E ids are `executed-pass` tier-1 on the reference host, which advertises both. The remedy is a host advertising `a2a`/`mcp` in production, not a change to this RFC.

## Evidence correction (2026-09-23) — one acceptance row measured the harness, and §D.1's clause is unexercised

**Status is unchanged and nothing here is flipped.** This section records what one of the eight `executed-pass` rows cited in the acceptance tick above actually measured, because the row measured the test harness rather than the host, and finding that exposed a second, larger fact about §D.1.

**1. The vacuous row.** `openwop.requirement.0175.negotiation-authenticated.mcp` is `executed-pass` in the committed reference-host bundle (suite 2.35.0, build `commit:8477d75f`, `witnessSha256 5562d7c57609…`) and measured nothing about the host's negotiation decision. `v2-negotiation-authenticated.test.ts` establishes its condition by constructing a single-era `McpFakeServer(['2025-06-18'])` on an ephemeral port and handing the host `hostFacingEndpoint()`. Since suite 2.33.0 that method returns `OPENWOP_MCP_FAKE_SERVER_URL` — the operator's public front, which forwards to the **pinned** port the shared, setup-level fake server owns, and that server is dual-era and speaks the preferred revision. `host-sample-test-seams.md` §23 defines no request field that makes a server offer *only* a lower revision (`requestVersion` overrides what the host **asks for**, which is §D.2's floor case, and the leg does not pass it), so no lower offer ever reached the host: it discovered `2026-07-28`, negotiated at it, and the leg asserted `negotiatedVersion === preferredVersion` — a property of the harness. The row's own assertion count records the moment it went hollow: **4** in every pre-front cut of this host (2.4.0, 2.4.1, the 2.4.2 acceptance witness, 2.4.5, 2.24.0, 2.25.0) and **3** in every cut since the fronts landed in suite 2.33.0 (2.33.1, 2.34.0, 2.35.0). The missing assertion is the wire leg, which iterates the scenario-owned server's `invocations()` — empty, because the host never reached that instance. Its three siblings (`minimum-version-refused`, `minimum-version-refused.mcp`, `negotiation-authenticated`) drove the host's decision genuinely through `peerOffersOnly` / `requestVersion`, and each of them refused as the RFC requires — but their wire half contributes zero assertions in the committed bundle too, for two different reasons. The MCP sibling lost its one wire assertion (8 → 7) when the front took the host away from the scenario's own server; the two A2A legs never had one, because the host refuses before it makes any non-GET call and the leg inspects only non-GET calls (the Agent Card `GET` is filtered out). A wire half that can only ever iterate an empty array is not a check.

**2. What that hid: §D.1's clause has never run.** The host refuses an exchange as `unauthenticated` only when the negotiated version would land **below `preferredVersion` and at or above the floor**. The only host that has ever witnessed these ids advertises `a2a.preferredVersion === a2a.minimumVersion === 1.0` and `mcp.preferredVersion === mcp.minimumRevision === 2026-07-28`, so no such version exists on it and every lower offer refuses `below-floor` instead. Every reference-host cut in the file's history was checked (17): the nine that advertise the facets all carry that posture, the eight before them advertise neither facet and record 0 assertions on these ids, and the two production bundles record them `inapplicable` or omit them. **No committed bundle has ever exercised §D.1's authentication clause**, fronted or loopback. What the three genuine rows measured is §D.2's floor rule, twice.

**3. The defect is the suite's, not the host's, and what now measures it.** No host emitted anything it should not have; the reference host's `decide()` implements §D.1 as written, and the corpus cannot convict or acquit it on this evidence. The harness fix has since landed (openwop#1520, suite 2.37.0): `conformance/src/lib/front-mux.ts` nonce-paths each scenario-owned fake behind the one operator front, so the host now reaches **this** server — the one that offers only `2025-06-18`, which is where the lower offer comes from, §23 still having no knob for it — and both legs now record `blocked` instead of a pass when the seam answers a success and the suite's own peer received no request. This PR touches no scenario; it records what the bundle already in the tree measured, which no code change can retract.

**4. What the remaining evidence supports, stated plainly.** §A, §B, §C, §D.2, §D.3, §D.4, §E.1 and §F.1 keep genuine tier-1 rows, so the acceptance is not withdrawn. **§D.1 is, as of this entry, unwitnessed** — not failed, not refuted, unwitnessed — and neither row may be cited as evidence that any host enforces it. Witnessing it needs a host whose advertised floor sits **below** its preferred version (or a suite lever producing that posture), which no host in `INTEROP-MATRIX.md` has today; recorded as `openwop.gap.0175.6`. The re-cut of the reference bundle owed after the harness fix is `openwop.gap.0175.5`, and the matrix row discloses that the recorded pass predates the fix.

**Verified for this entry** by reading the three committed bundles and all 17 reference-host cuts in the file's history, the scenario source, §22/§23's seam contract, `resolvePublicFront` + `conformance/src/setup.ts`, the cut script that sets the fronts, and the host's `decide()` at the exact build the bundle names. **Not re-measured:** the fronted path cannot be reproduced without opening public ingress, so which branch the 2.35.0 run took is read from the routing and the assertion arithmetic, not from a fresh run.

## References

- RFC 0167 §A (Axioms 1–2), §C, §E.1 axes 11–12, §E.3; RFC 0094 §H; RFC 0100 UQ4; RFC 0152 §B, G1, G3, G7–G9, R1; RFC 0153 §A/§C, G1, G3, G7–G9, R1; RFC 0147 G11, G12, R10; RFC 0169 §A.1; RFC 0171 §A/§B; RFC 0172 §B; RFC 0165 §B.6.
- `spec/v1/grpc-transport.md`, `api/grpc/openwop.proto`; `spec/v1/a2a-integration.md` §Discovery, §B, §Open spec gaps; `spec/v1/mcp-integration.md` §B, §C.1, §Open spec gaps; `spec/v1/host-sample-test-seams.md` §22–§23; `spec/v1/capabilities.md:162`; `schemas/capabilities.schema.json` (`supportedTransports`, `a2a`, `mcp`, `grpc`); `conformance/src/scenarios/grpc-transport.test.ts`; `SECURITY/threat-model-*.md` (the template).
