@openwop/openwop-conformance 2.0.0-rc.61 → 2.0.0-rc.63

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/dist/lib/seams.js CHANGED
@@ -31,7 +31,37 @@ export function seamPath(v1Path) {
31
31
  export function isSeamPath(path) {
32
32
  return V1_SEAM_PREFIXES.some(([re]) => re.test(path)) || path.startsWith(`${SEAMS_PREFIX}/`);
33
33
  }
34
- /** Whether a (v2) discovery document advertises the seams profile. */
34
+ /**
35
+ * Whether a (v2) discovery document advertises the seams profile.
36
+ *
37
+ * **The disposition rule, and it is load-bearing (rc.62).** A scenario that
38
+ * finds this FALSE records `inapplicable`, never `blocked`. The host has not
39
+ * claimed the instrument, so the obligation is out of scope for it — the same
40
+ * sense as `softSkip('inapplicable', 'host does not advertise X')` in
41
+ * `soft-skip.ts`. `blocked` is reserved for the DIFFERENT fact one line later
42
+ * in several of these files: the profile IS advertised and the seam answers
43
+ * 404 — an obligation the host took on and the suite could not measure.
44
+ *
45
+ * Why it matters that these are not the same. `blocked` is bundle-wide fatal
46
+ * (`verifyBundleV3` `blocked-certified`, RFC 0168 §E.1). Until rc.62 fifteen
47
+ * scenarios recorded `blocked` on an ABSENT advert while the seams profile's
48
+ * predicate was empty — and an empty predicate is vacuously satisfied, so
49
+ * `claimedProfilesForV2` claimed the profile for every v2 host. Together that
50
+ * denied certification of EVERY profile to any host that had simply not
51
+ * mounted the conformance seams: 19 of MyndHyve's 45 blocked rows and 9 of
52
+ * openwop-workflow-engine's 29, on hosts that never advertised the profile
53
+ * they were being held to. Mounting test-only surface is not a precondition of
54
+ * certifying `openwop-discovery-core`, and a barrier of that shape falls
55
+ * hardest on the independent implementers the v1 end-of-support clock needs.
56
+ *
57
+ * The predicate (`spec/v2/declaration.json`) now requires `conformance` at the
58
+ * discovery root, which is NECESSARY but not sufficient; this function is the
59
+ * sufficient test, applied per scenario. A host with a `conformance` block
60
+ * naming some other profile claims seams-v2, records every floor row
61
+ * `inapplicable`, witnesses nothing, and so certifies nothing — without a
62
+ * single blocked row. Claimed-and-unwitnessed and not-claimed are both honest;
63
+ * blocked-because-unclaimed was not.
64
+ */
35
65
  export function seamsProfileAdvertised(doc) {
36
66
  const conf = doc?.['conformance'];
37
67
  return typeof conf === 'object' && conf !== null && conf['seamsProfile'] === SEAMS_PROFILE_ID;
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "package": "@openwop/spec-artifacts",
3
- "version": "2.0.0-rc.61",
4
- "stampSha256": "67b73f2a8e8399ca1b2dfe35d4f56068272b23c3f9a983149eefff0896c623b5"
3
+ "version": "2.0.0-rc.63",
4
+ "stampSha256": "fc832118a094bf1ed10fa233af7b1f2eed7dd6cc9eb3df2ef13610c0957dd9a9"
5
5
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openwop/openwop-conformance",
3
- "version": "2.0.0-rc.61",
3
+ "version": "2.0.0-rc.63",
4
4
  "description": "Production-ready black-box conformance suite for OpenWOP v1.0 compliant servers.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -56,6 +56,6 @@
56
56
  "@openwop/spec-artifacts": "file:../spec-artifacts"
57
57
  },
58
58
  "peerDependencies": {
59
- "@openwop/spec-artifacts": "2.0.0-rc.61"
59
+ "@openwop/spec-artifacts": "2.0.0-rc.63"
60
60
  }
61
61
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "_comment": "Provenance of @openwop/spec-artifacts (RFC 0168 §D.2). files: SHA-256 per file; the conformance suite compares the installed peer against dist/spec-artifacts.lock.json at start.",
3
3
  "package": "@openwop/spec-artifacts",
4
- "version": "2.0.0-rc.61",
4
+ "version": "2.0.0-rc.63",
5
5
  "corpusTag": null,
6
6
  "files": {
7
7
  "api/.redocly.lint-ignore.yaml": "bf5a8350b88a72fa43f59605ed8d903ed24b6cfccda5e45509c9f6ed9ee4e712",
@@ -9,9 +9,9 @@
9
9
  "api/grpc/openwop.proto": "c3e72bb17cba514ee98feb6434e6c9b6ea6795bfd086489ec69fd882dd1ad977",
10
10
  "api/openapi.yaml": "39081c59fb696159806b0f2f9a42e7e9ff830d622fcf2ad4159b21357580a955",
11
11
  "api/redocly.yaml": "b0604c89b2ca6d5076ec25725c539dad44a741a811fe524439ee6daef8baa09f",
12
- "api/seams-v2.yaml": "61f994f6ddec77b13abf2ed1619915722c865e4f62e8e01dab2842ecf5c527e1",
13
- "api/v2/asyncapi.yaml": "d15466109cf6ac72ecd0cac2d757809a29e2bafe194903efd52fe91c21a58c46",
14
- "api/v2/openapi.yaml": "3f40eaf3333ac91c50e5c5c232af8066b7783c36bcea2a2670bc3b36b2263136",
12
+ "api/seams-v2.yaml": "3346a3abd83920d38c37ba3a76e9853f5eecd9daac5d449c3a81ee89af291f2b",
13
+ "api/v2/asyncapi.yaml": "573603322c45df47b803e26fc6eedc12c1d4c71a69f650e64da15728c9f4865e",
14
+ "api/v2/openapi.yaml": "40a5c055d5e6f0395754c5fe550f3f1b9aa4ce0f6b272fe0cbef7da48499e93c",
15
15
  "api/v2/redocly.yaml": "1e66b60e6118ad11a823bb620678be464d99dfe50a40e3e6f93ec9429b88b34c",
16
16
  "schemas/README.md": "0c0b737ffcf8f30e7d2809cec8a498232de710f41443212922ad8337cdde0b51",
17
17
  "schemas/a2a-task-state.schema.json": "c9365918f993f943b4b619d42551eb066a1ed33a08d895d51b395432a5b1f1bc",
@@ -199,7 +199,7 @@
199
199
  "schemas/workspace-file.schema.json": "464de85c2a068243084ee9c1d969bc7cd5d8f7948574e58450d6493c38a0e1e4",
200
200
  "spec/v1/alias-detectors.json": "fee4594ef49953953ffcd0b3813300067d16b3e65ebff2aac722034ac9b3f545",
201
201
  "spec/v1/capability-declaration-classes.json": "e7729aed5c4b4e1dd02abab0530f14cc95f5d4070fe51fb139e7f5cccefa00c6",
202
- "spec/v1/core-standard-manifest.json": "d0b1aaf541284ba740b80ceb6758ec3cd1b954341d751c803d194b4840d11b32",
202
+ "spec/v1/core-standard-manifest.json": "061b0986b66396273bb08ee7177746b51a66227cc6a535e3f57fa60c932c003d",
203
203
  "spec/v1/deprecations.json": "1d5acb69a9b8ccb57275a95605f74aef1d920685f8407c9d382a46b59dc803bb",
204
204
  "spec/v1/deprecations.schema.json": "18c87e78bedc210431f795ae44c5b5d202f2f3317850d5cf86867d4f1fa1cdfb",
205
205
  "spec/v1/event-codemap.json": "3da60d884157793a360da532a9fcbbfb5285636db325a74cec94b34622186d97",
@@ -211,7 +211,7 @@
211
211
  "spec/v1/migrations.schema.json": "886779aa6c22e646db097f5df210adb018a4dd14a7b815465a18c8a7056c8f72",
212
212
  "spec/v1/operation-path-manifest.json": "5f5f4e3842669371730ebbd1aace3fb794192615f0018dc144f484ba5db82ac3",
213
213
  "spec/v1/spec-gaps.json": "6cc9962c6b969f632e07a78b52a4f61447ff579e2990cbae989866f584a86042",
214
- "spec/v2/declaration.json": "936c8f02efde6ab2e9878e38de48a762793c2229a083d435edb608fb40612518",
214
+ "spec/v2/declaration.json": "a624cfa6a46d0b10e0dac40fa49abbe05190aff87a8e852ce125d19379067b00",
215
215
  "spec/v2/declaration.schema.json": "b0881a76228dfbd1b85a2ec7b7259a60197f768344535cdb475db6ff719b0e54",
216
216
  "spec/v2/errors.json": "f179414a92f30b5dadf26e9e57699649a67324bd7186d5287647d17605d137d3",
217
217
  "spec/v2/event-codemap.json": "37869a03cdfd8758b57e6f350641a6ebbd383231cebda51f5473ad85f94ab74c",
@@ -229,9 +229,9 @@
229
229
  "spec/v2/id-field-bindings.json": "d9d1f8e266660b581f11020b9511a65c677e026b1a71ada870682ad77e18555d",
230
230
  "spec/v2/path-manifest.json": "034152e09b1458c66810d4050e20a273b2b9b8fe2d92b66e8b819477de58a1be",
231
231
  "spec/v2/peer-dependency-aliases.json": "d10299280abee08258502925bc327293ee413e0108cd6e6ec75ff6110653308d",
232
- "spec/v2/profiles.json": "bf38fc9c5ad32212385ad798c0744de33837ea80c0ef9bec86ecefb4ea914f27",
233
- "spec/v2/release.json": "27a4db67291746c0bcaa5814703a3c50b1bbe0ed22c257cad616b3ea5a1b8469",
232
+ "spec/v2/profiles.json": "0636f19fceae625390003a347e70ef4797d84766b5c24ce8a02cea52aadebca4",
233
+ "spec/v2/release.json": "efa92244efb4782514548a5c467a968454ca43aacd6339452cba1cc5bd265436",
234
234
  "spec/v2/retention-floors.json": "eaf3722d95c79947af1d4269ef85117e126518c588cfcf1a2b21b97269f51624"
235
235
  },
236
- "corpusCommit": "2b321db0d2d4520b8877ca83bd21bb6f49a46b99"
236
+ "corpusCommit": "443c27405e4bc132f8d436da5f08903291b824e0"
237
237
  }
