@openwop/openwop-conformance 1.152.0 → 1.154.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 (57) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +9 -0
  3. package/dist/cli.js +7 -2
  4. package/dist/lib/requirement-ids.js +100 -0
  5. package/dist/lib/scenario-disposition.js +22 -0
  6. package/package.json +33 -2
  7. package/requirement-aliases.json +4 -0
  8. package/requirements.json +23554 -0
  9. package/schemas/CORPUS-STAMP.json +99 -3
  10. package/src/cli.ts +7 -5
  11. package/src/global-setup.ts +13 -0
  12. package/src/lib/corpus-stamp.ts +125 -0
  13. package/src/lib/requirement-ids.ts +111 -0
  14. package/src/lib/scenario-disposition.ts +22 -0
  15. package/src/setup.ts +84 -5
  16. package/src/lib/capabilities-auth-subject-link.test.ts +0 -103
  17. package/src/lib/fork-availability.test.ts +0 -69
  18. package/src/lib/global-setup.test.ts +0 -76
  19. package/src/lib/grpc-framing.test.ts +0 -96
  20. package/src/lib/oidc-issuer.test.ts +0 -328
  21. package/src/lib/otel-collector-grpc.test.ts +0 -191
  22. package/src/lib/otel-collector.test.ts +0 -303
  23. package/src/lib/otlp-protobuf.test.ts +0 -461
  24. package/src/lib/polling.test.ts +0 -80
  25. package/src/lib/requirement-ledger.test.ts +0 -75
  26. package/src/lib/risk-disposition.test.ts +0 -91
  27. package/src/lib/saml-idp.test.ts +0 -127
  28. package/src/lib/spec-coherence-registry.test.ts +0 -155
  29. package/src/lib/webhook-receiver.test.ts +0 -144
  30. package/src/scenarios/artifact-schema-compile-bounded.test.ts +0 -126
  31. package/src/scenarios/artifact-type-legacy-ids.test.ts +0 -124
  32. package/src/scenarios/capability-example-root-layout.test.ts +0 -272
  33. package/src/scenarios/certification-floor-enforcement.test.ts +0 -204
  34. package/src/scenarios/chain-subchain-unsupported-refused.test.ts +0 -70
  35. package/src/scenarios/compensation-profile.test.ts +0 -340
  36. package/src/scenarios/core-manifest-and-extension-registry.test.ts +0 -250
  37. package/src/scenarios/discovery-canonical-family-no-shadow.test.ts +0 -219
  38. package/src/scenarios/edge-condition-truthy-falsy.test.ts +0 -108
  39. package/src/scenarios/effect-identity-composition.test.ts +0 -129
  40. package/src/scenarios/effect-identity-cross-scope.test.ts +0 -82
  41. package/src/scenarios/error-envelope-canonical-shape.test.ts +0 -64
  42. package/src/scenarios/form-content-packs.test.ts +0 -415
  43. package/src/scenarios/multi-region-effect-vocabulary.test.ts +0 -175
  44. package/src/scenarios/normative-example-extraction.test.ts +0 -242
  45. package/src/scenarios/openapi-asyncapi-sdk-parity.test.ts +0 -309
  46. package/src/scenarios/pack-manifest-extensions.test.ts +0 -203
  47. package/src/scenarios/protocol-version-grammar.test.ts +0 -119
  48. package/src/scenarios/registry-declarative-kinds.test.ts +0 -121
  49. package/src/scenarios/rfc-0147-self-audit.test.ts +0 -104
  50. package/src/scenarios/rfc-lifecycle-coherence.test.ts +0 -215
  51. package/src/scenarios/semantic-digest-v2.test.ts +0 -128
  52. package/src/scenarios/spec-corpus-validity.test.ts +0 -1727
  53. package/src/scenarios/spec-section-citations.test.ts +0 -132
  54. package/src/scenarios/tool-result-trust-monotone.test.ts +0 -168
  55. package/src/scenarios/versioned-composition-profiles.test.ts +0 -201
  56. package/src/scenarios/workflow-chain-internal-flag.test.ts +0 -84
  57. package/src/scenarios/workload-identity-profile.test.ts +0 -184
