@openwop/openwop-conformance 1.134.0 → 1.135.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.
Files changed (44) hide show
  1. package/README.md +2 -2
  2. package/package.json +1 -1
  3. package/schemas/CORPUS-STAMP.json +2 -2
  4. package/src/lib/discovery-capabilities.ts +21 -0
  5. package/src/lib/feedback.ts +2 -1
  6. package/src/lib/heartbeat.ts +2 -5
  7. package/src/lib/memoryAttribution.ts +2 -5
  8. package/src/lib/toolHooks.ts +2 -5
  9. package/src/scenarios/aiEnvelope.contractRefusal.test.ts +2 -1
  10. package/src/scenarios/aiEnvelope.correlationReplay.test.ts +2 -1
  11. package/src/scenarios/aiEnvelope.redaction.test.ts +2 -1
  12. package/src/scenarios/aiEnvelope.schemaDrift.test.ts +3 -3
  13. package/src/scenarios/aiEnvelope.trustBoundaryPropagation.test.ts +2 -1
  14. package/src/scenarios/aiEnvelope.universalKinds.test.ts +2 -2
  15. package/src/scenarios/blob-cross-tenant-isolation.test.ts +2 -1
  16. package/src/scenarios/blob-presign-expiry.test.ts +2 -1
  17. package/src/scenarios/blob-roundtrip.test.ts +0 -0
  18. package/src/scenarios/cache-cross-tenant-isolation.test.ts +2 -1
  19. package/src/scenarios/cache-ttl-expiry.test.ts +2 -1
  20. package/src/scenarios/discovery-families-view.test.ts +38 -0
  21. package/src/scenarios/discovery.test.ts +5 -7
  22. package/src/scenarios/kv-atomic-increment.test.ts +2 -1
  23. package/src/scenarios/kv-cas.test.ts +2 -1
  24. package/src/scenarios/kv-cross-tenant-isolation.test.ts +2 -1
  25. package/src/scenarios/kv-ttl-expiry.test.ts +2 -1
  26. package/src/scenarios/mcp-server-elicitation-bridge.test.ts +2 -1
  27. package/src/scenarios/mcp-server-prompt-roundtrip.test.ts +2 -1
  28. package/src/scenarios/mcp-server-resource-roundtrip.test.ts +2 -1
  29. package/src/scenarios/mcp-server-sampling-bridge.test.ts +2 -1
  30. package/src/scenarios/mcp-server-tool-roundtrip.test.ts +2 -1
  31. package/src/scenarios/mcp-server-untrusted-args.test.ts +2 -1
  32. package/src/scenarios/pack-registry-isolation.test.ts +2 -1
  33. package/src/scenarios/pack-registry-publish.test.ts +2 -1
  34. package/src/scenarios/queue-ack-nack-dlq.test.ts +2 -1
  35. package/src/scenarios/queue-cross-tenant-isolation.test.ts +2 -1
  36. package/src/scenarios/queue-publish-consume-roundtrip.test.ts +2 -1
  37. package/src/scenarios/search-bm25-roundtrip.test.ts +2 -1
  38. package/src/scenarios/sql-injection-rejection.test.ts +2 -1
  39. package/src/scenarios/sql-transaction-atomicity.test.ts +2 -1
  40. package/src/scenarios/stream-subscribe-from-beginning.test.ts +2 -1
  41. package/src/scenarios/table-cross-tenant-isolation.test.ts +2 -1
  42. package/src/scenarios/table-cursor-pagination.test.ts +2 -1
  43. package/src/scenarios/table-schema-enforcement.test.ts +2 -1
  44. package/src/scenarios/vector-knn-roundtrip.test.ts +2 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openwop/openwop-conformance",
3
- "version": "1.134.0",
3
+ "version": "1.135.0",
4
4
  "description": "Production-ready black-box conformance suite for OpenWOP v1.0 compliant servers.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "_comment": "Provenance of this vendored schemas/ copy. See conformance/README.md \u00a7\"Resolving the contract\". Compare against the stamp in your installed @openwop/openwop-conformance to detect a stale hand-copied contract.",
3
- "suiteVersion": "1.134.0",
4
- "corpusCommit": "fbb82fa8ea94c25358a63fda98bd49fdb528693a"
3
+ "suiteVersion": "1.135.0",
4
+ "corpusCommit": "1b8327c673b8a11c004c17b848ba0a8d2128c2b8"
5
5
  }
@@ -47,3 +47,24 @@ export async function readCapabilityFamily<T = Record<string, unknown>>(
47
47
  if (res.status !== 200) return undefined;
48
48
  return capabilityFamily<T>(res.json, name);
49
49
  }
