@openwop/openwop-conformance 2.0.4 → 2.0.5
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/CHANGELOG.md +54 -0
- package/dist/cli.js +5 -1
- package/dist/lib/certification-bundle-v3.js +29 -0
- package/dist/spec-artifacts.lock.json +2 -2
- package/package.json +2 -2
- package/requirement-aliases.json +167 -2
- package/requirements.json +606 -766
- package/scenario-majors.json +3 -2
- package/schemas/CORPUS-STAMP.json +49 -11
- package/src/cli.ts +5 -1
- package/src/lib/certification-bundle-v3.ts +54 -1
- package/src/lib/era2-seed.ts +27 -0
- package/src/lib/memoryAttribution.ts +30 -3
- package/src/scenarios/memory-attribution-replay-stable.test.ts +30 -6
- package/src/scenarios/v2-run-fork-prefix.test.ts +85 -1
- package/src/scenarios/v2-unmapped-type-refused.test.ts +82 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,59 @@
|
|
|
1
1
|
# `@openwop/openwop-conformance` Changelog
|
|
2
2
|
|
|
3
|
+
## [2.0.5] — 2026-09-06 — four rules with no way to be checked
|
|
4
|
+
|
|
5
|
+
Four instruments that could not, even in principle, return the answer they
|
|
6
|
+
appeared to give. Three of them were green.
|
|
7
|
+
|
|
8
|
+
**The vendor rule's registry did not exist.** `events.md` §Rules and
|
|
9
|
+
`persistence.md` §The codemap is data both require a vendor event type's first
|
|
10
|
+
segment to be an org registered under `extensions` in
|
|
11
|
+
`spec/v2/declaration.json`. There was no `extensions` key. Three near misses
|
|
12
|
+
kept it plausible — `extensionsKeyPattern` is a key SHAPE, `reservedOrgs` lists
|
|
13
|
+
FORBIDDEN orgs, and `metadata[]` carries a row keyed `extensions` that is the
|
|
14
|
+
host's own extension map in the discovery payload. The registry now exists and
|
|
15
|
+
holds `example`, reserved by the protocol and never assignable to a vendor.
|
|
16
|
+
|
|
17
|
+
**`v2-unmapped-type-refused` drove only the refusal half**, so a host that
|
|
18
|
+
refuses EVERY unmapped type — including a registered vendor type it MUST pass
|
|
19
|
+
through — went green while violating the rule. New leg
|
|
20
|
+
`openwop.requirement.0176.vendor-type-passthrough`: same log shape, one segment
|
|
21
|
+
changed. Its preconditions were a note inside a seeded payload, prose in a place
|
|
22
|
+
no runner reads; they are checked now, and the file blocks with the reason.
|
|
23
|
+
|
|
24
|
+
**"Byte-equivalent" was witnessed by comparing two of ten fields.**
|
|
25
|
+
`v2-run-fork-prefix` compared `${sequence}:${type}`, so a fork could inherit a
|
|
26
|
+
prefix whose payloads differed in every field and pass. It now compares `type`,
|
|
27
|
+
`nodeId` and `payload`, excluding `eventId`/`runId`/`timestamp`/`causationId` —
|
|
28
|
+
using **`runs.md` §Diff and ancestry's** exclusion set rather than one invented
|
|
29
|
+
for the leg. `schemaVersion`, `engineVersion` and the §37 snapshot claim are
|
|
30
|
+
recorded as named residue, unasserted, with the reason. Floor membership
|
|
31
|
+
unchanged: still RULED OUT.
|
|
32
|
+
|
|
33
|
+
**A v3 bundle's `certified: true` was uncheckable by its recipient.** v2 bundles
|
|
34
|
+
carried `discovery.document` and the verifier re-derived every claimed profile
|
|
35
|
+
from it (RFC 0148 §B(1)); v3 dropped the field and the check with it. Optional
|
|
36
|
+
`discovery.document` returns: the digest is re-derived first (the signature
|
|
37
|
+
covers `sha256`, not the document, so a swap would otherwise verify), then every
|
|
38
|
+
certified profile is re-derived, and absence is surfaced as
|
|
39
|
+
`derivabilityChecked: false` rather than swallowed. Sabotage-proved.
|
|
40
|
+
|
|
41
|
+
**A requirement's id depended on whether it passed.** The registry generator
|
|
42
|
+
read `req()`'s first argument only as a string literal, so `const ID = …`
|
|
43
|
+
recorded `explicitId: null` and the row fell back to a title-derived slug —
|
|
44
|
+
`v2-run-fork-prefix` is in the evidence tree under two ids, the explicit one
|
|
45
|
+
where the assertion ran and the slug where the leg was `inapplicable`. A
|
|
46
|
+
verifier asking whether a bundle carries a requirement got a well-formed NO from
|
|
47
|
+
a host that had merely not held the profile. 2058 explicit ids became 2106.
|
|
48
|
+
|
|
49
|
+
**`memory-attribution-replay-stable` is `majors: [1, 2]`** (was `[1]`). Its rule
|
|
50
|
+
is `replay.md` §Determinism caveat 5 in both majors, word for word. What held it
|
|
51
|
+
back was a gate returning early **unrecorded** and three hard-coded `/v1/` paths
|
|
52
|
+
that are not seams. Both are properties of the instrument. First row of the
|
|
53
|
+
445-file backfill.
|
|
54
|
+
|
|
55
|
+
**A rule you cannot check is not a weaker rule; it is a rule that is not there.**
|
|
56
|
+
|
|
3
57
|
## [2.0.4] — 2026-09-06 — a fixture that punished a host for obeying the rule the scenario checks
|
|
4
58
|
|
|
5
59
|
`v2-provider-conflict` drove `connection-pack-github`. On a host shipping a built-in `github`, RFC 0177 §D.1 requires refusing the later registration — so the fixture never installed and the qualified-form leg recorded **`blocked`** permanently, on a host whose only fault was obeying the rule under test. A production host carried that row across a dozen cuts; any blocked row denies certification (RFC 0168 §E.1).
|
package/dist/cli.js
CHANGED
|
@@ -653,7 +653,11 @@ async function runCertify(args, baseUrl, apiKey) {
|
|
|
653
653
|
generatedAt: new Date().toISOString(),
|
|
654
654
|
suite: { name: '@openwop/openwop-conformance', version, targetMajor: target.major, specArtifactsVersion: lock?.version ?? 'repo-layout', ...(lock ? { stampSha256: lock.stampSha256 } : {}) },
|
|
655
655
|
host: { name: host.name, version: host.version, ...(host.vendor ? { vendor: host.vendor } : {}), build, signingKeyId: keyId, ...(relaxations && relaxations.length ? { relaxations } : {}) },
|
|
656
|
-
|
|
656
|
+
// `document` is what makes `claimedProfiles[].certified` checkable by
|
|
657
|
+
// someone other than this process (RFC 0148 §B(1)); v2 carried it and v3
|
|
658
|
+
// dropped it. `sha256` is a digest of `canonicalJSON(document)`, so the
|
|
659
|
+
// two are consistent by construction and the verifier re-derives it.
|
|
660
|
+
discovery: { url: discoveryUrl, sha256, protocolVersions, preferredVersion, document },
|
|
657
661
|
claimedProfiles: claimed3,
|
|
658
662
|
results: { totals: totals3, requirements: rows3 },
|
|
659
663
|
witnessSha256: witnessDigest(rows3),
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
* in cli.ts) and pure: it never reads the environment.
|
|
19
19
|
*/
|
|
20
20
|
import { createHash, createPrivateKey, createPublicKey, sign as edSign, verify as edVerify } from 'node:crypto';
|
|
21
|
+
import { profileDerivable } from './profiles.js';
|
|
21
22
|
export const SIGNATURE_OVER = ['witnessSha256', 'host.build', 'suite.version', 'discovery.sha256'];
|
|
22
23
|
/** Deterministic JSON: keys sorted at every level, no whitespace. */
|
|
23
24
|
export function canonicalJSON(value) {
|
|
@@ -125,6 +126,33 @@ export function verifyBundleV3(bundle, opts = {}) {
|
|
|
125
126
|
}
|
|
126
127
|
if (expected.blocked > 0 && certifiedProfiles.length > 0)
|
|
127
128
|
rejections.push({ kind: 'blocked-certified', detail: `${expected.blocked} blocked row(s): a bundle with blocked > 0 does not certify (RFC 0168 §E.1)` });
|
|
129
|
+
// Derivability, restored. RFC 0148 §B(1): a profile certifies only if it is
|
|
130
|
+
// DERIVABLE from what the host advertised. `verifyBundleV2` checked exactly
|
|
131
|
+
// that against `discovery.document`; v3 stopped carrying the document and the
|
|
132
|
+
// check went with it, leaving `certified: true` a claim only its emitter
|
|
133
|
+
// could evaluate. When the document is present the check runs again — and it
|
|
134
|
+
// runs on the SAME bytes the signature covers, because `discovery.sha256` is
|
|
135
|
+
// a digest of `canonicalJSON(document)` and is re-derived here first. A
|
|
136
|
+
// document that does not hash to the signed digest is a substituted
|
|
137
|
+
// document, and rejecting it is the whole point of checking.
|
|
138
|
+
const document = bundle.discovery?.document;
|
|
139
|
+
let derivabilityChecked = false;
|
|
140
|
+
if (document !== undefined) {
|
|
141
|
+
const digest = createHash('sha256').update(canonicalJSON(document)).digest('hex');
|
|
142
|
+
if (digest !== bundle.discovery?.sha256) {
|
|
143
|
+
rejections.push({ kind: 'discovery-digest', detail: `discovery.document hashes to ${digest.slice(0, 12)} but discovery.sha256 is ${String(bundle.discovery?.sha256).slice(0, 12)} — the captured document is not the one the signature attests to` });
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
derivabilityChecked = true;
|
|
147
|
+
for (const p of bundle.claimedProfiles ?? []) {
|
|
148
|
+
if (!p.certified)
|
|
149
|
+
continue;
|
|
150
|
+
if (!profileDerivable(document, p.id)) {
|
|
151
|
+
rejections.push({ kind: 'profile-not-derivable', profile: p.id, detail: `${p.id} is marked certified, but the captured discovery document does not derive it (RFC 0148 §B(1)) — evidence cannot certify a profile the host does not advertise` });
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
128
156
|
// RFC 0168 §E.2: the verifier REFUSES, it does not warn — but a refusal is
|
|
129
157
|
// scoped to what it names. A rejection carrying a `profile` removes that
|
|
130
158
|
// profile only (a relaxation on one obligation does not poison an unrelated
|
|
@@ -138,5 +166,6 @@ export function verifyBundleV3(bundle, opts = {}) {
|
|
|
138
166
|
signatureVerified,
|
|
139
167
|
verifierSignatureVerified,
|
|
140
168
|
certifiedProfiles: bundleWide.length > 0 ? [] : certifiedProfiles.filter((p) => !scoped.has(p)),
|
|
169
|
+
derivabilityChecked,
|
|
141
170
|
};
|
|
142
171
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openwop/openwop-conformance",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.5",
|
|
4
4
|
"description": "Production-ready black-box conformance suite for OpenWOP v1.0 compliant servers.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -56,6 +56,6 @@
|
|
|
56
56
|
"@openwop/spec-artifacts": "file:../spec-artifacts"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
|
-
"@openwop/spec-artifacts": "2.0.
|
|
59
|
+
"@openwop/spec-artifacts": "2.0.5"
|
|
60
60
|
}
|
|
61
61
|
}
|
package/requirement-aliases.json
CHANGED
|
@@ -1,7 +1,172 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$comment": "old id → new id. Add a row when a test title is reworded so bundles citing the old id still resolve.",
|
|
2
|
+
"$comment": "old id → new id. Add a row when a test title is reworded so bundles citing the old id still resolve. Suite 2.0.5 added 165 rows for a SECOND cause: the registry generator now resolves module-level const bindings, so a leg that soft-skips is labelled by its explicit requirement id instead of the title-derived slug it used to fall back to. The label moved without any title changing, and the generator --check cannot see it (it compares the record id, which did not move) — 11 rows across the three committed host bundles cited slugs the 2.0.5 suite no longer mints.",
|
|
3
3
|
"aliases": {
|
|
4
4
|
"openwop.it.v2-run-cancel.cancelling-a-terminal-run-answers-409-run-terminal-or-200-idempotently-the-prose": "openwop.it.v2-run-cancel.cancelling-a-terminal-run-is-refused-409-run-terminal",
|
|
5
|
-
"openwop.it.pause-resume.pause-on-an-already-paused-run-is-a-no-op-200-202-idempotent": "openwop.it.pause-resume.pause-on-an-already-paused-run-returns-409-with-details-runstatus-paused-unless"
|
|
5
|
+
"openwop.it.pause-resume.pause-on-an-already-paused-run-is-a-no-op-200-202-idempotent": "openwop.it.pause-resume.pause-on-an-already-paused-run-returns-409-with-details-runstatus-paused-unless",
|
|
6
|
+
"openwop.it.era-key-stamped-v1.a-run-the-host-just-created-carries-eventlogschemaversion": "openwop.requirement.version-negotiation.era-key-stamped",
|
|
7
|
+
"openwop.it.era-key-stamped-v1.a-freshly-created-run-is-not-classified-legacy-by-the-host-s-own-rule": "openwop.requirement.version-negotiation.era-key-not-legacy",
|
|
8
|
+
"openwop.it.era-key-stamped-v1.a-run-the-host-just-created-carries-engineversion-the-legacy-escape-cannot-reach": "openwop.requirement.version-negotiation.engine-version-stamped",
|
|
9
|
+
"openwop.it.v2-advertised-fixtures-exist.a-sampled-advertised-fixture-is-actually-creatable-not-just-listed": "openwop.requirement.0168.advertised-fixtures-exist",
|
|
10
|
+
"openwop.it.v2-advertised-path-space-served.a-host-advertising-major-2-reaches-the-surfaces-it-already-serves-under-v1": "openwop.requirement.0172.advertised-path-space-served",
|
|
11
|
+
"openwop.it.v2-approver-enforced.a-resolver-outside-approverslist-is-refused-at-resolve-time": "openwop.requirement.0173.approver-enforced",
|
|
12
|
+
"openwop.it.v2-assurance-downgrade-audited.an-identity-below-the-lane-floor-is-refused-with-sender-constraint-missing": "openwop.requirement.0170.assurance-downgrade-audited.refused",
|
|
13
|
+
"openwop.it.v2-assurance-downgrade-audited.a-resolved-identity-records-the-assurance-actually-used-never-a-downgraded-beare": "openwop.requirement.0170.assurance-downgrade-audited.audited",
|
|
14
|
+
"openwop.it.v2-bundle-v3-signed.a-signed-v3-bundle-validates-against-the-closed-root-schema-an-extra-root-key-is": "openwop.requirement.0168.bundle-v3-signed.schema-closed-root",
|
|
15
|
+
"openwop.it.v2-bundle-v3-signed.the-attestation-verifies-under-the-host-key-and-a-flipped-witnesssha256-is-refus": "openwop.requirement.0168.bundle-v3-signed.witness-digest",
|
|
16
|
+
"openwop.it.v2-bundle-v3-signed.an-independent-claim-self-signed-under-the-host-key-is-refused-a-distinct-verifi": "openwop.requirement.0168.bundle-v3-signed.independent-self-signed",
|
|
17
|
+
"openwop.it.v2-capabilities-root-closed.the-host-document-validates-against-capabilities-schema-json": "openwop.requirement.0169.capabilities-root-closed.valid",
|
|
18
|
+
"openwop.it.v2-capabilities-root-closed.an-unknown-root-key-fails-validation": "openwop.requirement.0169.capabilities-root-closed.unknown-root-key",
|
|
19
|
+
"openwop.it.v2-capabilities-root-closed.a-dotted-mirror-key-fails-validation": "openwop.requirement.0169.capabilities-root-closed.dotted-key",
|
|
20
|
+
"openwop.it.v2-capabilities-root-closed.the-v1-capabilities-wrapper-fails-validation": "openwop.requirement.0169.capabilities-root-closed.wrapper",
|
|
21
|
+
"openwop.it.v2-capabilities-root-closed.a-root-profiles-fails-validation": "openwop.requirement.0169.capabilities-root-closed.profiles",
|
|
22
|
+
"openwop.it.v2-capability-record-shape.every-family-record-carries-status-since-and-witness-from-the-wire-legal-sets": "openwop.requirement.0169.capability-record-shape.required-fields",
|
|
23
|
+
"openwop.it.v2-capability-record-shape.until-is-present-iff-the-record-is-experimental-or-deprecated": "openwop.requirement.0169.capability-record-shape.until-iff-not-stable",
|
|
24
|
+
"openwop.it.v2-capability-record-shape.no-advertised-record-carries-an-until-already-in-the-past": "openwop.requirement.0169.capability-record-shape.until-not-past",
|
|
25
|
+
"openwop.it.v2-chain-pin-exact.a-chain-reference-carrying-a-range-core-ai-callprompt-1-is-refused-at-register": "openwop.requirement.0177.chain-pin-exact.range-refused",
|
|
26
|
+
"openwop.it.v2-chain-pin-exact.a-chain-reference-pinning-an-exact-version-core-ai-callprompt-1-0-0-registers": "openwop.requirement.0177.chain-pin-exact.exact-accepted",
|
|
27
|
+
"openwop.it.v2-coherence-not-in-bundle.every-corpus-ledger-id-has-a-scenario-in-src-coherence-and-none-in-src-scenarios": "openwop.requirement.0168.coherence-not-in-bundle.disjoint-by-construction",
|
|
28
|
+
"openwop.it.v2-coherence-not-in-bundle.the-bundle-schema-rejects-a-v3-bundle-carrying-a-corpus-coherence-id-and-accepts": "openwop.requirement.0168.coherence-not-in-bundle.schema-forbids-coherence-ids",
|
|
29
|
+
"openwop.it.v2-compensation-read-projection.get-runs-runid-compensation-on-a-fresh-run-validates-with-status-none": "openwop.requirement.0173.compensation-read-projection",
|
|
30
|
+
"openwop.it.v2-compensation-read-projection.an-unknown-run-projects-404-not-found-through-the-canonical-envelope": "openwop.requirement.0173.compensation-read-projection.not-found",
|
|
31
|
+
"openwop.it.v2-configurable-closed.the-standalone-schema-rejects-a-dotted-key-and-an-unknown-root-key-and-accepts-t": "openwop.requirement.0171.configurable-closed.schema",
|
|
32
|
+
"openwop.it.v2-configurable-closed.post-runs-rejects-a-dotted-key-with-400-validation-error": "openwop.requirement.0171.configurable-closed.dotted-key",
|
|
33
|
+
"openwop.it.v2-configurable-closed.post-runs-rejects-an-unknown-root-key-with-400-validation-error": "openwop.requirement.0171.configurable-closed.unknown-key",
|
|
34
|
+
"openwop.it.v2-created-run-readable.a-run-created-at-this-base-is-readable-and-pollable-at-this-base-by-the-id-it-re": "openwop.requirement.0172.created-run-readable",
|
|
35
|
+
"openwop.it.v2-dual-stack-negotiation.a-run-created-through-v1-runs-with-no-header-is-readable-through-runs-under-open": "openwop.requirement.0172.dual-stack-negotiation.cross-major-read",
|
|
36
|
+
"openwop.it.v2-dual-stack-negotiation.an-unlisted-major-is-406-protocol-version-unsupported-with-details-protocolversi": "openwop.requirement.0172.dual-stack-negotiation.unlisted-major",
|
|
37
|
+
"openwop.it.v2-dual-stack-negotiation.openwop-version-2-0-on-a-v1-path-is-400-protocol-version-mismatch": "openwop.requirement.0172.dual-stack-negotiation.v1-path-mismatch",
|
|
38
|
+
"openwop.it.v2-dual-stack-negotiation.every-response-reports-the-contract-that-produced-it": "openwop.requirement.0172.dual-stack-negotiation.response-header",
|
|
39
|
+
"openwop.it.v2-effect-identity-business-key.get-runs-runid-effects-validates-and-every-row-is-keyed-on-business-identity-or": "openwop.requirement.0173.effect-identity-business-key",
|
|
40
|
+
"openwop.it.v2-effect-identity-business-key.the-same-provider-key-is-presented-across-two-transport-retries": "openwop.requirement.0173.effect-identity-business-key.retry",
|
|
41
|
+
"openwop.it.v2-effect-seam-manifest.get-host-effect-seams-validates-and-every-row-is-guarded": "openwop.requirement.0173.effect-seam-manifest",
|
|
42
|
+
"openwop.it.v2-effect-seam-manifest.the-replay-facet-names-the-manifest-address-as-the-constant-host-effect-seams": "openwop.requirement.0173.effect-seam-manifest.facet",
|
|
43
|
+
"openwop.it.v2-effect-seam-no-refire.driving-one-seam-of-each-kind-observes-no-re-fire-on-replay": "openwop.requirement.0173.effect-seam-no-refire",
|
|
44
|
+
"openwop.it.v2-enum-growth-rule.the-envelope-accepts-a-registered-but-unknown-to-this-suite-vendor-member": "openwop.requirement.0171.enum-growth-rule.unknown-member-accepted",
|
|
45
|
+
"openwop.it.v2-enum-growth-rule.the-reserved-prefix-and-a-malformed-member-are-rejected": "openwop.requirement.0171.enum-growth-rule.reserved-rejected",
|
|
46
|
+
"openwop.it.v2-era-2-append-vocabulary.a-host-append-to-an-open-era-2-run-keeps-the-log-in-v1-vocabulary-so-the-whole-l": "openwop.requirement.0176.era-2-append-vocabulary",
|
|
47
|
+
"openwop.it.v2-era-2-append-vocabulary.the-run-keeps-the-era-it-was-created-with-an-append-does-not-promote-it-to-era-3": "openwop.requirement.0176.era-2-append-vocabulary",
|
|
48
|
+
"openwop.it.v2-era-key.a-run-created-now-carries-eventlogschemaversion-3-on-its-snapshot": "openwop.requirement.0176.era-key",
|
|
49
|
+
"openwop.it.v2-era-key.discovery-advertises-the-value-the-host-writes-for-new-runs-and-nothing-else": "openwop.requirement.0176.era-key.discovery",
|
|
50
|
+
"openwop.it.v2-era-stamp-universal.discovery-advertises-an-era-the-host-actually-writes-and-a-new-run-carries-it": "openwop.requirement.0176.era-stamp-universal",
|
|
51
|
+
"openwop.it.v2-era-stamp-universal.a-v2-era-host-stamps-3-so-its-new-runs-are-never-read-as-the-v1-era": "openwop.requirement.0176.era-stamp-universal",
|
|
52
|
+
"openwop.it.v2-error-registry.an-error-response-is-the-closed-envelope-with-a-registered-code-at-its-registere": "openwop.requirement.0171.error-registry.envelope",
|
|
53
|
+
"openwop.it.v2-error-registry.retry-timing-is-never-spelled-inside-details": "openwop.requirement.0171.error-registry.no-retry-details",
|
|
54
|
+
"openwop.it.v2-error-registry.a-429-rate-limited-response-carries-retry-after": "openwop.requirement.0171.error-registry.retry-after",
|
|
55
|
+
"openwop.it.v2-event-type-closed.every-emitted-type-is-a-registered-protocol-type-or-a-vendor-type-under-an-adver": "openwop.requirement.0171.event-type-closed.type",
|
|
56
|
+
"openwop.it.v2-event-type-closed.every-emitted-event-validates-as-a-runeventdoc": "openwop.requirement.0171.event-type-closed.envelope",
|
|
57
|
+
"openwop.it.v2-fork-a-v1-run.the-fork-of-an-era-2-run-is-accepted-and-its-prefix-is-byte-equivalent-to-the-tr": "openwop.requirement.0176.fork-a-v1-run.prefix",
|
|
58
|
+
"openwop.it.v2-fork-a-v1-run.run-started-on-the-fork-carries-the-legacy-subject-where-the-parent-had-none": "openwop.requirement.0176.fork-a-v1-run.legacy-subject",
|
|
59
|
+
"openwop.it.v2-form-when-reuses-edge-conditions.a-field-when-is-the-edge-condition-grammar-type-left-right-and-no-other-expressi": "openwop.requirement.0177.form-when-reuses-edge-conditions",
|
|
60
|
+
"openwop.it.v2-header-scheme.no-removed-header-family-appears-on-any-response": "openwop.requirement.0171.header-scheme.no-legacy-headers",
|
|
61
|
+
"openwop.it.v2-header-scheme.openwop-version-names-the-contract-on-every-response": "openwop.requirement.0171.header-scheme.version-on-every-response",
|
|
62
|
+
"openwop.it.v2-id-grammar.every-id-on-the-run-snapshot-matches-its-ids-schema-json-kind": "openwop.requirement.0170.id-grammar.snapshot",
|
|
63
|
+
"openwop.it.v2-id-grammar.every-id-on-the-run-events-matches-its-ids-schema-json-kind": "openwop.requirement.0170.id-grammar.events",
|
|
64
|
+
"openwop.it.v2-id-grammar.a-run-id-whose-tenant-segment-is-not-the-caller-s-is-refused": "openwop.requirement.0170.id-grammar.tenant-binding",
|
|
65
|
+
"openwop.it.v2-idempotency-key-grammar.a-22-character-key-inside-the-grammar-is-accepted": "openwop.requirement.0170.idempotency-key-grammar.valid-accepted",
|
|
66
|
+
"openwop.it.v2-idempotency-key-grammar.a-key-outside-the-grammar-is-refused-with-400-idempotency-key-invalid": "openwop.requirement.0170.idempotency-key-grammar.invalid-refused",
|
|
67
|
+
"openwop.it.v2-interrupt-token-scheme.a-token-without-the-ow2-prefix-is-refused": "openwop.requirement.0170.interrupt-token-scheme.unprefixed-refused",
|
|
68
|
+
"openwop.it.v2-interrupt-token-scheme.a-well-formed-token-under-a-kid-the-host-does-not-hold-is-401-interrupt-token-in": "openwop.requirement.0170.interrupt-token-scheme.unheld-kid-refused",
|
|
69
|
+
"openwop.it.v2-lane-issuer-advertised.every-auth-lanes-member-names-lane-issuers-revocation-and-minimumassurance": "openwop.requirement.0170.lane-issuer-advertised.members",
|
|
70
|
+
"openwop.it.v2-lane-issuer-advertised.a-windowed-revocation-rule-advertises-revocationwindowseconds": "openwop.requirement.0170.lane-issuer-advertised.window",
|
|
71
|
+
"openwop.it.v2-legacy-profiles-absent.no-legacy-id-appears-in-a2a-profiles-or-mcp-profiles-and-each-id-matches-its-fac": "openwop.requirement.0175.legacy-profiles-absent",
|
|
72
|
+
"openwop.it.v2-legacy-profiles-absent.no-root-profiles-exists-in-the-v2-representation": "openwop.requirement.0175.legacy-profiles-absent.no-root-profiles",
|
|
73
|
+
"openwop.it.v2-manifest-ceiling-refused.an-engines-openwop-range-with-no-upper-bound-1-0-0-reads-2-0-0-and-is-refused-at": "openwop.requirement.0177.manifest-ceiling-refused.unbounded",
|
|
74
|
+
"openwop.it.v2-manifest-ceiling-refused.a-v1-ceiling-1-0-0-2-0-0-is-refused-at-install-with-pack-engine-unsupported": "openwop.requirement.0177.manifest-ceiling-refused.v1-ceiling",
|
|
75
|
+
"openwop.it.v2-manifest-ceiling-refused.a-range-admitting-the-host-major-2-0-0-3-0-0-installs": "openwop.requirement.0177.manifest-ceiling-refused.v2-installs",
|
|
76
|
+
"openwop.it.v2-manifest-hatch-carried.an-x-field-inside-agents-0-of-a-node-pack-is-ignored-not-rejected-the-pack-insta": "openwop.requirement.0177.manifest-hatch-carried.agents-x-field",
|
|
77
|
+
"openwop.it.v2-manifest-hatch-carried.an-x-field-inside-a-prompt-template-of-a-prompt-pack-is-ignored-not-rejected-the": "openwop.requirement.0177.manifest-hatch-carried.prompt-template-x-field",
|
|
78
|
+
"openwop.it.v2-min-client-version.a-client-below-minclientversion-is-refused-with-426-client-version-unsupported": "openwop.requirement.0172.min-client-version",
|
|
79
|
+
"openwop.it.v2-minimum-version-refused.an-a2a-peer-offering-only-a-version-below-minimumversion-is-refused": "openwop.requirement.0175.minimum-version-refused",
|
|
80
|
+
"openwop.it.v2-minimum-version-refused.an-mcp-server-offering-only-a-revision-below-minimumrevision-is-refused": "openwop.requirement.0175.minimum-version-refused.mcp",
|
|
81
|
+
"openwop.it.v2-mrtr-rounds-ceiling.mcp-mrtr-maxrounds-is-an-integer-ceiling-in-1-16": "openwop.requirement.0175.mrtr-rounds-ceiling",
|
|
82
|
+
"openwop.it.v2-mrtr-rounds-ceiling.round-maxrounds-1-is-refused-with-mcp-mrtr-rounds-exceeded": "openwop.requirement.0175.mrtr-rounds-ceiling.refused",
|
|
83
|
+
"openwop.it.v2-no-transport-advertisement.the-v2-root-carries-no-supportedtransports-and-no-grpc-block": "openwop.requirement.0175.no-transport-advertisement",
|
|
84
|
+
"openwop.it.v2-owner-subject-required.owner-subject-is-present-and-validates-against-subject-schema-json": "openwop.requirement.0170.owner-subject-required.subject",
|
|
85
|
+
"openwop.it.v2-owner-subject-required.owner-carries-no-principal-principalkind": "openwop.requirement.0170.owner-subject-required.no-principal",
|
|
86
|
+
"openwop.it.v2-pack-isolation.sandbox-isolationmodel-names-a-real-mechanism-never-node-vm": "openwop.requirement.0173.pack-isolation",
|
|
87
|
+
"openwop.it.v2-pack-isolation.node-pack-sandbox-timeout-exceeding-wallclocklimitms-fails-with-sandbox-timeout": "openwop.requirement.0173.pack-isolation.timeout",
|
|
88
|
+
"openwop.it.v2-pack-isolation.node-pack-sandbox-memory-cap-exceeding-memorylimitbytes-fails-with-sandbox-memor": "openwop.requirement.0173.pack-isolation.memory-cap",
|
|
89
|
+
"openwop.it.v2-pack-isolation.node-pack-sandbox-isolated-context-a-pack-cannot-mutate-state-another-invocation": "openwop.requirement.0173.pack-isolation.isolated-context",
|
|
90
|
+
"openwop.it.v2-payload-registry-closed.every-registered-event-carries-a-payload-that-validates-against-its-typeindex-en": "openwop.requirement.0171.payload-registry-closed",
|
|
91
|
+
"openwop.it.v2-peer-dependency-declared.a-peerdependencies-key-the-declaration-file-does-not-name-is-refused-with-pack-p": "openwop.requirement.0177.peer-dependency-declared.undefined-key",
|
|
92
|
+
"openwop.it.v2-peer-dependency-declared.an-alias-table-row-host-fs-fs-resolves-through-the-overlap-and-the-pack-installs": "openwop.requirement.0177.peer-dependency-declared.alias-overlap",
|
|
93
|
+
"openwop.it.v2-pinned-run-disposition.a-pin-naming-a-change-id-the-host-does-not-implement-is-cancelled-with-v1-pin-un": "openwop.requirement.0176.pinned-run-disposition.cancelled",
|
|
94
|
+
"openwop.it.v2-pinned-run-disposition.a-pin-naming-a-change-id-the-host-still-implements-continues-under-the-reader-ru": "openwop.requirement.0176.pinned-run-disposition.continued",
|
|
95
|
+
"openwop.it.v2-poll-cursor-v2.the-response-is-the-closed-runid-events-lastsequence-status-isterminal": "openwop.requirement.0171.poll-cursor-v2.shape",
|
|
96
|
+
"openwop.it.v2-poll-cursor-v2.omitting-the-cursor-returns-from-the-first-event-sequence-0": "openwop.requirement.0171.poll-cursor-v2.from-first",
|
|
97
|
+
"openwop.it.v2-poll-cursor-v2.aftersequence-n-returns-only-events-with-sequence-n": "openwop.requirement.0171.poll-cursor-v2.after-sequence",
|
|
98
|
+
"openwop.it.v2-poll-cursor-v2.a-cursor-past-the-end-of-the-log-returns-200-with-an-empty-events-array": "openwop.requirement.0171.poll-cursor-v2.past-end",
|
|
99
|
+
"openwop.it.v2-preferred-version-default.preferredversion-is-a-member-of-protocolversions": "openwop.requirement.0172.preferred-version-default.member",
|
|
100
|
+
"openwop.it.v2-preferred-version-default.a-header-less-get-well-known-openwop-is-the-preferredversion-representation": "openwop.requirement.0172.preferred-version-default.headerless",
|
|
101
|
+
"openwop.it.v2-preferred-version-default.through-the-overlap-preferredversion-names-a-1-x-member": "openwop.requirement.0172.preferred-version-default.overlap",
|
|
102
|
+
"openwop.it.v2-profiles-derived-only.the-v2-document-carries-no-root-profiles": "openwop.requirement.0169.profiles-derived-only.no-root-profiles",
|
|
103
|
+
"openwop.it.v2-profiles-derived-only.every-registry-profile-is-derivable-from-the-document-the-discovery-core-predica": "openwop.requirement.0169.profiles-derived-only.derivable",
|
|
104
|
+
"openwop.it.v2-provider-conflict.two-definitions-of-one-bare-provider-id-fail-closed-the-later-registration-is-re": "openwop.requirement.0177.provider-conflict.fail-closed",
|
|
105
|
+
"openwop.it.v2-provider-conflict.the-qualified-form-packname-acme-widgets-resolves-to-the-named-pack-s-definition": "openwop.requirement.0177.provider-conflict.qualified-form",
|
|
106
|
+
"openwop.it.v2-refresh-sla.refreshedat-on-each-embedded-protocol-facet-is-within-90-days-of-now": "openwop.requirement.0175.refresh-sla",
|
|
107
|
+
"openwop.it.v2-relaxation-recorded.a-bundle-recording-a-relaxation-cannot-certify-the-relaxed-profile": "openwop.requirement.0173.relaxation-recorded",
|
|
108
|
+
"openwop.it.v2-relaxation-recorded.durability-is-a-closed-set-session-deployment-persisted": "openwop.requirement.0173.relaxation-recorded.durability-closed",
|
|
109
|
+
"openwop.it.v2-revocation-honored.a-revoked-next-request-credential-is-refused-on-the-next-request-with-credential": "openwop.requirement.0170.revocation-honored",
|
|
110
|
+
"openwop.it.v2-run-annotation-not-event.an-annotation-is-created-and-listed-and-never-enters-the-run-s-event-log": "openwop.requirement.0170.run-annotation-not-event",
|
|
111
|
+
"openwop.it.v2-run-bulk-cancel.101-ids-are-refused-400-validation-error-with-details-maxrunids": "openwop.requirement.0170.run-bulk-cancel",
|
|
112
|
+
"openwop.it.v2-run-bulk-cancel.results-come-back-in-request-order-each-id-processed-independently-a-foreign-id": "openwop.requirement.0170.run-bulk-cancel",
|
|
113
|
+
"openwop.it.v2-run-cancel.cancelling-a-terminal-run-is-refused-409-run-terminal": "openwop.requirement.0170.run-cancel",
|
|
114
|
+
"openwop.it.v2-run-cancel.cancelling-a-running-run-answers-200-with-cancelling-cancelled-emits-run-cancell": "openwop.requirement.0170.run-cancel",
|
|
115
|
+
"openwop.it.v2-run-completed-outputs.the-run-completed-event-of-a-run-that-completed-carries-an-outputs-object": "openwop.requirement.0171.run-completed-outputs",
|
|
116
|
+
"openwop.it.v2-run-diff-identical.two-identical-logs-diff-to-divergedatseq-null-and-empty-eventdiffs-in-a-response": "openwop.requirement.0170.run-diff-identical",
|
|
117
|
+
"openwop.it.v2-run-fork-prefix.a-replay-fork-inherits-exactly-0-fromseq-the-event-at-fromseq-is-re-executed-nev": "openwop.requirement.0170.fork-prefix-boundary",
|
|
118
|
+
"openwop.it.v2-run-fork-refusals.replay-overlay-400-a-fromseq-outside-the-log-422-fork-point-invalid-a-valid-repl": "openwop.requirement.0170.run-fork-refusals",
|
|
119
|
+
"openwop.it.v2-run-options-limits.odd-format-tags-and-free-form-metadata-are-accepted-and-surface-unchanged-on-the": "openwop.requirement.0171.run-options-limits",
|
|
120
|
+
"openwop.it.v2-run-pause-resume.pause-and-resume-on-a-terminal-run-answer-409-with-an-error-envelope": "openwop.requirement.0170.run-pause-resume",
|
|
121
|
+
"openwop.it.v2-run-pause-resume.a-running-run-pauses-202-paused-refuses-a-second-pause-409-resumes-202-running-a": "openwop.requirement.0170.run-pause-resume",
|
|
122
|
+
"openwop.it.v2-run-snapshot-etag.a-matching-if-none-match-receives-304-with-no-body-and-the-version-header-a-non": "openwop.requirement.0170.run-snapshot-etag",
|
|
123
|
+
"openwop.it.v2-sse-last-event-id.last-event-id-resumes-at-the-next-sequence-never-re-emits-the-resumption-point-l": "openwop.requirement.0171.sse-last-event-id",
|
|
124
|
+
"openwop.it.v2-stream-mode-refusal.a-value-outside-the-pattern-a-forbidden-combination-and-an-unimplemented-mode-ar": "openwop.requirement.0171.stream-mode-refusal",
|
|
125
|
+
"openwop.it.v2-stream-mode-refusal.updates-streams-200-text-event-stream-with-frames-bufferms-yields-at-least-one-b": "openwop.requirement.0171.stream-mode-refusal",
|
|
126
|
+
"openwop.it.v2-stream-sse-projection.every-data-frame-on-the-major-2-stream-carries-the-tenant-bound-runid-of-the-run": "openwop.requirement.0171.stream-sse-projection",
|
|
127
|
+
"openwop.it.v2-subject-link-record.the-link-formed-across-scim-and-saml-is-a-closed-subjectlink-record": "openwop.requirement.0170.subject-link-record.shape",
|
|
128
|
+
"openwop.it.v2-subject-link-record.deactivation-sets-deniedat-and-the-saml-decision-path-consults-it": "openwop.requirement.0170.subject-link-record.denied-at",
|
|
129
|
+
"openwop.it.v2-unmapped-type-refused.poll-over-a-log-with-an-unmapped-unprefixed-type-fails-with-500-event-type-unmap": "openwop.requirement.0176.unmapped-type-refused",
|
|
130
|
+
"openwop.it.v2-unmapped-type-refused.a-registered-vendor-type-the-codemap-does-not-name-is-read-under-its-own-name-un": "openwop.requirement.0176.vendor-type-passthrough",
|
|
131
|
+
"openwop.it.v2-unmapped-type-refused.a-fork-of-the-same-log-is-refused-for-the-same-reason-the-rule-binds-every-reade": "openwop.requirement.0176.unmapped-type-refused.fork",
|
|
132
|
+
"openwop.it.v2-v1-events-translated.poll-reads-an-era-2-log-with-v2-type-names-and-sequence-0-present": "openwop.requirement.0176.v1-events-translated.poll",
|
|
133
|
+
"openwop.it.v2-v1-events-translated.sse-reads-the-same-era-2-log-with-v2-type-names": "openwop.requirement.0176.v1-events-translated.sse",
|
|
134
|
+
"openwop.it.v2-v1-events-translated.a-fork-of-the-era-2-run-reads-its-inherited-prefix-with-v2-type-names": "openwop.requirement.0176.v1-events-translated.fork",
|
|
135
|
+
"openwop.it.v2-v1-signed-webhook-accepted.the-webhooks-facet-lists-scheme-v1-the-scheme-a-v1-signed-delivery-is-verified-u": "openwop.requirement.0176.v1-signed-webhook-accepted.facet",
|
|
136
|
+
"openwop.it.v2-v1-signed-webhook-accepted.the-host-s-v2-receiver-path-accepts-an-x-openwop-only-scheme-v1-delivery-and-ref": "openwop.requirement.0176.v1-signed-webhook-accepted",
|
|
137
|
+
"openwop.it.v2-version-header-honored.openwop-version-is-honored-or-refused-never-ignored": "openwop.requirement.0172.version-header-honored",
|
|
138
|
+
"openwop.it.v2-version-header-honored.a-host-advertising-two-majors-serves-two-different-representations": "openwop.requirement.0172.version-header-honored",
|
|
139
|
+
"openwop.it.v2-webhook-durable-delivery.a-failed-attempt-is-retried-and-the-event-is-delivered-at-least-once": "openwop.requirement.0173.webhook-durable-delivery",
|
|
140
|
+
"openwop.it.v2-webhook-durable-delivery.an-exhausted-delivery-is-dead-lettered-never-dropped": "openwop.requirement.0173.webhook-durable-delivery.dead-letter",
|
|
141
|
+
"openwop.it.v2-well-known-one-resource.a-header-less-get-and-an-openwop-version-2-0-get-are-two-representations-of-one": "openwop.requirement.0176.well-known-one-resource",
|
|
142
|
+
"openwop.it.v2-well-known-one-resource.the-v2-representation-carries-no-capabilities-wrapper-no-dotted-host-key-no-prof": "openwop.requirement.0176.well-known-one-resource.v2-representation",
|
|
143
|
+
"openwop.it.v2-alias-covers-reword.the-corpus-gate-script-exits-0": "openwop.requirement.0168.alias-covers-reword",
|
|
144
|
+
"openwop.it.v2-bundle-signature-attributable.the-v2-discovery-root-publishes-signingkeys-the-surface-the-rfc-named": "openwop.requirement.0168.bundle-signature-attributable.surface",
|
|
145
|
+
"openwop.it.v2-bundle-signature-attributable.the-front-door-gate-verifies-the-attestation-instead-of-inspecting-the-string": "openwop.requirement.0168.bundle-signature-attributable.verifies",
|
|
146
|
+
"openwop.it.v2-bundle-signature-attributable.the-four-signature-outcomes-stay-distinct-collapsing-any-two-restores-the-defect": "openwop.requirement.0168.bundle-signature-attributable.outcomes",
|
|
147
|
+
"openwop.it.v2-bundle-signature-attributable.signingkeys-is-reachable-from-a-v1-root-too-a-bundle-is-v3-regardless-of-major": "openwop.requirement.0168.bundle-signature-attributable.v1-root",
|
|
148
|
+
"openwop.it.v2-corpus-tag-pinned.every-vendoring-consumer-in-the-cross-repo-inventory-records-a-published-corpus": "openwop.requirement.0176.corpus-tag-pinned",
|
|
149
|
+
"openwop.it.v2-declaration-parity.the-corpus-gate-script-exits-0": "openwop.requirement.0169.declaration-parity",
|
|
150
|
+
"openwop.it.v2-eos-clock.the-clock-file-is-current-with-the-matrix-and-the-public-history": "openwop.requirement.0174.v1-eos-clock",
|
|
151
|
+
"openwop.it.v2-eos-clock.check-removal-dates-fails-the-v1-tree-sources-of-v1-end-of-support-rows-once-the": "openwop.requirement.0174.v1-eos-clock",
|
|
152
|
+
"openwop.it.v2-eos-clock.check-removal-dates-passes-under-the-same-clock-when-today-is-before-the-date-an": "openwop.requirement.0174.v1-eos-clock",
|
|
153
|
+
"openwop.it.v2-error-registry-prose-parity.errors-md-states-the-registry-count-it-was-generated-from-and-renders-every-code": "openwop.requirement.0171.error-registry-prose-parity",
|
|
154
|
+
"openwop.it.v2-event-naming-rule.every-closed-enum-v2-event-type-is-two-kebab-segments-and-every-recorded-artifac": "openwop.requirement.0171.event-naming-rule",
|
|
155
|
+
"openwop.it.v2-event-naming-rule.the-closed-enum-and-the-vendor-branch-are-disjoint-every-registered-type-validat": "openwop.requirement.0171.event-naming-rule",
|
|
156
|
+
"openwop.it.v2-events-channel-parity.the-corpus-gate-script-exits-0": "openwop.requirement.0171.events-channel-parity",
|
|
157
|
+
"openwop.it.v2-externally-gated-never-stable.the-corpus-gate-script-exits-0": "openwop.requirement.0169.externally-gated-never-stable",
|
|
158
|
+
"openwop.it.v2-id-kinds-bound.every-v2-id-field-refs-its-kind-and-every-id-property-is-triaged": "openwop.requirement.0170.id-kinds-bound",
|
|
159
|
+
"openwop.it.v2-one-signing-scheme.registry-version-manifest-signing-has-exactly-one-scheme-ed25519-canonical-json": "openwop.requirement.0177.one-signing-scheme",
|
|
160
|
+
"openwop.it.v2-path-parity.the-corpus-gate-script-exits-0": "openwop.requirement.0172.path-parity",
|
|
161
|
+
"openwop.it.v2-release-identity.the-corpus-gate-script-exits-0": "openwop.requirement.0172.release-identity",
|
|
162
|
+
"openwop.it.v2-req-only-assertions.the-corpus-gate-script-exits-0": "openwop.requirement.0168.req-only-assertions",
|
|
163
|
+
"openwop.it.v2-retention-floors.the-registry-validates-and-the-script-prints-the-floor-state-offline": "openwop.requirement.0174.retention-floors",
|
|
164
|
+
"openwop.it.v2-retention-floors.a-pinned-old-major-version-missing-from-its-registry-while-the-floor-is-open-fai": "openwop.requirement.0174.retention-floors",
|
|
165
|
+
"openwop.it.v2-retention-floors.the-same-probe-with-every-pinned-version-present-passes-while-the-floor-is-open": "openwop.requirement.0174.retention-floors",
|
|
166
|
+
"openwop.it.v2-seams-not-in-canonical.the-corpus-gate-script-exits-0": "openwop.requirement.0168.seams-not-in-canonical",
|
|
167
|
+
"openwop.it.v2-security-defaults-table.the-obligation-table-has-a-witness-column-and-no-row-is-unwitnessable": "openwop.requirement.0173.security-defaults-table",
|
|
168
|
+
"openwop.it.v2-spec-artifacts-digest.the-corpus-gate-script-exits-0": "openwop.requirement.0168.spec-artifacts-digest",
|
|
169
|
+
"openwop.it.v2-threat-model-template.the-corpus-gate-script-exits-0": "openwop.requirement.0173.threat-model-template",
|
|
170
|
+
"openwop.it.v2-witness-required.the-corpus-gate-script-exits-0": "openwop.requirement.0168.witness-required"
|
|
6
171
|
}
|
|
7
172
|
}
|