@@ -69,7 +69,18 @@ async function http(fn: () => Promise<OpenWOPResponse>): Promise<OpenWOPResponse
69
69
  export function era2Gate(doc: Record<string, unknown> | null): Seeded | null {
70
70
  if (!doc) return { ok: false, kind: 'blocked', reason: 'discovery unreachable' };
71
71
  if (!seamsProfileAdvertised(doc)) {
72
- return { ok: false, kind: 'blocked', reason: `seams profile not advertised (conformance.seamsProfile !== openwop-conformance-seams-v2) an era-2 log can only be seeded through ${SEED_PATH}` };
72
+ // rc.63: `inapplicable`, not `blocked` — the host never claimed the
73
+ // instrument, so the obligation is out of scope for it (`lib/seams.ts`).
74
+ // rc.62 fixed the fifteen scenarios that call `seamsProfileAdvertised`
75
+ // directly and MISSED this one, which mints the same disposition one call
76
+ // deeper for six scenarios that import only `era2Gate`: era-2-append-
77
+ // vocabulary, fork-a-v1-run, pinned-run-disposition, stream-sse-projection,
78
+ // unmapped-type-refused, v1-events-translated. On MyndHyve's bundle that
79
+ // left 16 rows blocked on advert-absence after rc.62 — the same defect
80
+ // wearing a different import. `blocked` above (discovery unreachable) and
81
+ // below (the seam does not answer) is untouched: those are real failed
82
+ // measurements.
83
+ return { ok: false, kind: 'inapplicable', reason: `seams profile not advertised (conformance.seamsProfile !== openwop-conformance-seams-v2) — an era-2 log can only be seeded through ${SEED_PATH}` };
73
84
  }
74
85
  return null;
75
86
  }
