@openwop/openwop-conformance 2.46.35 → 2.46.37

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 (33) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +3 -3
  3. package/coverage.md +5 -6
  4. package/dist/spec-artifacts.lock.json +2 -2
  5. package/fixtures/conformance-clarification.json +1 -1
  6. package/fixtures/conformance-interrupt-form-refused.json +108 -0
  7. package/fixtures/conformance-interrupt-form-unbound.json +108 -0
  8. package/fixtures/conformance-interrupt-form.json +107 -0
  9. package/fixtures/conformance-stream-text.json +1 -2
  10. package/fixtures.md +20 -5
  11. package/package.json +2 -2
  12. package/requirement-aliases.json +98 -1
  13. package/requirements.json +596 -804
  14. package/scenario-majors.json +16 -19
  15. package/schemas/CORPUS-STAMP.json +56 -69
  16. package/src/lib/callai-attempts-witness.ts +13 -1
  17. package/src/lib/family-advert-witness.ts +37 -50
  18. package/src/scenarios/stream-text-fixture.test.ts +13 -5
  19. package/src/scenarios/v2-clarification-resume-answers.test.ts +66 -0
  20. package/src/scenarios/v2-envelope-surfaces-absent.test.ts +55 -0
  21. package/src/scenarios/v2-interrupt-form-rules.test.ts +143 -0
  22. package/src/scenarios/v2-limits-clarification-rounds-advertisement.test.ts +42 -0
  23. package/src/scenarios/v2-peer-dependency-declared.test.ts +1 -1
  24. package/src/scenarios/v2-provider-output-reliability.test.ts +94 -0
  25. package/src/scenarios/v2-structured-output-advertisement.test.ts +82 -0
  26. package/src/lib/envelope-schema-static.ts +0 -167
  27. package/src/scenarios/v2-a2ui-v09-surface.test.ts +0 -323
  28. package/src/scenarios/v2-ai-envelope-advertisement.test.ts +0 -43
  29. package/src/scenarios/v2-envelope-contracts-advertisement.test.ts +0 -48
  30. package/src/scenarios/v2-envelope-reasoning-shape.test.ts +0 -81
  31. package/src/scenarios/v2-envelope-tier-one-subset-static.test.ts +0 -64
  32. package/src/scenarios/v2-envelopes-advertisement.test.ts +0 -85
  33. package/src/scenarios/v2-limits-envelope-caps-advertisement.test.ts +0 -61
