@openwop/openwop-conformance 1.128.0 → 1.130.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -92,7 +92,7 @@ Exit code is non-zero on any failed assertion. `--certify` distinguishes: `0`
92
92
 
93
93
  ## What's Covered
94
94
 
95
- The current suite has 459 scenario files under `src/scenarios/`. 2026-08-16 (suite `1.127.0 → 1.128.0`): NEW `workload-identity-chain-bounds.test.ts` — RFC 0154 §B chain bounds through the §20 seam (too-long / cyclic / scope-amplified refusals + a narrowing chain resolves), gated on `auth.workloadIdentity.delegation.supported`. 2026-08-16 (suite `1.123.0 → 1.124.0`, S22): NEW `error-envelope-canonical-shape.test.ts` (server-free) pins the decision that the HTTP error envelope is **flat** — `{ error: <code>, message, details? }`, `details.retriable` — against the schema, the new `lib/error-envelope.ts` helper (`readErrorCode` / `readRetriable`, tolerating the legacy nested `{ error: { code } }` seam shape through the first minor after 2026-11-10) and the prose; 15 HTTP-envelope legs read through the helper. 2026-08-16 (suite `1.122.0 → 1.123.0`) added two, both server-free and always-on: `conformance-execution-witness.test.ts` (an early return can never become a pass — the runner's `resolveFileRecord`, the emitter derivation and the consumer verifier each pinned with sabotage vectors) and `conformance-advertised-seam-required.test.ts` (under `OPENWOP_REQUIRE_BEHAVIOR=true` an advertised profile with a missing seam FAILS — `behaviorGate`, `behaviorGatePresent`, `seamAbsent` — and the only escape is an explicit opt-out that records `skipped`); `mcp-stateless-request.test.ts` gained the Mcp-Method/Mcp-Name half of `mcp-header-body-consistent`. Every scenario RFC 0148 §Conformance names now exists. 2026-08-16 (suite `1.119.0 → 1.120.0`, no new files): RFC 0148 §C gap G7 closed — `PROFILE_FLOOR_SCENARIOS` gained a discovery-conditional model (`conditional: [{ path, includes, required }]`, evaluated against the captured discovery document) for `openwop-replay-fork`, and `openwop-interrupts` / `openwop-secrets` / `openwop-provider-policy` / `openwop-memory` / `openwop-trigger-bridge` received floors transcribed into `profiles.md`; every catalog profile now has a floor and *unprovable* is reserved for names outside the catalog. Against the tier-1 reference host: interrupts, secrets and provider-policy now **certify** on witnessed floors; replay-fork does not (its `replay` branch carries the unconditional no-re-fire obligation, `blocked` while the host advertises `sideEffectSuppression: none`); trigger-bridge does not (delivery seam unwired). 2026-08-16 (suite `1.118.0 → 1.119.0`, no new files): 84 scenarios that returned early in silence now say why — 256 early-return sites converted to `softSkip(kind, reason)` (`inapplicable` for a capability/profile/fixture the host does not advertise, `blocked` for a seam, prior step, or precondition that was unavailable); against the tier-1 reference host the RFC 0148 §A marker rows fell from 84 to 8 (all `describe.skipIf`/`it.skip` files) and `inapplicable` rose from 47 to 97. 2026-08-16 (suite `1.117.0 → 1.118.0`, no new files): the runner resolves a silent zero-assertion file to `blocked` (RFC 0148 §A) instead of a vacuous pass; NEW `lib/soft-skip.ts` (`softSkip`, `seamAbsent`) lets a scenario say why it returned early, and ten scenarios were converted as exemplars. 2026-08-16 (suite `1.116.0 → 1.117.0`, no new files): `openwop-node-packs` became runtime-derived in `--certify` (claimed only when held) and its two floor scenarios record `inapplicable`/`blocked` with reasons instead of returning early into a vacuous pass. 2026-08-16 (S7 — RFC 0149 §D, suite `1.115.0 → 1.116.0`) added one, server-free: `normative-example-extraction.test.ts` (a `<!-- normative-example: <name>.schema.json -->` marker above a fenced example declares it a whole instance; every declared example is extracted at test time and validated against `schemas/<name>`, and every undeclared whole-instance example fails — 26 declared across `spec/v1`). 2026-08-16 (S12 — RFC 0148 §Conformance + RFC 0149 §A coverage residue, suite `1.114.0 → 1.115.0`) added three, all server-free and always-on: `certification-bundle-non-vacuous.test.ts` (the consumer re-derivation of a v2 bundle — `verifyBundleV2`: missing witness, vacuous pass, duplicate requirement, tampered totals, invented disposition, missing reason all REJECT the evidence; an honest `blocked`/`executed-fail` on a required row is valid evidence that does not certify), `certification-bundle-redaction.test.ts` (secret canaries never enter evidence — the emitter scrubs the finished document with the handed credential + `OPENWOP_*` secrets + the conformance canary, and the verifier rejects the canary anywhere), and `openapi-asyncapi-sdk-parity.test.ts` (the generated `spec/v1/operation-path-manifest.json` re-derives from `api/openapi.yaml`; AsyncAPI addresses resolve to OpenAPI GET paths with exactly one `/v1`; the SDK half witnesses `openwop-sdks` when reachable and records `blocked` with a reason when not). 2026-08-16 (RFC 0148 acceptance item 2 — S6, suite `1.113.0 → 1.114.0`) added one: `runner-ledger.test.ts` (server-free — the §A ledger file sink, the reader's conflict rank, file-level disposition derivation, and `--certify`'s rejection of silent and vacuous returns). Every scenario file now records its own disposition (with `assertionCount`) into the ledger from `setup.ts`, and `--certify` exits 3 when a claimed profile has an unclassified return. The first end-to-end run found that the `openwop-core-standard` floor had named `audit-log-verification.test.ts` — a file that never existed — since RFC 0088; the scenario it meant (`audit-log-integrity.test.ts`) gates on the optional annex profile `openwop-audit-log-integrity`, so by the floor's own no-soft-skip rule the row was never a floor scenario and is removed (`core-standard-profile.md` §C). 2026-08-16 (RFC 0153 §B/§C/§D/§E — S16, suite `1.112.0 → 1.113.0`) added six: `mcp-2026-07-28-discover.test.ts` (peer pin of the now dual-era `McpFakeServer` — stateless `_meta`, header/body agreement `-32020`, `-32022` + `data.supported[]`, `server/discover`, `resultType`, `CacheableResult`, MRTR `input_required` → retry with echoed `requestState`, `-32021` without the `elicitation` capability — plus the host `server/discover` ⇔ `protocolVersions` leg), `mcp-stateless-request`, `mcp-mrtr-roundtrip` (client half cross-checked against the wire; server half against an exposed suspending tool), `mcp-cache-tenant-scope`, `mcp-extension-opacity`, `mcp-current-auth-boundary` — all gated on `mcp.profiles ∋ mcp-2026-07-28` / the §B advert + additive seam blocks (`mrtr`, `extensionAuthority`), `blocked` on today's 2025-06-18 hosts. Header-less requests to the fake server still get 2025-06-18 semantics, so `mcp-tool-roundtrip` and the legacy `mcp-server-*` legs are unchanged. 2026-08-16 (RFC 0152 §C/§D/§E — S15, suite `1.111.0 → 1.112.0`) added four: `a2a-1-0-agent-card.test.ts` (server-free — the suite's own `A2AFakePeer`, now dual-era, pinned at 1.0 from the wire: `supportedInterfaces[]` card, `SendMessage`/`GetTask`/`CancelTask`/`ListTasks`, `TASK_STATE_*`, `Part` oneof, `-32009` on an unsupported `A2A-Version`, header-less = 0.3), `a2a-card-runtime-consistency.test.ts` (black-box, gated on `a2a.profiles ∋ a2a-1.0`), `a2a-1-0-task-roundtrip.test.ts` (host as 1.0 server, same gate), `a2a-peer-authority.test.ts` (host as client; additive seam `scenario`, `blocked` until the host reports). Also (S14) `fixtures-valid.test.ts` and `workflow-primary-output-annotation.test.ts` now register schemas by enumerating the directory instead of a fixed list — the fourth cross-file `$ref` (#1009) had broken the list at describe time, here and in every downstream runner resolving the sibling corpus with a pinned suite. **Correction recorded the same day:** openwop-app's live origin passes the RFC 0152/0153 §A legs and has NOT wired the `invoke` seams, so its §B legs are `blocked` (RFC 0148 §A) — an earlier note here said they pass. 2026-08-16 (RFC 0157 — chain fragments carry compensation, suite `1.110.0 → 1.111.0`) added one: `chain-compensation-expansion.test.ts` — the `FragmentNode.compensation` / `WorkflowChain.compensation` mirrors are byte-equal to their sources, the manifest stays self-contained (no cross-file `$ref` — the S14 lesson), and `carryCompensation` (composed after the byte-mirrored expansion core, not inside it) carries the declaration verbatim with params substituted and node-id refs rewritten, refuses an unresolvable compensator before any node is emitted, and copies / accepts / conflicts the chain policy into `settings.compensation`. 2026-08-16 (RFC 0155 §A — `openwop-discovery-core` canonical / `openwop-core` deprecated alias, suite `1.109.0 → 1.110.0`) added one: `profile-discovery-core-alias.test.ts` — the alias MUST derive exactly when the canonical name derives, checked over payloads on both sides of the predicate (an equivalence over payloads that all derive proves nothing about the other side), the doc's rename and claim vocabulary (an unqualified claim means `openwop-core-standard`), and a gated live-host leg; `PROFILE_NAMES` gained the canonical name and `deriveProfiles` emits both or neither. Same release: `spec/v1/extensions.json` gained a DERIVED `coverage` block — 5 covered / 81 uncovered / 4 core of 90 capability families — gated by `generate-extension-registry-coverage.mjs --check` in `openwop:check`, so "unlisted means uncovered" is a checked list rather than a sentence. 2026-08-13 (host-callback declaration — every scenario needing the HOST to reach the harness declares it, so an off-process consumer can enumerate the unwitnessable set before running). 2026-08-13 (RFC 0153 §A/§B — MCP revision negotiation witness, suite `1.96.0 → 1.97.0`) added one: `mcp-version-negotiation.test.ts` (four capability-gated legs) plus header capture on `McpFakeServer`. **Both fake peers had the identical gap** — recording the call body but not its headers — which is worth naming as a shared assumption rather than two oversights: *the interesting part of a call is its body*. Version negotiation is precisely the case where that is wrong. MCP revisions are **dates**, so the wire header is checked for date form and not merely for presence: a host sending `latest` or `2026-7-28` has sent something **unmatchable against a pinned peer**, and the failure then surfaces at the peer rather than at the handshake meant to prevent it. A further leg requires the negotiated revision to appear in `protocolVersions`, because **a host that negotiates a revision it never advertised has made its own discovery document unreliable** — worse than advertising nothing, since a consumer that read it decided on a fact that was not true. **`Pinned real MCP current peer passes in CI` stays separate and unmet.** 2026-08-13 (RFC 0152 §B — A2A version negotiation witness, suite `1.95.1 → 1.96.0`) added one: `a2a-version-negotiation.test.ts` (four capability-gated legs) plus header capture on `A2AFakePeer`. **RFC 0152 was twice described here as needing a live upstream peer, and that was half true**: interop needs a real peer, **negotiation does not** — negotiation is the *host's* behavior and the host is right here. What was actually missing is that `A2AFakePeer` recorded method, path, rpcMethod, and body but **not headers**, and §B lives entirely in the headers: the peer could see that a call happened but not which version was negotiated, which is the only part §B is about. The fix was to record what the fake peer already received. The load-bearing leg is negative — *"a host MUST NOT silently downgrade an authenticated request"* — and **a silent downgrade is dangerous precisely because it SUCCEEDS**: the caller believes it negotiated 1.0, the peer answered 0.3, and nothing in the response says otherwise. A failure would at least be visible. So a host that proceeds after a downgrade MUST report the version it actually negotiated, and the wire header MUST match. **`Real upstream A2A 1.0 peer passes in CI` remains separate and unmet** — that item tests interoperation, which no fake can stand in for, and the RFC's acceptance criteria still say so. 2026-08-13 (RFC 0154 §A/§B — the workload-identity BEHAVIORAL witness, suite `1.94.0 → 1.95.0`) added one: `workload-identity-behavior.test.ts` (six capability-gated legs) plus `host-sample-test-seams.md` §20. **§A's requirements are invisible from the wire**: verify, bind to request, resolve to a principal *before* authorization, fail closed — and a normal request either succeeds or 401s, **both of which look identical whether the host verified anything or simply trusted a header**. That invisibility is why the seam exists, and why a missing seam is reported as **`blocked` rather than skipped**: RFC 0148 §A resolves an unobservable requirement to blocked, so without it RFC 0154 **cannot be certified at all**. **The negatives carry the weight** — a host that echoes its input satisfies every positive assertion, so only the rejections distinguish a verifier from a passthrough: `audience_mismatch` (an identity minted for another host, accepted here, is how a credential valid elsewhere becomes valid here — RFC 0147 **R12**), `delegation_expired` (a delegation without a live expiry is a standing grant, which is not what delegation means), and `sender_constraint_missing` (without proof-of-possession a bearer credential is replayable by anyone who observed it). Failures MUST be **non-retriable** — an identity that does not resolve will not resolve on retry, and marking it retriable invites hammering a failing authorization path. The seam **MUST NOT be a mock**: it drives the host's real resolver, or the witness proves nothing about production. 2026-08-13 (RFC 0151 §C–§G — the compensation BEHAVIORAL witness, suite `1.93.0 → 1.94.0`) added one: `compensation-behavior.test.ts` (five capability-gated legs). **This closes a gap in the SUITE, not in any host.** RFC 0147 §A.5 requires a host to execute every normative behavioral path in strict mode — and RFC 0151 had **no behavioral scenario at all**, only a server-free schema check. **A willing host had nothing to run.** For several turns the blocker was described as "no host implements this" when part of it was that the evidence-collecting apparatus did not exist either. Each leg is gated on `compensation.supported` via `behaviorGate`, so it soft-skips against a non-advertising host and **hard-fails under `OPENWOP_REQUIRE_BEHAVIOR=true`**, recording an RFC 0148 §A ledger disposition either way. The legs pin the §C rules that are otherwise unverifiable: **plan persisted before the first inverse action** (`requested` strictly precedes `started` — a host that unwinds before persisting cannot resume, and the crash is exactly when that matters); **descending forward-completion order** (compensating forward can release a resource a later inverse action still needs); **replay does not re-fire** (§F — a replay that re-executes inverse effects turns a recovery into a second outage); and **no provider bodies or credentials in events** (§D/§G — these land in the durable log, the least revocable place a credential can reach). A missing sample seam fails with a message saying the requirement is unobservable and therefore `blocked`, not passed. 2026-08-13 (RFC 0148 §C — certification bundle v2, suite `1.91.0 → 1.92.0`) added one: `certification-bundle-v2.test.ts` (eight legs, server-free) plus `schemas/certification-bundle-v2.schema.json`. v1 recorded `{passed, failed, skipped}` as scenario-FILE lists, and those three words cannot express the distinction this program turns on: a file counted as `passed` **whether its assertions ran or its runner returned early**, and `skipped` flattened three different claims — "the operator excluded this", "the requirement does not apply", and "we could not check" — into one word, when only the first two are certifiable. v2 carries per-requirement dispositions from §A plus the counts §A.4 requires. Two properties are load-bearing: **`blocked` is a REQUIRED total**, because `blocked: 0` asserted is a different claim from `blocked` unstated and an omitted total reads as zero; and **`assertionCount` makes a vacuous pass visible** — the schema deliberately still ADMITS `executed-pass` with `assertionCount: 0`, because forbidding it would only move the lie one field over, while putting the number in the artifact lets a reader see a pass that executed nothing **without re-running the suite**. Sabotage-verified: dropping `blocked` from `required` and removing `minItems` on the requirement list red two legs. 2026-08-13 (RFC 0154 §A/§B — workload identity and delegation, SHAPE ONLY, suite `1.90.0 → 1.91.0`) added one: `workload-identity-profile.test.ts` (eleven legs, server-free) plus `schemas/workload-identity.schema.json` and an `auth.workloadIdentity` capability. §A's real requirements are **behavioral** — cryptographically verify the presented identity, bind it to the request, resolve it to a principal before authorization, fail closed when unresolvable — and **a schema demonstrates none of them**. What a schema *can* do is make the dangerous shape unrepresentable, which is what this checks: **raw certificates, tokens, proofs, and credentials MUST NOT enter these objects.** `subject` is opaque; `proofRef` and `thumbprintRef` are pattern-constrained digest *references*, so a JWT or a raw key cannot be pasted in and still validate. That matters because these objects are projected into events, spans, and audit records — **the three places credential material must never reach**. `audience` is required on a delegation because an identity minted for somewhere else, accepted here, is the confused-deputy path (RFC 0147 R12), and **identity is not authorization** is the one rule a schema cannot enforce at all. Sabotage-verified: opening `additionalProperties` and dropping the digest pattern red two legs. 2026-08-12 (RFC 0152 + RFC 0153 §A — versioned composition discovery, SHAPE ONLY, suite `1.89.0 → 1.90.0`) added one: `versioned-composition-profiles.test.ts` (eleven legs, server-free) plus `protocolVersions` / `preferredVersion` / `profiles` on `a2a` and `mcp`, and a closed `features` list on `mcp`. **Both RFCs address the same defect**, which is why they land together: **`supported: true` with no version is a claim a peer cannot negotiate against.** Two hosts can both advertise it, share no revision, and discover that only when a call fails — at the peer, not at the handshake meant to prevent it. **MCP versions are date-patterned rather than free strings** because MCP revisions *are* dates: accepting `latest` or `2026-7-28` would let two hosts disagree about which revision they share while both validate. **The MCP feature list is closed** because an unrecognized name is indistinguishable from a typo. **Shape only, and the file says so** — nothing contacts a peer, and a final leg asserts both RFCs keep their upstream-peer acceptance items unticked, since interop is the one thing a schema cannot demonstrate. **A first draft had the negatives passing for the wrong reason**: the `a2a` family independently requires `agentCardUrl`, so fixtures omitting it failed on the missing card URL rather than the version defect under test — the vacuity pattern, inside a test written to prevent it. 2026-08-12 (RFC 0151 §A/§B — compensation profile SHAPE ONLY, suite `1.88.0 → 1.89.0`) added one: `compensation-profile.test.ts` (nine legs, server-free) plus the `compensation` capability family and the node-level `compensation` declaration. **What it proves is stated in the file itself**: the schemas admit the shapes §A/§B describe and reject the ones they forbid. That is **shape-only evidence** — not evidence that any host orders an unwind, persists a plan before the first inverse action, or resumes after a crash. **RFC 0147 §A.5 forbids `Accepted` on shape-only evidence for a behavioral requirement**, and a final leg asserts 0151's behavioral acceptance item stays unticked and annotated, so reading the suite alone cannot leave a different impression. Design constraints the schema encodes: **compensation is a second effect, not an undo** — it can fail, be partially applied, and be harmful (R9), hence `requiresApproval` and security-high; **inputs come from recorded facts**, since an inverse built from a re-inferred value is not the inverse of what was done; and **`nodeTypeId` resolves at registration**, so an unwind cannot fail on a typo first discovered during a failure. Sabotage-verified: opening `additionalProperties` on the declaration reds the closed-shape leg. 2026-08-12 (RFC 0147 §A.10 — program self-audit, suite `1.87.0 → 1.88.0`) added one: `rfc-0147-self-audit.test.ts` (four legs, server-free) plus `docs/RFC-0147-SELF-AUDIT.md`. §A states ten invariants that "apply to every workstream", and §A.10 forbids citing the RFC's partial implementation as evidence its gaps are closed — so **a program that audits everything except itself has the same defect it was written to fix, one level up**. The audit found **two violations**: §A.5 (0151–0154 reached `Accepted` with *no* evidence, not merely shape-only) and **§A.6** (0148/0150/0152/0153/0154 had comment windows waived under `MAINTAINERS.md` bootstrap language — *the exact mechanism §A.6 says must not shorten a high-risk window*). The available technicality — 0147 was `Draft` at the instant of the flip — is **recorded and not relied upon**, because reading the program's partial state in whichever direction is convenient is the shape §A.10 forbids. **The gate does not assert compliance**; it asserts every invariant carries an explicit disposition, including the adverse ones. Making it fail on a violation would create pressure to delete the row rather than fix the program. Sabotage-verified both ways: replacing `VIOLATED` with `satisfied` reds, and deleting the §A.6 row reds. 2026-08-12 (RFC 0155 §B/§C — core-standard manifest + extension registry, suite `1.86.0 → 1.87.0`) added one: `core-manifest-and-extension-registry.test.ts` (eight legs, server-free), plus `spec/v1/core-standard-manifest.json`, `spec/v1/extensions.json`, and a generator wired into `openwop:check`. **§B's value is the sentence after the inventory** — *"prose and code profile definitions MUST be generated from or checked against this manifest"*. Three places described the core-standard floor independently and could only be *assumed* to agree; they did not, and `PROFILE_FLOOR_SCENARIOS` being an incomplete transcription is what let five profiles verify as floor-proven against nothing (RFC 0148 §C). The manifest is **derived, never hand-listed**, because a hand-listed manifest drifts the moment the corpus moves and then asserts the drift with a digest attached. §C's registry carries six records backfilled from each RFC's own status. **Every one is `draft`, and none can currently be `stable`**: §C gates stable on a Tier-3 implementation and none exists, so that ceiling is recorded rather than worked around — a fact about adoption, not about the work. Sabotage-verified on both halves: dropping a floor scenario from the manifest reds the parity leg, and marking any extension `stable` without an `evidenceTier` reds the overclaim leg. 2026-08-12 (RFC 0150 §C — golden vectors, suite `1.85.0 → 1.86.0`) added one: `semantic-digest-vectors.test.ts` (sixteen legs, server-free) plus `conformance/vectors/semantic-request-digest-v2.json`. §C's acceptance criterion is that TypeScript, Python, and Go compute the same digest, and **prose cannot deliver that** — three independent readings of "canonicalize via JCS and hash" is exactly how three implementations diverge, invisibly, until two hosts replay the same run and get different cache keys. The vectors are the contract; an SDK reproduces the file. **Several are pairs whose relationship IS the requirement**: tools sorted vs reversed MUST agree, message order reversed MUST NOT, and the two Unicode forms of `é` MUST NOT — because JCS does not apply NFC. That last pair catches a well-meaning "add NFC to be safe" change **that every other vector passes**. **The first draft of this gate had the bug it was written to catch:** the relationship legs compared two stored digests from the same file — two constants — so they validated the vector set and would have passed unchanged against a broken implementation. They now recompute from `input`. Sabotage before the fix reddened one leg; after, two. 2026-08-12 (RFC 0150 §C — semantic request digest v2, **safety-fix**, suite `1.84.0 → 1.85.0`) added one: `semantic-digest-v2.test.ts` (six legs, server-free). Three defects in `replay.md`. **(1) The exclusion list forbade exactly what §C requires**: it said `max_tokens`, `stop`, and `seed` MUST NOT influence the cache key — but all three change the completion, so keying them identically causes a **wrong hit, not a miss**, deterministically returning a response the caller never asked for. **(2) It prescribed a normalization JCS does not perform**: canonicalize "via RFC 8785 JCS", then, for hosts without JCS, "UTF-8 NFC for all strings" — so the two routes the same sentence offered produced **different bytes for the same input**, defeating the cross-host portability §D asserts as a normative invariant. **(3) It quoted a formula that no longer exists**: the `attempt`-bearing Layer-2 composition RFC 0150 §B retired, left behind when `idempotency.md` went to v1.4 — a cross-document staleness **§B itself introduced and did not catch**. v2 stamps the canonical object `openwop-semantic-request-v2` so retired digests are distinguishable, and carries unknown provider options in a namespaced `providerOptions` rather than dropping them. The gate reads **normative text only**, excluding blockquotes, because the document deliberately quotes the rules it retired — with a guard that the filter retains >70% of the file, and sabotage-verified that reintroducing a retired rule in normative voice still reds. 2026-08-12 (RFC 0148 §B — strict behavior, suite `1.83.0 → 1.84.0`) added one: `strict-behavior-gate.test.ts` (seven legs, server-free). §B says *"a host MUST NOT both advertise and opt out of the same profile"* — and `behaviorGate()` detected exactly that contradiction, emitted a `console.warn`, and **proceeded as if advertised**. **A MUST NOT enforced by a warning is not enforced**: nothing consumes the warning, nothing fails on it, and the certification bundle produced from that run records a pass. It matters because the two claims are opposite in kind — advertising says the host implements the profile, opting out says the operator declares it does not — so a run where both hold has no defensible reading, and the resolution the gate chose (advertisement wins) extracted **more** certification claim from a **more** contradictory input. Now throws. The second half wires §B to §A: a gate decision records a ledger disposition, so an honest opt-out is `skipped` and an unadvertised profile is `inapplicable` — both certifiable, and both distinct from the `blocked` that §A assigns to silence. **Before the ledger existed there was nothing to record into, which is why §B could not be implemented before §A.** 2026-08-12 (RFC 0148 §A — requirement execution ledger, suite `1.82.1 → 1.83.0`) added one: `requirement-ledger.test.ts` (thirteen legs, server-free) plus `src/lib/requirement-ledger.ts` and `src/lib/requirement-registry.ts`. §A's operative sentence is **negative** — "a plain test return, caught exception converted to a return, or empty assertion body MUST NOT produce `executed-pass`" — and a ledger that merely *offers* five dispositions does not deliver it. **Every vacuity found in this corpus reached `pass` by not running, not by running wrong**: `[].every(...)` over an undefined floor, a gated subtest that 404'd and soft-skipped, a scenario whose assertions never executed while its file counted green. So the ledger **inverts the default**: a requirement with no recorded disposition resolves to `blocked`, never to a pass. Silence is evidence of nothing, and the data structure says so instead of relying on each author to remember it. `blocked` is not certifiable (`skipped` and `inapplicable` are); an **empty** requirement set does not certify, because that is the `[].every(...)` shape itself; `requirementsFor()` returns **null** rather than `[]` for an unwritten floor, forcing the caller to distinguish "empty by design" from "not transcribed yet"; a non-pass disposition without a reason throws; and contradictory dispositions for one requirement throw rather than last-write-wins, since silent overwrite would let a later soft-skip bury an earlier real failure. **Scoped to the certification floor, not all 423 files** — tagging every assertion in one pass would produce a registry nobody could review, and an unreviewed requirement ID is worth less than none because it looks like coverage. Sabotage-verified on the load-bearing property: defaulting absence to `executed-pass` reds the gate. 2026-08-12 (RFC 0150 §B — cross-scope effect identity, additive, suite `1.81.0 → 1.82.0`) added one: `effect-identity-cross-scope.test.ts` (four legs, server-free). **`runId` is in the §B preimage**, so an effect issued outside any run cannot produce a Layer-2 identity at all and can never collide with one. Layer 2 dedupes a node effect against its own retries; it does **not** dedupe it against the same logical effect issued via an operator route, admin action, or scheduled job. Since §"Why this exists" requires Layer 2 "for any node executor that performs an external side effect", **a host reading that literally would use the ordinal form and stop** — and for a cross-entry-point effect that reintroduces the duplicate-effect class §B exists to kill, on the highest-stakes path it touches. v1.4 requires such effects to be **additionally keyed on a business identity**, stable across entry points and containing no `runId`/`nodeId`/ordinal. Reported by a tier-1 host from a shipped node pack (`refund-order` plus three non-run entry points reaching one implementation), not proposed in the abstract. The fork note and this are **one limitation seen twice**, and a leg asserts the linkage so a reader cannot read the fork case as a special exception. 2026-08-12 (RFC 0149 §D — lifecycle coherence, governance, suite `1.80.0 → 1.81.0`) added one: `rfc-lifecycle-coherence.test.ts` (three legs, server-free). §D asks the generator to fail when an `Accepted` RFC "retains an unresolved acceptance blocker not explicitly carried". **The obvious gate — every box ticked before `Accepted` — was measured and rejected**: of 141 `Accepted` RFCs, 42% ticked all, 25% ticked none, 24% ticked some, so a blanket rule fails 69 RFCs on its first run, and a gate that fires 69 times gets disabled rather than fixed. **The first triage hypothesis was also wrong**, and correcting it produced the rule that shipped: the partially-ticked RFCs are not a blocker backlog — every trailing item in `0027`/`0040`/`0041` is deliberately unticked *and annotated with why*, which **is** §D's "explicitly carried", just in a parenthetical rather than a register row. So the signal is **annotated vs bare, not ticked vs unticked**: an unticked item with no explanation is indistinguishable from one nobody checked. Scoped to RFCs ≥ 0147 — the program's own cohort — so **the rule binds the RFC that proposed it**, with a leg asserting exactly that; earlier RFCs are the dated record of a period when the convention did not exist, and the boundary is asserted so a new RFC cannot inherit the exemption. **All 67 bare items across 0147–0156 were annotated to land it**, which is the real work: each now names its gate. Sabotage-verified — stripping one annotation reds the leg with its file:line. 2026-08-12 (RFC 0149 §E — canonical-family shadowing, security, suite `1.79.0 → 1.80.0`) added one: `discovery-canonical-family-no-shadow.test.ts` (three legs, server-free). RFC 0073 puts canonical families at the document root and `host-extensions.md` puts vendor surface under `x-host-*` / `vendor.*` / `private.*`; together that is what makes discovery negotiable. **Nothing forbade a canonical family name appearing INSIDE the namespaced region** — `vendor.acme.auth`, or an `x-host-acme-*` object carrying its own `interrupts`. A consumer that merges vendor surface over the root before negotiating then reads a vendor's `auth` block as *the* auth contract. `host-extensions.md` already tells clients to treat extension surface as opaque, but that binds the **consumer** — it does not stop a host publishing the collision, and the consumer that gets the merge order wrong is exactly the one the rule exists to protect. Second leg, unconditional: **no discovery example may carry credential material**, because discovery is served credential-free to anonymous callers, so a real-shaped secret in an example sits in the most-copied, least-guarded artifact in the corpus. The family list is **read from `capabilities.schema.json`** rather than hand-listed, so a new family is covered the day it lands. **The corpus was already clean, making this a guardrail rather than a repair** — so it was sabotage-verified rather than red-before-green: injecting `"vendor.acme.suite": { "auth": … }` reds the shadow leg with its file:line and the colliding key, and an `sk-`-prefixed value reds the credential leg. 2026-08-12 (RFC 0149 §C — `protocolVersion` grammar, **safety-fix**, suite `1.78.0 → 1.79.0`) added one: `protocol-version-grammar.test.ts` (twenty legs, server-free). The field was specified **three incompatible ways at once**: `capabilities.schema.json` constrained it to `minLength: 1`, the suite's own core predicate tested `startsWith('1.')`, and prose called it semver while every example showed two components. So `"v1.0"`, `"1.0.0"`, and `"banana"` all validated — and `"1.0.0"` additionally **derived `openwop-core`**, because the predicate deciding whether a host is openwop-compatible at all was looser than the schema every host validates against. Comparison needs an integer major (the hard boundary) and an integer minor (the additive contract level); neither is extractable from a string nothing constrains, so two hosts advertising `"1.0"` and `"1.0.0"` gave a consumer no way to tell a patch convention from a typo from a different protocol. Now `^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$` in the schema, in `profiles.ts`, and in `version-negotiation.md` §"Protocol version grammar" — with a leg asserting the schema pattern and the predicate agree, so they cannot drift apart again. Closes gap V2, open since v1.0 with owner `future`. 2026-08-12 (RFC 0150 §D — multi-region effect vocabulary, **safety-fix**, suite `1.77.0 → 1.78.0`) added one: `multi-region-effect-vocabulary.test.ts` (eight legs, server-free). Two capability values promised things they did not deliver. **`crossRegion: "strict"`** was documented as "cross-region read-visibility is bounded by `multiRegion.replicationLagBoundMs`" — a **latency** claim occupying the top slot of a ladder implementers read as effect safety. A host replicating synchronously at 0 ms can still issue duplicate effects from two regions, because knowing what the other region wrote is not the same as being authorized to act. It was **removed rather than renamed** to `fenced-effects`: a rename would have promoted every existing `strict` advertisement into a claim no host substantiated, and its latency content is not lost because `replicationLagBoundMs` already carries it. **`partitionRecoveryStrategy`** offered `last-writer-wins` and `first-writer-wins`, both time-ordered — but under a partition there is no shared clock, so each region believes it wrote last, which cannot satisfy the annex MUST that "re-running the same conflict input MUST produce the same survivor", and both select a different survivor than the lex-min(runId) rule the same document requires. **The schema was advertising strategies that violate two MUSTs already in force.** RFC 0150 §D names only `last-writer-wins`; removing that alone would have left the identical defect under a different label, so both went and `lexicographic-min-run-id` was added to name the rule the annex actually requires. The gate also catches the unparseable ```json example RFC 0149 §B found and deliberately left. Corpus-structural tier: it reads the schema and the prose, not a host — whether an engine fences before issuing an effect needs a partition simulator plus an observable effect sink, which the existing seam does not provide. 2026-08-12 (RFC 0150 §B — Layer-2 effect identity v2, **safety-fix**, suite `1.76.0 → 1.77.0`) added one: `effect-identity-composition.test.ts` (six always-on server-free legs, skipped under the published layout). `spec/v1/idempotency.md` specified the Layer-2 key as `sha256(runId ':' nodeId ':' attempt ':' providerKey)` while the same document promised that a retried call's identity "is identical" — **both cannot hold**, and the formula was the wrong half. A retry counter in the preimage gives every retry a fresh key, so the invocation log never hits, and because the engine injects that value as the provider's `Idempotency-Key`, it also sends Stripe or OpenAI a different key each attempt — defeating the provider-side dedup the same paragraph invokes as its safety net. v1.2 specifies the domain-separated, tenant-bound composition over a `logicalInvocationOrdinal` that MUST NOT change across retries. **The gate's tier is labelled corpus-structural on purpose:** it reads the normative composition, not a host, because whether an engine reuses the identity across a retry is observed by the *provider*, not the caller, and a wire probe claiming otherwise would be the vacuous-witness pattern RFC 0148 exists to close (gap G9). Sabotage: weakening the ordinal rule to `SHOULD NOT`, or deleting it, reds the leg. 2026-08-12 (RFC 0149 §B — discovery-example root layout, editorial, suite `1.75.0 → 1.76.0`) added one: `capability-example-root-layout.test.ts` (three legs, server-free, skipped under the published layout because `spec/v1/` and `RFCS/` are not in the tarball). RFC 0073 made the document-root layout "the normative MUST since Phase 1" and, at Phase 4, made the suite grade a wrapper-only host non-conformant — the `capabilities` wrapper survives only as a deprecated shape runtime discovery tolerates until v2.0. **Tolerating a shape at runtime and teaching it in a normative example are different things:** eight `spec/v1` examples, several under headings like "Capability advertisement (normative)" introduced by prose saying hosts "advertise it under `/.well-known/openwop`", showed the deprecated wrapper. An implementer copying one produced a document RFC 0073 grades as non-conformant, and no gate noticed, **because a fenced example is prose to every validator in the corpus**. All eight unwrapped. Authoring-time only — nothing here reads a host, and RFC 0149 §B keeps runtime discovery open to unknown server-emitted properties. The RFC leg asserts the historical carve-out rather than assuming it: every `RFCS/` example still showing the wrapper is in an RFC numbered **below 0073**, so a *new* post-0073 RFC introducing one fails and the exemption cannot widen into a licence. Sabotage: restoring one wrapped example reds the lint with its file:line. 2026-08-12 (RFC 0148 §C / gap G6 — floor enforcement, implementation of existing normative text, suite `1.74.0 → 1.75.0`) added one: `certification-floor-enforcement.test.ts` (six always-on server-free legs). `PROFILE_FLOOR_SCENARIOS` defined a floor for `openwop-core-standard` alone, and `verifyBundleProfile()` computed `floorProven` from `missingFloor.length === 0 && prefixOk` — **both vacuously true over an absent floor**, so a claimed profile with nothing behind it verified as *proven*. **The floors were transcribed, not invented:** `profiles.md` §"Claiming vs passing" already requires "predicate AND passing the conformance scenarios labelled with the profile tag", and its per-profile sections already name them — so this enforces normative prose rather than adding to it, and needs no safety-fix window. **An empty floor and an unwritten floor are now different values:** `openwop-core` and `openwop-fixtures` are discovery-payload-only by prose and carry an explicit `discoveryOnly` marker; an absent key means unprovable, surfaced as `floorUnspecified` so "the corpus has no floor" stays distinct from "the host failed its floor". `openwop-replay-fork` is deliberately left unspecified — its floor is conditional on the advertised mode, which a flat required-list cannot express, and forcing it would either fail an honest single-mode host or restore the vacuity. Sabotage: restoring the old undefined-floor branch reds two legs. 2026-08-11 (RFC 0149 §A — canonical URL resolution, editorial, suite `1.73.1 → 1.74.0`) added one: `openapi-resolved-paths.test.ts` (three always-on server-free legs). It resolves each `servers[].url` against each path key and asserts exactly one `/v1` segment for versioned operations. **Why every existing gate was blind to this:** `redocly lint` validates the server, validates the paths, and never composes the two — the defect existed only in the join, where all 44 versioned path keys resolved to `/v1/v1/*`. The reference SDKs were the control: `OpenwopClient` issues `/v1/runs` against a bare base URL, so the SDKs and the canonical document disagreed about where the version segment lives and the SDKs were correct. A third leg asserts `/.well-known/*` resolves unversioned — the red run showed the duplicated base also resolved discovery to `/v1/.well-known/openwop`, so a generated client could not bootstrap at all. A guard leg fails if the extraction finds no servers or no paths, because a scan that silently matched nothing would make the other legs vacuously true. Written red first, observed failing on both counts, then green after the one-line correction. 2026-08-11 (RFC 0146 — `contractProvenance`, additive, suite `1.72.2 → 1.73.0`) added one: `contract-provenance.test.ts` (four always-on corpus legs + one behavioral). **Why validation alone cannot catch what this closes:** v1.x changes are additive, so a discovery document written against an older contract still validates against the newer schema — which is exactly why a host validating against a vendored copy 7 properties behind was green. Only a claim on the wire surfaces it. The legs assert the SHAPE of that claim and never that a host is current, because a host on an older corpus revision is CONFORMANT; a leg failing a host for being behind would convert an optional disclosure into a de-facto upgrade mandate inside a version line where being behind is permitted. Sabotage: dropping the property reds A1/A2/A3; relaxing `corpusCommit`'s 40-hex pattern reds A2 alone; opening the object reds A3 alone; softening the RFC's advisory MUST NOT reds A4 alone. 2026-08-11 (RFC 0144 G1 — which resolver arm a host lands on, suite `1.71.1 → 1.72.0`) added one: `capability-arm-witness.test.ts`. Every capability helper resolves a family through four arms — plain at root (canonical), dotted at root, plain under the deprecated `capabilities` wrapper, dotted under it — and because arms 2–4 succeed silently, **a host that never migrated reads exactly like one that did**. The suite's own tolerance was hiding the drift. The leg **enforces an existing MUST rather than adding one**: `capabilities.md` §"Document-root layout" already says *"the conformance suite reads the root only … a host that serves families exclusively under the wrapper is non-conformant and is graded as such"* — but the helpers fall back, so the corpus said one thing and the code did another. Asserted: no family reachable ONLY under the wrapper. Reported, not asserted: dotted-at-root spellings — RFC 0137 G16 makes the plain name the discovery key, but `capabilities.md`'s MUST is about the root rather than the spelling at it, so failing there would be a v1.x tightening this leg has no license for. Sabotage-verified across six placements: canonical passes; root+wrapper *mirrored* passes (mirroring is a permitted v1.x affordance); root-dotted passes **and reports**; wrapper-only and wrapper-dotted both fail. 2026-08-10 (RFC 0145 — `registrationSource` as a per-type artifact capability facet, additive, suite `1.69.0 → 1.70.0`) added one: `artifact-type-registration-source.test.ts` (five always-on corpus legs. The facet discloses which §"Schema distribution" regime a registered type falls under — serving the canonical schema URL is a MUST for host-registered (no-pack) types and only a SHOULD for pack-backed ones, and nothing in discovery said which. A2 is the load-bearing leg and is the deliberate INVERSE of RFC 0136's `format`: an out-of-enum value is REJECTED, because this facet has exactly two meanings and rides a server-emitted document, where `format` is an advisory hint on a client-submitted closed shape that must degrade rather than fail. A3 pins the discovery enum against `artifact.created.registrationSource` so the two surfaces requirement 3 forbids from disagreeing cannot drift out of comparability. Sabotage: dropping the schema property reds A1/A2/A3 and leaves the prose legs green; widening the enum reds the same three; removing the facet from either prose site reds A4 alone; relaxing the no-pack serving MUST reds A5 alone. NOT built — cross-surface agreement (requirement 3) against a live host, carried as RFC 0145 G1: no host advertises the facet yet, so the leg would be vacuously green). 2026-08-10 (RFC 0136 — `WorkflowVariable.format`, additive, suite `1.68.2 → 1.69.0`) added one: `workflow-variable-format.test.ts` (five always-on corpus legs + two capability-gated host legs. The load-bearing leg is A2, which asserts a format value OUTSIDE the v1 recognised table still validates — the property is deliberately NOT an enum, because a workflow definition is a client-submitted CLOSED shape where an enum would turn an unrecognised hint into a hard `POST /v1/workflows` failure and contradict requirement 2. Sabotage: adding `"enum"` to the schema property reds A2 alone, leaving A1 green. Host legs gate on `workflowChainPacks.deferredParameters.supported` — the only mode that mints a `WorkflowVariable` from a chain parameter, so the only mode where `format` propagation can be a MUST). 2026-08-09 (RFC 0143 — tool-result trust monotone through composition, additive, suite `1.67.1 → 1.68.0`) added one: `tool-result-trust-monotone.test.ts` (always-on server-free — the general rule the corpus's ~ten point-invariants instance: a COMPLETENESS leg asserts every §4 STRIDE ingress the threat model names has a real fencing invariant + a curated floor of prompt-ingress surfaces, so a new ingress shipped without a fence reds it; the meet-semilattice rule is stated normatively in §2a; and the MCP/A2A + compose-boundary instances cross-reference the general rule. Host behaviour through the durable-store hop is witnessed at openwop-app, not here. Sabotage-verified one-per-surface: renaming a floor invariant reds the completeness leg, softening the meet reds the prose leg). 2026-08-08 (RFC 0140 — replay side-effect suppression, additive, suite `1.66.0 → 1.67.0`) added one: `replay-side-effect-suppression.test.ts` (capability-gated on `replay.sideEffectSuppression: "recorded-outcome"`. The load-bearing leg is the FAIL-CLOSED path, not the happy path: a node replayed from a recorded outcome is log-indistinguishable from one that re-fired and recorded the same thing, but a node with NO recorded outcome is not — a non-suppressing host completes it, a suppressing host must emit `replay_source_missing`. That asymmetry is what lets the leg run with no operator-side effect instrumentation. Uses the conformance-RESERVED `core.conformance.side-effect` typeId, host-mapped to a genuinely side-effecting node. Non-vacuity proven with TWO sabotages against the reference host, one per suppression mechanism: disabling both reds it; leaving only the host's runtime backstop keeps it green, which is the evidence for the whole-run guarantee in §B.4). 2026-08-08 (RFC 0141 — legacy artifact-type identifiers, additive, suite `1.64.0 → 1.65.0`) added one: `artifact-type-legacy-ids.test.ts` (always-on server-free prose-pinning — a bare legacy id is rejected by the manifest schema while a canonical id validates, and the corpus states normatively that legacy ids were never wire-conformant with no grandfather clause, that a migrating host MUST NOT rewrite historical `artifact.created.artifactType` values, that the read-side alias is permanent and MUST resolve where validation is decided, and that an alias map is a host shim, not a conformance claim. Host-side alias behaviour is witnessed at openwop-app, not by this suite; a rewritten log is undetectable after the fact). 2026-08-07 (RFC 0139 — host-side witness for pack-manifest extension opacity, additive, suite `1.63.0 → 1.64.0`) added one: `pack-manifest-extension-opacity.test.ts` (gated on `behaviorGate` — the host-side half RFC 0138 could not provide. The load-bearing leg is DIFFERENTIAL, not presence: install the same manifest with and without an unrecognized `vendor.conformance.*` extension and require the registration projection to be identical once extensions are stripped. Sink-agnostic, because a suite cannot enumerate a host's sinks. Measured against stub hosts — a violating stub that routes an unrecognized extension into a derived facet PASSES the presence legs and fails only the differential ones. Witnesses INSTALL-TIME sinks only; does not witness `artifact.created` (RFC 0138 G8) since this seam emits no run events. Landed with the G14 flip: `artifact-type-pack-install`, `artifact-type-store-without-render` and `chat-card-pack-execution` moved from bare `return` to `behaviorGate`, so advertised-with-no-seam now FAILS under `OPENWOP_REQUIRE_BEHAVIOR=true` instead of reporting green). 2026-08-06 (RFC 0138 — vendor-extension hatch on pack manifests, additive, suite `1.62.0 → 1.63.0`) added one: `pack-manifest-extensions.test.ts` (always-on server-free — every pack manifest root admits the `^(x-|vendor\.)` hatch, enumerated against an explicit in-scope count of 9 rather than a naming glob, because the first draft globbed `*-pack-manifest.schema.json` and silently skipped `frontend-plugin-manifest.schema.json`; the hatch stays NARROW — a misspelled canonical field is still rejected and no pattern anywhere matches a bare canonical-looking key; and the corpus states the MUST-ignore, the "ignore means ignore" definition, the pack-authored/untrusted framing, and the not-a-capability-channel rule normatively, since the schema alone cannot express "MUST ignore". Host-side honoring of MUST-ignore is NOT covered — that needs a host-sample seam behind `behaviorGate`, gaps G6/G7). 2026-08-05 (RFC 0137 — the behavioral half, suite `1.60.1 → 1.61.0`) added one: `form-content-instantiation.test.ts` (capability-gated on `host.forms.contentPacks` + the `POST /v1/host/sample/formcontent/instantiate` seam — instantiation goes through the host's NORMAL create path with no pack-bound routing destination, an unrecognized `vendor.*`/`x-` field type DEGRADES to a plain text input rather than failing, and pack-authored fields stay fully editable. Added because RFC 0137's original graduation gate was unsatisfiable: every leg it shipped was server-free and passed identically against a host that never implemented it). 2026-08-05 (RFC 0137 — form-content packs, additive, suite `1.58.0 → 1.59.0`) added one: `form-content-packs.test.ts` (always-on server-free corpus legs — the registry version manifest carries `kind: "form-content"`, the `templates` payload property AND the load-bearing `anyOf` payload branch; the new source manifest enforces the schema-discipline floor and rejects `email`/`textarea` as field types, `key` in place of `id`, an integer `templates[].version`, and any `runtime`; and — the regression guard that matters — `fields[].type` is asserted byte-identical to chat-card `inputs[].type` so neither declarative kind's field vocabulary can be widened alone. The host-side instantiation + trust-boundary behavior is capability-gated on `host.forms.contentPacks` and host-pending). 2026-07-23 (RFC 0135 — workflow-chain gallery visibility, additive, suite `1.57.0 → 1.58.0`) added one: `workflow-chain-internal-flag.test.ts` (always-on server-free corpus legs — the manifest §WorkflowChain carries a boolean `internal`, an `internal: true` chain validates and a non-boolean is rejected, and the spec pins the MUST-omit-from-default-gallery + not-an-authorization-boundary rules; the gallery-omission behavior is witnessed at the reference host, not over the wire). 2026-07-23 (RFC 0134 — edge-condition `truthy`/`falsy` operators, additive) added one: `edge-condition-truthy-falsy.test.ts` (always-on corpus legs — the `workflow-definition` + inlined manifest `§EdgeCondition` `type` enums carry `truthy`/`falsy`, a no-`right` truthy/falsy edge validates, the spec documents the no-`right`+required-`left` semantics — plus a capability-gated host-mapping leg that soft-skips until a reference host maps the operators). 2026-07-22 (RFC 0133 — workflow-chain composition, suite `1.55.1 → 1.56.0`) added five: three always-on server-free scenarios (`chain-subchain-sibling.test.ts` — sub-chain co-registration mints a deterministic child id + rewrites `config.subChainRef` → the child `config.workflowId` + dedups a doubly-referenced child; `chain-subchain-cycle-rejected.test.ts` — the public witness for `sub-chain-expansion-bounded`: self-composition AND a depth-bound breach both reject with `sub_chain_cycle`, an acyclic tree within the bound expands, an unresolvable ref is `sub_chain_unresolved`; `chain-produced-var-roundtrip.test.ts` — `producedVariables` emit into `variables[]` with no value + closed-world `variable_undeclared` rejection) plus two capability-gated scenarios (`chain-subchain-fanout.test.ts` — a `core.dispatch` child-run over a `subChainRef` worker + the manifest `not`-guard on a concrete `config.workflowId`, behavioral home of `sub-chain-child-tenant-scoped`; `chain-subchain-unsupported-refused.test.ts` — an unsupported host refuses a `subChains`-bearing chain with `sub_chain_unsupported` (422), never flattening) that soft-skip until a reference host wires runtime child dispatch. 2026-07-22 (RFC 0132 — anonymous-actor authorization) added six: `anonymous-actor-shape.test.ts` (always-on, server-free — validates the `capabilities.anonymousActor` advert + the §B.2 `writeEgressControls`-iff-`bounded-write-egress` conditional + `owner.principalKind` + the RFC 0049 `authorization.decided` audit reuse) plus five capability-gated behavioral scenarios (`anonymous-actor-default-deny`, `-no-secret-reach`, `-egress-guarded`, `-write-gated`, `-audit-opaque`) that drive the `/v1/host/sample/anon-surface/{tools,dispatch}` seam and soft-skip until a host wires a tool-enabled public surface — each the public witness for a reference-impl-tier SECURITY invariant that graduates to protocol tier once a host passes it non-vacuously. 2026-07-07 (RFC 0131 — agent-manifest `role` + the Skill profile) added `agent-manifest-role-profile.test.ts` (always-on, server-free schema-shape probe of the additive optional `AgentManifest.role` + the schema-encoded Skill profile: a `role:"skill"` manifest with `handoff` + scratchpad-only memory validates; one declaring `conversation`/`longTerm` memory or omitting `handoff` FAILS validation — a malformed-manifest reject, NOT an RFC 0072 `degraded[]` runtime tier; an absent `role` with any `memoryShape` validates unconstrained; a bad enum value fails — the public witness for `agent-skill-profile-stateless`). 2026-07-06 (RFC 0129 — data-residency, suite `1.53.1 → 1.54.0`) added `data-residency-admission.test.ts` (always-on `capabilities.dataResidency` + `residency.schema.json` shape probes + `residency_unavailable` error-registration check; plus capability-gated behavioral legs driving the NORMATIVE `POST /v1/runs` endpoint — an advertised region MUST NOT be rejected `residency_unavailable`, an unadvertised region MUST be rejected with that code at HTTP one-of 400/404/422 and create no run — advertise-only-what-you-honor, soft-skip until a host advertises `dataResidency`). 2026-07-06 (RFC 0127 + RFC 0128 — CDP Track-2, suite `1.52.0 → 1.53.0`) added `trigger-stream-cdc-sources.test.ts` (always-on schema probes for the `stream`/`change` TriggerEvent sub-objects — `op` REQUIRED negative, exactly-one rule, registration + capabilities vocabulary pins — plus capability-gated behavioral legs driving the existing `/v1/host/sample/trigger-bridge/ingest` + `/deliver` seams: schema-valid delivered envelopes, SR-1 content-free durable events with a body canary, `(topic,partition,offset)` dedup effectively-once) and `purpose-propagation.test.ts` (always-on `permittedPurposes` + `capabilities.purposePropagation` family shape probes, plus the capability-gated two-hop legs via the new `POST /v1/host/sample/purpose-propagation/forward` seam: onward label ⊆ received, derived-output ⊆ intersection of labelled inputs, unlabelled adds no constraint, `[]` fail-closed dropped with an unlabelled positive control). Both behavioral suites soft-skip pre-implementation and become REQUIRED once the host advertises the surface (advertise-only-what-you-honor). 2026-07-05 (RFC 0013 erratum A-lite — bundle + load the sample-pack fixture, suite `1.51.0 → 1.52.0`) bundled the `vendor.openwop.workflow-chain-sample` pack into the conformance package at `fixtures/pack-manifests/workflow-chain-sample.pack.json` (host-syncable, ships in `files`) and refactored `workflow-chain-host-expansion.test.ts` to **load** it + derive the expected expansion from the `expandChain()` reference library instead of hardcoding — so a live host serving `POST /v1/host/sample/workflow-chain:expand` is checked against the spec algorithm for the identical published pack (closes the RFC 0013 host-expansion witness's fixture gap; the seam still soft-skips until a host advertises `workflowChainPacks.hostExpansionSeam`). `fixtures-valid.test.ts` now schema-selects pack-manifest fixtures by `kind` (node-pack vs workflow-chain-pack). No scenario-file count change. 2026-07-05 (RFC 0013 erratum — host-expansion test seam decouple, suite `1.50.0 → 1.51.0`) re-gated `workflow-chain-host-expansion.test.ts` from the semantic `workflowChainPacks.supported` claim onto a new OPTIONAL `workflowChainPacks.hostExpansionSeam` test-harness sub-flag (no scenario-file count change), so a host advertising `workflowChainPacks.supported` / RFC 0124 `deferredParameters.supported` is no longer conscripted into the never-bundled `vendor.openwop.workflow-chain-sample` seam under `OPENWOP_REQUIRE_BEHAVIOR` — the semantic claim rides the server-free `workflow-chain-expansion.test.ts` legs, RFC 0124's deferred path its own `/chain/deferred-expand` seam. 2026-07-04 (RFC 0124 — portable per-run parameter deferral, suite `1.49.0 → 1.50.0`) added `workflow-chain-deferred-parameters.test.ts` (always-on, server-free legs against the reference `expandChainDeferred` in `conformance/src/lib/workflow-chain-expansion.ts`: non-sensitive deferral materializes `variables[]` with `defaultValue`+`type` and leaves ZERO `{{params.*}}` tokens (R3), a whole-value input token → variable-sourced PortValue, the bare param name is the auto-generated `configurableSchema` override key (R6); §Security legs: a `x-openwop-sensitive` prompt-body param materializes `source:"secret"` with the plaintext appearing NOWHERE — not bagged — a sensitive whole-value `node.input` fails closed `sensitive_param_not_deferrable` (422), a sensitive param on a host without `secrets` support fails closed, and a host without a `prompts.variable` source falls back to expansion-time (G5); plus schema-surface legs pinning the amended `source:"secret"` wording in the manifest schema + the `credentialRef` per-run supply shape; capability-gated host legs over `POST /v1/host/sample/chain/deferred-expand` for the bare-param override / `:fork` replay / `contentTrust:"untrusted"` fence / `[REDACTED]` sensitive compose, soft-skip 404/403). 2026-07-04 (RFC 0126 — data-parallel dispatch per-item input, suite `1.48.0 → 1.49.0`) added `dispatch-per-item-input.test.ts` (always-on, server-free schema legs on `orchestrator-decision.schema.json` §NextWorkerDecision: a well-formed index-aligned `nextWorkerInputs` validates, a decision omitting it stays valid (additive/back-compat), a non-object item and a non-array are rejected, a mis-named `perItemInputs` is rejected by `additionalProperties:false` (the fail-closed rail for pre-RFC-0126 strict validators), and a length-mismatch is ADMITTED at the wire because `nextWorkerInputs.length == nextWorkerIds.length` is not JSON-Schema-expressible — a host runtime MUST; capability-gated behavioral legs over `POST /v1/host/sample/dispatch/per-item` asserting a host advertising `capabilities.dispatch.perItemInput` projects `nextWorkerInputs[i]` into child `i` (per-item value wins over `inputMapping`), a length-mismatch fails with a `validation_error` dispatching no child, and a host NOT advertising the capability fails closed on a non-empty `nextWorkerInputs` rather than silently dropping it and dispatching N identical children; soft-skips on 404/403). 2026-07-02 (RFC 0122 — self-hosted runner, suite `1.47.0 → 1.48.0`) added `self-hosted-runner.test.ts` (always-on schema legs for the `selfHostedRunner` capability block + the dispatch/result/registration frame shapes; an advertisement-gated block-shape leg; capability-gated behavioral legs over `POST /v1/host/sample/runner/{register,dispatch}` asserting subject-first isolation, retriable `runner_unavailable`, and at-most-once dedup — the public test for the protocol-tier `runner-credential-non-transit` + `runner-output-untrusted-transport` invariants; soft-skips on 404). 2026-07-01 (RFC 0121 — subscription-reuse provider auth mode, suite `1.46.0 → 1.47.0`) added `aiproviders-subscription-scope.test.ts` (always-on schema leg: the `aiProviders.authModes` closed enum includes `subscription`; §B.7 advertisement-gated leg: a `subscription` provider MUST appear in `byok`; §B.8 bind-seam-gated leg over `POST /v1/host/sample/credentials/bind` asserting a tenant-scope binding is rejected with `credential_scope_forbidden` — the public test for the protocol-tier `subscription-credential-user-scope-only` invariant. §B.8 is gated on the seam rather than on advertisement, so a host that cannot lawfully advertise `subscription` can still witness the user-scope safety rail; soft-skips when the seam is unwired). 2026-06-29 (RFC 0120 — connection-pack `apiHosts` credential-egress allow-list, suite `1.45.0 → 1.46.0`) added `connection-pack-apihosts.test.ts` (always-on schema legs: the `connection-pack-apihosts-valid` fixture validates, an `openapi`-reach provider omitting `apiHosts` is rejected by the conditional-MUST `allOf`, and IP/wildcard/port/single-label/uppercase entries are each rejected; always-on matching-rule legs: the item-10 dot-anchored eTLD+1 suffix-containment rule permits subdomains + a tighter exact host and fails closed with no substring/suffix/prefix escape — the public tests for the protocol-tier `connection-pack-api-host-shape` + `connection-pack-egress-host-bound` invariants; plus a capability-gated behavioral egress allow-list leg over the new `POST /v1/host/sample/connection-packs/egress-check` seam, soft-skipping when unadvertised/unwired). 2026-06-28 (RFC 0118 — parallel sub-workflow fan-out and join, suite `1.44.0 → 1.45.0`) added `dispatch-fanout-parallel.test.ts` (always-on schema legs for `dispatch-config.schema.json` — accepts a valid `parallel` config + each `joinPolicy.mode` + `maxConcurrency`, rejects unknown enum values / `additionalProperties` on `joinPolicy` / non-positive `maxConcurrency`, keeps a pre-RFC-0118 config valid — and the `dispatchFanOut`/`dispatchJoin` event `$defs` of `run-event-payloads.schema.json` — `fanOutPolicy` const `parallel`, `childCount ≥ 2`, the required replay-deterministic `mergeOrder`; capability-gated behavioral legs over `POST /v1/host/sample/dispatch/fanout` (wait-all/collect → `joinOutcome: satisfied` + full `children[]` + `mergeOrder`) plus the un-gated registration-rejection leg (`fanOutSupported:false` host MUST reject `parallel` with a 4xx); soft-skips on absent `dispatch.fanOutSupported` / `parallel` ∉ `fanOutPolicies`). 2026-06-27 (RFC 0117 — front-end plugin packs, suite `1.43.0 → 1.44.0`) added `frontend-plugin-packs.test.ts` (always-on schema legs for `frontend-plugin-manifest.schema.json` + the `ui-plugin/1` envelope `ui-plugin-message.schema.json`: manifest validity, `runtime`-forbidden, path-traversal-guarded `entry`, the closed `hostApi` allowlist, the version-token `artifact_conflict` + `currentVersion` concurrency shape, and no credential-bearing envelope field (`additionalProperties:false`); the capability-shape leg asserts `isolation` pins to the `cross-origin-iframe` const; capability-gated behavioral legs over `POST /v1/host/sample/ui-plugin/rpc` assert an undeclared method → `method_not_allowed` and a stale `artifact.write` → `artifact_conflict` with no persist; soft-skips on absent `capabilities.uiPlugins.supported` or `404`/`403` on the seam (RFC 0117 stays Active pending host witnesses); the public test for the protocol-tier `frontend-plugin-{isolation,egress,rpc-allowlist,no-byok}` invariants). 2026-06-26 (RFC 0116 — portable prompt-prefix cache, suite `1.42.0 → 1.43.0`) added `prompt-prefix-cache.test.ts` (advertisement-shape on `aiProviders.promptPrefixCache` + behavioral legs over the OPTIONAL `POST /v1/host/sample/ai/generate` seam (`host-sample-test-seams.md` §16): (a) outcome-invariance — a generate with `cachePrefixId` and a control without produce the same accepted envelope + identical `provider.usage.inputTokens`/`outputTokens` (cost-hint-only, replay-invariant); (b) cache-hit observable — a repeat generate shows `cacheReadTokens > 0`; (c) cross-tenant isolation — tenant B’s first use of tenant A’s `cachePrefixId` shows `cacheReadTokens == 0`, the public test for the protocol-tier `prompt-prefix-cache-cross-tenant-isolation` invariant (the host MUST key its provider cache by `(tenant, cachePrefixId)`, never global); (d) secret-free — the cost-only cache-token fields carry no prompt substrings (SR-1); soft-skips on absent `aiProviders.promptPrefixCache.supported` or `404`/`405` on the seam, since RFC 0116 defers reference-host impl as provider-gated). 2026-06-26 (RFC 0114 — A2UI surface deltas, suite `1.41.0 → 1.42.0`) added `a2ui-surface-delta-transport.test.ts` (always-on legs use a cast-free, dependency-free client-side RFC 6902 applier + Ajv2020 to assert: the new `a2ui-surface-delta-frame.schema.json` compiles, the op enum excludes `test`, a full surface + delta frames reconstruct the expected tree AND equal the full a non-negotiating subscriber materializes and re-validate against the closed catalog, an out-of-catalog/script-bearing delta fails closed-catalog validation post-patch — the `a2ui-surface-no-code-exec` boundary holds — and the recorded envelope is always the full surface; the HTTP leg is capability-gated on `a2uiSurface.deltaTransport` and soft-skips on absent host/capability or `404`/`405` on the OPTIONAL `GET /v1/host/sample/a2ui/surface/materialized` seam). 2026-06-26 (RFC 0111 — context economy, suite `1.40.0 → 1.41.0`) added `context-budget-transcript-bound.test.ts` (capability-gated on `multiAgent.executionModel.contextBudget.transcriptTokenBudget` being present via `behaviorGate(openwop-context-budget, …)` — drives the `conformance-context-budget-multiturn` orchestrator fixture, reads the host’s per-iteration accounting via the OPTIONAL seam `GET /v1/host/sample/agent/transcript-window?runId=…&iteration=N` (`host-sample-test-seams.md` §14), and asserts `tokenCount ≤ transcriptTokenBudget` in the advertised `tokenCounter` unit, that every `eventId` in the seam accounting is a real persisted run event (internal-consistency cross-check against `/v1/host/sample/test/runs/:runId/events`), recent-tail + no-double-count, every `summarizedRanges.summaryRef` has a matching `context.summarized` event, and `keepLastTurns` recent turns are fed verbatim — never inside a summarized range; soft-skips on `404`/`405` since the RFC defers reference-host impl) + `context-summarization-replay.test.ts` (capability-gated on `multiAgent.executionModel.contextBudget.summarization.supported` via `behaviorGate(openwop-context-summarization, …)` — replays the run via `:fork mode:replay` and asserts the recorded `context.summarized` → `summaryRef` records are REUSED, never re-summarized, the direct analogue of RFC 0041 envelope-refusal recovery; soft-skips when the event-log seam is unwired, no `replay` mode is advertised, or the run produced no summarization). 2026-06-26 (RFC 0113 — memory injection budget, suite `1.39.0 → 1.40.0`) added `memory-injection-budget.test.ts` (capability-gated on `memory.injectionBudget.supported === true` via `behaviorGate(openwop-memory-injection-budget, …)` — drives the `conformance-agent-memory-injection-budget` fixture through the host-sample memory seam and asserts the budgeted injection read's cumulative tokens ≤ the requested `tokenBudget` in the advertised `tokenCounter` unit (`o200k_base`/`cl100k_base`/`chars`/`host-defined`), an over-budget single entry is omitted not truncated, and re-asserts SR-1 (`[REDACTED:<secretId>]` content) + CTI-1 (cross-tenant probe returns empty) on the budgeted path; the `rank:'relevance'` leg DELEGATES to `memory.search` semantic (RFC 0080) and asserts relevance ordering differs from recency ONLY when the host ALSO advertises `memory.search` semantic, else it soft-skips — there is NO ranking primitive in `injectionBudget`; soft-skips on hosts that do not advertise `memory.injectionBudget`). 2026-06-26 (RFC 0112 — compact tool projection, suite `1.38.0 → 1.39.0`) added `tool-catalog-compact-projection.test.ts` (capability-gated on `toolCatalog.compactView === true` via `behaviorGate(openwop-tool-catalog-compact, …)` — drives `GET /v1/tools?view=compact` and asserts the host returns the `{ tools: CompactToolDescriptor[] }` envelope where every descriptor validates against `compact-tool-descriptor.schema.json` with the heavy `ToolDescriptor` fields dropped, every present `inputSchema` satisfies the self-contained compact structural subset (top-level `type:"object"`+`properties`; no `$ref`/`oneOf`/`allOf`/`anyOf`/`not`/`patternProperties`/`dependentSchemas`), and the compact `tools[]` `toolId` set EQUALS the standard view set for the same principal (projection completeness); soft-skips on hosts that do not advertise `toolCatalog.compactView`). 2026-06-26 (RFC 0115 — run transport economy, suite `1.37.0 → 1.38.0`) added `run-transport-economy.test.ts` (capability-gated on `restTransport.conditionalRunGet === true` and a non-empty `restTransport.contentEncodings` — drives `GET /v1/runs/{runId}` and asserts a sequence-derived strong `ETag` on the `200`, `If-None-Match` → `304` with an empty body while the run is unchanged, the `ETag` ROTATES after the `conformance-approval` fixture advances `waiting-approval → completed` (proving it derives from the latest persisted event-log sequence, not a coarser signal that would leave a `304` stale), and each advertised `Content-Encoding` (`gzip` baseline; `br`/`zstd` optional) round-trips byte-identically to the identity body; soft-skips on hosts that do not advertise `restTransport`). 2026-06-24 (RFC 0110 — channel presence, behavioral leg) added `channel-presence-behavioral.test.ts` (capability-gated on `channelPresence.supported` via `behaviorGate('openwop-channel-presence', …)` — drives the `POST /v1/host/sample/channel-presence/snapshot` seam and asserts a live `channel.presence` snapshot is the CLOSED `{conversationId,present,typing}` shape (no PII), every ref is an opaque RFC 0041 `user:`/`agent:` subject, `typing ⊆ present`, and the snapshotting member is non-vacuously present; soft-skips on 404/405 — a host whose presence is bound to a product flow witnesses via its own route test + an INTEROP-MATRIX row, the RFC 0086 dual-staging). 2026-06-24 (RFC 0110 — channel presence, Accept cycle) added `channel-presence-shape.test.ts` (always-on server-free — the OPTIONAL `channel.presence` ephemeral payload validates a conforming snapshot, REQUIRES `conversationId`+`present`, is CLOSED `additionalProperties:false` (the no-PII guard), `typing` optional; `channel.presence` is in the `RunEventType` enum; the `channelPresence` capability block is declared + closed). 2026-06-24 (RFC 0109 — conversation-turn model provenance, Accept cycle) added `conversation-turn-model-provenance-shape.test.ts` (always-on server-free — `agent.model` `{provider, model}` validates conforming / both-required / closed-SR-1 / optional-back-compat, + the `conversationTurnModelProvenance` capability declared + closed). 2026-06-24 (RFC 0108 — self-hosted / OpenAI-compatible provider class, Accept cycle, suite `1.36.0 → 1.37.0`) added the gated behavioral honesty leg `aiproviders-selfhosted-honesty.test.ts` (gated on `aiProviders.selfHosted.length > 0` via `behaviorGate('openwop-selfhosted-providers', …)` — drives `POST /v1/host/sample/ai/call` against an advertised `selfHosted` id and asserts **§A.2** the dispatch reaches a real configured endpoint (success or transport error — never `capability_not_provided` / `provider_not_supported`, which would prove a dishonest advertisement with no endpoint behind it) and **§D** the endpoint location — supplied out-of-band via `OPENWOP_TEST_COMPAT_ENDPOINT`, checked as the raw string + bare `host`/`host:port` — never appears in the seam response or error payload; soft-skips on 404 / when the env var is unset for the §D leg). 2026-06-24 (RFC 0108, suite `1.35.0 → 1.36.0`) added the always-on server-free shape leg `aiproviders-selfhosted-shape.test.ts` (the additive `aiProviders.selfHosted` advertisement: a `string[]` with `uniqueItems`/`minLength:1` items, absent from `aiProviders.required`, validates a conforming array via Ajv2020 while rejecting non-array / duplicate / empty-string forms, and enforces the two §A rules JSON Schema cannot express — §A.1 every `selfHosted` entry is a subset of `supported`, and §A.3 / `self-hosted-endpoint-no-disclosure` no entry is URL-shaped (`://`, bare `host:port`, or leading `/` path) — exercised against good/bad example docs). 2026-06-23 (RFC 0106 — real-time voice session profile, Accept cycle) added six gated behavioral scenarios driving the openwop-app live host (rev `00293-89w`): `voice-transcription-streaming` + `voice-transcription-unadvertised` (the `call-transcriber` seam; the latter gated-by-absence), `voice-synthesis-streaming` (the `stream:true` synthesis arm → metadata-only `voice.synthesis_chunk` events), `voice-bargein-no-partial-leak` (the `/voice/barge-in` seam — `voice.barge_in`→`voice.cancelled` with no chunk after; **graduated `voice-bargein-no-partial-leak` reference-impl→protocol** on the live proof), and `voice-interim-not-durable` + `voice-streamref-tenant-bound` (§F INV-1/INV-4; soft-skip on the §E `transcription_unsupported` / no-live-streamRef path — stay reference-impl until a host with a scripted-interim / live-streamRef arm proves them). 2026-06-23 (RFC 0107 — publishable declarative pack kinds) added one: `registry-declarative-kinds.test.ts` (always-on server-free — the registry version-manifest carries the `kind` discriminator + per-kind declarative payload, `runtime` is conditional on `kind` via `allOf if/then/else`, published artifact-type and connection manifests validate, and a declarative-with-`runtime` or node-without-`runtime` manifest is rejected). 2026-06-23 (RFC 0107 correction, suite `1.34.0 → 1.35.0`) extended that scenario with two cases — a published **chat-card** pack manifest (`kind: "card"`, RFC 0071) validates, and the never-canonical `kind: "chat-card"` is **rejected** — fixing a kind-string mismatch where RFC 0107's published schema enumerated `chat-card` while RFC 0071 (authoritative) defines `card` (no scenario-file count change; cases added to the existing file). 2026-06-23 (RFC 0106 — real-time voice session profile, Phase 2) added one: `voice-event-payloads-shape.test.ts` (always-on server-free — all seven `voice.*` types are in the `RunEventType` enum, each has a payload `$def` via `typeIndex`, `voice.transcript` REQUIRES `contentTrust:"untrusted"` (the schema-enforced half of `voice-transcript-untrusted`), `voice.synthesis_chunk` is metadata-shaped (seq+mimeType required; bytes by `url`/`streamRef`), and the content-free events reject unknown properties). Phase 2 also lands the `voice.*` payload `$defs` in `run-event-payloads.schema.json` + the `asyncapi.yaml` messages + the four §F `SECURITY/invariants.yaml` rows (1 protocol-tier `voice-transcript-untrusted` + 3 reference-impl behavioral, graduating at `Active → Accepted`). The gated behavioral legs (`voice-transcription-streaming`/`-unadvertised`, `voice-synthesis-streaming` + the three behavioral invariant scenarios) land with the reference host at `Active → Accepted`. 2026-06-23 (RFC 0106 — real-time voice session profile, Phase 1) added one: `aiproviders-realtimevoice-shape.test.ts` (always-on server-free — the `aiProviders.realtimeVoice` object advertisement: the four sub-flags `transcription`/`synthesis`/`turnDetection`/`bargeIn` are declared, `realtimeVoice` is absent from `aiProviders.required`, the `turnDetection`/`bargeIn ⇒ transcription` `dependentRequired` closure and the `synthesis ⇒ speechSynthesis` if/then closure hold via Ajv2020, and out-of-enum / boolean sub-flag values are rejected). The gated behavioral legs (`voice-transcription-streaming` / `-unadvertised`, `voice-synthesis-streaming`) and the four §F live-ingress invariant scenarios land in Phase 2 at the `Active → Accepted` cycle. 2026-06-22 (RFC 0101 — multi-party group conversation) added two — `multi-party-conversation-shape.test.ts` (always-on server-free — asserts the three additive RFC 0101 wire facts: a 3-agent council `conversation.opened` participant roster (instance ids) + a user opening turn validates, every `role: 'agent'` turn carrying a roster-instance `speakerId` validates while one OMITTING `speakerId` MUST FAIL schema validation (the `allOf`/`if role==='agent' then required:['speakerId']` conditional), a non-AgentRef participant item is rejected, the `capabilities.multiPartyConversation { supported, maxParticipants? }` block is declared + closed and rejects extras / `maxParticipants:1` / a missing `supported`, and the non-participant membership predicate is asserted server-free) and `multi-party-conversation-behavioral.test.ts` (capability-gated on `multiPartyConversation.supported` via `behaviorGate('openwop-multi-party-conversation', …)` — drives the conformance-only seam `POST /v1/host/sample/conversation/multi-party/{open,exchange}` (`host-sample-test-seams.md`, since RFC 0101 mints no normative client trigger to open a council): a 3-agent council opens and a roster-valid attributed agent turn is accepted, while a `role:'agent'` turn missing `speakerId`, a non-participant `speakerId`, and an over-`maxParticipants` open are each rejected with `error.code:'validation_error'` (status-tolerant 400/422 per RFC 0005 §E); soft-skips on 404/405 — reference impl: the postgres example host). 2026-06-20 (RFC 0105 — speech synthesis adapter) added three: `aiproviders-speechsynth-shape.test.ts` (always-on server-free — the `aiProviders.speechSynthesis` `const "supported"` flag is declared, absent from `aiProviders.required`, and a string-const advertisement validates while the object form `{supported:true}` is rejected), `speech-synthesis-roundtrip.test.ts` (gated on `aiProviders.speechSynthesis === "supported"` via `behaviorGate('openwop-speech-synthesis', …)` — an advertising host's `callSpeechSynthesizer` round-trip via the `POST /v1/host/sample/ai/call-speech-synthesizer` seam returns `audio` with EXACTLY ONE of `url`/`base64`, a non-empty `mimeType`, and the echoed `voiceId`; soft-skips on 404), and `speech-synthesis-unadvertised.test.ts` (gated-by-absence via `behaviorGate('openwop-speech-synthesis-unadvertised', …)` — a host NOT advertising `speechSynthesis` MUST reject the call with `speech_synthesis_unsupported`, never a silent no-op). 2026-06-19 (RFC 0104 — portable HITL approver routing) added one: `interrupt-approver-routing.test.ts` (server-free Ajv2020 — the `interrupt.approverRouting` capability block shape, the additive optionality of `approverGroupRefs` / `approverRoleRefs` / `audience` on the `ApprovalData` schema, the closed `audience` object, and the §"Portable approver routing" `notifyTargets` reference rule that `audience` DEFAULTS to the resolved eligibility union when omitted and OVERRIDES it when present; the capability-gated leg asserts an advertising host's `interrupt.approverRouting` is honest — `refKinds` ⊆ {group, role}, `audience` boolean — and soft-skips when the host does not advertise the capability). 2026-06-17 (RFC 0103 — localized content surface) added one: `localized-content-delivery.test.ts` (server-free Ajv2020 — the four content schemas + the §C `resolveSection` merge + §A capability coherence; the public test for `content-published-cache-no-draft` / `content-response-tenant-scoped` / `content-no-cross-tenant-enumeration`; the live legs gate on `capabilities.content.supported` and soft-skip without a `GET /v1/content/pages/{slug}` target). 2026-06-15 (RFC 0102 — A2UI agent-authored interface surfaces) added five: `a2ui-surface-shape.test.ts` (server-free Ajv2020 — the closed core `ui.a2ui-surface` payload validates, while an out-of-catalog component / extra script-bearing property / unenumerated `catalogVersion` / `action.target` outside `enum["resume","exchange"]` each fail; the structural half of `a2ui-action-confinement` and the enabling precondition for the render-side `a2ui-surface-no-code-exec` / `a2ui-surface-no-network-egress` reference-app probes), `a2ui-surface-degrades.test.ts` (the kind is optional/advertised, not a MUST-recognize universal kind, and an unadvertised kind is gated — N6 — never crashing the run), `a2ui-surface-version-refusal.test.ts` (the enumerated `catalogVersion` rejects an unadvertised version → `unknown_schema_version`, and the surface schema carries no external `$ref`), `a2ui-surface-replay.test.ts` (all `$ref`s internal so a stored surface `:fork`/replays deterministically; same-`correlationId` + divergent `type` → `envelope_correlation_conflict`), and `a2ui-untrusted-blocks-approval.test.ts` (a `meta.contentTrust:'untrusted'` surface is trust-gated and MUST NOT advance an approval interrupt — composition of `untrusted_content_blocks_approval`). The four behavioral legs soft-skip on 404 (host-pending; the `openwop-app` reference renderer is the render-side probe). 2026-06-14 (RFCs 0099/0100 — external-event trigger ingestion + async/durable A2A tasks) added one new scenario (`trigger-ingestion.test.ts`) and extended `a2a-task-roundtrip.test.ts` with the RFC 0100 async subtests: `trigger-ingestion.test.ts` (RFC 0099 — always-on `TriggerEvent` / `TriggerSubscriptionRegistration` schema legs incl. the §F.1 per-source one-of, the `AttachmentRef.ref`-only rule + raw-URL rejection backing `trigger-ingestion-ssrf`, and the content-free `trigger.delivery.attempted` shape backing `trigger-ingestion-content-redaction`; plus a capability-gated behavioral leg on `triggerBridge.ingestion` driving the `POST /v1/host/sample/trigger-bridge/ingest` seam for SSRF refusal + header-redaction), and the `a2a-task-roundtrip.test.ts` additions (RFC 0100 — always-on `A2ATaskState` + `capabilities.a2a` shape legs incl. the lowercase-hyphen state enum, the `PushConfig` `url`-required + truncated-`tokenFingerprint` rule backing `a2a-push-egress-ssrf`, the no-inline-inputs `additionalProperties:false` SR-1 check; plus capability-gated durable-`tasks/get`-after-disconnect and push-SSRF behavioral legs on `a2a.durableTasks` / `a2a.pushNotifications` via the `/v1/host/sample/a2a/tasks/*` seam). 2026-06-13 (RFCs 0096/0097/0098 — reviewable learning, standing goals, agent-platform portability) added three always-on-plus-gated scenarios: `proposal-reviewable-learning.test.ts` (RFC 0096 — the `agents.proposals` shape + the `Proposal` round-trip incl. the dropped `rule` kind + the content-free `proposal.{created,activated}` events, plus a gated apply-without-scope→403 leg; backs `proposal-inert-until-applied` + `proposal-no-resynthesis`), `goal-standing-continuation.test.ts` (RFC 0097 — the `agents.goals` shape + the `Goal` round-trip + the content-free `goal.{evaluated,closed}` events, plus gated bounded-termination→422 + judge-only-completion legs; backs `goal-continuation-bounded` + `goal-completion-judge-only`), and `export-bundle-portability.test.ts` (RFC 0098 — the `portability` shape incl. the `import⇒dryRun` if/then + the `ExportBundle` round-trip rejecting every credential-named field + the content-free `import.applied` event, plus a gated literal-credential-import→422 leg; backs `export-bundle-no-credential-material`). 2026-06-11 (RFCs 0093/0094 — protocol hardening + wire-shape reconciliation) added five: `version-fold.test.ts` (the `version-negotiation.md` §`X-Force-Engine-Version` cross-version matrix through the previously-orphaned `conformance-version-fold` fixture — closes catalog gap F5; soft-skips when `Capabilities.testing.forceEngineVersionRange` is unadvertised), `stream-text-fixture.test.ts` (the `stream-modes.md` §`messages` fold through the deterministic `stream-text` mock provider + the previously-orphaned `conformance-stream-text` fixture — closes catalog gap F1), `i18n-negotiation.test.ts` (gated on `capabilities.i18n` via `behaviorGate('openwop-i18n', …)` — an unsupported or malformed `Accept-Language` never 400s, `Content-Language` reflects the locale actually used, and error `code` strings stay the canonical English tokens), `grpc-transport.test.ts` (gated on `capabilities.grpc` via `behaviorGate('openwop-grpc-transport', …)` — advertisement-shape only per `grpc-transport.md` §Field semantics: `service` MUST be `openwop.v1.Engine`, the `tls` enum, `grpcs?://` endpoint URIs, `supportedTransports` includes `grpc` when exposed, production claimants require `tls: "required"`; no gRPC dialing), and `webhook-tenant-isolation.test.ts` (RFC 0093 §A.3 — backs the new protocol-tier `webhook-cross-tenant-isolation` invariant; a two-tenant proof through the `/v1/host/sample/test/surface` seam plus black-box registration-surface scoping). `spec-corpus-validity.test.ts` also gained the RFC 0094 §A satisfiability probe: canonical `createRun` bodies MUST pass the composed request schema (closed via `unevaluatedProperties: false` at the composition site, never inside an `allOf` branch) and an undeclared property MUST fail. 2026-06-07 (RFCs 0090/0091/0092 — verifier turn + convergence, multimodal perception input, agent capability requirements) added six: the always-on, server-free shape probes `agent-verifier-shape.test.ts`, `aiproviders-input-shape.test.ts`, `agent-requires-capabilities-shape.test.ts`, plus the capability-gated **behavioral** legs `agent-capability-degraded-projection.test.ts` (RFC 0092 §B — the `degraded[]` projection on `GET /v1/agents`, black-box, non-vacuous via `OPENWOP_DEGRADED_CAPABILITY_AGENT_ID`), `callai-multimodal.test.ts` (RFC 0091 §A/§B — advertised modality accepted / unadvertised → `unsupported_modality`, via the `POST /v1/host/sample/ai/call` seam), and `verifier-gating.test.ts` (RFC 0090 §B — a `fail` verdict blocks commit, via the `POST /v1/host/sample/agents/verify-run` seam). The three behavioral legs soft-skip by default and hard-fail under `OPENWOP_REQUIRE_BEHAVIOR=true` — the Active→Accepted reference-host proof for each RFC. 2026-06-02 (RFC 0082 §B — deployment channel resolve-and-pin, production-path coverage) added `agent-channel-dispatch.test.ts` (capability-gated on `agents.deployment.supported` + the seeded `conformance-agent-channel-dispatch` fixture + advertised `replay` mode via `behaviorGate('openwop-deployment-channel-dispatch', …)` — proves the §B pin from a REAL run graph, complementing `agent-deployment-lifecycle.test.ts` Leg 4's host-sample seam: a canonical `POST /v1/runs` of a node binding `agent.channel:"stable"` MUST record `resolvedChannel` + `resolvedAgentVersion` on `agent.invocation.started` (RFC 0077), a `:fork{mode:"replay"}` MUST re-read that recorded version, and the seam-guarded Leg 3 MOVES the channel then asserts a replay STILL carries the original pin — never re-resolving a moved channel; soft-skips by default, hard-fails under `OPENWOP_REQUIRE_BEHAVIOR=true` — the production-path proof of the §B contract). 2026-06-01 (RFC 0085 — `openwop-agent-platform` meta-profile, the Active→Accepted behavioral gate) added `agent-platform-aggregate-evidence.test.ts` (capability-gated on a host CLAIMING `openwop-agent-platform` in its live discovery `profiles[]` via `behaviorGate('openwop-agent-platform', …)` — the §C/§D honest-advertisement rule on the live `/.well-known/openwop`: the claim MUST satisfy the §B floor predicate (`isAgentPlatformPartial` → `partial`/`full`, never `none`), backed by the per-capability evidence not the profile string; `OPENWOP_AGENT_PLATFORM_TIER=full` forces the non-vacuous full bar — all governance terms + tenant installScope + all 16 §D terms; server-requiring, the always-on §B/§D derivation legs stay in `agent-platform-profile.test.ts` — the RFC 0085 → Accepted bar). 2026-06-01 (RFC 0084 — budget, quota + cost policy, the Active→Accepted behavioral gate) added `budget-enforcement.test.ts` (capability-gated on `budget.supported` via `behaviorGate('openwop-budget-enforcement', …)` — the §C/§D enforcement via the new `POST /v1/host/sample/budget/run` seam + the test event-log seam: a `hard-cost-exhaust` run emits the strict-ordered `budget.reserved → budget.consumed → budget.threshold.crossed{percent} → budget.exhausted → cap.breached{kind:"budget-cost"} → run.failed{error:"budget_exhausted"}` chain; a `model-denied` run is refused `budget_model_denied` BEFORE the provider call (fail-closed); an `advisory` host emits the `budget.*` events without stopping; every `budget.*` payload content-free backing `budget-no-pricing-leak`; new lib helper `src/lib/budgetPolicy.ts`; soft-skips on 404 — the RFC 0084 → Accepted bar). 2026-06-01 (RFC 0080 — agent memory capability reconciliation, the Active→Accepted behavioral gate) added `memory-degraded-projection.test.ts` (capability-gated on `agents.manifestRuntime.supported` + `memory.supported` via `behaviorGate('openwop-memory-degraded', …)` — the §C degraded-projection iff-contract on the NORMATIVE `GET /v1/agents`: a degraded inventory entry MUST carry `memoryDegraded:true` + a non-empty, unique `degradedMemoryDimensions[]` from the closed §A-name enum, a non-degraded entry MUST NOT, the inventory is non-empty, and the degraded branch runs non-vacuously when `OPENWOP_DEGRADED_AGENT_ID` names a known-degraded agent; black-box, no POST seam — the RFC 0080 → Accepted bar). This batch also documents the two RFC 0068 conformance seams (`POST /v1/host/sample/memory/consolidate` + `.../commitment/fire`) in `host-sample-test-seams.md` (the 0068 gated scenarios shipped in 1.14.0). 2026-06-01 (RFC 0034 — collector-side BYOK-canary inspection) added `otel-collector-canary-inspection.test.ts` (always-on server-free: stands up a real `OtelCollector`, POSTs synthetic OTLP/HTTP-JSON traces + metrics through its actual ingest path, and proves the new `findCanaryLeakage()` inspector catches a canary embedded in a span attribute / resource attribute / span name / metric data-point attribute while reporting ZERO hits on a redacted payload and never matching an empty canary — the non-vacuous proof that the conformance collector now inspects what the host's OTLP exporter ACTUALLY shipped over the wire, closing the `secret-leakage-otel-attribute` / `-debug-bundle-otel` collector-seam gap; the live capability-gated complement is the new collector-export describe block in `secret-leakage-otel-attribute.test.ts`). 2026-06-01 (RFC 0035 — sandbox wall-clock timeout, the 7th-of-8 graduation) added `sandbox-wasm-timeout.test.ts` (worker-driven server-free: `probeTimeout` in `wasm-sandbox-probe.ts` spawns a worker thread running the committed `misbehaving-timeout.wasm` + a main-thread kill-timer — the thread preemption a same-thread probe can't do — asserting `sandbox_timeout` with a well-behaved positive control; graduates `node-pack-sandbox-timeout` reference-impl→protocol, so 7 of 8 `node-pack-sandbox-*` invariants are now protocol-tier, only the JS-specific `no-eval` permanently exempt). 2026-05-31 (audit-response black-box / graduation batch) added three more: `sandbox-wasm-isolation.test.ts` (RFC 0035 — drives the committed `fixtures/wasm-sandbox/*.wasm` through `wasm-sandbox-probe.ts`: escape/capability-gate via static `WebAssembly.Module.imports()`, an OOB-store memory trap, double-instantiate isolation; 10/10; graduates 6 `node-pack-sandbox-*` invariants reference-impl→protocol), `workspace-cross-tenant-isolation-blackbox.test.ts` (RFC 0059 — two-credential black-box on the normative §C `/v1/host/workspace/files` endpoints: owner A writes, a second-tenant credential fails closed; no seam), and `prompt-resolution-chain-event.test.ts` (RFC 0029 — reads the durable `agent.promptResolved.chain[]` precedence record via the normative `GET /v1/runs/{runId}/events/poll`; no seam) — each the production-path proof that graduates its surface into the `openwop-core-standard` floor. 2026-05-31 (RFC 0088 — the `openwop-core-standard` Core Standard Profile, the audit-response Core Candidate target) added `core-standard-profile.test.ts` (always-on server-free derivation probe: `isCoreStandard` derives the §B floor — `openwop-core` ∧ `openwop-interrupts` ∧ (`openwop-stream-sse` ∨ `openwop-stream-poll`) — a bare `openwop-core` host without interrupts is excluded, a host with no event transport fails, and the annex is absent from `deriveProfiles` because it composes rather than redefines). 2026-05-31 (RFC 0082 — agent deployment lifecycle, the Active→Accepted behavioral gate) added `agent-deployment-lifecycle.test.ts` (capability-gated on `agents.deployment.supported` via `behaviorGate('openwop-deployment-lifecycle', …)` — the §E promotion contract via the new `POST /v1/host/sample/agents/deployment-transition` seam + the test event-log seam across four legs: `promote` (authorize RFC 0049 → approvalGate RFC 0051 → eval-verify RFC 0081 → content-free `deployment.promoted` with a seven-state `toState` + `toVersion`, the record validating `agent-deployment.schema.json`), `unauthorized` (fail-closed — `allowed:false`, no `deployment.promoted`, the behavioral leg of `deployment-promotion-fail-closed`), `eval-gate-unmet` (`eval_gate_unmet` denial, §E-3), and `channel-pin` (the §B `resolvedAgentVersion` recorded-fact on `agent.invocation.started`); new lib helper `src/lib/agentDeployment.ts`; soft-skips on 404 — the RFC 0082 → Accepted bar). 2026-05-31 (RFC 0081 — agent evaluation, the Active→Accepted behavioral gate) added `agent-eval-run.test.ts` (capability-gated on `agents.evalSuite.supported` via `behaviorGate('openwop-eval-run', …)` — the §B `mode:"eval"` projection via the new `POST /v1/host/sample/agents/eval-run` seam + the test event-log seam: `eval.started`-first → one `eval.scored` per task → `eval.completed`-once ordering (count == `eval.completed.taskCount`), the content-free `eval.scored` legs (`score` ∈ 0..1) backing `eval-summary-no-content-leak`, and the NORMATIVE `GET /v1/runs/{runId}/eval-summary` schema-valid `EvalSummary` round-trip with `passedCount <= taskCount`; new lib helper `src/lib/agentEval.ts`; soft-skips on 404 — the RFC 0081 → Accepted bar). 2026-05-31 (RFC 0083 — durable trigger bridge, the Active→Accepted behavioral gate) added `trigger-bridge-delivery.test.ts` (profile-gated on `openwop-trigger-bridge` derived from the live discovery doc — the §C delivery model via the `POST /v1/host/sample/trigger-bridge/deliver` seam + the test event-log seam: dedup→effectively-once `trigger.delivery.attempted{delivered}` (§C-1), retry-exhaustion→`{dead-lettered}` + `trigger.subscription.state.changed{toState:dead-lettered}` (§C-2 + RFC 0053), and the delivered run's `run.started.causationId` == the delivery id (§C / RFC 0040); both `trigger.*` events content-free; the always-on shape stays in `trigger-bridge-shape.test.ts`; new lib helper `src/lib/triggerBridge.ts`). 2026-05-31 (RFC 0087 — agent org-chart, the Active→Accepted behavioral gate) added two capability-gated behavioral scenarios (both gated on `agents.orgChart.supported`, black-box on the normative `/v1/agents/org-chart` surface — no new POST seam): `agent-org-chart-scoping.test.ts` (the `GET /v1/agents/org-chart` tree-shape — departments form an acyclic `parentDepartmentId` tree, members reference `host:<id>` roster entries — + the §D responsibility roll-up via `GET /v1/agents/org-chart/{departmentId}` with a deduped `responsibilities[]` union + the RFC 0074 cross-tenant 404 via `OPENWOP_CROSS_TENANT_ORG_CHART_DEPARTMENT_ID`) and `org-position-no-authority-escalation.test.ts` (the behavioral leg of the protocol-tier invariant — the live org-chart wire carries NO authority-bearing field on any member/department/responsibility-view object; the structural leg stays always-on in `agent-org-chart-shape.test.ts`, and the deeper RFC 0049/0051 authority-invariance legs stay reference-impl tier per the `agent-manifest-runtime` no-host-hook precedent). 2026-05-31 (RFCs 0086 + 0077 — the Active→Accepted behavioral gate) added four capability-gated behavioral scenarios so a non-steward host can be mechanically certified non-vacuously under `OPENWOP_REQUIRE_BEHAVIOR=true`: `agent-roster-attribution.test.ts` (RFC 0086 §B/§C; gated on `agents.roster.supported` — the normative `GET /v1/agents/roster` read shape + `total==roster.length`, the §C `roster.run.initiated`-before-`agent.invocation.started` ordering, the content-free payload backing `roster-attribution-no-content`, the durable work-item `triggerSubscriptionId`, and the RFC 0074 cross-tenant 404 via `OPENWOP_CROSS_TENANT_ROSTER_ID`), `agent-live-invocation-bracket.test.ts` (RFC 0077 §E; gated on `agents.liveRuntime.supported` — `agent.invocation.started`-first / `agent.invocation.completed`-last bracket, matching `invocationId`, `source`/`outcome` closed enums, content-free), `agent-live-structured-output.test.ts` (RFC 0077 §B step 6; gated on `agents.liveRuntime.structuredOutput` — a result violating `handoff.returnSchemaRef` fails the invocation `outcome:"failed"` rather than shipping as completed), and `agent-live-allowlist-enforced.test.ts` (RFC 0077 §F-1 / RFC 0002 §A14; gated on `agents.liveRuntime.supported` — a tool outside `toolAllowlist` is not callable); all four drive the documented `POST /v1/host/sample/roster/fire` + `POST /v1/host/sample/agents/live-invoke` seams plus the test event-log seam and soft-skip on 404 (these are the RFC 0086 / 0077 Active→Accepted bars). 2026-05-30 (RFC 0087 — agent org-chart, Draft -> Active) added `agent-org-chart-shape.test.ts` (always-on server-free: the `capabilities.agents.orgChart` shape + the `AgentOrgChart` round-trip + the non-`host:` member negative + the **§B structural non-authority guarantee** — the schema rejects a `scopes`/`canDispatch`/`permissions`/`authority` field on a member (`additionalProperties:false`), and a member's key set is exactly `{rosterId, departmentId, roleId, reportsTo}` — backing the protocol-tier `org-position-no-authority-escalation` invariant; no new RunEventType). 2026-05-30 (RFC 0086 — standing agent roster, Draft -> Active) added `agent-roster-shape.test.ts` (always-on server-free: the `capabilities.agents.roster` shape + the `AgentRosterEntry` round-trip + the `host:` `rosterId` + `agentRef` version-XOR-channel negatives + the content-free `roster.run.initiated` negatives backing the protocol-tier `roster-attribution-no-content` invariant + the additive `roster` inventory projection + RunEventType-enum membership). 2026-05-30 (RFC 0082 — agent deployment lifecycle, Draft -> Active) added `agent-deployment-shape.test.ts` (always-on server-free: the `capabilities.agents.deployment` shape + the `AgentDeployment` record round-trip + the `AgentRef` `channel` XOR `version` `not`-clause + the four `deployment.*` payloads + the content-free negatives backing the protocol-tier `deployment-event-no-content-leak` invariant). 2026-05-30 (RFC 0085 — `openwop-agent-platform` meta-profile, Draft -> Active) added `agent-platform-profile.test.ts` (always-on server-free derivation of the operational-annex `none`/`partial`/`full` status: all-floor ⇒ partial, missing-flag ⇒ none, the replay-OR-`nondeterminismPolicy.declared` term, floor+governance ⇒ full, missing-tenant-scope ⇒ partial-not-full per the honest-advertisement rule, eval/deploy/budget-are-advisory-not-hard-terms, + the `capabilities.nondeterminismPolicy.declared` shape). 2026-05-30 (RFC 0084 — budget, quota + cost policy, Draft -> Active) added `budget-policy-shape.test.ts` (always-on server-free: `budget-policy.schema.json` round-trip + the §A orthogonality guard — a wall-time field is rejected (it's RFC 0058's `runTimeoutMs`) — + threshold/onExhaustion negatives + the four content-free `budget.{reserved,consumed,threshold.crossed,exhausted}` payloads + the four `cap.breached{budget-*}` kinds + RunEventType-enum membership + the no-pricing-property structural check backing the protocol-tier `budget-no-pricing-leak` invariant + the `capabilities.budget`/`limits.maxBudget*` shape). 2026-05-30 (RFC 0083 — durable trigger + channel bridge, Draft -> Active) added `trigger-bridge-shape.test.ts` (always-on server-free: `trigger-subscription.schema.json` round-trip + missing-`state`/out-of-enum-`source`/unknown-property negatives + the four-state vocab + the two content-free `trigger.{subscription.state.changed,delivery.attempted}` payloads incl. closed `state`/`outcome` enums + RunEventType-enum membership + the `triggerBridge`/`webhooks.durable` capability shape + the `openwop-trigger-bridge` profile derivation incl. the no-dead-letter-sink negative). 2026-05-30 (RFC 0079 — credential provenance + egress policy, Draft -> Active) added `egress-provenance-shape.test.ts` (always-on server-free: `credential-provenance.schema.json` round-trip + `audiences:[]`/missing-`credentialId`/unknown-property negatives + the no-secret-property structural check backing the protocol-tier `egress-decision-no-secret-leak` invariant + the content-free `egress.decided` record incl. the `decision` enum + RunEventType-enum membership + the `httpClient.egressPolicy` shape; the behavioral `egress-credential-audience-bound` confused-deputy MUST is reference-impl tier, deferred to a host). 2026-05-30 (RFC 0078 — portable tool catalog, Draft -> Active) added `tool-descriptor-shape.test.ts` (always-on server-free: `tool-descriptor.schema.json` round-trip + the §C-1 `exec` ⇒ `host-extension` cross-field MUST (RFC 0069) + the `safetyTier`-required negative + `additionalProperties:false`, the `capabilities.toolCatalog` `supported`/`sources`/`sessionLifecycle` shape, and the two content-free `tool.session.{opened,closed}` payload $defs incl. the closed `outcome` enum + RunEventType-enum membership). 2026-05-30 (RFC 0080 — agent memory capability reconciliation, Draft -> Active) added `memory-capability-model-shape.test.ts` (always-on server-free: the additive `capabilities.memory.{writable,search,retention}` dimension shapes + malformed-instance negatives — `retention.ttl` non-boolean, out-of-enum `search.modes`, unknown property under `additionalProperties:false` — the `agent-inventory-response` `memoryDegraded`/`degradedMemoryDimensions` closed-enum fields, and the `openwop-memory` derivation surfacing for read/write + long-term hosts while withholding from `writable:false`). 2026-05-30 (RFC 0081 — agent evaluation, Draft -> Active) added `agent-eval-suite-shape.test.ts` (always-on server-free: the `capabilities.agents.evalSuite` shape + the `AgentEvalSuite`/`EvalSummary` schema round-trips + the three `eval.{started,scored,completed}` payloads + the content-free negatives — a task entry with a `taskOutput` body, a `safetyFinding` with an `excerpt` — backing the new `eval-summary-no-content-leak` SECURITY invariant). 2026-05-29 (RFC 0076 §B — `ctx.http.safeFetch` live-run audit) added `safefetch-live-audit.test.ts` (`behaviorGate('openwop-safefetch-live-audit', …)`, gated on `httpClient.safeFetch` + `toolHooks.prePostEvents`) — asserts the audit-when-both MUST against the **durable run event log** via the new `POST /v1/host/sample/http/safe-fetch-run` open seam + the test event-log seam, closing the seam-vs-production gap (a production `createSafeFetch()` with no audit hooks passes the inline `safefetch-behavior.test.ts` but FAILS this under `OPENWOP_REQUIRE_BEHAVIOR=true`); this is the RFC 0076 §B → Accepted bar; run seam soft-skips on 404 (host-pending). 2026-05-29 (RFC 0066 — `x-openwop-form` picker UX hints, Draft → Active) added `x-openwop-form-pack-manifest.test.ts` (always-on server-free: an annotated `configSchema` stays a valid 2020-12 schema + the advisory hints don't change what it accepts, each §A annotation matches the shape, an unknown `kind` validates for forward-compat, 3 negatives — missing/non-string `kind`, non-string `dependsOn`). 2026-05-29 (RFC 0076 §B — `ctx.http.safeFetch`) added `safefetch-behavior.test.ts` (seam-gated: SSRF block / DNS-rebinding / `Connection: upgrade` refusal / tool-hooks audit-when-both, via `POST /v1/host/sample/http/safe-fetch`; advertisement contract stays in `http-client-ssrf.test.ts`). 2026-05-29 (RFC 0076 §A — pack `runtime.requires[]` install gate) added two: `runtime-requires-shape.test.ts` (server-free closed-vocabulary validation — the 8 tokens validate, a raw builtin name is rejected, empty-array≡omission, `uniqueItems`) + `runtime-requires-install-gate.test.ts` (seam-gated install-grant / install-refuse → `pack_runtime_requirement_unmet` / non-sandbox SHOULD-projection, soft-skip on 404 via `POST /v1/host/sample/packs/install-gate`). 2026-05-29 (RFC 0047 — `host.oauth` authorization-code roundtrip) added `oauth-authorization-code-roundtrip.test.ts` — capability-gated on `capabilities.oauth.supported` + `grants` including `authorization_code`; drives the `POST /v1/host/sample/oauth/authorize-code-roundtrip` seam against the one canonical synthetic provider in `fixtures/oauth-providers/synthetic.json` (soft-skip on 404, Tier-2 host-pending), asserting a successful grant returns a credential REFERENCE (token persisted as a `host.credentials` entry) and that the authorization code / state / PKCE verifier / acquired access+refresh tokens never appear on any run-visible surface (RFC 0047 §C + §C.2 / `credential-payload-redaction`). Closes the RFC 0047 Tier-2 gap (capability-shape + redaction scenarios existed; the actual authorization-code dance was unexercised). 2026-05-26 (RFC 0070 — agent-manifest runtime) added `agent-manifest-runtime.test.ts`; 2026-05-26 (RFC 0071 — artifact-type + chat card packs) added six: `artifact-type-pack-manifest-validation.test.ts` + `artifact-schema-compile-bounded.test.ts` (server-free) + `artifact-type-pack-install.test.ts` + `artifact-type-store-without-render.test.ts` + `chat-card-pack-manifest-validation.test.ts` (server-free) + `chat-card-pack-execution.test.ts` (capability-gated, host-pending). 2026-05-26 (RFCs 0067 / 0068 / 0069 — spec-gap Draft cohort) added five scenarios: `byok-auth-modes.test.ts` (RFC 0067; always-on schema-shape of `aiProviders.authModes` + a discovery-gated §B auth-mode-contract cross-field check), `memory-consolidation-shape.test.ts` (RFC 0068; always-on shape of `agents.memoryConsolidation`/`agents.commitments` + the `agent.memory.consolidated`/`commitment.fired` payload $defs), `memory-consolidation-idempotent.test.ts` + `commitment-fired.test.ts` (RFC 0068; capability-gated behavioral, soft-skip on the documented `/v1/host/sample/memory/consolidate` + `/commitment/fire` seams), and `exec-not-protocol-tier.test.ts` (RFC 0069; always-on server-free structural assertion that the protocol corpus defines no `core.*`/`openwop.*` exec-class primitive — backs the `exec-must-not-be-protocol-tier` SECURITY invariant). 2026-05-25 (RFC 0061 — stateful agent-loop lifecycle, executionModel.version 5) added four `agent-loop-*.test.ts` scenarios: `-version5-shape` (always-on; validates `executionModel.statefulResume`/`transcriptWindow` + the 1–5 version ceiling) plus `-iteration-monotonic` (gated on `version >= 5`; `runOrchestrator.decided.iteration` increments 1,2,3… exactly once per turn), `-workspace-snapshot` (gated additionally on `host.workspace.supported`; a turn-i workspace write is invisible to turn i, visible to turn i+1), and `-stateful-resume` (gated on `statefulResume`; a mid-loop suspend resumes at the same iteration without resetting the counter) — the three behavioral scenarios drive the documented agent-loop seam (`POST /v1/host/sample/agentloop/run`) and soft-skip until a host wires it. 2026-05-25 (RFC 0059 — host.workspace M2, reference-host enforcement) added two `workspace-*.test.ts` scenarios: `-behavior` (capability-gated CRUD round-trip / `If-Match` 409 `workspace_conflict` / `workspace_too_large` / §D run-start snapshot, all via the real `/v1/host/workspace/files` §C endpoints) and `-cross-tenant-isolation` (WCT-1 — drives the documented `POST /v1/host/sample/workspace/op` seam to assert a file owned by one `{tenant, workspace}` is unreadable, on both `get` and `list`, under a different owner; backs the new `workspace-cross-tenant-isolation` SECURITY invariant). The in-memory reference host now advertises `capabilities.workspace.supported` and honors §C/§D/§E end-to-end. 2026-05-25 (RFC 0062 — memory.distillation "dreams") added five `distillation-*.test.ts` scenarios: `-shape` (always-on; validates the `capabilities.memory.distillation` block + the additive `distillation` sub-object on `memory.compacted`) plus `-token-budget` (within budget `tokensUsed ≤ tokenBudget`; an un-meetable budget → `token_budget_exceeded` with no partial archive), `-stable-archive` (same sources + budget ⇒ byte-stable archive checksum), `-index-roundtrip` (gated additionally on `indexEmitted`; the `MEMORY-INDEX.json` workspace file is retrievable + `workspace.updated` fired), and `-secret-carryforward` (SR-1: a redacted source secret never appears in the archive) — the four behavioral scenarios drive the documented memory-distillation seam (`POST /v1/host/sample/memory/distill`) and soft-skip until a host wires it. 2026-05-25 (RFC 0063 — core.subWorkflow.outputAttestation) added four `subrun-*.test.ts` scenarios: `-attestation-shape` (always-on; validates the `capabilities.agents.subRunAttestation` flag) plus `-checksum-stable` (the child output checksum is the byte-stable, key-order-invariant RFC 8785 JCS + SHA-256 digest), `-approval-gate` (`requireApproval` → `accept` merges, `reject` does not), and `-approval-fail-closed` (no `accept`/`edit-accept` → no merge; backs the deferred `subrun-merge-approval-fail-closed` invariant) — the three behavioral scenarios drive the documented sub-run attestation seam (`POST /v1/host/sample/subrun/attest`) and soft-skip until a host wires it. 2026-05-25 (RFC 0064 — host.toolHooks) added five `tool-hooks-*.test.ts` scenarios: `-shape` (always-on; validates the `capabilities.toolHooks` block + the optional content-free fields on `agentToolCalled` / `agentToolReturned`) plus `-content-free` (gated on `prePostEvents`), `-authorization-fail-closed` (gated on `perToolAuthorization`), `-rate-limit` (gated on `perToolRateLimit`), and `-secret-redaction` (gated on `prePostEvents` + the SR-1 `argsHash` redaction rule) — the four behavioral scenarios drive the documented tool-hooks invoke seam (`POST /v1/host/sample/toolhooks/invoke`) and soft-skip until a host wires it. 2026-05-25 (RFC 0060 — host.heartbeat) added four `heartbeat-*.test.ts` scenarios: `-capability-shape` (always-on; validates the `capabilities.heartbeat` block) plus `-fires-once-per-tick`, `-idempotent-no-spam`, and `-runtime-bound` (gated on `capabilities.heartbeat.supported` + the host heartbeat tick seam; soft-skip until a host wires it). 2026-05-25 (RFC 0057 — memory write-attribution) added five `memory-attribution-*.test.ts` scenarios: `-shape` (always-on advertisement check on `capabilities.memory.attribution`), plus `-no-content`, `-tenant-scoped`, `-emits-on-write`, and `-replay-stable` (gated on `capabilities.memory.attribution.emitsWriteEvents`) verifying the content-free `memory.written` RunEvent, its two SECURITY invariants (`memory-attribution-no-content` + `memory-attribution-tenant-scoped`), and the §D replay rule that a `replay`-mode fork MUST NOT regenerate `memoryId`. 2026-05-25 (RFC 0025 §C point 1 — test-catalog isolation invariant; pairs with the 25 publish-error scenarios in `pack-registry-publish.test.ts`) added `pack-registry-isolation.test.ts` — capability-gated on `capabilities.packs.testMode.{supported, isolated}: true`; PUTs a disposable pack into `/v1/packs-test/{name}` and asserts the same `(name, version)` does NOT appear via `GET /v1/packs/{name}` — anchors the test-catalog isolation MUST in RFC 0025 §C. 2026-05-25 (RFC 0028 Tier-2 post-promotion T2 — read-side sister scenario for workspace-membership enforcement) added `prompt-read-workspace-membership-enforced.test.ts` — gates on `capabilities.prompts.supported: true` (broader than `mutableLibrary` so read-only hosts that expose `?workspaceId=` are also probed); drives `GET /v1/prompts?workspaceId=<random-non-member>` and interprets the response: 4xx PASS (canonical envelope check on 403); 200 with empty `templates[]` PASS (correct null result for a nonexistent workspace); 200 with non-empty `templates[]` FAIL (cross-tenant leak); 200 without `templates[]` field SKIP (host doesn't expose workspace-scoped reads). Verifies SECURITY invariant `prompt-read-workspace-membership-enforced`. Same-day T1 strengthened `prompt-mutation-workspace-membership-enforced.test.ts` to pin `error === "workspace_membership_required"` when the host's refusal status is 403 (other refusal codes unconstrained). 2026-05-25 (RFC 0028 Tier-2 follow-up — workspace-membership enforcement on mutating prompt endpoints, filed in response to a self-disclosed adopter vulnerability) added `prompt-mutation-workspace-membership-enforced.test.ts` — capability-gated on `capabilities.prompts.mutableLibrary: true`; drives `POST /v1/prompts` with a cryptographically-random non-member `workspaceId` and asserts the host refuses (NOT a 2xx; any 4xx/5xx is acceptable — silent success is the failure mode). Verifies SECURITY invariant `prompt-mutation-workspace-membership-enforced`. 2026-05-22 (RFC 0034 §B follow-up — secret-leakage harness against the OTel + debug-bundle seams) added `secret-leakage-otel-attribute.test.ts` — gates on `capabilities.secrets.supported` + `capabilities.observability.testSeams.{otelScrape,debugBundleExport}` AND the `OPENWOP_CANARY_SECRET_VALUE` env (host operator + conformance runner agree on the canary). Drives the existing `openwop-smoke-byok-roundtrip` fixture end-to-end; scrapes both seams after run completion; hard-fails if the canary plaintext appears in any OTel span attribute or debug-bundle field. Verifies SECURITY invariants `secret-leakage-otel-attribute` + `secret-leakage-debug-bundle-otel`. 2026-05-22 (RFC 0041 Phase 4 — replay determinism under nondeterministic models) added three scenarios: `replay-divergence-at-refusal.test.ts` (advertisement-shape probe on `replayDeterminism.refusalDivergenceEmission` + 2 `it.todo` for the dual-direction refusal-divergence case), `replay-observable-sequence-determinism.test.ts` (capability-gated; behavioral assertion soft-skipped until a `conformance-phase4-nondet-tool` fixture ships), `replay-llm-cache-key-portable.test.ts` (intra-host reproducibility + non-recipe-field invariance + Phase 4 advertisement alignment — reuses the existing `POST /v1/host/sample/test/llm-cache-key` seam from the sibling `replay-llm-cache-key.test.ts`). 2026-05-20 (RFC 0027 §A templateKinds-coverage follow-up — paired with `prompt-end-to-end-events.test.ts`) added `prompt-all-four-kinds-events.test.ts` exercising all four `PromptKind` values (`system`, `user`, `schema-hint`, `few-shot`) end-to-end through the reference workflow-engine sample's `local.sample.demo.mock-ai` dispatch path; capability-gated via `behaviorGate('prompts-supported', ...)`. Closes the credibility gap where the host advertised `templateKinds: ["system", "user", "few-shot", "schema-hint"]` but only the system+user pair was actually wired into dispatch. 2026-05-20 (RFCs 0030–0033 — envelope LLM-contract-hardening track) added 15 scenarios across four `Active` RFCs: `envelope-reasoning-shape.test.ts` (RFC 0030, always-on; asserts the OPTIONAL `reasoning` property on the three universal-kind schemas + the `schema.response` deliberate omission), `envelope-reasoning-secret-redaction.test.ts` (RFC 0030, capability-gated on `capabilities.envelopes.reasoning.supported` + `secrets.supported`; 5 `it.todo()` placeholders for SECURITY invariant `envelope-reasoning-secret-redaction`), `envelope-tier-one-subset-static.test.ts` (RFC 0030, always-on for load-bearing rules — no `oneOf` / `allOf` / `not` / `prefixItems` / `propertyNames` anywhere; gated on `tierOneSubsetCompliance: "strict"` for OpenAI-strict-only constraints), `envelope-variant-discriminator-static.test.ts` (RFC 0031, always-on; asserts no `oneOf` + every `anyOf` branch declares a single-string-enum discriminator in `required` on every `schemas/envelopes/*.schema.json`), `model-capability-substituted.test.ts` (RFC 0031, advertisement-shape probe on `capabilities.modelCapabilities.advertised[]` identifier pattern + 5 `it.todo()` placeholders for SECURITY invariant `model-capability-substituted-no-credential-disclosure`), `model-capability-insufficient.test.ts` (RFC 0031, 6 `it.todo()` placeholders for refusal + no-recursive-fallback), `node-module-required-capabilities-shape.test.ts` (RFC 0031 SHOULD-tier authoring-convention; 4 `it.todo()` placeholders), and the six envelope-reliability events from RFC 0032 (`envelope-retry-attempted` carrying the shared advertisement-shape probe enforcing both MUST-tier events in `events[]` per RFC 0032 §C, plus `envelope-retry-exhausted`, `envelope-refusal-shape`, `envelope-truncated`, `envelope-nl-to-format-engaged`, `envelope-recovery-applied` — collectively 39 `it.todo()` placeholders covering retry/refusal/truncation/recovery + SECURITY invariants `envelope-refusal-no-prompt-leak` and `envelope-recovery-no-content-leak`), plus RFC 0033's two scenarios (`envelope-completion-distinguishes-truncation.test.ts` + `envelope-truncation-cap-exhaustion.test.ts` — 12 `it.todo()` placeholders covering the truncation-vs-schema-violation retry-routing distinction + the DoS-bound assertion). Reference workflow-engine sample advertises `capabilities.envelopes.reasoning: { supported: true, promptDirective: "off" }` + `tierOneSubsetCompliance: "warn"` honestly (schemas accept the field; host doesn't yet inject the directive); the other three RFCs' capability blocks defer to reference-host emission code per the staged RFC 0027 §G precedent. 2026-05-20 (RFC 0028 §B Phase B — prompt-pack boot-time install) added `prompt-pack-install.test.ts` (capability-gated on `capabilities.prompts.endpointsSupported: true`; asserts a host that ran the boot-time pack loader surfaces ≥ 1 pack-source template under `GET /v1/prompts?source=pack` carrying the canonical `meta.source: "pack"` + `meta.packName` + `meta.packVersion` stamps; positively identifies the in-tree `vendor.openwop.prompt-sample` reference pack's `writer-system` template when present). Pairs with the new `host/promptPackLoader.ts` boot-time entry on the reference workflow-engine sample, which scans `examples/packs/*` plus `OPENWOP_PROMPT_PACKS_DIR` and calls `installPackTemplates()` for each `kind: "prompt"` pack found. 2026-05-20 (RFC 0029 Phase C — prompt resolution chain wire shape) added three more scenarios: `prompt-resolution-chain-node-wins.test.ts` (capability-gated on `capabilities.prompts.supported: true`; asserts layer-1 node-config supersedes lower layers per `spec/v1/prompts.md` §"Resolution chain (normative)"), `prompt-resolution-chain-agent-intrinsic.test.ts` (additionally gated on `capabilities.prompts.agentBindings: true`; asserts agent intrinsic `systemPromptRef` wins over `promptOverrides` AND lower layers when the node has no layer-1 ref), `prompt-resolution-chain-fallback-cascade.test.ts` (asserts layer 3 workflow-defaults wins over layer 4 host-defaults; layer 4 host-defaults wins when 1-3 yield null; resolved is null when all four yield null but chain[] still lists every attempted layer). The scenarios drive the host's `POST /v1/host/sample/prompt/resolve` test seam (reference-host implementation deferred to follow-up slice per RFC 0021 staging precedent). 2026-05-20 (RFC 0027 Phase A — prompt templates wire shape) added three scenarios: `prompt-template-shape.test.ts` (always-on; Ajv compileability + positive/negative round-trip for PromptTemplate + PromptRef + PromptKind), `prompt-composed-secret-redaction.test.ts` (capability-gated on `capabilities.prompts.supported: true` + `observability: "full"`; asserts `[REDACTED:<secretId>]` markers in `prompt.composed` payloads for `source: "secret"` variable bindings per SECURITY/threat-model-secret-leakage.md §SR-1), `prompt-composed-trust-marker.test.ts` (same capability gates; asserts `<UNTRUSTED>...</UNTRUSTED>` wrapping + `contentTrust: "untrusted"` propagation per RFC 0020 §D). Paired with new `fixtures/prompt-templates/` sub-directory + per-fixture schema-validity describe block + future SECURITY invariants `prompt-composed-secret-redaction` and `prompt-composed-trust-marker` (lands alongside reference-host emission per RFC 0021 staging precedent). 2026-05-18 (RFC 0022 `Draft` — runtime variable mapping) added four `it.todo()` placeholder scenarios covering the new mapping surfaces on `core.dispatch` (§A — `dispatch-input-mapping.test.ts`, `dispatch-output-mapping.test.ts`, `dispatch-cross-worker-handoff.test.ts`) and `core.subWorkflow` (§B — `subworkflow-input-mapping.test.ts`). Gated on `capabilities.agents.dispatchMapping` (dispatch trio) and `capabilities.subWorkflow.inputMapping` (subWorkflow). Promote to live assertions when RFC 0022 reaches `Active` + a reference host advertises the matching flags. 2026-05-17 (RFC 0003 §D handoff-schema enforcement, HV-1) added `agentPackHandoffSchemaValidation.test.ts` — verifies the host validates dispatch payloads against `handoff.taskSchemaRef` AND return payloads against `handoff.returnSchemaRef` per RFC 0003 §D. Paired with the new `agent-pack-handoff-schema-enforcement` row in `SECURITY/invariants.yaml`. 2026-05-17 (AI Envelope gap-closure, DRAFT v1.x — `spec/v1/ai-envelope.md`) added 7 advertisement-shape scenarios with `it.todo()` behavioral placeholders gated on `capabilities.envelopeContracts.advertised: true`: `aiEnvelope.universalKinds.test.ts`, `aiEnvelope.schemaDrift.test.ts`, `aiEnvelope.correlationReplay.test.ts`, `aiEnvelope.contractRefusal.test.ts`, `aiEnvelope.trustBoundaryPropagation.test.ts`, `aiEnvelope.redaction.test.ts`, `aiEnvelope.capBreached.test.ts`. Paired with the new `envelope-redaction-sr-1-carry-forward` row in `SECURITY/invariants.yaml`. 2026-05-17 (post-publish hardening, deep audit of `core.openwop.agents`) added `agents-run-tool-allowlist.test.ts` — server-free scenario locking in the `core.openwop.agents@1.0.1` safety-fix that closes `OPENWOP-AUDIT-2026-003` (function-typed `tool.handler` properties rejected at `validateTools()` with `INVALID_TOOL_DECLARATION`; tool-driven runs require `ctx.agentRuntime`; tool-less safe fallback preserved). Paired with the new `agents-run-no-raw-handler` row in `SECURITY/invariants.yaml`. Same-day post-publish hardening added `idempotency-key-determinism.test.ts` — server-free scenario locking in the `core.openwop.http@1.1.2` determinism safety-fix (default `composite` mode produces deterministic keys in `(runId, nodeId, payload)`; removed `uuid` mode rejects with `CONFIG_INVALID`; cross-impl vector test lets third-party reimplementations verify wire agreement). Paired with the new `idempotency-key-deterministic` row in `SECURITY/invariants.yaml`. 2026-05-17 (Phase 3 of RFC 0013) added three server-free scenarios exercising the reference workflow-chain expansion library (`conformance/src/lib/workflow-chain-expansion.ts`): `workflow-chain-expansion.test.ts` (parameter substitution + node id collision avoidance + edge rewriting + capability propagation + runtime-invariance contract), `workflow-chain-unresolvable-typeid.test.ts` (rejection with `chain_unresolvable_typeid` when a chain references an unknown typeId), and `workflow-chain-pack-signature-verification.test.ts` (Ed25519 verification recipe reuse from `node-packs.md §Signing`). Earlier that day (Phase 1) added `workflow-chain-pack-manifest-validation.test.ts` — server-free schema-validation scenario covering the new `workflow-chain-pack-manifest.schema.json` (positive sample + two negatives: kind/contents mismatch and invalid `chainId`). Closes RFC 0013 (`Workflow-chain packs`, `Draft`) Phases 1 + 3 alongside the new `spec/v1/workflow-chain-packs.md`, the `Capabilities.workflowChainPacks` block, and the registry build-index/conformance-check `kind` routing from Phase 2. Earlier that day, the suite added 27 `it.todo()` placeholder scenarios paired with RFCs 0014-0020 (host capability surfaces — fs, kvStorage, tableStorage, queueBus, sql/vector/search, blob/cache, mcp.serverMount). These promote to live assertions when each RFC reaches `Active` + the matching capability block lands in `schemas/capabilities.schema.json` + a reference host advertises the capability. Earlier additions include 18 Multi-Agent Shift scenarios (Phases 1-5) added 2026-05-10, the `registry-public.test.ts` public-registry healthcheck added 2026-05-11 (opt-in via `OPENWOP_TEST_PUBLIC_REGISTRY=true`), the `replay-llm-cache-key.test.ts` placeholder added 2026-05-11 (three `it.todo()` cases for the cross-host LLM cache-key recipe per `replay.md` §"LLM cache-key recipe"), the two `production-*.test.ts` scenarios added 2026-05-11 for the `openwop-production` profile per RFC 0009 (`production-backpressure.test.ts`, `production-retention-expiry.test.ts`), the four `auth-*.test.ts` scenarios added 2026-05-11/12 for the production-auth profiles per RFC 0010 (`auth-api-key-rotation.test.ts`, `auth-oauth2-client-credentials.test.ts`, `auth-oidc-user-bearer.test.ts`, `auth-mtls.test.ts` (opt-in via `OPENWOP_TEST_MTLS=1`)), `replay-retention-expiry.test.ts` added 2026-05-12 (capability shape + 410/422 envelope per `replay.md` §"Retention and garbage collection"), `bulk-cancel.test.ts` added 2026-05-12 (Phase B close-out of R1 — `POST /v1/runs:bulk-cancel`), the two Phase H launch-blocker advertisement-contract scenarios added 2026-05-12 (`mcp-toolcall-redaction.test.ts` for the MCP-1 invariant per `host-capabilities.md §host.mcp` + `threat-model-prompt-injection.md §UNTRUSTED`, and `http-client-ssrf.test.ts` for the SSRF + body-size cap advertisement contract on `capabilities.httpClient`), the `wasm-pack-abi-version-rejection.test.ts` Track 7 scenario added 2026-05-12 for the ABI-mismatch positive path via the `vendor.openwop.misbehaving-abi` pack per RFC 0008 §H, the `otel-trace-propagation-subworkflow.test.ts` Track 11 close-out added 2026-05-13 (parent + child run spans share the inbound traceparent's traceId across the `core.subWorkflow` dispatch boundary), and the three RFC 0012 (Memory Compaction Profile, `Active`) scenarios added 2026-05-13/14: `memory-compaction-sr1-carry-forward.test.ts` (load-bearing SR-1 §D), `memory-compaction-event-emitted.test.ts` (canonical §B payload shape), and `memory-compaction-provenance-tag.test.ts` (soft assertion on §C `compacted-from:<id>` convention). All three gate on `capabilities.memory.compaction.supported` + the host's test seam at `/v1/test/memory/{seed,compact}` (Postgres reference host enables both via `OPENWOP_MEMORY_COMPACTION=true OPENWOP_TEST_TRIGGER_COMPACTION=true`). 2026-05-15 (gap-closure CF-3) added `interrupt-token-matrix.test.ts` (malformed / unknown / replay / cross-run-id paths on `GET|POST /v1/interrupts/{token}`). 2026-05-31 (RFC 0078 portable tool catalog + RFC 0079 credential provenance / egress policy — the Active→Accepted behavioral gate) added four: `tool-catalog-projection.test.ts` (capability-gated on `toolCatalog.supported` via `behaviorGate('openwop-tool-catalog', …)` — the NORMATIVE `GET /v1/tools` list with each `ToolDescriptor` schema-valid + `source`/`safetyTier` in the closed vocab + content-free, `GET /v1/tools/{toolId}` round-trip + unknown-id 404, 401-unauthenticated, and the §F-2 cross-principal non-disclosure; black-box, no POST seam), `tool-session-lifecycle.test.ts` (gated on `toolCatalog.sessionLifecycle` — the §D `tool.session.opened`-before / `tool.session.closed`-after bracket over the RFC 0064 call events via the `POST /v1/host/sample/tools/session-run` seam, one shared `sessionId`, content-free), `egress-audience-binding.test.ts` (KEYSTONE — gated on `httpClient.egressPolicy.supported`; the §C confused-deputy MUST via `POST /v1/host/sample/egress/decide`: an out-of-audience egress is denied/downgraded with the credential NOT attached, a provenance-unevaluable egress fails closed — the behavioral leg of `egress-credential-audience-bound`), and `egress-decision-content-free.test.ts` (the SR-1 canary — the credential value never surfaces in `egress.decided` and `reason` stays in the CLOSED vocabulary). The maintained scenario-to-spec map lives in [`coverage.md`](./coverage.md); this README keeps the operator quickstart and the historical scenario notes below. 2026-08-08 (RFC 0142 — store-gated emission witness, additive, suite `1.65.0 → 1.66.0`) added one: `artifact-type-store-emission.test.ts` (leg A always-on server-free: `artifactCreated` REQUIRES `artifactType`; leg B behavioral, applicable only to hosts advertising `store: true` at either scope: a real run via the `runproduce` seam, asserting `artifact.created` on the standard events-poll wire with the bound type and `registered:true`. `store` absent ⇒ inapplicable in both modes — the facet is optional; advertised-without-seam fails strict. Stub-measured: silent and wrong-type emitters both red). 2026-08-08 (RFC 0141 — legacy artifact-type identifiers, additive, suite `1.64.0 → 1.65.0`) added one: `artifact-type-legacy-ids.test.ts` (always-on server-free prose-pinning — a bare legacy id is rejected by the manifest schema while a canonical id validates, and the corpus states normatively that legacy ids were never wire-conformant with no grandfather clause, that a migrating host MUST NOT rewrite historical `artifact.created.artifactType` values, that the read-side alias is permanent and MUST resolve where validation is decided, and that an alias map is a host shim, not a conformance claim. Host-side alias behaviour is witnessed at openwop-app, not by this suite; a rewritten log is undetectable after the fact). 2026-08-07 (RFC 0139 — host-side witness for pack-manifest extension opacity, additive, suite `1.63.0 → 1.64.0`) added one: `pack-manifest-extension-opacity.test.ts` (gated on `behaviorGate` — the host-side half RFC 0138 could not provide. The load-bearing leg is DIFFERENTIAL, not presence: install the same manifest with and without an unrecognized `vendor.conformance.*` extension and require the registration projection to be identical once extensions are stripped. Sink-agnostic, because a suite cannot enumerate a host's sinks. Measured against stub hosts — a violating stub that routes an unrecognized extension into a derived facet PASSES the presence legs and fails only the differential ones. Witnesses INSTALL-TIME sinks only; does not witness `artifact.created` (RFC 0138 G8) since this seam emits no run events. Landed with the G14 flip: `artifact-type-pack-install`, `artifact-type-store-without-render` and `chat-card-pack-execution` moved from bare `return` to `behaviorGate`, so advertised-with-no-seam now FAILS under `OPENWOP_REQUIRE_BEHAVIOR=true` instead of reporting green). 2026-08-06 (RFC 0138 — vendor-extension hatch on pack manifests, additive, suite `1.62.0 → 1.63.0`) added one: `pack-manifest-extensions.test.ts` (always-on server-free — every pack manifest root admits the `^(x-|vendor\.)` hatch, enumerated against an explicit in-scope count of 9 rather than a naming glob, because the first draft globbed `*-pack-manifest.schema.json` and silently skipped `frontend-plugin-manifest.schema.json`; the hatch stays NARROW — a misspelled canonical field is still rejected and no pattern anywhere matches a bare canonical-looking key; and the corpus states the MUST-ignore, the "ignore means ignore" definition, the pack-authored/untrusted framing, and the not-a-capability-channel rule normatively, since the schema alone cannot express "MUST ignore". Host-side honoring of MUST-ignore is NOT covered — that needs a host-sample seam behind `behaviorGate`, gaps G6/G7). 2026-08-05 (RFC 0137 — the behavioral half, suite `1.60.1 → 1.61.0`) added one: `form-content-instantiation.test.ts` (capability-gated on `host.forms.contentPacks` + the `POST /v1/host/sample/formcontent/instantiate` seam — instantiation goes through the host's NORMAL create path with no pack-bound routing destination, an unrecognized `vendor.*`/`x-` field type DEGRADES to a plain text input rather than failing, and pack-authored fields stay fully editable. Added because RFC 0137's original graduation gate was unsatisfiable: every leg it shipped was server-free and passed identically against a host that never implemented it). 2026-08-05 (RFC 0137 — form-content packs, additive, suite `1.58.0 → 1.59.0`) added one: `form-content-packs.test.ts` (always-on server-free corpus legs — the registry version manifest carries `kind: "form-content"`, the `templates` payload property AND the load-bearing `anyOf` payload branch; the new source manifest enforces the schema-discipline floor and rejects `email`/`textarea` as field types, `key` in place of `id`, an integer `templates[].version`, and any `runtime`; and — the regression guard that matters — `fields[].type` is asserted byte-identical to chat-card `inputs[].type` so neither declarative kind's field vocabulary can be widened alone. The host-side instantiation + trust-boundary behavior is capability-gated on `host.forms.contentPacks` and host-pending). 2026-07-23 (RFC 0135 — workflow-chain gallery visibility, additive, suite `1.57.0 → 1.58.0`) added one: `workflow-chain-internal-flag.test.ts` (always-on server-free corpus legs — the manifest §WorkflowChain carries a boolean `internal`, an `internal: true` chain validates and a non-boolean is rejected, and the spec pins the MUST-omit-from-default-gallery + not-an-authorization-boundary rules; the gallery-omission behavior is witnessed at the reference host, not over the wire). 2026-07-23 (RFC 0134 — edge-condition `truthy`/`falsy` operators, additive) added one: `edge-condition-truthy-falsy.test.ts` (always-on corpus legs — the `workflow-definition` + inlined manifest `§EdgeCondition` `type` enums carry `truthy`/`falsy`, a no-`right` truthy/falsy edge validates, the spec documents the no-`right`+required-`left` semantics — plus a capability-gated host-mapping leg that soft-skips until a reference host maps the operators). 2026-07-22 (RFC 0133 — workflow-chain composition, suite `1.55.1 → 1.56.0`) added five: three always-on server-free scenarios (`chain-subchain-sibling.test.ts` — sub-chain co-registration mints a deterministic child id + rewrites `config.subChainRef` → the child `config.workflowId` + dedups a doubly-referenced child; `chain-subchain-cycle-rejected.test.ts` — the public witness for `sub-chain-expansion-bounded`: self-composition AND a depth-bound breach both reject with `sub_chain_cycle`, an acyclic tree within the bound expands, an unresolvable ref is `sub_chain_unresolved`; `chain-produced-var-roundtrip.test.ts` — `producedVariables` emit into `variables[]` with no value + closed-world `variable_undeclared` rejection) plus two capability-gated scenarios (`chain-subchain-fanout.test.ts` — a `core.dispatch` child-run over a `subChainRef` worker + the manifest `not`-guard on a concrete `config.workflowId`, behavioral home of `sub-chain-child-tenant-scoped`; `chain-subchain-unsupported-refused.test.ts` — an unsupported host refuses a `subChains`-bearing chain with `sub_chain_unsupported` (422), never flattening) that soft-skip until a reference host wires runtime child dispatch. 2026-07-22 (RFC 0132 — anonymous-actor authorization) added six: `anonymous-actor-shape.test.ts` (always-on, server-free — validates the `capabilities.anonymousActor` advert + the §B.2 `writeEgressControls`-iff-`bounded-write-egress` conditional + `owner.principalKind` + the RFC 0049 `authorization.decided` audit reuse) plus five capability-gated behavioral scenarios (`anonymous-actor-default-deny`, `-no-secret-reach`, `-egress-guarded`, `-write-gated`, `-audit-opaque`) that drive the `/v1/host/sample/anon-surface/{tools,dispatch}` seam and soft-skip until a host wires a tool-enabled public surface — each the public witness for a reference-impl-tier SECURITY invariant that graduates to protocol tier once a host passes it non-vacuously. 2026-07-07 (RFC 0131 — agent-manifest `role` + the Skill profile) added `agent-manifest-role-profile.test.ts` (always-on, server-free schema-shape probe of the additive optional `AgentManifest.role` + the schema-encoded Skill profile: a `role:"skill"` manifest with `handoff` + scratchpad-only memory validates; one declaring `conversation`/`longTerm` memory or omitting `handoff` FAILS validation — a malformed-manifest reject, NOT an RFC 0072 `degraded[]` runtime tier; an absent `role` with any `memoryShape` validates unconstrained; a bad enum value fails — the public witness for `agent-skill-profile-stateless`). 2026-07-06 (RFC 0129 — data-residency, suite `1.53.1 → 1.54.0`) added `data-residency-admission.test.ts` (always-on `capabilities.dataResidency` + `residency.schema.json` shape probes + `residency_unavailable` error-registration check; plus capability-gated behavioral legs driving the NORMATIVE `POST /v1/runs` endpoint — an advertised region MUST NOT be rejected `residency_unavailable`, an unadvertised region MUST be rejected with that code at HTTP one-of 400/404/422 and create no run — advertise-only-what-you-honor, soft-skip until a host advertises `dataResidency`). 2026-07-06 (RFC 0127 + RFC 0128 — CDP Track-2, suite `1.52.0 → 1.53.0`) added `trigger-stream-cdc-sources.test.ts` (always-on schema probes for the `stream`/`change` TriggerEvent sub-objects — `op` REQUIRED negative, exactly-one rule, registration + capabilities vocabulary pins — plus capability-gated behavioral legs driving the existing `/v1/host/sample/trigger-bridge/ingest` + `/deliver` seams: schema-valid delivered envelopes, SR-1 content-free durable events with a body canary, `(topic,partition,offset)` dedup effectively-once) and `purpose-propagation.test.ts` (always-on `permittedPurposes` + `capabilities.purposePropagation` family shape probes, plus the capability-gated two-hop legs via the new `POST /v1/host/sample/purpose-propagation/forward` seam: onward label ⊆ received, derived-output ⊆ intersection of labelled inputs, unlabelled adds no constraint, `[]` fail-closed dropped with an unlabelled positive control). Both behavioral suites soft-skip pre-implementation and become REQUIRED once the host advertises the surface (advertise-only-what-you-honor). 2026-07-05 (RFC 0013 erratum A-lite — bundle + load the sample-pack fixture, suite `1.51.0 → 1.52.0`) bundled the `vendor.openwop.workflow-chain-sample` pack into the conformance package at `fixtures/pack-manifests/workflow-chain-sample.pack.json` (host-syncable, ships in `files`) and refactored `workflow-chain-host-expansion.test.ts` to **load** it + derive the expected expansion from the `expandChain()` reference library instead of hardcoding — so a live host serving `POST /v1/host/sample/workflow-chain:expand` is checked against the spec algorithm for the identical published pack (closes the RFC 0013 host-expansion witness's fixture gap; the seam still soft-skips until a host advertises `workflowChainPacks.hostExpansionSeam`). `fixtures-valid.test.ts` now schema-selects pack-manifest fixtures by `kind` (node-pack vs workflow-chain-pack). No scenario-file count change. 2026-07-05 (RFC 0013 erratum — host-expansion test seam decouple, suite `1.50.0 → 1.51.0`) re-gated `workflow-chain-host-expansion.test.ts` from the semantic `workflowChainPacks.supported` claim onto a new OPTIONAL `workflowChainPacks.hostExpansionSeam` test-harness sub-flag (no scenario-file count change), so a host advertising `workflowChainPacks.supported` / RFC 0124 `deferredParameters.supported` is no longer conscripted into the never-bundled `vendor.openwop.workflow-chain-sample` seam under `OPENWOP_REQUIRE_BEHAVIOR` — the semantic claim rides the server-free `workflow-chain-expansion.test.ts` legs, RFC 0124's deferred path its own `/chain/deferred-expand` seam. 2026-07-04 (RFC 0124 — portable per-run parameter deferral, suite `1.49.0 → 1.50.0`) added `workflow-chain-deferred-parameters.test.ts` (always-on, server-free legs against the reference `expandChainDeferred` in `conformance/src/lib/workflow-chain-expansion.ts`: non-sensitive deferral materializes `variables[]` with `defaultValue`+`type` and leaves ZERO `{{params.*}}` tokens (R3), a whole-value input token → variable-sourced PortValue, the bare param name is the auto-generated `configurableSchema` override key (R6); §Security legs: a `x-openwop-sensitive` prompt-body param materializes `source:"secret"` with the plaintext appearing NOWHERE — not bagged — a sensitive whole-value `node.input` fails closed `sensitive_param_not_deferrable` (422), a sensitive param on a host without `secrets` support fails closed, and a host without a `prompts.variable` source falls back to expansion-time (G5); plus schema-surface legs pinning the amended `source:"secret"` wording in the manifest schema + the `credentialRef` per-run supply shape; capability-gated host legs over `POST /v1/host/sample/chain/deferred-expand` for the bare-param override / `:fork` replay / `contentTrust:"untrusted"` fence / `[REDACTED]` sensitive compose, soft-skip 404/403). 2026-07-04 (RFC 0126 — data-parallel dispatch per-item input, suite `1.48.0 → 1.49.0`) added `dispatch-per-item-input.test.ts` (always-on, server-free schema legs on `orchestrator-decision.schema.json` §NextWorkerDecision: a well-formed index-aligned `nextWorkerInputs` validates, a decision omitting it stays valid (additive/back-compat), a non-object item and a non-array are rejected, a mis-named `perItemInputs` is rejected by `additionalProperties:false` (the fail-closed rail for pre-RFC-0126 strict validators), and a length-mismatch is ADMITTED at the wire because `nextWorkerInputs.length == nextWorkerIds.length` is not JSON-Schema-expressible — a host runtime MUST; capability-gated behavioral legs over `POST /v1/host/sample/dispatch/per-item` asserting a host advertising `capabilities.dispatch.perItemInput` projects `nextWorkerInputs[i]` into child `i` (per-item value wins over `inputMapping`), a length-mismatch fails with a `validation_error` dispatching no child, and a host NOT advertising the capability fails closed on a non-empty `nextWorkerInputs` rather than silently dropping it and dispatching N identical children; soft-skips on 404/403). 2026-07-02 (RFC 0122 — self-hosted runner, suite `1.47.0 → 1.48.0`) added `self-hosted-runner.test.ts` (always-on schema legs for the `selfHostedRunner` capability block + the dispatch/result/registration frame shapes; an advertisement-gated block-shape leg; capability-gated behavioral legs over `POST /v1/host/sample/runner/{register,dispatch}` asserting subject-first isolation, retriable `runner_unavailable`, and at-most-once dedup — the public test for the protocol-tier `runner-credential-non-transit` + `runner-output-untrusted-transport` invariants; soft-skips on 404). 2026-07-01 (RFC 0121 — subscription-reuse provider auth mode, suite `1.46.0 → 1.47.0`) added `aiproviders-subscription-scope.test.ts` (always-on schema leg: the `aiProviders.authModes` closed enum includes `subscription`; §B.7 advertisement-gated leg: a `subscription` provider MUST appear in `byok`; §B.8 bind-seam-gated leg over `POST /v1/host/sample/credentials/bind` asserting a tenant-scope binding is rejected with `credential_scope_forbidden` — the public test for the protocol-tier `subscription-credential-user-scope-only` invariant. §B.8 is gated on the seam rather than on advertisement, so a host that cannot lawfully advertise `subscription` can still witness the user-scope safety rail; soft-skips when the seam is unwired). 2026-06-29 (RFC 0120 — connection-pack `apiHosts` credential-egress allow-list, suite `1.45.0 → 1.46.0`) added `connection-pack-apihosts.test.ts` (always-on schema legs: the `connection-pack-apihosts-valid` fixture validates, an `openapi`-reach provider omitting `apiHosts` is rejected by the conditional-MUST `allOf`, and IP/wildcard/port/single-label/uppercase entries are each rejected; always-on matching-rule legs: the item-10 dot-anchored eTLD+1 suffix-containment rule permits subdomains + a tighter exact host and fails closed with no substring/suffix/prefix escape — the public tests for the protocol-tier `connection-pack-api-host-shape` + `connection-pack-egress-host-bound` invariants; plus a capability-gated behavioral egress allow-list leg over the new `POST /v1/host/sample/connection-packs/egress-check` seam, soft-skipping when unadvertised/unwired). 2026-06-28 (RFC 0118 — parallel sub-workflow fan-out and join, suite `1.44.0 → 1.45.0`) added `dispatch-fanout-parallel.test.ts` (always-on schema legs for `dispatch-config.schema.json` — accepts a valid `parallel` config + each `joinPolicy.mode` + `maxConcurrency`, rejects unknown enum values / `additionalProperties` on `joinPolicy` / non-positive `maxConcurrency`, keeps a pre-RFC-0118 config valid — and the `dispatchFanOut`/`dispatchJoin` event `$defs` of `run-event-payloads.schema.json` — `fanOutPolicy` const `parallel`, `childCount ≥ 2`, the required replay-deterministic `mergeOrder`; capability-gated behavioral legs over `POST /v1/host/sample/dispatch/fanout` (wait-all/collect → `joinOutcome: satisfied` + full `children[]` + `mergeOrder`) plus the un-gated registration-rejection leg (`fanOutSupported:false` host MUST reject `parallel` with a 4xx); soft-skips on absent `dispatch.fanOutSupported` / `parallel` ∉ `fanOutPolicies`). 2026-06-27 (RFC 0117 — front-end plugin packs, suite `1.43.0 → 1.44.0`) added `frontend-plugin-packs.test.ts` (always-on schema legs for `frontend-plugin-manifest.schema.json` + the `ui-plugin/1` envelope `ui-plugin-message.schema.json`: manifest validity, `runtime`-forbidden, path-traversal-guarded `entry`, the closed `hostApi` allowlist, the version-token `artifact_conflict` + `currentVersion` concurrency shape, and no credential-bearing envelope field (`additionalProperties:false`); the capability-shape leg asserts `isolation` pins to the `cross-origin-iframe` const; capability-gated behavioral legs over `POST /v1/host/sample/ui-plugin/rpc` assert an undeclared method → `method_not_allowed` and a stale `artifact.write` → `artifact_conflict` with no persist; soft-skips on absent `capabilities.uiPlugins.supported` or `404`/`403` on the seam (RFC 0117 stays Active pending host witnesses); the public test for the protocol-tier `frontend-plugin-{isolation,egress,rpc-allowlist,no-byok}` invariants). 2026-06-26 (RFC 0116 — portable prompt-prefix cache, suite `1.42.0 → 1.43.0`) added `prompt-prefix-cache.test.ts` (advertisement-shape on `aiProviders.promptPrefixCache` + behavioral legs over the OPTIONAL `POST /v1/host/sample/ai/generate` seam (`host-sample-test-seams.md` §16): (a) outcome-invariance — a generate with `cachePrefixId` and a control without produce the same accepted envelope + identical `provider.usage.inputTokens`/`outputTokens` (cost-hint-only, replay-invariant); (b) cache-hit observable — a repeat generate shows `cacheReadTokens > 0`; (c) cross-tenant isolation — tenant B’s first use of tenant A’s `cachePrefixId` shows `cacheReadTokens == 0`, the public test for the protocol-tier `prompt-prefix-cache-cross-tenant-isolation` invariant (the host MUST key its provider cache by `(tenant, cachePrefixId)`, never global); (d) secret-free — the cost-only cache-token fields carry no prompt substrings (SR-1); soft-skips on absent `aiProviders.promptPrefixCache.supported` or `404`/`405` on the seam, since RFC 0116 defers reference-host impl as provider-gated). 2026-06-26 (RFC 0114 — A2UI surface deltas, suite `1.41.0 → 1.42.0`) added `a2ui-surface-delta-transport.test.ts` (always-on legs use a cast-free, dependency-free client-side RFC 6902 applier + Ajv2020 to assert: the new `a2ui-surface-delta-frame.schema.json` compiles, the op enum excludes `test`, a full surface + delta frames reconstruct the expected tree AND equal the full a non-negotiating subscriber materializes and re-validate against the closed catalog, an out-of-catalog/script-bearing delta fails closed-catalog validation post-patch — the `a2ui-surface-no-code-exec` boundary holds — and the recorded envelope is always the full surface; the HTTP leg is capability-gated on `a2uiSurface.deltaTransport` and soft-skips on absent host/capability or `404`/`405` on the OPTIONAL `GET /v1/host/sample/a2ui/surface/materialized` seam). 2026-06-26 (RFC 0111 — context economy, suite `1.40.0 → 1.41.0`) added `context-budget-transcript-bound.test.ts` (capability-gated on `multiAgent.executionModel.contextBudget.transcriptTokenBudget` being present via `behaviorGate(openwop-context-budget, …)` — drives the `conformance-context-budget-multiturn` orchestrator fixture, reads the host’s per-iteration accounting via the OPTIONAL seam `GET /v1/host/sample/agent/transcript-window?runId=…&iteration=N` (`host-sample-test-seams.md` §14), and asserts `tokenCount ≤ transcriptTokenBudget` in the advertised `tokenCounter` unit, that every `eventId` in the seam accounting is a real persisted run event (internal-consistency cross-check against `/v1/host/sample/test/runs/:runId/events`), recent-tail + no-double-count, every `summarizedRanges.summaryRef` has a matching `context.summarized` event, and `keepLastTurns` recent turns are fed verbatim — never inside a summarized range; soft-skips on `404`/`405` since the RFC defers reference-host impl) + `context-summarization-replay.test.ts` (capability-gated on `multiAgent.executionModel.contextBudget.summarization.supported` via `behaviorGate(openwop-context-summarization, …)` — replays the run via `:fork mode:replay` and asserts the recorded `context.summarized` → `summaryRef` records are REUSED, never re-summarized, the direct analogue of RFC 0041 envelope-refusal recovery; soft-skips when the event-log seam is unwired, no `replay` mode is advertised, or the run produced no summarization). 2026-06-26 (RFC 0113 — memory injection budget, suite `1.39.0 → 1.40.0`) added `memory-injection-budget.test.ts` (capability-gated on `memory.injectionBudget.supported === true` via `behaviorGate(openwop-memory-injection-budget, …)` — drives the `conformance-agent-memory-injection-budget` fixture through the host-sample memory seam and asserts the budgeted injection read's cumulative tokens ≤ the requested `tokenBudget` in the advertised `tokenCounter` unit (`o200k_base`/`cl100k_base`/`chars`/`host-defined`), an over-budget single entry is omitted not truncated, and re-asserts SR-1 (`[REDACTED:<secretId>]` content) + CTI-1 (cross-tenant probe returns empty) on the budgeted path; the `rank:'relevance'` leg DELEGATES to `memory.search` semantic (RFC 0080) and asserts relevance ordering differs from recency ONLY when the host ALSO advertises `memory.search` semantic, else it soft-skips — there is NO ranking primitive in `injectionBudget`; soft-skips on hosts that do not advertise `memory.injectionBudget`). 2026-06-26 (RFC 0112 — compact tool projection, suite `1.38.0 → 1.39.0`) added `tool-catalog-compact-projection.test.ts` (capability-gated on `toolCatalog.compactView === true` via `behaviorGate(openwop-tool-catalog-compact, …)` — drives `GET /v1/tools?view=compact` and asserts the host returns the `{ tools: CompactToolDescriptor[] }` envelope where every descriptor validates against `compact-tool-descriptor.schema.json` with the heavy `ToolDescriptor` fields dropped, every present `inputSchema` satisfies the self-contained compact structural subset (top-level `type:"object"`+`properties`; no `$ref`/`oneOf`/`allOf`/`anyOf`/`not`/`patternProperties`/`dependentSchemas`), and the compact `tools[]` `toolId` set EQUALS the standard view set for the same principal (projection completeness); soft-skips on hosts that do not advertise `toolCatalog.compactView`). 2026-06-26 (RFC 0115 — run transport economy, suite `1.37.0 → 1.38.0`) added `run-transport-economy.test.ts` (capability-gated on `restTransport.conditionalRunGet === true` and a non-empty `restTransport.contentEncodings` — drives `GET /v1/runs/{runId}` and asserts a sequence-derived strong `ETag` on the `200`, `If-None-Match` → `304` with an empty body while the run is unchanged, the `ETag` ROTATES after the `conformance-approval` fixture advances `waiting-approval → completed` (proving it derives from the latest persisted event-log sequence, not a coarser signal that would leave a `304` stale), and each advertised `Content-Encoding` (`gzip` baseline; `br`/`zstd` optional) round-trips byte-identically to the identity body; soft-skips on hosts that do not advertise `restTransport`). 2026-06-24 (RFC 0110 — channel presence, behavioral leg) added `channel-presence-behavioral.test.ts` (capability-gated on `channelPresence.supported` via `behaviorGate('openwop-channel-presence', …)` — drives the `POST /v1/host/sample/channel-presence/snapshot` seam and asserts a live `channel.presence` snapshot is the CLOSED `{conversationId,present,typing}` shape (no PII), every ref is an opaque RFC 0041 `user:`/`agent:` subject, `typing ⊆ present`, and the snapshotting member is non-vacuously present; soft-skips on 404/405 — a host whose presence is bound to a product flow witnesses via its own route test + an INTEROP-MATRIX row, the RFC 0086 dual-staging). 2026-06-24 (RFC 0110 — channel presence, Accept cycle) added `channel-presence-shape.test.ts` (always-on server-free — the OPTIONAL `channel.presence` ephemeral payload validates a conforming snapshot, REQUIRES `conversationId`+`present`, is CLOSED `additionalProperties:false` (the no-PII guard), `typing` optional; `channel.presence` is in the `RunEventType` enum; the `channelPresence` capability block is declared + closed). 2026-06-24 (RFC 0109 — conversation-turn model provenance, Accept cycle) added `conversation-turn-model-provenance-shape.test.ts` (always-on server-free — `agent.model` `{provider, model}` validates conforming / both-required / closed-SR-1 / optional-back-compat, + the `conversationTurnModelProvenance` capability declared + closed). 2026-06-24 (RFC 0108 — self-hosted / OpenAI-compatible provider class, Accept cycle, suite `1.36.0 → 1.37.0`) added the gated behavioral honesty leg `aiproviders-selfhosted-honesty.test.ts` (gated on `aiProviders.selfHosted.length > 0` via `behaviorGate('openwop-selfhosted-providers', …)` — drives `POST /v1/host/sample/ai/call` against an advertised `selfHosted` id and asserts **§A.2** the dispatch reaches a real configured endpoint (success or transport error — never `capability_not_provided` / `provider_not_supported`, which would prove a dishonest advertisement with no endpoint behind it) and **§D** the endpoint location — supplied out-of-band via `OPENWOP_TEST_COMPAT_ENDPOINT`, checked as the raw string + bare `host`/`host:port` — never appears in the seam response or error payload; soft-skips on 404 / when the env var is unset for the §D leg). 2026-06-24 (RFC 0108, suite `1.35.0 → 1.36.0`) added the always-on server-free shape leg `aiproviders-selfhosted-shape.test.ts` (the additive `aiProviders.selfHosted` advertisement: a `string[]` with `uniqueItems`/`minLength:1` items, absent from `aiProviders.required`, validates a conforming array via Ajv2020 while rejecting non-array / duplicate / empty-string forms, and enforces the two §A rules JSON Schema cannot express — §A.1 every `selfHosted` entry is a subset of `supported`, and §A.3 / `self-hosted-endpoint-no-disclosure` no entry is URL-shaped (`://`, bare `host:port`, or leading `/` path) — exercised against good/bad example docs). 2026-06-23 (RFC 0106 — real-time voice session profile, Accept cycle) added six gated behavioral scenarios driving the openwop-app live host (rev `00293-89w`): `voice-transcription-streaming` + `voice-transcription-unadvertised` (the `call-transcriber` seam; the latter gated-by-absence), `voice-synthesis-streaming` (the `stream:true` synthesis arm → metadata-only `voice.synthesis_chunk` events), `voice-bargein-no-partial-leak` (the `/voice/barge-in` seam — `voice.barge_in`→`voice.cancelled` with no chunk after; **graduated `voice-bargein-no-partial-leak` reference-impl→protocol** on the live proof), and `voice-interim-not-durable` + `voice-streamref-tenant-bound` (§F INV-1/INV-4; soft-skip on the §E `transcription_unsupported` / no-live-streamRef path — stay reference-impl until a host with a scripted-interim / live-streamRef arm proves them). 2026-06-23 (RFC 0107 — publishable declarative pack kinds) added one: `registry-declarative-kinds.test.ts` (always-on server-free — the registry version-manifest carries the `kind` discriminator + per-kind declarative payload, `runtime` is conditional on `kind` via `allOf if/then/else`, published artifact-type and connection manifests validate, and a declarative-with-`runtime` or node-without-`runtime` manifest is rejected). 2026-06-23 (RFC 0107 correction, suite `1.34.0 → 1.35.0`) extended that scenario with two cases — a published **chat-card** pack manifest (`kind: "card"`, RFC 0071) validates, and the never-canonical `kind: "chat-card"` is **rejected** — fixing a kind-string mismatch where RFC 0107's published schema enumerated `chat-card` while RFC 0071 (authoritative) defines `card` (no scenario-file count change; cases added to the existing file). 2026-06-23 (RFC 0106 — real-time voice session profile, Phase 2) added one: `voice-event-payloads-shape.test.ts` (always-on server-free — all seven `voice.*` types are in the `RunEventType` enum, each has a payload `$def` via `typeIndex`, `voice.transcript` REQUIRES `contentTrust:"untrusted"` (the schema-enforced half of `voice-transcript-untrusted`), `voice.synthesis_chunk` is metadata-shaped (seq+mimeType required; bytes by `url`/`streamRef`), and the content-free events reject unknown properties). Phase 2 also lands the `voice.*` payload `$defs` in `run-event-payloads.schema.json` + the `asyncapi.yaml` messages + the four §F `SECURITY/invariants.yaml` rows (1 protocol-tier `voice-transcript-untrusted` + 3 reference-impl behavioral, graduating at `Active → Accepted`). The gated behavioral legs (`voice-transcription-streaming`/`-unadvertised`, `voice-synthesis-streaming` + the three behavioral invariant scenarios) land with the reference host at `Active → Accepted`. 2026-06-23 (RFC 0106 — real-time voice session profile, Phase 1) added one: `aiproviders-realtimevoice-shape.test.ts` (always-on server-free — the `aiProviders.realtimeVoice` object advertisement: the four sub-flags `transcription`/`synthesis`/`turnDetection`/`bargeIn` are declared, `realtimeVoice` is absent from `aiProviders.required`, the `turnDetection`/`bargeIn ⇒ transcription` `dependentRequired` closure and the `synthesis ⇒ speechSynthesis` if/then closure hold via Ajv2020, and out-of-enum / boolean sub-flag values are rejected). The gated behavioral legs (`voice-transcription-streaming` / `-unadvertised`, `voice-synthesis-streaming`) and the four §F live-ingress invariant scenarios land in Phase 2 at the `Active → Accepted` cycle. 2026-06-22 (RFC 0101 — multi-party group conversation) added two — `multi-party-conversation-shape.test.ts` (always-on server-free — asserts the three additive RFC 0101 wire facts: a 3-agent council `conversation.opened` participant roster (instance ids) + a user opening turn validates, every `role: 'agent'` turn carrying a roster-instance `speakerId` validates while one OMITTING `speakerId` MUST FAIL schema validation (the `allOf`/`if role==='agent' then required:['speakerId']` conditional), a non-AgentRef participant item is rejected, the `capabilities.multiPartyConversation { supported, maxParticipants? }` block is declared + closed and rejects extras / `maxParticipants:1` / a missing `supported`, and the non-participant membership predicate is asserted server-free) and `multi-party-conversation-behavioral.test.ts` (capability-gated on `multiPartyConversation.supported` via `behaviorGate('openwop-multi-party-conversation', …)` — drives the conformance-only seam `POST /v1/host/sample/conversation/multi-party/{open,exchange}` (`host-sample-test-seams.md`, since RFC 0101 mints no normative client trigger to open a council): a 3-agent council opens and a roster-valid attributed agent turn is accepted, while a `role:'agent'` turn missing `speakerId`, a non-participant `speakerId`, and an over-`maxParticipants` open are each rejected with `error.code:'validation_error'` (status-tolerant 400/422 per RFC 0005 §E); soft-skips on 404/405 — reference impl: the postgres example host). 2026-06-20 (RFC 0105 — speech synthesis adapter) added three: `aiproviders-speechsynth-shape.test.ts` (always-on server-free — the `aiProviders.speechSynthesis` `const "supported"` flag is declared, absent from `aiProviders.required`, and a string-const advertisement validates while the object form `{supported:true}` is rejected), `speech-synthesis-roundtrip.test.ts` (gated on `aiProviders.speechSynthesis === "supported"` via `behaviorGate('openwop-speech-synthesis', …)` — an advertising host's `callSpeechSynthesizer` round-trip via the `POST /v1/host/sample/ai/call-speech-synthesizer` seam returns `audio` with EXACTLY ONE of `url`/`base64`, a non-empty `mimeType`, and the echoed `voiceId`; soft-skips on 404), and `speech-synthesis-unadvertised.test.ts` (gated-by-absence via `behaviorGate('openwop-speech-synthesis-unadvertised', …)` — a host NOT advertising `speechSynthesis` MUST reject the call with `speech_synthesis_unsupported`, never a silent no-op). 2026-06-19 (RFC 0104 — portable HITL approver routing) added one: `interrupt-approver-routing.test.ts` (server-free Ajv2020 — the `interrupt.approverRouting` capability block shape, the additive optionality of `approverGroupRefs` / `approverRoleRefs` / `audience` on the `ApprovalData` schema, the closed `audience` object, and the §"Portable approver routing" `notifyTargets` reference rule that `audience` DEFAULTS to the resolved eligibility union when omitted and OVERRIDES it when present; the capability-gated leg asserts an advertising host's `interrupt.approverRouting` is honest — `refKinds` ⊆ {group, role}, `audience` boolean — and soft-skips when the host does not advertise the capability). 2026-06-17 (RFC 0103 — localized content surface) added one: `localized-content-delivery.test.ts` (server-free Ajv2020 — the four content schemas + the §C `resolveSection` merge + §A capability coherence; the public test for `content-published-cache-no-draft` / `content-response-tenant-scoped` / `content-no-cross-tenant-enumeration`; the live legs gate on `capabilities.content.supported` and soft-skip without a `GET /v1/content/pages/{slug}` target). 2026-06-15 (RFC 0102 — A2UI agent-authored interface surfaces) added five: `a2ui-surface-shape.test.ts` (server-free Ajv2020 — the closed core `ui.a2ui-surface` payload validates, while an out-of-catalog component / extra script-bearing property / unenumerated `catalogVersion` / `action.target` outside `enum["resume","exchange"]` each fail; the structural half of `a2ui-action-confinement` and the enabling precondition for the render-side `a2ui-surface-no-code-exec` / `a2ui-surface-no-network-egress` reference-app probes), `a2ui-surface-degrades.test.ts` (the kind is optional/advertised, not a MUST-recognize universal kind, and an unadvertised kind is gated — N6 — never crashing the run), `a2ui-surface-version-refusal.test.ts` (the enumerated `catalogVersion` rejects an unadvertised version → `unknown_schema_version`, and the surface schema carries no external `$ref`), `a2ui-surface-replay.test.ts` (all `$ref`s internal so a stored surface `:fork`/replays deterministically; same-`correlationId` + divergent `type` → `envelope_correlation_conflict`), and `a2ui-untrusted-blocks-approval.test.ts` (a `meta.contentTrust:'untrusted'` surface is trust-gated and MUST NOT advance an approval interrupt — composition of `untrusted_content_blocks_approval`). The four behavioral legs soft-skip on 404 (host-pending; the `openwop-app` reference renderer is the render-side probe). 2026-06-14 (RFCs 0099/0100 — external-event trigger ingestion + async/durable A2A tasks) added one new scenario (`trigger-ingestion.test.ts`) and extended `a2a-task-roundtrip.test.ts` with the RFC 0100 async subtests: `trigger-ingestion.test.ts` (RFC 0099 — always-on `TriggerEvent` / `TriggerSubscriptionRegistration` schema legs incl. the §F.1 per-source one-of, the `AttachmentRef.ref`-only rule + raw-URL rejection backing `trigger-ingestion-ssrf`, and the content-free `trigger.delivery.attempted` shape backing `trigger-ingestion-content-redaction`; plus a capability-gated behavioral leg on `triggerBridge.ingestion` driving the `POST /v1/host/sample/trigger-bridge/ingest` seam for SSRF refusal + header-redaction), and the `a2a-task-roundtrip.test.ts` additions (RFC 0100 — always-on `A2ATaskState` + `capabilities.a2a` shape legs incl. the lowercase-hyphen state enum, the `PushConfig` `url`-required + truncated-`tokenFingerprint` rule backing `a2a-push-egress-ssrf`, the no-inline-inputs `additionalProperties:false` SR-1 check; plus capability-gated durable-`tasks/get`-after-disconnect and push-SSRF behavioral legs on `a2a.durableTasks` / `a2a.pushNotifications` via the `/v1/host/sample/a2a/tasks/*` seam). 2026-06-13 (RFCs 0096/0097/0098 — reviewable learning, standing goals, agent-platform portability) added three always-on-plus-gated scenarios: `proposal-reviewable-learning.test.ts` (RFC 0096 — the `agents.proposals` shape + the `Proposal` round-trip incl. the dropped `rule` kind + the content-free `proposal.{created,activated}` events, plus a gated apply-without-scope→403 leg; backs `proposal-inert-until-applied` + `proposal-no-resynthesis`), `goal-standing-continuation.test.ts` (RFC 0097 — the `agents.goals` shape + the `Goal` round-trip + the content-free `goal.{evaluated,closed}` events, plus gated bounded-termination→422 + judge-only-completion legs; backs `goal-continuation-bounded` + `goal-completion-judge-only`), and `export-bundle-portability.test.ts` (RFC 0098 — the `portability` shape incl. the `import⇒dryRun` if/then + the `ExportBundle` round-trip rejecting every credential-named field + the content-free `import.applied` event, plus a gated literal-credential-import→422 leg; backs `export-bundle-no-credential-material`). 2026-06-11 (RFCs 0093/0094 — protocol hardening + wire-shape reconciliation) added five: `version-fold.test.ts` (the `version-negotiation.md` §`X-Force-Engine-Version` cross-version matrix through the previously-orphaned `conformance-version-fold` fixture — closes catalog gap F5; soft-skips when `Capabilities.testing.forceEngineVersionRange` is unadvertised), `stream-text-fixture.test.ts` (the `stream-modes.md` §`messages` fold through the deterministic `stream-text` mock provider + the previously-orphaned `conformance-stream-text` fixture — closes catalog gap F1), `i18n-negotiation.test.ts` (gated on `capabilities.i18n` via `behaviorGate('openwop-i18n', …)` — an unsupported or malformed `Accept-Language` never 400s, `Content-Language` reflects the locale actually used, and error `code` strings stay the canonical English tokens), `grpc-transport.test.ts` (gated on `capabilities.grpc` via `behaviorGate('openwop-grpc-transport', …)` — advertisement-shape only per `grpc-transport.md` §Field semantics: `service` MUST be `openwop.v1.Engine`, the `tls` enum, `grpcs?://` endpoint URIs, `supportedTransports` includes `grpc` when exposed, production claimants require `tls: "required"`; no gRPC dialing), and `webhook-tenant-isolation.test.ts` (RFC 0093 §A.3 — backs the new protocol-tier `webhook-cross-tenant-isolation` invariant; a two-tenant proof through the `/v1/host/sample/test/surface` seam plus black-box registration-surface scoping). `spec-corpus-validity.test.ts` also gained the RFC 0094 §A satisfiability probe: canonical `createRun` bodies MUST pass the composed request schema (closed via `unevaluatedProperties: false` at the composition site, never inside an `allOf` branch) and an undeclared property MUST fail. 2026-06-07 (RFCs 0090/0091/0092 — verifier turn + convergence, multimodal perception input, agent capability requirements) added six: the always-on, server-free shape probes `agent-verifier-shape.test.ts`, `aiproviders-input-shape.test.ts`, `agent-requires-capabilities-shape.test.ts`, plus the capability-gated **behavioral** legs `agent-capability-degraded-projection.test.ts` (RFC 0092 §B — the `degraded[]` projection on `GET /v1/agents`, black-box, non-vacuous via `OPENWOP_DEGRADED_CAPABILITY_AGENT_ID`), `callai-multimodal.test.ts` (RFC 0091 §A/§B — advertised modality accepted / unadvertised → `unsupported_modality`, via the `POST /v1/host/sample/ai/call` seam), and `verifier-gating.test.ts` (RFC 0090 §B — a `fail` verdict blocks commit, via the `POST /v1/host/sample/agents/verify-run` seam). The three behavioral legs soft-skip by default and hard-fail under `OPENWOP_REQUIRE_BEHAVIOR=true` — the Active→Accepted reference-host proof for each RFC. 2026-06-02 (RFC 0082 §B — deployment channel resolve-and-pin, production-path coverage) added `agent-channel-dispatch.test.ts` (capability-gated on `agents.deployment.supported` + the seeded `conformance-agent-channel-dispatch` fixture + advertised `replay` mode via `behaviorGate('openwop-deployment-channel-dispatch', …)` — proves the §B pin from a REAL run graph, complementing `agent-deployment-lifecycle.test.ts` Leg 4's host-sample seam: a canonical `POST /v1/runs` of a node binding `agent.channel:"stable"` MUST record `resolvedChannel` + `resolvedAgentVersion` on `agent.invocation.started` (RFC 0077), a `:fork{mode:"replay"}` MUST re-read that recorded version, and the seam-guarded Leg 3 MOVES the channel then asserts a replay STILL carries the original pin — never re-resolving a moved channel; soft-skips by default, hard-fails under `OPENWOP_REQUIRE_BEHAVIOR=true` — the production-path proof of the §B contract). 2026-06-01 (RFC 0085 — `openwop-agent-platform` meta-profile, the Active→Accepted behavioral gate) added `agent-platform-aggregate-evidence.test.ts` (capability-gated on a host CLAIMING `openwop-agent-platform` in its live discovery `profiles[]` via `behaviorGate('openwop-agent-platform', …)` — the §C/§D honest-advertisement rule on the live `/.well-known/openwop`: the claim MUST satisfy the §B floor predicate (`isAgentPlatformPartial` → `partial`/`full`, never `none`), backed by the per-capability evidence not the profile string; `OPENWOP_AGENT_PLATFORM_TIER=full` forces the non-vacuous full bar — all governance terms + tenant installScope + all 16 §D terms; server-requiring, the always-on §B/§D derivation legs stay in `agent-platform-profile.test.ts` — the RFC 0085 → Accepted bar). 2026-06-01 (RFC 0084 — budget, quota + cost policy, the Active→Accepted behavioral gate) added `budget-enforcement.test.ts` (capability-gated on `budget.supported` via `behaviorGate('openwop-budget-enforcement', …)` — the §C/§D enforcement via the new `POST /v1/host/sample/budget/run` seam + the test event-log seam: a `hard-cost-exhaust` run emits the strict-ordered `budget.reserved → budget.consumed → budget.threshold.crossed{percent} → budget.exhausted → cap.breached{kind:"budget-cost"} → run.failed{error:"budget_exhausted"}` chain; a `model-denied` run is refused `budget_model_denied` BEFORE the provider call (fail-closed); an `advisory` host emits the `budget.*` events without stopping; every `budget.*` payload content-free backing `budget-no-pricing-leak`; new lib helper `src/lib/budgetPolicy.ts`; soft-skips on 404 — the RFC 0084 → Accepted bar). 2026-06-01 (RFC 0080 — agent memory capability reconciliation, the Active→Accepted behavioral gate) added `memory-degraded-projection.test.ts` (capability-gated on `agents.manifestRuntime.supported` + `memory.supported` via `behaviorGate('openwop-memory-degraded', …)` — the §C degraded-projection iff-contract on the NORMATIVE `GET /v1/agents`: a degraded inventory entry MUST carry `memoryDegraded:true` + a non-empty, unique `degradedMemoryDimensions[]` from the closed §A-name enum, a non-degraded entry MUST NOT, the inventory is non-empty, and the degraded branch runs non-vacuously when `OPENWOP_DEGRADED_AGENT_ID` names a known-degraded agent; black-box, no POST seam — the RFC 0080 → Accepted bar). This batch also documents the two RFC 0068 conformance seams (`POST /v1/host/sample/memory/consolidate` + `.../commitment/fire`) in `host-sample-test-seams.md` (the 0068 gated scenarios shipped in 1.14.0). 2026-06-01 (RFC 0034 — collector-side BYOK-canary inspection) added `otel-collector-canary-inspection.test.ts` (always-on server-free: stands up a real `OtelCollector`, POSTs synthetic OTLP/HTTP-JSON traces + metrics through its actual ingest path, and proves the new `findCanaryLeakage()` inspector catches a canary embedded in a span attribute / resource attribute / span name / metric data-point attribute while reporting ZERO hits on a redacted payload and never matching an empty canary — the non-vacuous proof that the conformance collector now inspects what the host's OTLP exporter ACTUALLY shipped over the wire, closing the `secret-leakage-otel-attribute` / `-debug-bundle-otel` collector-seam gap; the live capability-gated complement is the new collector-export describe block in `secret-leakage-otel-attribute.test.ts`). 2026-06-01 (RFC 0035 — sandbox wall-clock timeout, the 7th-of-8 graduation) added `sandbox-wasm-timeout.test.ts` (worker-driven server-free: `probeTimeout` in `wasm-sandbox-probe.ts` spawns a worker thread running the committed `misbehaving-timeout.wasm` + a main-thread kill-timer — the thread preemption a same-thread probe can't do — asserting `sandbox_timeout` with a well-behaved positive control; graduates `node-pack-sandbox-timeout` reference-impl→protocol, so 7 of 8 `node-pack-sandbox-*` invariants are now protocol-tier, only the JS-specific `no-eval` permanently exempt). 2026-05-31 (audit-response black-box / graduation batch) added three more: `sandbox-wasm-isolation.test.ts` (RFC 0035 — drives the committed `fixtures/wasm-sandbox/*.wasm` through `wasm-sandbox-probe.ts`: escape/capability-gate via static `WebAssembly.Module.imports()`, an OOB-store memory trap, double-instantiate isolation; 10/10; graduates 6 `node-pack-sandbox-*` invariants reference-impl→protocol), `workspace-cross-tenant-isolation-blackbox.test.ts` (RFC 0059 — two-credential black-box on the normative §C `/v1/host/workspace/files` endpoints: owner A writes, a second-tenant credential fails closed; no seam), and `prompt-resolution-chain-event.test.ts` (RFC 0029 — reads the durable `agent.promptResolved.chain[]` precedence record via the normative `GET /v1/runs/{runId}/events/poll`; no seam) — each the production-path proof that graduates its surface into the `openwop-core-standard` floor. 2026-05-31 (RFC 0088 — the `openwop-core-standard` Core Standard Profile, the audit-response Core Candidate target) added `core-standard-profile.test.ts` (always-on server-free derivation probe: `isCoreStandard` derives the §B floor — `openwop-core` ∧ `openwop-interrupts` ∧ (`openwop-stream-sse` ∨ `openwop-stream-poll`) — a bare `openwop-core` host without interrupts is excluded, a host with no event transport fails, and the annex is absent from `deriveProfiles` because it composes rather than redefines). 2026-05-31 (RFC 0082 — agent deployment lifecycle, the Active→Accepted behavioral gate) added `agent-deployment-lifecycle.test.ts` (capability-gated on `agents.deployment.supported` via `behaviorGate('openwop-deployment-lifecycle', …)` — the §E promotion contract via the new `POST /v1/host/sample/agents/deployment-transition` seam + the test event-log seam across four legs: `promote` (authorize RFC 0049 → approvalGate RFC 0051 → eval-verify RFC 0081 → content-free `deployment.promoted` with a seven-state `toState` + `toVersion`, the record validating `agent-deployment.schema.json`), `unauthorized` (fail-closed — `allowed:false`, no `deployment.promoted`, the behavioral leg of `deployment-promotion-fail-closed`), `eval-gate-unmet` (`eval_gate_unmet` denial, §E-3), and `channel-pin` (the §B `resolvedAgentVersion` recorded-fact on `agent.invocation.started`); new lib helper `src/lib/agentDeployment.ts`; soft-skips on 404 — the RFC 0082 → Accepted bar). 2026-05-31 (RFC 0081 — agent evaluation, the Active→Accepted behavioral gate) added `agent-eval-run.test.ts` (capability-gated on `agents.evalSuite.supported` via `behaviorGate('openwop-eval-run', …)` — the §B `mode:"eval"` projection via the new `POST /v1/host/sample/agents/eval-run` seam + the test event-log seam: `eval.started`-first → one `eval.scored` per task → `eval.completed`-once ordering (count == `eval.completed.taskCount`), the content-free `eval.scored` legs (`score` ∈ 0..1) backing `eval-summary-no-content-leak`, and the NORMATIVE `GET /v1/runs/{runId}/eval-summary` schema-valid `EvalSummary` round-trip with `passedCount <= taskCount`; new lib helper `src/lib/agentEval.ts`; soft-skips on 404 — the RFC 0081 → Accepted bar). 2026-05-31 (RFC 0083 — durable trigger bridge, the Active→Accepted behavioral gate) added `trigger-bridge-delivery.test.ts` (profile-gated on `openwop-trigger-bridge` derived from the live discovery doc — the §C delivery model via the `POST /v1/host/sample/trigger-bridge/deliver` seam + the test event-log seam: dedup→effectively-once `trigger.delivery.attempted{delivered}` (§C-1), retry-exhaustion→`{dead-lettered}` + `trigger.subscription.state.changed{toState:dead-lettered}` (§C-2 + RFC 0053), and the delivered run's `run.started.causationId` == the delivery id (§C / RFC 0040); both `trigger.*` events content-free; the always-on shape stays in `trigger-bridge-shape.test.ts`; new lib helper `src/lib/triggerBridge.ts`). 2026-05-31 (RFC 0087 — agent org-chart, the Active→Accepted behavioral gate) added two capability-gated behavioral scenarios (both gated on `agents.orgChart.supported`, black-box on the normative `/v1/agents/org-chart` surface — no new POST seam): `agent-org-chart-scoping.test.ts` (the `GET /v1/agents/org-chart` tree-shape — departments form an acyclic `parentDepartmentId` tree, members reference `host:<id>` roster entries — + the §D responsibility roll-up via `GET /v1/agents/org-chart/{departmentId}` with a deduped `responsibilities[]` union + the RFC 0074 cross-tenant 404 via `OPENWOP_CROSS_TENANT_ORG_CHART_DEPARTMENT_ID`) and `org-position-no-authority-escalation.test.ts` (the behavioral leg of the protocol-tier invariant — the live org-chart wire carries NO authority-bearing field on any member/department/responsibility-view object; the structural leg stays always-on in `agent-org-chart-shape.test.ts`, and the deeper RFC 0049/0051 authority-invariance legs stay reference-impl tier per the `agent-manifest-runtime` no-host-hook precedent). 2026-05-31 (RFCs 0086 + 0077 — the Active→Accepted behavioral gate) added four capability-gated behavioral scenarios so a non-steward host can be mechanically certified non-vacuously under `OPENWOP_REQUIRE_BEHAVIOR=true`: `agent-roster-attribution.test.ts` (RFC 0086 §B/§C; gated on `agents.roster.supported` — the normative `GET /v1/agents/roster` read shape + `total==roster.length`, the §C `roster.run.initiated`-before-`agent.invocation.started` ordering, the content-free payload backing `roster-attribution-no-content`, the durable work-item `triggerSubscriptionId`, and the RFC 0074 cross-tenant 404 via `OPENWOP_CROSS_TENANT_ROSTER_ID`), `agent-live-invocation-bracket.test.ts` (RFC 0077 §E; gated on `agents.liveRuntime.supported` — `agent.invocation.started`-first / `agent.invocation.completed`-last bracket, matching `invocationId`, `source`/`outcome` closed enums, content-free), `agent-live-structured-output.test.ts` (RFC 0077 §B step 6; gated on `agents.liveRuntime.structuredOutput` — a result violating `handoff.returnSchemaRef` fails the invocation `outcome:"failed"` rather than shipping as completed), and `agent-live-allowlist-enforced.test.ts` (RFC 0077 §F-1 / RFC 0002 §A14; gated on `agents.liveRuntime.supported` — a tool outside `toolAllowlist` is not callable); all four drive the documented `POST /v1/host/sample/roster/fire` + `POST /v1/host/sample/agents/live-invoke` seams plus the test event-log seam and soft-skip on 404 (these are the RFC 0086 / 0077 Active→Accepted bars). 2026-05-30 (RFC 0087 — agent org-chart, Draft -> Active) added `agent-org-chart-shape.test.ts` (always-on server-free: the `capabilities.agents.orgChart` shape + the `AgentOrgChart` round-trip + the non-`host:` member negative + the **§B structural non-authority guarantee** — the schema rejects a `scopes`/`canDispatch`/`permissions`/`authority` field on a member (`additionalProperties:false`), and a member's key set is exactly `{rosterId, departmentId, roleId, reportsTo}` — backing the protocol-tier `org-position-no-authority-escalation` invariant; no new RunEventType). 2026-05-30 (RFC 0086 — standing agent roster, Draft -> Active) added `agent-roster-shape.test.ts` (always-on server-free: the `capabilities.agents.roster` shape + the `AgentRosterEntry` round-trip + the `host:` `rosterId` + `agentRef` version-XOR-channel negatives + the content-free `roster.run.initiated` negatives backing the protocol-tier `roster-attribution-no-content` invariant + the additive `roster` inventory projection + RunEventType-enum membership). 2026-05-30 (RFC 0082 — agent deployment lifecycle, Draft -> Active) added `agent-deployment-shape.test.ts` (always-on server-free: the `capabilities.agents.deployment` shape + the `AgentDeployment` record round-trip + the `AgentRef` `channel` XOR `version` `not`-clause + the four `deployment.*` payloads + the content-free negatives backing the protocol-tier `deployment-event-no-content-leak` invariant). 2026-05-30 (RFC 0085 — `openwop-agent-platform` meta-profile, Draft -> Active) added `agent-platform-profile.test.ts` (always-on server-free derivation of the operational-annex `none`/`partial`/`full` status: all-floor ⇒ partial, missing-flag ⇒ none, the replay-OR-`nondeterminismPolicy.declared` term, floor+governance ⇒ full, missing-tenant-scope ⇒ partial-not-full per the honest-advertisement rule, eval/deploy/budget-are-advisory-not-hard-terms, + the `capabilities.nondeterminismPolicy.declared` shape). 2026-05-30 (RFC 0084 — budget, quota + cost policy, Draft -> Active) added `budget-policy-shape.test.ts` (always-on server-free: `budget-policy.schema.json` round-trip + the §A orthogonality guard — a wall-time field is rejected (it's RFC 0058's `runTimeoutMs`) — + threshold/onExhaustion negatives + the four content-free `budget.{reserved,consumed,threshold.crossed,exhausted}` payloads + the four `cap.breached{budget-*}` kinds + RunEventType-enum membership + the no-pricing-property structural check backing the protocol-tier `budget-no-pricing-leak` invariant + the `capabilities.budget`/`limits.maxBudget*` shape). 2026-05-30 (RFC 0083 — durable trigger + channel bridge, Draft -> Active) added `trigger-bridge-shape.test.ts` (always-on server-free: `trigger-subscription.schema.json` round-trip + missing-`state`/out-of-enum-`source`/unknown-property negatives + the four-state vocab + the two content-free `trigger.{subscription.state.changed,delivery.attempted}` payloads incl. closed `state`/`outcome` enums + RunEventType-enum membership + the `triggerBridge`/`webhooks.durable` capability shape + the `openwop-trigger-bridge` profile derivation incl. the no-dead-letter-sink negative). 2026-05-30 (RFC 0079 — credential provenance + egress policy, Draft -> Active) added `egress-provenance-shape.test.ts` (always-on server-free: `credential-provenance.schema.json` round-trip + `audiences:[]`/missing-`credentialId`/unknown-property negatives + the no-secret-property structural check backing the protocol-tier `egress-decision-no-secret-leak` invariant + the content-free `egress.decided` record incl. the `decision` enum + RunEventType-enum membership + the `httpClient.egressPolicy` shape; the behavioral `egress-credential-audience-bound` confused-deputy MUST is reference-impl tier, deferred to a host). 2026-05-30 (RFC 0078 — portable tool catalog, Draft -> Active) added `tool-descriptor-shape.test.ts` (always-on server-free: `tool-descriptor.schema.json` round-trip + the §C-1 `exec` ⇒ `host-extension` cross-field MUST (RFC 0069) + the `safetyTier`-required negative + `additionalProperties:false`, the `capabilities.toolCatalog` `supported`/`sources`/`sessionLifecycle` shape, and the two content-free `tool.session.{opened,closed}` payload $defs incl. the closed `outcome` enum + RunEventType-enum membership). 2026-05-30 (RFC 0080 — agent memory capability reconciliation, Draft -> Active) added `memory-capability-model-shape.test.ts` (always-on server-free: the additive `capabilities.memory.{writable,search,retention}` dimension shapes + malformed-instance negatives — `retention.ttl` non-boolean, out-of-enum `search.modes`, unknown property under `additionalProperties:false` — the `agent-inventory-response` `memoryDegraded`/`degradedMemoryDimensions` closed-enum fields, and the `openwop-memory` derivation surfacing for read/write + long-term hosts while withholding from `writable:false`). 2026-05-30 (RFC 0081 — agent evaluation, Draft -> Active) added `agent-eval-suite-shape.test.ts` (always-on server-free: the `capabilities.agents.evalSuite` shape + the `AgentEvalSuite`/`EvalSummary` schema round-trips + the three `eval.{started,scored,completed}` payloads + the content-free negatives — a task entry with a `taskOutput` body, a `safetyFinding` with an `excerpt` — backing the new `eval-summary-no-content-leak` SECURITY invariant). 2026-05-29 (RFC 0076 §B — `ctx.http.safeFetch` live-run audit) added `safefetch-live-audit.test.ts` (`behaviorGate('openwop-safefetch-live-audit', …)`, gated on `httpClient.safeFetch` + `toolHooks.prePostEvents`) — asserts the audit-when-both MUST against the **durable run event log** via the new `POST /v1/host/sample/http/safe-fetch-run` open seam + the test event-log seam, closing the seam-vs-production gap (a production `createSafeFetch()` with no audit hooks passes the inline `safefetch-behavior.test.ts` but FAILS this under `OPENWOP_REQUIRE_BEHAVIOR=true`); this is the RFC 0076 §B → Accepted bar; run seam soft-skips on 404 (host-pending). 2026-05-29 (RFC 0066 — `x-openwop-form` picker UX hints, Draft → Active) added `x-openwop-form-pack-manifest.test.ts` (always-on server-free: an annotated `configSchema` stays a valid 2020-12 schema + the advisory hints don't change what it accepts, each §A annotation matches the shape, an unknown `kind` validates for forward-compat, 3 negatives — missing/non-string `kind`, non-string `dependsOn`). 2026-05-29 (RFC 0076 §B — `ctx.http.safeFetch`) added `safefetch-behavior.test.ts` (seam-gated: SSRF block / DNS-rebinding / `Connection: upgrade` refusal / tool-hooks audit-when-both, via `POST /v1/host/sample/http/safe-fetch`; advertisement contract stays in `http-client-ssrf.test.ts`). 2026-05-29 (RFC 0076 §A — pack `runtime.requires[]` install gate) added two: `runtime-requires-shape.test.ts` (server-free closed-vocabulary validation — the 8 tokens validate, a raw builtin name is rejected, empty-array≡omission, `uniqueItems`) + `runtime-requires-install-gate.test.ts` (seam-gated install-grant / install-refuse → `pack_runtime_requirement_unmet` / non-sandbox SHOULD-projection, soft-skip on 404 via `POST /v1/host/sample/packs/install-gate`). 2026-05-29 (RFC 0047 — `host.oauth` authorization-code roundtrip) added `oauth-authorization-code-roundtrip.test.ts` — capability-gated on `capabilities.oauth.supported` + `grants` including `authorization_code`; drives the `POST /v1/host/sample/oauth/authorize-code-roundtrip` seam against the one canonical synthetic provider in `fixtures/oauth-providers/synthetic.json` (soft-skip on 404, Tier-2 host-pending), asserting a successful grant returns a credential REFERENCE (token persisted as a `host.credentials` entry) and that the authorization code / state / PKCE verifier / acquired access+refresh tokens never appear on any run-visible surface (RFC 0047 §C + §C.2 / `credential-payload-redaction`). Closes the RFC 0047 Tier-2 gap (capability-shape + redaction scenarios existed; the actual authorization-code dance was unexercised). 2026-05-26 (RFC 0070 — agent-manifest runtime) added `agent-manifest-runtime.test.ts`; 2026-05-26 (RFC 0071 — artifact-type + chat card packs) added six: `artifact-type-pack-manifest-validation.test.ts` + `artifact-schema-compile-bounded.test.ts` (server-free) + `artifact-type-pack-install.test.ts` + `artifact-type-store-without-render.test.ts` + `chat-card-pack-manifest-validation.test.ts` (server-free) + `chat-card-pack-execution.test.ts` (capability-gated, host-pending). 2026-05-26 (RFCs 0067 / 0068 / 0069 — spec-gap Draft cohort) added five scenarios: `byok-auth-modes.test.ts` (RFC 0067; always-on schema-shape of `aiProviders.authModes` + a discovery-gated §B auth-mode-contract cross-field check), `memory-consolidation-shape.test.ts` (RFC 0068; always-on shape of `agents.memoryConsolidation`/`agents.commitments` + the `agent.memory.consolidated`/`commitment.fired` payload $defs), `memory-consolidation-idempotent.test.ts` + `commitment-fired.test.ts` (RFC 0068; capability-gated behavioral, soft-skip on the documented `/v1/host/sample/memory/consolidate` + `/commitment/fire` seams), and `exec-not-protocol-tier.test.ts` (RFC 0069; always-on server-free structural assertion that the protocol corpus defines no `core.*`/`openwop.*` exec-class primitive — backs the `exec-must-not-be-protocol-tier` SECURITY invariant). 2026-05-25 (RFC 0061 — stateful agent-loop lifecycle, executionModel.version 5) added four `agent-loop-*.test.ts` scenarios: `-version5-shape` (always-on; validates `executionModel.statefulResume`/`transcriptWindow` + the 1–5 version ceiling) plus `-iteration-monotonic` (gated on `version >= 5`; `runOrchestrator.decided.iteration` increments 1,2,3… exactly once per turn), `-workspace-snapshot` (gated additionally on `host.workspace.supported`; a turn-i workspace write is invisible to turn i, visible to turn i+1), and `-stateful-resume` (gated on `statefulResume`; a mid-loop suspend resumes at the same iteration without resetting the counter) — the three behavioral scenarios drive the documented agent-loop seam (`POST /v1/host/sample/agentloop/run`) and soft-skip until a host wires it. 2026-05-25 (RFC 0059 — host.workspace M2, reference-host enforcement) added two `workspace-*.test.ts` scenarios: `-behavior` (capability-gated CRUD round-trip / `If-Match` 409 `workspace_conflict` / `workspace_too_large` / §D run-start snapshot, all via the real `/v1/host/workspace/files` §C endpoints) and `-cross-tenant-isolation` (WCT-1 — drives the documented `POST /v1/host/sample/workspace/op` seam to assert a file owned by one `{tenant, workspace}` is unreadable, on both `get` and `list`, under a different owner; backs the new `workspace-cross-tenant-isolation` SECURITY invariant). The in-memory reference host now advertises `capabilities.workspace.supported` and honors §C/§D/§E end-to-end. 2026-05-25 (RFC 0062 — memory.distillation "dreams") added five `distillation-*.test.ts` scenarios: `-shape` (always-on; validates the `capabilities.memory.distillation` block + the additive `distillation` sub-object on `memory.compacted`) plus `-token-budget` (within budget `tokensUsed ≤ tokenBudget`; an un-meetable budget → `token_budget_exceeded` with no partial archive), `-stable-archive` (same sources + budget ⇒ byte-stable archive checksum), `-index-roundtrip` (gated additionally on `indexEmitted`; the `MEMORY-INDEX.json` workspace file is retrievable + `workspace.updated` fired), and `-secret-carryforward` (SR-1: a redacted source secret never appears in the archive) — the four behavioral scenarios drive the documented memory-distillation seam (`POST /v1/host/sample/memory/distill`) and soft-skip until a host wires it. 2026-05-25 (RFC 0063 — core.subWorkflow.outputAttestation) added four `subrun-*.test.ts` scenarios: `-attestation-shape` (always-on; validates the `capabilities.agents.subRunAttestation` flag) plus `-checksum-stable` (the child output checksum is the byte-stable, key-order-invariant RFC 8785 JCS + SHA-256 digest), `-approval-gate` (`requireApproval` → `accept` merges, `reject` does not), and `-approval-fail-closed` (no `accept`/`edit-accept` → no merge; backs the deferred `subrun-merge-approval-fail-closed` invariant) — the three behavioral scenarios drive the documented sub-run attestation seam (`POST /v1/host/sample/subrun/attest`) and soft-skip until a host wires it. 2026-05-25 (RFC 0064 — host.toolHooks) added five `tool-hooks-*.test.ts` scenarios: `-shape` (always-on; validates the `capabilities.toolHooks` block + the optional content-free fields on `agentToolCalled` / `agentToolReturned`) plus `-content-free` (gated on `prePostEvents`), `-authorization-fail-closed` (gated on `perToolAuthorization`), `-rate-limit` (gated on `perToolRateLimit`), and `-secret-redaction` (gated on `prePostEvents` + the SR-1 `argsHash` redaction rule) — the four behavioral scenarios drive the documented tool-hooks invoke seam (`POST /v1/host/sample/toolhooks/invoke`) and soft-skip until a host wires it. 2026-05-25 (RFC 0060 — host.heartbeat) added four `heartbeat-*.test.ts` scenarios: `-capability-shape` (always-on; validates the `capabilities.heartbeat` block) plus `-fires-once-per-tick`, `-idempotent-no-spam`, and `-runtime-bound` (gated on `capabilities.heartbeat.supported` + the host heartbeat tick seam; soft-skip until a host wires it). 2026-05-25 (RFC 0057 — memory write-attribution) added five `memory-attribution-*.test.ts` scenarios: `-shape` (always-on advertisement check on `capabilities.memory.attribution`), plus `-no-content`, `-tenant-scoped`, `-emits-on-write`, and `-replay-stable` (gated on `capabilities.memory.attribution.emitsWriteEvents`) verifying the content-free `memory.written` RunEvent, its two SECURITY invariants (`memory-attribution-no-content` + `memory-attribution-tenant-scoped`), and the §D replay rule that a `replay`-mode fork MUST NOT regenerate `memoryId`. 2026-05-25 (RFC 0025 §C point 1 — test-catalog isolation invariant; pairs with the 25 publish-error scenarios in `pack-registry-publish.test.ts`) added `pack-registry-isolation.test.ts` — capability-gated on `capabilities.packs.testMode.{supported, isolated}: true`; PUTs a disposable pack into `/v1/packs-test/{name}` and asserts the same `(name, version)` does NOT appear via `GET /v1/packs/{name}` — anchors the test-catalog isolation MUST in RFC 0025 §C. 2026-05-25 (RFC 0028 Tier-2 post-promotion T2 — read-side sister scenario for workspace-membership enforcement) added `prompt-read-workspace-membership-enforced.test.ts` — gates on `capabilities.prompts.supported: true` (broader than `mutableLibrary` so read-only hosts that expose `?workspaceId=` are also probed); drives `GET /v1/prompts?workspaceId=<random-non-member>` and interprets the response: 4xx PASS (canonical envelope check on 403); 200 with empty `templates[]` PASS (correct null result for a nonexistent workspace); 200 with non-empty `templates[]` FAIL (cross-tenant leak); 200 without `templates[]` field SKIP (host doesn't expose workspace-scoped reads). Verifies SECURITY invariant `prompt-read-workspace-membership-enforced`. Same-day T1 strengthened `prompt-mutation-workspace-membership-enforced.test.ts` to pin `error === "workspace_membership_required"` when the host's refusal status is 403 (other refusal codes unconstrained). 2026-05-25 (RFC 0028 Tier-2 follow-up — workspace-membership enforcement on mutating prompt endpoints, filed in response to a self-disclosed adopter vulnerability) added `prompt-mutation-workspace-membership-enforced.test.ts` — capability-gated on `capabilities.prompts.mutableLibrary: true`; drives `POST /v1/prompts` with a cryptographically-random non-member `workspaceId` and asserts the host refuses (NOT a 2xx; any 4xx/5xx is acceptable — silent success is the failure mode). Verifies SECURITY invariant `prompt-mutation-workspace-membership-enforced`. 2026-05-22 (RFC 0034 §B follow-up — secret-leakage harness against the OTel + debug-bundle seams) added `secret-leakage-otel-attribute.test.ts` — gates on `capabilities.secrets.supported` + `capabilities.observability.testSeams.{otelScrape,debugBundleExport}` AND the `OPENWOP_CANARY_SECRET_VALUE` env (host operator + conformance runner agree on the canary). Drives the existing `openwop-smoke-byok-roundtrip` fixture end-to-end; scrapes both seams after run completion; hard-fails if the canary plaintext appears in any OTel span attribute or debug-bundle field. Verifies SECURITY invariants `secret-leakage-otel-attribute` + `secret-leakage-debug-bundle-otel`. 2026-05-22 (RFC 0041 Phase 4 — replay determinism under nondeterministic models) added three scenarios: `replay-divergence-at-refusal.test.ts` (advertisement-shape probe on `replayDeterminism.refusalDivergenceEmission` + 2 `it.todo` for the dual-direction refusal-divergence case), `replay-observable-sequence-determinism.test.ts` (capability-gated; behavioral assertion soft-skipped until a `conformance-phase4-nondet-tool` fixture ships), `replay-llm-cache-key-portable.test.ts` (intra-host reproducibility + non-recipe-field invariance + Phase 4 advertisement alignment — reuses the existing `POST /v1/host/sample/test/llm-cache-key` seam from the sibling `replay-llm-cache-key.test.ts`). 2026-05-20 (RFC 0027 §A templateKinds-coverage follow-up — paired with `prompt-end-to-end-events.test.ts`) added `prompt-all-four-kinds-events.test.ts` exercising all four `PromptKind` values (`system`, `user`, `schema-hint`, `few-shot`) end-to-end through the reference workflow-engine sample's `local.sample.demo.mock-ai` dispatch path; capability-gated via `behaviorGate('prompts-supported', ...)`. Closes the credibility gap where the host advertised `templateKinds: ["system", "user", "few-shot", "schema-hint"]` but only the system+user pair was actually wired into dispatch. 2026-05-20 (RFCs 0030–0033 — envelope LLM-contract-hardening track) added 15 scenarios across four `Active` RFCs: `envelope-reasoning-shape.test.ts` (RFC 0030, always-on; asserts the OPTIONAL `reasoning` property on the three universal-kind schemas + the `schema.response` deliberate omission), `envelope-reasoning-secret-redaction.test.ts` (RFC 0030, capability-gated on `capabilities.envelopes.reasoning.supported` + `secrets.supported`; 5 `it.todo()` placeholders for SECURITY invariant `envelope-reasoning-secret-redaction`), `envelope-tier-one-subset-static.test.ts` (RFC 0030, always-on for load-bearing rules — no `oneOf` / `allOf` / `not` / `prefixItems` / `propertyNames` anywhere; gated on `tierOneSubsetCompliance: "strict"` for OpenAI-strict-only constraints), `envelope-variant-discriminator-static.test.ts` (RFC 0031, always-on; asserts no `oneOf` + every `anyOf` branch declares a single-string-enum discriminator in `required` on every `schemas/envelopes/*.schema.json`), `model-capability-substituted.test.ts` (RFC 0031, advertisement-shape probe on `capabilities.modelCapabilities.advertised[]` identifier pattern + 5 `it.todo()` placeholders for SECURITY invariant `model-capability-substituted-no-credential-disclosure`), `model-capability-insufficient.test.ts` (RFC 0031, 6 `it.todo()` placeholders for refusal + no-recursive-fallback), `node-module-required-capabilities-shape.test.ts` (RFC 0031 SHOULD-tier authoring-convention; 4 `it.todo()` placeholders), and the six envelope-reliability events from RFC 0032 (`envelope-retry-attempted` carrying the shared advertisement-shape probe enforcing both MUST-tier events in `events[]` per RFC 0032 §C, plus `envelope-retry-exhausted`, `envelope-refusal-shape`, `envelope-truncated`, `envelope-nl-to-format-engaged`, `envelope-recovery-applied` — collectively 39 `it.todo()` placeholders covering retry/refusal/truncation/recovery + SECURITY invariants `envelope-refusal-no-prompt-leak` and `envelope-recovery-no-content-leak`), plus RFC 0033's two scenarios (`envelope-completion-distinguishes-truncation.test.ts` + `envelope-truncation-cap-exhaustion.test.ts` — 12 `it.todo()` placeholders covering the truncation-vs-schema-violation retry-routing distinction + the DoS-bound assertion). Reference workflow-engine sample advertises `capabilities.envelopes.reasoning: { supported: true, promptDirective: "off" }` + `tierOneSubsetCompliance: "warn"` honestly (schemas accept the field; host doesn't yet inject the directive); the other three RFCs' capability blocks defer to reference-host emission code per the staged RFC 0027 §G precedent. 2026-05-20 (RFC 0028 §B Phase B — prompt-pack boot-time install) added `prompt-pack-install.test.ts` (capability-gated on `capabilities.prompts.endpointsSupported: true`; asserts a host that ran the boot-time pack loader surfaces ≥ 1 pack-source template under `GET /v1/prompts?source=pack` carrying the canonical `meta.source: "pack"` + `meta.packName` + `meta.packVersion` stamps; positively identifies the in-tree `vendor.openwop.prompt-sample` reference pack's `writer-system` template when present). Pairs with the new `host/promptPackLoader.ts` boot-time entry on the reference workflow-engine sample, which scans `examples/packs/*` plus `OPENWOP_PROMPT_PACKS_DIR` and calls `installPackTemplates()` for each `kind: "prompt"` pack found. 2026-05-20 (RFC 0029 Phase C — prompt resolution chain wire shape) added three more scenarios: `prompt-resolution-chain-node-wins.test.ts` (capability-gated on `capabilities.prompts.supported: true`; asserts layer-1 node-config supersedes lower layers per `spec/v1/prompts.md` §"Resolution chain (normative)"), `prompt-resolution-chain-agent-intrinsic.test.ts` (additionally gated on `capabilities.prompts.agentBindings: true`; asserts agent intrinsic `systemPromptRef` wins over `promptOverrides` AND lower layers when the node has no layer-1 ref), `prompt-resolution-chain-fallback-cascade.test.ts` (asserts layer 3 workflow-defaults wins over layer 4 host-defaults; layer 4 host-defaults wins when 1-3 yield null; resolved is null when all four yield null but chain[] still lists every attempted layer). The scenarios drive the host's `POST /v1/host/sample/prompt/resolve` test seam (reference-host implementation deferred to follow-up slice per RFC 0021 staging precedent). 2026-05-20 (RFC 0027 Phase A — prompt templates wire shape) added three scenarios: `prompt-template-shape.test.ts` (always-on; Ajv compileability + positive/negative round-trip for PromptTemplate + PromptRef + PromptKind), `prompt-composed-secret-redaction.test.ts` (capability-gated on `capabilities.prompts.supported: true` + `observability: "full"`; asserts `[REDACTED:<secretId>]` markers in `prompt.composed` payloads for `source: "secret"` variable bindings per SECURITY/threat-model-secret-leakage.md §SR-1), `prompt-composed-trust-marker.test.ts` (same capability gates; asserts `<UNTRUSTED>...</UNTRUSTED>` wrapping + `contentTrust: "untrusted"` propagation per RFC 0020 §D). Paired with new `fixtures/prompt-templates/` sub-directory + per-fixture schema-validity describe block + future SECURITY invariants `prompt-composed-secret-redaction` and `prompt-composed-trust-marker` (lands alongside reference-host emission per RFC 0021 staging precedent). 2026-05-18 (RFC 0022 `Draft` — runtime variable mapping) added four `it.todo()` placeholder scenarios covering the new mapping surfaces on `core.dispatch` (§A — `dispatch-input-mapping.test.ts`, `dispatch-output-mapping.test.ts`, `dispatch-cross-worker-handoff.test.ts`) and `core.subWorkflow` (§B — `subworkflow-input-mapping.test.ts`). Gated on `capabilities.agents.dispatchMapping` (dispatch trio) and `capabilities.subWorkflow.inputMapping` (subWorkflow). Promote to live assertions when RFC 0022 reaches `Active` + a reference host advertises the matching flags. 2026-05-17 (RFC 0003 §D handoff-schema enforcement, HV-1) added `agentPackHandoffSchemaValidation.test.ts` — verifies the host validates dispatch payloads against `handoff.taskSchemaRef` AND return payloads against `handoff.returnSchemaRef` per RFC 0003 §D. Paired with the new `agent-pack-handoff-schema-enforcement` row in `SECURITY/invariants.yaml`. 2026-05-17 (AI Envelope gap-closure, DRAFT v1.x — `spec/v1/ai-envelope.md`) added 7 advertisement-shape scenarios with `it.todo()` behavioral placeholders gated on `capabilities.envelopeContracts.advertised: true`: `aiEnvelope.universalKinds.test.ts`, `aiEnvelope.schemaDrift.test.ts`, `aiEnvelope.correlationReplay.test.ts`, `aiEnvelope.contractRefusal.test.ts`, `aiEnvelope.trustBoundaryPropagation.test.ts`, `aiEnvelope.redaction.test.ts`, `aiEnvelope.capBreached.test.ts`. Paired with the new `envelope-redaction-sr-1-carry-forward` row in `SECURITY/invariants.yaml`. 2026-05-17 (post-publish hardening, deep audit of `core.openwop.agents`) added `agents-run-tool-allowlist.test.ts` — server-free scenario locking in the `core.openwop.agents@1.0.1` safety-fix that closes `OPENWOP-AUDIT-2026-003` (function-typed `tool.handler` properties rejected at `validateTools()` with `INVALID_TOOL_DECLARATION`; tool-driven runs require `ctx.agentRuntime`; tool-less safe fallback preserved). Paired with the new `agents-run-no-raw-handler` row in `SECURITY/invariants.yaml`. Same-day post-publish hardening added `idempotency-key-determinism.test.ts` — server-free scenario locking in the `core.openwop.http@1.1.2` determinism safety-fix (default `composite` mode produces deterministic keys in `(runId, nodeId, payload)`; removed `uuid` mode rejects with `CONFIG_INVALID`; cross-impl vector test lets third-party reimplementations verify wire agreement). Paired with the new `idempotency-key-deterministic` row in `SECURITY/invariants.yaml`. 2026-05-17 (Phase 3 of RFC 0013) added three server-free scenarios exercising the reference workflow-chain expansion library (`conformance/src/lib/workflow-chain-expansion.ts`): `workflow-chain-expansion.test.ts` (parameter substitution + node id collision avoidance + edge rewriting + capability propagation + runtime-invariance contract), `workflow-chain-unresolvable-typeid.test.ts` (rejection with `chain_unresolvable_typeid` when a chain references an unknown typeId), and `workflow-chain-pack-signature-verification.test.ts` (Ed25519 verification recipe reuse from `node-packs.md §Signing`). Earlier that day (Phase 1) added `workflow-chain-pack-manifest-validation.test.ts` — server-free schema-validation scenario covering the new `workflow-chain-pack-manifest.schema.json` (positive sample + two negatives: kind/contents mismatch and invalid `chainId`). Closes RFC 0013 (`Workflow-chain packs`, `Draft`) Phases 1 + 3 alongside the new `spec/v1/workflow-chain-packs.md`, the `Capabilities.workflowChainPacks` block, and the registry build-index/conformance-check `kind` routing from Phase 2. Earlier that day, the suite added 27 `it.todo()` placeholder scenarios paired with RFCs 0014-0020 (host capability surfaces — fs, kvStorage, tableStorage, queueBus, sql/vector/search, blob/cache, mcp.serverMount). These promote to live assertions when each RFC reaches `Active` + the matching capability block lands in `schemas/capabilities.schema.json` + a reference host advertises the capability. Earlier additions include 18 Multi-Agent Shift scenarios (Phases 1-5) added 2026-05-10, the `registry-public.test.ts` public-registry healthcheck added 2026-05-11 (opt-in via `OPENWOP_TEST_PUBLIC_REGISTRY=true`), the `replay-llm-cache-key.test.ts` placeholder added 2026-05-11 (three `it.todo()` cases for the cross-host LLM cache-key recipe per `replay.md` §"LLM cache-key recipe"), the two `production-*.test.ts` scenarios added 2026-05-11 for the `openwop-production` profile per RFC 0009 (`production-backpressure.test.ts`, `production-retention-expiry.test.ts`), the four `auth-*.test.ts` scenarios added 2026-05-11/12 for the production-auth profiles per RFC 0010 (`auth-api-key-rotation.test.ts`, `auth-oauth2-client-credentials.test.ts`, `auth-oidc-user-bearer.test.ts`, `auth-mtls.test.ts` (opt-in via `OPENWOP_TEST_MTLS=1`)), `replay-retention-expiry.test.ts` added 2026-05-12 (capability shape + 410/422 envelope per `replay.md` §"Retention and garbage collection"), `bulk-cancel.test.ts` added 2026-05-12 (Phase B close-out of R1 — `POST /v1/runs:bulk-cancel`), the two Phase H launch-blocker advertisement-contract scenarios added 2026-05-12 (`mcp-toolcall-redaction.test.ts` for the MCP-1 invariant per `host-capabilities.md §host.mcp` + `threat-model-prompt-injection.md §UNTRUSTED`, and `http-client-ssrf.test.ts` for the SSRF + body-size cap advertisement contract on `capabilities.httpClient`), the `wasm-pack-abi-version-rejection.test.ts` Track 7 scenario added 2026-05-12 for the ABI-mismatch positive path via the `vendor.openwop.misbehaving-abi` pack per RFC 0008 §H, the `otel-trace-propagation-subworkflow.test.ts` Track 11 close-out added 2026-05-13 (parent + child run spans share the inbound traceparent's traceId across the `core.subWorkflow` dispatch boundary), and the three RFC 0012 (Memory Compaction Profile, `Active`) scenarios added 2026-05-13/14: `memory-compaction-sr1-carry-forward.test.ts` (load-bearing SR-1 §D), `memory-compaction-event-emitted.test.ts` (canonical §B payload shape), and `memory-compaction-provenance-tag.test.ts` (soft assertion on §C `compacted-from:<id>` convention). All three gate on `capabilities.memory.compaction.supported` + the host's test seam at `/v1/test/memory/{seed,compact}` (Postgres reference host enables both via `OPENWOP_MEMORY_COMPACTION=true OPENWOP_TEST_TRIGGER_COMPACTION=true`). 2026-05-15 (gap-closure CF-3) added `interrupt-token-matrix.test.ts` (malformed / unknown / replay / cross-run-id paths on `GET|POST /v1/interrupts/{token}`). 2026-05-31 (RFC 0078 portable tool catalog + RFC 0079 credential provenance / egress policy — the Active→Accepted behavioral gate) added four: `tool-catalog-projection.test.ts` (capability-gated on `toolCatalog.supported` via `behaviorGate('openwop-tool-catalog', …)` — the NORMATIVE `GET /v1/tools` list with each `ToolDescriptor` schema-valid + `source`/`safetyTier` in the closed vocab + content-free, `GET /v1/tools/{toolId}` round-trip + unknown-id 404, 401-unauthenticated, and the §F-2 cross-principal non-disclosure; black-box, no POST seam), `tool-session-lifecycle.test.ts` (gated on `toolCatalog.sessionLifecycle` — the §D `tool.session.opened`-before / `tool.session.closed`-after bracket over the RFC 0064 call events via the `POST /v1/host/sample/tools/session-run` seam, one shared `sessionId`, content-free), `egress-audience-binding.test.ts` (KEYSTONE — gated on `httpClient.egressPolicy.supported`; the §C confused-deputy MUST via `POST /v1/host/sample/egress/decide`: an out-of-audience egress is denied/downgraded with the credential NOT attached, a provenance-unevaluable egress fails closed — the behavioral leg of `egress-credential-audience-bound`), and `egress-decision-content-free.test.ts` (the SR-1 canary — the credential value never surfaces in `egress.decided` and `reason` stays in the CLOSED vocabulary). The maintained scenario-to-spec map lives in [`coverage.md`](./coverage.md); this README keeps the operator quickstart and the historical scenario notes below.
95
+ The current suite has 460 scenario files under `src/scenarios/`. 2026-08-16 (suite `1.128.0 → 1.129.0`): NEW `compensation-recovery.test.ts` — RFC 0151 §C retry-stable identity, §E tenant-bound operator authority, §B/§F recorded-facts replay, through the §21 recovery extension (`unwind` `failFirstInverseAttempts`/`hold` + `inverseActions[]`, `replay` `source[]`/`replayed[]`, NEW `operator` seam); gated on `compensation.supported`, `blocked` per sub-feature when the extension is absent. 2026-08-16 (suite `1.127.0 → 1.128.0`): NEW `workload-identity-chain-bounds.test.ts` — RFC 0154 §B chain bounds through the §20 seam (too-long / cyclic / scope-amplified refusals + a narrowing chain resolves), gated on `auth.workloadIdentity.delegation.supported`. 2026-08-16 (suite `1.123.0 → 1.124.0`, S22): NEW `error-envelope-canonical-shape.test.ts` (server-free) pins the decision that the HTTP error envelope is **flat** — `{ error: <code>, message, details? }`, `details.retriable` — against the schema, the new `lib/error-envelope.ts` helper (`readErrorCode` / `readRetriable`, tolerating the legacy nested `{ error: { code } }` seam shape through the first minor after 2026-11-10) and the prose; 15 HTTP-envelope legs read through the helper. 2026-08-16 (suite `1.122.0 → 1.123.0`) added two, both server-free and always-on: `conformance-execution-witness.test.ts` (an early return can never become a pass — the runner's `resolveFileRecord`, the emitter derivation and the consumer verifier each pinned with sabotage vectors) and `conformance-advertised-seam-required.test.ts` (under `OPENWOP_REQUIRE_BEHAVIOR=true` an advertised profile with a missing seam FAILS — `behaviorGate`, `behaviorGatePresent`, `seamAbsent` — and the only escape is an explicit opt-out that records `skipped`); `mcp-stateless-request.test.ts` gained the Mcp-Method/Mcp-Name half of `mcp-header-body-consistent`. Every scenario RFC 0148 §Conformance names now exists. 2026-08-16 (suite `1.119.0 → 1.120.0`, no new files): RFC 0148 §C gap G7 closed — `PROFILE_FLOOR_SCENARIOS` gained a discovery-conditional model (`conditional: [{ path, includes, required }]`, evaluated against the captured discovery document) for `openwop-replay-fork`, and `openwop-interrupts` / `openwop-secrets` / `openwop-provider-policy` / `openwop-memory` / `openwop-trigger-bridge` received floors transcribed into `profiles.md`; every catalog profile now has a floor and *unprovable* is reserved for names outside the catalog. Against the tier-1 reference host: interrupts, secrets and provider-policy now **certify** on witnessed floors; replay-fork does not (its `replay` branch carries the unconditional no-re-fire obligation, `blocked` while the host advertises `sideEffectSuppression: none`); trigger-bridge does not (delivery seam unwired). 2026-08-16 (suite `1.118.0 → 1.119.0`, no new files): 84 scenarios that returned early in silence now say why — 256 early-return sites converted to `softSkip(kind, reason)` (`inapplicable` for a capability/profile/fixture the host does not advertise, `blocked` for a seam, prior step, or precondition that was unavailable); against the tier-1 reference host the RFC 0148 §A marker rows fell from 84 to 8 (all `describe.skipIf`/`it.skip` files) and `inapplicable` rose from 47 to 97. 2026-08-16 (suite `1.117.0 → 1.118.0`, no new files): the runner resolves a silent zero-assertion file to `blocked` (RFC 0148 §A) instead of a vacuous pass; NEW `lib/soft-skip.ts` (`softSkip`, `seamAbsent`) lets a scenario say why it returned early, and ten scenarios were converted as exemplars. 2026-08-16 (suite `1.116.0 → 1.117.0`, no new files): `openwop-node-packs` became runtime-derived in `--certify` (claimed only when held) and its two floor scenarios record `inapplicable`/`blocked` with reasons instead of returning early into a vacuous pass. 2026-08-16 (S7 — RFC 0149 §D, suite `1.115.0 → 1.116.0`) added one, server-free: `normative-example-extraction.test.ts` (a `<!-- normative-example: <name>.schema.json -->` marker above a fenced example declares it a whole instance; every declared example is extracted at test time and validated against `schemas/<name>`, and every undeclared whole-instance example fails — 26 declared across `spec/v1`). 2026-08-16 (S12 — RFC 0148 §Conformance + RFC 0149 §A coverage residue, suite `1.114.0 → 1.115.0`) added three, all server-free and always-on: `certification-bundle-non-vacuous.test.ts` (the consumer re-derivation of a v2 bundle — `verifyBundleV2`: missing witness, vacuous pass, duplicate requirement, tampered totals, invented disposition, missing reason all REJECT the evidence; an honest `blocked`/`executed-fail` on a required row is valid evidence that does not certify), `certification-bundle-redaction.test.ts` (secret canaries never enter evidence — the emitter scrubs the finished document with the handed credential + `OPENWOP_*` secrets + the conformance canary, and the verifier rejects the canary anywhere), and `openapi-asyncapi-sdk-parity.test.ts` (the generated `spec/v1/operation-path-manifest.json` re-derives from `api/openapi.yaml`; AsyncAPI addresses resolve to OpenAPI GET paths with exactly one `/v1`; the SDK half witnesses `openwop-sdks` when reachable and records `blocked` with a reason when not). 2026-08-16 (RFC 0148 acceptance item 2 — S6, suite `1.113.0 → 1.114.0`) added one: `runner-ledger.test.ts` (server-free — the §A ledger file sink, the reader's conflict rank, file-level disposition derivation, and `--certify`'s rejection of silent and vacuous returns). Every scenario file now records its own disposition (with `assertionCount`) into the ledger from `setup.ts`, and `--certify` exits 3 when a claimed profile has an unclassified return. The first end-to-end run found that the `openwop-core-standard` floor had named `audit-log-verification.test.ts` — a file that never existed — since RFC 0088; the scenario it meant (`audit-log-integrity.test.ts`) gates on the optional annex profile `openwop-audit-log-integrity`, so by the floor's own no-soft-skip rule the row was never a floor scenario and is removed (`core-standard-profile.md` §C). 2026-08-16 (RFC 0153 §B/§C/§D/§E — S16, suite `1.112.0 → 1.113.0`) added six: `mcp-2026-07-28-discover.test.ts` (peer pin of the now dual-era `McpFakeServer` — stateless `_meta`, header/body agreement `-32020`, `-32022` + `data.supported[]`, `server/discover`, `resultType`, `CacheableResult`, MRTR `input_required` → retry with echoed `requestState`, `-32021` without the `elicitation` capability — plus the host `server/discover` ⇔ `protocolVersions` leg), `mcp-stateless-request`, `mcp-mrtr-roundtrip` (client half cross-checked against the wire; server half against an exposed suspending tool), `mcp-cache-tenant-scope`, `mcp-extension-opacity`, `mcp-current-auth-boundary` — all gated on `mcp.profiles ∋ mcp-2026-07-28` / the §B advert + additive seam blocks (`mrtr`, `extensionAuthority`), `blocked` on today's 2025-06-18 hosts. Header-less requests to the fake server still get 2025-06-18 semantics, so `mcp-tool-roundtrip` and the legacy `mcp-server-*` legs are unchanged. 2026-08-16 (RFC 0152 §C/§D/§E — S15, suite `1.111.0 → 1.112.0`) added four: `a2a-1-0-agent-card.test.ts` (server-free — the suite's own `A2AFakePeer`, now dual-era, pinned at 1.0 from the wire: `supportedInterfaces[]` card, `SendMessage`/`GetTask`/`CancelTask`/`ListTasks`, `TASK_STATE_*`, `Part` oneof, `-32009` on an unsupported `A2A-Version`, header-less = 0.3), `a2a-card-runtime-consistency.test.ts` (black-box, gated on `a2a.profiles ∋ a2a-1.0`), `a2a-1-0-task-roundtrip.test.ts` (host as 1.0 server, same gate), `a2a-peer-authority.test.ts` (host as client; additive seam `scenario`, `blocked` until the host reports). Also (S14) `fixtures-valid.test.ts` and `workflow-primary-output-annotation.test.ts` now register schemas by enumerating the directory instead of a fixed list — the fourth cross-file `$ref` (#1009) had broken the list at describe time, here and in every downstream runner resolving the sibling corpus with a pinned suite. **Correction recorded the same day:** openwop-app's live origin passes the RFC 0152/0153 §A legs and has NOT wired the `invoke` seams, so its §B legs are `blocked` (RFC 0148 §A) — an earlier note here said they pass. 2026-08-16 (RFC 0157 — chain fragments carry compensation, suite `1.110.0 → 1.111.0`) added one: `chain-compensation-expansion.test.ts` — the `FragmentNode.compensation` / `WorkflowChain.compensation` mirrors are byte-equal to their sources, the manifest stays self-contained (no cross-file `$ref` — the S14 lesson), and `carryCompensation` (composed after the byte-mirrored expansion core, not inside it) carries the declaration verbatim with params substituted and node-id refs rewritten, refuses an unresolvable compensator before any node is emitted, and copies / accepts / conflicts the chain policy into `settings.compensation`. 2026-08-16 (RFC 0155 §A — `openwop-discovery-core` canonical / `openwop-core` deprecated alias, suite `1.109.0 → 1.110.0`) added one: `profile-discovery-core-alias.test.ts` — the alias MUST derive exactly when the canonical name derives, checked over payloads on both sides of the predicate (an equivalence over payloads that all derive proves nothing about the other side), the doc's rename and claim vocabulary (an unqualified claim means `openwop-core-standard`), and a gated live-host leg; `PROFILE_NAMES` gained the canonical name and `deriveProfiles` emits both or neither. Same release: `spec/v1/extensions.json` gained a DERIVED `coverage` block — 5 covered / 81 uncovered / 4 core of 90 capability families — gated by `generate-extension-registry-coverage.mjs --check` in `openwop:check`, so "unlisted means uncovered" is a checked list rather than a sentence. 2026-08-13 (host-callback declaration — every scenario needing the HOST to reach the harness declares it, so an off-process consumer can enumerate the unwitnessable set before running). 2026-08-13 (RFC 0153 §A/§B — MCP revision negotiation witness, suite `1.96.0 → 1.97.0`) added one: `mcp-version-negotiation.test.ts` (four capability-gated legs) plus header capture on `McpFakeServer`. **Both fake peers had the identical gap** — recording the call body but not its headers — which is worth naming as a shared assumption rather than two oversights: *the interesting part of a call is its body*. Version negotiation is precisely the case where that is wrong. MCP revisions are **dates**, so the wire header is checked for date form and not merely for presence: a host sending `latest` or `2026-7-28` has sent something **unmatchable against a pinned peer**, and the failure then surfaces at the peer rather than at the handshake meant to prevent it. A further leg requires the negotiated revision to appear in `protocolVersions`, because **a host that negotiates a revision it never advertised has made its own discovery document unreliable** — worse than advertising nothing, since a consumer that read it decided on a fact that was not true. **`Pinned real MCP current peer passes in CI` stays separate and unmet.** 2026-08-13 (RFC 0152 §B — A2A version negotiation witness, suite `1.95.1 → 1.96.0`) added one: `a2a-version-negotiation.test.ts` (four capability-gated legs) plus header capture on `A2AFakePeer`. **RFC 0152 was twice described here as needing a live upstream peer, and that was half true**: interop needs a real peer, **negotiation does not** — negotiation is the *host's* behavior and the host is right here. What was actually missing is that `A2AFakePeer` recorded method, path, rpcMethod, and body but **not headers**, and §B lives entirely in the headers: the peer could see that a call happened but not which version was negotiated, which is the only part §B is about. The fix was to record what the fake peer already received. The load-bearing leg is negative — *"a host MUST NOT silently downgrade an authenticated request"* — and **a silent downgrade is dangerous precisely because it SUCCEEDS**: the caller believes it negotiated 1.0, the peer answered 0.3, and nothing in the response says otherwise. A failure would at least be visible. So a host that proceeds after a downgrade MUST report the version it actually negotiated, and the wire header MUST match. **`Real upstream A2A 1.0 peer passes in CI` remains separate and unmet** — that item tests interoperation, which no fake can stand in for, and the RFC's acceptance criteria still say so. 2026-08-13 (RFC 0154 §A/§B — the workload-identity BEHAVIORAL witness, suite `1.94.0 → 1.95.0`) added one: `workload-identity-behavior.test.ts` (six capability-gated legs) plus `host-sample-test-seams.md` §20. **§A's requirements are invisible from the wire**: verify, bind to request, resolve to a principal *before* authorization, fail closed — and a normal request either succeeds or 401s, **both of which look identical whether the host verified anything or simply trusted a header**. That invisibility is why the seam exists, and why a missing seam is reported as **`blocked` rather than skipped**: RFC 0148 §A resolves an unobservable requirement to blocked, so without it RFC 0154 **cannot be certified at all**. **The negatives carry the weight** — a host that echoes its input satisfies every positive assertion, so only the rejections distinguish a verifier from a passthrough: `audience_mismatch` (an identity minted for another host, accepted here, is how a credential valid elsewhere becomes valid here — RFC 0147 **R12**), `delegation_expired` (a delegation without a live expiry is a standing grant, which is not what delegation means), and `sender_constraint_missing` (without proof-of-possession a bearer credential is replayable by anyone who observed it). Failures MUST be **non-retriable** — an identity that does not resolve will not resolve on retry, and marking it retriable invites hammering a failing authorization path. The seam **MUST NOT be a mock**: it drives the host's real resolver, or the witness proves nothing about production. 2026-08-13 (RFC 0151 §C–§G — the compensation BEHAVIORAL witness, suite `1.93.0 → 1.94.0`) added one: `compensation-behavior.test.ts` (five capability-gated legs). **This closes a gap in the SUITE, not in any host.** RFC 0147 §A.5 requires a host to execute every normative behavioral path in strict mode — and RFC 0151 had **no behavioral scenario at all**, only a server-free schema check. **A willing host had nothing to run.** For several turns the blocker was described as "no host implements this" when part of it was that the evidence-collecting apparatus did not exist either. Each leg is gated on `compensation.supported` via `behaviorGate`, so it soft-skips against a non-advertising host and **hard-fails under `OPENWOP_REQUIRE_BEHAVIOR=true`**, recording an RFC 0148 §A ledger disposition either way. The legs pin the §C rules that are otherwise unverifiable: **plan persisted before the first inverse action** (`requested` strictly precedes `started` — a host that unwinds before persisting cannot resume, and the crash is exactly when that matters); **descending forward-completion order** (compensating forward can release a resource a later inverse action still needs); **replay does not re-fire** (§F — a replay that re-executes inverse effects turns a recovery into a second outage); and **no provider bodies or credentials in events** (§D/§G — these land in the durable log, the least revocable place a credential can reach). A missing sample seam fails with a message saying the requirement is unobservable and therefore `blocked`, not passed. 2026-08-13 (RFC 0148 §C — certification bundle v2, suite `1.91.0 → 1.92.0`) added one: `certification-bundle-v2.test.ts` (eight legs, server-free) plus `schemas/certification-bundle-v2.schema.json`. v1 recorded `{passed, failed, skipped}` as scenario-FILE lists, and those three words cannot express the distinction this program turns on: a file counted as `passed` **whether its assertions ran or its runner returned early**, and `skipped` flattened three different claims — "the operator excluded this", "the requirement does not apply", and "we could not check" — into one word, when only the first two are certifiable. v2 carries per-requirement dispositions from §A plus the counts §A.4 requires. Two properties are load-bearing: **`blocked` is a REQUIRED total**, because `blocked: 0` asserted is a different claim from `blocked` unstated and an omitted total reads as zero; and **`assertionCount` makes a vacuous pass visible** — the schema deliberately still ADMITS `executed-pass` with `assertionCount: 0`, because forbidding it would only move the lie one field over, while putting the number in the artifact lets a reader see a pass that executed nothing **without re-running the suite**. Sabotage-verified: dropping `blocked` from `required` and removing `minItems` on the requirement list red two legs. 2026-08-13 (RFC 0154 §A/§B — workload identity and delegation, SHAPE ONLY, suite `1.90.0 → 1.91.0`) added one: `workload-identity-profile.test.ts` (eleven legs, server-free) plus `schemas/workload-identity.schema.json` and an `auth.workloadIdentity` capability. §A's real requirements are **behavioral** — cryptographically verify the presented identity, bind it to the request, resolve it to a principal before authorization, fail closed when unresolvable — and **a schema demonstrates none of them**. What a schema *can* do is make the dangerous shape unrepresentable, which is what this checks: **raw certificates, tokens, proofs, and credentials MUST NOT enter these objects.** `subject` is opaque; `proofRef` and `thumbprintRef` are pattern-constrained digest *references*, so a JWT or a raw key cannot be pasted in and still validate. That matters because these objects are projected into events, spans, and audit records — **the three places credential material must never reach**. `audience` is required on a delegation because an identity minted for somewhere else, accepted here, is the confused-deputy path (RFC 0147 R12), and **identity is not authorization** is the one rule a schema cannot enforce at all. Sabotage-verified: opening `additionalProperties` and dropping the digest pattern red two legs. 2026-08-12 (RFC 0152 + RFC 0153 §A — versioned composition discovery, SHAPE ONLY, suite `1.89.0 → 1.90.0`) added one: `versioned-composition-profiles.test.ts` (eleven legs, server-free) plus `protocolVersions` / `preferredVersion` / `profiles` on `a2a` and `mcp`, and a closed `features` list on `mcp`. **Both RFCs address the same defect**, which is why they land together: **`supported: true` with no version is a claim a peer cannot negotiate against.** Two hosts can both advertise it, share no revision, and discover that only when a call fails — at the peer, not at the handshake meant to prevent it. **MCP versions are date-patterned rather than free strings** because MCP revisions *are* dates: accepting `latest` or `2026-7-28` would let two hosts disagree about which revision they share while both validate. **The MCP feature list is closed** because an unrecognized name is indistinguishable from a typo. **Shape only, and the file says so** — nothing contacts a peer, and a final leg asserts both RFCs keep their upstream-peer acceptance items unticked, since interop is the one thing a schema cannot demonstrate. **A first draft had the negatives passing for the wrong reason**: the `a2a` family independently requires `agentCardUrl`, so fixtures omitting it failed on the missing card URL rather than the version defect under test — the vacuity pattern, inside a test written to prevent it. 2026-08-12 (RFC 0151 §A/§B — compensation profile SHAPE ONLY, suite `1.88.0 → 1.89.0`) added one: `compensation-profile.test.ts` (nine legs, server-free) plus the `compensation` capability family and the node-level `compensation` declaration. **What it proves is stated in the file itself**: the schemas admit the shapes §A/§B describe and reject the ones they forbid. That is **shape-only evidence** — not evidence that any host orders an unwind, persists a plan before the first inverse action, or resumes after a crash. **RFC 0147 §A.5 forbids `Accepted` on shape-only evidence for a behavioral requirement**, and a final leg asserts 0151's behavioral acceptance item stays unticked and annotated, so reading the suite alone cannot leave a different impression. Design constraints the schema encodes: **compensation is a second effect, not an undo** — it can fail, be partially applied, and be harmful (R9), hence `requiresApproval` and security-high; **inputs come from recorded facts**, since an inverse built from a re-inferred value is not the inverse of what was done; and **`nodeTypeId` resolves at registration**, so an unwind cannot fail on a typo first discovered during a failure. Sabotage-verified: opening `additionalProperties` on the declaration reds the closed-shape leg. 2026-08-12 (RFC 0147 §A.10 — program self-audit, suite `1.87.0 → 1.88.0`) added one: `rfc-0147-self-audit.test.ts` (four legs, server-free) plus `docs/RFC-0147-SELF-AUDIT.md`. §A states ten invariants that "apply to every workstream", and §A.10 forbids citing the RFC's partial implementation as evidence its gaps are closed — so **a program that audits everything except itself has the same defect it was written to fix, one level up**. The audit found **two violations**: §A.5 (0151–0154 reached `Accepted` with *no* evidence, not merely shape-only) and **§A.6** (0148/0150/0152/0153/0154 had comment windows waived under `MAINTAINERS.md` bootstrap language — *the exact mechanism §A.6 says must not shorten a high-risk window*). The available technicality — 0147 was `Draft` at the instant of the flip — is **recorded and not relied upon**, because reading the program's partial state in whichever direction is convenient is the shape §A.10 forbids. **The gate does not assert compliance**; it asserts every invariant carries an explicit disposition, including the adverse ones. Making it fail on a violation would create pressure to delete the row rather than fix the program. Sabotage-verified both ways: replacing `VIOLATED` with `satisfied` reds, and deleting the §A.6 row reds. 2026-08-12 (RFC 0155 §B/§C — core-standard manifest + extension registry, suite `1.86.0 → 1.87.0`) added one: `core-manifest-and-extension-registry.test.ts` (eight legs, server-free), plus `spec/v1/core-standard-manifest.json`, `spec/v1/extensions.json`, and a generator wired into `openwop:check`. **§B's value is the sentence after the inventory** — *"prose and code profile definitions MUST be generated from or checked against this manifest"*. Three places described the core-standard floor independently and could only be *assumed* to agree; they did not, and `PROFILE_FLOOR_SCENARIOS` being an incomplete transcription is what let five profiles verify as floor-proven against nothing (RFC 0148 §C). The manifest is **derived, never hand-listed**, because a hand-listed manifest drifts the moment the corpus moves and then asserts the drift with a digest attached. §C's registry carries six records backfilled from each RFC's own status. **Every one is `draft`, and none can currently be `stable`**: §C gates stable on a Tier-3 implementation and none exists, so that ceiling is recorded rather than worked around — a fact about adoption, not about the work. Sabotage-verified on both halves: dropping a floor scenario from the manifest reds the parity leg, and marking any extension `stable` without an `evidenceTier` reds the overclaim leg. 2026-08-12 (RFC 0150 §C — golden vectors, suite `1.85.0 → 1.86.0`) added one: `semantic-digest-vectors.test.ts` (sixteen legs, server-free) plus `conformance/vectors/semantic-request-digest-v2.json`. §C's acceptance criterion is that TypeScript, Python, and Go compute the same digest, and **prose cannot deliver that** — three independent readings of "canonicalize via JCS and hash" is exactly how three implementations diverge, invisibly, until two hosts replay the same run and get different cache keys. The vectors are the contract; an SDK reproduces the file. **Several are pairs whose relationship IS the requirement**: tools sorted vs reversed MUST agree, message order reversed MUST NOT, and the two Unicode forms of `é` MUST NOT — because JCS does not apply NFC. That last pair catches a well-meaning "add NFC to be safe" change **that every other vector passes**. **The first draft of this gate had the bug it was written to catch:** the relationship legs compared two stored digests from the same file — two constants — so they validated the vector set and would have passed unchanged against a broken implementation. They now recompute from `input`. Sabotage before the fix reddened one leg; after, two. 2026-08-12 (RFC 0150 §C — semantic request digest v2, **safety-fix**, suite `1.84.0 → 1.85.0`) added one: `semantic-digest-v2.test.ts` (six legs, server-free). Three defects in `replay.md`. **(1) The exclusion list forbade exactly what §C requires**: it said `max_tokens`, `stop`, and `seed` MUST NOT influence the cache key — but all three change the completion, so keying them identically causes a **wrong hit, not a miss**, deterministically returning a response the caller never asked for. **(2) It prescribed a normalization JCS does not perform**: canonicalize "via RFC 8785 JCS", then, for hosts without JCS, "UTF-8 NFC for all strings" — so the two routes the same sentence offered produced **different bytes for the same input**, defeating the cross-host portability §D asserts as a normative invariant. **(3) It quoted a formula that no longer exists**: the `attempt`-bearing Layer-2 composition RFC 0150 §B retired, left behind when `idempotency.md` went to v1.4 — a cross-document staleness **§B itself introduced and did not catch**. v2 stamps the canonical object `openwop-semantic-request-v2` so retired digests are distinguishable, and carries unknown provider options in a namespaced `providerOptions` rather than dropping them. The gate reads **normative text only**, excluding blockquotes, because the document deliberately quotes the rules it retired — with a guard that the filter retains >70% of the file, and sabotage-verified that reintroducing a retired rule in normative voice still reds. 2026-08-12 (RFC 0148 §B — strict behavior, suite `1.83.0 → 1.84.0`) added one: `strict-behavior-gate.test.ts` (seven legs, server-free). §B says *"a host MUST NOT both advertise and opt out of the same profile"* — and `behaviorGate()` detected exactly that contradiction, emitted a `console.warn`, and **proceeded as if advertised**. **A MUST NOT enforced by a warning is not enforced**: nothing consumes the warning, nothing fails on it, and the certification bundle produced from that run records a pass. It matters because the two claims are opposite in kind — advertising says the host implements the profile, opting out says the operator declares it does not — so a run where both hold has no defensible reading, and the resolution the gate chose (advertisement wins) extracted **more** certification claim from a **more** contradictory input. Now throws. The second half wires §B to §A: a gate decision records a ledger disposition, so an honest opt-out is `skipped` and an unadvertised profile is `inapplicable` — both certifiable, and both distinct from the `blocked` that §A assigns to silence. **Before the ledger existed there was nothing to record into, which is why §B could not be implemented before §A.** 2026-08-12 (RFC 0148 §A — requirement execution ledger, suite `1.82.1 → 1.83.0`) added one: `requirement-ledger.test.ts` (thirteen legs, server-free) plus `src/lib/requirement-ledger.ts` and `src/lib/requirement-registry.ts`. §A's operative sentence is **negative** — "a plain test return, caught exception converted to a return, or empty assertion body MUST NOT produce `executed-pass`" — and a ledger that merely *offers* five dispositions does not deliver it. **Every vacuity found in this corpus reached `pass` by not running, not by running wrong**: `[].every(...)` over an undefined floor, a gated subtest that 404'd and soft-skipped, a scenario whose assertions never executed while its file counted green. So the ledger **inverts the default**: a requirement with no recorded disposition resolves to `blocked`, never to a pass. Silence is evidence of nothing, and the data structure says so instead of relying on each author to remember it. `blocked` is not certifiable (`skipped` and `inapplicable` are); an **empty** requirement set does not certify, because that is the `[].every(...)` shape itself; `requirementsFor()` returns **null** rather than `[]` for an unwritten floor, forcing the caller to distinguish "empty by design" from "not transcribed yet"; a non-pass disposition without a reason throws; and contradictory dispositions for one requirement throw rather than last-write-wins, since silent overwrite would let a later soft-skip bury an earlier real failure. **Scoped to the certification floor, not all 423 files** — tagging every assertion in one pass would produce a registry nobody could review, and an unreviewed requirement ID is worth less than none because it looks like coverage. Sabotage-verified on the load-bearing property: defaulting absence to `executed-pass` reds the gate. 2026-08-12 (RFC 0150 §B — cross-scope effect identity, additive, suite `1.81.0 → 1.82.0`) added one: `effect-identity-cross-scope.test.ts` (four legs, server-free). **`runId` is in the §B preimage**, so an effect issued outside any run cannot produce a Layer-2 identity at all and can never collide with one. Layer 2 dedupes a node effect against its own retries; it does **not** dedupe it against the same logical effect issued via an operator route, admin action, or scheduled job. Since §"Why this exists" requires Layer 2 "for any node executor that performs an external side effect", **a host reading that literally would use the ordinal form and stop** — and for a cross-entry-point effect that reintroduces the duplicate-effect class §B exists to kill, on the highest-stakes path it touches. v1.4 requires such effects to be **additionally keyed on a business identity**, stable across entry points and containing no `runId`/`nodeId`/ordinal. Reported by a tier-1 host from a shipped node pack (`refund-order` plus three non-run entry points reaching one implementation), not proposed in the abstract. The fork note and this are **one limitation seen twice**, and a leg asserts the linkage so a reader cannot read the fork case as a special exception. 2026-08-12 (RFC 0149 §D — lifecycle coherence, governance, suite `1.80.0 → 1.81.0`) added one: `rfc-lifecycle-coherence.test.ts` (three legs, server-free). §D asks the generator to fail when an `Accepted` RFC "retains an unresolved acceptance blocker not explicitly carried". **The obvious gate — every box ticked before `Accepted` — was measured and rejected**: of 141 `Accepted` RFCs, 42% ticked all, 25% ticked none, 24% ticked some, so a blanket rule fails 69 RFCs on its first run, and a gate that fires 69 times gets disabled rather than fixed. **The first triage hypothesis was also wrong**, and correcting it produced the rule that shipped: the partially-ticked RFCs are not a blocker backlog — every trailing item in `0027`/`0040`/`0041` is deliberately unticked *and annotated with why*, which **is** §D's "explicitly carried", just in a parenthetical rather than a register row. So the signal is **annotated vs bare, not ticked vs unticked**: an unticked item with no explanation is indistinguishable from one nobody checked. Scoped to RFCs ≥ 0147 — the program's own cohort — so **the rule binds the RFC that proposed it**, with a leg asserting exactly that; earlier RFCs are the dated record of a period when the convention did not exist, and the boundary is asserted so a new RFC cannot inherit the exemption. **All 67 bare items across 0147–0156 were annotated to land it**, which is the real work: each now names its gate. Sabotage-verified — stripping one annotation reds the leg with its file:line. 2026-08-12 (RFC 0149 §E — canonical-family shadowing, security, suite `1.79.0 → 1.80.0`) added one: `discovery-canonical-family-no-shadow.test.ts` (three legs, server-free). RFC 0073 puts canonical families at the document root and `host-extensions.md` puts vendor surface under `x-host-*` / `vendor.*` / `private.*`; together that is what makes discovery negotiable. **Nothing forbade a canonical family name appearing INSIDE the namespaced region** — `vendor.acme.auth`, or an `x-host-acme-*` object carrying its own `interrupts`. A consumer that merges vendor surface over the root before negotiating then reads a vendor's `auth` block as *the* auth contract. `host-extensions.md` already tells clients to treat extension surface as opaque, but that binds the **consumer** — it does not stop a host publishing the collision, and the consumer that gets the merge order wrong is exactly the one the rule exists to protect. Second leg, unconditional: **no discovery example may carry credential material**, because discovery is served credential-free to anonymous callers, so a real-shaped secret in an example sits in the most-copied, least-guarded artifact in the corpus. The family list is **read from `capabilities.schema.json`** rather than hand-listed, so a new family is covered the day it lands. **The corpus was already clean, making this a guardrail rather than a repair** — so it was sabotage-verified rather than red-before-green: injecting `"vendor.acme.suite": { "auth": … }` reds the shadow leg with its file:line and the colliding key, and an `sk-`-prefixed value reds the credential leg. 2026-08-12 (RFC 0149 §C — `protocolVersion` grammar, **safety-fix**, suite `1.78.0 → 1.79.0`) added one: `protocol-version-grammar.test.ts` (twenty legs, server-free). The field was specified **three incompatible ways at once**: `capabilities.schema.json` constrained it to `minLength: 1`, the suite's own core predicate tested `startsWith('1.')`, and prose called it semver while every example showed two components. So `"v1.0"`, `"1.0.0"`, and `"banana"` all validated — and `"1.0.0"` additionally **derived `openwop-core`**, because the predicate deciding whether a host is openwop-compatible at all was looser than the schema every host validates against. Comparison needs an integer major (the hard boundary) and an integer minor (the additive contract level); neither is extractable from a string nothing constrains, so two hosts advertising `"1.0"` and `"1.0.0"` gave a consumer no way to tell a patch convention from a typo from a different protocol. Now `^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$` in the schema, in `profiles.ts`, and in `version-negotiation.md` §"Protocol version grammar" — with a leg asserting the schema pattern and the predicate agree, so they cannot drift apart again. Closes gap V2, open since v1.0 with owner `future`. 2026-08-12 (RFC 0150 §D — multi-region effect vocabulary, **safety-fix**, suite `1.77.0 → 1.78.0`) added one: `multi-region-effect-vocabulary.test.ts` (eight legs, server-free). Two capability values promised things they did not deliver. **`crossRegion: "strict"`** was documented as "cross-region read-visibility is bounded by `multiRegion.replicationLagBoundMs`" — a **latency** claim occupying the top slot of a ladder implementers read as effect safety. A host replicating synchronously at 0 ms can still issue duplicate effects from two regions, because knowing what the other region wrote is not the same as being authorized to act. It was **removed rather than renamed** to `fenced-effects`: a rename would have promoted every existing `strict` advertisement into a claim no host substantiated, and its latency content is not lost because `replicationLagBoundMs` already carries it. **`partitionRecoveryStrategy`** offered `last-writer-wins` and `first-writer-wins`, both time-ordered — but under a partition there is no shared clock, so each region believes it wrote last, which cannot satisfy the annex MUST that "re-running the same conflict input MUST produce the same survivor", and both select a different survivor than the lex-min(runId) rule the same document requires. **The schema was advertising strategies that violate two MUSTs already in force.** RFC 0150 §D names only `last-writer-wins`; removing that alone would have left the identical defect under a different label, so both went and `lexicographic-min-run-id` was added to name the rule the annex actually requires. The gate also catches the unparseable ```json example RFC 0149 §B found and deliberately left. Corpus-structural tier: it reads the schema and the prose, not a host — whether an engine fences before issuing an effect needs a partition simulator plus an observable effect sink, which the existing seam does not provide. 2026-08-12 (RFC 0150 §B — Layer-2 effect identity v2, **safety-fix**, suite `1.76.0 → 1.77.0`) added one: `effect-identity-composition.test.ts` (six always-on server-free legs, skipped under the published layout). `spec/v1/idempotency.md` specified the Layer-2 key as `sha256(runId ':' nodeId ':' attempt ':' providerKey)` while the same document promised that a retried call's identity "is identical" — **both cannot hold**, and the formula was the wrong half. A retry counter in the preimage gives every retry a fresh key, so the invocation log never hits, and because the engine injects that value as the provider's `Idempotency-Key`, it also sends Stripe or OpenAI a different key each attempt — defeating the provider-side dedup the same paragraph invokes as its safety net. v1.2 specifies the domain-separated, tenant-bound composition over a `logicalInvocationOrdinal` that MUST NOT change across retries. **The gate's tier is labelled corpus-structural on purpose:** it reads the normative composition, not a host, because whether an engine reuses the identity across a retry is observed by the *provider*, not the caller, and a wire probe claiming otherwise would be the vacuous-witness pattern RFC 0148 exists to close (gap G9). Sabotage: weakening the ordinal rule to `SHOULD NOT`, or deleting it, reds the leg. 2026-08-12 (RFC 0149 §B — discovery-example root layout, editorial, suite `1.75.0 → 1.76.0`) added one: `capability-example-root-layout.test.ts` (three legs, server-free, skipped under the published layout because `spec/v1/` and `RFCS/` are not in the tarball). RFC 0073 made the document-root layout "the normative MUST since Phase 1" and, at Phase 4, made the suite grade a wrapper-only host non-conformant — the `capabilities` wrapper survives only as a deprecated shape runtime discovery tolerates until v2.0. **Tolerating a shape at runtime and teaching it in a normative example are different things:** eight `spec/v1` examples, several under headings like "Capability advertisement (normative)" introduced by prose saying hosts "advertise it under `/.well-known/openwop`", showed the deprecated wrapper. An implementer copying one produced a document RFC 0073 grades as non-conformant, and no gate noticed, **because a fenced example is prose to every validator in the corpus**. All eight unwrapped. Authoring-time only — nothing here reads a host, and RFC 0149 §B keeps runtime discovery open to unknown server-emitted properties. The RFC leg asserts the historical carve-out rather than assuming it: every `RFCS/` example still showing the wrapper is in an RFC numbered **below 0073**, so a *new* post-0073 RFC introducing one fails and the exemption cannot widen into a licence. Sabotage: restoring one wrapped example reds the lint with its file:line. 2026-08-12 (RFC 0148 §C / gap G6 — floor enforcement, implementation of existing normative text, suite `1.74.0 → 1.75.0`) added one: `certification-floor-enforcement.test.ts` (six always-on server-free legs). `PROFILE_FLOOR_SCENARIOS` defined a floor for `openwop-core-standard` alone, and `verifyBundleProfile()` computed `floorProven` from `missingFloor.length === 0 && prefixOk` — **both vacuously true over an absent floor**, so a claimed profile with nothing behind it verified as *proven*. **The floors were transcribed, not invented:** `profiles.md` §"Claiming vs passing" already requires "predicate AND passing the conformance scenarios labelled with the profile tag", and its per-profile sections already name them — so this enforces normative prose rather than adding to it, and needs no safety-fix window. **An empty floor and an unwritten floor are now different values:** `openwop-core` and `openwop-fixtures` are discovery-payload-only by prose and carry an explicit `discoveryOnly` marker; an absent key means unprovable, surfaced as `floorUnspecified` so "the corpus has no floor" stays distinct from "the host failed its floor". `openwop-replay-fork` is deliberately left unspecified — its floor is conditional on the advertised mode, which a flat required-list cannot express, and forcing it would either fail an honest single-mode host or restore the vacuity. Sabotage: restoring the old undefined-floor branch reds two legs. 2026-08-11 (RFC 0149 §A — canonical URL resolution, editorial, suite `1.73.1 → 1.74.0`) added one: `openapi-resolved-paths.test.ts` (three always-on server-free legs). It resolves each `servers[].url` against each path key and asserts exactly one `/v1` segment for versioned operations. **Why every existing gate was blind to this:** `redocly lint` validates the server, validates the paths, and never composes the two — the defect existed only in the join, where all 44 versioned path keys resolved to `/v1/v1/*`. The reference SDKs were the control: `OpenwopClient` issues `/v1/runs` against a bare base URL, so the SDKs and the canonical document disagreed about where the version segment lives and the SDKs were correct. A third leg asserts `/.well-known/*` resolves unversioned — the red run showed the duplicated base also resolved discovery to `/v1/.well-known/openwop`, so a generated client could not bootstrap at all. A guard leg fails if the extraction finds no servers or no paths, because a scan that silently matched nothing would make the other legs vacuously true. Written red first, observed failing on both counts, then green after the one-line correction. 2026-08-11 (RFC 0146 — `contractProvenance`, additive, suite `1.72.2 → 1.73.0`) added one: `contract-provenance.test.ts` (four always-on corpus legs + one behavioral). **Why validation alone cannot catch what this closes:** v1.x changes are additive, so a discovery document written against an older contract still validates against the newer schema — which is exactly why a host validating against a vendored copy 7 properties behind was green. Only a claim on the wire surfaces it. The legs assert the SHAPE of that claim and never that a host is current, because a host on an older corpus revision is CONFORMANT; a leg failing a host for being behind would convert an optional disclosure into a de-facto upgrade mandate inside a version line where being behind is permitted. Sabotage: dropping the property reds A1/A2/A3; relaxing `corpusCommit`'s 40-hex pattern reds A2 alone; opening the object reds A3 alone; softening the RFC's advisory MUST NOT reds A4 alone. 2026-08-11 (RFC 0144 G1 — which resolver arm a host lands on, suite `1.71.1 → 1.72.0`) added one: `capability-arm-witness.test.ts`. Every capability helper resolves a family through four arms — plain at root (canonical), dotted at root, plain under the deprecated `capabilities` wrapper, dotted under it — and because arms 2–4 succeed silently, **a host that never migrated reads exactly like one that did**. The suite's own tolerance was hiding the drift. The leg **enforces an existing MUST rather than adding one**: `capabilities.md` §"Document-root layout" already says *"the conformance suite reads the root only … a host that serves families exclusively under the wrapper is non-conformant and is graded as such"* — but the helpers fall back, so the corpus said one thing and the code did another. Asserted: no family reachable ONLY under the wrapper. Reported, not asserted: dotted-at-root spellings — RFC 0137 G16 makes the plain name the discovery key, but `capabilities.md`'s MUST is about the root rather than the spelling at it, so failing there would be a v1.x tightening this leg has no license for. Sabotage-verified across six placements: canonical passes; root+wrapper *mirrored* passes (mirroring is a permitted v1.x affordance); root-dotted passes **and reports**; wrapper-only and wrapper-dotted both fail. 2026-08-10 (RFC 0145 — `registrationSource` as a per-type artifact capability facet, additive, suite `1.69.0 → 1.70.0`) added one: `artifact-type-registration-source.test.ts` (five always-on corpus legs. The facet discloses which §"Schema distribution" regime a registered type falls under — serving the canonical schema URL is a MUST for host-registered (no-pack) types and only a SHOULD for pack-backed ones, and nothing in discovery said which. A2 is the load-bearing leg and is the deliberate INVERSE of RFC 0136's `format`: an out-of-enum value is REJECTED, because this facet has exactly two meanings and rides a server-emitted document, where `format` is an advisory hint on a client-submitted closed shape that must degrade rather than fail. A3 pins the discovery enum against `artifact.created.registrationSource` so the two surfaces requirement 3 forbids from disagreeing cannot drift out of comparability. Sabotage: dropping the schema property reds A1/A2/A3 and leaves the prose legs green; widening the enum reds the same three; removing the facet from either prose site reds A4 alone; relaxing the no-pack serving MUST reds A5 alone. NOT built — cross-surface agreement (requirement 3) against a live host, carried as RFC 0145 G1: no host advertises the facet yet, so the leg would be vacuously green). 2026-08-10 (RFC 0136 — `WorkflowVariable.format`, additive, suite `1.68.2 → 1.69.0`) added one: `workflow-variable-format.test.ts` (five always-on corpus legs + two capability-gated host legs. The load-bearing leg is A2, which asserts a format value OUTSIDE the v1 recognised table still validates — the property is deliberately NOT an enum, because a workflow definition is a client-submitted CLOSED shape where an enum would turn an unrecognised hint into a hard `POST /v1/workflows` failure and contradict requirement 2. Sabotage: adding `"enum"` to the schema property reds A2 alone, leaving A1 green. Host legs gate on `workflowChainPacks.deferredParameters.supported` — the only mode that mints a `WorkflowVariable` from a chain parameter, so the only mode where `format` propagation can be a MUST). 2026-08-09 (RFC 0143 — tool-result trust monotone through composition, additive, suite `1.67.1 → 1.68.0`) added one: `tool-result-trust-monotone.test.ts` (always-on server-free — the general rule the corpus's ~ten point-invariants instance: a COMPLETENESS leg asserts every §4 STRIDE ingress the threat model names has a real fencing invariant + a curated floor of prompt-ingress surfaces, so a new ingress shipped without a fence reds it; the meet-semilattice rule is stated normatively in §2a; and the MCP/A2A + compose-boundary instances cross-reference the general rule. Host behaviour through the durable-store hop is witnessed at openwop-app, not here. Sabotage-verified one-per-surface: renaming a floor invariant reds the completeness leg, softening the meet reds the prose leg). 2026-08-08 (RFC 0140 — replay side-effect suppression, additive, suite `1.66.0 → 1.67.0`) added one: `replay-side-effect-suppression.test.ts` (capability-gated on `replay.sideEffectSuppression: "recorded-outcome"`. The load-bearing leg is the FAIL-CLOSED path, not the happy path: a node replayed from a recorded outcome is log-indistinguishable from one that re-fired and recorded the same thing, but a node with NO recorded outcome is not — a non-suppressing host completes it, a suppressing host must emit `replay_source_missing`. That asymmetry is what lets the leg run with no operator-side effect instrumentation. Uses the conformance-RESERVED `core.conformance.side-effect` typeId, host-mapped to a genuinely side-effecting node. Non-vacuity proven with TWO sabotages against the reference host, one per suppression mechanism: disabling both reds it; leaving only the host's runtime backstop keeps it green, which is the evidence for the whole-run guarantee in §B.4). 2026-08-08 (RFC 0141 — legacy artifact-type identifiers, additive, suite `1.64.0 → 1.65.0`) added one: `artifact-type-legacy-ids.test.ts` (always-on server-free prose-pinning — a bare legacy id is rejected by the manifest schema while a canonical id validates, and the corpus states normatively that legacy ids were never wire-conformant with no grandfather clause, that a migrating host MUST NOT rewrite historical `artifact.created.artifactType` values, that the read-side alias is permanent and MUST resolve where validation is decided, and that an alias map is a host shim, not a conformance claim. Host-side alias behaviour is witnessed at openwop-app, not by this suite; a rewritten log is undetectable after the fact). 2026-08-07 (RFC 0139 — host-side witness for pack-manifest extension opacity, additive, suite `1.63.0 → 1.64.0`) added one: `pack-manifest-extension-opacity.test.ts` (gated on `behaviorGate` — the host-side half RFC 0138 could not provide. The load-bearing leg is DIFFERENTIAL, not presence: install the same manifest with and without an unrecognized `vendor.conformance.*` extension and require the registration projection to be identical once extensions are stripped. Sink-agnostic, because a suite cannot enumerate a host's sinks. Measured against stub hosts — a violating stub that routes an unrecognized extension into a derived facet PASSES the presence legs and fails only the differential ones. Witnesses INSTALL-TIME sinks only; does not witness `artifact.created` (RFC 0138 G8) since this seam emits no run events. Landed with the G14 flip: `artifact-type-pack-install`, `artifact-type-store-without-render` and `chat-card-pack-execution` moved from bare `return` to `behaviorGate`, so advertised-with-no-seam now FAILS under `OPENWOP_REQUIRE_BEHAVIOR=true` instead of reporting green). 2026-08-06 (RFC 0138 — vendor-extension hatch on pack manifests, additive, suite `1.62.0 → 1.63.0`) added one: `pack-manifest-extensions.test.ts` (always-on server-free — every pack manifest root admits the `^(x-|vendor\.)` hatch, enumerated against an explicit in-scope count of 9 rather than a naming glob, because the first draft globbed `*-pack-manifest.schema.json` and silently skipped `frontend-plugin-manifest.schema.json`; the hatch stays NARROW — a misspelled canonical field is still rejected and no pattern anywhere matches a bare canonical-looking key; and the corpus states the MUST-ignore, the "ignore means ignore" definition, the pack-authored/untrusted framing, and the not-a-capability-channel rule normatively, since the schema alone cannot express "MUST ignore". Host-side honoring of MUST-ignore is NOT covered — that needs a host-sample seam behind `behaviorGate`, gaps G6/G7). 2026-08-05 (RFC 0137 — the behavioral half, suite `1.60.1 → 1.61.0`) added one: `form-content-instantiation.test.ts` (capability-gated on `host.forms.contentPacks` + the `POST /v1/host/sample/formcontent/instantiate` seam — instantiation goes through the host's NORMAL create path with no pack-bound routing destination, an unrecognized `vendor.*`/`x-` field type DEGRADES to a plain text input rather than failing, and pack-authored fields stay fully editable. Added because RFC 0137's original graduation gate was unsatisfiable: every leg it shipped was server-free and passed identically against a host that never implemented it). 2026-08-05 (RFC 0137 — form-content packs, additive, suite `1.58.0 → 1.59.0`) added one: `form-content-packs.test.ts` (always-on server-free corpus legs — the registry version manifest carries `kind: "form-content"`, the `templates` payload property AND the load-bearing `anyOf` payload branch; the new source manifest enforces the schema-discipline floor and rejects `email`/`textarea` as field types, `key` in place of `id`, an integer `templates[].version`, and any `runtime`; and — the regression guard that matters — `fields[].type` is asserted byte-identical to chat-card `inputs[].type` so neither declarative kind's field vocabulary can be widened alone. The host-side instantiation + trust-boundary behavior is capability-gated on `host.forms.contentPacks` and host-pending). 2026-07-23 (RFC 0135 — workflow-chain gallery visibility, additive, suite `1.57.0 → 1.58.0`) added one: `workflow-chain-internal-flag.test.ts` (always-on server-free corpus legs — the manifest §WorkflowChain carries a boolean `internal`, an `internal: true` chain validates and a non-boolean is rejected, and the spec pins the MUST-omit-from-default-gallery + not-an-authorization-boundary rules; the gallery-omission behavior is witnessed at the reference host, not over the wire). 2026-07-23 (RFC 0134 — edge-condition `truthy`/`falsy` operators, additive) added one: `edge-condition-truthy-falsy.test.ts` (always-on corpus legs — the `workflow-definition` + inlined manifest `§EdgeCondition` `type` enums carry `truthy`/`falsy`, a no-`right` truthy/falsy edge validates, the spec documents the no-`right`+required-`left` semantics — plus a capability-gated host-mapping leg that soft-skips until a reference host maps the operators). 2026-07-22 (RFC 0133 — workflow-chain composition, suite `1.55.1 → 1.56.0`) added five: three always-on server-free scenarios (`chain-subchain-sibling.test.ts` — sub-chain co-registration mints a deterministic child id + rewrites `config.subChainRef` → the child `config.workflowId` + dedups a doubly-referenced child; `chain-subchain-cycle-rejected.test.ts` — the public witness for `sub-chain-expansion-bounded`: self-composition AND a depth-bound breach both reject with `sub_chain_cycle`, an acyclic tree within the bound expands, an unresolvable ref is `sub_chain_unresolved`; `chain-produced-var-roundtrip.test.ts` — `producedVariables` emit into `variables[]` with no value + closed-world `variable_undeclared` rejection) plus two capability-gated scenarios (`chain-subchain-fanout.test.ts` — a `core.dispatch` child-run over a `subChainRef` worker + the manifest `not`-guard on a concrete `config.workflowId`, behavioral home of `sub-chain-child-tenant-scoped`; `chain-subchain-unsupported-refused.test.ts` — an unsupported host refuses a `subChains`-bearing chain with `sub_chain_unsupported` (422), never flattening) that soft-skip until a reference host wires runtime child dispatch. 2026-07-22 (RFC 0132 — anonymous-actor authorization) added six: `anonymous-actor-shape.test.ts` (always-on, server-free — validates the `capabilities.anonymousActor` advert + the §B.2 `writeEgressControls`-iff-`bounded-write-egress` conditional + `owner.principalKind` + the RFC 0049 `authorization.decided` audit reuse) plus five capability-gated behavioral scenarios (`anonymous-actor-default-deny`, `-no-secret-reach`, `-egress-guarded`, `-write-gated`, `-audit-opaque`) that drive the `/v1/host/sample/anon-surface/{tools,dispatch}` seam and soft-skip until a host wires a tool-enabled public surface — each the public witness for a reference-impl-tier SECURITY invariant that graduates to protocol tier once a host passes it non-vacuously. 2026-07-07 (RFC 0131 — agent-manifest `role` + the Skill profile) added `agent-manifest-role-profile.test.ts` (always-on, server-free schema-shape probe of the additive optional `AgentManifest.role` + the schema-encoded Skill profile: a `role:"skill"` manifest with `handoff` + scratchpad-only memory validates; one declaring `conversation`/`longTerm` memory or omitting `handoff` FAILS validation — a malformed-manifest reject, NOT an RFC 0072 `degraded[]` runtime tier; an absent `role` with any `memoryShape` validates unconstrained; a bad enum value fails — the public witness for `agent-skill-profile-stateless`). 2026-07-06 (RFC 0129 — data-residency, suite `1.53.1 → 1.54.0`) added `data-residency-admission.test.ts` (always-on `capabilities.dataResidency` + `residency.schema.json` shape probes + `residency_unavailable` error-registration check; plus capability-gated behavioral legs driving the NORMATIVE `POST /v1/runs` endpoint — an advertised region MUST NOT be rejected `residency_unavailable`, an unadvertised region MUST be rejected with that code at HTTP one-of 400/404/422 and create no run — advertise-only-what-you-honor, soft-skip until a host advertises `dataResidency`). 2026-07-06 (RFC 0127 + RFC 0128 — CDP Track-2, suite `1.52.0 → 1.53.0`) added `trigger-stream-cdc-sources.test.ts` (always-on schema probes for the `stream`/`change` TriggerEvent sub-objects — `op` REQUIRED negative, exactly-one rule, registration + capabilities vocabulary pins — plus capability-gated behavioral legs driving the existing `/v1/host/sample/trigger-bridge/ingest` + `/deliver` seams: schema-valid delivered envelopes, SR-1 content-free durable events with a body canary, `(topic,partition,offset)` dedup effectively-once) and `purpose-propagation.test.ts` (always-on `permittedPurposes` + `capabilities.purposePropagation` family shape probes, plus the capability-gated two-hop legs via the new `POST /v1/host/sample/purpose-propagation/forward` seam: onward label ⊆ received, derived-output ⊆ intersection of labelled inputs, unlabelled adds no constraint, `[]` fail-closed dropped with an unlabelled positive control). Both behavioral suites soft-skip pre-implementation and become REQUIRED once the host advertises the surface (advertise-only-what-you-honor). 2026-07-05 (RFC 0013 erratum A-lite — bundle + load the sample-pack fixture, suite `1.51.0 → 1.52.0`) bundled the `vendor.openwop.workflow-chain-sample` pack into the conformance package at `fixtures/pack-manifests/workflow-chain-sample.pack.json` (host-syncable, ships in `files`) and refactored `workflow-chain-host-expansion.test.ts` to **load** it + derive the expected expansion from the `expandChain()` reference library instead of hardcoding — so a live host serving `POST /v1/host/sample/workflow-chain:expand` is checked against the spec algorithm for the identical published pack (closes the RFC 0013 host-expansion witness's fixture gap; the seam still soft-skips until a host advertises `workflowChainPacks.hostExpansionSeam`). `fixtures-valid.test.ts` now schema-selects pack-manifest fixtures by `kind` (node-pack vs workflow-chain-pack). No scenario-file count change. 2026-07-05 (RFC 0013 erratum — host-expansion test seam decouple, suite `1.50.0 → 1.51.0`) re-gated `workflow-chain-host-expansion.test.ts` from the semantic `workflowChainPacks.supported` claim onto a new OPTIONAL `workflowChainPacks.hostExpansionSeam` test-harness sub-flag (no scenario-file count change), so a host advertising `workflowChainPacks.supported` / RFC 0124 `deferredParameters.supported` is no longer conscripted into the never-bundled `vendor.openwop.workflow-chain-sample` seam under `OPENWOP_REQUIRE_BEHAVIOR` — the semantic claim rides the server-free `workflow-chain-expansion.test.ts` legs, RFC 0124's deferred path its own `/chain/deferred-expand` seam. 2026-07-04 (RFC 0124 — portable per-run parameter deferral, suite `1.49.0 → 1.50.0`) added `workflow-chain-deferred-parameters.test.ts` (always-on, server-free legs against the reference `expandChainDeferred` in `conformance/src/lib/workflow-chain-expansion.ts`: non-sensitive deferral materializes `variables[]` with `defaultValue`+`type` and leaves ZERO `{{params.*}}` tokens (R3), a whole-value input token → variable-sourced PortValue, the bare param name is the auto-generated `configurableSchema` override key (R6); §Security legs: a `x-openwop-sensitive` prompt-body param materializes `source:"secret"` with the plaintext appearing NOWHERE — not bagged — a sensitive whole-value `node.input` fails closed `sensitive_param_not_deferrable` (422), a sensitive param on a host without `secrets` support fails closed, and a host without a `prompts.variable` source falls back to expansion-time (G5); plus schema-surface legs pinning the amended `source:"secret"` wording in the manifest schema + the `credentialRef` per-run supply shape; capability-gated host legs over `POST /v1/host/sample/chain/deferred-expand` for the bare-param override / `:fork` replay / `contentTrust:"untrusted"` fence / `[REDACTED]` sensitive compose, soft-skip 404/403). 2026-07-04 (RFC 0126 — data-parallel dispatch per-item input, suite `1.48.0 → 1.49.0`) added `dispatch-per-item-input.test.ts` (always-on, server-free schema legs on `orchestrator-decision.schema.json` §NextWorkerDecision: a well-formed index-aligned `nextWorkerInputs` validates, a decision omitting it stays valid (additive/back-compat), a non-object item and a non-array are rejected, a mis-named `perItemInputs` is rejected by `additionalProperties:false` (the fail-closed rail for pre-RFC-0126 strict validators), and a length-mismatch is ADMITTED at the wire because `nextWorkerInputs.length == nextWorkerIds.length` is not JSON-Schema-expressible — a host runtime MUST; capability-gated behavioral legs over `POST /v1/host/sample/dispatch/per-item` asserting a host advertising `capabilities.dispatch.perItemInput` projects `nextWorkerInputs[i]` into child `i` (per-item value wins over `inputMapping`), a length-mismatch fails with a `validation_error` dispatching no child, and a host NOT advertising the capability fails closed on a non-empty `nextWorkerInputs` rather than silently dropping it and dispatching N identical children; soft-skips on 404/403). 2026-07-02 (RFC 0122 — self-hosted runner, suite `1.47.0 → 1.48.0`) added `self-hosted-runner.test.ts` (always-on schema legs for the `selfHostedRunner` capability block + the dispatch/result/registration frame shapes; an advertisement-gated block-shape leg; capability-gated behavioral legs over `POST /v1/host/sample/runner/{register,dispatch}` asserting subject-first isolation, retriable `runner_unavailable`, and at-most-once dedup — the public test for the protocol-tier `runner-credential-non-transit` + `runner-output-untrusted-transport` invariants; soft-skips on 404). 2026-07-01 (RFC 0121 — subscription-reuse provider auth mode, suite `1.46.0 → 1.47.0`) added `aiproviders-subscription-scope.test.ts` (always-on schema leg: the `aiProviders.authModes` closed enum includes `subscription`; §B.7 advertisement-gated leg: a `subscription` provider MUST appear in `byok`; §B.8 bind-seam-gated leg over `POST /v1/host/sample/credentials/bind` asserting a tenant-scope binding is rejected with `credential_scope_forbidden` — the public test for the protocol-tier `subscription-credential-user-scope-only` invariant. §B.8 is gated on the seam rather than on advertisement, so a host that cannot lawfully advertise `subscription` can still witness the user-scope safety rail; soft-skips when the seam is unwired). 2026-06-29 (RFC 0120 — connection-pack `apiHosts` credential-egress allow-list, suite `1.45.0 → 1.46.0`) added `connection-pack-apihosts.test.ts` (always-on schema legs: the `connection-pack-apihosts-valid` fixture validates, an `openapi`-reach provider omitting `apiHosts` is rejected by the conditional-MUST `allOf`, and IP/wildcard/port/single-label/uppercase entries are each rejected; always-on matching-rule legs: the item-10 dot-anchored eTLD+1 suffix-containment rule permits subdomains + a tighter exact host and fails closed with no substring/suffix/prefix escape — the public tests for the protocol-tier `connection-pack-api-host-shape` + `connection-pack-egress-host-bound` invariants; plus a capability-gated behavioral egress allow-list leg over the new `POST /v1/host/sample/connection-packs/egress-check` seam, soft-skipping when unadvertised/unwired). 2026-06-28 (RFC 0118 — parallel sub-workflow fan-out and join, suite `1.44.0 → 1.45.0`) added `dispatch-fanout-parallel.test.ts` (always-on schema legs for `dispatch-config.schema.json` — accepts a valid `parallel` config + each `joinPolicy.mode` + `maxConcurrency`, rejects unknown enum values / `additionalProperties` on `joinPolicy` / non-positive `maxConcurrency`, keeps a pre-RFC-0118 config valid — and the `dispatchFanOut`/`dispatchJoin` event `$defs` of `run-event-payloads.schema.json` — `fanOutPolicy` const `parallel`, `childCount ≥ 2`, the required replay-deterministic `mergeOrder`; capability-gated behavioral legs over `POST /v1/host/sample/dispatch/fanout` (wait-all/collect → `joinOutcome: satisfied` + full `children[]` + `mergeOrder`) plus the un-gated registration-rejection leg (`fanOutSupported:false` host MUST reject `parallel` with a 4xx); soft-skips on absent `dispatch.fanOutSupported` / `parallel` ∉ `fanOutPolicies`). 2026-06-27 (RFC 0117 — front-end plugin packs, suite `1.43.0 → 1.44.0`) added `frontend-plugin-packs.test.ts` (always-on schema legs for `frontend-plugin-manifest.schema.json` + the `ui-plugin/1` envelope `ui-plugin-message.schema.json`: manifest validity, `runtime`-forbidden, path-traversal-guarded `entry`, the closed `hostApi` allowlist, the version-token `artifact_conflict` + `currentVersion` concurrency shape, and no credential-bearing envelope field (`additionalProperties:false`); the capability-shape leg asserts `isolation` pins to the `cross-origin-iframe` const; capability-gated behavioral legs over `POST /v1/host/sample/ui-plugin/rpc` assert an undeclared method → `method_not_allowed` and a stale `artifact.write` → `artifact_conflict` with no persist; soft-skips on absent `capabilities.uiPlugins.supported` or `404`/`403` on the seam (RFC 0117 stays Active pending host witnesses); the public test for the protocol-tier `frontend-plugin-{isolation,egress,rpc-allowlist,no-byok}` invariants). 2026-06-26 (RFC 0116 — portable prompt-prefix cache, suite `1.42.0 → 1.43.0`) added `prompt-prefix-cache.test.ts` (advertisement-shape on `aiProviders.promptPrefixCache` + behavioral legs over the OPTIONAL `POST /v1/host/sample/ai/generate` seam (`host-sample-test-seams.md` §16): (a) outcome-invariance — a generate with `cachePrefixId` and a control without produce the same accepted envelope + identical `provider.usage.inputTokens`/`outputTokens` (cost-hint-only, replay-invariant); (b) cache-hit observable — a repeat generate shows `cacheReadTokens > 0`; (c) cross-tenant isolation — tenant B’s first use of tenant A’s `cachePrefixId` shows `cacheReadTokens == 0`, the public test for the protocol-tier `prompt-prefix-cache-cross-tenant-isolation` invariant (the host MUST key its provider cache by `(tenant, cachePrefixId)`, never global); (d) secret-free — the cost-only cache-token fields carry no prompt substrings (SR-1); soft-skips on absent `aiProviders.promptPrefixCache.supported` or `404`/`405` on the seam, since RFC 0116 defers reference-host impl as provider-gated). 2026-06-26 (RFC 0114 — A2UI surface deltas, suite `1.41.0 → 1.42.0`) added `a2ui-surface-delta-transport.test.ts` (always-on legs use a cast-free, dependency-free client-side RFC 6902 applier + Ajv2020 to assert: the new `a2ui-surface-delta-frame.schema.json` compiles, the op enum excludes `test`, a full surface + delta frames reconstruct the expected tree AND equal the full a non-negotiating subscriber materializes and re-validate against the closed catalog, an out-of-catalog/script-bearing delta fails closed-catalog validation post-patch — the `a2ui-surface-no-code-exec` boundary holds — and the recorded envelope is always the full surface; the HTTP leg is capability-gated on `a2uiSurface.deltaTransport` and soft-skips on absent host/capability or `404`/`405` on the OPTIONAL `GET /v1/host/sample/a2ui/surface/materialized` seam). 2026-06-26 (RFC 0111 — context economy, suite `1.40.0 → 1.41.0`) added `context-budget-transcript-bound.test.ts` (capability-gated on `multiAgent.executionModel.contextBudget.transcriptTokenBudget` being present via `behaviorGate(openwop-context-budget, …)` — drives the `conformance-context-budget-multiturn` orchestrator fixture, reads the host’s per-iteration accounting via the OPTIONAL seam `GET /v1/host/sample/agent/transcript-window?runId=…&iteration=N` (`host-sample-test-seams.md` §14), and asserts `tokenCount ≤ transcriptTokenBudget` in the advertised `tokenCounter` unit, that every `eventId` in the seam accounting is a real persisted run event (internal-consistency cross-check against `/v1/host/sample/test/runs/:runId/events`), recent-tail + no-double-count, every `summarizedRanges.summaryRef` has a matching `context.summarized` event, and `keepLastTurns` recent turns are fed verbatim — never inside a summarized range; soft-skips on `404`/`405` since the RFC defers reference-host impl) + `context-summarization-replay.test.ts` (capability-gated on `multiAgent.executionModel.contextBudget.summarization.supported` via `behaviorGate(openwop-context-summarization, …)` — replays the run via `:fork mode:replay` and asserts the recorded `context.summarized` → `summaryRef` records are REUSED, never re-summarized, the direct analogue of RFC 0041 envelope-refusal recovery; soft-skips when the event-log seam is unwired, no `replay` mode is advertised, or the run produced no summarization). 2026-06-26 (RFC 0113 — memory injection budget, suite `1.39.0 → 1.40.0`) added `memory-injection-budget.test.ts` (capability-gated on `memory.injectionBudget.supported === true` via `behaviorGate(openwop-memory-injection-budget, …)` — drives the `conformance-agent-memory-injection-budget` fixture through the host-sample memory seam and asserts the budgeted injection read's cumulative tokens ≤ the requested `tokenBudget` in the advertised `tokenCounter` unit (`o200k_base`/`cl100k_base`/`chars`/`host-defined`), an over-budget single entry is omitted not truncated, and re-asserts SR-1 (`[REDACTED:<secretId>]` content) + CTI-1 (cross-tenant probe returns empty) on the budgeted path; the `rank:'relevance'` leg DELEGATES to `memory.search` semantic (RFC 0080) and asserts relevance ordering differs from recency ONLY when the host ALSO advertises `memory.search` semantic, else it soft-skips — there is NO ranking primitive in `injectionBudget`; soft-skips on hosts that do not advertise `memory.injectionBudget`). 2026-06-26 (RFC 0112 — compact tool projection, suite `1.38.0 → 1.39.0`) added `tool-catalog-compact-projection.test.ts` (capability-gated on `toolCatalog.compactView === true` via `behaviorGate(openwop-tool-catalog-compact, …)` — drives `GET /v1/tools?view=compact` and asserts the host returns the `{ tools: CompactToolDescriptor[] }` envelope where every descriptor validates against `compact-tool-descriptor.schema.json` with the heavy `ToolDescriptor` fields dropped, every present `inputSchema` satisfies the self-contained compact structural subset (top-level `type:"object"`+`properties`; no `$ref`/`oneOf`/`allOf`/`anyOf`/`not`/`patternProperties`/`dependentSchemas`), and the compact `tools[]` `toolId` set EQUALS the standard view set for the same principal (projection completeness); soft-skips on hosts that do not advertise `toolCatalog.compactView`). 2026-06-26 (RFC 0115 — run transport economy, suite `1.37.0 → 1.38.0`) added `run-transport-economy.test.ts` (capability-gated on `restTransport.conditionalRunGet === true` and a non-empty `restTransport.contentEncodings` — drives `GET /v1/runs/{runId}` and asserts a sequence-derived strong `ETag` on the `200`, `If-None-Match` → `304` with an empty body while the run is unchanged, the `ETag` ROTATES after the `conformance-approval` fixture advances `waiting-approval → completed` (proving it derives from the latest persisted event-log sequence, not a coarser signal that would leave a `304` stale), and each advertised `Content-Encoding` (`gzip` baseline; `br`/`zstd` optional) round-trips byte-identically to the identity body; soft-skips on hosts that do not advertise `restTransport`). 2026-06-24 (RFC 0110 — channel presence, behavioral leg) added `channel-presence-behavioral.test.ts` (capability-gated on `channelPresence.supported` via `behaviorGate('openwop-channel-presence', …)` — drives the `POST /v1/host/sample/channel-presence/snapshot` seam and asserts a live `channel.presence` snapshot is the CLOSED `{conversationId,present,typing}` shape (no PII), every ref is an opaque RFC 0041 `user:`/`agent:` subject, `typing ⊆ present`, and the snapshotting member is non-vacuously present; soft-skips on 404/405 — a host whose presence is bound to a product flow witnesses via its own route test + an INTEROP-MATRIX row, the RFC 0086 dual-staging). 2026-06-24 (RFC 0110 — channel presence, Accept cycle) added `channel-presence-shape.test.ts` (always-on server-free — the OPTIONAL `channel.presence` ephemeral payload validates a conforming snapshot, REQUIRES `conversationId`+`present`, is CLOSED `additionalProperties:false` (the no-PII guard), `typing` optional; `channel.presence` is in the `RunEventType` enum; the `channelPresence` capability block is declared + closed). 2026-06-24 (RFC 0109 — conversation-turn model provenance, Accept cycle) added `conversation-turn-model-provenance-shape.test.ts` (always-on server-free — `agent.model` `{provider, model}` validates conforming / both-required / closed-SR-1 / optional-back-compat, + the `conversationTurnModelProvenance` capability declared + closed). 2026-06-24 (RFC 0108 — self-hosted / OpenAI-compatible provider class, Accept cycle, suite `1.36.0 → 1.37.0`) added the gated behavioral honesty leg `aiproviders-selfhosted-honesty.test.ts` (gated on `aiProviders.selfHosted.length > 0` via `behaviorGate('openwop-selfhosted-providers', …)` — drives `POST /v1/host/sample/ai/call` against an advertised `selfHosted` id and asserts **§A.2** the dispatch reaches a real configured endpoint (success or transport error — never `capability_not_provided` / `provider_not_supported`, which would prove a dishonest advertisement with no endpoint behind it) and **§D** the endpoint location — supplied out-of-band via `OPENWOP_TEST_COMPAT_ENDPOINT`, checked as the raw string + bare `host`/`host:port` — never appears in the seam response or error payload; soft-skips on 404 / when the env var is unset for the §D leg). 2026-06-24 (RFC 0108, suite `1.35.0 → 1.36.0`) added the always-on server-free shape leg `aiproviders-selfhosted-shape.test.ts` (the additive `aiProviders.selfHosted` advertisement: a `string[]` with `uniqueItems`/`minLength:1` items, absent from `aiProviders.required`, validates a conforming array via Ajv2020 while rejecting non-array / duplicate / empty-string forms, and enforces the two §A rules JSON Schema cannot express — §A.1 every `selfHosted` entry is a subset of `supported`, and §A.3 / `self-hosted-endpoint-no-disclosure` no entry is URL-shaped (`://`, bare `host:port`, or leading `/` path) — exercised against good/bad example docs). 2026-06-23 (RFC 0106 — real-time voice session profile, Accept cycle) added six gated behavioral scenarios driving the openwop-app live host (rev `00293-89w`): `voice-transcription-streaming` + `voice-transcription-unadvertised` (the `call-transcriber` seam; the latter gated-by-absence), `voice-synthesis-streaming` (the `stream:true` synthesis arm → metadata-only `voice.synthesis_chunk` events), `voice-bargein-no-partial-leak` (the `/voice/barge-in` seam — `voice.barge_in`→`voice.cancelled` with no chunk after; **graduated `voice-bargein-no-partial-leak` reference-impl→protocol** on the live proof), and `voice-interim-not-durable` + `voice-streamref-tenant-bound` (§F INV-1/INV-4; soft-skip on the §E `transcription_unsupported` / no-live-streamRef path — stay reference-impl until a host with a scripted-interim / live-streamRef arm proves them). 2026-06-23 (RFC 0107 — publishable declarative pack kinds) added one: `registry-declarative-kinds.test.ts` (always-on server-free — the registry version-manifest carries the `kind` discriminator + per-kind declarative payload, `runtime` is conditional on `kind` via `allOf if/then/else`, published artifact-type and connection manifests validate, and a declarative-with-`runtime` or node-without-`runtime` manifest is rejected). 2026-06-23 (RFC 0107 correction, suite `1.34.0 → 1.35.0`) extended that scenario with two cases — a published **chat-card** pack manifest (`kind: "card"`, RFC 0071) validates, and the never-canonical `kind: "chat-card"` is **rejected** — fixing a kind-string mismatch where RFC 0107's published schema enumerated `chat-card` while RFC 0071 (authoritative) defines `card` (no scenario-file count change; cases added to the existing file). 2026-06-23 (RFC 0106 — real-time voice session profile, Phase 2) added one: `voice-event-payloads-shape.test.ts` (always-on server-free — all seven `voice.*` types are in the `RunEventType` enum, each has a payload `$def` via `typeIndex`, `voice.transcript` REQUIRES `contentTrust:"untrusted"` (the schema-enforced half of `voice-transcript-untrusted`), `voice.synthesis_chunk` is metadata-shaped (seq+mimeType required; bytes by `url`/`streamRef`), and the content-free events reject unknown properties). Phase 2 also lands the `voice.*` payload `$defs` in `run-event-payloads.schema.json` + the `asyncapi.yaml` messages + the four §F `SECURITY/invariants.yaml` rows (1 protocol-tier `voice-transcript-untrusted` + 3 reference-impl behavioral, graduating at `Active → Accepted`). The gated behavioral legs (`voice-transcription-streaming`/`-unadvertised`, `voice-synthesis-streaming` + the three behavioral invariant scenarios) land with the reference host at `Active → Accepted`. 2026-06-23 (RFC 0106 — real-time voice session profile, Phase 1) added one: `aiproviders-realtimevoice-shape.test.ts` (always-on server-free — the `aiProviders.realtimeVoice` object advertisement: the four sub-flags `transcription`/`synthesis`/`turnDetection`/`bargeIn` are declared, `realtimeVoice` is absent from `aiProviders.required`, the `turnDetection`/`bargeIn ⇒ transcription` `dependentRequired` closure and the `synthesis ⇒ speechSynthesis` if/then closure hold via Ajv2020, and out-of-enum / boolean sub-flag values are rejected). The gated behavioral legs (`voice-transcription-streaming` / `-unadvertised`, `voice-synthesis-streaming`) and the four §F live-ingress invariant scenarios land in Phase 2 at the `Active → Accepted` cycle. 2026-06-22 (RFC 0101 — multi-party group conversation) added two — `multi-party-conversation-shape.test.ts` (always-on server-free — asserts the three additive RFC 0101 wire facts: a 3-agent council `conversation.opened` participant roster (instance ids) + a user opening turn validates, every `role: 'agent'` turn carrying a roster-instance `speakerId` validates while one OMITTING `speakerId` MUST FAIL schema validation (the `allOf`/`if role==='agent' then required:['speakerId']` conditional), a non-AgentRef participant item is rejected, the `capabilities.multiPartyConversation { supported, maxParticipants? }` block is declared + closed and rejects extras / `maxParticipants:1` / a missing `supported`, and the non-participant membership predicate is asserted server-free) and `multi-party-conversation-behavioral.test.ts` (capability-gated on `multiPartyConversation.supported` via `behaviorGate('openwop-multi-party-conversation', …)` — drives the conformance-only seam `POST /v1/host/sample/conversation/multi-party/{open,exchange}` (`host-sample-test-seams.md`, since RFC 0101 mints no normative client trigger to open a council): a 3-agent council opens and a roster-valid attributed agent turn is accepted, while a `role:'agent'` turn missing `speakerId`, a non-participant `speakerId`, and an over-`maxParticipants` open are each rejected with `error.code:'validation_error'` (status-tolerant 400/422 per RFC 0005 §E); soft-skips on 404/405 — reference impl: the postgres example host). 2026-06-20 (RFC 0105 — speech synthesis adapter) added three: `aiproviders-speechsynth-shape.test.ts` (always-on server-free — the `aiProviders.speechSynthesis` `const "supported"` flag is declared, absent from `aiProviders.required`, and a string-const advertisement validates while the object form `{supported:true}` is rejected), `speech-synthesis-roundtrip.test.ts` (gated on `aiProviders.speechSynthesis === "supported"` via `behaviorGate('openwop-speech-synthesis', …)` — an advertising host's `callSpeechSynthesizer` round-trip via the `POST /v1/host/sample/ai/call-speech-synthesizer` seam returns `audio` with EXACTLY ONE of `url`/`base64`, a non-empty `mimeType`, and the echoed `voiceId`; soft-skips on 404), and `speech-synthesis-unadvertised.test.ts` (gated-by-absence via `behaviorGate('openwop-speech-synthesis-unadvertised', …)` — a host NOT advertising `speechSynthesis` MUST reject the call with `speech_synthesis_unsupported`, never a silent no-op). 2026-06-19 (RFC 0104 — portable HITL approver routing) added one: `interrupt-approver-routing.test.ts` (server-free Ajv2020 — the `interrupt.approverRouting` capability block shape, the additive optionality of `approverGroupRefs` / `approverRoleRefs` / `audience` on the `ApprovalData` schema, the closed `audience` object, and the §"Portable approver routing" `notifyTargets` reference rule that `audience` DEFAULTS to the resolved eligibility union when omitted and OVERRIDES it when present; the capability-gated leg asserts an advertising host's `interrupt.approverRouting` is honest — `refKinds` ⊆ {group, role}, `audience` boolean — and soft-skips when the host does not advertise the capability). 2026-06-17 (RFC 0103 — localized content surface) added one: `localized-content-delivery.test.ts` (server-free Ajv2020 — the four content schemas + the §C `resolveSection` merge + §A capability coherence; the public test for `content-published-cache-no-draft` / `content-response-tenant-scoped` / `content-no-cross-tenant-enumeration`; the live legs gate on `capabilities.content.supported` and soft-skip without a `GET /v1/content/pages/{slug}` target). 2026-06-15 (RFC 0102 — A2UI agent-authored interface surfaces) added five: `a2ui-surface-shape.test.ts` (server-free Ajv2020 — the closed core `ui.a2ui-surface` payload validates, while an out-of-catalog component / extra script-bearing property / unenumerated `catalogVersion` / `action.target` outside `enum["resume","exchange"]` each fail; the structural half of `a2ui-action-confinement` and the enabling precondition for the render-side `a2ui-surface-no-code-exec` / `a2ui-surface-no-network-egress` reference-app probes), `a2ui-surface-degrades.test.ts` (the kind is optional/advertised, not a MUST-recognize universal kind, and an unadvertised kind is gated — N6 — never crashing the run), `a2ui-surface-version-refusal.test.ts` (the enumerated `catalogVersion` rejects an unadvertised version → `unknown_schema_version`, and the surface schema carries no external `$ref`), `a2ui-surface-replay.test.ts` (all `$ref`s internal so a stored surface `:fork`/replays deterministically; same-`correlationId` + divergent `type` → `envelope_correlation_conflict`), and `a2ui-untrusted-blocks-approval.test.ts` (a `meta.contentTrust:'untrusted'` surface is trust-gated and MUST NOT advance an approval interrupt — composition of `untrusted_content_blocks_approval`). The four behavioral legs soft-skip on 404 (host-pending; the `openwop-app` reference renderer is the render-side probe). 2026-06-14 (RFCs 0099/0100 — external-event trigger ingestion + async/durable A2A tasks) added one new scenario (`trigger-ingestion.test.ts`) and extended `a2a-task-roundtrip.test.ts` with the RFC 0100 async subtests: `trigger-ingestion.test.ts` (RFC 0099 — always-on `TriggerEvent` / `TriggerSubscriptionRegistration` schema legs incl. the §F.1 per-source one-of, the `AttachmentRef.ref`-only rule + raw-URL rejection backing `trigger-ingestion-ssrf`, and the content-free `trigger.delivery.attempted` shape backing `trigger-ingestion-content-redaction`; plus a capability-gated behavioral leg on `triggerBridge.ingestion` driving the `POST /v1/host/sample/trigger-bridge/ingest` seam for SSRF refusal + header-redaction), and the `a2a-task-roundtrip.test.ts` additions (RFC 0100 — always-on `A2ATaskState` + `capabilities.a2a` shape legs incl. the lowercase-hyphen state enum, the `PushConfig` `url`-required + truncated-`tokenFingerprint` rule backing `a2a-push-egress-ssrf`, the no-inline-inputs `additionalProperties:false` SR-1 check; plus capability-gated durable-`tasks/get`-after-disconnect and push-SSRF behavioral legs on `a2a.durableTasks` / `a2a.pushNotifications` via the `/v1/host/sample/a2a/tasks/*` seam). 2026-06-13 (RFCs 0096/0097/0098 — reviewable learning, standing goals, agent-platform portability) added three always-on-plus-gated scenarios: `proposal-reviewable-learning.test.ts` (RFC 0096 — the `agents.proposals` shape + the `Proposal` round-trip incl. the dropped `rule` kind + the content-free `proposal.{created,activated}` events, plus a gated apply-without-scope→403 leg; backs `proposal-inert-until-applied` + `proposal-no-resynthesis`), `goal-standing-continuation.test.ts` (RFC 0097 — the `agents.goals` shape + the `Goal` round-trip + the content-free `goal.{evaluated,closed}` events, plus gated bounded-termination→422 + judge-only-completion legs; backs `goal-continuation-bounded` + `goal-completion-judge-only`), and `export-bundle-portability.test.ts` (RFC 0098 — the `portability` shape incl. the `import⇒dryRun` if/then + the `ExportBundle` round-trip rejecting every credential-named field + the content-free `import.applied` event, plus a gated literal-credential-import→422 leg; backs `export-bundle-no-credential-material`). 2026-06-11 (RFCs 0093/0094 — protocol hardening + wire-shape reconciliation) added five: `version-fold.test.ts` (the `version-negotiation.md` §`X-Force-Engine-Version` cross-version matrix through the previously-orphaned `conformance-version-fold` fixture — closes catalog gap F5; soft-skips when `Capabilities.testing.forceEngineVersionRange` is unadvertised), `stream-text-fixture.test.ts` (the `stream-modes.md` §`messages` fold through the deterministic `stream-text` mock provider + the previously-orphaned `conformance-stream-text` fixture — closes catalog gap F1), `i18n-negotiation.test.ts` (gated on `capabilities.i18n` via `behaviorGate('openwop-i18n', …)` — an unsupported or malformed `Accept-Language` never 400s, `Content-Language` reflects the locale actually used, and error `code` strings stay the canonical English tokens), `grpc-transport.test.ts` (gated on `capabilities.grpc` via `behaviorGate('openwop-grpc-transport', …)` — advertisement-shape only per `grpc-transport.md` §Field semantics: `service` MUST be `openwop.v1.Engine`, the `tls` enum, `grpcs?://` endpoint URIs, `supportedTransports` includes `grpc` when exposed, production claimants require `tls: "required"`; no gRPC dialing), and `webhook-tenant-isolation.test.ts` (RFC 0093 §A.3 — backs the new protocol-tier `webhook-cross-tenant-isolation` invariant; a two-tenant proof through the `/v1/host/sample/test/surface` seam plus black-box registration-surface scoping). `spec-corpus-validity.test.ts` also gained the RFC 0094 §A satisfiability probe: canonical `createRun` bodies MUST pass the composed request schema (closed via `unevaluatedProperties: false` at the composition site, never inside an `allOf` branch) and an undeclared property MUST fail. 2026-06-07 (RFCs 0090/0091/0092 — verifier turn + convergence, multimodal perception input, agent capability requirements) added six: the always-on, server-free shape probes `agent-verifier-shape.test.ts`, `aiproviders-input-shape.test.ts`, `agent-requires-capabilities-shape.test.ts`, plus the capability-gated **behavioral** legs `agent-capability-degraded-projection.test.ts` (RFC 0092 §B — the `degraded[]` projection on `GET /v1/agents`, black-box, non-vacuous via `OPENWOP_DEGRADED_CAPABILITY_AGENT_ID`), `callai-multimodal.test.ts` (RFC 0091 §A/§B — advertised modality accepted / unadvertised → `unsupported_modality`, via the `POST /v1/host/sample/ai/call` seam), and `verifier-gating.test.ts` (RFC 0090 §B — a `fail` verdict blocks commit, via the `POST /v1/host/sample/agents/verify-run` seam). The three behavioral legs soft-skip by default and hard-fail under `OPENWOP_REQUIRE_BEHAVIOR=true` — the Active→Accepted reference-host proof for each RFC. 2026-06-02 (RFC 0082 §B — deployment channel resolve-and-pin, production-path coverage) added `agent-channel-dispatch.test.ts` (capability-gated on `agents.deployment.supported` + the seeded `conformance-agent-channel-dispatch` fixture + advertised `replay` mode via `behaviorGate('openwop-deployment-channel-dispatch', …)` — proves the §B pin from a REAL run graph, complementing `agent-deployment-lifecycle.test.ts` Leg 4's host-sample seam: a canonical `POST /v1/runs` of a node binding `agent.channel:"stable"` MUST record `resolvedChannel` + `resolvedAgentVersion` on `agent.invocation.started` (RFC 0077), a `:fork{mode:"replay"}` MUST re-read that recorded version, and the seam-guarded Leg 3 MOVES the channel then asserts a replay STILL carries the original pin — never re-resolving a moved channel; soft-skips by default, hard-fails under `OPENWOP_REQUIRE_BEHAVIOR=true` — the production-path proof of the §B contract). 2026-06-01 (RFC 0085 — `openwop-agent-platform` meta-profile, the Active→Accepted behavioral gate) added `agent-platform-aggregate-evidence.test.ts` (capability-gated on a host CLAIMING `openwop-agent-platform` in its live discovery `profiles[]` via `behaviorGate('openwop-agent-platform', …)` — the §C/§D honest-advertisement rule on the live `/.well-known/openwop`: the claim MUST satisfy the §B floor predicate (`isAgentPlatformPartial` → `partial`/`full`, never `none`), backed by the per-capability evidence not the profile string; `OPENWOP_AGENT_PLATFORM_TIER=full` forces the non-vacuous full bar — all governance terms + tenant installScope + all 16 §D terms; server-requiring, the always-on §B/§D derivation legs stay in `agent-platform-profile.test.ts` — the RFC 0085 → Accepted bar). 2026-06-01 (RFC 0084 — budget, quota + cost policy, the Active→Accepted behavioral gate) added `budget-enforcement.test.ts` (capability-gated on `budget.supported` via `behaviorGate('openwop-budget-enforcement', …)` — the §C/§D enforcement via the new `POST /v1/host/sample/budget/run` seam + the test event-log seam: a `hard-cost-exhaust` run emits the strict-ordered `budget.reserved → budget.consumed → budget.threshold.crossed{percent} → budget.exhausted → cap.breached{kind:"budget-cost"} → run.failed{error:"budget_exhausted"}` chain; a `model-denied` run is refused `budget_model_denied` BEFORE the provider call (fail-closed); an `advisory` host emits the `budget.*` events without stopping; every `budget.*` payload content-free backing `budget-no-pricing-leak`; new lib helper `src/lib/budgetPolicy.ts`; soft-skips on 404 — the RFC 0084 → Accepted bar). 2026-06-01 (RFC 0080 — agent memory capability reconciliation, the Active→Accepted behavioral gate) added `memory-degraded-projection.test.ts` (capability-gated on `agents.manifestRuntime.supported` + `memory.supported` via `behaviorGate('openwop-memory-degraded', …)` — the §C degraded-projection iff-contract on the NORMATIVE `GET /v1/agents`: a degraded inventory entry MUST carry `memoryDegraded:true` + a non-empty, unique `degradedMemoryDimensions[]` from the closed §A-name enum, a non-degraded entry MUST NOT, the inventory is non-empty, and the degraded branch runs non-vacuously when `OPENWOP_DEGRADED_AGENT_ID` names a known-degraded agent; black-box, no POST seam — the RFC 0080 → Accepted bar). This batch also documents the two RFC 0068 conformance seams (`POST /v1/host/sample/memory/consolidate` + `.../commitment/fire`) in `host-sample-test-seams.md` (the 0068 gated scenarios shipped in 1.14.0). 2026-06-01 (RFC 0034 — collector-side BYOK-canary inspection) added `otel-collector-canary-inspection.test.ts` (always-on server-free: stands up a real `OtelCollector`, POSTs synthetic OTLP/HTTP-JSON traces + metrics through its actual ingest path, and proves the new `findCanaryLeakage()` inspector catches a canary embedded in a span attribute / resource attribute / span name / metric data-point attribute while reporting ZERO hits on a redacted payload and never matching an empty canary — the non-vacuous proof that the conformance collector now inspects what the host's OTLP exporter ACTUALLY shipped over the wire, closing the `secret-leakage-otel-attribute` / `-debug-bundle-otel` collector-seam gap; the live capability-gated complement is the new collector-export describe block in `secret-leakage-otel-attribute.test.ts`). 2026-06-01 (RFC 0035 — sandbox wall-clock timeout, the 7th-of-8 graduation) added `sandbox-wasm-timeout.test.ts` (worker-driven server-free: `probeTimeout` in `wasm-sandbox-probe.ts` spawns a worker thread running the committed `misbehaving-timeout.wasm` + a main-thread kill-timer — the thread preemption a same-thread probe can't do — asserting `sandbox_timeout` with a well-behaved positive control; graduates `node-pack-sandbox-timeout` reference-impl→protocol, so 7 of 8 `node-pack-sandbox-*` invariants are now protocol-tier, only the JS-specific `no-eval` permanently exempt). 2026-05-31 (audit-response black-box / graduation batch) added three more: `sandbox-wasm-isolation.test.ts` (RFC 0035 — drives the committed `fixtures/wasm-sandbox/*.wasm` through `wasm-sandbox-probe.ts`: escape/capability-gate via static `WebAssembly.Module.imports()`, an OOB-store memory trap, double-instantiate isolation; 10/10; graduates 6 `node-pack-sandbox-*` invariants reference-impl→protocol), `workspace-cross-tenant-isolation-blackbox.test.ts` (RFC 0059 — two-credential black-box on the normative §C `/v1/host/workspace/files` endpoints: owner A writes, a second-tenant credential fails closed; no seam), and `prompt-resolution-chain-event.test.ts` (RFC 0029 — reads the durable `agent.promptResolved.chain[]` precedence record via the normative `GET /v1/runs/{runId}/events/poll`; no seam) — each the production-path proof that graduates its surface into the `openwop-core-standard` floor. 2026-05-31 (RFC 0088 — the `openwop-core-standard` Core Standard Profile, the audit-response Core Candidate target) added `core-standard-profile.test.ts` (always-on server-free derivation probe: `isCoreStandard` derives the §B floor — `openwop-core` ∧ `openwop-interrupts` ∧ (`openwop-stream-sse` ∨ `openwop-stream-poll`) — a bare `openwop-core` host without interrupts is excluded, a host with no event transport fails, and the annex is absent from `deriveProfiles` because it composes rather than redefines). 2026-05-31 (RFC 0082 — agent deployment lifecycle, the Active→Accepted behavioral gate) added `agent-deployment-lifecycle.test.ts` (capability-gated on `agents.deployment.supported` via `behaviorGate('openwop-deployment-lifecycle', …)` — the §E promotion contract via the new `POST /v1/host/sample/agents/deployment-transition` seam + the test event-log seam across four legs: `promote` (authorize RFC 0049 → approvalGate RFC 0051 → eval-verify RFC 0081 → content-free `deployment.promoted` with a seven-state `toState` + `toVersion`, the record validating `agent-deployment.schema.json`), `unauthorized` (fail-closed — `allowed:false`, no `deployment.promoted`, the behavioral leg of `deployment-promotion-fail-closed`), `eval-gate-unmet` (`eval_gate_unmet` denial, §E-3), and `channel-pin` (the §B `resolvedAgentVersion` recorded-fact on `agent.invocation.started`); new lib helper `src/lib/agentDeployment.ts`; soft-skips on 404 — the RFC 0082 → Accepted bar). 2026-05-31 (RFC 0081 — agent evaluation, the Active→Accepted behavioral gate) added `agent-eval-run.test.ts` (capability-gated on `agents.evalSuite.supported` via `behaviorGate('openwop-eval-run', …)` — the §B `mode:"eval"` projection via the new `POST /v1/host/sample/agents/eval-run` seam + the test event-log seam: `eval.started`-first → one `eval.scored` per task → `eval.completed`-once ordering (count == `eval.completed.taskCount`), the content-free `eval.scored` legs (`score` ∈ 0..1) backing `eval-summary-no-content-leak`, and the NORMATIVE `GET /v1/runs/{runId}/eval-summary` schema-valid `EvalSummary` round-trip with `passedCount <= taskCount`; new lib helper `src/lib/agentEval.ts`; soft-skips on 404 — the RFC 0081 → Accepted bar). 2026-05-31 (RFC 0083 — durable trigger bridge, the Active→Accepted behavioral gate) added `trigger-bridge-delivery.test.ts` (profile-gated on `openwop-trigger-bridge` derived from the live discovery doc — the §C delivery model via the `POST /v1/host/sample/trigger-bridge/deliver` seam + the test event-log seam: dedup→effectively-once `trigger.delivery.attempted{delivered}` (§C-1), retry-exhaustion→`{dead-lettered}` + `trigger.subscription.state.changed{toState:dead-lettered}` (§C-2 + RFC 0053), and the delivered run's `run.started.causationId` == the delivery id (§C / RFC 0040); both `trigger.*` events content-free; the always-on shape stays in `trigger-bridge-shape.test.ts`; new lib helper `src/lib/triggerBridge.ts`). 2026-05-31 (RFC 0087 — agent org-chart, the Active→Accepted behavioral gate) added two capability-gated behavioral scenarios (both gated on `agents.orgChart.supported`, black-box on the normative `/v1/agents/org-chart` surface — no new POST seam): `agent-org-chart-scoping.test.ts` (the `GET /v1/agents/org-chart` tree-shape — departments form an acyclic `parentDepartmentId` tree, members reference `host:<id>` roster entries — + the §D responsibility roll-up via `GET /v1/agents/org-chart/{departmentId}` with a deduped `responsibilities[]` union + the RFC 0074 cross-tenant 404 via `OPENWOP_CROSS_TENANT_ORG_CHART_DEPARTMENT_ID`) and `org-position-no-authority-escalation.test.ts` (the behavioral leg of the protocol-tier invariant — the live org-chart wire carries NO authority-bearing field on any member/department/responsibility-view object; the structural leg stays always-on in `agent-org-chart-shape.test.ts`, and the deeper RFC 0049/0051 authority-invariance legs stay reference-impl tier per the `agent-manifest-runtime` no-host-hook precedent). 2026-05-31 (RFCs 0086 + 0077 — the Active→Accepted behavioral gate) added four capability-gated behavioral scenarios so a non-steward host can be mechanically certified non-vacuously under `OPENWOP_REQUIRE_BEHAVIOR=true`: `agent-roster-attribution.test.ts` (RFC 0086 §B/§C; gated on `agents.roster.supported` — the normative `GET /v1/agents/roster` read shape + `total==roster.length`, the §C `roster.run.initiated`-before-`agent.invocation.started` ordering, the content-free payload backing `roster-attribution-no-content`, the durable work-item `triggerSubscriptionId`, and the RFC 0074 cross-tenant 404 via `OPENWOP_CROSS_TENANT_ROSTER_ID`), `agent-live-invocation-bracket.test.ts` (RFC 0077 §E; gated on `agents.liveRuntime.supported` — `agent.invocation.started`-first / `agent.invocation.completed`-last bracket, matching `invocationId`, `source`/`outcome` closed enums, content-free), `agent-live-structured-output.test.ts` (RFC 0077 §B step 6; gated on `agents.liveRuntime.structuredOutput` — a result violating `handoff.returnSchemaRef` fails the invocation `outcome:"failed"` rather than shipping as completed), and `agent-live-allowlist-enforced.test.ts` (RFC 0077 §F-1 / RFC 0002 §A14; gated on `agents.liveRuntime.supported` — a tool outside `toolAllowlist` is not callable); all four drive the documented `POST /v1/host/sample/roster/fire` + `POST /v1/host/sample/agents/live-invoke` seams plus the test event-log seam and soft-skip on 404 (these are the RFC 0086 / 0077 Active→Accepted bars). 2026-05-30 (RFC 0087 — agent org-chart, Draft -> Active) added `agent-org-chart-shape.test.ts` (always-on server-free: the `capabilities.agents.orgChart` shape + the `AgentOrgChart` round-trip + the non-`host:` member negative + the **§B structural non-authority guarantee** — the schema rejects a `scopes`/`canDispatch`/`permissions`/`authority` field on a member (`additionalProperties:false`), and a member's key set is exactly `{rosterId, departmentId, roleId, reportsTo}` — backing the protocol-tier `org-position-no-authority-escalation` invariant; no new RunEventType). 2026-05-30 (RFC 0086 — standing agent roster, Draft -> Active) added `agent-roster-shape.test.ts` (always-on server-free: the `capabilities.agents.roster` shape + the `AgentRosterEntry` round-trip + the `host:` `rosterId` + `agentRef` version-XOR-channel negatives + the content-free `roster.run.initiated` negatives backing the protocol-tier `roster-attribution-no-content` invariant + the additive `roster` inventory projection + RunEventType-enum membership). 2026-05-30 (RFC 0082 — agent deployment lifecycle, Draft -> Active) added `agent-deployment-shape.test.ts` (always-on server-free: the `capabilities.agents.deployment` shape + the `AgentDeployment` record round-trip + the `AgentRef` `channel` XOR `version` `not`-clause + the four `deployment.*` payloads + the content-free negatives backing the protocol-tier `deployment-event-no-content-leak` invariant). 2026-05-30 (RFC 0085 — `openwop-agent-platform` meta-profile, Draft -> Active) added `agent-platform-profile.test.ts` (always-on server-free derivation of the operational-annex `none`/`partial`/`full` status: all-floor ⇒ partial, missing-flag ⇒ none, the replay-OR-`nondeterminismPolicy.declared` term, floor+governance ⇒ full, missing-tenant-scope ⇒ partial-not-full per the honest-advertisement rule, eval/deploy/budget-are-advisory-not-hard-terms, + the `capabilities.nondeterminismPolicy.declared` shape). 2026-05-30 (RFC 0084 — budget, quota + cost policy, Draft -> Active) added `budget-policy-shape.test.ts` (always-on server-free: `budget-policy.schema.json` round-trip + the §A orthogonality guard — a wall-time field is rejected (it's RFC 0058's `runTimeoutMs`) — + threshold/onExhaustion negatives + the four content-free `budget.{reserved,consumed,threshold.crossed,exhausted}` payloads + the four `cap.breached{budget-*}` kinds + RunEventType-enum membership + the no-pricing-property structural check backing the protocol-tier `budget-no-pricing-leak` invariant + the `capabilities.budget`/`limits.maxBudget*` shape). 2026-05-30 (RFC 0083 — durable trigger + channel bridge, Draft -> Active) added `trigger-bridge-shape.test.ts` (always-on server-free: `trigger-subscription.schema.json` round-trip + missing-`state`/out-of-enum-`source`/unknown-property negatives + the four-state vocab + the two content-free `trigger.{subscription.state.changed,delivery.attempted}` payloads incl. closed `state`/`outcome` enums + RunEventType-enum membership + the `triggerBridge`/`webhooks.durable` capability shape + the `openwop-trigger-bridge` profile derivation incl. the no-dead-letter-sink negative). 2026-05-30 (RFC 0079 — credential provenance + egress policy, Draft -> Active) added `egress-provenance-shape.test.ts` (always-on server-free: `credential-provenance.schema.json` round-trip + `audiences:[]`/missing-`credentialId`/unknown-property negatives + the no-secret-property structural check backing the protocol-tier `egress-decision-no-secret-leak` invariant + the content-free `egress.decided` record incl. the `decision` enum + RunEventType-enum membership + the `httpClient.egressPolicy` shape; the behavioral `egress-credential-audience-bound` confused-deputy MUST is reference-impl tier, deferred to a host). 2026-05-30 (RFC 0078 — portable tool catalog, Draft -> Active) added `tool-descriptor-shape.test.ts` (always-on server-free: `tool-descriptor.schema.json` round-trip + the §C-1 `exec` ⇒ `host-extension` cross-field MUST (RFC 0069) + the `safetyTier`-required negative + `additionalProperties:false`, the `capabilities.toolCatalog` `supported`/`sources`/`sessionLifecycle` shape, and the two content-free `tool.session.{opened,closed}` payload $defs incl. the closed `outcome` enum + RunEventType-enum membership). 2026-05-30 (RFC 0080 — agent memory capability reconciliation, Draft -> Active) added `memory-capability-model-shape.test.ts` (always-on server-free: the additive `capabilities.memory.{writable,search,retention}` dimension shapes + malformed-instance negatives — `retention.ttl` non-boolean, out-of-enum `search.modes`, unknown property under `additionalProperties:false` — the `agent-inventory-response` `memoryDegraded`/`degradedMemoryDimensions` closed-enum fields, and the `openwop-memory` derivation surfacing for read/write + long-term hosts while withholding from `writable:false`). 2026-05-30 (RFC 0081 — agent evaluation, Draft -> Active) added `agent-eval-suite-shape.test.ts` (always-on server-free: the `capabilities.agents.evalSuite` shape + the `AgentEvalSuite`/`EvalSummary` schema round-trips + the three `eval.{started,scored,completed}` payloads + the content-free negatives — a task entry with a `taskOutput` body, a `safetyFinding` with an `excerpt` — backing the new `eval-summary-no-content-leak` SECURITY invariant). 2026-05-29 (RFC 0076 §B — `ctx.http.safeFetch` live-run audit) added `safefetch-live-audit.test.ts` (`behaviorGate('openwop-safefetch-live-audit', …)`, gated on `httpClient.safeFetch` + `toolHooks.prePostEvents`) — asserts the audit-when-both MUST against the **durable run event log** via the new `POST /v1/host/sample/http/safe-fetch-run` open seam + the test event-log seam, closing the seam-vs-production gap (a production `createSafeFetch()` with no audit hooks passes the inline `safefetch-behavior.test.ts` but FAILS this under `OPENWOP_REQUIRE_BEHAVIOR=true`); this is the RFC 0076 §B → Accepted bar; run seam soft-skips on 404 (host-pending). 2026-05-29 (RFC 0066 — `x-openwop-form` picker UX hints, Draft → Active) added `x-openwop-form-pack-manifest.test.ts` (always-on server-free: an annotated `configSchema` stays a valid 2020-12 schema + the advisory hints don't change what it accepts, each §A annotation matches the shape, an unknown `kind` validates for forward-compat, 3 negatives — missing/non-string `kind`, non-string `dependsOn`). 2026-05-29 (RFC 0076 §B — `ctx.http.safeFetch`) added `safefetch-behavior.test.ts` (seam-gated: SSRF block / DNS-rebinding / `Connection: upgrade` refusal / tool-hooks audit-when-both, via `POST /v1/host/sample/http/safe-fetch`; advertisement contract stays in `http-client-ssrf.test.ts`). 2026-05-29 (RFC 0076 §A — pack `runtime.requires[]` install gate) added two: `runtime-requires-shape.test.ts` (server-free closed-vocabulary validation — the 8 tokens validate, a raw builtin name is rejected, empty-array≡omission, `uniqueItems`) + `runtime-requires-install-gate.test.ts` (seam-gated install-grant / install-refuse → `pack_runtime_requirement_unmet` / non-sandbox SHOULD-projection, soft-skip on 404 via `POST /v1/host/sample/packs/install-gate`). 2026-05-29 (RFC 0047 — `host.oauth` authorization-code roundtrip) added `oauth-authorization-code-roundtrip.test.ts` — capability-gated on `capabilities.oauth.supported` + `grants` including `authorization_code`; drives the `POST /v1/host/sample/oauth/authorize-code-roundtrip` seam against the one canonical synthetic provider in `fixtures/oauth-providers/synthetic.json` (soft-skip on 404, Tier-2 host-pending), asserting a successful grant returns a credential REFERENCE (token persisted as a `host.credentials` entry) and that the authorization code / state / PKCE verifier / acquired access+refresh tokens never appear on any run-visible surface (RFC 0047 §C + §C.2 / `credential-payload-redaction`). Closes the RFC 0047 Tier-2 gap (capability-shape + redaction scenarios existed; the actual authorization-code dance was unexercised). 2026-05-26 (RFC 0070 — agent-manifest runtime) added `agent-manifest-runtime.test.ts`; 2026-05-26 (RFC 0071 — artifact-type + chat card packs) added six: `artifact-type-pack-manifest-validation.test.ts` + `artifact-schema-compile-bounded.test.ts` (server-free) + `artifact-type-pack-install.test.ts` + `artifact-type-store-without-render.test.ts` + `chat-card-pack-manifest-validation.test.ts` (server-free) + `chat-card-pack-execution.test.ts` (capability-gated, host-pending). 2026-05-26 (RFCs 0067 / 0068 / 0069 — spec-gap Draft cohort) added five scenarios: `byok-auth-modes.test.ts` (RFC 0067; always-on schema-shape of `aiProviders.authModes` + a discovery-gated §B auth-mode-contract cross-field check), `memory-consolidation-shape.test.ts` (RFC 0068; always-on shape of `agents.memoryConsolidation`/`agents.commitments` + the `agent.memory.consolidated`/`commitment.fired` payload $defs), `memory-consolidation-idempotent.test.ts` + `commitment-fired.test.ts` (RFC 0068; capability-gated behavioral, soft-skip on the documented `/v1/host/sample/memory/consolidate` + `/commitment/fire` seams), and `exec-not-protocol-tier.test.ts` (RFC 0069; always-on server-free structural assertion that the protocol corpus defines no `core.*`/`openwop.*` exec-class primitive — backs the `exec-must-not-be-protocol-tier` SECURITY invariant). 2026-05-25 (RFC 0061 — stateful agent-loop lifecycle, executionModel.version 5) added four `agent-loop-*.test.ts` scenarios: `-version5-shape` (always-on; validates `executionModel.statefulResume`/`transcriptWindow` + the 1–5 version ceiling) plus `-iteration-monotonic` (gated on `version >= 5`; `runOrchestrator.decided.iteration` increments 1,2,3… exactly once per turn), `-workspace-snapshot` (gated additionally on `host.workspace.supported`; a turn-i workspace write is invisible to turn i, visible to turn i+1), and `-stateful-resume` (gated on `statefulResume`; a mid-loop suspend resumes at the same iteration without resetting the counter) — the three behavioral scenarios drive the documented agent-loop seam (`POST /v1/host/sample/agentloop/run`) and soft-skip until a host wires it. 2026-05-25 (RFC 0059 — host.workspace M2, reference-host enforcement) added two `workspace-*.test.ts` scenarios: `-behavior` (capability-gated CRUD round-trip / `If-Match` 409 `workspace_conflict` / `workspace_too_large` / §D run-start snapshot, all via the real `/v1/host/workspace/files` §C endpoints) and `-cross-tenant-isolation` (WCT-1 — drives the documented `POST /v1/host/sample/workspace/op` seam to assert a file owned by one `{tenant, workspace}` is unreadable, on both `get` and `list`, under a different owner; backs the new `workspace-cross-tenant-isolation` SECURITY invariant). The in-memory reference host now advertises `capabilities.workspace.supported` and honors §C/§D/§E end-to-end. 2026-05-25 (RFC 0062 — memory.distillation "dreams") added five `distillation-*.test.ts` scenarios: `-shape` (always-on; validates the `capabilities.memory.distillation` block + the additive `distillation` sub-object on `memory.compacted`) plus `-token-budget` (within budget `tokensUsed ≤ tokenBudget`; an un-meetable budget → `token_budget_exceeded` with no partial archive), `-stable-archive` (same sources + budget ⇒ byte-stable archive checksum), `-index-roundtrip` (gated additionally on `indexEmitted`; the `MEMORY-INDEX.json` workspace file is retrievable + `workspace.updated` fired), and `-secret-carryforward` (SR-1: a redacted source secret never appears in the archive) — the four behavioral scenarios drive the documented memory-distillation seam (`POST /v1/host/sample/memory/distill`) and soft-skip until a host wires it. 2026-05-25 (RFC 0063 — core.subWorkflow.outputAttestation) added four `subrun-*.test.ts` scenarios: `-attestation-shape` (always-on; validates the `capabilities.agents.subRunAttestation` flag) plus `-checksum-stable` (the child output checksum is the byte-stable, key-order-invariant RFC 8785 JCS + SHA-256 digest), `-approval-gate` (`requireApproval` → `accept` merges, `reject` does not), and `-approval-fail-closed` (no `accept`/`edit-accept` → no merge; backs the deferred `subrun-merge-approval-fail-closed` invariant) — the three behavioral scenarios drive the documented sub-run attestation seam (`POST /v1/host/sample/subrun/attest`) and soft-skip until a host wires it. 2026-05-25 (RFC 0064 — host.toolHooks) added five `tool-hooks-*.test.ts` scenarios: `-shape` (always-on; validates the `capabilities.toolHooks` block + the optional content-free fields on `agentToolCalled` / `agentToolReturned`) plus `-content-free` (gated on `prePostEvents`), `-authorization-fail-closed` (gated on `perToolAuthorization`), `-rate-limit` (gated on `perToolRateLimit`), and `-secret-redaction` (gated on `prePostEvents` + the SR-1 `argsHash` redaction rule) — the four behavioral scenarios drive the documented tool-hooks invoke seam (`POST /v1/host/sample/toolhooks/invoke`) and soft-skip until a host wires it. 2026-05-25 (RFC 0060 — host.heartbeat) added four `heartbeat-*.test.ts` scenarios: `-capability-shape` (always-on; validates the `capabilities.heartbeat` block) plus `-fires-once-per-tick`, `-idempotent-no-spam`, and `-runtime-bound` (gated on `capabilities.heartbeat.supported` + the host heartbeat tick seam; soft-skip until a host wires it). 2026-05-25 (RFC 0057 — memory write-attribution) added five `memory-attribution-*.test.ts` scenarios: `-shape` (always-on advertisement check on `capabilities.memory.attribution`), plus `-no-content`, `-tenant-scoped`, `-emits-on-write`, and `-replay-stable` (gated on `capabilities.memory.attribution.emitsWriteEvents`) verifying the content-free `memory.written` RunEvent, its two SECURITY invariants (`memory-attribution-no-content` + `memory-attribution-tenant-scoped`), and the §D replay rule that a `replay`-mode fork MUST NOT regenerate `memoryId`. 2026-05-25 (RFC 0025 §C point 1 — test-catalog isolation invariant; pairs with the 25 publish-error scenarios in `pack-registry-publish.test.ts`) added `pack-registry-isolation.test.ts` — capability-gated on `capabilities.packs.testMode.{supported, isolated}: true`; PUTs a disposable pack into `/v1/packs-test/{name}` and asserts the same `(name, version)` does NOT appear via `GET /v1/packs/{name}` — anchors the test-catalog isolation MUST in RFC 0025 §C. 2026-05-25 (RFC 0028 Tier-2 post-promotion T2 — read-side sister scenario for workspace-membership enforcement) added `prompt-read-workspace-membership-enforced.test.ts` — gates on `capabilities.prompts.supported: true` (broader than `mutableLibrary` so read-only hosts that expose `?workspaceId=` are also probed); drives `GET /v1/prompts?workspaceId=<random-non-member>` and interprets the response: 4xx PASS (canonical envelope check on 403); 200 with empty `templates[]` PASS (correct null result for a nonexistent workspace); 200 with non-empty `templates[]` FAIL (cross-tenant leak); 200 without `templates[]` field SKIP (host doesn't expose workspace-scoped reads). Verifies SECURITY invariant `prompt-read-workspace-membership-enforced`. Same-day T1 strengthened `prompt-mutation-workspace-membership-enforced.test.ts` to pin `error === "workspace_membership_required"` when the host's refusal status is 403 (other refusal codes unconstrained). 2026-05-25 (RFC 0028 Tier-2 follow-up — workspace-membership enforcement on mutating prompt endpoints, filed in response to a self-disclosed adopter vulnerability) added `prompt-mutation-workspace-membership-enforced.test.ts` — capability-gated on `capabilities.prompts.mutableLibrary: true`; drives `POST /v1/prompts` with a cryptographically-random non-member `workspaceId` and asserts the host refuses (NOT a 2xx; any 4xx/5xx is acceptable — silent success is the failure mode). Verifies SECURITY invariant `prompt-mutation-workspace-membership-enforced`. 2026-05-22 (RFC 0034 §B follow-up — secret-leakage harness against the OTel + debug-bundle seams) added `secret-leakage-otel-attribute.test.ts` — gates on `capabilities.secrets.supported` + `capabilities.observability.testSeams.{otelScrape,debugBundleExport}` AND the `OPENWOP_CANARY_SECRET_VALUE` env (host operator + conformance runner agree on the canary). Drives the existing `openwop-smoke-byok-roundtrip` fixture end-to-end; scrapes both seams after run completion; hard-fails if the canary plaintext appears in any OTel span attribute or debug-bundle field. Verifies SECURITY invariants `secret-leakage-otel-attribute` + `secret-leakage-debug-bundle-otel`. 2026-05-22 (RFC 0041 Phase 4 — replay determinism under nondeterministic models) added three scenarios: `replay-divergence-at-refusal.test.ts` (advertisement-shape probe on `replayDeterminism.refusalDivergenceEmission` + 2 `it.todo` for the dual-direction refusal-divergence case), `replay-observable-sequence-determinism.test.ts` (capability-gated; behavioral assertion soft-skipped until a `conformance-phase4-nondet-tool` fixture ships), `replay-llm-cache-key-portable.test.ts` (intra-host reproducibility + non-recipe-field invariance + Phase 4 advertisement alignment — reuses the existing `POST /v1/host/sample/test/llm-cache-key` seam from the sibling `replay-llm-cache-key.test.ts`). 2026-05-20 (RFC 0027 §A templateKinds-coverage follow-up — paired with `prompt-end-to-end-events.test.ts`) added `prompt-all-four-kinds-events.test.ts` exercising all four `PromptKind` values (`system`, `user`, `schema-hint`, `few-shot`) end-to-end through the reference workflow-engine sample's `local.sample.demo.mock-ai` dispatch path; capability-gated via `behaviorGate('prompts-supported', ...)`. Closes the credibility gap where the host advertised `templateKinds: ["system", "user", "few-shot", "schema-hint"]` but only the system+user pair was actually wired into dispatch. 2026-05-20 (RFCs 0030–0033 — envelope LLM-contract-hardening track) added 15 scenarios across four `Active` RFCs: `envelope-reasoning-shape.test.ts` (RFC 0030, always-on; asserts the OPTIONAL `reasoning` property on the three universal-kind schemas + the `schema.response` deliberate omission), `envelope-reasoning-secret-redaction.test.ts` (RFC 0030, capability-gated on `capabilities.envelopes.reasoning.supported` + `secrets.supported`; 5 `it.todo()` placeholders for SECURITY invariant `envelope-reasoning-secret-redaction`), `envelope-tier-one-subset-static.test.ts` (RFC 0030, always-on for load-bearing rules — no `oneOf` / `allOf` / `not` / `prefixItems` / `propertyNames` anywhere; gated on `tierOneSubsetCompliance: "strict"` for OpenAI-strict-only constraints), `envelope-variant-discriminator-static.test.ts` (RFC 0031, always-on; asserts no `oneOf` + every `anyOf` branch declares a single-string-enum discriminator in `required` on every `schemas/envelopes/*.schema.json`), `model-capability-substituted.test.ts` (RFC 0031, advertisement-shape probe on `capabilities.modelCapabilities.advertised[]` identifier pattern + 5 `it.todo()` placeholders for SECURITY invariant `model-capability-substituted-no-credential-disclosure`), `model-capability-insufficient.test.ts` (RFC 0031, 6 `it.todo()` placeholders for refusal + no-recursive-fallback), `node-module-required-capabilities-shape.test.ts` (RFC 0031 SHOULD-tier authoring-convention; 4 `it.todo()` placeholders), and the six envelope-reliability events from RFC 0032 (`envelope-retry-attempted` carrying the shared advertisement-shape probe enforcing both MUST-tier events in `events[]` per RFC 0032 §C, plus `envelope-retry-exhausted`, `envelope-refusal-shape`, `envelope-truncated`, `envelope-nl-to-format-engaged`, `envelope-recovery-applied` — collectively 39 `it.todo()` placeholders covering retry/refusal/truncation/recovery + SECURITY invariants `envelope-refusal-no-prompt-leak` and `envelope-recovery-no-content-leak`), plus RFC 0033's two scenarios (`envelope-completion-distinguishes-truncation.test.ts` + `envelope-truncation-cap-exhaustion.test.ts` — 12 `it.todo()` placeholders covering the truncation-vs-schema-violation retry-routing distinction + the DoS-bound assertion). Reference workflow-engine sample advertises `capabilities.envelopes.reasoning: { supported: true, promptDirective: "off" }` + `tierOneSubsetCompliance: "warn"` honestly (schemas accept the field; host doesn't yet inject the directive); the other three RFCs' capability blocks defer to reference-host emission code per the staged RFC 0027 §G precedent. 2026-05-20 (RFC 0028 §B Phase B — prompt-pack boot-time install) added `prompt-pack-install.test.ts` (capability-gated on `capabilities.prompts.endpointsSupported: true`; asserts a host that ran the boot-time pack loader surfaces ≥ 1 pack-source template under `GET /v1/prompts?source=pack` carrying the canonical `meta.source: "pack"` + `meta.packName` + `meta.packVersion` stamps; positively identifies the in-tree `vendor.openwop.prompt-sample` reference pack's `writer-system` template when present). Pairs with the new `host/promptPackLoader.ts` boot-time entry on the reference workflow-engine sample, which scans `examples/packs/*` plus `OPENWOP_PROMPT_PACKS_DIR` and calls `installPackTemplates()` for each `kind: "prompt"` pack found. 2026-05-20 (RFC 0029 Phase C — prompt resolution chain wire shape) added three more scenarios: `prompt-resolution-chain-node-wins.test.ts` (capability-gated on `capabilities.prompts.supported: true`; asserts layer-1 node-config supersedes lower layers per `spec/v1/prompts.md` §"Resolution chain (normative)"), `prompt-resolution-chain-agent-intrinsic.test.ts` (additionally gated on `capabilities.prompts.agentBindings: true`; asserts agent intrinsic `systemPromptRef` wins over `promptOverrides` AND lower layers when the node has no layer-1 ref), `prompt-resolution-chain-fallback-cascade.test.ts` (asserts layer 3 workflow-defaults wins over layer 4 host-defaults; layer 4 host-defaults wins when 1-3 yield null; resolved is null when all four yield null but chain[] still lists every attempted layer). The scenarios drive the host's `POST /v1/host/sample/prompt/resolve` test seam (reference-host implementation deferred to follow-up slice per RFC 0021 staging precedent). 2026-05-20 (RFC 0027 Phase A — prompt templates wire shape) added three scenarios: `prompt-template-shape.test.ts` (always-on; Ajv compileability + positive/negative round-trip for PromptTemplate + PromptRef + PromptKind), `prompt-composed-secret-redaction.test.ts` (capability-gated on `capabilities.prompts.supported: true` + `observability: "full"`; asserts `[REDACTED:<secretId>]` markers in `prompt.composed` payloads for `source: "secret"` variable bindings per SECURITY/threat-model-secret-leakage.md §SR-1), `prompt-composed-trust-marker.test.ts` (same capability gates; asserts `<UNTRUSTED>...</UNTRUSTED>` wrapping + `contentTrust: "untrusted"` propagation per RFC 0020 §D). Paired with new `fixtures/prompt-templates/` sub-directory + per-fixture schema-validity describe block + future SECURITY invariants `prompt-composed-secret-redaction` and `prompt-composed-trust-marker` (lands alongside reference-host emission per RFC 0021 staging precedent). 2026-05-18 (RFC 0022 `Draft` — runtime variable mapping) added four `it.todo()` placeholder scenarios covering the new mapping surfaces on `core.dispatch` (§A — `dispatch-input-mapping.test.ts`, `dispatch-output-mapping.test.ts`, `dispatch-cross-worker-handoff.test.ts`) and `core.subWorkflow` (§B — `subworkflow-input-mapping.test.ts`). Gated on `capabilities.agents.dispatchMapping` (dispatch trio) and `capabilities.subWorkflow.inputMapping` (subWorkflow). Promote to live assertions when RFC 0022 reaches `Active` + a reference host advertises the matching flags. 2026-05-17 (RFC 0003 §D handoff-schema enforcement, HV-1) added `agentPackHandoffSchemaValidation.test.ts` — verifies the host validates dispatch payloads against `handoff.taskSchemaRef` AND return payloads against `handoff.returnSchemaRef` per RFC 0003 §D. Paired with the new `agent-pack-handoff-schema-enforcement` row in `SECURITY/invariants.yaml`. 2026-05-17 (AI Envelope gap-closure, DRAFT v1.x — `spec/v1/ai-envelope.md`) added 7 advertisement-shape scenarios with `it.todo()` behavioral placeholders gated on `capabilities.envelopeContracts.advertised: true`: `aiEnvelope.universalKinds.test.ts`, `aiEnvelope.schemaDrift.test.ts`, `aiEnvelope.correlationReplay.test.ts`, `aiEnvelope.contractRefusal.test.ts`, `aiEnvelope.trustBoundaryPropagation.test.ts`, `aiEnvelope.redaction.test.ts`, `aiEnvelope.capBreached.test.ts`. Paired with the new `envelope-redaction-sr-1-carry-forward` row in `SECURITY/invariants.yaml`. 2026-05-17 (post-publish hardening, deep audit of `core.openwop.agents`) added `agents-run-tool-allowlist.test.ts` — server-free scenario locking in the `core.openwop.agents@1.0.1` safety-fix that closes `OPENWOP-AUDIT-2026-003` (function-typed `tool.handler` properties rejected at `validateTools()` with `INVALID_TOOL_DECLARATION`; tool-driven runs require `ctx.agentRuntime`; tool-less safe fallback preserved). Paired with the new `agents-run-no-raw-handler` row in `SECURITY/invariants.yaml`. Same-day post-publish hardening added `idempotency-key-determinism.test.ts` — server-free scenario locking in the `core.openwop.http@1.1.2` determinism safety-fix (default `composite` mode produces deterministic keys in `(runId, nodeId, payload)`; removed `uuid` mode rejects with `CONFIG_INVALID`; cross-impl vector test lets third-party reimplementations verify wire agreement). Paired with the new `idempotency-key-deterministic` row in `SECURITY/invariants.yaml`. 2026-05-17 (Phase 3 of RFC 0013) added three server-free scenarios exercising the reference workflow-chain expansion library (`conformance/src/lib/workflow-chain-expansion.ts`): `workflow-chain-expansion.test.ts` (parameter substitution + node id collision avoidance + edge rewriting + capability propagation + runtime-invariance contract), `workflow-chain-unresolvable-typeid.test.ts` (rejection with `chain_unresolvable_typeid` when a chain references an unknown typeId), and `workflow-chain-pack-signature-verification.test.ts` (Ed25519 verification recipe reuse from `node-packs.md §Signing`). Earlier that day (Phase 1) added `workflow-chain-pack-manifest-validation.test.ts` — server-free schema-validation scenario covering the new `workflow-chain-pack-manifest.schema.json` (positive sample + two negatives: kind/contents mismatch and invalid `chainId`). Closes RFC 0013 (`Workflow-chain packs`, `Draft`) Phases 1 + 3 alongside the new `spec/v1/workflow-chain-packs.md`, the `Capabilities.workflowChainPacks` block, and the registry build-index/conformance-check `kind` routing from Phase 2. Earlier that day, the suite added 27 `it.todo()` placeholder scenarios paired with RFCs 0014-0020 (host capability surfaces — fs, kvStorage, tableStorage, queueBus, sql/vector/search, blob/cache, mcp.serverMount). These promote to live assertions when each RFC reaches `Active` + the matching capability block lands in `schemas/capabilities.schema.json` + a reference host advertises the capability. Earlier additions include 18 Multi-Agent Shift scenarios (Phases 1-5) added 2026-05-10, the `registry-public.test.ts` public-registry healthcheck added 2026-05-11 (opt-in via `OPENWOP_TEST_PUBLIC_REGISTRY=true`), the `replay-llm-cache-key.test.ts` placeholder added 2026-05-11 (three `it.todo()` cases for the cross-host LLM cache-key recipe per `replay.md` §"LLM cache-key recipe"), the two `production-*.test.ts` scenarios added 2026-05-11 for the `openwop-production` profile per RFC 0009 (`production-backpressure.test.ts`, `production-retention-expiry.test.ts`), the four `auth-*.test.ts` scenarios added 2026-05-11/12 for the production-auth profiles per RFC 0010 (`auth-api-key-rotation.test.ts`, `auth-oauth2-client-credentials.test.ts`, `auth-oidc-user-bearer.test.ts`, `auth-mtls.test.ts` (opt-in via `OPENWOP_TEST_MTLS=1`)), `replay-retention-expiry.test.ts` added 2026-05-12 (capability shape + 410/422 envelope per `replay.md` §"Retention and garbage collection"), `bulk-cancel.test.ts` added 2026-05-12 (Phase B close-out of R1 — `POST /v1/runs:bulk-cancel`), the two Phase H launch-blocker advertisement-contract scenarios added 2026-05-12 (`mcp-toolcall-redaction.test.ts` for the MCP-1 invariant per `host-capabilities.md §host.mcp` + `threat-model-prompt-injection.md §UNTRUSTED`, and `http-client-ssrf.test.ts` for the SSRF + body-size cap advertisement contract on `capabilities.httpClient`), the `wasm-pack-abi-version-rejection.test.ts` Track 7 scenario added 2026-05-12 for the ABI-mismatch positive path via the `vendor.openwop.misbehaving-abi` pack per RFC 0008 §H, the `otel-trace-propagation-subworkflow.test.ts` Track 11 close-out added 2026-05-13 (parent + child run spans share the inbound traceparent's traceId across the `core.subWorkflow` dispatch boundary), and the three RFC 0012 (Memory Compaction Profile, `Active`) scenarios added 2026-05-13/14: `memory-compaction-sr1-carry-forward.test.ts` (load-bearing SR-1 §D), `memory-compaction-event-emitted.test.ts` (canonical §B payload shape), and `memory-compaction-provenance-tag.test.ts` (soft assertion on §C `compacted-from:<id>` convention). All three gate on `capabilities.memory.compaction.supported` + the host's test seam at `/v1/test/memory/{seed,compact}` (Postgres reference host enables both via `OPENWOP_MEMORY_COMPACTION=true OPENWOP_TEST_TRIGGER_COMPACTION=true`). 2026-05-15 (gap-closure CF-3) added `interrupt-token-matrix.test.ts` (malformed / unknown / replay / cross-run-id paths on `GET|POST /v1/interrupts/{token}`). 2026-05-31 (RFC 0078 portable tool catalog + RFC 0079 credential provenance / egress policy — the Active→Accepted behavioral gate) added four: `tool-catalog-projection.test.ts` (capability-gated on `toolCatalog.supported` via `behaviorGate('openwop-tool-catalog', …)` — the NORMATIVE `GET /v1/tools` list with each `ToolDescriptor` schema-valid + `source`/`safetyTier` in the closed vocab + content-free, `GET /v1/tools/{toolId}` round-trip + unknown-id 404, 401-unauthenticated, and the §F-2 cross-principal non-disclosure; black-box, no POST seam), `tool-session-lifecycle.test.ts` (gated on `toolCatalog.sessionLifecycle` — the §D `tool.session.opened`-before / `tool.session.closed`-after bracket over the RFC 0064 call events via the `POST /v1/host/sample/tools/session-run` seam, one shared `sessionId`, content-free), `egress-audience-binding.test.ts` (KEYSTONE — gated on `httpClient.egressPolicy.supported`; the §C confused-deputy MUST via `POST /v1/host/sample/egress/decide`: an out-of-audience egress is denied/downgraded with the credential NOT attached, a provenance-unevaluable egress fails closed — the behavioral leg of `egress-credential-audience-bound`), and `egress-decision-content-free.test.ts` (the SR-1 canary — the credential value never surfaces in `egress.decided` and `reason` stays in the CLOSED vocabulary). The maintained scenario-to-spec map lives in [`coverage.md`](./coverage.md); this README keeps the operator quickstart and the historical scenario notes below. 2026-08-08 (RFC 0142 — store-gated emission witness, additive, suite `1.65.0 → 1.66.0`) added one: `artifact-type-store-emission.test.ts` (leg A always-on server-free: `artifactCreated` REQUIRES `artifactType`; leg B behavioral, applicable only to hosts advertising `store: true` at either scope: a real run via the `runproduce` seam, asserting `artifact.created` on the standard events-poll wire with the bound type and `registered:true`. `store` absent ⇒ inapplicable in both modes — the facet is optional; advertised-without-seam fails strict. Stub-measured: silent and wrong-type emitters both red). 2026-08-08 (RFC 0141 — legacy artifact-type identifiers, additive, suite `1.64.0 → 1.65.0`) added one: `artifact-type-legacy-ids.test.ts` (always-on server-free prose-pinning — a bare legacy id is rejected by the manifest schema while a canonical id validates, and the corpus states normatively that legacy ids were never wire-conformant with no grandfather clause, that a migrating host MUST NOT rewrite historical `artifact.created.artifactType` values, that the read-side alias is permanent and MUST resolve where validation is decided, and that an alias map is a host shim, not a conformance claim. Host-side alias behaviour is witnessed at openwop-app, not by this suite; a rewritten log is undetectable after the fact). 2026-08-07 (RFC 0139 — host-side witness for pack-manifest extension opacity, additive, suite `1.63.0 → 1.64.0`) added one: `pack-manifest-extension-opacity.test.ts` (gated on `behaviorGate` — the host-side half RFC 0138 could not provide. The load-bearing leg is DIFFERENTIAL, not presence: install the same manifest with and without an unrecognized `vendor.conformance.*` extension and require the registration projection to be identical once extensions are stripped. Sink-agnostic, because a suite cannot enumerate a host's sinks. Measured against stub hosts — a violating stub that routes an unrecognized extension into a derived facet PASSES the presence legs and fails only the differential ones. Witnesses INSTALL-TIME sinks only; does not witness `artifact.created` (RFC 0138 G8) since this seam emits no run events. Landed with the G14 flip: `artifact-type-pack-install`, `artifact-type-store-without-render` and `chat-card-pack-execution` moved from bare `return` to `behaviorGate`, so advertised-with-no-seam now FAILS under `OPENWOP_REQUIRE_BEHAVIOR=true` instead of reporting green). 2026-08-06 (RFC 0138 — vendor-extension hatch on pack manifests, additive, suite `1.62.0 → 1.63.0`) added one: `pack-manifest-extensions.test.ts` (always-on server-free — every pack manifest root admits the `^(x-|vendor\.)` hatch, enumerated against an explicit in-scope count of 9 rather than a naming glob, because the first draft globbed `*-pack-manifest.schema.json` and silently skipped `frontend-plugin-manifest.schema.json`; the hatch stays NARROW — a misspelled canonical field is still rejected and no pattern anywhere matches a bare canonical-looking key; and the corpus states the MUST-ignore, the "ignore means ignore" definition, the pack-authored/untrusted framing, and the not-a-capability-channel rule normatively, since the schema alone cannot express "MUST ignore". Host-side honoring of MUST-ignore is NOT covered — that needs a host-sample seam behind `behaviorGate`, gaps G6/G7). 2026-08-05 (RFC 0137 — the behavioral half, suite `1.60.1 → 1.61.0`) added one: `form-content-instantiation.test.ts` (capability-gated on `host.forms.contentPacks` + the `POST /v1/host/sample/formcontent/instantiate` seam — instantiation goes through the host's NORMAL create path with no pack-bound routing destination, an unrecognized `vendor.*`/`x-` field type DEGRADES to a plain text input rather than failing, and pack-authored fields stay fully editable. Added because RFC 0137's original graduation gate was unsatisfiable: every leg it shipped was server-free and passed identically against a host that never implemented it). 2026-08-05 (RFC 0137 — form-content packs, additive, suite `1.58.0 → 1.59.0`) added one: `form-content-packs.test.ts` (always-on server-free corpus legs — the registry version manifest carries `kind: "form-content"`, the `templates` payload property AND the load-bearing `anyOf` payload branch; the new source manifest enforces the schema-discipline floor and rejects `email`/`textarea` as field types, `key` in place of `id`, an integer `templates[].version`, and any `runtime`; and — the regression guard that matters — `fields[].type` is asserted byte-identical to chat-card `inputs[].type` so neither declarative kind's field vocabulary can be widened alone. The host-side instantiation + trust-boundary behavior is capability-gated on `host.forms.contentPacks` and host-pending). 2026-07-23 (RFC 0135 — workflow-chain gallery visibility, additive, suite `1.57.0 → 1.58.0`) added one: `workflow-chain-internal-flag.test.ts` (always-on server-free corpus legs — the manifest §WorkflowChain carries a boolean `internal`, an `internal: true` chain validates and a non-boolean is rejected, and the spec pins the MUST-omit-from-default-gallery + not-an-authorization-boundary rules; the gallery-omission behavior is witnessed at the reference host, not over the wire). 2026-07-23 (RFC 0134 — edge-condition `truthy`/`falsy` operators, additive) added one: `edge-condition-truthy-falsy.test.ts` (always-on corpus legs — the `workflow-definition` + inlined manifest `§EdgeCondition` `type` enums carry `truthy`/`falsy`, a no-`right` truthy/falsy edge validates, the spec documents the no-`right`+required-`left` semantics — plus a capability-gated host-mapping leg that soft-skips until a reference host maps the operators). 2026-07-22 (RFC 0133 — workflow-chain composition, suite `1.55.1 → 1.56.0`) added five: three always-on server-free scenarios (`chain-subchain-sibling.test.ts` — sub-chain co-registration mints a deterministic child id + rewrites `config.subChainRef` → the child `config.workflowId` + dedups a doubly-referenced child; `chain-subchain-cycle-rejected.test.ts` — the public witness for `sub-chain-expansion-bounded`: self-composition AND a depth-bound breach both reject with `sub_chain_cycle`, an acyclic tree within the bound expands, an unresolvable ref is `sub_chain_unresolved`; `chain-produced-var-roundtrip.test.ts` — `producedVariables` emit into `variables[]` with no value + closed-world `variable_undeclared` rejection) plus two capability-gated scenarios (`chain-subchain-fanout.test.ts` — a `core.dispatch` child-run over a `subChainRef` worker + the manifest `not`-guard on a concrete `config.workflowId`, behavioral home of `sub-chain-child-tenant-scoped`; `chain-subchain-unsupported-refused.test.ts` — an unsupported host refuses a `subChains`-bearing chain with `sub_chain_unsupported` (422), never flattening) that soft-skip until a reference host wires runtime child dispatch. 2026-07-22 (RFC 0132 — anonymous-actor authorization) added six: `anonymous-actor-shape.test.ts` (always-on, server-free — validates the `capabilities.anonymousActor` advert + the §B.2 `writeEgressControls`-iff-`bounded-write-egress` conditional + `owner.principalKind` + the RFC 0049 `authorization.decided` audit reuse) plus five capability-gated behavioral scenarios (`anonymous-actor-default-deny`, `-no-secret-reach`, `-egress-guarded`, `-write-gated`, `-audit-opaque`) that drive the `/v1/host/sample/anon-surface/{tools,dispatch}` seam and soft-skip until a host wires a tool-enabled public surface — each the public witness for a reference-impl-tier SECURITY invariant that graduates to protocol tier once a host passes it non-vacuously. 2026-07-07 (RFC 0131 — agent-manifest `role` + the Skill profile) added `agent-manifest-role-profile.test.ts` (always-on, server-free schema-shape probe of the additive optional `AgentManifest.role` + the schema-encoded Skill profile: a `role:"skill"` manifest with `handoff` + scratchpad-only memory validates; one declaring `conversation`/`longTerm` memory or omitting `handoff` FAILS validation — a malformed-manifest reject, NOT an RFC 0072 `degraded[]` runtime tier; an absent `role` with any `memoryShape` validates unconstrained; a bad enum value fails — the public witness for `agent-skill-profile-stateless`). 2026-07-06 (RFC 0129 — data-residency, suite `1.53.1 → 1.54.0`) added `data-residency-admission.test.ts` (always-on `capabilities.dataResidency` + `residency.schema.json` shape probes + `residency_unavailable` error-registration check; plus capability-gated behavioral legs driving the NORMATIVE `POST /v1/runs` endpoint — an advertised region MUST NOT be rejected `residency_unavailable`, an unadvertised region MUST be rejected with that code at HTTP one-of 400/404/422 and create no run — advertise-only-what-you-honor, soft-skip until a host advertises `dataResidency`). 2026-07-06 (RFC 0127 + RFC 0128 — CDP Track-2, suite `1.52.0 → 1.53.0`) added `trigger-stream-cdc-sources.test.ts` (always-on schema probes for the `stream`/`change` TriggerEvent sub-objects — `op` REQUIRED negative, exactly-one rule, registration + capabilities vocabulary pins — plus capability-gated behavioral legs driving the existing `/v1/host/sample/trigger-bridge/ingest` + `/deliver` seams: schema-valid delivered envelopes, SR-1 content-free durable events with a body canary, `(topic,partition,offset)` dedup effectively-once) and `purpose-propagation.test.ts` (always-on `permittedPurposes` + `capabilities.purposePropagation` family shape probes, plus the capability-gated two-hop legs via the new `POST /v1/host/sample/purpose-propagation/forward` seam: onward label ⊆ received, derived-output ⊆ intersection of labelled inputs, unlabelled adds no constraint, `[]` fail-closed dropped with an unlabelled positive control). Both behavioral suites soft-skip pre-implementation and become REQUIRED once the host advertises the surface (advertise-only-what-you-honor). 2026-07-05 (RFC 0013 erratum A-lite — bundle + load the sample-pack fixture, suite `1.51.0 → 1.52.0`) bundled the `vendor.openwop.workflow-chain-sample` pack into the conformance package at `fixtures/pack-manifests/workflow-chain-sample.pack.json` (host-syncable, ships in `files`) and refactored `workflow-chain-host-expansion.test.ts` to **load** it + derive the expected expansion from the `expandChain()` reference library instead of hardcoding — so a live host serving `POST /v1/host/sample/workflow-chain:expand` is checked against the spec algorithm for the identical published pack (closes the RFC 0013 host-expansion witness's fixture gap; the seam still soft-skips until a host advertises `workflowChainPacks.hostExpansionSeam`). `fixtures-valid.test.ts` now schema-selects pack-manifest fixtures by `kind` (node-pack vs workflow-chain-pack). No scenario-file count change. 2026-07-05 (RFC 0013 erratum — host-expansion test seam decouple, suite `1.50.0 → 1.51.0`) re-gated `workflow-chain-host-expansion.test.ts` from the semantic `workflowChainPacks.supported` claim onto a new OPTIONAL `workflowChainPacks.hostExpansionSeam` test-harness sub-flag (no scenario-file count change), so a host advertising `workflowChainPacks.supported` / RFC 0124 `deferredParameters.supported` is no longer conscripted into the never-bundled `vendor.openwop.workflow-chain-sample` seam under `OPENWOP_REQUIRE_BEHAVIOR` — the semantic claim rides the server-free `workflow-chain-expansion.test.ts` legs, RFC 0124's deferred path its own `/chain/deferred-expand` seam. 2026-07-04 (RFC 0124 — portable per-run parameter deferral, suite `1.49.0 → 1.50.0`) added `workflow-chain-deferred-parameters.test.ts` (always-on, server-free legs against the reference `expandChainDeferred` in `conformance/src/lib/workflow-chain-expansion.ts`: non-sensitive deferral materializes `variables[]` with `defaultValue`+`type` and leaves ZERO `{{params.*}}` tokens (R3), a whole-value input token → variable-sourced PortValue, the bare param name is the auto-generated `configurableSchema` override key (R6); §Security legs: a `x-openwop-sensitive` prompt-body param materializes `source:"secret"` with the plaintext appearing NOWHERE — not bagged — a sensitive whole-value `node.input` fails closed `sensitive_param_not_deferrable` (422), a sensitive param on a host without `secrets` support fails closed, and a host without a `prompts.variable` source falls back to expansion-time (G5); plus schema-surface legs pinning the amended `source:"secret"` wording in the manifest schema + the `credentialRef` per-run supply shape; capability-gated host legs over `POST /v1/host/sample/chain/deferred-expand` for the bare-param override / `:fork` replay / `contentTrust:"untrusted"` fence / `[REDACTED]` sensitive compose, soft-skip 404/403). 2026-07-04 (RFC 0126 — data-parallel dispatch per-item input, suite `1.48.0 → 1.49.0`) added `dispatch-per-item-input.test.ts` (always-on, server-free schema legs on `orchestrator-decision.schema.json` §NextWorkerDecision: a well-formed index-aligned `nextWorkerInputs` validates, a decision omitting it stays valid (additive/back-compat), a non-object item and a non-array are rejected, a mis-named `perItemInputs` is rejected by `additionalProperties:false` (the fail-closed rail for pre-RFC-0126 strict validators), and a length-mismatch is ADMITTED at the wire because `nextWorkerInputs.length == nextWorkerIds.length` is not JSON-Schema-expressible — a host runtime MUST; capability-gated behavioral legs over `POST /v1/host/sample/dispatch/per-item` asserting a host advertising `capabilities.dispatch.perItemInput` projects `nextWorkerInputs[i]` into child `i` (per-item value wins over `inputMapping`), a length-mismatch fails with a `validation_error` dispatching no child, and a host NOT advertising the capability fails closed on a non-empty `nextWorkerInputs` rather than silently dropping it and dispatching N identical children; soft-skips on 404/403). 2026-07-02 (RFC 0122 — self-hosted runner, suite `1.47.0 → 1.48.0`) added `self-hosted-runner.test.ts` (always-on schema legs for the `selfHostedRunner` capability block + the dispatch/result/registration frame shapes; an advertisement-gated block-shape leg; capability-gated behavioral legs over `POST /v1/host/sample/runner/{register,dispatch}` asserting subject-first isolation, retriable `runner_unavailable`, and at-most-once dedup — the public test for the protocol-tier `runner-credential-non-transit` + `runner-output-untrusted-transport` invariants; soft-skips on 404). 2026-07-01 (RFC 0121 — subscription-reuse provider auth mode, suite `1.46.0 → 1.47.0`) added `aiproviders-subscription-scope.test.ts` (always-on schema leg: the `aiProviders.authModes` closed enum includes `subscription`; §B.7 advertisement-gated leg: a `subscription` provider MUST appear in `byok`; §B.8 bind-seam-gated leg over `POST /v1/host/sample/credentials/bind` asserting a tenant-scope binding is rejected with `credential_scope_forbidden` — the public test for the protocol-tier `subscription-credential-user-scope-only` invariant. §B.8 is gated on the seam rather than on advertisement, so a host that cannot lawfully advertise `subscription` can still witness the user-scope safety rail; soft-skips when the seam is unwired). 2026-06-29 (RFC 0120 — connection-pack `apiHosts` credential-egress allow-list, suite `1.45.0 → 1.46.0`) added `connection-pack-apihosts.test.ts` (always-on schema legs: the `connection-pack-apihosts-valid` fixture validates, an `openapi`-reach provider omitting `apiHosts` is rejected by the conditional-MUST `allOf`, and IP/wildcard/port/single-label/uppercase entries are each rejected; always-on matching-rule legs: the item-10 dot-anchored eTLD+1 suffix-containment rule permits subdomains + a tighter exact host and fails closed with no substring/suffix/prefix escape — the public tests for the protocol-tier `connection-pack-api-host-shape` + `connection-pack-egress-host-bound` invariants; plus a capability-gated behavioral egress allow-list leg over the new `POST /v1/host/sample/connection-packs/egress-check` seam, soft-skipping when unadvertised/unwired). 2026-06-28 (RFC 0118 — parallel sub-workflow fan-out and join, suite `1.44.0 → 1.45.0`) added `dispatch-fanout-parallel.test.ts` (always-on schema legs for `dispatch-config.schema.json` — accepts a valid `parallel` config + each `joinPolicy.mode` + `maxConcurrency`, rejects unknown enum values / `additionalProperties` on `joinPolicy` / non-positive `maxConcurrency`, keeps a pre-RFC-0118 config valid — and the `dispatchFanOut`/`dispatchJoin` event `$defs` of `run-event-payloads.schema.json` — `fanOutPolicy` const `parallel`, `childCount ≥ 2`, the required replay-deterministic `mergeOrder`; capability-gated behavioral legs over `POST /v1/host/sample/dispatch/fanout` (wait-all/collect → `joinOutcome: satisfied` + full `children[]` + `mergeOrder`) plus the un-gated registration-rejection leg (`fanOutSupported:false` host MUST reject `parallel` with a 4xx); soft-skips on absent `dispatch.fanOutSupported` / `parallel` ∉ `fanOutPolicies`). 2026-06-27 (RFC 0117 — front-end plugin packs, suite `1.43.0 → 1.44.0`) added `frontend-plugin-packs.test.ts` (always-on schema legs for `frontend-plugin-manifest.schema.json` + the `ui-plugin/1` envelope `ui-plugin-message.schema.json`: manifest validity, `runtime`-forbidden, path-traversal-guarded `entry`, the closed `hostApi` allowlist, the version-token `artifact_conflict` + `currentVersion` concurrency shape, and no credential-bearing envelope field (`additionalProperties:false`); the capability-shape leg asserts `isolation` pins to the `cross-origin-iframe` const; capability-gated behavioral legs over `POST /v1/host/sample/ui-plugin/rpc` assert an undeclared method → `method_not_allowed` and a stale `artifact.write` → `artifact_conflict` with no persist; soft-skips on absent `capabilities.uiPlugins.supported` or `404`/`403` on the seam (RFC 0117 stays Active pending host witnesses); the public test for the protocol-tier `frontend-plugin-{isolation,egress,rpc-allowlist,no-byok}` invariants). 2026-06-26 (RFC 0116 — portable prompt-prefix cache, suite `1.42.0 → 1.43.0`) added `prompt-prefix-cache.test.ts` (advertisement-shape on `aiProviders.promptPrefixCache` + behavioral legs over the OPTIONAL `POST /v1/host/sample/ai/generate` seam (`host-sample-test-seams.md` §16): (a) outcome-invariance — a generate with `cachePrefixId` and a control without produce the same accepted envelope + identical `provider.usage.inputTokens`/`outputTokens` (cost-hint-only, replay-invariant); (b) cache-hit observable — a repeat generate shows `cacheReadTokens > 0`; (c) cross-tenant isolation — tenant B’s first use of tenant A’s `cachePrefixId` shows `cacheReadTokens == 0`, the public test for the protocol-tier `prompt-prefix-cache-cross-tenant-isolation` invariant (the host MUST key its provider cache by `(tenant, cachePrefixId)`, never global); (d) secret-free — the cost-only cache-token fields carry no prompt substrings (SR-1); soft-skips on absent `aiProviders.promptPrefixCache.supported` or `404`/`405` on the seam, since RFC 0116 defers reference-host impl as provider-gated). 2026-06-26 (RFC 0114 — A2UI surface deltas, suite `1.41.0 → 1.42.0`) added `a2ui-surface-delta-transport.test.ts` (always-on legs use a cast-free, dependency-free client-side RFC 6902 applier + Ajv2020 to assert: the new `a2ui-surface-delta-frame.schema.json` compiles, the op enum excludes `test`, a full surface + delta frames reconstruct the expected tree AND equal the full a non-negotiating subscriber materializes and re-validate against the closed catalog, an out-of-catalog/script-bearing delta fails closed-catalog validation post-patch — the `a2ui-surface-no-code-exec` boundary holds — and the recorded envelope is always the full surface; the HTTP leg is capability-gated on `a2uiSurface.deltaTransport` and soft-skips on absent host/capability or `404`/`405` on the OPTIONAL `GET /v1/host/sample/a2ui/surface/materialized` seam). 2026-06-26 (RFC 0111 — context economy, suite `1.40.0 → 1.41.0`) added `context-budget-transcript-bound.test.ts` (capability-gated on `multiAgent.executionModel.contextBudget.transcriptTokenBudget` being present via `behaviorGate(openwop-context-budget, …)` — drives the `conformance-context-budget-multiturn` orchestrator fixture, reads the host’s per-iteration accounting via the OPTIONAL seam `GET /v1/host/sample/agent/transcript-window?runId=…&iteration=N` (`host-sample-test-seams.md` §14), and asserts `tokenCount ≤ transcriptTokenBudget` in the advertised `tokenCounter` unit, that every `eventId` in the seam accounting is a real persisted run event (internal-consistency cross-check against `/v1/host/sample/test/runs/:runId/events`), recent-tail + no-double-count, every `summarizedRanges.summaryRef` has a matching `context.summarized` event, and `keepLastTurns` recent turns are fed verbatim — never inside a summarized range; soft-skips on `404`/`405` since the RFC defers reference-host impl) + `context-summarization-replay.test.ts` (capability-gated on `multiAgent.executionModel.contextBudget.summarization.supported` via `behaviorGate(openwop-context-summarization, …)` — replays the run via `:fork mode:replay` and asserts the recorded `context.summarized` → `summaryRef` records are REUSED, never re-summarized, the direct analogue of RFC 0041 envelope-refusal recovery; soft-skips when the event-log seam is unwired, no `replay` mode is advertised, or the run produced no summarization). 2026-06-26 (RFC 0113 — memory injection budget, suite `1.39.0 → 1.40.0`) added `memory-injection-budget.test.ts` (capability-gated on `memory.injectionBudget.supported === true` via `behaviorGate(openwop-memory-injection-budget, …)` — drives the `conformance-agent-memory-injection-budget` fixture through the host-sample memory seam and asserts the budgeted injection read's cumulative tokens ≤ the requested `tokenBudget` in the advertised `tokenCounter` unit (`o200k_base`/`cl100k_base`/`chars`/`host-defined`), an over-budget single entry is omitted not truncated, and re-asserts SR-1 (`[REDACTED:<secretId>]` content) + CTI-1 (cross-tenant probe returns empty) on the budgeted path; the `rank:'relevance'` leg DELEGATES to `memory.search` semantic (RFC 0080) and asserts relevance ordering differs from recency ONLY when the host ALSO advertises `memory.search` semantic, else it soft-skips — there is NO ranking primitive in `injectionBudget`; soft-skips on hosts that do not advertise `memory.injectionBudget`). 2026-06-26 (RFC 0112 — compact tool projection, suite `1.38.0 → 1.39.0`) added `tool-catalog-compact-projection.test.ts` (capability-gated on `toolCatalog.compactView === true` via `behaviorGate(openwop-tool-catalog-compact, …)` — drives `GET /v1/tools?view=compact` and asserts the host returns the `{ tools: CompactToolDescriptor[] }` envelope where every descriptor validates against `compact-tool-descriptor.schema.json` with the heavy `ToolDescriptor` fields dropped, every present `inputSchema` satisfies the self-contained compact structural subset (top-level `type:"object"`+`properties`; no `$ref`/`oneOf`/`allOf`/`anyOf`/`not`/`patternProperties`/`dependentSchemas`), and the compact `tools[]` `toolId` set EQUALS the standard view set for the same principal (projection completeness); soft-skips on hosts that do not advertise `toolCatalog.compactView`). 2026-06-26 (RFC 0115 — run transport economy, suite `1.37.0 → 1.38.0`) added `run-transport-economy.test.ts` (capability-gated on `restTransport.conditionalRunGet === true` and a non-empty `restTransport.contentEncodings` — drives `GET /v1/runs/{runId}` and asserts a sequence-derived strong `ETag` on the `200`, `If-None-Match` → `304` with an empty body while the run is unchanged, the `ETag` ROTATES after the `conformance-approval` fixture advances `waiting-approval → completed` (proving it derives from the latest persisted event-log sequence, not a coarser signal that would leave a `304` stale), and each advertised `Content-Encoding` (`gzip` baseline; `br`/`zstd` optional) round-trips byte-identically to the identity body; soft-skips on hosts that do not advertise `restTransport`). 2026-06-24 (RFC 0110 — channel presence, behavioral leg) added `channel-presence-behavioral.test.ts` (capability-gated on `channelPresence.supported` via `behaviorGate('openwop-channel-presence', …)` — drives the `POST /v1/host/sample/channel-presence/snapshot` seam and asserts a live `channel.presence` snapshot is the CLOSED `{conversationId,present,typing}` shape (no PII), every ref is an opaque RFC 0041 `user:`/`agent:` subject, `typing ⊆ present`, and the snapshotting member is non-vacuously present; soft-skips on 404/405 — a host whose presence is bound to a product flow witnesses via its own route test + an INTEROP-MATRIX row, the RFC 0086 dual-staging). 2026-06-24 (RFC 0110 — channel presence, Accept cycle) added `channel-presence-shape.test.ts` (always-on server-free — the OPTIONAL `channel.presence` ephemeral payload validates a conforming snapshot, REQUIRES `conversationId`+`present`, is CLOSED `additionalProperties:false` (the no-PII guard), `typing` optional; `channel.presence` is in the `RunEventType` enum; the `channelPresence` capability block is declared + closed). 2026-06-24 (RFC 0109 — conversation-turn model provenance, Accept cycle) added `conversation-turn-model-provenance-shape.test.ts` (always-on server-free — `agent.model` `{provider, model}` validates conforming / both-required / closed-SR-1 / optional-back-compat, + the `conversationTurnModelProvenance` capability declared + closed). 2026-06-24 (RFC 0108 — self-hosted / OpenAI-compatible provider class, Accept cycle, suite `1.36.0 → 1.37.0`) added the gated behavioral honesty leg `aiproviders-selfhosted-honesty.test.ts` (gated on `aiProviders.selfHosted.length > 0` via `behaviorGate('openwop-selfhosted-providers', …)` — drives `POST /v1/host/sample/ai/call` against an advertised `selfHosted` id and asserts **§A.2** the dispatch reaches a real configured endpoint (success or transport error — never `capability_not_provided` / `provider_not_supported`, which would prove a dishonest advertisement with no endpoint behind it) and **§D** the endpoint location — supplied out-of-band via `OPENWOP_TEST_COMPAT_ENDPOINT`, checked as the raw string + bare `host`/`host:port` — never appears in the seam response or error payload; soft-skips on 404 / when the env var is unset for the §D leg). 2026-06-24 (RFC 0108, suite `1.35.0 → 1.36.0`) added the always-on server-free shape leg `aiproviders-selfhosted-shape.test.ts` (the additive `aiProviders.selfHosted` advertisement: a `string[]` with `uniqueItems`/`minLength:1` items, absent from `aiProviders.required`, validates a conforming array via Ajv2020 while rejecting non-array / duplicate / empty-string forms, and enforces the two §A rules JSON Schema cannot express — §A.1 every `selfHosted` entry is a subset of `supported`, and §A.3 / `self-hosted-endpoint-no-disclosure` no entry is URL-shaped (`://`, bare `host:port`, or leading `/` path) — exercised against good/bad example docs). 2026-06-23 (RFC 0106 — real-time voice session profile, Accept cycle) added six gated behavioral scenarios driving the openwop-app live host (rev `00293-89w`): `voice-transcription-streaming` + `voice-transcription-unadvertised` (the `call-transcriber` seam; the latter gated-by-absence), `voice-synthesis-streaming` (the `stream:true` synthesis arm → metadata-only `voice.synthesis_chunk` events), `voice-bargein-no-partial-leak` (the `/voice/barge-in` seam — `voice.barge_in`→`voice.cancelled` with no chunk after; **graduated `voice-bargein-no-partial-leak` reference-impl→protocol** on the live proof), and `voice-interim-not-durable` + `voice-streamref-tenant-bound` (§F INV-1/INV-4; soft-skip on the §E `transcription_unsupported` / no-live-streamRef path — stay reference-impl until a host with a scripted-interim / live-streamRef arm proves them). 2026-06-23 (RFC 0107 — publishable declarative pack kinds) added one: `registry-declarative-kinds.test.ts` (always-on server-free — the registry version-manifest carries the `kind` discriminator + per-kind declarative payload, `runtime` is conditional on `kind` via `allOf if/then/else`, published artifact-type and connection manifests validate, and a declarative-with-`runtime` or node-without-`runtime` manifest is rejected). 2026-06-23 (RFC 0107 correction, suite `1.34.0 → 1.35.0`) extended that scenario with two cases — a published **chat-card** pack manifest (`kind: "card"`, RFC 0071) validates, and the never-canonical `kind: "chat-card"` is **rejected** — fixing a kind-string mismatch where RFC 0107's published schema enumerated `chat-card` while RFC 0071 (authoritative) defines `card` (no scenario-file count change; cases added to the existing file). 2026-06-23 (RFC 0106 — real-time voice session profile, Phase 2) added one: `voice-event-payloads-shape.test.ts` (always-on server-free — all seven `voice.*` types are in the `RunEventType` enum, each has a payload `$def` via `typeIndex`, `voice.transcript` REQUIRES `contentTrust:"untrusted"` (the schema-enforced half of `voice-transcript-untrusted`), `voice.synthesis_chunk` is metadata-shaped (seq+mimeType required; bytes by `url`/`streamRef`), and the content-free events reject unknown properties). Phase 2 also lands the `voice.*` payload `$defs` in `run-event-payloads.schema.json` + the `asyncapi.yaml` messages + the four §F `SECURITY/invariants.yaml` rows (1 protocol-tier `voice-transcript-untrusted` + 3 reference-impl behavioral, graduating at `Active → Accepted`). The gated behavioral legs (`voice-transcription-streaming`/`-unadvertised`, `voice-synthesis-streaming` + the three behavioral invariant scenarios) land with the reference host at `Active → Accepted`. 2026-06-23 (RFC 0106 — real-time voice session profile, Phase 1) added one: `aiproviders-realtimevoice-shape.test.ts` (always-on server-free — the `aiProviders.realtimeVoice` object advertisement: the four sub-flags `transcription`/`synthesis`/`turnDetection`/`bargeIn` are declared, `realtimeVoice` is absent from `aiProviders.required`, the `turnDetection`/`bargeIn ⇒ transcription` `dependentRequired` closure and the `synthesis ⇒ speechSynthesis` if/then closure hold via Ajv2020, and out-of-enum / boolean sub-flag values are rejected). The gated behavioral legs (`voice-transcription-streaming` / `-unadvertised`, `voice-synthesis-streaming`) and the four §F live-ingress invariant scenarios land in Phase 2 at the `Active → Accepted` cycle. 2026-06-22 (RFC 0101 — multi-party group conversation) added two — `multi-party-conversation-shape.test.ts` (always-on server-free — asserts the three additive RFC 0101 wire facts: a 3-agent council `conversation.opened` participant roster (instance ids) + a user opening turn validates, every `role: 'agent'` turn carrying a roster-instance `speakerId` validates while one OMITTING `speakerId` MUST FAIL schema validation (the `allOf`/`if role==='agent' then required:['speakerId']` conditional), a non-AgentRef participant item is rejected, the `capabilities.multiPartyConversation { supported, maxParticipants? }` block is declared + closed and rejects extras / `maxParticipants:1` / a missing `supported`, and the non-participant membership predicate is asserted server-free) and `multi-party-conversation-behavioral.test.ts` (capability-gated on `multiPartyConversation.supported` via `behaviorGate('openwop-multi-party-conversation', …)` — drives the conformance-only seam `POST /v1/host/sample/conversation/multi-party/{open,exchange}` (`host-sample-test-seams.md`, since RFC 0101 mints no normative client trigger to open a council): a 3-agent council opens and a roster-valid attributed agent turn is accepted, while a `role:'agent'` turn missing `speakerId`, a non-participant `speakerId`, and an over-`maxParticipants` open are each rejected with `error.code:'validation_error'` (status-tolerant 400/422 per RFC 0005 §E); soft-skips on 404/405 — reference impl: the postgres example host). 2026-06-20 (RFC 0105 — speech synthesis adapter) added three: `aiproviders-speechsynth-shape.test.ts` (always-on server-free — the `aiProviders.speechSynthesis` `const "supported"` flag is declared, absent from `aiProviders.required`, and a string-const advertisement validates while the object form `{supported:true}` is rejected), `speech-synthesis-roundtrip.test.ts` (gated on `aiProviders.speechSynthesis === "supported"` via `behaviorGate('openwop-speech-synthesis', …)` — an advertising host's `callSpeechSynthesizer` round-trip via the `POST /v1/host/sample/ai/call-speech-synthesizer` seam returns `audio` with EXACTLY ONE of `url`/`base64`, a non-empty `mimeType`, and the echoed `voiceId`; soft-skips on 404), and `speech-synthesis-unadvertised.test.ts` (gated-by-absence via `behaviorGate('openwop-speech-synthesis-unadvertised', …)` — a host NOT advertising `speechSynthesis` MUST reject the call with `speech_synthesis_unsupported`, never a silent no-op). 2026-06-19 (RFC 0104 — portable HITL approver routing) added one: `interrupt-approver-routing.test.ts` (server-free Ajv2020 — the `interrupt.approverRouting` capability block shape, the additive optionality of `approverGroupRefs` / `approverRoleRefs` / `audience` on the `ApprovalData` schema, the closed `audience` object, and the §"Portable approver routing" `notifyTargets` reference rule that `audience` DEFAULTS to the resolved eligibility union when omitted and OVERRIDES it when present; the capability-gated leg asserts an advertising host's `interrupt.approverRouting` is honest — `refKinds` ⊆ {group, role}, `audience` boolean — and soft-skips when the host does not advertise the capability). 2026-06-17 (RFC 0103 — localized content surface) added one: `localized-content-delivery.test.ts` (server-free Ajv2020 — the four content schemas + the §C `resolveSection` merge + §A capability coherence; the public test for `content-published-cache-no-draft` / `content-response-tenant-scoped` / `content-no-cross-tenant-enumeration`; the live legs gate on `capabilities.content.supported` and soft-skip without a `GET /v1/content/pages/{slug}` target). 2026-06-15 (RFC 0102 — A2UI agent-authored interface surfaces) added five: `a2ui-surface-shape.test.ts` (server-free Ajv2020 — the closed core `ui.a2ui-surface` payload validates, while an out-of-catalog component / extra script-bearing property / unenumerated `catalogVersion` / `action.target` outside `enum["resume","exchange"]` each fail; the structural half of `a2ui-action-confinement` and the enabling precondition for the render-side `a2ui-surface-no-code-exec` / `a2ui-surface-no-network-egress` reference-app probes), `a2ui-surface-degrades.test.ts` (the kind is optional/advertised, not a MUST-recognize universal kind, and an unadvertised kind is gated — N6 — never crashing the run), `a2ui-surface-version-refusal.test.ts` (the enumerated `catalogVersion` rejects an unadvertised version → `unknown_schema_version`, and the surface schema carries no external `$ref`), `a2ui-surface-replay.test.ts` (all `$ref`s internal so a stored surface `:fork`/replays deterministically; same-`correlationId` + divergent `type` → `envelope_correlation_conflict`), and `a2ui-untrusted-blocks-approval.test.ts` (a `meta.contentTrust:'untrusted'` surface is trust-gated and MUST NOT advance an approval interrupt — composition of `untrusted_content_blocks_approval`). The four behavioral legs soft-skip on 404 (host-pending; the `openwop-app` reference renderer is the render-side probe). 2026-06-14 (RFCs 0099/0100 — external-event trigger ingestion + async/durable A2A tasks) added one new scenario (`trigger-ingestion.test.ts`) and extended `a2a-task-roundtrip.test.ts` with the RFC 0100 async subtests: `trigger-ingestion.test.ts` (RFC 0099 — always-on `TriggerEvent` / `TriggerSubscriptionRegistration` schema legs incl. the §F.1 per-source one-of, the `AttachmentRef.ref`-only rule + raw-URL rejection backing `trigger-ingestion-ssrf`, and the content-free `trigger.delivery.attempted` shape backing `trigger-ingestion-content-redaction`; plus a capability-gated behavioral leg on `triggerBridge.ingestion` driving the `POST /v1/host/sample/trigger-bridge/ingest` seam for SSRF refusal + header-redaction), and the `a2a-task-roundtrip.test.ts` additions (RFC 0100 — always-on `A2ATaskState` + `capabilities.a2a` shape legs incl. the lowercase-hyphen state enum, the `PushConfig` `url`-required + truncated-`tokenFingerprint` rule backing `a2a-push-egress-ssrf`, the no-inline-inputs `additionalProperties:false` SR-1 check; plus capability-gated durable-`tasks/get`-after-disconnect and push-SSRF behavioral legs on `a2a.durableTasks` / `a2a.pushNotifications` via the `/v1/host/sample/a2a/tasks/*` seam). 2026-06-13 (RFCs 0096/0097/0098 — reviewable learning, standing goals, agent-platform portability) added three always-on-plus-gated scenarios: `proposal-reviewable-learning.test.ts` (RFC 0096 — the `agents.proposals` shape + the `Proposal` round-trip incl. the dropped `rule` kind + the content-free `proposal.{created,activated}` events, plus a gated apply-without-scope→403 leg; backs `proposal-inert-until-applied` + `proposal-no-resynthesis`), `goal-standing-continuation.test.ts` (RFC 0097 — the `agents.goals` shape + the `Goal` round-trip + the content-free `goal.{evaluated,closed}` events, plus gated bounded-termination→422 + judge-only-completion legs; backs `goal-continuation-bounded` + `goal-completion-judge-only`), and `export-bundle-portability.test.ts` (RFC 0098 — the `portability` shape incl. the `import⇒dryRun` if/then + the `ExportBundle` round-trip rejecting every credential-named field + the content-free `import.applied` event, plus a gated literal-credential-import→422 leg; backs `export-bundle-no-credential-material`). 2026-06-11 (RFCs 0093/0094 — protocol hardening + wire-shape reconciliation) added five: `version-fold.test.ts` (the `version-negotiation.md` §`X-Force-Engine-Version` cross-version matrix through the previously-orphaned `conformance-version-fold` fixture — closes catalog gap F5; soft-skips when `Capabilities.testing.forceEngineVersionRange` is unadvertised), `stream-text-fixture.test.ts` (the `stream-modes.md` §`messages` fold through the deterministic `stream-text` mock provider + the previously-orphaned `conformance-stream-text` fixture — closes catalog gap F1), `i18n-negotiation.test.ts` (gated on `capabilities.i18n` via `behaviorGate('openwop-i18n', …)` — an unsupported or malformed `Accept-Language` never 400s, `Content-Language` reflects the locale actually used, and error `code` strings stay the canonical English tokens), `grpc-transport.test.ts` (gated on `capabilities.grpc` via `behaviorGate('openwop-grpc-transport', …)` — advertisement-shape only per `grpc-transport.md` §Field semantics: `service` MUST be `openwop.v1.Engine`, the `tls` enum, `grpcs?://` endpoint URIs, `supportedTransports` includes `grpc` when exposed, production claimants require `tls: "required"`; no gRPC dialing), and `webhook-tenant-isolation.test.ts` (RFC 0093 §A.3 — backs the new protocol-tier `webhook-cross-tenant-isolation` invariant; a two-tenant proof through the `/v1/host/sample/test/surface` seam plus black-box registration-surface scoping). `spec-corpus-validity.test.ts` also gained the RFC 0094 §A satisfiability probe: canonical `createRun` bodies MUST pass the composed request schema (closed via `unevaluatedProperties: false` at the composition site, never inside an `allOf` branch) and an undeclared property MUST fail. 2026-06-07 (RFCs 0090/0091/0092 — verifier turn + convergence, multimodal perception input, agent capability requirements) added six: the always-on, server-free shape probes `agent-verifier-shape.test.ts`, `aiproviders-input-shape.test.ts`, `agent-requires-capabilities-shape.test.ts`, plus the capability-gated **behavioral** legs `agent-capability-degraded-projection.test.ts` (RFC 0092 §B — the `degraded[]` projection on `GET /v1/agents`, black-box, non-vacuous via `OPENWOP_DEGRADED_CAPABILITY_AGENT_ID`), `callai-multimodal.test.ts` (RFC 0091 §A/§B — advertised modality accepted / unadvertised → `unsupported_modality`, via the `POST /v1/host/sample/ai/call` seam), and `verifier-gating.test.ts` (RFC 0090 §B — a `fail` verdict blocks commit, via the `POST /v1/host/sample/agents/verify-run` seam). The three behavioral legs soft-skip by default and hard-fail under `OPENWOP_REQUIRE_BEHAVIOR=true` — the Active→Accepted reference-host proof for each RFC. 2026-06-02 (RFC 0082 §B — deployment channel resolve-and-pin, production-path coverage) added `agent-channel-dispatch.test.ts` (capability-gated on `agents.deployment.supported` + the seeded `conformance-agent-channel-dispatch` fixture + advertised `replay` mode via `behaviorGate('openwop-deployment-channel-dispatch', …)` — proves the §B pin from a REAL run graph, complementing `agent-deployment-lifecycle.test.ts` Leg 4's host-sample seam: a canonical `POST /v1/runs` of a node binding `agent.channel:"stable"` MUST record `resolvedChannel` + `resolvedAgentVersion` on `agent.invocation.started` (RFC 0077), a `:fork{mode:"replay"}` MUST re-read that recorded version, and the seam-guarded Leg 3 MOVES the channel then asserts a replay STILL carries the original pin — never re-resolving a moved channel; soft-skips by default, hard-fails under `OPENWOP_REQUIRE_BEHAVIOR=true` — the production-path proof of the §B contract). 2026-06-01 (RFC 0085 — `openwop-agent-platform` meta-profile, the Active→Accepted behavioral gate) added `agent-platform-aggregate-evidence.test.ts` (capability-gated on a host CLAIMING `openwop-agent-platform` in its live discovery `profiles[]` via `behaviorGate('openwop-agent-platform', …)` — the §C/§D honest-advertisement rule on the live `/.well-known/openwop`: the claim MUST satisfy the §B floor predicate (`isAgentPlatformPartial` → `partial`/`full`, never `none`), backed by the per-capability evidence not the profile string; `OPENWOP_AGENT_PLATFORM_TIER=full` forces the non-vacuous full bar — all governance terms + tenant installScope + all 16 §D terms; server-requiring, the always-on §B/§D derivation legs stay in `agent-platform-profile.test.ts` — the RFC 0085 → Accepted bar). 2026-06-01 (RFC 0084 — budget, quota + cost policy, the Active→Accepted behavioral gate) added `budget-enforcement.test.ts` (capability-gated on `budget.supported` via `behaviorGate('openwop-budget-enforcement', …)` — the §C/§D enforcement via the new `POST /v1/host/sample/budget/run` seam + the test event-log seam: a `hard-cost-exhaust` run emits the strict-ordered `budget.reserved → budget.consumed → budget.threshold.crossed{percent} → budget.exhausted → cap.breached{kind:"budget-cost"} → run.failed{error:"budget_exhausted"}` chain; a `model-denied` run is refused `budget_model_denied` BEFORE the provider call (fail-closed); an `advisory` host emits the `budget.*` events without stopping; every `budget.*` payload content-free backing `budget-no-pricing-leak`; new lib helper `src/lib/budgetPolicy.ts`; soft-skips on 404 — the RFC 0084 → Accepted bar). 2026-06-01 (RFC 0080 — agent memory capability reconciliation, the Active→Accepted behavioral gate) added `memory-degraded-projection.test.ts` (capability-gated on `agents.manifestRuntime.supported` + `memory.supported` via `behaviorGate('openwop-memory-degraded', …)` — the §C degraded-projection iff-contract on the NORMATIVE `GET /v1/agents`: a degraded inventory entry MUST carry `memoryDegraded:true` + a non-empty, unique `degradedMemoryDimensions[]` from the closed §A-name enum, a non-degraded entry MUST NOT, the inventory is non-empty, and the degraded branch runs non-vacuously when `OPENWOP_DEGRADED_AGENT_ID` names a known-degraded agent; black-box, no POST seam — the RFC 0080 → Accepted bar). This batch also documents the two RFC 0068 conformance seams (`POST /v1/host/sample/memory/consolidate` + `.../commitment/fire`) in `host-sample-test-seams.md` (the 0068 gated scenarios shipped in 1.14.0). 2026-06-01 (RFC 0034 — collector-side BYOK-canary inspection) added `otel-collector-canary-inspection.test.ts` (always-on server-free: stands up a real `OtelCollector`, POSTs synthetic OTLP/HTTP-JSON traces + metrics through its actual ingest path, and proves the new `findCanaryLeakage()` inspector catches a canary embedded in a span attribute / resource attribute / span name / metric data-point attribute while reporting ZERO hits on a redacted payload and never matching an empty canary — the non-vacuous proof that the conformance collector now inspects what the host's OTLP exporter ACTUALLY shipped over the wire, closing the `secret-leakage-otel-attribute` / `-debug-bundle-otel` collector-seam gap; the live capability-gated complement is the new collector-export describe block in `secret-leakage-otel-attribute.test.ts`). 2026-06-01 (RFC 0035 — sandbox wall-clock timeout, the 7th-of-8 graduation) added `sandbox-wasm-timeout.test.ts` (worker-driven server-free: `probeTimeout` in `wasm-sandbox-probe.ts` spawns a worker thread running the committed `misbehaving-timeout.wasm` + a main-thread kill-timer — the thread preemption a same-thread probe can't do — asserting `sandbox_timeout` with a well-behaved positive control; graduates `node-pack-sandbox-timeout` reference-impl→protocol, so 7 of 8 `node-pack-sandbox-*` invariants are now protocol-tier, only the JS-specific `no-eval` permanently exempt). 2026-05-31 (audit-response black-box / graduation batch) added three more: `sandbox-wasm-isolation.test.ts` (RFC 0035 — drives the committed `fixtures/wasm-sandbox/*.wasm` through `wasm-sandbox-probe.ts`: escape/capability-gate via static `WebAssembly.Module.imports()`, an OOB-store memory trap, double-instantiate isolation; 10/10; graduates 6 `node-pack-sandbox-*` invariants reference-impl→protocol), `workspace-cross-tenant-isolation-blackbox.test.ts` (RFC 0059 — two-credential black-box on the normative §C `/v1/host/workspace/files` endpoints: owner A writes, a second-tenant credential fails closed; no seam), and `prompt-resolution-chain-event.test.ts` (RFC 0029 — reads the durable `agent.promptResolved.chain[]` precedence record via the normative `GET /v1/runs/{runId}/events/poll`; no seam) — each the production-path proof that graduates its surface into the `openwop-core-standard` floor. 2026-05-31 (RFC 0088 — the `openwop-core-standard` Core Standard Profile, the audit-response Core Candidate target) added `core-standard-profile.test.ts` (always-on server-free derivation probe: `isCoreStandard` derives the §B floor — `openwop-core` ∧ `openwop-interrupts` ∧ (`openwop-stream-sse` ∨ `openwop-stream-poll`) — a bare `openwop-core` host without interrupts is excluded, a host with no event transport fails, and the annex is absent from `deriveProfiles` because it composes rather than redefines). 2026-05-31 (RFC 0082 — agent deployment lifecycle, the Active→Accepted behavioral gate) added `agent-deployment-lifecycle.test.ts` (capability-gated on `agents.deployment.supported` via `behaviorGate('openwop-deployment-lifecycle', …)` — the §E promotion contract via the new `POST /v1/host/sample/agents/deployment-transition` seam + the test event-log seam across four legs: `promote` (authorize RFC 0049 → approvalGate RFC 0051 → eval-verify RFC 0081 → content-free `deployment.promoted` with a seven-state `toState` + `toVersion`, the record validating `agent-deployment.schema.json`), `unauthorized` (fail-closed — `allowed:false`, no `deployment.promoted`, the behavioral leg of `deployment-promotion-fail-closed`), `eval-gate-unmet` (`eval_gate_unmet` denial, §E-3), and `channel-pin` (the §B `resolvedAgentVersion` recorded-fact on `agent.invocation.started`); new lib helper `src/lib/agentDeployment.ts`; soft-skips on 404 — the RFC 0082 → Accepted bar). 2026-05-31 (RFC 0081 — agent evaluation, the Active→Accepted behavioral gate) added `agent-eval-run.test.ts` (capability-gated on `agents.evalSuite.supported` via `behaviorGate('openwop-eval-run', …)` — the §B `mode:"eval"` projection via the new `POST /v1/host/sample/agents/eval-run` seam + the test event-log seam: `eval.started`-first → one `eval.scored` per task → `eval.completed`-once ordering (count == `eval.completed.taskCount`), the content-free `eval.scored` legs (`score` ∈ 0..1) backing `eval-summary-no-content-leak`, and the NORMATIVE `GET /v1/runs/{runId}/eval-summary` schema-valid `EvalSummary` round-trip with `passedCount <= taskCount`; new lib helper `src/lib/agentEval.ts`; soft-skips on 404 — the RFC 0081 → Accepted bar). 2026-05-31 (RFC 0083 — durable trigger bridge, the Active→Accepted behavioral gate) added `trigger-bridge-delivery.test.ts` (profile-gated on `openwop-trigger-bridge` derived from the live discovery doc — the §C delivery model via the `POST /v1/host/sample/trigger-bridge/deliver` seam + the test event-log seam: dedup→effectively-once `trigger.delivery.attempted{delivered}` (§C-1), retry-exhaustion→`{dead-lettered}` + `trigger.subscription.state.changed{toState:dead-lettered}` (§C-2 + RFC 0053), and the delivered run's `run.started.causationId` == the delivery id (§C / RFC 0040); both `trigger.*` events content-free; the always-on shape stays in `trigger-bridge-shape.test.ts`; new lib helper `src/lib/triggerBridge.ts`). 2026-05-31 (RFC 0087 — agent org-chart, the Active→Accepted behavioral gate) added two capability-gated behavioral scenarios (both gated on `agents.orgChart.supported`, black-box on the normative `/v1/agents/org-chart` surface — no new POST seam): `agent-org-chart-scoping.test.ts` (the `GET /v1/agents/org-chart` tree-shape — departments form an acyclic `parentDepartmentId` tree, members reference `host:<id>` roster entries — + the §D responsibility roll-up via `GET /v1/agents/org-chart/{departmentId}` with a deduped `responsibilities[]` union + the RFC 0074 cross-tenant 404 via `OPENWOP_CROSS_TENANT_ORG_CHART_DEPARTMENT_ID`) and `org-position-no-authority-escalation.test.ts` (the behavioral leg of the protocol-tier invariant — the live org-chart wire carries NO authority-bearing field on any member/department/responsibility-view object; the structural leg stays always-on in `agent-org-chart-shape.test.ts`, and the deeper RFC 0049/0051 authority-invariance legs stay reference-impl tier per the `agent-manifest-runtime` no-host-hook precedent). 2026-05-31 (RFCs 0086 + 0077 — the Active→Accepted behavioral gate) added four capability-gated behavioral scenarios so a non-steward host can be mechanically certified non-vacuously under `OPENWOP_REQUIRE_BEHAVIOR=true`: `agent-roster-attribution.test.ts` (RFC 0086 §B/§C; gated on `agents.roster.supported` — the normative `GET /v1/agents/roster` read shape + `total==roster.length`, the §C `roster.run.initiated`-before-`agent.invocation.started` ordering, the content-free payload backing `roster-attribution-no-content`, the durable work-item `triggerSubscriptionId`, and the RFC 0074 cross-tenant 404 via `OPENWOP_CROSS_TENANT_ROSTER_ID`), `agent-live-invocation-bracket.test.ts` (RFC 0077 §E; gated on `agents.liveRuntime.supported` — `agent.invocation.started`-first / `agent.invocation.completed`-last bracket, matching `invocationId`, `source`/`outcome` closed enums, content-free), `agent-live-structured-output.test.ts` (RFC 0077 §B step 6; gated on `agents.liveRuntime.structuredOutput` — a result violating `handoff.returnSchemaRef` fails the invocation `outcome:"failed"` rather than shipping as completed), and `agent-live-allowlist-enforced.test.ts` (RFC 0077 §F-1 / RFC 0002 §A14; gated on `agents.liveRuntime.supported` — a tool outside `toolAllowlist` is not callable); all four drive the documented `POST /v1/host/sample/roster/fire` + `POST /v1/host/sample/agents/live-invoke` seams plus the test event-log seam and soft-skip on 404 (these are the RFC 0086 / 0077 Active→Accepted bars). 2026-05-30 (RFC 0087 — agent org-chart, Draft -> Active) added `agent-org-chart-shape.test.ts` (always-on server-free: the `capabilities.agents.orgChart` shape + the `AgentOrgChart` round-trip + the non-`host:` member negative + the **§B structural non-authority guarantee** — the schema rejects a `scopes`/`canDispatch`/`permissions`/`authority` field on a member (`additionalProperties:false`), and a member's key set is exactly `{rosterId, departmentId, roleId, reportsTo}` — backing the protocol-tier `org-position-no-authority-escalation` invariant; no new RunEventType). 2026-05-30 (RFC 0086 — standing agent roster, Draft -> Active) added `agent-roster-shape.test.ts` (always-on server-free: the `capabilities.agents.roster` shape + the `AgentRosterEntry` round-trip + the `host:` `rosterId` + `agentRef` version-XOR-channel negatives + the content-free `roster.run.initiated` negatives backing the protocol-tier `roster-attribution-no-content` invariant + the additive `roster` inventory projection + RunEventType-enum membership). 2026-05-30 (RFC 0082 — agent deployment lifecycle, Draft -> Active) added `agent-deployment-shape.test.ts` (always-on server-free: the `capabilities.agents.deployment` shape + the `AgentDeployment` record round-trip + the `AgentRef` `channel` XOR `version` `not`-clause + the four `deployment.*` payloads + the content-free negatives backing the protocol-tier `deployment-event-no-content-leak` invariant). 2026-05-30 (RFC 0085 — `openwop-agent-platform` meta-profile, Draft -> Active) added `agent-platform-profile.test.ts` (always-on server-free derivation of the operational-annex `none`/`partial`/`full` status: all-floor ⇒ partial, missing-flag ⇒ none, the replay-OR-`nondeterminismPolicy.declared` term, floor+governance ⇒ full, missing-tenant-scope ⇒ partial-not-full per the honest-advertisement rule, eval/deploy/budget-are-advisory-not-hard-terms, + the `capabilities.nondeterminismPolicy.declared` shape). 2026-05-30 (RFC 0084 — budget, quota + cost policy, Draft -> Active) added `budget-policy-shape.test.ts` (always-on server-free: `budget-policy.schema.json` round-trip + the §A orthogonality guard — a wall-time field is rejected (it's RFC 0058's `runTimeoutMs`) — + threshold/onExhaustion negatives + the four content-free `budget.{reserved,consumed,threshold.crossed,exhausted}` payloads + the four `cap.breached{budget-*}` kinds + RunEventType-enum membership + the no-pricing-property structural check backing the protocol-tier `budget-no-pricing-leak` invariant + the `capabilities.budget`/`limits.maxBudget*` shape). 2026-05-30 (RFC 0083 — durable trigger + channel bridge, Draft -> Active) added `trigger-bridge-shape.test.ts` (always-on server-free: `trigger-subscription.schema.json` round-trip + missing-`state`/out-of-enum-`source`/unknown-property negatives + the four-state vocab + the two content-free `trigger.{subscription.state.changed,delivery.attempted}` payloads incl. closed `state`/`outcome` enums + RunEventType-enum membership + the `triggerBridge`/`webhooks.durable` capability shape + the `openwop-trigger-bridge` profile derivation incl. the no-dead-letter-sink negative). 2026-05-30 (RFC 0079 — credential provenance + egress policy, Draft -> Active) added `egress-provenance-shape.test.ts` (always-on server-free: `credential-provenance.schema.json` round-trip + `audiences:[]`/missing-`credentialId`/unknown-property negatives + the no-secret-property structural check backing the protocol-tier `egress-decision-no-secret-leak` invariant + the content-free `egress.decided` record incl. the `decision` enum + RunEventType-enum membership + the `httpClient.egressPolicy` shape; the behavioral `egress-credential-audience-bound` confused-deputy MUST is reference-impl tier, deferred to a host). 2026-05-30 (RFC 0078 — portable tool catalog, Draft -> Active) added `tool-descriptor-shape.test.ts` (always-on server-free: `tool-descriptor.schema.json` round-trip + the §C-1 `exec` ⇒ `host-extension` cross-field MUST (RFC 0069) + the `safetyTier`-required negative + `additionalProperties:false`, the `capabilities.toolCatalog` `supported`/`sources`/`sessionLifecycle` shape, and the two content-free `tool.session.{opened,closed}` payload $defs incl. the closed `outcome` enum + RunEventType-enum membership). 2026-05-30 (RFC 0080 — agent memory capability reconciliation, Draft -> Active) added `memory-capability-model-shape.test.ts` (always-on server-free: the additive `capabilities.memory.{writable,search,retention}` dimension shapes + malformed-instance negatives — `retention.ttl` non-boolean, out-of-enum `search.modes`, unknown property under `additionalProperties:false` — the `agent-inventory-response` `memoryDegraded`/`degradedMemoryDimensions` closed-enum fields, and the `openwop-memory` derivation surfacing for read/write + long-term hosts while withholding from `writable:false`). 2026-05-30 (RFC 0081 — agent evaluation, Draft -> Active) added `agent-eval-suite-shape.test.ts` (always-on server-free: the `capabilities.agents.evalSuite` shape + the `AgentEvalSuite`/`EvalSummary` schema round-trips + the three `eval.{started,scored,completed}` payloads + the content-free negatives — a task entry with a `taskOutput` body, a `safetyFinding` with an `excerpt` — backing the new `eval-summary-no-content-leak` SECURITY invariant). 2026-05-29 (RFC 0076 §B — `ctx.http.safeFetch` live-run audit) added `safefetch-live-audit.test.ts` (`behaviorGate('openwop-safefetch-live-audit', …)`, gated on `httpClient.safeFetch` + `toolHooks.prePostEvents`) — asserts the audit-when-both MUST against the **durable run event log** via the new `POST /v1/host/sample/http/safe-fetch-run` open seam + the test event-log seam, closing the seam-vs-production gap (a production `createSafeFetch()` with no audit hooks passes the inline `safefetch-behavior.test.ts` but FAILS this under `OPENWOP_REQUIRE_BEHAVIOR=true`); this is the RFC 0076 §B → Accepted bar; run seam soft-skips on 404 (host-pending). 2026-05-29 (RFC 0066 — `x-openwop-form` picker UX hints, Draft → Active) added `x-openwop-form-pack-manifest.test.ts` (always-on server-free: an annotated `configSchema` stays a valid 2020-12 schema + the advisory hints don't change what it accepts, each §A annotation matches the shape, an unknown `kind` validates for forward-compat, 3 negatives — missing/non-string `kind`, non-string `dependsOn`). 2026-05-29 (RFC 0076 §B — `ctx.http.safeFetch`) added `safefetch-behavior.test.ts` (seam-gated: SSRF block / DNS-rebinding / `Connection: upgrade` refusal / tool-hooks audit-when-both, via `POST /v1/host/sample/http/safe-fetch`; advertisement contract stays in `http-client-ssrf.test.ts`). 2026-05-29 (RFC 0076 §A — pack `runtime.requires[]` install gate) added two: `runtime-requires-shape.test.ts` (server-free closed-vocabulary validation — the 8 tokens validate, a raw builtin name is rejected, empty-array≡omission, `uniqueItems`) + `runtime-requires-install-gate.test.ts` (seam-gated install-grant / install-refuse → `pack_runtime_requirement_unmet` / non-sandbox SHOULD-projection, soft-skip on 404 via `POST /v1/host/sample/packs/install-gate`). 2026-05-29 (RFC 0047 — `host.oauth` authorization-code roundtrip) added `oauth-authorization-code-roundtrip.test.ts` — capability-gated on `capabilities.oauth.supported` + `grants` including `authorization_code`; drives the `POST /v1/host/sample/oauth/authorize-code-roundtrip` seam against the one canonical synthetic provider in `fixtures/oauth-providers/synthetic.json` (soft-skip on 404, Tier-2 host-pending), asserting a successful grant returns a credential REFERENCE (token persisted as a `host.credentials` entry) and that the authorization code / state / PKCE verifier / acquired access+refresh tokens never appear on any run-visible surface (RFC 0047 §C + §C.2 / `credential-payload-redaction`). Closes the RFC 0047 Tier-2 gap (capability-shape + redaction scenarios existed; the actual authorization-code dance was unexercised). 2026-05-26 (RFC 0070 — agent-manifest runtime) added `agent-manifest-runtime.test.ts`; 2026-05-26 (RFC 0071 — artifact-type + chat card packs) added six: `artifact-type-pack-manifest-validation.test.ts` + `artifact-schema-compile-bounded.test.ts` (server-free) + `artifact-type-pack-install.test.ts` + `artifact-type-store-without-render.test.ts` + `chat-card-pack-manifest-validation.test.ts` (server-free) + `chat-card-pack-execution.test.ts` (capability-gated, host-pending). 2026-05-26 (RFCs 0067 / 0068 / 0069 — spec-gap Draft cohort) added five scenarios: `byok-auth-modes.test.ts` (RFC 0067; always-on schema-shape of `aiProviders.authModes` + a discovery-gated §B auth-mode-contract cross-field check), `memory-consolidation-shape.test.ts` (RFC 0068; always-on shape of `agents.memoryConsolidation`/`agents.commitments` + the `agent.memory.consolidated`/`commitment.fired` payload $defs), `memory-consolidation-idempotent.test.ts` + `commitment-fired.test.ts` (RFC 0068; capability-gated behavioral, soft-skip on the documented `/v1/host/sample/memory/consolidate` + `/commitment/fire` seams), and `exec-not-protocol-tier.test.ts` (RFC 0069; always-on server-free structural assertion that the protocol corpus defines no `core.*`/`openwop.*` exec-class primitive — backs the `exec-must-not-be-protocol-tier` SECURITY invariant). 2026-05-25 (RFC 0061 — stateful agent-loop lifecycle, executionModel.version 5) added four `agent-loop-*.test.ts` scenarios: `-version5-shape` (always-on; validates `executionModel.statefulResume`/`transcriptWindow` + the 1–5 version ceiling) plus `-iteration-monotonic` (gated on `version >= 5`; `runOrchestrator.decided.iteration` increments 1,2,3… exactly once per turn), `-workspace-snapshot` (gated additionally on `host.workspace.supported`; a turn-i workspace write is invisible to turn i, visible to turn i+1), and `-stateful-resume` (gated on `statefulResume`; a mid-loop suspend resumes at the same iteration without resetting the counter) — the three behavioral scenarios drive the documented agent-loop seam (`POST /v1/host/sample/agentloop/run`) and soft-skip until a host wires it. 2026-05-25 (RFC 0059 — host.workspace M2, reference-host enforcement) added two `workspace-*.test.ts` scenarios: `-behavior` (capability-gated CRUD round-trip / `If-Match` 409 `workspace_conflict` / `workspace_too_large` / §D run-start snapshot, all via the real `/v1/host/workspace/files` §C endpoints) and `-cross-tenant-isolation` (WCT-1 — drives the documented `POST /v1/host/sample/workspace/op` seam to assert a file owned by one `{tenant, workspace}` is unreadable, on both `get` and `list`, under a different owner; backs the new `workspace-cross-tenant-isolation` SECURITY invariant). The in-memory reference host now advertises `capabilities.workspace.supported` and honors §C/§D/§E end-to-end. 2026-05-25 (RFC 0062 — memory.distillation "dreams") added five `distillation-*.test.ts` scenarios: `-shape` (always-on; validates the `capabilities.memory.distillation` block + the additive `distillation` sub-object on `memory.compacted`) plus `-token-budget` (within budget `tokensUsed ≤ tokenBudget`; an un-meetable budget → `token_budget_exceeded` with no partial archive), `-stable-archive` (same sources + budget ⇒ byte-stable archive checksum), `-index-roundtrip` (gated additionally on `indexEmitted`; the `MEMORY-INDEX.json` workspace file is retrievable + `workspace.updated` fired), and `-secret-carryforward` (SR-1: a redacted source secret never appears in the archive) — the four behavioral scenarios drive the documented memory-distillation seam (`POST /v1/host/sample/memory/distill`) and soft-skip until a host wires it. 2026-05-25 (RFC 0063 — core.subWorkflow.outputAttestation) added four `subrun-*.test.ts` scenarios: `-attestation-shape` (always-on; validates the `capabilities.agents.subRunAttestation` flag) plus `-checksum-stable` (the child output checksum is the byte-stable, key-order-invariant RFC 8785 JCS + SHA-256 digest), `-approval-gate` (`requireApproval` → `accept` merges, `reject` does not), and `-approval-fail-closed` (no `accept`/`edit-accept` → no merge; backs the deferred `subrun-merge-approval-fail-closed` invariant) — the three behavioral scenarios drive the documented sub-run attestation seam (`POST /v1/host/sample/subrun/attest`) and soft-skip until a host wires it. 2026-05-25 (RFC 0064 — host.toolHooks) added five `tool-hooks-*.test.ts` scenarios: `-shape` (always-on; validates the `capabilities.toolHooks` block + the optional content-free fields on `agentToolCalled` / `agentToolReturned`) plus `-content-free` (gated on `prePostEvents`), `-authorization-fail-closed` (gated on `perToolAuthorization`), `-rate-limit` (gated on `perToolRateLimit`), and `-secret-redaction` (gated on `prePostEvents` + the SR-1 `argsHash` redaction rule) — the four behavioral scenarios drive the documented tool-hooks invoke seam (`POST /v1/host/sample/toolhooks/invoke`) and soft-skip until a host wires it. 2026-05-25 (RFC 0060 — host.heartbeat) added four `heartbeat-*.test.ts` scenarios: `-capability-shape` (always-on; validates the `capabilities.heartbeat` block) plus `-fires-once-per-tick`, `-idempotent-no-spam`, and `-runtime-bound` (gated on `capabilities.heartbeat.supported` + the host heartbeat tick seam; soft-skip until a host wires it). 2026-05-25 (RFC 0057 — memory write-attribution) added five `memory-attribution-*.test.ts` scenarios: `-shape` (always-on advertisement check on `capabilities.memory.attribution`), plus `-no-content`, `-tenant-scoped`, `-emits-on-write`, and `-replay-stable` (gated on `capabilities.memory.attribution.emitsWriteEvents`) verifying the content-free `memory.written` RunEvent, its two SECURITY invariants (`memory-attribution-no-content` + `memory-attribution-tenant-scoped`), and the §D replay rule that a `replay`-mode fork MUST NOT regenerate `memoryId`. 2026-05-25 (RFC 0025 §C point 1 — test-catalog isolation invariant; pairs with the 25 publish-error scenarios in `pack-registry-publish.test.ts`) added `pack-registry-isolation.test.ts` — capability-gated on `capabilities.packs.testMode.{supported, isolated}: true`; PUTs a disposable pack into `/v1/packs-test/{name}` and asserts the same `(name, version)` does NOT appear via `GET /v1/packs/{name}` — anchors the test-catalog isolation MUST in RFC 0025 §C. 2026-05-25 (RFC 0028 Tier-2 post-promotion T2 — read-side sister scenario for workspace-membership enforcement) added `prompt-read-workspace-membership-enforced.test.ts` — gates on `capabilities.prompts.supported: true` (broader than `mutableLibrary` so read-only hosts that expose `?workspaceId=` are also probed); drives `GET /v1/prompts?workspaceId=<random-non-member>` and interprets the response: 4xx PASS (canonical envelope check on 403); 200 with empty `templates[]` PASS (correct null result for a nonexistent workspace); 200 with non-empty `templates[]` FAIL (cross-tenant leak); 200 without `templates[]` field SKIP (host doesn't expose workspace-scoped reads). Verifies SECURITY invariant `prompt-read-workspace-membership-enforced`. Same-day T1 strengthened `prompt-mutation-workspace-membership-enforced.test.ts` to pin `error === "workspace_membership_required"` when the host's refusal status is 403 (other refusal codes unconstrained). 2026-05-25 (RFC 0028 Tier-2 follow-up — workspace-membership enforcement on mutating prompt endpoints, filed in response to a self-disclosed adopter vulnerability) added `prompt-mutation-workspace-membership-enforced.test.ts` — capability-gated on `capabilities.prompts.mutableLibrary: true`; drives `POST /v1/prompts` with a cryptographically-random non-member `workspaceId` and asserts the host refuses (NOT a 2xx; any 4xx/5xx is acceptable — silent success is the failure mode). Verifies SECURITY invariant `prompt-mutation-workspace-membership-enforced`. 2026-05-22 (RFC 0034 §B follow-up — secret-leakage harness against the OTel + debug-bundle seams) added `secret-leakage-otel-attribute.test.ts` — gates on `capabilities.secrets.supported` + `capabilities.observability.testSeams.{otelScrape,debugBundleExport}` AND the `OPENWOP_CANARY_SECRET_VALUE` env (host operator + conformance runner agree on the canary). Drives the existing `openwop-smoke-byok-roundtrip` fixture end-to-end; scrapes both seams after run completion; hard-fails if the canary plaintext appears in any OTel span attribute or debug-bundle field. Verifies SECURITY invariants `secret-leakage-otel-attribute` + `secret-leakage-debug-bundle-otel`. 2026-05-22 (RFC 0041 Phase 4 — replay determinism under nondeterministic models) added three scenarios: `replay-divergence-at-refusal.test.ts` (advertisement-shape probe on `replayDeterminism.refusalDivergenceEmission` + 2 `it.todo` for the dual-direction refusal-divergence case), `replay-observable-sequence-determinism.test.ts` (capability-gated; behavioral assertion soft-skipped until a `conformance-phase4-nondet-tool` fixture ships), `replay-llm-cache-key-portable.test.ts` (intra-host reproducibility + non-recipe-field invariance + Phase 4 advertisement alignment — reuses the existing `POST /v1/host/sample/test/llm-cache-key` seam from the sibling `replay-llm-cache-key.test.ts`). 2026-05-20 (RFC 0027 §A templateKinds-coverage follow-up — paired with `prompt-end-to-end-events.test.ts`) added `prompt-all-four-kinds-events.test.ts` exercising all four `PromptKind` values (`system`, `user`, `schema-hint`, `few-shot`) end-to-end through the reference workflow-engine sample's `local.sample.demo.mock-ai` dispatch path; capability-gated via `behaviorGate('prompts-supported', ...)`. Closes the credibility gap where the host advertised `templateKinds: ["system", "user", "few-shot", "schema-hint"]` but only the system+user pair was actually wired into dispatch. 2026-05-20 (RFCs 0030–0033 — envelope LLM-contract-hardening track) added 15 scenarios across four `Active` RFCs: `envelope-reasoning-shape.test.ts` (RFC 0030, always-on; asserts the OPTIONAL `reasoning` property on the three universal-kind schemas + the `schema.response` deliberate omission), `envelope-reasoning-secret-redaction.test.ts` (RFC 0030, capability-gated on `capabilities.envelopes.reasoning.supported` + `secrets.supported`; 5 `it.todo()` placeholders for SECURITY invariant `envelope-reasoning-secret-redaction`), `envelope-tier-one-subset-static.test.ts` (RFC 0030, always-on for load-bearing rules — no `oneOf` / `allOf` / `not` / `prefixItems` / `propertyNames` anywhere; gated on `tierOneSubsetCompliance: "strict"` for OpenAI-strict-only constraints), `envelope-variant-discriminator-static.test.ts` (RFC 0031, always-on; asserts no `oneOf` + every `anyOf` branch declares a single-string-enum discriminator in `required` on every `schemas/envelopes/*.schema.json`), `model-capability-substituted.test.ts` (RFC 0031, advertisement-shape probe on `capabilities.modelCapabilities.advertised[]` identifier pattern + 5 `it.todo()` placeholders for SECURITY invariant `model-capability-substituted-no-credential-disclosure`), `model-capability-insufficient.test.ts` (RFC 0031, 6 `it.todo()` placeholders for refusal + no-recursive-fallback), `node-module-required-capabilities-shape.test.ts` (RFC 0031 SHOULD-tier authoring-convention; 4 `it.todo()` placeholders), and the six envelope-reliability events from RFC 0032 (`envelope-retry-attempted` carrying the shared advertisement-shape probe enforcing both MUST-tier events in `events[]` per RFC 0032 §C, plus `envelope-retry-exhausted`, `envelope-refusal-shape`, `envelope-truncated`, `envelope-nl-to-format-engaged`, `envelope-recovery-applied` — collectively 39 `it.todo()` placeholders covering retry/refusal/truncation/recovery + SECURITY invariants `envelope-refusal-no-prompt-leak` and `envelope-recovery-no-content-leak`), plus RFC 0033's two scenarios (`envelope-completion-distinguishes-truncation.test.ts` + `envelope-truncation-cap-exhaustion.test.ts` — 12 `it.todo()` placeholders covering the truncation-vs-schema-violation retry-routing distinction + the DoS-bound assertion). Reference workflow-engine sample advertises `capabilities.envelopes.reasoning: { supported: true, promptDirective: "off" }` + `tierOneSubsetCompliance: "warn"` honestly (schemas accept the field; host doesn't yet inject the directive); the other three RFCs' capability blocks defer to reference-host emission code per the staged RFC 0027 §G precedent. 2026-05-20 (RFC 0028 §B Phase B — prompt-pack boot-time install) added `prompt-pack-install.test.ts` (capability-gated on `capabilities.prompts.endpointsSupported: true`; asserts a host that ran the boot-time pack loader surfaces ≥ 1 pack-source template under `GET /v1/prompts?source=pack` carrying the canonical `meta.source: "pack"` + `meta.packName` + `meta.packVersion` stamps; positively identifies the in-tree `vendor.openwop.prompt-sample` reference pack's `writer-system` template when present). Pairs with the new `host/promptPackLoader.ts` boot-time entry on the reference workflow-engine sample, which scans `examples/packs/*` plus `OPENWOP_PROMPT_PACKS_DIR` and calls `installPackTemplates()` for each `kind: "prompt"` pack found. 2026-05-20 (RFC 0029 Phase C — prompt resolution chain wire shape) added three more scenarios: `prompt-resolution-chain-node-wins.test.ts` (capability-gated on `capabilities.prompts.supported: true`; asserts layer-1 node-config supersedes lower layers per `spec/v1/prompts.md` §"Resolution chain (normative)"), `prompt-resolution-chain-agent-intrinsic.test.ts` (additionally gated on `capabilities.prompts.agentBindings: true`; asserts agent intrinsic `systemPromptRef` wins over `promptOverrides` AND lower layers when the node has no layer-1 ref), `prompt-resolution-chain-fallback-cascade.test.ts` (asserts layer 3 workflow-defaults wins over layer 4 host-defaults; layer 4 host-defaults wins when 1-3 yield null; resolved is null when all four yield null but chain[] still lists every attempted layer). The scenarios drive the host's `POST /v1/host/sample/prompt/resolve` test seam (reference-host implementation deferred to follow-up slice per RFC 0021 staging precedent). 2026-05-20 (RFC 0027 Phase A — prompt templates wire shape) added three scenarios: `prompt-template-shape.test.ts` (always-on; Ajv compileability + positive/negative round-trip for PromptTemplate + PromptRef + PromptKind), `prompt-composed-secret-redaction.test.ts` (capability-gated on `capabilities.prompts.supported: true` + `observability: "full"`; asserts `[REDACTED:<secretId>]` markers in `prompt.composed` payloads for `source: "secret"` variable bindings per SECURITY/threat-model-secret-leakage.md §SR-1), `prompt-composed-trust-marker.test.ts` (same capability gates; asserts `<UNTRUSTED>...</UNTRUSTED>` wrapping + `contentTrust: "untrusted"` propagation per RFC 0020 §D). Paired with new `fixtures/prompt-templates/` sub-directory + per-fixture schema-validity describe block + future SECURITY invariants `prompt-composed-secret-redaction` and `prompt-composed-trust-marker` (lands alongside reference-host emission per RFC 0021 staging precedent). 2026-05-18 (RFC 0022 `Draft` — runtime variable mapping) added four `it.todo()` placeholder scenarios covering the new mapping surfaces on `core.dispatch` (§A — `dispatch-input-mapping.test.ts`, `dispatch-output-mapping.test.ts`, `dispatch-cross-worker-handoff.test.ts`) and `core.subWorkflow` (§B — `subworkflow-input-mapping.test.ts`). Gated on `capabilities.agents.dispatchMapping` (dispatch trio) and `capabilities.subWorkflow.inputMapping` (subWorkflow). Promote to live assertions when RFC 0022 reaches `Active` + a reference host advertises the matching flags. 2026-05-17 (RFC 0003 §D handoff-schema enforcement, HV-1) added `agentPackHandoffSchemaValidation.test.ts` — verifies the host validates dispatch payloads against `handoff.taskSchemaRef` AND return payloads against `handoff.returnSchemaRef` per RFC 0003 §D. Paired with the new `agent-pack-handoff-schema-enforcement` row in `SECURITY/invariants.yaml`. 2026-05-17 (AI Envelope gap-closure, DRAFT v1.x — `spec/v1/ai-envelope.md`) added 7 advertisement-shape scenarios with `it.todo()` behavioral placeholders gated on `capabilities.envelopeContracts.advertised: true`: `aiEnvelope.universalKinds.test.ts`, `aiEnvelope.schemaDrift.test.ts`, `aiEnvelope.correlationReplay.test.ts`, `aiEnvelope.contractRefusal.test.ts`, `aiEnvelope.trustBoundaryPropagation.test.ts`, `aiEnvelope.redaction.test.ts`, `aiEnvelope.capBreached.test.ts`. Paired with the new `envelope-redaction-sr-1-carry-forward` row in `SECURITY/invariants.yaml`. 2026-05-17 (post-publish hardening, deep audit of `core.openwop.agents`) added `agents-run-tool-allowlist.test.ts` — server-free scenario locking in the `core.openwop.agents@1.0.1` safety-fix that closes `OPENWOP-AUDIT-2026-003` (function-typed `tool.handler` properties rejected at `validateTools()` with `INVALID_TOOL_DECLARATION`; tool-driven runs require `ctx.agentRuntime`; tool-less safe fallback preserved). Paired with the new `agents-run-no-raw-handler` row in `SECURITY/invariants.yaml`. Same-day post-publish hardening added `idempotency-key-determinism.test.ts` — server-free scenario locking in the `core.openwop.http@1.1.2` determinism safety-fix (default `composite` mode produces deterministic keys in `(runId, nodeId, payload)`; removed `uuid` mode rejects with `CONFIG_INVALID`; cross-impl vector test lets third-party reimplementations verify wire agreement). Paired with the new `idempotency-key-deterministic` row in `SECURITY/invariants.yaml`. 2026-05-17 (Phase 3 of RFC 0013) added three server-free scenarios exercising the reference workflow-chain expansion library (`conformance/src/lib/workflow-chain-expansion.ts`): `workflow-chain-expansion.test.ts` (parameter substitution + node id collision avoidance + edge rewriting + capability propagation + runtime-invariance contract), `workflow-chain-unresolvable-typeid.test.ts` (rejection with `chain_unresolvable_typeid` when a chain references an unknown typeId), and `workflow-chain-pack-signature-verification.test.ts` (Ed25519 verification recipe reuse from `node-packs.md §Signing`). Earlier that day (Phase 1) added `workflow-chain-pack-manifest-validation.test.ts` — server-free schema-validation scenario covering the new `workflow-chain-pack-manifest.schema.json` (positive sample + two negatives: kind/contents mismatch and invalid `chainId`). Closes RFC 0013 (`Workflow-chain packs`, `Draft`) Phases 1 + 3 alongside the new `spec/v1/workflow-chain-packs.md`, the `Capabilities.workflowChainPacks` block, and the registry build-index/conformance-check `kind` routing from Phase 2. Earlier that day, the suite added 27 `it.todo()` placeholder scenarios paired with RFCs 0014-0020 (host capability surfaces — fs, kvStorage, tableStorage, queueBus, sql/vector/search, blob/cache, mcp.serverMount). These promote to live assertions when each RFC reaches `Active` + the matching capability block lands in `schemas/capabilities.schema.json` + a reference host advertises the capability. Earlier additions include 18 Multi-Agent Shift scenarios (Phases 1-5) added 2026-05-10, the `registry-public.test.ts` public-registry healthcheck added 2026-05-11 (opt-in via `OPENWOP_TEST_PUBLIC_REGISTRY=true`), the `replay-llm-cache-key.test.ts` placeholder added 2026-05-11 (three `it.todo()` cases for the cross-host LLM cache-key recipe per `replay.md` §"LLM cache-key recipe"), the two `production-*.test.ts` scenarios added 2026-05-11 for the `openwop-production` profile per RFC 0009 (`production-backpressure.test.ts`, `production-retention-expiry.test.ts`), the four `auth-*.test.ts` scenarios added 2026-05-11/12 for the production-auth profiles per RFC 0010 (`auth-api-key-rotation.test.ts`, `auth-oauth2-client-credentials.test.ts`, `auth-oidc-user-bearer.test.ts`, `auth-mtls.test.ts` (opt-in via `OPENWOP_TEST_MTLS=1`)), `replay-retention-expiry.test.ts` added 2026-05-12 (capability shape + 410/422 envelope per `replay.md` §"Retention and garbage collection"), `bulk-cancel.test.ts` added 2026-05-12 (Phase B close-out of R1 — `POST /v1/runs:bulk-cancel`), the two Phase H launch-blocker advertisement-contract scenarios added 2026-05-12 (`mcp-toolcall-redaction.test.ts` for the MCP-1 invariant per `host-capabilities.md §host.mcp` + `threat-model-prompt-injection.md §UNTRUSTED`, and `http-client-ssrf.test.ts` for the SSRF + body-size cap advertisement contract on `capabilities.httpClient`), the `wasm-pack-abi-version-rejection.test.ts` Track 7 scenario added 2026-05-12 for the ABI-mismatch positive path via the `vendor.openwop.misbehaving-abi` pack per RFC 0008 §H, the `otel-trace-propagation-subworkflow.test.ts` Track 11 close-out added 2026-05-13 (parent + child run spans share the inbound traceparent's traceId across the `core.subWorkflow` dispatch boundary), and the three RFC 0012 (Memory Compaction Profile, `Active`) scenarios added 2026-05-13/14: `memory-compaction-sr1-carry-forward.test.ts` (load-bearing SR-1 §D), `memory-compaction-event-emitted.test.ts` (canonical §B payload shape), and `memory-compaction-provenance-tag.test.ts` (soft assertion on §C `compacted-from:<id>` convention). All three gate on `capabilities.memory.compaction.supported` + the host's test seam at `/v1/test/memory/{seed,compact}` (Postgres reference host enables both via `OPENWOP_MEMORY_COMPACTION=true OPENWOP_TEST_TRIGGER_COMPACTION=true`). 2026-05-15 (gap-closure CF-3) added `interrupt-token-matrix.test.ts` (malformed / unknown / replay / cross-run-id paths on `GET|POST /v1/interrupts/{token}`). 2026-05-31 (RFC 0078 portable tool catalog + RFC 0079 credential provenance / egress policy — the Active→Accepted behavioral gate) added four: `tool-catalog-projection.test.ts` (capability-gated on `toolCatalog.supported` via `behaviorGate('openwop-tool-catalog', …)` — the NORMATIVE `GET /v1/tools` list with each `ToolDescriptor` schema-valid + `source`/`safetyTier` in the closed vocab + content-free, `GET /v1/tools/{toolId}` round-trip + unknown-id 404, 401-unauthenticated, and the §F-2 cross-principal non-disclosure; black-box, no POST seam), `tool-session-lifecycle.test.ts` (gated on `toolCatalog.sessionLifecycle` — the §D `tool.session.opened`-before / `tool.session.closed`-after bracket over the RFC 0064 call events via the `POST /v1/host/sample/tools/session-run` seam, one shared `sessionId`, content-free), `egress-audience-binding.test.ts` (KEYSTONE — gated on `httpClient.egressPolicy.supported`; the §C confused-deputy MUST via `POST /v1/host/sample/egress/decide`: an out-of-audience egress is denied/downgraded with the credential NOT attached, a provenance-unevaluable egress fails closed — the behavioral leg of `egress-credential-audience-bound`), and `egress-decision-content-free.test.ts` (the SR-1 canary — the credential value never surfaces in `egress.decided` and `reason` stays in the CLOSED vocabulary). The maintained scenario-to-spec map lives in [`coverage.md`](./coverage.md); this README keeps the operator quickstart and the historical scenario notes below.
96
96
 
97
97
  High-level coverage includes:
98
98
 
@@ -171,7 +171,7 @@ Server-required (added in 1.7.0):
171
171
  | ------------- | ----------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
172
172
  | **Redaction** | [`capabilities.md`](../spec/v1/capabilities.md) §"Secrets" + NFR-7 + §"aiProviders" | Vendor-neutral assertions that the server doesn't leak secret material. Three scenario groups: (a) discovery shape contract — `secrets` + `aiProviders` advertisements are well-formed regardless of `secrets.supported`; when `supported === true`, scopes MUST be non-empty + `resolution === 'host-managed'`; `byok ⊆ supported`. (b) bearer-token redaction — invalid Bearer canary in `Authorization` header is not echoed in the 401 response body. (c) credentialRef echo control — gated on `secrets.supported === true`; canary planted in `configurable.ai.credentialRef` MUST NOT appear in any RunEvent payload (poll-based capture; transport-agnostic). Uses runtime-built canary fixtures (`lib/canaries.ts`) that defeat static secret scanners. 6 scenarios. |
173
173
 
174
- Current source tree: 459 scenario files. Use [`coverage.md`](./coverage.md) for current grade/gap tracking.
174
+ Current source tree: 460 scenario files. Use [`coverage.md`](./coverage.md) for current grade/gap tracking.
175
175
 
176
176
  ## Remaining Gaps
177
177