@openwop/openwop-conformance 2.0.0-rc.0 → 2.0.0-rc.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.
Files changed (72) hide show
  1. package/README.md +2 -2
  2. package/dist/cli.js +209 -14
  3. package/dist/lib/certification-bundle-v3.js +142 -0
  4. package/dist/lib/requirement-ids.js +23 -0
  5. package/dist/lib/requirement-ledger.js +1 -0
  6. package/dist/lib/scenario-disposition.js +5 -1
  7. package/dist/spec-artifacts.lock.json +2 -2
  8. package/package.json +2 -2
  9. package/requirements.json +2744 -4
  10. package/scenario-majors.json +155 -2
  11. package/schemas/CORPUS-STAMP.json +17 -17
  12. package/src/cli.ts +190 -19
  13. package/src/lib/certification-bundle-v3.ts +175 -0
  14. package/src/lib/driver.ts +9 -1
  15. package/src/lib/era2-seed.ts +197 -0
  16. package/src/lib/requirement-ids.ts +21 -0
  17. package/src/lib/requirement-ledger.ts +7 -1
  18. package/src/lib/scenario-disposition.ts +5 -1
  19. package/src/lib/seams.ts +45 -0
  20. package/src/lib/v2.ts +62 -0
  21. package/src/scenarios/v2-approver-enforced.test.ts +97 -0
  22. package/src/scenarios/v2-assurance-downgrade-audited.test.ts +75 -0
  23. package/src/scenarios/v2-bundle-v3-signed.test.ts +96 -0
  24. package/src/scenarios/v2-capabilities-root-closed.test.ts +63 -0
  25. package/src/scenarios/v2-capability-record-shape.test.ts +104 -0
  26. package/src/scenarios/v2-chain-pin-exact.test.ts +118 -0
  27. package/src/scenarios/v2-coherence-not-in-bundle.test.ts +98 -0
  28. package/src/scenarios/v2-compensation-read-projection.test.ts +85 -0
  29. package/src/scenarios/v2-configurable-closed.test.ts +67 -0
  30. package/src/scenarios/v2-dual-stack-negotiation.test.ts +118 -0
  31. package/src/scenarios/v2-effect-identity-business-key.test.ts +132 -0
  32. package/src/scenarios/v2-effect-seam-manifest.test.ts +163 -0
  33. package/src/scenarios/v2-enum-growth-rule.test.ts +69 -0
  34. package/src/scenarios/v2-era-2-append-vocabulary.test.ts +140 -0
  35. package/src/scenarios/v2-era-key.test.ts +86 -0
  36. package/src/scenarios/v2-error-registry.test.ts +89 -0
  37. package/src/scenarios/v2-event-type-closed.test.ts +97 -0
  38. package/src/scenarios/v2-fork-a-v1-run.test.ts +109 -0
  39. package/src/scenarios/v2-form-when-reuses-edge-conditions.test.ts +70 -0
  40. package/src/scenarios/v2-header-scheme.test.ts +67 -0
  41. package/src/scenarios/v2-id-grammar.test.ts +77 -0
  42. package/src/scenarios/v2-idempotency-key-grammar.test.ts +65 -0
  43. package/src/scenarios/v2-interrupt-token-scheme.test.ts +55 -0
  44. package/src/scenarios/v2-lane-issuer-advertised.test.ts +62 -0
  45. package/src/scenarios/v2-legacy-profiles-absent.test.ts +78 -0
  46. package/src/scenarios/v2-manifest-ceiling-refused.test.ts +130 -0
  47. package/src/scenarios/v2-manifest-hatch-carried.test.ts +120 -0
  48. package/src/scenarios/v2-min-client-version.test.ts +48 -0
  49. package/src/scenarios/v2-minimum-version-refused.test.ts +141 -0
  50. package/src/scenarios/v2-mrtr-rounds-ceiling.test.ts +95 -0
  51. package/src/scenarios/v2-negotiation-authenticated.test.ts +125 -0
  52. package/src/scenarios/v2-negotiation-decided-emitted.test.ts +149 -0
  53. package/src/scenarios/v2-no-transport-advertisement.test.ts +57 -0
  54. package/src/scenarios/v2-owner-subject-required.test.ts +72 -0
  55. package/src/scenarios/v2-pack-isolation.test.ts +147 -0
  56. package/src/scenarios/v2-payload-registry-closed.test.ts +110 -0
  57. package/src/scenarios/v2-peer-dependency-declared.test.ts +132 -0
  58. package/src/scenarios/v2-pinned-run-disposition.test.ts +124 -0
  59. package/src/scenarios/v2-poll-cursor-v2.test.ts +114 -0
  60. package/src/scenarios/v2-preferred-version-default.test.ts +83 -0
  61. package/src/scenarios/v2-profiles-derived-only.test.ts +70 -0
  62. package/src/scenarios/v2-provider-conflict.test.ts +115 -0
  63. package/src/scenarios/v2-refresh-sla.test.ts +78 -0
  64. package/src/scenarios/v2-relaxation-recorded.test.ts +134 -0
  65. package/src/scenarios/v2-revocation-honored.test.ts +66 -0
  66. package/src/scenarios/v2-subject-link-record.test.ts +102 -0
  67. package/src/scenarios/v2-unmapped-type-refused.test.ts +95 -0
  68. package/src/scenarios/v2-v1-events-translated.test.ts +105 -0
  69. package/src/scenarios/v2-v1-signed-webhook-accepted.test.ts +109 -0
  70. package/src/scenarios/v2-webhook-durable-delivery.test.ts +238 -0
  71. package/src/scenarios/v2-well-known-one-resource.test.ts +129 -0
  72. package/src/setup.ts +40 -4