package/src/lib/seams.ts CHANGED
@@ -33,7 +33,37 @@ export function isSeamPath(path: string): boolean {
33
33
  return V1_SEAM_PREFIXES.some(([re]) => re.test(path)) || path.startsWith(`${SEAMS_PREFIX}/`);
34
34
  }
35
35
 
36
- /** Whether a (v2) discovery document advertises the seams profile. */
36
+ /**
37
+ * Whether a (v2) discovery document advertises the seams profile.
38
+ *
39
+ * **The disposition rule, and it is load-bearing (rc.62).** A scenario that
40
+ * finds this FALSE records `inapplicable`, never `blocked`. The host has not
41
+ * claimed the instrument, so the obligation is out of scope for it — the same
42
+ * sense as `softSkip('inapplicable', 'host does not advertise X')` in
43
+ * `soft-skip.ts`. `blocked` is reserved for the DIFFERENT fact one line later
44
+ * in several of these files: the profile IS advertised and the seam answers
45
+ * 404 — an obligation the host took on and the suite could not measure.
46
+ *
47
+ * Why it matters that these are not the same. `blocked` is bundle-wide fatal
48
+ * (`verifyBundleV3` `blocked-certified`, RFC 0168 §E.1). Until rc.62 fifteen
49
+ * scenarios recorded `blocked` on an ABSENT advert while the seams profile's
50
+ * predicate was empty — and an empty predicate is vacuously satisfied, so
51
+ * `claimedProfilesForV2` claimed the profile for every v2 host. Together that
52
+ * denied certification of EVERY profile to any host that had simply not
53
+ * mounted the conformance seams: 19 of MyndHyve's 45 blocked rows and 9 of
54
+ * openwop-workflow-engine's 29, on hosts that never advertised the profile
55
+ * they were being held to. Mounting test-only surface is not a precondition of
56
+ * certifying `openwop-discovery-core`, and a barrier of that shape falls
57
+ * hardest on the independent implementers the v1 end-of-support clock needs.
58
+ *
59
+ * The predicate (`spec/v2/declaration.json`) now requires `conformance` at the
60
+ * discovery root, which is NECESSARY but not sufficient; this function is the
61
+ * sufficient test, applied per scenario. A host with a `conformance` block
62
+ * naming some other profile claims seams-v2, records every floor row
63
+ * `inapplicable`, witnesses nothing, and so certifies nothing — without a
64
+ * single blocked row. Claimed-and-unwitnessed and not-claimed are both honest;
65
+ * blocked-because-unclaimed was not.
66
+ */
37
67
  export function seamsProfileAdvertised(doc: Readonly<Record<string, unknown>> | null | undefined): boolean {
38
68
  const conf = doc?.['conformance'];
39
69
  return typeof conf === 'object' && conf !== null && (conf as Record<string, unknown>)['seamsProfile'] === SEAMS_PROFILE_ID;
@@ -39,7 +39,7 @@ async function http(fn: () => Promise<OpenWOPResponse>): Promise<OpenWOPResponse
39
39
  async function gate(): Promise<{ floor: string } | { kind: 'blocked' | 'inapplicable'; reason: string }> {
40
40
  const doc = await discovery();
41
41
  if (!doc) return { kind: 'blocked', reason: 'v2 discovery unreachable — /.well-known/openwop did not answer 200 with a JSON body under OpenWOP-Version: 2.0' };
42
- if (!seamsProfileAdvertised(doc)) return { kind: 'blocked', reason: 'seams profile not advertised (conformance.seamsProfile !== openwop-conformance-seams-v2) — the assurance floor is seam-gated' };
42
+ if (!seamsProfileAdvertised(doc)) return { kind: 'inapplicable', reason: 'seams profile not advertised (conformance.seamsProfile !== openwop-conformance-seams-v2) — the assurance floor is seam-gated' };
43
43
  const auth = await familyAdvertised('auth');
44
44
  const lanes = Array.isArray(auth?.['lanes']) ? (auth['lanes'] as Array<Record<string, unknown>>) : [];
45
45
  const workload = lanes.find((l) => l['lane'] === 'workload');
@@ -93,7 +93,7 @@ async function preflight(): Promise<{ kind: SoftSkipKind; reason: string } | nul
93
93
  }
94
94
  if (!doc) return { kind: 'blocked', reason: 'discovery unreachable — /.well-known/openwop (OpenWOP-Version: 2.0) did not answer 200 JSON' };
95
95
  if (!(await gateFamily('workflowChainPacks'))) return { kind: 'inapplicable', reason: 'v2 discovery does not advertise the workflowChainPacks family (RFC 0169 §A.2)' };
96
- if (!seamsProfileAdvertised(doc)) return { kind: 'blocked', reason: 'host does not advertise conformance.seamsProfile: openwop-conformance-seams-v2 — the packs-test publish seam is the only register path the suite can drive (RFC 0168 §C.1)' };
96
+ if (!seamsProfileAdvertised(doc)) return { kind: 'inapplicable', reason: 'host does not advertise conformance.seamsProfile: openwop-conformance-seams-v2 — the packs-test publish seam is the only register path the suite can drive (RFC 0168 §C.1)' };
97
97
  if (!v2Validator('workflow-chain-pack-manifest')(chainPack('core.openwop.pin-probe', 'core.ai.callPrompt@1.0.0')).ok) return { kind: 'blocked', reason: SCHEMA_GAP };
98
98
  return null;
99
99
  }