@@ -1,81 +0,0 @@
1
- /**
2
- * v2 — the optional `reasoning` payload field (`spec/v2/core/events.md`
3
- * §`envelopes`; RFC 0030 §A). Static: reads `schemas/v2/envelopes/` only. The
4
- * v1 twin is `envelope-reasoning-shape`; its two advertisement legs
5
- * (`envelopes.reasoning`, `envelopes.tierOneSubsetCompliance`) are ported to
6
- * `v2-envelopes-advertisement`, not repeated here.
7
- *
8
- * declared `clarification.request`, `schema.request` and `error` declare an
9
- * OPTIONAL `reasoning: string` ("A vendor kind whose payload needs
10
- * multi-step reasoning SHOULD declare it as optional");
11
- * omitted `schema.response` (a side-channel ack) does not declare it;
12
- * absent ok each of the three validates WITHOUT `reasoning` ("A host MUST NOT
13
- * reject an envelope without it, whatever `promptDirective` says");
14
- * present ok each validates WITH a string `reasoning`;
15
- * typed a non-string `reasoning` is rejected.
16
- *
17
- * Host-free: every leg runs with no OPENWOP_BASE_URL.
18
- *
19
- * @see spec/v2/core/events.md §envelopes
20
- * @see schemas/v2/envelopes/
21
- */
22
-
23
- import { describe, it, expect } from 'vitest';
24
- import { v2Validator } from '../lib/v2.js';
25
- import { req } from '../lib/requirement-ids.js';
26
- import { loadV2EnvelopeSchema } from '../lib/envelope-schema-static.js';
27
-
28
- const DOC = 'events.md §envelopes';
29
- const ID_DECLARED = 'openwop.requirement.envelopes.reasoning-declared-optional-string';
30
- const ID_OMITTED = 'openwop.requirement.envelopes.reasoning-omitted-from-schema-response';
31
- const ID_ABSENT_OK = 'openwop.requirement.envelopes.reasoning-absent-accepted';
32
- const ID_PRESENT_OK = 'openwop.requirement.envelopes.reasoning-present-accepted';
33
- const ID_TYPED = 'openwop.requirement.envelopes.reasoning-non-string-rejected';
34
-
35
- /** A valid payload per kind, without `reasoning`. */
36
- const BASE: Readonly<Record<string, Record<string, unknown>>> = {
37
- 'clarification.request': { questions: [{ id: 'q1', question: 'Which provider?' }] },
38
- 'schema.request': { envelopeType: 'acme.prd.create' },
39
- error: { code: 'validation_failed', message: 'Could not match the schema.' },
40
- };
41
- const KINDS = Object.keys(BASE);
42
-
43
- describe('v2 envelope reasoning: payload schemas (events.md §envelopes)', () => {
44
- for (const kind of KINDS) {
45
- it(`${kind} declares an optional reasoning of type string`, () => {
46
- const schema = loadV2EnvelopeSchema(kind);
47
- const props = (schema?.['properties'] ?? {}) as Record<string, Record<string, unknown>>;
48
- const required = (schema?.['required'] ?? []) as unknown[];
49
- expect(schema !== null, req(ID_DECLARED, DOC, `schemas/v2/envelopes/${kind}.schema.json MUST exist`)).toBe(true);
50
- expect(props['reasoning']?.['type'], req(ID_DECLARED, DOC, `${kind} MUST declare reasoning as type string`)).toBe('string');
51
- expect(required.includes('reasoning'), req(ID_DECLARED, DOC, `${kind} MUST NOT require reasoning — it is optional`)).toBe(false);
52
- });
53
- }
54
-
55
- it('schema.response does not declare reasoning (a side-channel ack)', () => {
56
- const schema = loadV2EnvelopeSchema('schema.response');
57
- const props = (schema?.['properties'] ?? {}) as Record<string, unknown>;
58
- expect(schema !== null, req(ID_OMITTED, 'RFC 0030 §A', 'schemas/v2/envelopes/schema.response.schema.json MUST exist')).toBe(true);
59
- expect('reasoning' in props, req(ID_OMITTED, 'RFC 0030 §A', 'schema.response MUST NOT declare reasoning')).toBe(false);
60
- });
61
- });
62
-
63
- describe('v2 envelope reasoning: round-trip (events.md §envelopes)', () => {
64
- for (const kind of KINDS) {
65
- const validate = v2Validator(`envelopes/${kind}`);
66
-
67
- it(`${kind} validates without reasoning`, () => {
68
- const r = validate(BASE[kind]);
69
- expect(r.ok, req(ID_ABSENT_OK, DOC, `a ${kind} payload without reasoning MUST validate — a host MUST NOT reject it (${r.errors})`)).toBe(true);
70
- });
71
-
72
- it(`${kind} validates with a string reasoning`, () => {
73
- const r = validate({ reasoning: 'The input named X twice; I asked which one.', ...BASE[kind] });
74
- expect(r.ok, req(ID_PRESENT_OK, DOC, `a ${kind} payload with a string reasoning MUST validate (${r.errors})`)).toBe(true);
75
- });
76
-
77
- it(`${kind} rejects a non-string reasoning`, () => {
78
- expect(validate({ reasoning: 42, ...BASE[kind] }).ok, req(ID_TYPED, DOC, `${kind}: a numeric reasoning MUST be rejected — reasoning is a plain string`)).toBe(false);
79
- });
80
- }
81
- });
@@ -1,64 +0,0 @@
1
- /**
2
- * v2 — the Tier-1 structured-output subset, statically (RFC 0030 §B;
3
- * `envelopes.tierOneSubsetCompliance` in `schemas/v2/capabilities.schema.json`).
4
- * The v1 twin is `envelope-tier-one-subset-static`; the walker lives in
5
- * `lib/envelope-schema-static.ts`.
6
- *
7
- * The always-on load-bearing walk over the universal kinds reads only the
8
- * corpus, so it lives in `src/coherence/v2-envelope-tier-one-universal-static`
9
- * (moved in 2.45.18; `conformance.md` §Two products). This file keeps the one
10
- * leg that reads host output:
11
- *
12
- * strict LIVE: a host advertising `tierOneSubsetCompliance: "strict"`
13
- * has, for every kind it lists in `supportedEnvelopes.kinds`
14
- * that resolves to a corpus schema, a schema meeting the whole
15
- * intersection (closed objects, every property required, no
16
- * string/number/array bounds). Host-served vendor schemas are
17
- * not fetched, as at v1.
18
- *
19
- * The strict rule is stated by the schema seat's description ("`strict`: every
20
- * host-served envelope schema passes the static subset-compliance check"). The
21
- * v2 prose (`events.md` §envelopes) states a different, behavioural rule — the
22
- * host MUST accept an envelope restricted to the subset from any advertised
23
- * provider — and does not distinguish strict, warn and off.
24
- *
25
- * Dispositions: discovery unreadable ⇒ `blocked`; `envelopes` not
26
- * advertised, or `tierOneSubsetCompliance` other than "strict" ⇒
27
- * `inapplicable`; no advertised kind resolving to a corpus schema ⇒
28
- * `inapplicable`.
29
- *
30
- * @see RFCS/0030-envelope-reasoning-and-tier-one-subset.md §B
31
- * @see spec/v2/core/events.md §envelopes
32
- */
33
-
34
- import { describe, it, expect } from 'vitest';
35
- import { familyAdvertised, v2Discovery } from '../lib/v2.js';
36
- import { softSkip } from '../lib/soft-skip.js';
37
- import { req } from '../lib/requirement-ids.js';
38
- import { loadV2EnvelopeSchema, tierOneViolations, type SchemaViolation } from '../lib/envelope-schema-static.js';
39
-
40
- const ID_STRICT = 'openwop.requirement.envelopes.tier-one-strict-advertised-kinds';
41
-
42
- describe('v2 Tier-1 subset: a strict host\'s advertised kinds meet the whole intersection', () => {
43
- it('a host advertising tierOneSubsetCompliance strict has advertised kinds whose corpus schemas satisfy the Tier-1 intersection', async () => {
44
- let doc: Record<string, unknown> | null;
45
- try { doc = await v2Discovery(); } catch { doc = null; }
46
- if (!doc) return softSkip('blocked', 'v2 discovery unreachable — /.well-known/openwop did not answer 200 JSON under OpenWOP-Version: 2.0');
47
- const envelopes = await familyAdvertised('envelopes');
48
- if (envelopes === null) return softSkip('inapplicable', 'the host does not advertise envelopes');
49
- if (envelopes['tierOneSubsetCompliance'] !== 'strict') return softSkip('inapplicable', `envelopes.tierOneSubsetCompliance is ${JSON.stringify(envelopes['tierOneSubsetCompliance'])}, not "strict" — the strict walk binds only a strict host`);
50
- const catalog = await familyAdvertised('supportedEnvelopes');
51
- const kinds = Array.isArray(catalog?.['kinds']) ? (catalog['kinds'] as unknown[]).filter((k): k is string => typeof k === 'string') : [];
52
- const walked: Record<string, SchemaViolation[]> = {};
53
- let resolved = 0;
54
- for (const kind of kinds) {
55
- const schema = loadV2EnvelopeSchema(kind);
56
- if (schema === null) continue;
57
- resolved++;
58
- const v = tierOneViolations(schema, 'strict');
59
- if (v.length > 0) walked[kind] = v;
60
- }
61
- if (resolved === 0) return softSkip('inapplicable', `none of the ${kinds.length} kinds in supportedEnvelopes.kinds resolves to a corpus schema; host-served vendor schemas are not fetched`);
62
- expect(walked, req(ID_STRICT, 'capabilities.schema.json §envelopes.tierOneSubsetCompliance', `a strict host's advertised kinds MUST satisfy the Tier-1 intersection: ${JSON.stringify(walked)}`)).toEqual({});
63
- });
64
- });
@@ -1,85 +0,0 @@
1
- /**
2
- * v2 — the `envelopes` advertisement (`spec/v2/core/events.md` §`envelopes`;
3
- * RFCs 0030, 0032, 0033). A claims-check family: what the host says about its
4
- * envelope posture is what is witnessed. The v1 twins are the advertisement
5
- * legs of `envelope-reasoning-shape`, `envelope-retry-attempted` /
6
- * `envelope-refusal-shape` and `envelope-completion-distinguishes-truncation`;
7
- * the legs live in `lib/family-advert-witness.ts`.
8
- *
9
- * record the record validates against its seat in
10
- * `schemas/v2/capabilities.schema.json` (no v1 `supported` seat);
11
- * reasoning `reasoning.promptDirective` is mandatory | advisory | off;
12
- * tier-one `tierOneSubsetCompliance` is strict | warn | off;
13
- * reliability `reliability.events[]` names only reliability events and, with
14
- * the four v1 dotted names folded to their v2 equivalents
15
- * (aliases until 3.0, RFC 0228 §G), lists the two MUST-tier
16
- * events `envelope.retry-exhausted` and `envelope.refusal`;
17
- * completion `reliability.completion.distinguishesTruncation` is a boolean
18
- * and `truncationBudgetMultiplier` is in [1, 8].
19
- *
20
- * Dispositions: discovery unreadable ⇒ `blocked`; `envelopes` absent, or the
21
- * facet a leg reads absent ⇒ `inapplicable`.
22
- *
23
- * @see spec/v2/core/events.md §envelopes
24
- */
25
-
26
- import { describe, it, expect } from 'vitest';
27
- import { v2Discovery } from '../lib/v2.js';
28
- import { softSkip } from '../lib/soft-skip.js';
29
- import { req } from '../lib/requirement-ids.js';
30
- import { majorProfile } from '../lib/major-profile.js';
31
- import { envelopesCompletionLeg, envelopesReasoningLeg, envelopesReliabilityLeg, envelopesTierOneLeg, recordSchemaLeg } from '../lib/family-advert-witness.js';
32
-
33
- const PROFILE = majorProfile(2);
34
- const ID_RECORD = 'openwop.requirement.envelopes.advert-record-schema';
35
- const ID_REASONING = 'openwop.requirement.envelopes.reasoning-advert-shape';
36
- const ID_TIER_ONE = 'openwop.requirement.envelopes.tier-one-subset-compliance-value';
37
- const ID_RELIABILITY = 'openwop.requirement.envelopes.reliability-events-advert';
38
- const ID_COMPLETION = 'openwop.requirement.envelopes.completion-advert-shape';
39
-
40
- async function discovery(): Promise<Record<string, unknown> | null> {
41
- try { return await v2Discovery(); } catch { return null; }
42
- }
43
- const UNREADABLE = 'v2 discovery unreachable — /.well-known/openwop did not answer 200 JSON under OpenWOP-Version: 2.0';
44
-
45
- describe('v2 envelopes advertisement (events.md §envelopes)', () => {
46
- it('the envelopes record validates against its capabilities-schema seat', async () => {
47
- const doc = await discovery();
48
- if (!doc) return softSkip('blocked', UNREADABLE);
49
- const out = recordSchemaLeg(PROFILE, doc, 'envelopes', 'events.md §envelopes');
50
- if (out.kind === 'skip') return softSkip(out.disposition, out.reason);
51
- for (const x of out.findings) expect(x.ok, req(ID_RECORD, x.doc, x.message)).toBe(true);
52
- });
53
-
54
- it('envelopes.reasoning.promptDirective is mandatory, advisory or off', async () => {
55
- const doc = await discovery();
56
- if (!doc) return softSkip('blocked', UNREADABLE);
57
- const out = envelopesReasoningLeg(PROFILE, doc);
58
- if (out.kind === 'skip') return softSkip(out.disposition, out.reason);
59
- for (const x of out.findings) expect(x.ok, req(ID_REASONING, x.doc, x.message)).toBe(true);
60
- });
61
-
62
- it('envelopes.tierOneSubsetCompliance is strict, warn or off', async () => {
63
- const doc = await discovery();
64
- if (!doc) return softSkip('blocked', UNREADABLE);
65
- const out = envelopesTierOneLeg(PROFILE, doc);
66
- if (out.kind === 'skip') return softSkip(out.disposition, out.reason);
67
- for (const x of out.findings) expect(x.ok, req(ID_TIER_ONE, x.doc, x.message)).toBe(true);
68
- });
69
-
70
- it('envelopes.reliability.events lists only reliability events and includes retry-exhausted and refusal', async () => {
71
- const doc = await discovery();
72
- if (!doc) return softSkip('blocked', UNREADABLE);
73
- const out = envelopesReliabilityLeg(PROFILE, doc);
74
- if (out.kind === 'skip') return softSkip(out.disposition, out.reason);
75
- for (const x of out.findings) expect(x.ok, req(ID_RELIABILITY, x.doc, x.message)).toBe(true);
76
- });
77
-
78
- it('envelopes.reliability.completion.distinguishesTruncation is a boolean', async () => {
79
- const doc = await discovery();
80
- if (!doc) return softSkip('blocked', UNREADABLE);
81
- const out = envelopesCompletionLeg(PROFILE, doc);
82
- if (out.kind === 'skip') return softSkip(out.disposition, out.reason);
83
- for (const x of out.findings) expect(x.ok, req(ID_COMPLETION, x.doc, x.message)).toBe(true);
84
- });
85
- });
@@ -1,61 +0,0 @@
1
- /**
2
- * v2 — the three envelope caps on `limits` (`spec/v2/core/runs.md` §Limits:
3
- * "`limits` always carries `clarificationRounds` (per task), `schemaRounds`
4
- * (per envelope) and `envelopesPerTurn` (per chat turn)"). The v1 twin is the
5
- * advertisement half of `aiEnvelope.capBreached`; the legs live in
6
- * `lib/family-advert-witness.ts`. The other `limits` facets
7
- * (`maxRunDurationMs`, `maxLoopIterations`) are `v2-run-execution-bounds`.
8
- *
9
- * Each cap MUST be present and validate against its subschema in
10
- * `schemas/v2/capabilities.schema.json` (a non-negative integer).
11
- *
12
- * Dispositions: discovery unreadable ⇒ `blocked`; `limits` absent ⇒
13
- * `inapplicable` (at v2 presence of the record is the claim; the v1 rule that
14
- * `limits` itself is always present has no v2 seat — the root schema requires
15
- * only `protocolVersions` and `preferredVersion`).
16
- *
17
- * @see spec/v2/core/runs.md §Limits
18
- */
19
-
20
- import { describe, it, expect } from 'vitest';
21
- import { v2Discovery } from '../lib/v2.js';
22
- import { softSkip } from '../lib/soft-skip.js';
23
- import { req } from '../lib/requirement-ids.js';
24
- import { majorProfile } from '../lib/major-profile.js';
25
- import { limitsCapLeg } from '../lib/family-advert-witness.js';
26
-
27
- const PROFILE = majorProfile(2);
28
- const UNREADABLE = 'v2 discovery unreachable — /.well-known/openwop did not answer 200 JSON under OpenWOP-Version: 2.0';
29
- const ID_CLARIFICATION = 'openwop.requirement.limits.clarification-rounds-advertised';
30
- const ID_SCHEMA = 'openwop.requirement.limits.schema-rounds-advertised';
31
- const ID_ENVELOPES = 'openwop.requirement.limits.envelopes-per-turn-advertised';
32
-
33
- async function discovery(): Promise<Record<string, unknown> | null> {
34
- try { return await v2Discovery(); } catch { return null; }
35
- }
36
-
37
- describe('v2 limits envelope caps (runs.md §Limits)', () => {
38
- it('limits.clarificationRounds is present and a non-negative integer', async () => {
39
- const doc = await discovery();
40
- if (!doc) return softSkip('blocked', UNREADABLE);
41
- const out = limitsCapLeg(PROFILE, doc, 'clarificationRounds');
42
- if (out.kind === 'skip') return softSkip(out.disposition, out.reason);
43
- for (const x of out.findings) expect(x.ok, req(ID_CLARIFICATION, x.doc, x.message)).toBe(true);
44
- });
45
-
46
- it('limits.schemaRounds is present and a non-negative integer', async () => {
47
- const doc = await discovery();
48
- if (!doc) return softSkip('blocked', UNREADABLE);
49
- const out = limitsCapLeg(PROFILE, doc, 'schemaRounds');
50
- if (out.kind === 'skip') return softSkip(out.disposition, out.reason);
51
- for (const x of out.findings) expect(x.ok, req(ID_SCHEMA, x.doc, x.message)).toBe(true);
52
- });
53
-
54
- it('limits.envelopesPerTurn is present and a non-negative integer', async () => {
55
- const doc = await discovery();
56
- if (!doc) return softSkip('blocked', UNREADABLE);
57
- const out = limitsCapLeg(PROFILE, doc, 'envelopesPerTurn');
58
- if (out.kind === 'skip') return softSkip(out.disposition, out.reason);
59
- for (const x of out.findings) expect(x.ok, req(ID_ENVELOPES, x.doc, x.message)).toBe(true);
60
- });
61
- });