@openwop/openwop-conformance 2.46.1 → 2.46.2

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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # `@openwop/openwop-conformance` Changelog
2
2
 
3
+ ## [2.46.2] — 2026-10-12 — the seams profile is derived from its advert
4
+
5
+ - **`openwop-conformance-seams-v2` derives from `conformance.seamsProfile`, not from any `conformance` block.** The predicate was the bare `conformance` metadata key, which also carries `certificationBundleUrl` and `mockAgent`. A host that published only a bundle URL claimed the profile, so its claim flapped with whether the URL was set (openwop-app, 7 cuts on 2.45.30 with no host change), and four openwop-app bundles (`openwop-workflow-engine-2.35.1`, `-2.43.0`, `-2.44.0`, `-2.45.28-4683d9f89`) certified it with no seam mounted. A predicate `metadata` entry may now name one member, `key.member` (capabilities.md §7); `v2ProfileIds` and `v2-profiles-derived-only` share one `metadataPresent`.
6
+ - **What a host's next bundle shows:** a host with a `conformance` block but no `seamsProfile` no longer lists the profile. `--verify` of the four bundles above now refuses their seams-v2 certification (`profile-not-derivable`, scoped to that profile); their other certifications stand. The v2 reference host and MyndHyve are unaffected.
7
+ - **`check-declaration` rule 13:** every predicate entry resolves to a declared family, a kept metadata key, or `key.member` naming a property of that key's generated schema.
8
+
3
9
  ## [2.46.1] — 2026-10-11 — the modal webhook receiver closes through a tunnel
4
10
 
5
11
  - **`startModalReceiver().close()` no longer hangs on a keep-alive socket.** Through a public tunnel the tunnel client holds a keep-alive connection open, and a bare `server.close()` waits for it: the v2 reference host's certified public cut on 2.46.0 recorded `v2-webhook-message-id-stable` `executed-fail` with "Hook timed out in 30000ms" in its `afterEach`, while the host's deliveries were correct (the loopback rehearsal passed the same leg). `close()` now closes idle and then all connections, the idiom `scoped-receiver.ts` already used. No assertion changes.
@@ -68,12 +68,30 @@ function readRegistry() {
68
68
  export function v2RegistryAvailable() {
69
69
  return readRegistry() !== null;
70
70
  }
71
+ /**
72
+ * Is one predicate `metadata` entry present in `doc`? An entry is a metadata
73
+ * key, or `key.member` for one member of it (capabilities.md §7).
74
+ *
75
+ * The member form exists for the seams profile. Its advert is
76
+ * `conformance.seamsProfile` (conformance.md §The seams profile), but the
77
+ * `conformance` block also carries `certificationBundleUrl` and `mockAgent`.
78
+ * Until 2.46.2 the predicate was the bare key, so a host that published only a
79
+ * bundle URL claimed the profile, and four openwop-app bundles certified it
80
+ * with no seam mounted.
81
+ */
82
+ export function metadataPresent(doc, entry) {
83
+ const dot = entry.indexOf('.');
84
+ if (dot < 0)
85
+ return doc[entry] !== undefined;
86
+ const v = doc[entry.slice(0, dot)];
87
+ return typeof v === 'object' && v !== null && !Array.isArray(v) && v[entry.slice(dot + 1)] !== undefined;
88
+ }
71
89
  /**
72
90
  * Every profile the declaration derives at major 2, or `null` when the registry
73
91
  * is unavailable (see the module docblock — `null` is not `[]`).
74
92
  *
75
93
  * The predicate is the registry's own: every listed family present as a record,
76
- * every listed metadata key present at the root. Nothing here is hand-written
94
+ * every listed metadata entry present ({@link metadataPresent}). Nothing here is hand-written
77
95
  * per profile, so adding a v2 profile is a corpus edit and not a code edit.
78
96
  */
79
97
  export function v2ProfileIds(doc) {
@@ -91,7 +109,7 @@ export function v2ProfileIds(doc) {
91
109
  continue;
92
110
  const families = Array.isArray(p.predicate?.families) ? p.predicate.families.map(String) : [];
93
111
  const metadata = Array.isArray(p.predicate?.metadata) ? p.predicate.metadata.map(String) : [];
94
- if (families.every(isRecord) && metadata.every((k) => root[k] !== undefined))
112
+ if (families.every(isRecord) && metadata.every((k) => metadataPresent(root, k)))
95
113
  out.push(p.id);
96
114
  }
97
115
  return out;
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "package": "@openwop/spec-artifacts",
3
- "version": "2.46.1",
4
- "stampSha256": "292af71458912382d78a12adc1da1d6a913346d875096727354f909a35bab2b2"
3
+ "version": "2.46.2",
4
+ "stampSha256": "073549c538635c3ba6989c6872c2c7586489e9d469315026a6d9d138e6dcfab9"
5
5
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openwop/openwop-conformance",
3
- "version": "2.46.1",
3
+ "version": "2.46.2",
4
4
  "description": "Black-box conformance suite for OpenWOP hosts (v2 current; v1 scenarios retained for the frozen v1 tree).",
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.46.1"
59
+ "@openwop/spec-artifacts": "2.46.2"
60
60
  }
61
61
  }
