@openwop/openwop-conformance 1.139.0 → 1.140.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.
- package/dist/lib/scenario-disposition.js +14 -1
- package/dist/lib/spec-coherence.js +103 -0
- package/package.json +1 -1
- package/schemas/CORPUS-STAMP.json +2 -2
- package/src/lib/scenario-disposition.ts +16 -0
- package/src/lib/spec-coherence-registry.test.ts +100 -0
- package/src/lib/spec-coherence.ts +106 -0
- package/src/setup.ts +1 -1
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
import { PROFILE_FLOOR_SCENARIOS } from './profiles.js';
|
|
29
29
|
import { requirementIdForScenario, requirementIdForPrefix, requirementsFor } from './requirement-registry.js';
|
|
30
30
|
import { UNCLASSIFIED_RETURN_DETAIL } from './soft-skip.js';
|
|
31
|
+
import { SPEC_COHERENCE_SCENARIOS, SPEC_COHERENCE_DETAIL } from './spec-coherence.js';
|
|
31
32
|
import { CERTIFIABLE } from './requirement-ledger.js';
|
|
32
33
|
/** All scenario basenames that appear in some profile's runtime floor. */
|
|
33
34
|
export function floorScenarioFiles() {
|
|
@@ -100,7 +101,19 @@ export function fileDisposition(states, gateReason, assertionCount) {
|
|
|
100
101
|
* - every test `ctx.skip()`ped ⇒ the file's noted reason if it wrote one
|
|
101
102
|
* BEFORE skipping (`ctx.skip()` throws), else `blocked` + the marker.
|
|
102
103
|
*/
|
|
103
|
-
export function resolveFileRecord(states, gateReason, assertionCount, noted) {
|
|
104
|
+
export function resolveFileRecord(states, gateReason, assertionCount, noted, specCoherenceFile) {
|
|
105
|
+
// A scenario whose subject is the CORPUS, skipped because the published
|
|
106
|
+
// tarball does not bundle spec/v1/. RFC 0148 §A: `blocked` is defined over
|
|
107
|
+
// ADVERTISED BEHAVIOUR, and there is none here — nothing about the host was
|
|
108
|
+
// ever going to be exercised. `inapplicable` is the honest label, and it is
|
|
109
|
+
// CERTIFIABLE, so these rows stop counting against a host that cannot affect
|
|
110
|
+
// them. See lib/spec-coherence.ts for why not a new disposition value.
|
|
111
|
+
if (specCoherenceFile !== undefined
|
|
112
|
+
&& SPEC_COHERENCE_SCENARIOS.has(specCoherenceFile)
|
|
113
|
+
&& !states.includes('fail')
|
|
114
|
+
&& assertionCount === 0) {
|
|
115
|
+
return { disposition: 'inapplicable', detail: SPEC_COHERENCE_DETAIL };
|
|
116
|
+
}
|
|
104
117
|
let { disposition, detail } = fileDisposition(states, gateReason, assertionCount);
|
|
105
118
|
if (disposition === 'executed-pass' && assertionCount === 0) {
|
|
106
119
|
if (noted !== null) {
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scenarios that measure the SPEC, not the host (RFC 0148 §A).
|
|
3
|
+
*
|
|
4
|
+
* ## The defect
|
|
5
|
+
*
|
|
6
|
+
* 28 scenarios read `spec/v1/*.md` to check the corpus is internally coherent —
|
|
7
|
+
* that the `protocolVersion` grammar in the schema matches RFC 0149, that error
|
|
8
|
+
* envelopes are the shape `error-envelope.schema.json` declares, that every
|
|
9
|
+
* normative example extracts and validates. They assert nothing whatever about
|
|
10
|
+
* a host.
|
|
11
|
+
*
|
|
12
|
+
* `spec/v1/` is deliberately NOT bundled in the published tarball (`paths.ts`
|
|
13
|
+
* says so), so in a published-layout run `V1_DIR` is null and they
|
|
14
|
+
* `describe.skipIf` at COLLECTION time. No test body runs, so no `softSkip`
|
|
15
|
+
* note is recorded, and `resolveFileRecord` resolves an all-skipped file with no
|
|
16
|
+
* reason to **`blocked`** carrying "every test returned early … no recorded
|
|
17
|
+
* reason".
|
|
18
|
+
*
|
|
19
|
+
* That row then lands in a HOST's certification bundle. A host operator reads
|
|
20
|
+
* `blocked` and cannot tell it from a real gap in their implementation. A
|
|
21
|
+
* tier-2 host measured 13 such rows — **a third of their undiagnosed set** —
|
|
22
|
+
* and only discovered what they were by pointing `OPENWOP_CONFORMANCE_ROOT` at
|
|
23
|
+
* a spec checkout and watching 85 assertions pass in about a second, 59 of them
|
|
24
|
+
* against a dead `localhost:9`.
|
|
25
|
+
*
|
|
26
|
+
* ## Why `inapplicable`, and why not the other four
|
|
27
|
+
*
|
|
28
|
+
* RFC 0148 §A defines the two candidates precisely, and the definitions decide
|
|
29
|
+
* it:
|
|
30
|
+
*
|
|
31
|
+
* - `blocked` — "**advertised behavior** could not be exercised because a
|
|
32
|
+
* required seam, fixture, credential, or dependency was unavailable."
|
|
33
|
+
* There is no advertised behaviour here. Nothing about the host was ever
|
|
34
|
+
* going to be exercised, so nothing about the host failed to be.
|
|
35
|
+
* - `inapplicable` — "the requirement does not apply to the captured
|
|
36
|
+
* discovery/profile set." A requirement about the spec corpus does not
|
|
37
|
+
* apply to any host's discovery set. This is the honest label.
|
|
38
|
+
*
|
|
39
|
+
* `executed-pass` is wrong for the obvious reason: in a run where the corpus is
|
|
40
|
+
* absent, nothing executed, and claiming a pass for an unrun scenario is the
|
|
41
|
+
* defect this whole disposition system exists to prevent. A NEW disposition
|
|
42
|
+
* value was considered and rejected — `certification-bundle-v2.schema.json`
|
|
43
|
+
* enumerates the five, and `verifyBundleV2` is a published consumer contract,
|
|
44
|
+
* so a sixth is a wire break for every existing verifier. Correct use of an
|
|
45
|
+
* existing value costs nothing and breaks no one.
|
|
46
|
+
*
|
|
47
|
+
* `inapplicable` is in `CERTIFIABLE`, which is the point: these rows stop
|
|
48
|
+
* counting against a host that has no way to affect them.
|
|
49
|
+
*
|
|
50
|
+
* ## Why a list and not a predicate
|
|
51
|
+
*
|
|
52
|
+
* The property is static — "gates on `V1_DIR` and never touches `driver`" — and
|
|
53
|
+
* cannot be evaluated from `setup.ts` at runtime. So it is a list, and a list
|
|
54
|
+
* drifts. `spec-coherence-registry.test.ts` re-derives it from source on every
|
|
55
|
+
* run and fails when the two disagree, which is the only thing that makes a
|
|
56
|
+
* hand-maintained set trustworthy.
|
|
57
|
+
*
|
|
58
|
+
* ## What is deliberately NOT here
|
|
59
|
+
*
|
|
60
|
+
* Seven scenarios gate on `V1_DIR` **and** drive the host
|
|
61
|
+
* (`replay-side-effect-suppression`, `data-residency-admission`,
|
|
62
|
+
* `profile-discovery-core-alias`, `workflow-variable-format`,
|
|
63
|
+
* `workflow-chain-deferred-parameters`, `artifact-type-store-emission`,
|
|
64
|
+
* `artifact-type-registration-source`). Those assert advertised host behaviour
|
|
65
|
+
* that could not be exercised because a dependency was unavailable — which is
|
|
66
|
+
* `blocked`, exactly as §A defines it. Classifying them `inapplicable` would
|
|
67
|
+
* tell a host "this does not apply to you" about a requirement that does.
|
|
68
|
+
*/
|
|
69
|
+
/** Scenarios whose subject is the corpus. Kept honest by `spec-coherence-registry.test.ts`. */
|
|
70
|
+
export const SPEC_COHERENCE_SCENARIOS = new Set([
|
|
71
|
+
'artifact-schema-compile-bounded.test.ts',
|
|
72
|
+
'artifact-type-legacy-ids.test.ts',
|
|
73
|
+
'capability-example-root-layout.test.ts',
|
|
74
|
+
'certification-floor-enforcement.test.ts',
|
|
75
|
+
'chain-subchain-unsupported-refused.test.ts',
|
|
76
|
+
'compensation-profile.test.ts',
|
|
77
|
+
'core-manifest-and-extension-registry.test.ts',
|
|
78
|
+
'discovery-canonical-family-no-shadow.test.ts',
|
|
79
|
+
'edge-condition-truthy-falsy.test.ts',
|
|
80
|
+
'effect-identity-composition.test.ts',
|
|
81
|
+
'effect-identity-cross-scope.test.ts',
|
|
82
|
+
'error-envelope-canonical-shape.test.ts',
|
|
83
|
+
'form-content-packs.test.ts',
|
|
84
|
+
'multi-region-effect-vocabulary.test.ts',
|
|
85
|
+
'normative-example-extraction.test.ts',
|
|
86
|
+
'openapi-asyncapi-sdk-parity.test.ts',
|
|
87
|
+
'pack-manifest-extensions.test.ts',
|
|
88
|
+
'protocol-version-grammar.test.ts',
|
|
89
|
+
'registry-declarative-kinds.test.ts',
|
|
90
|
+
'rfc-0147-self-audit.test.ts',
|
|
91
|
+
'rfc-lifecycle-coherence.test.ts',
|
|
92
|
+
'semantic-digest-v2.test.ts',
|
|
93
|
+
'spec-corpus-validity.test.ts',
|
|
94
|
+
'spec-section-citations.test.ts',
|
|
95
|
+
'tool-result-trust-monotone.test.ts',
|
|
96
|
+
'versioned-composition-profiles.test.ts',
|
|
97
|
+
'workflow-chain-internal-flag.test.ts',
|
|
98
|
+
'workload-identity-profile.test.ts',
|
|
99
|
+
]);
|
|
100
|
+
/** The reason recorded on such a row, written for the host operator reading it. */
|
|
101
|
+
export const SPEC_COHERENCE_DETAIL = 'inapplicable to any host: this scenario reads spec/v1/ to check the SPEC corpus is internally coherent and asserts nothing about a host. '
|
|
102
|
+
+ 'The published tarball does not bundle spec/v1/ (see lib/paths.ts), so it does not run here. '
|
|
103
|
+
+ 'Set OPENWOP_CONFORMANCE_ROOT to a spec checkout to run it; it needs no host.';
|
package/package.json
CHANGED
|
@@ -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.
|
|
4
|
-
"corpusCommit": "
|
|
3
|
+
"suiteVersion": "1.140.0",
|
|
4
|
+
"corpusCommit": "8fe8053bfa7436a9c9a2dbbebd304095ecd29b16"
|
|
5
5
|
}
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
import { PROFILE_FLOOR_SCENARIOS } from './profiles.js';
|
|
30
30
|
import { requirementIdForScenario, requirementIdForPrefix, requirementsFor } from './requirement-registry.js';
|
|
31
31
|
import { UNCLASSIFIED_RETURN_DETAIL } from './soft-skip.js';
|
|
32
|
+
import { SPEC_COHERENCE_SCENARIOS, SPEC_COHERENCE_DETAIL } from './spec-coherence.js';
|
|
32
33
|
import { CERTIFIABLE, type Disposition, type LedgerEntry } from './requirement-ledger.js';
|
|
33
34
|
|
|
34
35
|
/** All scenario basenames that appear in some profile's runtime floor. */
|
|
@@ -112,7 +113,22 @@ export function resolveFileRecord(
|
|
|
112
113
|
gateReason: 'inapplicable' | 'skipped' | undefined,
|
|
113
114
|
assertionCount: number,
|
|
114
115
|
noted: { kind: 'inapplicable' | 'skipped' | 'blocked'; reason: string } | null,
|
|
116
|
+
specCoherenceFile?: string,
|
|
115
117
|
): { disposition: Disposition; detail?: string } {
|
|
118
|
+
// A scenario whose subject is the CORPUS, skipped because the published
|
|
119
|
+
// tarball does not bundle spec/v1/. RFC 0148 §A: `blocked` is defined over
|
|
120
|
+
// ADVERTISED BEHAVIOUR, and there is none here — nothing about the host was
|
|
121
|
+
// ever going to be exercised. `inapplicable` is the honest label, and it is
|
|
122
|
+
// CERTIFIABLE, so these rows stop counting against a host that cannot affect
|
|
123
|
+
// them. See lib/spec-coherence.ts for why not a new disposition value.
|
|
124
|
+
if (
|
|
125
|
+
specCoherenceFile !== undefined
|
|
126
|
+
&& SPEC_COHERENCE_SCENARIOS.has(specCoherenceFile)
|
|
127
|
+
&& !states.includes('fail')
|
|
128
|
+
&& assertionCount === 0
|
|
129
|
+
) {
|
|
130
|
+
return { disposition: 'inapplicable', detail: SPEC_COHERENCE_DETAIL };
|
|
131
|
+
}
|
|
116
132
|
let { disposition, detail } = fileDisposition(states, gateReason, assertionCount);
|
|
117
133
|
if (disposition === 'executed-pass' && assertionCount === 0) {
|
|
118
134
|
if (noted !== null) {
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keeps `SPEC_COHERENCE_SCENARIOS` honest by re-deriving it from source.
|
|
3
|
+
*
|
|
4
|
+
* A hand-maintained list of filenames is a claim that decays silently: a new
|
|
5
|
+
* spec-coherence scenario lands and reports `blocked` in every host's bundle
|
|
6
|
+
* forever, or one grows a `driver` call and starts telling hosts a requirement
|
|
7
|
+
* about their own behaviour does not apply to them. Neither shows up as a
|
|
8
|
+
* failure anywhere — which is the whole reason the original defect survived.
|
|
9
|
+
*
|
|
10
|
+
* The membership rule is mechanical, so the check can be too:
|
|
11
|
+
* gates on `V1_DIR === null` AND never calls `driver.get/post/delete`.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { describe, expect, it } from 'vitest';
|
|
15
|
+
import { readFileSync, readdirSync } from 'node:fs';
|
|
16
|
+
import { join } from 'node:path';
|
|
17
|
+
import { SPEC_COHERENCE_SCENARIOS, SPEC_COHERENCE_DETAIL } from './spec-coherence.js';
|
|
18
|
+
import { resolveFileRecord } from './scenario-disposition.js';
|
|
19
|
+
|
|
20
|
+
const SCENARIOS = new URL('../scenarios/', import.meta.url).pathname;
|
|
21
|
+
|
|
22
|
+
function derive(): { pure: string[]; hostTouching: string[] } {
|
|
23
|
+
const pure: string[] = [];
|
|
24
|
+
const hostTouching: string[] = [];
|
|
25
|
+
for (const f of readdirSync(SCENARIOS)) {
|
|
26
|
+
if (!f.endsWith('.test.ts')) continue;
|
|
27
|
+
const src = readFileSync(join(SCENARIOS, f), 'utf8');
|
|
28
|
+
if (!/V1_DIR\s*===?\s*null/.test(src)) continue;
|
|
29
|
+
(/\bdriver\.(get|post|delete)\b/.test(src) ? hostTouching : pure).push(f);
|
|
30
|
+
}
|
|
31
|
+
return { pure: pure.sort(), hostTouching: hostTouching.sort() };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
describe('SPEC_COHERENCE_SCENARIOS is derivable, not asserted', () => {
|
|
35
|
+
it('matches every scenario that reads spec/v1 and never drives a host', () => {
|
|
36
|
+
const { pure } = derive();
|
|
37
|
+
const listed = [...SPEC_COHERENCE_SCENARIOS].sort();
|
|
38
|
+
// Named diffs rather than a bare inequality: a failure here should say
|
|
39
|
+
// which file to add or drop, not that two sets differ.
|
|
40
|
+
expect(pure.filter((f) => !SPEC_COHERENCE_SCENARIOS.has(f)), 'reads spec/v1, drives no host, NOT in the registry — it will report `blocked` in every host bundle').toEqual([]);
|
|
41
|
+
expect(listed.filter((f) => !pure.includes(f)), 'in the registry but no longer qualifies — it now drives a host, or stopped reading spec/v1').toEqual([]);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('excludes the host-touching ones, which are honestly `blocked`', () => {
|
|
45
|
+
// These assert ADVERTISED behaviour that a missing dependency prevented
|
|
46
|
+
// exercising — RFC 0148 §A's definition of `blocked`, verbatim. Calling
|
|
47
|
+
// them `inapplicable` would tell a host a requirement about its own
|
|
48
|
+
// behaviour does not apply to it.
|
|
49
|
+
const { hostTouching } = derive();
|
|
50
|
+
expect(hostTouching.length, 'expected some V1_DIR-gated scenarios to also drive the host').toBeGreaterThan(0);
|
|
51
|
+
for (const f of hostTouching) {
|
|
52
|
+
expect(SPEC_COHERENCE_SCENARIOS.has(f), `${f} drives a host and must NOT be classified inapplicable`).toBe(false);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('the registry is non-empty — an empty set would silently disable the fix', () => {
|
|
57
|
+
expect(SPEC_COHERENCE_SCENARIOS.size).toBeGreaterThan(20);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
describe('resolveFileRecord classifies a corpus scenario as inapplicable, not blocked', () => {
|
|
62
|
+
// A published-layout run: describe.skipIf fires at COLLECTION, so vitest
|
|
63
|
+
// reports the file's tests as skipped, nothing notes a reason, and before
|
|
64
|
+
// this change resolveFileRecord returned `blocked` with the unclassified
|
|
65
|
+
// marker — the row a host operator could not tell from a real gap.
|
|
66
|
+
const CORPUS = 'protocol-version-grammar.test.ts';
|
|
67
|
+
|
|
68
|
+
it('a corpus scenario that never ran is inapplicable, with a reason aimed at the host operator', () => {
|
|
69
|
+
const r = resolveFileRecord(['skip', 'skip'], undefined, 0, null, CORPUS);
|
|
70
|
+
expect(r.disposition).toBe('inapplicable');
|
|
71
|
+
expect(r.detail).toBe(SPEC_COHERENCE_DETAIL);
|
|
72
|
+
expect(r.detail).toContain('asserts nothing about a host');
|
|
73
|
+
expect(r.detail).toContain('OPENWOP_CONFORMANCE_ROOT');
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('WITHOUT the registry it would still be blocked — the branch is what changes it', () => {
|
|
77
|
+
// Same inputs, filename withheld: the pre-change behaviour. This is the
|
|
78
|
+
// negative control; if it ever returns `inapplicable`, the branch is not
|
|
79
|
+
// what is doing the work and the test above proves nothing.
|
|
80
|
+
const r = resolveFileRecord(['skip', 'skip'], undefined, 0, null);
|
|
81
|
+
expect(r.disposition).toBe('blocked');
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('a non-corpus scenario is untouched', () => {
|
|
85
|
+
const r = resolveFileRecord(['skip', 'skip'], undefined, 0, null, 'webhook-signed-delivery.test.ts');
|
|
86
|
+
expect(r.disposition).toBe('blocked');
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('a corpus scenario that FAILED is never laundered into inapplicable', () => {
|
|
90
|
+
// The guard that matters: if the corpus IS present and an assertion fails,
|
|
91
|
+
// that is a real spec-coherence defect and must stay executed-fail.
|
|
92
|
+
const r = resolveFileRecord(['pass', 'fail'], undefined, 12, null, CORPUS);
|
|
93
|
+
expect(r.disposition).toBe('executed-fail');
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('a corpus scenario that RAN and passed stays executed-pass', () => {
|
|
97
|
+
const r = resolveFileRecord(['pass'], undefined, 40, null, CORPUS);
|
|
98
|
+
expect(r.disposition).toBe('executed-pass');
|
|
99
|
+
});
|
|
100
|
+
});
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scenarios that measure the SPEC, not the host (RFC 0148 §A).
|
|
3
|
+
*
|
|
4
|
+
* ## The defect
|
|
5
|
+
*
|
|
6
|
+
* 28 scenarios read `spec/v1/*.md` to check the corpus is internally coherent —
|
|
7
|
+
* that the `protocolVersion` grammar in the schema matches RFC 0149, that error
|
|
8
|
+
* envelopes are the shape `error-envelope.schema.json` declares, that every
|
|
9
|
+
* normative example extracts and validates. They assert nothing whatever about
|
|
10
|
+
* a host.
|
|
11
|
+
*
|
|
12
|
+
* `spec/v1/` is deliberately NOT bundled in the published tarball (`paths.ts`
|
|
13
|
+
* says so), so in a published-layout run `V1_DIR` is null and they
|
|
14
|
+
* `describe.skipIf` at COLLECTION time. No test body runs, so no `softSkip`
|
|
15
|
+
* note is recorded, and `resolveFileRecord` resolves an all-skipped file with no
|
|
16
|
+
* reason to **`blocked`** carrying "every test returned early … no recorded
|
|
17
|
+
* reason".
|
|
18
|
+
*
|
|
19
|
+
* That row then lands in a HOST's certification bundle. A host operator reads
|
|
20
|
+
* `blocked` and cannot tell it from a real gap in their implementation. A
|
|
21
|
+
* tier-2 host measured 13 such rows — **a third of their undiagnosed set** —
|
|
22
|
+
* and only discovered what they were by pointing `OPENWOP_CONFORMANCE_ROOT` at
|
|
23
|
+
* a spec checkout and watching 85 assertions pass in about a second, 59 of them
|
|
24
|
+
* against a dead `localhost:9`.
|
|
25
|
+
*
|
|
26
|
+
* ## Why `inapplicable`, and why not the other four
|
|
27
|
+
*
|
|
28
|
+
* RFC 0148 §A defines the two candidates precisely, and the definitions decide
|
|
29
|
+
* it:
|
|
30
|
+
*
|
|
31
|
+
* - `blocked` — "**advertised behavior** could not be exercised because a
|
|
32
|
+
* required seam, fixture, credential, or dependency was unavailable."
|
|
33
|
+
* There is no advertised behaviour here. Nothing about the host was ever
|
|
34
|
+
* going to be exercised, so nothing about the host failed to be.
|
|
35
|
+
* - `inapplicable` — "the requirement does not apply to the captured
|
|
36
|
+
* discovery/profile set." A requirement about the spec corpus does not
|
|
37
|
+
* apply to any host's discovery set. This is the honest label.
|
|
38
|
+
*
|
|
39
|
+
* `executed-pass` is wrong for the obvious reason: in a run where the corpus is
|
|
40
|
+
* absent, nothing executed, and claiming a pass for an unrun scenario is the
|
|
41
|
+
* defect this whole disposition system exists to prevent. A NEW disposition
|
|
42
|
+
* value was considered and rejected — `certification-bundle-v2.schema.json`
|
|
43
|
+
* enumerates the five, and `verifyBundleV2` is a published consumer contract,
|
|
44
|
+
* so a sixth is a wire break for every existing verifier. Correct use of an
|
|
45
|
+
* existing value costs nothing and breaks no one.
|
|
46
|
+
*
|
|
47
|
+
* `inapplicable` is in `CERTIFIABLE`, which is the point: these rows stop
|
|
48
|
+
* counting against a host that has no way to affect them.
|
|
49
|
+
*
|
|
50
|
+
* ## Why a list and not a predicate
|
|
51
|
+
*
|
|
52
|
+
* The property is static — "gates on `V1_DIR` and never touches `driver`" — and
|
|
53
|
+
* cannot be evaluated from `setup.ts` at runtime. So it is a list, and a list
|
|
54
|
+
* drifts. `spec-coherence-registry.test.ts` re-derives it from source on every
|
|
55
|
+
* run and fails when the two disagree, which is the only thing that makes a
|
|
56
|
+
* hand-maintained set trustworthy.
|
|
57
|
+
*
|
|
58
|
+
* ## What is deliberately NOT here
|
|
59
|
+
*
|
|
60
|
+
* Seven scenarios gate on `V1_DIR` **and** drive the host
|
|
61
|
+
* (`replay-side-effect-suppression`, `data-residency-admission`,
|
|
62
|
+
* `profile-discovery-core-alias`, `workflow-variable-format`,
|
|
63
|
+
* `workflow-chain-deferred-parameters`, `artifact-type-store-emission`,
|
|
64
|
+
* `artifact-type-registration-source`). Those assert advertised host behaviour
|
|
65
|
+
* that could not be exercised because a dependency was unavailable — which is
|
|
66
|
+
* `blocked`, exactly as §A defines it. Classifying them `inapplicable` would
|
|
67
|
+
* tell a host "this does not apply to you" about a requirement that does.
|
|
68
|
+
*/
|
|
69
|
+
|
|
70
|
+
/** Scenarios whose subject is the corpus. Kept honest by `spec-coherence-registry.test.ts`. */
|
|
71
|
+
export const SPEC_COHERENCE_SCENARIOS: ReadonlySet<string> = new Set([
|
|
72
|
+
'artifact-schema-compile-bounded.test.ts',
|
|
73
|
+
'artifact-type-legacy-ids.test.ts',
|
|
74
|
+
'capability-example-root-layout.test.ts',
|
|
75
|
+
'certification-floor-enforcement.test.ts',
|
|
76
|
+
'chain-subchain-unsupported-refused.test.ts',
|
|
77
|
+
'compensation-profile.test.ts',
|
|
78
|
+
'core-manifest-and-extension-registry.test.ts',
|
|
79
|
+
'discovery-canonical-family-no-shadow.test.ts',
|
|
80
|
+
'edge-condition-truthy-falsy.test.ts',
|
|
81
|
+
'effect-identity-composition.test.ts',
|
|
82
|
+
'effect-identity-cross-scope.test.ts',
|
|
83
|
+
'error-envelope-canonical-shape.test.ts',
|
|
84
|
+
'form-content-packs.test.ts',
|
|
85
|
+
'multi-region-effect-vocabulary.test.ts',
|
|
86
|
+
'normative-example-extraction.test.ts',
|
|
87
|
+
'openapi-asyncapi-sdk-parity.test.ts',
|
|
88
|
+
'pack-manifest-extensions.test.ts',
|
|
89
|
+
'protocol-version-grammar.test.ts',
|
|
90
|
+
'registry-declarative-kinds.test.ts',
|
|
91
|
+
'rfc-0147-self-audit.test.ts',
|
|
92
|
+
'rfc-lifecycle-coherence.test.ts',
|
|
93
|
+
'semantic-digest-v2.test.ts',
|
|
94
|
+
'spec-corpus-validity.test.ts',
|
|
95
|
+
'spec-section-citations.test.ts',
|
|
96
|
+
'tool-result-trust-monotone.test.ts',
|
|
97
|
+
'versioned-composition-profiles.test.ts',
|
|
98
|
+
'workflow-chain-internal-flag.test.ts',
|
|
99
|
+
'workload-identity-profile.test.ts',
|
|
100
|
+
]);
|
|
101
|
+
|
|
102
|
+
/** The reason recorded on such a row, written for the host operator reading it. */
|
|
103
|
+
export const SPEC_COHERENCE_DETAIL =
|
|
104
|
+
'inapplicable to any host: this scenario reads spec/v1/ to check the SPEC corpus is internally coherent and asserts nothing about a host. '
|
|
105
|
+
+ 'The published tarball does not bundle spec/v1/ (see lib/paths.ts), so it does not run here. '
|
|
106
|
+
+ 'Set OPENWOP_CONFORMANCE_ROOT to a spec checkout to run it; it needs no host.';
|
package/src/setup.ts
CHANGED
|
@@ -278,7 +278,7 @@ afterAll(({}, suite) => {
|
|
|
278
278
|
// the marker detail — never to a pass. Floors still REJECT that row, so the
|
|
279
279
|
// honest bundle row and the pressure to say why both survive. The rule is
|
|
280
280
|
// `resolveFileRecord` (pinned by conformance-execution-witness.test.ts).
|
|
281
|
-
const { disposition, detail } = resolveFileRecord(states, gateReason, assertionCount, softSkipDisposition(file));
|
|
281
|
+
const { disposition, detail } = resolveFileRecord(states, gateReason, assertionCount, softSkipDisposition(file), file);
|
|
282
282
|
const fileRequirementId = requirementIdForFile(file);
|
|
283
283
|
// A scenario that classified ITSELF wins outright — including its `detail` and
|
|
284
284
|
// its `assertionCount`.
|