Status: Stable.
Why this exists
spec/v2/core/ is what a host implements to pass the 2.0.0 floor: reading order, the six axioms, and rules other documents reference.
Reading order
overview.md— axioms, §0, §0a, claims,ext/versioning.md—OpenWOP-Version, version axescapabilities.md— discovery, profilesidentity.md— Subject,SubjectLink, id grammarsruns.md,events.md,errors.md,headers.md— runs,configurable, eventoneOf, registries,OpenWOP-*headersinterrupt.md,idempotency.md,replay.md,conversation.md,execution.md,persistence.mdsecurity-defaults.md,webhooks.md,interop.md,host-services.md,storage.md,tool-catalog.md,i18n.md,portability.mdpacks.md,node-pack-runtimes.md,connection-packs.md,form-content-packs.md,workflow-chain-packs.md,artifact-type-packs.mdconformance.md— requirement ids, witness classes, bundles, seams
Axioms in force
- A MUST without a witness class is not a requirement.
- One name per thing. Every alias has a removal date in
spec/v1/deprecations.jsonand a codemod id. - Closed by default. The discovery root, event envelope, payload and error registries, bundle, and
configurableareadditionalProperties: false. Vendor extension is one positive pattern in one namespace. - Registers are data. Gaps, risks, deprecations, migrations, witness classes, and dispositions are files with schemas and gates; prose is checked against them, never the reverse.
- Security defaults are obligations of the surface. A protecting behavior binds when the surface is advertised, never when a flag is set.
- Nothing persisted under v1 is orphaned. Every v1 artifact has a disposition in the migration register.
§0 Closed-enum growth rule
A registry-backed enum (event types, error codes, reason vocabularies, lanes) grows by adding a row to its registry and regenerating.
- Consumers MUST accept an unknown member of a registry-backed enum and MUST NOT act on it.
- Producers MUST NOT emit an unregistered member.
- Adding a member is additive in v2.x. Renaming one is a major; removing one is a major except under §0a.
§0a Retiring a v2 surface
A 2.x minor MUST NOT change the shape of an existing v2 surface; a new shape is a new surface added beside the old one.
A 2.x minor MAY remove a surface only when scripts/check-v2-retirement.mjs proves all of the following; otherwise the removal waits for 3.0:
- Its replacement shipped in an earlier 2.x minor.
- A
v2-minorrow inspec/v1/deprecations.jsonnamed the removal minor at least two minors and 30 days earlier. - No committed v2 host bundle and no published registry manifest carries it.
- It is an optional family, facet or enum member, so its absence is already a 2.0 state.
- Its family is
experimentalinspec/v2/declaration.json. - No independent host is in the INTEROP-MATRIX v2 table.
Until an outside host exists, a steward-deletion row in spec/v2/corrections.json can license removing any surface. check-v2-retirement.mjs refuses one that misstates its census or removes persisted-data readers, or is new while a tier-3 host is listed.
Readers MUST keep accepting a retired shape on replay, fork and poll; only emission narrows.
v1 end-of-support
v1 support ends at the later of:
- (a) every INTEROP-MATRIX host's non-vacuous v2 bundle, plus 90 days;
- (b) 18 months from the v2 release — applied if and only if an independent host is in the matrix at release.
The date is computed from the matrix, or set earlier under (c); nothing else MAY set it.
- (c) An
AcceptedRFC MAY set an earlier date once every counted host has a certified non-vacuous v2 bundle inevidence/v2-host-bundles/and reports no old-major traffic from third parties (anyone but the host's operator and the conformance suite) over at least the 7 days before the RFC. The date and that evidence are inspec/v2/eos-override.json. - After the date a host MAY drop the old major from
protocolVersions[]; it is not required to that day. - The old-major tree is then frozen as history by a marker naming the date, not edited.
- Counted hosts. Those with a row in the INTEROP-MATRIX v2 table.
- Non-vacuous. At least one claimed profile carries
witnessCount ≥ 1. - Anchor. The date the host's signed bundle was committed to
evidence/v2-host-bundles/in the spec repository, read from the public history (git log --diff-filter=A). NevergeneratedAtinside the bundle, which nothing signs. A later re-certification replaces the file and does not move the anchor. - The computed date.
evidence/v1-end-of-support.json, GENERATED byscripts/generate-v1-eos-clock.mjs, which honours a (c) override only when it meets (c). On or after the date,check-removal-dates.mjsfails the v1-tree sources of everyv1-end-of-supportrow unless that tree is frozen.
Old-major retention floors
Every published old-major artifact MUST remain installable at its last 1.x version for 12 months from the 2.0.0 publish (the v2.0.0 tag's commit date). A consumer pinned to the old major MUST be able to rebuild through that window.
The artifacts are the npm packages @openwop/openwop (1.x) and @openwop/openwop-conformance (1.x), the PyPI package openwop-client (1.x), and the Go module github.com/openwop/openwop-sdks/go (v1.x). Their identities and last 1.x versions are in spec/v2/retention-floors.json. scripts/check-retention-floors.mjs prints the floor state and, with --network, probes each registry for the pinned version.
Unpublishing, deprecating-with-removal, or retracting a listed version inside the window is a Phase 5 exit failure.
Profile claim vocabulary
These rules bind any public conformance statement:
- An unqualified "OpenWOP conformant" or "OpenWOP compatible" statement MUST mean
openwop-core-standard, the executable floor, never the discovery predicate. - A discovery-only claim MUST say
openwop-discovery-coreand MUST NOT use the same badge asopenwop-core-standard. - Every claim MUST state every additional profile it relies on; an omitted profile is an unclaimed one.
- A certification bundle MUST name canonical profile ids;
openwop-coreis deleted (seecapabilities.md). - A vendor extension MUST NOT use an
openwop-*id without an accepted RFC.
What is ext/
spec/v2/core/ stays within the word budget that scripts/check-core-budget.mjs enforces; spec/v2/ext/ holds the rest.
- Every
spec/v2/ext/<key>/document MUST declarewitnessand both maturity axes (technical,adoption) in its header. - A MUST with
witness: unwitnessableMUST NOT appear incore/. A document whose only witness is "deferred to Active → Accepted" entersext/or is deleted. - An
ext/family is advertised only under a wire-legal witness class (seecapabilities.md).
What a MUST means (Axiom 1)
Every MUST, SHOULD, and MAY in core/ is a requirement with an id in requirements.json and a witness from witnessable-unaided | witnessable-gated | seam-gated | claims-check | negative-existence. A seam-gated MUST is governed by conformance.md §"Witness class".
Sources: RFCs 0155, 0167, 0168, 0169, 0171, 0174, 0190, 0197.