50
+
51
+ /**
52
+ * A root-first VIEW of the discovery document's capability families for
53
+ * readers that were written against the deprecated top-level `capabilities`
54
+ * wrapper (RFC 0073: root is the MUST; the wrapper is a v1.x-tolerated
55
+ * mirror that retires at v2). Root families win; a family that exists only in
56
+ * the wrapper is still visible so a legacy host does not lose coverage. Until
57
+ * suite 1.135.0 forty-four readers consulted the wrapper ONLY, which meant a
58
+ * root-only host — the shape RFC 0073 asks for — silently lost their legs
59
+ * (S26, found by the second sibling host, which had to keep its wrapper as a
60
+ * mirror because of it).
61
+ */
62
+ export function discoveryFamilies(doc: unknown): Record<string, unknown> {
63
+ if (!doc || typeof doc !== 'object') return {};
64
+ const root = doc as Record<string, unknown>;
65
+ const wrapper = root['capabilities'];
66
+ const merged: Record<string, unknown> = {};
67
+ if (wrapper && typeof wrapper === 'object' && !Array.isArray(wrapper)) Object.assign(merged, wrapper as Record<string, unknown>);
68
+ for (const [k, v] of Object.entries(root)) if (k !== 'capabilities') merged[k] = v;
69
+ return merged;
70
+ }
@@ -4,6 +4,7 @@
4
4
  * standard `../lib/feedback.js` path.
5
5
  */
6
6
  import { driver } from './driver.js';
7
+ import { discoveryFamilies } from './discovery-capabilities.js';
7
8
  import { isFixtureAdvertised } from './fixtures.js';
8
9
 