package/src/setup.ts CHANGED
@@ -31,7 +31,9 @@ import { OtelCollector, setCollector } from './lib/otel-collector.js';
31
31
  import { McpFakeServer, setMcpFakeServer } from './lib/mcp-fake-server.js';
32
32
  import { A2AFakePeer, setA2AFakePeer } from './lib/a2a-fake-peer.js';
33
33
  import { afterAll, afterEach, beforeAll, beforeEach, expect } from 'vitest';
34
- import { basename } from 'node:path';
34
+ import { basename, join } from 'node:path';
35
+ import { existsSync, readFileSync } from 'node:fs';
36
+ import { PKG_ROOT_PATH } from './lib/paths.js';
35
37
  import { recordRequirement, hasRequirement, journalLength, journalSince } from './lib/requirement-ledger.js';
36
38
  import { requirementIdForFile, resolveFileRecord, type FileTestState } from './lib/scenario-disposition.js';
37
39
  import { softSkipDisposition } from './lib/soft-skip.js';
@@ -243,6 +245,34 @@ function _assertionCalls(): number {
243
245
  return 0;
244
246
  }
245
247
  }
248
+
249
+ /**
250
+ * (file, title) → the explicit `req()` id the scenario cites, read from the
251
+ * generated `requirements.json` that ships with the package. Only ids under
252
+ * `openwop.requirement.` are returned: a per-`it` id is what the allocator
253
+ * would mint anyway.
254
+ */
255
+ let _registry: Map<string, string> | undefined;
256
+ function registeredExplicitId(file: string, title: string): string | null {
257
+ if (_registry === undefined) {
258
+ _registry = new Map();
259
+ for (const root of [PKG_ROOT_PATH, join(PKG_ROOT_PATH, '..')]) {
260
+ const path = join(root, 'requirements.json');
261
+ if (!existsSync(path)) continue;
262
+ try {
263
+ const doc = JSON.parse(readFileSync(path, 'utf8')) as { records?: Array<{ file?: unknown; title?: unknown; explicitId?: unknown }> };
264
+ for (const r of doc.records ?? []) {
265
+ if (typeof r.file === 'string' && typeof r.title === 'string' && typeof r.explicitId === 'string' && r.explicitId.startsWith('openwop.requirement.')) {
266
+ _registry.set(`${r.file}\u0000${r.title}`, r.explicitId);
267
+ }
268
+ }
269
+ } catch { /* an unreadable registry simply yields no fallback */ }
270
+ break;
271
+ }
272
+ }
273
+ return _registry.get(`${file}\u0000${title}`) ?? null;
274
+ }
275
+
246
276
  function _fileOf(task: { file?: { filepath?: string; name?: string } } | undefined): string | null {
247
277
  const f = task?.file?.filepath ?? task?.file?.name;
248
278
  return typeof f === 'string' && f.length > 0 ? basename(f) : null;
@@ -297,7 +327,13 @@ afterEach(({ task }) => {
297
327
  takeExplicitRequirementId();
298
328
  return;
299
329
  }
300
- const explicit = takeExplicitRequirementId();
330
+ // A leg that soft-skips before its first assertion never calls `req()`, so the
331
+ // runtime override is empty and the row lands under the per-`it` id instead of
332
+ // the requirement the leg is about — leaving that requirement with no row in
333
+ // any bundle, which is the §F Witness gate's subject. The generated registry
334
+ // already knows (file, title) → explicit id statically, so fall back to it and
335
+ // the disposition is attributed either way.
336
+ const explicit = takeExplicitRequirementId() ?? registeredExplicitId(file, task.name);
301
337
  const alloc = _itAllocators.get(file) ?? new ItIdAllocator();
302
338
  _itAllocators.set(file, alloc);
303
339
  const itId = explicit ?? alloc.allocate(file, task.name);
@@ -329,7 +365,7 @@ afterEach(({ task }) => {
329
365
  detail = 'vitest skipped the test (ctx.skip / it.skip) without a recorded gate reason';
330
366
  }
331
367
  try {
332
- recordRequirement(itId, disposition, detail, { assertionCount: calls });
368
+ recordRequirement(itId, disposition, detail, { assertionCount: calls, scenarioFile: file });
333
369
  } catch {
334
370
  /* never fail a test for bookkeeping */
335
371
  }
@@ -376,7 +412,7 @@ afterAll(({}, suite) => {
376
412
  // of both now.
377
413
  if (!hasRequirement(fileRequirementId)) {
378
414
  try {
379
- recordRequirement(fileRequirementId, disposition, detail, { assertionCount });
415
+ recordRequirement(fileRequirementId, disposition, detail, { assertionCount, scenarioFile: file });
380
416
  } catch {
381
417
  /* never fail a file for bookkeeping */
382
418
  }