@@ -97,7 +97,7 @@ describe('RFC 0173 §B — effect-identity-business-key (gated on idempotency)',
97
97
  const doc = await discovery();
98
98
  if (!doc) return softSkip('blocked', 'discovery unreachable');
99
99
  if (!(await gateFamily('idempotency'))) return softSkip('inapplicable', 'idempotency family not advertised — no Layer-2 obligation (gate recorded under openwop.family.idempotency)');
100
- if (!seamsProfileAdvertised(doc)) return softSkip('blocked', 'the retry leg is driven through the suite fixture provider (RFC 0173 §D.2 G4) under the seams profile — seams profile not advertised');
100
+ if (!seamsProfileAdvertised(doc)) return softSkip('inapplicable', 'the retry leg is driven through the suite fixture provider (RFC 0173 §D.2 G4) under the seams profile — seams profile not advertised');
101
101
  // The seam is catalogued (api/seams-v2.yaml `forceEffectTransportRetry`). An
102
102
  // unreachable providerUrl forces the transport retry; the witness is the
103
103
  // host's own Layer-2 ledger (RFC 0173 §C.2), where every attempt of one
@@ -45,7 +45,7 @@ describe('RFC 0173 §C.2 — effect-seam-no-refire (gated on replay, seam-driven
45
45
  const replay = await gateFamily('replay');
46
46
  if (!replay) return softSkip('inapplicable', 'replay family not advertised (gate recorded under openwop.family.replay)');
47
47
  if (!seamsProfileAdvertised(doc)) {
48
- return softSkip('blocked', `the no-re-fire leg is seam-gated (RFC 0173 falsifiability §B replay row is witnessable-gated only through a seam that fires a named manifest row inside a run) — seams profile not advertised (conformance.seamsProfile)`);
48
+ return softSkip('inapplicable', `the no-re-fire leg is seam-gated (RFC 0173 falsifiability §B replay row is witnessable-gated only through a seam that fires a named manifest row inside a run) — seams profile not advertised (conformance.seamsProfile)`);
49
49
  }
50
50
  // The seam is catalogued (api/seams-v2.yaml `fireEffectSeam`). The witness is
51
51
  // the host's own Layer-2 ledger, not an externally reachable receiver: fire a
@@ -97,7 +97,7 @@ async function preflight(): Promise<{ kind: SoftSkipKind; reason: string } | nul
97
97
  }
98
98
  if (!doc) return { kind: 'blocked', reason: 'discovery unreachable — /.well-known/openwop (OpenWOP-Version: 2.0) did not answer 200 JSON' };
99
99
  if (!(await gateFamily('packs'))) return { kind: 'inapplicable', reason: 'v2 discovery does not advertise the packs family (RFC 0169 §A.2)' };
100
- if (!seamsProfileAdvertised(doc)) return { kind: 'blocked', reason: 'host does not advertise conformance.seamsProfile: openwop-conformance-seams-v2 — the packs-test publish seam is the only install path the suite can drive (RFC 0168 §C.1)' };
100
+ if (!seamsProfileAdvertised(doc)) return { kind: 'inapplicable', reason: 'host does not advertise conformance.seamsProfile: openwop-conformance-seams-v2 — the packs-test publish seam is the only install path the suite can drive (RFC 0168 §C.1)' };
101
101
  return null;
102
102
  }