9
10
  interface DiscoveryDoc {
@@ -14,7 +15,7 @@ interface DiscoveryDoc {
14
15
  export async function readFeedbackCap(): Promise<Record<string, unknown> | null> {
15
16
  const res = await driver.get('/.well-known/openwop');
16
17
  const body = res.json as DiscoveryDoc | undefined;
17
- const top = body?.capabilities as Record<string, unknown> | undefined;
18
+ const top = discoveryFamilies(body);
18
19
  const fb = top && typeof top === 'object' ? (top as Record<string, unknown>)['feedback'] : undefined;
19
20
  return fb && typeof fb === 'object' ? (fb as Record<string, unknown>) : null;
20
21
  }
@@ -3,15 +3,12 @@
3
3
  * Lives in lib/ (not a *.test.ts) so scenarios import it via `../lib/heartbeat.js`.
4
4
  */
5
5
  import { driver } from './driver.js';
6
-
7
- interface DiscoveryDoc {
8
- capabilities?: Record<string, unknown>;
9
- }
6
+ import { discoveryFamilies } from './discovery-capabilities.js';
10
7
 
11
8
  /** Reads `capabilities.heartbeat` from discovery; null when unadvertised. */
12
9
  export async function readHeartbeatCap(): Promise<Record<string, unknown> | null> {
13
10
  const res = await driver.get('/.well-known/openwop');
14
- const caps = (res.json as DiscoveryDoc | undefined)?.capabilities;
11
+ const caps = discoveryFamilies(res.json);
15
12
  const hb = caps && typeof caps === 'object' ? (caps as Record<string, unknown>)['heartbeat'] : undefined;
16
13
  return hb && typeof hb === 'object' ? (hb as Record<string, unknown>) : null;
17
14
  }
@@ -3,16 +3,13 @@
3
3
  * Lives in lib/ (not a *.test.ts) so scenarios import it via `../lib/memoryAttribution.js`.
4
4
  */
5
5
  import { driver } from './driver.js';
6
+ import { discoveryFamilies } from './discovery-capabilities.js';
6
7
  import { isFixtureAdvertised } from './fixtures.js';
7
8
 
8
- interface DiscoveryDoc {
9
- capabilities?: Record<string, unknown>;
10
- }
11
-
12
9
  /** Reads `capabilities.memory.attribution` from discovery; null when unadvertised. */
13
10
  export async function readMemoryAttributionCap(): Promise<Record<string, unknown> | null> {
14
11
  const res = await driver.get('/.well-known/openwop');
15
- const caps = (res.json as DiscoveryDoc | undefined)?.capabilities;
12
+ const caps = discoveryFamilies(res.json);
16
13
  const mem = caps && typeof caps === 'object' ? (caps as Record<string, unknown>)['memory'] : undefined;
17
14
  const attr = mem && typeof mem === 'object' ? (mem as Record<string, unknown>)['attribution'] : undefined;
18
15
  return attr && typeof attr === 'object' ? (attr as Record<string, unknown>) : null;
@@ -3,15 +3,12 @@
3
3
  * Lives in lib/ (not a *.test.ts) so scenarios import it via `../lib/toolHooks.js`.
4
4
  */
5
5
  import { driver } from './driver.js';
6
-
7
- interface DiscoveryDoc {
8
- capabilities?: Record<string, unknown>;
9
- }
6
+ import { discoveryFamilies } from './discovery-capabilities.js';
10
7
 
11
8
  /** Reads `capabilities.toolHooks` from discovery; null when unadvertised. */
12
9
  export async function readToolHooksCap(): Promise<Record<string, unknown> | null> {
13
10
  const res = await driver.get('/.well-known/openwop');
14
- const caps = (res.json as DiscoveryDoc | undefined)?.capabilities;
11
+ const caps = discoveryFamilies(res.json);
15
12
  const th = caps && typeof caps === 'object' ? (caps as Record<string, unknown>)['toolHooks'] : undefined;
16
13
  return th && typeof th === 'object' ? (th as Record<string, unknown>) : null;
17
14
  }
@@ -22,6 +22,7 @@
22
22
 
23
23
  import { describe, it, expect, afterEach } from 'vitest';
24
24
  import { driver } from '../lib/driver.js';
25
+ import { discoveryFamilies } from '../lib/discovery-capabilities.js';
25
26
  import { setHostCapability, resetHostCapabilities, isToggleAvailable } from '../lib/host-toggle.js';
26
27
 
27
28
  interface DiscoveryDoc {
@@ -32,7 +33,7 @@ describe('aiEnvelope.contractRefusal: advertisement shape (FINAL v1.1)', () => {
32
33
  it('opted-in hosts advertise envelopeContracts.advertised as a boolean', async () => {
33
34
  const res = await driver.get('/.well-known/openwop');
34
35
  const body = res.json as DiscoveryDoc | undefined;
35
- const top = body?.capabilities as Record<string, unknown> | undefined;
36
+ const top = discoveryFamilies(body);
36
37
  const block = top && typeof top === 'object' ? top['envelopeContracts'] : undefined;
37
38
  if (block === undefined) return; // absent — skip
38
39
  expect(
@@ -22,6 +22,7 @@
22
22
 
23
23
  import { describe, it, expect } from 'vitest';
24
24
  import { driver } from '../lib/driver.js';
25
+ import { discoveryFamilies } from '../lib/discovery-capabilities.js';
25
26
 
26
27
  interface DiscoveryDoc {
27
28
  capabilities?: Record<string, unknown>;
@@ -30,7 +31,7 @@ interface DiscoveryDoc {
30
31
  async function isEnvelopeContractsAdvertised(): Promise<boolean> {
31
32
  const res = await driver.get('/.well-known/openwop');
32
33
  const body = res.json as DiscoveryDoc | undefined;
33
- const top = body?.capabilities as Record<string, unknown> | undefined;
34
+ const top = discoveryFamilies(body);
34
35
  const block = top && typeof top === 'object' ? (top['envelopeContracts'] as Record<string, unknown> | undefined) : undefined;
35
36
  return Boolean(block && block['advertised'] === true);
36
37
  }
@@ -24,6 +24,7 @@
24
24
 
25
25
  import { describe, it, expect } from 'vitest';
26
26
  import { driver } from '../lib/driver.js';
27
+ import { discoveryFamilies } from '../lib/discovery-capabilities.js';
27
28
 
28
29
  interface DiscoveryDoc {
29
30
  capabilities?: Record<string, unknown>;
@@ -32,7 +33,7 @@ interface DiscoveryDoc {
32
33
  async function isBYOKAdvertised(): Promise<boolean> {
33
34
  const res = await driver.get('/.well-known/openwop');
34
35
  const body = res.json as DiscoveryDoc | undefined;
35
- const top = body?.capabilities as Record<string, unknown> | undefined;
36
+ const top = discoveryFamilies(body);
36
37
  const secrets = top && typeof top === 'object' ? top['secrets'] : undefined;
37
38
  return Boolean(secrets && typeof secrets === 'object');
38
39
  }
@@ -29,7 +29,7 @@ interface DiscoveryDoc {
29
29
  async function isEnvelopeContractsAdvertised(): Promise<boolean> {
30
30
  const res = await driver.get('/.well-known/openwop');
31
31
  const body = res.json as DiscoveryDoc | undefined;
32
- const top = body?.capabilities as Record<string, unknown> | undefined;
32
+ const top = discoveryFamilies(body);
33
33
  const block = top && typeof top === 'object' ? (top['envelopeContracts'] as Record<string, unknown> | undefined) : undefined;
34
34
  return Boolean(block && block['advertised'] === true);
35
35
  }
@@ -38,7 +38,7 @@ describe('aiEnvelope.schemaDrift: advertisement shape (FINAL v1.1)', () => {
38
38
  it('capabilities.envelopeStrictness is either absent (treated as "warn") or "warn" | "strict"', async () => {
39
39
  const res = await driver.get('/.well-known/openwop');
40
40
  const body = res.json as DiscoveryDoc | undefined;
41
- const top = body?.capabilities as Record<string, unknown> | undefined;
41
+ const top = discoveryFamilies(body);
42
42
  const val = top && typeof top === 'object' ? top['envelopeStrictness'] : undefined;
43
43
  if (val === undefined) return; // absent → treated as 'warn'; skip
44
44
  expect(
@@ -189,7 +189,7 @@ describe('aiEnvelope.schemaDrift: behavioral strictness gate (FINAL v1.1)', () =
189
189
  // E.2 OTel scrape seam.
190
190
  import { queryTestSpans, isOtelSeamAvailable } from '../lib/otel-scrape.js';
191
191
  import { resetTestSeam } from '../lib/event-log-query.js';
192
- import { capabilityFamily } from '../lib/discovery-capabilities.js';
192
+ import { capabilityFamily, discoveryFamilies } from '../lib/discovery-capabilities.js';
193
193
 
194
194
  describe('aiEnvelope.schemaDrift: OTel drift attribute projection (E.2)', () => {
195
195
  it('below-floor + strictness:warn → OTel span MUST carry envelope_schema_version_drift attribute', async () => {
@@ -23,6 +23,7 @@
23
23
 
24
24
  import { describe, it, expect } from 'vitest';
25
25
  import { driver } from '../lib/driver.js';
26
+ import { discoveryFamilies } from '../lib/discovery-capabilities.js';
26
27
 
27
28
  interface DiscoveryDoc {
28
29
  capabilities?: Record<string, unknown>;
@@ -31,7 +32,7 @@ interface DiscoveryDoc {
31
32
  async function readMcpTrustBoundary(): Promise<string | null> {
32
33
  const res = await driver.get('/.well-known/openwop');
33
34
  const body = res.json as DiscoveryDoc | undefined;
34
- const top = body?.capabilities as Record<string, unknown> | undefined;
35
+ const top = discoveryFamilies(body);
35
36
  const mcp = top && typeof top === 'object' ? (top['mcpClient'] as Record<string, unknown> | undefined) : undefined;
36
37
  if (!mcp || typeof mcp !== 'object') return null;
37
38
  const tb = mcp['trustBoundary'];
@@ -29,7 +29,7 @@ const UNIVERSALS = ['clarification.request', 'schema.request', 'schema.response'
29
29
  async function readEnvelopeContracts(): Promise<{ advertised: boolean } | null> {
30
30
  const res = await driver.get('/.well-known/openwop');
31
31
  const body = res.json as DiscoveryDoc | undefined;
32
- const top = body?.capabilities as Record<string, unknown> | undefined;
32
+ const top = discoveryFamilies(body);
33
33
  const block = top && typeof top === 'object' ? (top['envelopeContracts'] as Record<string, unknown> | undefined) : undefined;
34
34
  if (!block || typeof block !== 'object') return null;
35
35
  return { advertised: block['advertised'] === true };
@@ -166,7 +166,7 @@ describe('aiEnvelope.universalKinds: behavioral accept via /v1/host/sample/envel
166
166
 
167
167
  // E.1 engine-projection via the test-only event-log seam.
168
168
  import { queryTestEvents, isEventLogSeamAvailable, resetTestSeam } from '../lib/event-log-query.js';
169
- import { capabilityFamily } from '../lib/discovery-capabilities.js';
169
+ import { capabilityFamily, discoveryFamilies } from '../lib/discovery-capabilities.js';
170
170
 
171
171
  describe('aiEnvelope.universalKinds: engine projection via event-log seam', () => {
172
172
  it('clarification.request MUST be lifted to interrupt.requested { kind: "clarification" } per interrupt.md', async () => {
@@ -9,6 +9,7 @@
9
9
 
10
10
  import { describe, it, expect } from 'vitest';
11
11
  import { driver } from '../lib/driver.js';
12
+ import { discoveryFamilies } from '../lib/discovery-capabilities.js';
12
13
 
13
14
  interface DiscoveryDoc {
14
15
  capabilities?: Record<string, unknown>;
@@ -17,7 +18,7 @@ interface DiscoveryDoc {
17
18
  async function readCap(): Promise<Record<string, unknown> | null> {
18
19
  const res = await driver.get('/.well-known/openwop');
19
20
  const body = res.json as DiscoveryDoc | undefined;
20
- const top = body?.capabilities as Record<string, unknown> | undefined;
21
+ const top = discoveryFamilies(body);
21
22
  const final = (top && typeof top === 'object') ? (top as Record<string, unknown>)["blobStorage"] : undefined;
22
23
  return (final && typeof final === 'object' ? (final as Record<string, unknown>) : null);
23
24
  }
@@ -15,6 +15,7 @@
15
15
 
16
16
  import { describe, it, expect } from 'vitest';
17
17
  import { driver } from '../lib/driver.js';
18
+ import { discoveryFamilies } from '../lib/discovery-capabilities.js';
18
19
 
19
20
  interface DiscoveryDoc {
20
21
  capabilities?: Record<string, unknown>;
@@ -23,7 +24,7 @@ interface DiscoveryDoc {
23
24
  async function readCap(): Promise<Record<string, unknown> | null> {
24
25
  const res = await driver.get('/.well-known/openwop');
25
26
  const body = res.json as DiscoveryDoc | undefined;
26
- const top = body?.capabilities as Record<string, unknown> | undefined;
27
+ const top = discoveryFamilies(body);
27
28
  const final = (top && typeof top === 'object') ? (top as Record<string, unknown>)["blobStorage"] : undefined;
28
29
  return (final && typeof final === 'object' ? (final as Record<string, unknown>) : null);
29
30
  }
@@ -9,6 +9,7 @@
9
9
 
10
10
  import { describe, it, expect } from 'vitest';
11
11
  import { driver } from '../lib/driver.js';
12
+ import { discoveryFamilies } from '../lib/discovery-capabilities.js';
12
13
 
13
14
  interface DiscoveryDoc {
14
15
  capabilities?: Record<string, unknown>;
@@ -17,7 +18,7 @@ interface DiscoveryDoc {
17
18
  async function readCap(): Promise<Record<string, unknown> | null> {
18
19
  const res = await driver.get('/.well-known/openwop');
19
20
  const body = res.json as DiscoveryDoc | undefined;
20
- const top = body?.capabilities as Record<string, unknown> | undefined;
21
+ const top = discoveryFamilies(body);
21
22
  const final = (top && typeof top === 'object') ? (top as Record<string, unknown>)["cache"] : undefined;
22
23
  return (final && typeof final === 'object' ? (final as Record<string, unknown>) : null);
23
24
  }
@@ -15,6 +15,7 @@
15
15
 
16
16
  import { describe, it, expect } from 'vitest';
17
17
  import { driver } from '../lib/driver.js';
18
+ import { discoveryFamilies } from '../lib/discovery-capabilities.js';
18
19
 
19
20
  interface DiscoveryDoc {
20
21
  capabilities?: Record<string, unknown>;
@@ -23,7 +24,7 @@ interface DiscoveryDoc {
23
24
  async function readCap(): Promise<Record<string, unknown> | null> {
24
25
  const res = await driver.get('/.well-known/openwop');
25
26
  const body = res.json as DiscoveryDoc | undefined;
26
- const top = body?.capabilities as Record<string, unknown> | undefined;
27
+ const top = discoveryFamilies(body);
27
28
  const final = (top && typeof top === 'object') ? (top as Record<string, unknown>)["cache"] : undefined;
28
29
  return (final && typeof final === 'object' ? (final as Record<string, unknown>) : null);
29
30
  }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * RFC 0073 — root is the normative layout; the top-level `capabilities`
3
+ * wrapper is a v1.x-tolerated mirror. This pins `discoveryFamilies`, the view
4
+ * every reader that was written against the wrapper now goes through (S26,
5
+ * suite 1.135.0): root families win, a wrapper-only family is still visible,
6
+ * and a root-only host loses nothing.
7
+ *
8
+ * Why it exists: forty-four readers consulted the wrapper ONLY, so a host that
9
+ * did what RFC 0073 asks — root families, no wrapper — silently lost their
10
+ * legs, and the second sibling host had to keep its wrapper as a mirror
11
+ * because of it. Server-free, always-on.
12
+ */
13
+
14
+ import { describe, it, expect } from 'vitest';
15
+ import { discoveryFamilies } from '../lib/discovery-capabilities.js';
16
+
17
+ describe('RFC 0073 — discoveryFamilies is root-first with the deprecated wrapper as fallback', () => {
18
+ it('a root-only document is read as-is (the RFC 0073 shape)', () => {
19
+ expect(discoveryFamilies({ protocolVersion: '1.0', kvStorage: { supported: true } })).toEqual({ protocolVersion: '1.0', kvStorage: { supported: true } });
20
+ });
21
+
22
+ it('a wrapper-only family is still visible, and the wrapper key itself is not a family', () => {
23
+ const v = discoveryFamilies({ protocolVersion: '1.0', capabilities: { heartbeat: { supported: true } } });
24
+ expect(v['heartbeat']).toEqual({ supported: true });
25
+ expect('capabilities' in v).toBe(false);
26
+ });
27
+
28
+ it('when both carry a family, the root wins', () => {
29
+ const v = discoveryFamilies({ feedback: { supported: true, root: true }, capabilities: { feedback: { supported: false, root: false } } });
30
+ expect(v['feedback']).toEqual({ supported: true, root: true });
31
+ });
32
+
33
+ it('a non-object document reads as empty', () => {
34
+ expect(discoveryFamilies(null)).toEqual({});
35
+ expect(discoveryFamilies('nope')).toEqual({});
36
+ expect(discoveryFamilies({ capabilities: ['not', 'an', 'object'] })).toEqual({});
37
+ });
38
+ });
@@ -8,6 +8,7 @@
8
8
 
9
9
  import { describe, it, expect } from 'vitest';
10
10
  import { driver } from '../lib/driver.js';
11
+ import { discoveryFamilies } from '../lib/discovery-capabilities.js';
11
12
  import { behaviorGate } from '../lib/behavior-gate.js';
12
13
 
13
14
  describe('discovery: /.well-known/openwop', () => {
@@ -306,13 +307,10 @@ describe('discovery: auth-scoped is not an authorization oracle', () => {
306
307
  }
307
308
  expect(unauthorized.status).toBe(200);
308
309
 
309
- const primaryCaps = Object.keys(
310
- (primary.json as { capabilities?: Record<string, unknown> })?.capabilities ?? {},
311
- );
312
- const unauthorizedCaps = Object.keys(
313
- (unauthorized.json as { capabilities?: Record<string, unknown> })?.capabilities ??
314
- {},
315
- );
310
+ // Root-first (RFC 0073); the deprecated `capabilities` wrapper is folded in
311
+ // so a root-only host and a wrapper-only host are compared the same way (S26).
312
+ const primaryCaps = Object.keys(discoveryFamilies(primary.json));
313
+ const unauthorizedCaps = Object.keys(discoveryFamilies(unauthorized.json));
316
314
 
317
315
  // Spec annex line 69: "Hosts MUST NOT let scoped discovery become
318
316
  // an authorization oracle. A caller should learn only about
@@ -10,6 +10,7 @@
10
10
 
11
11
  import { describe, it, expect } from 'vitest';
12
12
  import { driver } from '../lib/driver.js';
13
+ import { discoveryFamilies } from '../lib/discovery-capabilities.js';
13
14
 
14
15
  interface DiscoveryDoc {
15
16
  capabilities?: Record<string, unknown>;
@@ -18,7 +19,7 @@ interface DiscoveryDoc {
18
19
  async function readCap(): Promise<Record<string, unknown> | null> {
19
20
  const res = await driver.get('/.well-known/openwop');
20
21
  const body = res.json as DiscoveryDoc | undefined;
21
- const top = body?.capabilities as Record<string, unknown> | undefined;
22
+ const top = discoveryFamilies(body);
22
23
  const final = (top && typeof top === 'object') ? (top as Record<string, unknown>)["kvStorage"] : undefined;
23
24
  return (final && typeof final === 'object' ? (final as Record<string, unknown>) : null);
24
25
  }
@@ -10,6 +10,7 @@
10
10
 
11
11
  import { describe, it, expect } from 'vitest';
12
12
  import { driver } from '../lib/driver.js';
13
+ import { discoveryFamilies } from '../lib/discovery-capabilities.js';
13
14
 
14
15
  interface DiscoveryDoc {
15
16
  capabilities?: Record<string, unknown>;
@@ -18,7 +19,7 @@ interface DiscoveryDoc {
18
19
  async function readCap(): Promise<Record<string, unknown> | null> {
19
20
  const res = await driver.get('/.well-known/openwop');
20
21
  const body = res.json as DiscoveryDoc | undefined;
21
- const top = body?.capabilities as Record<string, unknown> | undefined;
22
+ const top = discoveryFamilies(body);
22
23
  const final = (top && typeof top === 'object') ? (top as Record<string, unknown>)["kvStorage"] : undefined;
23
24
  return (final && typeof final === 'object' ? (final as Record<string, unknown>) : null);
24
25
  }
@@ -18,6 +18,7 @@
18
18
 
19
19
  import { describe, it, expect } from 'vitest';
20
20
  import { driver } from '../lib/driver.js';
21
+ import { discoveryFamilies } from '../lib/discovery-capabilities.js';
21
22
 
22
23
  interface DiscoveryDoc {
23
24
  capabilities?: Record<string, unknown>;
@@ -26,7 +27,7 @@ interface DiscoveryDoc {
26
27
  async function readCap(): Promise<Record<string, unknown> | null> {
27
28
  const res = await driver.get('/.well-known/openwop');
28
29
  const body = res.json as DiscoveryDoc | undefined;
29
- const top = body?.capabilities as Record<string, unknown> | undefined;
30
+ const top = discoveryFamilies(body);
30
31
  const final = (top && typeof top === 'object') ? (top as Record<string, unknown>)["kvStorage"] : undefined;
31
32
  return (final && typeof final === 'object' ? (final as Record<string, unknown>) : null);
32
33
  }
@@ -15,6 +15,7 @@
15
15
 
16
16
  import { describe, it, expect } from 'vitest';
17
17
  import { driver } from '../lib/driver.js';
18
+ import { discoveryFamilies } from '../lib/discovery-capabilities.js';
18
19
 
19
20
  interface DiscoveryDoc {
20
21
  capabilities?: Record<string, unknown>;
@@ -23,7 +24,7 @@ interface DiscoveryDoc {
23
24
  async function readCap(): Promise<Record<string, unknown> | null> {
24
25
  const res = await driver.get('/.well-known/openwop');
25
26
  const body = res.json as DiscoveryDoc | undefined;
26
- const top = body?.capabilities as Record<string, unknown> | undefined;
27
+ const top = discoveryFamilies(body);
27
28
  const final = (top && typeof top === 'object') ? (top as Record<string, unknown>)["kvStorage"] : undefined;
28
29
  return (final && typeof final === 'object' ? (final as Record<string, unknown>) : null);
29
30
  }
@@ -13,6 +13,7 @@
13
13
 
14
14
  import { describe, it, expect } from 'vitest';
15
15
  import { driver } from '../lib/driver.js';
16
+ import { discoveryFamilies } from '../lib/discovery-capabilities.js';
16
17
  import { seamAbsent } from '../lib/soft-skip.js';
17
18
  import { mcpServerMount } from '../lib/mcp-mount.js';
18
19
 
@@ -23,7 +24,7 @@ interface DiscoveryDoc {
23
24
  async function readCap(): Promise<Record<string, unknown> | null> {
24
25
  const res = await driver.get('/.well-known/openwop');
25
26
  const body = res.json as DiscoveryDoc | undefined;
26
- const top = body?.capabilities as Record<string, unknown> | undefined;
27
+ const top = discoveryFamilies(body);
27
28
  const cur = (top && typeof top === 'object') ? (top as Record<string, unknown>)["mcp"] : undefined;
28
29
  const final = (cur && typeof cur === 'object') ? (cur as Record<string, unknown>)["serverMount"] : undefined;
29
30
  return (final && typeof final === 'object' ? (final as Record<string, unknown>) : null);
@@ -8,6 +8,7 @@
8
8
 
9
9
  import { describe, it, expect } from 'vitest';
10
10
  import { driver } from '../lib/driver.js';
11
+ import { discoveryFamilies } from '../lib/discovery-capabilities.js';
11
12
  import { seamAbsent } from '../lib/soft-skip.js';
12
13
  import { mcpServerMount } from '../lib/mcp-mount.js';
13
14
 
@@ -18,7 +19,7 @@ interface DiscoveryDoc {
18
19
  async function readCap(): Promise<Record<string, unknown> | null> {
19
20
  const res = await driver.get('/.well-known/openwop');
20
21
  const body = res.json as DiscoveryDoc | undefined;
21
- const top = body?.capabilities as Record<string, unknown> | undefined;
22
+ const top = discoveryFamilies(body);
22
23
  const cur = (top && typeof top === 'object') ? (top as Record<string, unknown>)["mcp"] : undefined;
23
24
  const final = (cur && typeof cur === 'object') ? (cur as Record<string, unknown>)["serverMount"] : undefined;
24
25
  return (final && typeof final === 'object' ? (final as Record<string, unknown>) : null);
@@ -10,6 +10,7 @@
10
10
 
11
11
  import { describe, it, expect } from 'vitest';
12
12
  import { driver } from '../lib/driver.js';
13
+ import { discoveryFamilies } from '../lib/discovery-capabilities.js';
13
14
  import { seamAbsent } from '../lib/soft-skip.js';
14
15
  import { mcpServerMount } from '../lib/mcp-mount.js';
15
16
 
@@ -20,7 +21,7 @@ interface DiscoveryDoc {
20
21
  async function readCap(): Promise<Record<string, unknown> | null> {
21
22
  const res = await driver.get('/.well-known/openwop');
22
23
  const body = res.json as DiscoveryDoc | undefined;
23
- const top = body?.capabilities as Record<string, unknown> | undefined;
24
+ const top = discoveryFamilies(body);
24
25
  const cur = (top && typeof top === 'object') ? (top as Record<string, unknown>)["mcp"] : undefined;
25
26
  const final = (cur && typeof cur === 'object') ? (cur as Record<string, unknown>)["serverMount"] : undefined;
26
27
  return (final && typeof final === 'object' ? (final as Record<string, unknown>) : null);
@@ -16,6 +16,7 @@
16
16
 
17
17
  import { describe, it, expect } from 'vitest';
18
18
  import { driver } from '../lib/driver.js';
19
+ import { discoveryFamilies } from '../lib/discovery-capabilities.js';
19
20
  import { seamAbsent } from '../lib/soft-skip.js';
20
21
  import { mcpServerMount } from '../lib/mcp-mount.js';
21
22
 
@@ -26,7 +27,7 @@ interface DiscoveryDoc {
26
27
  async function readCap(): Promise<Record<string, unknown> | null> {
27
28
  const res = await driver.get('/.well-known/openwop');
28
29
  const body = res.json as DiscoveryDoc | undefined;
29
- const top = body?.capabilities as Record<string, unknown> | undefined;
30
+ const top = discoveryFamilies(body);
30
31
  const cur = (top && typeof top === 'object') ? (top as Record<string, unknown>)["mcp"] : undefined;
31
32
  const final = (cur && typeof cur === 'object') ? (cur as Record<string, unknown>)["serverMount"] : undefined;
32
33
  return (final && typeof final === 'object' ? (final as Record<string, unknown>) : null);
@@ -14,6 +14,7 @@
14
14
 
15
15
  import { describe, it, expect } from 'vitest';
16
16
  import { driver } from '../lib/driver.js';
17
+ import { discoveryFamilies } from '../lib/discovery-capabilities.js';
17
18
  import { seamAbsent } from '../lib/soft-skip.js';
18
19
  import { mcpServerMount } from '../lib/mcp-mount.js';
19
20
 
@@ -24,7 +25,7 @@ interface DiscoveryDoc {
24
25
  async function readCap(): Promise<Record<string, unknown> | null> {
25
26
  const res = await driver.get('/.well-known/openwop');
26
27
  const body = res.json as DiscoveryDoc | undefined;
27
- const top = body?.capabilities as Record<string, unknown> | undefined;
28
+ const top = discoveryFamilies(body);
28
29
  const cur = (top && typeof top === 'object') ? (top as Record<string, unknown>)["mcp"] : undefined;
29
30
  const final = (cur && typeof cur === 'object') ? (cur as Record<string, unknown>)["serverMount"] : undefined;
30
31
  return (final && typeof final === 'object' ? (final as Record<string, unknown>) : null);
@@ -12,6 +12,7 @@
12
12
 
13
13
  import { describe, it, expect } from 'vitest';
14
14
  import { driver } from '../lib/driver.js';
15
+ import { discoveryFamilies } from '../lib/discovery-capabilities.js';
15
16
  import { seamAbsent } from '../lib/soft-skip.js';
16
17
  import { mcpServerMount } from '../lib/mcp-mount.js';
17
18
 
@@ -22,7 +23,7 @@ interface DiscoveryDoc {
22
23
  async function readCap(): Promise<Record<string, unknown> | null> {
23
24
  const res = await driver.get('/.well-known/openwop');
24
25
  const body = res.json as DiscoveryDoc | undefined;
25
- const top = body?.capabilities as Record<string, unknown> | undefined;
26
+ const top = discoveryFamilies(body);
26
27
  const cur = (top && typeof top === 'object') ? (top as Record<string, unknown>)["mcp"] : undefined;
27
28
  const final = (cur && typeof cur === 'object') ? (cur as Record<string, unknown>)["serverMount"] : undefined;
28
29
  return (final && typeof final === 'object' ? (final as Record<string, unknown>) : null);
@@ -22,6 +22,7 @@
22
22
  import { describe, it, expect } from 'vitest';
23
23
  import { softSkip } from '../lib/soft-skip.js';
24
24
  import { driver } from '../lib/driver.js';
25
+ import { discoveryFamilies } from '../lib/discovery-capabilities.js';
25
26
 
26
27
  interface DiscoveryDoc {
27
28
  capabilities?: Record<string, unknown>;
@@ -35,7 +36,7 @@ interface TestModeAdvertisement {
35
36
  async function getTestModeAdvertisement(): Promise<TestModeAdvertisement | null> {
36
37
  const res = await driver.get('/.well-known/openwop');
37
38
  const body = res.json as DiscoveryDoc | undefined;
38
- const top = body?.capabilities as Record<string, unknown> | undefined;
39
+ const top = discoveryFamilies(body);
39
40
  const packs = top && typeof top === 'object' ? (top['packs'] as Record<string, unknown> | undefined) : undefined;
40
41
  const testMode = packs && typeof packs === 'object' ? (packs['testMode'] as Record<string, unknown> | undefined) : undefined;
41
42
  if (!testMode || typeof testMode !== 'object') return null;
@@ -22,6 +22,7 @@
22
22
 
23
23
  import { describe, it, expect } from 'vitest';
24
24
  import { driver } from '../lib/driver.js';
25
+ import { discoveryFamilies } from '../lib/discovery-capabilities.js';
25
26
  import { recordRequirement } from '../lib/requirement-ledger.js';
26
27
  import { requirementIdForScenario } from '../lib/requirement-registry.js';
27
28
 
@@ -50,7 +51,7 @@ async function isTestModeAdvertised(): Promise<boolean> {
50
51
  const res = await driver.get('/.well-known/openwop');
51
52
  const body = res.json as DiscoveryDoc | undefined;
52
53
  const rootPacks = body?.packs && typeof body.packs === 'object' ? body.packs : undefined;
53
- const top = body?.capabilities as Record<string, unknown> | undefined;
54
+ const top = discoveryFamilies(body);
54
55
  const wrappedPacks = top && typeof top === 'object' ? (top['packs'] as Record<string, unknown> | undefined) : undefined;
55
56
  const packs = rootPacks ?? wrappedPacks;
56
57
  const testMode = packs && typeof packs === 'object' ? (packs['testMode'] as Record<string, unknown> | undefined) : undefined;
@@ -15,6 +15,7 @@
15
15
 
16
16
  import { describe, it, expect } from 'vitest';
17
17
  import { driver } from '../lib/driver.js';
18
+ import { discoveryFamilies } from '../lib/discovery-capabilities.js';
18
19
 
19
20
  interface DiscoveryDoc {
20
21
  capabilities?: Record<string, unknown>;
@@ -23,7 +24,7 @@ interface DiscoveryDoc {
23
24
  async function readCap(): Promise<Record<string, unknown> | null> {
24
25
  const res = await driver.get('/.well-known/openwop');
25
26
  const body = res.json as DiscoveryDoc | undefined;
26
- const top = body?.capabilities as Record<string, unknown> | undefined;
27
+ const top = discoveryFamilies(body);
27
28
  const final = (top && typeof top === 'object') ? (top as Record<string, unknown>)["queueBus"] : undefined;
28
29
  return (final && typeof final === 'object' ? (final as Record<string, unknown>) : null);
29
30
  }
@@ -11,6 +11,7 @@
11
11
 
12
12
  import { describe, it, expect } from 'vitest';
13
13
  import { driver } from '../lib/driver.js';
14
+ import { discoveryFamilies } from '../lib/discovery-capabilities.js';
14
15
 
15
16
  interface DiscoveryDoc {
16
17
  capabilities?: Record<string, unknown>;
@@ -19,7 +20,7 @@ interface DiscoveryDoc {
19
20
  async function readCap(): Promise<Record<string, unknown> | null> {
20
21
  const res = await driver.get('/.well-known/openwop');
21
22
  const body = res.json as DiscoveryDoc | undefined;
22
- const top = body?.capabilities as Record<string, unknown> | undefined;
23
+ const top = discoveryFamilies(body);
23
24
  const final = (top && typeof top === 'object') ? (top as Record<string, unknown>)["queueBus"] : undefined;
24
25
  return (final && typeof final === 'object' ? (final as Record<string, unknown>) : null);
25
26
  }