package/requirements.json CHANGED
@@ -34711,7 +34711,7 @@
34711
34711
  {
34712
34712
  "id": "openwop.it.v2-profiles-derived-only.the-v2-document-carries-no-root-profiles",
34713
34713
  "file": "v2-profiles-derived-only.test.ts",
34714
- "line": 48,
34714
+ "line": 50,
34715
34715
  "title": "the v2 document carries no root `profiles[]`",
34716
34716
  "explicitId": "openwop.requirement.0169.profiles-derived-only.no-root-profiles",
34717
34717
  "citations": [
@@ -34724,7 +34724,7 @@
34724
34724
  {
34725
34725
  "id": "openwop.it.v2-profiles-derived-only.every-registry-profile-is-derivable-from-the-document-the-discovery-core-predica",
34726
34726
  "file": "v2-profiles-derived-only.test.ts",
34727
- "line": 54,
34727
+ "line": 56,
34728
34728
  "title": "every registry profile is derivable from the document; the discovery-core predicate holds on a valid document",
34729
34729
  "explicitId": "openwop.requirement.0169.profiles-derived-only.derivable",
34730
34730
  "citations": [
@@ -44764,7 +44764,7 @@
44764
44764
  {
44765
44765
  "id": "openwop.it.seams-floor-legs-gated.every-leg-of-a-seams-profile-floor-file-reaches-a-seams-gate-before-its-first-as",
44766
44766
  "file": "seams-floor-legs-gated.test.ts",
44767
- "line": 84,
44767
+ "line": 82,
44768
44768
  "title": "every leg of a seams-profile floor file reaches a seams gate before its first assertion",
44769
44769
  "explicitId": "openwop.it.seams-floor-legs-gated.every-leg-of-a-seams-profile-floor-file-reaches-a-seams-gate-before-its-first-a",
44770
44770
  "citations": [
@@ -1,17 +1,17 @@
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.46.1",
5
- "corpusTag": "v2.46.1",
4
+ "version": "2.46.2",
5
+ "corpusTag": "v2.46.2",
6
6
  "files": {
7
7
  "api/.redocly.lint-ignore.yaml": "bf5a8350b88a72fa43f59605ed8d903ed24b6cfccda5e45509c9f6ed9ee4e712",
8
8
  "api/asyncapi.yaml": "d5ecb9ee6114582be3b1f662c84bfac9ae96dae7bacb853e461168f70a8e1c7d",
9
9
  "api/grpc/openwop.proto": "c3e72bb17cba514ee98feb6434e6c9b6ea6795bfd086489ec69fd882dd1ad977",
10
10
  "api/openapi.yaml": "ac6de5303872664b78ff419c035915593e01599e02835e777a0123de1baeb398",
11
11
  "api/redocly.yaml": "b0604c89b2ca6d5076ec25725c539dad44a741a811fe524439ee6daef8baa09f",
12
- "api/seams-v2.yaml": "698ff413d4ab103656f15f784ecde2b72191dd9c48d47a459c3fed9c6ac5d65a",
13
- "api/v2/asyncapi.yaml": "31709ec59884ad87f2193ad5a855390ce05647a1ca507ab1aa31dd7b615e614a",
14
- "api/v2/openapi.yaml": "f00d724b067ccbad46d7d9d103efc641ced8118533af2346465559b286f04f86",
12
+ "api/seams-v2.yaml": "26eaead22194d03d4d8027eb6b9450ab66c8c15eb1bc77adba2118aa3384d32f",
13
+ "api/v2/asyncapi.yaml": "e8e435d575d9ea7312d3dc5e0191f0a9e389e2edc3775975df67b455ff293c4a",
14
+ "api/v2/openapi.yaml": "f77e9a4a0f61391341efbc426fa4b4eba215f731cbab0ddde7a229b640d4e6fc",
15
15
  "api/v2/redocly.yaml": "1e66b60e6118ad11a823bb620678be464d99dfe50a40e3e6f93ec9429b88b34c",
16
16
  "schemas/README.md": "276fc1d51eb08e14e9127b9fd27761d7046ee33c12000f3a64a801322db8bf58",
17
17
  "schemas/a2a-task-state.schema.json": "75d5049dea8bd873ff0e7546f1c60c8d36c219bec7084264360be54a8be30ae1",
@@ -208,14 +208,14 @@
208
208
  "schemas/workspace-file.schema.json": "464de85c2a068243084ee9c1d969bc7cd5d8f7948574e58450d6493c38a0e1e4",
209
209
  "spec/v1/alias-detectors.json": "22444c22bb88c568339ef512553f9fc38146e22b566d11ab8608f655d688d19c",
210
210
  "spec/v1/capability-declaration-classes.json": "e7729aed5c4b4e1dd02abab0530f14cc95f5d4070fe51fb139e7f5cccefa00c6",
211
- "spec/v1/core-standard-manifest.json": "cab62b59436a7b57339098abd99d90217b1ca310451dff63837ff27ab90e3a04",
211
+ "spec/v1/core-standard-manifest.json": "ca8ad2e3392b1cc1c1cd6ce6072f8a000c1a8a68ced7c319944297d90f114f87",
212
212
  "spec/v1/deprecations.json": "e723bc11d7272c71789ad1303bb7f21809a8a024abf57594f9d5c35dc199ece9",
213
213
  "spec/v1/deprecations.schema.json": "3e393c405d2a41b467d8c5e3c468549078df1ce6a6d2588fc488097b95d9b55b",
214
214
  "spec/v1/end-of-support.json": "35f0bf3b70fe78b16e2a2fd81a153fc27e703f6c16376c6fe7cdf1f4f2c4e6d4",
215
215
  "spec/v1/event-codemap.json": "3da60d884157793a360da532a9fcbbfb5285636db325a74cec94b34622186d97",
216
216
  "spec/v1/event-codemap.schema.json": "d05933b2e88103aff51a2f774df97b9bda065e0fc88dbd9b114cc47a32189174",
217
217
  "spec/v1/extensions.json": "79a60754aa16cbdbdb604f8e5c00038af535a1690a4d07bd5ff7c38f0256a7bc",
218
- "spec/v1/gaps.json": "132a59a97d6a9d1f5a5247062bdf69327256f7a3022b9590fd9481200001ab21",
218
+ "spec/v1/gaps.json": "2415b9a2152cb526fa7296b82a433d53ce19194a52389d44f43a81539ac26a1c",
219
219
  "spec/v1/gaps.schema.json": "8fd83259f556553c9df0f53e7a82ca8c2a4771d471197f69b4e2ae0ceeacfd66",
220
220
  "spec/v1/migrations.json": "4c50760be70cb644d02427bcaf5749606700edf4513f423903cf3b1d12f5c300",
221
221
  "spec/v1/migrations.schema.json": "886779aa6c22e646db097f5df210adb018a4dd14a7b815465a18c8a7056c8f72",
@@ -223,7 +223,7 @@
223
223
  "spec/v1/spec-gaps.json": "ea9612af55bea9dae3e82223d4f714243f8f590b0193f1188257b13491a38afc",
224
224
  "spec/v2/README.md": "c58acd84bb67c69043d9f777cbaa16d03e4f0f0a8158d2984526b69981067a14",
225
225
  "spec/v2/core/artifact-type-packs.md": "f734740cc3963f86c9f273a7dace26291bba2855161ddd3540618131a2c8d13e",
226
- "spec/v2/core/capabilities.md": "8218c44f90782df9630dd276e004def162dad989464cba85e7fc42d987bb61f8",
226
+ "spec/v2/core/capabilities.md": "6b766bcc1ec8c8dd8054defd8a93d8f5ceb046f16d256aef24d1a98bd89a1f73",
227
227
  "spec/v2/core/conformance.md": "3ca291e63bc70a6ef829ae8759ad0ded3741ea7aa507bbbdffc57de443ab2ae2",
228
228
  "spec/v2/core/connection-packs.md": "c80f95bd6a03698f35c72cdb2b46bd973f49203bbd786c26760e35fa86e6f23d",
229
229
  "spec/v2/core/conversation.md": "8d6abedf6af408a74577753bfca24719d318e2632e10b45ff5d63bdcf31a8aaa",
@@ -254,7 +254,7 @@
254
254
  "spec/v2/core/workflow-chain-packs.md": "fdce7a8477e269950a2bac05ee6eddbd66eb0b670b464d00054f7196ec05d29c",
255
255
  "spec/v2/corrections.json": "3a8d93e33865b692d26a3b6bfd3819766e206b2e0c2a69669baa4bf833d05a49",
256
256
  "spec/v2/corrections.schema.json": "46bbffb954d13bd9995aebc912ceeb2544f7064331abf25fd6ab85c81a5cec94",
257
- "spec/v2/declaration.json": "22530d99c92b9e0d3ae0dce25507f4cc6350486d560ad8cc01acda054e9face3",
257
+ "spec/v2/declaration.json": "6fa19c3a68df5a951f9dabea13afbd4ee3b288a110002461f373b191b3eca99b",
258
258
  "spec/v2/declaration.schema.json": "ef951633e4070899f64828f5cf1b5f4870270a0360f81dbb49b5b4d6cd407550",
259
259
  "spec/v2/eos-override.json": "4c72d2f6a658943b01c1de1643cf294642091933af7832f38ee5495df684cb2d",
260
260
  "spec/v2/errors.json": "1f0e29455edbd22e28f67f221766209c3c55ac4987beb77993b5702dd7cae131",
@@ -312,10 +312,10 @@
312
312
  "spec/v2/migrations.schema.json": "b91ade6320ad1b1185c9495b9424f3aa63438ed8e412c45171c227d82c0afd86",
313
313
  "spec/v2/path-manifest.json": "7b5679a4dad98c80d855361d88a98c8a4e045af15e310862a05b285b815dc9fc",
314
314
  "spec/v2/peer-dependency-aliases.json": "d10299280abee08258502925bc327293ee413e0108cd6e6ec75ff6110653308d",
315
- "spec/v2/profiles.json": "3d84d7712e93d1e823e362615d5f4aaba0789ea4e044b3774965876fbb8829a7",
316
- "spec/v2/release.json": "4facb248b7147ef0568bf434973a8a116d8f39f293e5c23665257f94c97cb3fe",
315
+ "spec/v2/profiles.json": "b382b261c7844798575f7c1b37c934f0da19846016a2337d883d4f5ef6e05479",
316
+ "spec/v2/release.json": "20e2ffa6bf1e1b10a4e0404a1f27fabdf9bc502ea705118b2ae0a9a0aaa60f40",
317
317
  "spec/v2/retention-floors.json": "eaf3722d95c79947af1d4269ef85117e126518c588cfcf1a2b21b97269f51624",
318
- "spec/v2/surface-baseline.json": "01a3e01c87e2b5fdbf4c6290e5730726acc195801c97b1f23c4297897b6d3979"
318
+ "spec/v2/surface-baseline.json": "473b133e092e3107893e23f5d7e8d42d117ad894e4d3db5042a780431302ee84"
319
319
  },
320
- "corpusCommit": "010da68bf57d317c7faeeda29f26bedfb3406a49"
320
+ "corpusCommit": "24368a14552d28c785adeea7b72647e8f6ae664e"
321
321
  }
@@ -76,12 +76,30 @@ export function v2RegistryAvailable(): boolean {
76
76
  return readRegistry() !== null;
77
77
  }
78
78
 
79
+ /**
80
+ * Is one predicate `metadata` entry present in `doc`? An entry is a metadata
81
+ * key, or `key.member` for one member of it (capabilities.md §7).
82
+ *
83
+ * The member form exists for the seams profile. Its advert is
84
+ * `conformance.seamsProfile` (conformance.md §The seams profile), but the
85
+ * `conformance` block also carries `certificationBundleUrl` and `mockAgent`.
86
+ * Until 2.46.2 the predicate was the bare key, so a host that published only a
87
+ * bundle URL claimed the profile, and four openwop-app bundles certified it
88
+ * with no seam mounted.
89
+ */
90
+ export function metadataPresent(doc: Record<string, unknown>, entry: string): boolean {
91
+ const dot = entry.indexOf('.');
92
+ if (dot < 0) return doc[entry] !== undefined;
93
+ const v = doc[entry.slice(0, dot)];
94
+ return typeof v === 'object' && v !== null && !Array.isArray(v) && (v as Record<string, unknown>)[entry.slice(dot + 1)] !== undefined;
95
+ }
96
+
79
97
  /**
80
98
  * Every profile the declaration derives at major 2, or `null` when the registry
81
99
  * is unavailable (see the module docblock — `null` is not `[]`).
82
100
  *
83
101
  * The predicate is the registry's own: every listed family present as a record,
84
- * every listed metadata key present at the root. Nothing here is hand-written
102
+ * every listed metadata entry present ({@link metadataPresent}). Nothing here is hand-written
85
103
  * per profile, so adding a v2 profile is a corpus edit and not a code edit.
86
104
  */
87
105
  export function v2ProfileIds(doc: DiscoveryPayload): readonly string[] | null {
@@ -97,7 +115,7 @@ export function v2ProfileIds(doc: DiscoveryPayload): readonly string[] | null {
97
115
  if (typeof p.id !== 'string') continue;
98
116
  const families = Array.isArray(p.predicate?.families) ? (p.predicate.families as unknown[]).map(String) : [];
99
117
  const metadata = Array.isArray(p.predicate?.metadata) ? (p.predicate.metadata as unknown[]).map(String) : [];
100
- if (families.every(isRecord) && metadata.every((k) => root[k] !== undefined)) out.push(p.id);
118
+ if (families.every(isRecord) && metadata.every((k) => metadataPresent(root, k))) out.push(p.id);
101
119
  }
102
120
  return out;
103
121
  }
@@ -6,7 +6,8 @@
6
6
  * declaration file, published in `spec/v2/profiles.json`; it is never a wire
7
7
  * field. The host's v2 document MUST NOT carry a root `profiles[]`, and every
8
8
  * profile in the registry MUST be derivable from the document alone: every
9
- * listed family present as a record and every listed metadata key present.
9
+ * listed family present as a record and every listed metadata entry present
10
+ * (a key, or `key.member`).
10
11
  * `profiles.json` is read from the spec tree beside `SCHEMAS_DIR`; under a
11
12
  * layout that does not ship it the derivation leg records `blocked`.
12
13
  */
@@ -17,6 +18,7 @@ import { join } from 'node:path';
17
18
  import { v2Discovery } from '../lib/v2.js';
18
19
  import { SCHEMAS_DIR } from '../lib/paths.js';
19
20
  import { softSkip } from '../lib/soft-skip.js';
21
+ import { metadataPresent } from '../lib/v2-profiles.js';
20
22
  import { req } from '../lib/requirement-ids.js';
21
23
 
22
24
  const DOC = 'spec/v2/core/capabilities.md §7';
@@ -41,7 +43,7 @@ function isRecord(v: unknown): v is Record<string, unknown> {
41
43
  function derive(doc: Record<string, unknown>, p: ProfileRow): boolean {
42
44
  const families = p.predicate.families ?? [];
43
45
  const metadata = p.predicate.metadata ?? [];
44
- return families.every((f) => isRecord(doc[f])) && metadata.every((m) => doc[m] !== undefined);
46
+ return families.every((f) => isRecord(doc[f])) && metadata.every((m) => metadataPresent(doc, m));
45
47
  }
46
48
 
47
49
  describe('v2 profiles-derived-only (RFC 0169 §C.1, §C.3)', () => {