103
103
 
@@ -77,7 +77,7 @@ async function preflight(): Promise<{ kind: SoftSkipKind; reason: string } | nul
77
77
  }
78
78
  if (!doc) return { kind: 'blocked', reason: 'discovery unreachable — /.well-known/openwop (OpenWOP-Version: 2.0) did not answer 200 JSON' };
79
79
  if (!(await gateFamily('packs'))) return { kind: 'inapplicable', reason: 'v2 discovery does not advertise the packs family (RFC 0169 §A.2)' };
80
- if (!seamsProfileAdvertised(doc)) return { kind: 'blocked', reason: 'host does not advertise conformance.seamsProfile: openwop-conformance-seams-v2 — the packs-test publish seam is the only install path the suite can drive (RFC 0168 §C.1)' };
80
+ if (!seamsProfileAdvertised(doc)) return { kind: 'inapplicable', reason: 'host does not advertise conformance.seamsProfile: openwop-conformance-seams-v2 — the packs-test publish seam is the only install path the suite can drive (RFC 0168 §C.1)' };
81
81
  return null;
82
82
  }
83
83
 
@@ -88,7 +88,7 @@ describe('RFC 0175 §D.2 — minimum-version-refused (gated on a2a/mcp + seams)'
88
88
  if (!doc) return softSkip('blocked', 'discovery unreachable');
89
89
  const facet = await familyAdvertised('a2a');
90
90
  if (!facet) return softSkip('inapplicable', 'a2a facet not advertised — no floor to enforce');
91
- if (!seamsProfileAdvertised(doc)) return softSkip('blocked', 'the below-floor exchange is driven through the seams profile — conformance.seamsProfile is not openwop-conformance-seams-v2');
91
+ if (!seamsProfileAdvertised(doc)) return softSkip('inapplicable', 'the below-floor exchange is driven through the seams profile — conformance.seamsProfile is not openwop-conformance-seams-v2');
92
92
  const floor = String(facet['minimumVersion']);
93
93
  if (!a2aBelow(A2A_LOWEST, floor)) {
94
94
  return softSkip('blocked', `the advertised a2a.minimumVersion (${floor}) is at or below the lowest version the suite peer can offer (${A2A_LOWEST}) — nothing below the floor can be offered; a peer speaking a lower A2A revision is needed`);
@@ -63,7 +63,7 @@ describe('RFC 0175 §E.1 — mrtr-rounds-ceiling (gated on mcp + mrtr)', () => {
63
63
  if (!facet) return softSkip('inapplicable', 'mcp facet not advertised — no MRTR ceiling');
64
64
  const maxRounds = maxRoundsOf(facet);
65
65
  if (!Number.isInteger(maxRounds)) return softSkip('inapplicable', 'mcp.mrtr.maxRounds not advertised — no ceiling to exceed');
66
- if (!seamsProfileAdvertised(doc)) return softSkip('blocked', 'the rounds are driven through the seams profile (§23 invoke seam) — conformance.seamsProfile is not openwop-conformance-seams-v2');
66
+ if (!seamsProfileAdvertised(doc)) return softSkip('inapplicable', 'the rounds are driven through the seams profile (§23 invoke seam) — conformance.seamsProfile is not openwop-conformance-seams-v2');
67
67
  const server = getMcpFakeServer();
68
68
  if (server === null) return softSkip('blocked', 'the suite MCP fake server (OPENWOP_MCP_FAKE_SERVER=true) is not started in this run');
69
69
  server.reset();
@@ -88,7 +88,7 @@ describe('RFC 0175 §D.1 — negotiation-authenticated (gated on a2a/mcp + seams
88
88
  if (!doc) return softSkip('blocked', 'discovery unreachable');
89
89
  const facet = await familyAdvertised('a2a');
90
90
  if (!facet) return softSkip('inapplicable', 'a2a facet not advertised — no negotiation to authenticate');
91
- if (!seamsProfileAdvertised(doc)) return softSkip('blocked', 'the unauthenticated exchange is driven through the seams profile — conformance.seamsProfile is not openwop-conformance-seams-v2');
91
+ if (!seamsProfileAdvertised(doc)) return softSkip('inapplicable', 'the unauthenticated exchange is driven through the seams profile — conformance.seamsProfile is not openwop-conformance-seams-v2');
92
92
  const preferred = String(facet['preferredVersion']);
93
93
  if (preferred === A2A_LOWER) return softSkip('blocked', `a2a.preferredVersion is ${preferred}, the lowest version the suite peer can offer — no lower version can be offered`);
94
94
  const peer = new A2AFakePeer({ protocolVersions: ['0.3'] });
@@ -88,7 +88,7 @@ async function leg(protocol: 'a2a' | 'mcp', id: string): Promise<void> {
88
88
  if (!doc) return softSkip('blocked', 'discovery unreachable');
89
89
  const facet = await familyAdvertised(protocol);
90
90
  if (!facet) return softSkip('inapplicable', `${protocol} facet not advertised — no negotiation to audit`);
91
- if (!seamsProfileAdvertised(doc)) return softSkip('blocked', `the exchange is driven through the seams profile (RFC 0175 §D.3) — conformance.seamsProfile is not openwop-conformance-seams-v2`);
91
+ if (!seamsProfileAdvertised(doc)) return softSkip('inapplicable', `the exchange is driven through the seams profile (RFC 0175 §D.3) — conformance.seamsProfile is not openwop-conformance-seams-v2`);
92
92
  const peer = protocol === 'a2a' ? getA2AFakePeer() : getMcpFakeServer();
93
93
  if (peer === null) return softSkip('blocked', `the suite ${protocol === 'a2a' ? 'A2A fake peer (OPENWOP_A2A_FAKE_PEER=true)' : 'MCP fake server (OPENWOP_MCP_FAKE_SERVER=true)'} is not started in this run`);
94
94
  peer.reset();
@@ -54,7 +54,7 @@ async function gated(): Promise<Record<string, unknown> | null> {
54
54
  /** Drive one misbehaving typeId through the sandbox seam; null (reason recorded) when the seam is absent. */
55
55
  async function invoke(typeId: string, extra: Record<string, unknown> = {}): Promise<InvokeResult | null> {
56
56
  const doc = await discovery();
57
- if (!doc || !seamsProfileAdvertised(doc)) { softSkip('blocked', `the ${typeId} leg is seam-driven — seams profile (conformance.seamsProfile = openwop-conformance-seams-v2) not advertised`); return null; }
57
+ if (!doc || !seamsProfileAdvertised(doc)) { softSkip('inapplicable', `the ${typeId} leg is seam-driven — seams profile (conformance.seamsProfile = openwop-conformance-seams-v2) not advertised`); return null; }
58
58
  const res = await driver.post(INVOKE, { typeId, ...extra });
59
59
  if (res.status === 404 || res.status === 403 || res.status === 405) { seamAbsent(`host advertises packs + sandbox but ${INVOKE} answered ${res.status} — the ${typeId} leg is unobservable (host-sample-test-seams.md §8)`); return null; }
60
60
  expect(res.status, req('openwop.requirement.0173.pack-isolation.seam', 'host-sample-test-seams.md §8', `${INVOKE} MUST answer 200 { result } | 200 { error } for ${typeId}`)).toBe(200);
@@ -96,7 +96,7 @@ async function preflight(): Promise<{ kind: SoftSkipKind; reason: string } | nul
96
96
  }
97
97
  if (!doc) return { kind: 'blocked', reason: 'discovery unreachable — /.well-known/openwop (OpenWOP-Version: 2.0) did not answer 200 JSON' };
98
98
  if (!(await gateFamily('packs'))) return { kind: 'inapplicable', reason: 'v2 discovery does not advertise the packs family (RFC 0169 §A.2)' };
99
- if (!seamsProfileAdvertised(doc)) return { kind: 'blocked', reason: 'host does not advertise conformance.seamsProfile: openwop-conformance-seams-v2 — the packs-test publish seam is the only install path the suite can drive (RFC 0168 §C.1)' };
99
+ if (!seamsProfileAdvertised(doc)) return { kind: 'inapplicable', reason: 'host does not advertise conformance.seamsProfile: openwop-conformance-seams-v2 — the packs-test publish seam is the only install path the suite can drive (RFC 0168 §C.1)' };
100
100
  return null;
101
101
  }
102
102
 
@@ -38,7 +38,7 @@ describe('v2 revocation-honored (RFC 0170 §B.3 — seam-gated)', () => {
38
38
  it('a revoked next-request credential is refused on the next request with credential_revoked', async () => {
39
39
  const doc = await discovery();
40
40
  if (!doc) return softSkip('blocked', 'v2 discovery unreachable — /.well-known/openwop did not answer 200 with a JSON body under OpenWOP-Version: 2.0');
41
- if (!seamsProfileAdvertised(doc)) return softSkip('blocked', 'seams profile not advertised (conformance.seamsProfile !== openwop-conformance-seams-v2) — revocation is seam-gated and cannot be observed from the canonical API');
41
+ if (!seamsProfileAdvertised(doc)) return softSkip('inapplicable', 'seams profile not advertised (conformance.seamsProfile !== openwop-conformance-seams-v2) — revocation is seam-gated and cannot be observed from the canonical API');
42
42
  const auth = await familyAdvertised('auth');
43
43
  const lanes = Array.isArray(auth?.['lanes']) ? (auth['lanes'] as Array<Record<string, unknown>>) : [];
44
44
  const nextRequest = lanes.filter((l) => l['revocation'] === 'next-request').map((l) => String(l['lane']));
@@ -56,7 +56,7 @@ async function readLink(externalId: string): Promise<Record<string, unknown> | n
56
56
  async function form(): Promise<Formed> {
57
57
  const doc = await discovery();
58
58
  if (!doc) return { kind: 'blocked', reason: 'v2 discovery unreachable — /.well-known/openwop did not answer 200 with a JSON body under OpenWOP-Version: 2.0' };
59
- if (!seamsProfileAdvertised(doc)) return { kind: 'blocked', reason: 'seams profile not advertised (conformance.seamsProfile !== openwop-conformance-seams-v2) — the link record is seam-gated' };
59
+ if (!seamsProfileAdvertised(doc)) return { kind: 'inapplicable', reason: 'seams profile not advertised (conformance.seamsProfile !== openwop-conformance-seams-v2) — the link record is seam-gated' };
60
60
  const auth = await familyAdvertised('auth');
61
61
  const lanes = new Set((Array.isArray(auth?.['lanes']) ? (auth['lanes'] as Array<Record<string, unknown>>) : []).map((l) => String(l['lane'])));
62
62
  if (!(lanes.has('saml') && lanes.has('scim'))) return { kind: 'inapplicable', reason: 'the host does not advertise both the saml and scim lanes — advertising both is what implies the linking contract (row C2.5)' };
@@ -90,7 +90,7 @@ describe('RFC 0176 §D.2 — v1-signed-webhook-accepted (gated on webhooks + sea
90
90
  const doc = await discovery();
91
91
  if (!doc) return softSkip('blocked', 'discovery unreachable');
92
92
  if (!(await gateFamily('webhooks'))) return softSkip('inapplicable', 'webhooks family not advertised (gate recorded under openwop.family.webhooks)');
93
- if (!seamsProfileAdvertised(doc)) return softSkip('blocked', `seams profile not advertised (conformance.seamsProfile !== openwop-conformance-seams-v2) — the host's inbound receiver is reachable only through ${RECEIVE}`);
93
+ if (!seamsProfileAdvertised(doc)) return softSkip('inapplicable', `seams profile not advertised (conformance.seamsProfile !== openwop-conformance-seams-v2) — the host's inbound receiver is reachable only through ${RECEIVE}`);
94
94
  const secret = `conformance-secret-${Date.now().toString(36)}`;
95
95
  const body = JSON.stringify({ runId: 'run-conformance-v1-signed', workspaceId: 'ws-conformance', event: { type: 'run.completed', sequence: 3, payload: { durationMs: 1 } } });
96
96
  const good = await deliver(secret, v1Delivery(secret, body));