@@ -1,215 +0,0 @@
1
- /**
2
- * RFC 0149 §D — an `Accepted` RFC's unticked acceptance items must say why.
3
- *
4
- * §D asks the corpus generator to fail when an `Accepted` RFC "retains an
5
- * unresolved acceptance blocker not explicitly carried to a register/known-limit".
6
- * The obvious signal is the `- [ ]` boxes under §"Acceptance criteria", and the
7
- * obvious gate — every box ticked before `Accepted` — was measured and rejected.
8
- *
9
- * `docs/RFC-LIFECYCLE-COHERENCE.md` recorded the distribution: of 141 `Accepted`
10
- * RFCs, 42% ticked every box, 25% ticked none, 24% ticked some. A blanket gate
11
- * fails 69 RFCs on its first run, mostly for an authoring convention, and a gate
12
- * that fires 69 times on its first run gets disabled rather than fixed.
13
- *
14
- * The first triage hypothesis was also wrong, and correcting it produced the rule
15
- * this gate actually enforces. The partially-ticked RFCs are not a blocker
16
- * backlog: reading `0027`/`0028`/`0029`/`0040`/`0041` shows every trailing item
17
- * deliberately unticked AND annotated with why — "(Will land alongside the first
18
- * non-steward advertisement.)", "(Path-to-Accepted.)", "(Follow-up — … not
19
- * normative gate-blockers.)". That inline annotation IS §D's "explicitly
20
- * carried", just carried in a parenthetical rather than a register row.
21
- *
22
- * So the signal is **annotated vs bare, not ticked vs unticked**. An unticked
23
- * item with no explanation is indistinguishable from one nobody checked; an
24
- * unticked item that states its external gate is a decision on record. Ticking
25
- * nothing stays legal — the RFC did not use the mechanism — but leaving a box
26
- * unticked and unexplained does not.
27
- *
28
- * Applies from `LIFECYCLE_RULE_RFC` forward. Earlier RFCs are the dated record
29
- * of a period when the convention did not exist, and rewriting them would make
30
- * the record lie; the boundary is asserted here rather than assumed, so a NEW
31
- * RFC cannot inherit the exemption. Same carve-out shape as RFC 0149 §B's
32
- * root-layout lint.
33
- *
34
- * Server-free. `RFCS/` is repository-only, so this self-skips under the
35
- * published tarball layout.
36
- */
37
-
38
- import { describe, it, expect } from 'vitest';
39
- import { readFileSync, readdirSync, existsSync } from 'node:fs';
40
- import { join, resolve as pathResolve } from 'node:path';
41
- import { V1_DIR } from '../lib/paths.js';
42
-
43
- /** RFC 0149 §D takes effect with the RFC 0147 program's own cohort. */
44
- const LIFECYCLE_RULE_RFC = 147;
45
-
46
- const RFCS_DIR = V1_DIR === null ? null : pathResolve(V1_DIR, '..', '..', 'RFCS');
47
-
48
- interface BareItem {
49
- readonly rfc: number;
50
- readonly file: string;
51
- readonly line: number;
52
- readonly text: string;
53
- }
54
-
55
- /**
56
- * An item is "carried" when it states a reason: a parenthetical, or a pointer to
57
- * a gap register / known-limit / follow-up RFC. Anything else is bare.
58
- */
59
- function isAnnotated(text: string): boolean {
60
- if (/\([^)]{12,}\)/.test(text)) return true;
61
- return /\b(gap register|known.limit|register row|carried|deferred|blocked on|gated on)\b/i.test(text);
62
- }
63
-
64
- function statusOf(doc: string): string | null {
65
- const m = /^\|\s*\*\*Status\*\*\s*\|\s*`([^`]+)`/m.exec(doc);
66
- return m === null ? null : m[1]!;
67
- }
68
-
69
- /** Unticked acceptance items lacking a stated reason, for `Accepted` RFCs at or after the cutoff. */
70
- function bareItems(dir: string): BareItem[] {
71
- const found: BareItem[] = [];
72
- for (const name of readdirSync(dir).filter((f) => /^\d{4}-.*\.md$/.test(f)).sort()) {
73
- const rfc = Number.parseInt(name.slice(0, 4), 10);
74
- if (!Number.isFinite(rfc) || rfc < LIFECYCLE_RULE_RFC) continue;
75
- const doc = readFileSync(join(dir, name), 'utf8');
76
- if (statusOf(doc) !== 'Accepted') continue;
77
- const lines = doc.split('\n');
78
- let inAcceptance = false;
79
- for (let i = 0; i < lines.length; i++) {
80
- const line = lines[i]!;
81
- if (/^##\s/.test(line)) inAcceptance = /^##\s+Acceptance criteria\s*$/.test(line);
82
- if (!inAcceptance) continue;
83
- if (!/^\s*-\s*\[ \]\s/.test(line)) continue;
84
- const text = line.replace(/^\s*-\s*\[ \]\s*/, '');
85
- if (!isAnnotated(text)) found.push({ rfc, file: name, line: i + 1, text });
86
- }
87
- }
88
- return found;
89
- }
90
-
91
- describe.skipIf(RFCS_DIR === null || !existsSync(RFCS_DIR))('RFC 0149 §D — lifecycle coherence', () => {
92
- const dir = RFCS_DIR as string;
93
-
94
- it('the scan reaches Accepted RFCs in the governed range', () => {
95
- // Guard: a status regex that matched nothing, or a heading regex that never
96
- // entered the section, would make the assertion below vacuously true. That
97
- // is the failure RFC 0148 exists to close, and it is especially easy here
98
- // because the gate's PASSING state and its BROKEN state look identical.
99
- const governed = readdirSync(dir)
100
- .filter((f) => /^\d{4}-.*\.md$/.test(f))
101
- .filter((f) => Number.parseInt(f.slice(0, 4), 10) >= LIFECYCLE_RULE_RFC)
102
- .filter((f) => statusOf(readFileSync(join(dir, f), 'utf8')) === 'Accepted');
103
- expect(
104
- governed.length,
105
- `at least one Accepted RFC numbered >= ${LIFECYCLE_RULE_RFC} MUST exist for this gate to mean anything`,
106
- ).toBeGreaterThan(0);
107
-
108
- const withBoxes = governed.filter((f) =>
109
- /^##\s+Acceptance criteria\s*$/m.test(readFileSync(join(dir, f), 'utf8')),
110
- );
111
- expect(withBoxes.length, 'the acceptance-criteria heading MUST be found').toBeGreaterThan(0);
112
- });
113
-
114
- it('every unticked acceptance item states why it is unticked', () => {
115
- const bare = bareItems(dir).map((b) => `RFCS/${b.file}:${b.line} — ${b.text}`);
116
- expect(
117
- bare,
118
- 'RFC 0149 §D: an unticked acceptance item on an `Accepted` RFC MUST carry its reason — an ' +
119
- 'external gate, a follow-up note, or a register / known-limit pointer. Unticked-and-' +
120
- 'unexplained is indistinguishable from unchecked, which is what makes the checkbox ' +
121
- 'signal unusable. Tick it, annotate it, or carry it to a register row.\n ' +
122
- bare.join('\n '),
123
- ).toEqual([]);
124
- });
125
-
126
- it('the rule binds the cohort that proposed it', () => {
127
- // RFC 0149 is itself in the governed range. A gate whose author exempted
128
- // their own RFC would be the shape RFC 0147 §A.10 forbids — citing a
129
- // program's status as evidence its gaps are closed.
130
- const self = readFileSync(join(dir, '0149-machine-contract-and-version-reconciliation.md'), 'utf8');
131
- expect(statusOf(self), 'RFC 0149 is `Accepted`').toBe('Accepted');
132
- expect(
133
- 149 >= LIFECYCLE_RULE_RFC,
134
- 'RFC 0149 MUST fall inside the range its own §D governs',
135
- ).toBe(true);
136
- });
137
- });
138
-
139
- /**
140
- * Every non-terminal RFC either carries the **Parked** annotation with a named
141
- * tripwire, or is genuinely in flight.
142
- *
143
- * `RFCS/README.md` §"Parked RFCs" extends the annotation from `Draft` to
144
- * `Active`, and the reason is the confusion this corpus has now made in both
145
- * directions: **an RFC blocked on the world and an RFC blocked on somebody's
146
- * unfinished work look identical from an index.** RFC 0038 was parked on an
147
- * external tripwire while three of its acceptance criteria were plain
148
- * repository work nobody had done; RFC 0121 sits on an unresolved legal
149
- * question and kept re-reading as an open action item.
150
- *
151
- * What this leg defends is the honesty of the annotation, not its presence. A
152
- * Parked RFC MUST name a **falsifiable** tripwire — a condition someone could
153
- * check and declare met. "Needs more adoption" is not one. Without this leg the
154
- * annotation would be a label anybody could apply to make an index look
155
- * finished, which is precisely the move RFC 0147 §A exists to stop: **Parked is
156
- * a reason an RFC has not graduated, never a substitute for having graduated.**
157
- */
158
- describe.skipIf(RFCS_DIR === null || !existsSync(RFCS_DIR))('RFCS/README §Parked — a park names its tripwire', () => {
159
- const dir = RFCS_DIR as string;
160
-
161
- function nonTerminal(): { file: string; doc: string; status: string }[] {
162
- const out: { file: string; doc: string; status: string }[] = [];
163
- for (const name of readdirSync(dir).filter((f) => /^\d{4}-.*\.md$/.test(f)).sort()) {
164
- if (name.startsWith('0000')) continue; // the template is not an RFC
165
- const doc = readFileSync(join(dir, name), 'utf8');
166
- const st = statusOf(doc);
167
- if (st === 'Draft' || st === 'Active') out.push({ file: name, doc, status: st });
168
- }
169
- return out;
170
- }
171
-
172
- it('the scan finds the non-terminal RFCs it is meant to govern', () => {
173
- // Guard: if every RFC were `Accepted` this leg would pass over an empty set,
174
- // which is the vacuity RFC 0148 §C found in the floor verifier. If the corpus
175
- // ever genuinely reaches zero, delete this leg deliberately rather than
176
- // letting it go quiet.
177
- expect(
178
- nonTerminal().length,
179
- 'RFCS/README §"Status index" records non-terminal RFCs; a zero here means the scan broke, ' +
180
- 'not that the corpus finished',
181
- ).toBeGreaterThan(0);
182
- });
183
-
184
- it('every Parked RFC names a falsifiable tripwire', () => {
185
- const offenders: string[] = [];
186
- for (const { file, doc } of nonTerminal()) {
187
- const statusLine = /^\|\s*\*\*Status\*\*\s*\|[^\n]*$/m.exec(doc)?.[0] ?? '';
188
- if (!/\(\*\*Parked\*\*\)/.test(statusLine)) continue;
189
- const updated = /^\|\s*\*\*Updated\*\*\s*\|([^\n]*)$/m.exec(doc)?.[1] ?? '';
190
- if (!/tripwire/i.test(updated) || updated.length < 80) {
191
- offenders.push(`${file}: Parked without a named tripwire in \`Updated\``);
192
- }
193
- }
194
- expect(
195
- offenders,
196
- 'RFCS/README.md §"Parked RFCs" rule 1: a Parked RFC MUST name the condition that un-parks ' +
197
- 'it, in `Updated`. An unfalsifiable park is a label that makes an index look finished ' +
198
- 'while nothing was decided — Parked records why an RFC has NOT graduated, and is never a ' +
199
- 'substitute for having graduated.\n ' + offenders.join('\n '),
200
- ).toEqual([]);
201
- });
202
-
203
- it('no Parked RFC claims to be Accepted', () => {
204
- // Rule 2. The annotation confers nothing: an `Active` (**Parked**) RFC is
205
- // exactly as unimplemented as an `Active` one, and licenses no advertisement.
206
- for (const { file, doc, status } of nonTerminal()) {
207
- const statusLine = /^\|\s*\*\*Status\*\*\s*\|[^\n]*$/m.exec(doc)?.[0] ?? '';
208
- if (!/\(\*\*Parked\*\*\)/.test(statusLine)) continue;
209
- expect(
210
- status,
211
- `${file}: Parked applies to \`Draft\` and \`Active\` only — it never stands in for \`Accepted\``,
212
- ).not.toBe('Accepted');
213
- }
214
- });
215
- });
@@ -1,128 +0,0 @@
1
- /**
2
- * RFC 0150 §C — the semantic request digest, and three defects in `replay.md`.
3
- *
4
- * **1. The exclusion list forbids exactly what §C requires.** `replay.md` §A
5
- * says "Fields NOT in this set MUST NOT influence the cache key — including but
6
- * not limited to: `max_tokens`, `stop`, … `seed`". §C says the digest "MUST
7
- * cover the complete semantic provider request … maximum output bound, stop
8
- * conditions, seed". Those are direct opposites, and §A's side is wrong: a
9
- * request with `stop: ["END"]` and one without produce different completions, so
10
- * a cache keyed identically for both **returns the wrong response** — not a
11
- * miss, a wrong hit. Same for `seed`, whose entire purpose is to change output,
12
- * and for the output bound, which decides whether a response is truncated.
13
- *
14
- * **2. It prescribes a normalization JCS does not perform.** Step 2 says
15
- * canonicalize "via RFC 8785 JCS", then tells hosts without JCS to emit "UTF-8
16
- * NFC for all strings". JCS does **not** apply NFC. So the two paths the same
17
- * sentence offers produce **different bytes for the same input** whenever a
18
- * string is not already NFC — which is the portability property §D claims as a
19
- * normative invariant. §C: "Implementations MUST NOT add Unicode normalization
20
- * outside JCS."
21
- *
22
- * **3. It cites a formula that no longer exists.** §C quotes the Layer-2 id as
23
- * `sha256(runId ':' nodeId ':' attempt ':' providerKey)` — the composition RFC
24
- * 0150 §B retired as a safety-fix, because `attempt` in the preimage guaranteed
25
- * a duplicate effect on every retry. `idempotency.md` is v1.4; `replay.md` was
26
- * left quoting v1.1. This one is a cross-document staleness the §B change itself
27
- * introduced and did not catch.
28
- *
29
- * Server-free; reads the corpus. `spec/v1/` is repository-only, so it self-skips
30
- * under the published tarball layout.
31
- */
32
-
33
- import { describe, it, expect } from 'vitest';
34
- import { readFileSync } from 'node:fs';
35
- import { join } from 'node:path';
36
- import { V1_DIR } from '../lib/paths.js';
37
-
38
- /** Fields whose presence changes the model's output, so they change its identity. */
39
- const OUTCOME_AFFECTING = ['seed', 'stop', 'maxOutputTokens'];
40
-
41
- describe.skipIf(V1_DIR === null)('RFC 0150 §C — semantic request digest v2', () => {
42
- const doc = V1_DIR === null ? '' : readFileSync(join(V1_DIR as string, 'replay.md'), 'utf8');
43
-
44
- /**
45
- * Normative text only. Blockquote lines are excluded because this document
46
- * deliberately QUOTES the rules it retired, so a reader can see what changed
47
- * and why — and a naive substring search cannot tell a live rule from a
48
- * quoted-and-retired one. Same carve-out shape as RFC 0149 §B's lint, which
49
- * exempts pre-0073 RFCs as the dated record of what was proposed.
50
- *
51
- * The exemption is narrow on purpose: it covers `>` blocks, not the body, so
52
- * a retired rule cannot be resurrected into normative voice unnoticed.
53
- */
54
- const normative = doc
55
- .split('\n')
56
- .filter((l) => !/^\s*>/.test(l))
57
- .join('\n');
58
- const plain = normative.replace(/[`*_]/g, '').replace(/\s+/g, ' ');
59
- /** Full text including quotes — used only where a quote is the thing under test. */
60
- const everything = doc.replace(/[`*_]/g, '').replace(/\s+/g, ' ');
61
-
62
- it('the digest recipe section is found at all', () => {
63
- // Guard: an empty read makes every leg below vacuously true.
64
- expect(doc.length, 'replay.md MUST be readable').toBeGreaterThan(1000);
65
- expect(plain, 'the cache-key recipe MUST exist').toMatch(/cache key/i);
66
- // The blockquote filter must not swallow the document.
67
- expect(
68
- plain.length / everything.length,
69
- 'the normative-text filter MUST retain most of the document, or every leg below is vacuous',
70
- ).toBeGreaterThan(0.7);
71
- });
72
-
73
- it('outcome-affecting fields are covered, not excluded', () => {
74
- for (const field of OUTCOME_AFFECTING) {
75
- expect(
76
- plain.includes(field),
77
- `RFC 0150 §C: the digest MUST cover \`${field}\`. Excluding it means two requests that ` +
78
- 'produce different completions share a cache key — a wrong hit, not a miss.',
79
- ).toBe(true);
80
- }
81
- // The v1 exclusion sentence named them as MUST NOT influence. It must be gone.
82
- expect(
83
- /Fields NOT in this set MUST NOT influence the cache key/.test(plain),
84
- 'RFC 0150 §C: the v1 exclusion list forbade the very fields §C requires. It cannot survive ' +
85
- 'alongside the v2 recipe — a reader following it would build the colliding digest.',
86
- ).toBe(false);
87
- });
88
-
89
- it('no Unicode normalization is prescribed outside JCS', () => {
90
- expect(
91
- /UTF-8 NFC for all strings/.test(plain),
92
- 'RFC 0150 §C: "Implementations MUST NOT add Unicode normalization outside JCS." JCS does ' +
93
- 'not apply NFC, so offering NFC as the no-JCS fallback makes the two paths produce ' +
94
- 'different bytes for the same input — defeating the portability §D asserts.',
95
- ).toBe(false);
96
- });
97
-
98
- it('the recipe carries a version stamp so v1 and v2 digests cannot collide', () => {
99
- expect(
100
- plain,
101
- 'RFC 0150 §C: the canonical object carries `recipe: "openwop-semantic-request-v2"`, so a ' +
102
- 'digest computed under the old rules is distinguishable rather than silently comparable.',
103
- ).toContain('openwop-semantic-request-v2');
104
- });
105
-
106
- it('unknown provider options are carried, not dropped', () => {
107
- expect(
108
- /providerOptions/.test(plain),
109
- 'RFC 0150 §C: unknown provider options MUST go in a closed, namespaced `providerOptions` ' +
110
- 'object before hashing. "Silently dropping them is nonconformant" — a dropped option that ' +
111
- 'changes output is the collision this section exists to prevent.',
112
- ).toBe(true);
113
- });
114
-
115
- it('the Layer-2 cross-reference matches the composition that actually exists', () => {
116
- // Cross-document staleness introduced by RFC 0150 §B and not caught by it.
117
- expect(
118
- /attempt \|\| ':' \|\| providerKey|nodeId ':' attempt/.test(plain),
119
- 'RFC 0150 §B retired the `attempt`-bearing Layer-2 composition as a safety-fix. `replay.md` ' +
120
- 'MUST NOT keep quoting it — a reader following this section would rebuild the exact ' +
121
- 'defect §B removed, and would do so believing they were following the spec.',
122
- ).toBe(false);
123
- expect(
124
- plain,
125
- 'replay.md MUST cite the current Layer-2 identity',
126
- ).toContain('logicalInvocationId');
127
- });
128
- });