“Oh baby baby, it’s a wild world It’s hard to get by just upon a smile Oh baby baby, it’s a wild world I’ll always remember you like a child, girl” — Cat Stevens
wild
wild is a language-agnostic test selection engine… no — that’s its sibling. wild does machine-checked compatibility and composition of software components, modelled as a category of contracts: contracts declare what a component provides and requires, tiers order ecosystem authority, and a checker verifies structural compatibility — first-party or third-party — before an update ships.
Part of the charly-vibes toolshed.
Status
A design with a prototype and a Rust implementation. The wild extract and
wild check subcommands are implemented and runtime-tested; the manual
describes the intended interface and marks what is implemented.
Crates.io. The publishable package is wild-vibes — the wild crate name
on crates.io belongs to an unrelated glob-expansion crate. The repository,
binary, and wire-format identities remain wild.
Quick Start
git clone https://github.com/charly-vibes/wild
cd wild
cargo build
# Extract design contracts from a Rust crate (beads wild-mh5.x)
./target/debug/wild extract --request request.json --output out/
# Run a scoped structural check against the extracted artifact
./target/debug/wild check --request request.json --format json --report report.json
Key Concepts
- Contracts: structural manifests of what a component provides and requires
- Tiers: ecosystem ordering — language standard library above frameworks, frameworks above first-party code
- Compatibility checking: machine-checked structural conformance of candidate updates against declared contracts
- Semantic composition: how compatibility composes (and where it doesn’t) — see the Specodelic specs
Continue
- Read the complete wild manual.
- Read the normative wild v1 formats — protocol for contracts, manifests, locks, sidecars, and bundles.
- Browse the Specodelic specs backing the design.
- Skim the integration failures verdict reports.
- Machine-readable landing: llms.txt.
Release Status
Generated artifact (docs.yml, from Cargo.toml + git ref). Do not hand-edit — the repo source files remain authoritative.
- Version: v0.2.0
- Built from: main @ 0c8f9dc
wild: manual
Machine-checked compatibility for software components, first-party or third-party.
Status, read first. wild is a design with a prototype, not a finished tool. What exists today: a nine-file specification suite (
specs/, lint-clean), a toy checker (wild_sim.py), prototype extractors for Rust, Python, and command-line tools (wild_proto.py,experiments/cli_extract.py), and experiments on real projects. Thewildcommand described below is the intended interface. Sections are marked [prototype] where code exists and [designed] where only the spec exists. The normative v1 formats and JSON Schema are specified; the older TOML sketch below is illustrative and is not the wire protocol.
1. What it does
Version numbers are claims. wild replaces them with checks.
For every release of a component it extracts a contract (what the component provides and what it requires), compares it with earlier releases, and decides mechanically whether the new release can replace the old one. For a set of components that must work together it decides whether they compose, picks the revisions, and produces a certificate that anyone can re-check offline.
You get three things:
- A compatibility verdict per change, computed from contracts, not from a version label.
- A composition verdict per assembly, with a certificate.
- A deploy order and rollback rules derived from those contracts, so continuous deployment needs no manual ordering.
2. The idea in one page
- A component’s contract is a set of named slots. A slot is something it provides (an output, a function, a command, a field) or requires (an input a caller must supply).
- Revision B is an accretion of revision A when it provides at least what A provided and requires no more than A required. Old users keep working.
- Accretions compose and have identities, so they form a category (a preorder). This is what lets verdicts chain: if B accretes A and C accretes B, then C accretes A, with no re-check needed.
- A change that is not an accretion is a break. A break must start a new lineage (a new name), with explicitly directed adapters or a disclosed unbridged boundary. Nobody is silently moved across a break.
- A consumer states its demand: the slots it actually uses. Scoped replacement checks demanded outputs and every required dependency of the replacement. Incomplete dynamic demand prevents a scoped safety claim.
- Checks run in tiers ordered by cost. Identity and shape check declared structure. Law results disclose proof, exhaustive, or sampled methods; evidence and signed attestations add separate scoped claims.
3. Concepts
| Term | Meaning |
|---|---|
| Contract | The set of slots, laws, limits, and defaults of one component revision. |
| Slot | A named provided or required item with a type. Outputs have out polarity, inputs in. |
| Openness | Each record or sum is open (consumers must tolerate additions) or closed (default). Growing a closed output sum is a break. |
| Revision | A contract identified by the hash of its canonical form. Never edited. |
| Lineage | An authority-qualified ancestry of accretive revisions with one accepted tip; unmerged forks refuse automatic selection. |
| Accretion | The relation “this revision can replace that one”. Reflexive and transitive. |
| Break | Any change that is not an accretion. Starts a new lineage. |
| Adapter | A checked bridge from one lineage to another (facade library, wire proxy, data upcaster, or component wrapper). |
| Demand | The slots a consumer uses, derived from its code and tests. |
| Floor | The least covering revision on ordered ancestry; incomparable covering minima require an explicit pin. |
| Law | A recorded property that must keep holding (for example idempotency). Laws accumulate across revisions. |
| Tombstone | A record that a required slot was dropped, so its name can never return with a different meaning. |
| Certificate | A committed assembly, policy, and proof bundle checked offline against caller-supplied commitments, trust roots, checker allowlist, and evaluation time. |
Tiers and verdicts
| Tier | What it checks | Nature |
|---|---|---|
| 0 identity | Hashes and lineage names | exact, instant |
| 1 shape | Provides, requires, polarity, openness, limits, defaults | exact, deterministic |
| 2 laws | Accumulated laws against a digest-bound implementation and harness | proof, exhaustive, or sampled |
| 3 evidence | Replayed traffic, consumer tests, canary | statistical |
| 4 attestation | A signed human claim with scope and expiry | human |
Structural assurance forms the lattice Reject < Unknown < PassDeclared. Reports separately name law methods/results, observation scope, attestation status, and the policy decision. Passing samples or version claims cannot establish structural assurance. Expired claims stop satisfying their policy requirement while independent checks remain valid. The word “compatible” alone is never printed.
4. How a change flows
source ──extract──▶ contract ──identify──▶ revision hash
│
tier 1 shape ◀─────────────┤ (checked against every ancestor)
tier 2 laws ◀─────────────┤
▼
accretion? ──yes──▶ publish to lineage
│
no ──▶ new lineage + bridge status ──▶ publish
│
consumers: demand ─▶ resolve ─▶ certificate ─▶ verify (offline)
│
deploy: floors ─▶ gate ─▶ canary ─▶ roll ─▶ live ─▶ retire old lineage when demand is zero
5. Using it
5.1 First week in an existing project [designed]
wild adopts a project in four levels. Each adds enforcement; none changes your package manager, registry, or release process.
wild init # writes extractor config, a baseline, and a CI hook; no edits needed
wild adopt observe # read-only: rebuilds your release history from contracts
wild adopt shadow # CI reports verdicts but never fails a build
wild adopt gate # rejects new breaks and expired baseline acknowledgements
wild adopt native # publishes sidecar records next to your existing artifacts
- observe extracts available historical releases, retains unavailable ones as Unknown, and lists disagreements between version labels and computed changes.
- baseline: first enforcement atomically records existing findings with an owner and acknowledgements expiring in 30 days. Rerunning init or changing levels never resets it; replacement and renewal require signed audit events. Expired acknowledgements reject.
- native adds a sidecar record that binds your host artifact’s digest to a revision hash. Your package, tag, and version are never modified.
5.2 Publishing a release (provider) [designed]
wild extract . # source → contract (draft)
wild check # tiers 0-2 against every earlier revision, locally
wild publish # signs and appends the revision to the registry log
check tells you which tier rejected and why: the tier, the slot or law, and the rule. Typical outcomes:
| You did | Verdict |
|---|---|
| Added an output slot or an optional input | accretion, publish |
| Removed an output or widened its value domain | break: new lineage with adapter or unbridged status |
| Made an optional input required | break |
| Added a variant to a closed output sum | break |
| Changed a declared default or tightened a provided limit | break |
| Reactivated a tombstoned input as required or with narrower acceptance | rejected |
5.3 Handling a break [designed]
wild adapt acme.billing acme.payments # drafts an adapter, TODO on each slot it cannot map
wild check --adapter # round-trip laws on recorded samples
wild publish --lineage acme.payments
- A draft adapter has an explicit TODO for every slot the tool cannot derive.
- An adapter declares its source/target hashes and losses. A lossless claim needs a reverse mapping and round-trip checks whose proof, exhaustive, or sampled method is disclosed. An infeasible adapter leaves an explicit unbridged boundary.
- Consumers whose demand does not touch the broken slot may move to the new lineage without an adapter. Moving is always opt-in.
5.4 Consuming a component [designed]
wild demand # derive the slots you use from code and tests (editable)
wild lock import # read your existing lockfile; unresolvable entries become Unknown
wild update # advice only: per candidate version, are your slots still compatible?
updatereports compatibility advice without changing the host resolver choice. Scoped replacement also checks new required dependencies; unresolved dynamic calls prevent a complete-demand claim.- Contracted lock entries pin authority, lineage, contract hash, and artifact digest. Unresolved entries retain their host locator and Unknown status; aliases are provenance, never identities.
5.5 Composing components [designed]
wild resolve # unique accepted tip per lineage; refuse unresolved forks or constraints
wild certify # write the certificate
wild verify bundle.json # offline; expected assembly/policy, trust roots and time are explicit inputs
- Resolution traverses finite dependency closure and selects each lineage’s unique accepted tip. Forks, singleton conflicts, and failed relations refuse selection without backtracking. Different required lineages remain separate copies.
- A component declared singleton has exactly one instance and one lineage per assembly.
- Values that cross between lineages need an adapter; otherwise the boundary is reported as unbridged.
- Assembly structural assurance is the meet of binding assurance; each binding must also satisfy law, evidence, and attestation policy. The report discloses coverage and method.
5.6 Deploying [designed]
wild deploy plan # derive the order from floors; manual ordering is not accepted
wild deploy gate # a consumer deploys only if its providers are live at or above its floor
wild deploy rollback # refuses to roll a provider below any live consumer's floor
wild deploy retire # retires an old lineage when no known consumer demands it
- Only unsatisfied floor prerequisites contribute ordering edges. A cycle of satisfied dependencies is allowed; an unsatisfied prerequisite cycle is refused with its members listed.
- A revision that writes data older revisions cannot read must declare itself irreversible; rollback past it is rejected after its first write.
- Every traffic-reachable provider revision must cover the floor. Reports expire at their TTL boundary (default 60 seconds); missing or future-dated reports block. A coordinator lease and snapshot generation are revalidated atomically at each route change, promotion, or rollback.
- An emergency override records scope, signer, reason, and expiry. It cannot bypass structural Reject, Unknown reachability, coordination failure, or irreversible-write barriers. Retirement needs seven continuous days of fresh empty known demand and zero traffic by default.
5.7 Third-party software without contracts [designed; extractors partly prototyped]
- Overlay: you may publish an overlay contract for an upstream package, bound to its artifact digest and labelled inferred.
- Tests as laws: your passing integration tests against an uncontracted upstream are recorded as laws of your own component.
- Version claims remain metadata until a trusted publisher signs a scoped, expiring attestation; they never substitute for structural or law checks.
- An uncontracted edge has Unknown structural assurance. An explicit digest-bound overlay can declare covered structure; integration tests provide sampled law evidence for their exercised domain.
6. Reading a report
Every command emits a JSON envelope by default when not attached to a terminal, and a human rendering on request. The envelope carries the tier, the verdict, and the slot ids. A report also states the checker version and lists which consumers are known and which cannot be known.
Example (illustrative):
check acme.billing (rev 4f2a… → 91c0…) checker 0.1
tier 0 identity pass
tier 1 shape REJECT invoice.total: output type int32 → str
stopped at tier 1 (first reject)
known consumers: 3 declared. Undeclared consumers are not covered.
7. Writing a contract (illustrative TOML sketch)
The wire format is versioned JSON in wild v1 formats, with structural examples. The TOML sketch below explains the concepts and is not accepted as v1 wire input. Extractors produce draft contracts; manual declarations fill semantic meaning, laws, limits, defaults, and unsupported constructs.
lineage = "acme.billing"
stability = "stable" # stable | experimental | deprecated
[[slot]]
name = "invoice.total"
polarity = "out"
type = "decimal(2)"
[[slot]]
name = "invoice.status"
polarity = "out"
type = "sum"
variants = ["draft", "paid"]
openness = "open" # consumers must tolerate new variants
[[slot]]
name = "charge.amount"
polarity = "in"
type = "decimal(2)"
[limit]
"batch.size" = { max = 500 }
[[law]]
name = "charge.idempotent"
8. What it does not do
- Undeclared behavior. A change in behavior behind an unchanged signature is caught only by a law or by evidence (tier 2 or 3). In experiments it was the main residual.
- Consumers it cannot see. Retirement and “safe to remove” are safe only against known consumers.
- Governance. Namespace disputes, typosquatting, business decisions to shut a service, and hardware retirements are out of scope; they can be recorded as attestations.
- Lossy extraction. The contract is a common denominator. What an extractor cannot express becomes an opaque slot, which is frozen, so it can cause false breaks. Extractors report their opaque share and false-break rate.
- Emergent behavior. Properties of a whole system, such as retry amplification, are outside per-contract checking.
9. Evidence so far
All from toy models or small real experiments; none from a production deployment.
- The accretion relation passed exhaustive reflexivity and transitivity checks over 76 single-slot states (438,976 triples) after four rule fixes found by the same tests.
- In a synthetic ecosystem, lineage resolution broke zero dependencies and needed no search; with truthful labels it coincides with semver-with-duplicates, so the gain is machine-checked labels.
- genesis-vibes and specodelic (Rust): across 15 consecutive genesis-vibes releases, Cargo’s 0.x caret rule and the contract check disagreed on 6, including one patch release that added a public struct field. specodelic’s actual usage tolerated 1 to 6 more genesis versions than its Cargo range allowed. No compile test was possible.
- Flask/Werkzeug and requests/urllib3 (Python): on 28 real version combinations, accuracy against an execution oracle was 0.89 for the contract check with call-site arguments and 0.75 for declared version ranges. Small sample, and two extractor fixes were made after seeing failures.
- specodelic’s own CLI: shapes were identical across v0.2.0 to v0.4.0, while lint behavior changed in two rules. A replayed corpus caught it; the shape tier could not.
10. Troubleshooting
| Symptom | Likely cause and fix |
|---|---|
| A change is rejected at tier 1 but you never touch that slot | The full check applies to the whole lineage. Publish as a new lineage; consumers whose demand is unaffected can adopt it unaided. |
| Many breaks on the first run | Use the baseline; breaks present at baseline are recorded, not rejected. |
| False breaks on an opaque slot | Replace opaque with a typed slot in the extractor config, or accept the reported opaque share. |
A dependency shows Unknown | It has no contract. Add an overlay, rely on tests-as-laws, or accept the weaker tier. |
| Deploy gate blocks | A provider is not live at your floor, or its live-revision report is stale. |
| Rollback refused | A live consumer’s floor is above the revision you chose; roll those consumers back first. |
| Verification fails offline | The certificate is incomplete or a hash was altered; regenerate it from the registry. |
11. Reference
Commands [designed]
| Command | Purpose |
|---|---|
init | Write extractor config, baseline, and CI hook |
extract <source> | Source to contract draft |
check | Run tiers 0 to 2 against every earlier revision |
publish | Sign and append a revision |
adapt <old> <new> | Draft an adapter across lineages |
demand | Derive consumer demand |
lock import | Import an existing lockfile |
update | Per-candidate compatibility advice |
resolve / certify / verify | Composition, certificate, offline check |
deploy plan / gate / rollback / retire | Rollout rules |
adopt observe / shadow / gate / native | Adoption levels |
status | Level, per-tier share of dependencies, open acknowledgements |
explain | Why a verdict was reached |
Specification map
| Spec | Covers |
|---|---|
wild | Umbrella: computed, verifiable, honest verdicts |
wild.core | Contract IR and the accretion category |
wild.tiers | Tier pipeline and verdict lattice |
wild.compose | Assemblies, resolution, certificates |
wild.registry | Append-only log, ownership, lockfile, sidecar |
wild.bridge | Adapters, overlays, third-party software |
wild.adopt | Staged adoption |
wild.deploy | Gate, canary, rollback, retirement |
wild.extract | Extractors and law harness |
Format reference
Wild v1 formats defines canonical bytes, IR, manifests, locks, sidecars, policies, evidence, certificate bundles, registry proofs, and deployment coordination. The schema and examples are structurally validated. Runtime conformance remains future work; current simulations exercise smaller models.
Wild v1 formats and decision rules
This reference defines the interoperable design contracts used by all nine wild specifications. These formats are intended behavior; the Python simulations are smaller models and do not implement this wire protocol.
The machine-readable structural schema is wild-v1.schema.json, using JSON Schema draft 2020-12. This document defines additional semantic validation that JSON Schema cannot express. A conforming reader validates both. Structural examples cover every wire kind; their placeholder digests and signatures are intentionally not valid certified assemblies. Their gate checks structure only. Unknown versions, kinds, fields, duplicate names, dangling references, or failed semantic checks are refused with a JSON diagnostic; no partial input receives a complete assurance claim.
Encoding, identities, and canonical bytes
All wire documents are UTF-8 JSON objects with schema_version: "1" and the kind specified by their schema definition. Duplicate JSON object keys, invalid UTF-8, unpaired surrogates, floating-point numbers, and integers outside [-9007199254740991, 9007199254740991] are invalid. Strings preserve their exact Unicode code points; no host-dependent normalization is applied. Identifier strings are restricted to the ASCII grammar in the schema.
Canonical JSON recursively sorts object keys by Unicode scalar value, omits whitespace and a byte-order mark, and writes integers in base ten without leading zeros or negative zero. It escapes quote and backslash as \" and \\, and control code points U+0000 through U+001F as lowercase \u00xx; all other scalar values are literal UTF-8. Solidus is not escaped. Input whitespace, escape spelling, and object-key order have no effect on canonical bytes.
Array ordering is explicit. These arrays are sets and must be sorted by the indicated unique key before canonicalization: contract slots and tombstones by slot name; contract laws by law id; contract relations by relation id; contract sunsets by date and then slot name; manifest providers by instance id; manifest demand lists and law-id lists lexically; assembly roots lexically, components by instance id, and bindings by binding id; certificate proofs by digest; policy required-law and allowed-method lists lexically; all slot-scope, parent-hash, adapter-hash, trusted-signer, lease-scope, and certificate proof lists lexically; bundle documents and blobs by digest; lockfile entries by entry id. Type record fields and sum variants are objects, whose keys are sorted by canonical JSON. Other arrays, including function arguments, observed samples, and arbitrary default values, preserve order. Repeated set keys are rejected, rather than silently deduplicated.
A content digest is sha256: followed by exactly 64 lowercase hexadecimal digits over canonical document bytes. Raw artifacts use the same syntax but hash their exact raw bytes. Artifact bytes and document bytes are never substituted for each other. v1 accepts SHA-256 only; introducing an algorithm requires a new supported format version. A contract hash excludes lineage ownership, timestamps, evidence, and artifact metadata, which reside in separate documents. Equal contract hashes establish structural identity, never implementation identity.
Canonical examples (byte strings shown as JSON without a trailing newline):
| Input | Canonical bytes |
|---|---|
{"b":2,"a":1} | {"a":1,"b":2} |
{ "text": "\u0061" } | {"text":"a"} |
{"text":"\n"} | {"text":"\u000a"} |
Contract with slots z, a | Same canonical bytes as that contract with slots a, z |
{"a":1,"a":2} or {"a":1.0} | Refused, no identity assigned |
Contract IR and subtyping
A contract contains slots, tombstones, laws, relations, and sunsets. Slot names are unique across slots and tombstones. Each slot has a stable meaning identifier, polarity out or in, one declared facet, a recursive type, required, and default. default is {present:false} or {present:true,value:...} so an explicit null is distinguishable from absence. Outputs must have required:true. Tombstones are former input slots and must retain their last accepted meaning and type. An opaque type carries an artifact or source-range fingerprint; any fingerprint change is a break.
The scalar domains are unit, boolean, integer, string, and bytes; integer types specify inclusive min and max, with min ≤ max. Byte values are objects containing canonical padded base64; decoded bytes define equality. No implicit conversion, rounding, coercion, or numeric widening across scalar kinds occurs. Defaults must inhabit their declared type. General cardinality and timeout constraints are represented as integer slots in the relevant facet, with immutable meaning describing units and whether they are guarantees or requirements; they are not untyped annotations.
subtype(A,B) means every value allowed by A is accepted by B. The v1 checker uses these conservative structural rules; when it cannot establish inclusion it returns Unknown rather than guessing:
| Shape | Rule for subtype(A,B) |
|---|---|
| Scalar | Same scalar kind; for integers, A’s interval is contained in B’s interval. |
| Record | Every required B field is required in A with a subtype; each field that A can emit is accepted by B with a subtype. Extra A fields require B to be open. An open A requires an open B. Optional fields may be absent, never substituted with an implicit default. |
| Sum | Every named A variant exists in B with a subtype payload unless B is open. Open A requires open B; unknown variants are retained as opaque payloads. |
| Sequence | A’s item type is a subtype of B’s; A’s inclusive length interval is contained in B’s. |
| Map | Key types are identical; value types are covariant; A’s cardinality interval is contained in B’s. |
| Function | Same argument arity; B’s argument types are subtypes of A’s corresponding arguments; A’s result is a subtype of B’s. |
| Opaque | Identical fingerprint only. |
For a missing B record field, an open B accepts the unknown field without interpreting its payload. For fields shared by A and B their declared type still applies. An open A cannot subtype B when B has an optional typed field absent from A: A could emit that field with an incompatible unknown value. Named variants use the same rule. Unknown record fields and variants are round-tripped byte-for-byte in the containing opaque payload. A bytes default is exactly { "base64": "..." }; unit defaults are null. Open sums use an opaque payload for labels absent from the named variants. Recursive cyclic type references are not supported in v1: types are finite trees. Supporting such references requires a new schema version and termination rules.
accretes(old,new) requires all of the following:
- Every old output remains under the same name, facet, polarity, and meaning, with a subtype output. New outputs are permitted. Retained inputs have supertype input domains; required may become optional, but optional may not become required. A new required input is forbidden; a new optional input is permitted.
- Removed inputs leave tombstones. Existing tombstones remain or reactivate as non-required inputs whose type accepts the tombstoned domain; a reintroduced required input is a new requirement and breaks accretion. Tombstones cannot be fabricated without history. Removed outputs always break.
- Provided defaults are identical. Changed input defaults are also conservatively a break in v1 because omission can change behavior. Limits expressed as slots obey the same polarity rules with no separate contradictory limit algorithm.
- Every old law id remains with the same suite digest and scope. New laws may be added. New required relations are a break; an existing relation may not change or disappear within a lineage. A schema revision is needed to add a facet or shape kind.
Binding checks additionally verify every required input of every selected component, facet match, and all declared relations. Demand restriction selects externally used outputs; it never removes a selected implementation’s own required dependencies. Dynamic usage that cannot be resolved marks the demand manifest incomplete and prevents scoped substitution or removal claims. A law counterexample blocks the relevant policy even when structure passes.
Consumer manifest, assembly, and lockfile
A manifest names its component contract hash, raw implementation artifact digest, demand_complete, and a unique set of provider instance requirements. Each provider record names authority, versionless lineage, required slots, and an explicit floor contract hash. Uncertain dynamic usage is listed in unresolved_usage and requires demand_complete:false. A lineage is an ASCII dot-separated semantic name; version suffixes matching v[0-9]+ or a numeric final segment are forbidden. Names do not decide compatibility.
An assembly contains explicit root instance ids, component instances with contract, artifact, and manifest hashes, and bindings whose endpoints are instance ids and slot names. All ids and endpoints must resolve. Every required input has exactly one binding. The set of provider output slots referenced by bindings for each manifest provider exactly matches its demand_slots; undeclared provider dependencies are refused. Duplicate competing providers for one input are refused. Components are exactly the transitive closure reachable from roots; unrelated or missing instances are refused. Components sharing a singleton lineage declaration must use one lineage and one artifact instance; a second singleton instance is refused. Disconnected unneeded instances cannot alter the verdict.
For no roots, no components and no bindings are allowed. This empty assembly has structural assurance PassDeclared, coverage numerator and denominator zero, and coverage ratio null (vacuous satisfaction). Cyclic dependencies are allowed for composition: deterministic closure visits each instance once, then validates all edges. Deploy ordering considers only prerequisites not already satisfied. Assembly composition uses disjoint union after an explicit injective renaming of instance ids; exposed interfaces are joined by declared bindings. Name collisions, singleton conflicts, or invalid relations make composition undefined, with diagnostics. The category laws apply to jointly composable interfaces. Equality is structural equality modulo the explicit injective renaming of instance ids, so incidental instance names cannot break associativity.
A v1 lock preserves every host entry using a stable entry_id, ecosystem, locator, raw artifact digest when available, and status. A contracted entry also pins authority, lineage, and contract hash; an unresolved entry has status Unknown and a reason. Unresolved entries are retained and never silently removed or treated as compatible. A host alias may remain in the locator as provenance, but it cannot replace an identity. A sidecar is signed over its canonical document and binds authority, lineage, ecosystem, locator, artifact digest, contract hash, extractor digest, and registry sequence. Signature payload excludes only the signature member; the remaining members, including signer and algorithm, are covered. Runtime loading verifies raw artifact bytes against the sidecar and lock, not merely the contract hash.
For each registry snapshot and authority/lineage, publication records an accepted tip and its ancestry. Publishing competing children marks that lineage forked; no automatic newest exists until an explicit merge accretes all ancestors and becomes its unique tip. “Newest” means accepted tip at snapshot sequence, not clock or lexical hash order. The resolver takes a finite snapshot, roots, manifests, and policy, traverses dependency closure, and selects unique tips. It refuses missing or retracted tips, singleton conflicts, and failed relations; it never backtracks to an older revision. Stable pinned hashes remain readable with advisories. A floor can be derived only on totally ordered accepted ancestry; incomparable covering revisions require an explicit pinned covering revision and a coverage check. Registry snapshot and evaluation inputs are recorded in the certificate. Registry newest-tip selection is unchanged by the local update mode: local update validation accepts a host-selected pinned assembly and makes no newest-tip or publication claim.
Relations are finite equal or less_equal predicates over two qualified integer or scalar slot values, provided explicitly by defaults with matching meaning/units. Each endpoint is an object with instance_id and slot; in a contract, self names the declaring component and other instance ids name its manifest providers. Resolution maps these local references to assembly instance ids. Missing values or incompatible types yield Unknown and refuse any policy requiring the relation. Selection happens before relation checks. Adapters and explicit lineage migration are proposals; they do not introduce automatic search paths or silently change host resolver choices.
Law results, observations, attestations, and policy
A law_result binds a law suite, contract, implementation artifact, harness artifact, ordered fixture digests, seed, resource budgets, method, status, and an optional witness digest. The method is proof, exhaustive, or sampled. A proof requires a witness accepted by an independently specified and digest-bound proof checker. Exhaustive means every value of an explicitly finite domain was enumerated; its domain descriptor and count are in the witness. Sampled includes the exact recorded cases and proves only their outcomes. Proof and exhaustive results require a non-null witness; proof results also require a proof checker digest. Counterexamples require a witness naming the failing input. Inconclusive results require a non-empty diagnostic reason. A signature on a result proves who claimed it, not whether the law holds.
Status is pass, counterexample, or inconclusive. Timeout, crash, missing fixtures, external access, or nondeterminism yields inconclusive, not pass. Harnesses receive fixed time, seed, fixtures, and resource budgets; network access, ambient files, process creation outside the sandbox, and uncontrolled clocks are forbidden. A harness sandbox unable to enforce those restrictions produces inconclusive. Seed alone is insufficient for reproducibility. An artifact with the same contract but different bytes must receive new law evaluation.
An observation binds artifact and contract digests, demanded slot scope, sample digest, independent observation count, confidence in integer parts per million, observation time, and expiry. Confidence aggregation takes the minimum over contributors to a particular claim; it does not claim a joint probabilistic guarantee for unrelated events. Contradictory observations create a repair draft and block promotion in that observed scope without rewriting the contract. Missing or expired observations satisfy no evidence requirement.
An attestation binds contract and artifact digests, authority/lineage, slot scope, claim, issue time, expiry, signer, and Ed25519 signature. The signature is over the canonical document without its signature member. Observation records use the same signing rule; unsigned traffic metadata cannot satisfy a trusted evidence policy. Issue and expiry times are UTC RFC3339 strings with exactly second precision and Z; expiry must exceed issue time. Verification receives evaluation time explicitly; at equality with expiry a claim is expired, and future-issued claims are invalid. Trust is determined from caller-supplied roots and authenticated key-history/revocation proofs included in the bundle. A legacy semver string is metadata until a trusted publisher signs such a claim.
The structural lattice is Reject < Unknown < PassDeclared, with meet as minimum and join as maximum. Identity success alone does not establish a binding; a binding reaches PassDeclared only when all declared structural checks pass. Law checks, observations, and attestations do not form a higher assurance ladder. A verdict includes assurance, law methods and statuses, evidence scope, attestation status, coverage, and a policy decision (accept or refuse). A known structural counterexample is Reject; a missing contract or incomplete required structural analysis is Unknown.
A policy declares structural minimum, required law ids, allowed law methods, minimum fresh observation count/confidence, whether scoped attestations are required, trusted signer ids, and law resource budgets. Each binding must satisfy policy for all demanded slots. Overlays can establish declared structure only for explicitly modelled, digest-bound demands. Traffic-derived partial overlays disclose Unknown outside their observed domain. Passing integration tests attach sampled law evidence; they cannot alone turn Unknown structure into PassDeclared. Expired attestation changes the attestation status and may refuse a requiring policy while preserving independent structural and law results. No policy can accept structural Reject or a relevant law counterexample.
Cache entries are immutable check records. Structural keys are (old_contract, new_contract, checker). Law keys additionally include implementation, harness, suite, fixtures, seed, method, and budgets. Current decisions also depend on assembly/demand, policy digest, evidence digest set, trust-root digest, revocation history, and explicit evaluation time. v1 does not cache final policy decisions: it recomputes them from cached checks and current input validity. Same-contract artifacts, new evidence, expired claims, or revoked keys therefore cannot reuse a stale policy acceptance.
Certificate bundle and independent verification
A certificate contains the assembly hash, policy hash, checker artifact hash, registry snapshot head, evaluation time, and proof record digests. Its content-addressed bundle contains the assembly, all manifests and contracts, policy, law results, observations, attestations, sidecars, registry inclusion/consistency/key-history proofs, and witnesses referenced by those records. Artifacts and harnesses needed to replay executable laws are supplied as raw digest-addressed blobs. Unsupported proof formats yield inconclusive; v1 does not invent a generic proof language or treat an opaque witness as valid. A policy requiring such a proof cannot pass until a supported independently specified checker verifies it.
The caller separately supplies the expected assembly commitment, policy commitment, trust roots, evaluation time, and allowed checker digest(s). These are verifier inputs; values taken solely from the untrusted certificate cannot replace them. Historic verification evaluates claims at the recorded time only when the caller explicitly supplies that time; current verification evaluates at the caller’s current evaluation time. A historical pass does not authorize current deployment.
Verification proceeds as follows:
- Validate wire structure and canonical digests of every document; compare the assembly and policy hashes with the caller’s commitments and enforce the caller’s checker allowlist.
- Reconstruct exact dependency closure from root instances and manifests; reject missing or extraneous components, demands, bindings, or artifacts. A missing root with its subtree is detected by the external assembly commitment. Reject duplicate ids and competing bindings.
- Independently check every binding, singleton, relation, and artifact/sidecar match. Do not call the resolver and do not claim that the chosen provider is currently the newest.
- Verify referenced law results by replay or an accepted independently checkable witness. Verify signatures, inclusion and key-history proofs against the caller’s trust roots and snapshot. Reevaluate claim validity at the caller’s evaluation time.
- Compute per-binding assurance, method-labelled coverage, and policy decisions. Aggregate structural assurance with meet; accept only if every required binding and global constraint passes policy.
A negative composition result also has a certificate containing the committed attempted assembly and an independently checkable failure or missing-reference diagnostic. A missing blob produces Unknown/refusal rather than a fabricated structural counterexample. Corrupted blobs, malformed certificates, or mismatched caller commitments are verification errors, not compatibility evidence. A local update report is not a registry certificate: it carries no registry snapshot head, no inclusion or key-history proofs, and no publication or ancestry claim, and it never replaces v1 native certificate rules or wire grammar.
Structural verification performs indexed visits proportional to bindings B plus reachable schema nodes S plus proof bytes P. Replay costs are reported separately with policy resource bounds; repeated shared documents are hashed once per bundle. Benchmarks report B, S, P, replay work, checker version, and hardware instead of claiming a wall-clock ratio with an unspecified tolerance.
Registry and deployment coordination
Namespace bootstrap is an append-only entry signed by a trust-root-authorized namespace authority. It names the initial owner and a distinct recovery key. A qualified identity is (authority, lineage), preventing a public name from shadowing a configured private authority. Ordinary rotation requires old and new signatures. Recovery uses the predesignated recovery key, explicitly revokes the compromised key from a log sequence, and flags affected submissions; past bytes are immutable. Loss of both owner and recovery keys cannot be bypassed: publication remains refused until a separately governed new namespace is established. Mirrors are equivalent only for the same authenticated snapshot and caller inputs; consistency proofs cannot detect split views without comparison to a trusted checkpoint.
A deployment live snapshot enumerates every revision reachable under the consumer’s routing, its artifact, observation time, TTL, and coordination generation. Each physical live instance has instance_id and the logical assembly component_instance_id. A routes entry names logical consumer/provider ids and the physical revision ids it can reach; every route id must resolve to a reported revision of that provider. An empty required route or an omitted manifest provider route blocks the gate. In-flight consumer manifests and signed write_barrier records are referenced by digest; barriers name the writer, minimum readable revision, monotone sequence, and committed or Unknown state. All reachable providers must cover the floor, not just the highest revision. Missing reports, reports from the future, or evaluation_time ≥ observed_at + ttl yield Unknown; default TTL is 60 seconds. A consumer can use a new floor during a provider roll only after old routes are drained or routing pins it exclusively to covering instances.
A deployment coordinator provides serializable leases spanning both live and planned consumers, provider routing, floors, and irreversible-write barriers. A gate verdict records snapshot generation, lease id, and validity deadline. Before every route change, promotion, rollback, and retirement the coordinator atomically checks the generation and lease, revalidates floors against all live/in-flight consumers, and commits the state transition. Lease expiry, generation conflict, or unreachable coordinator aborts; rerun the gate on a fresh snapshot. Reports alone without this coordination cannot authorize deployment. The pure gate receives explicit time and snapshot; collection and coordination are external effects.
Unsatisfied prerequisites alone contribute floor-order edges. A cycle of already satisfied service dependencies is allowed; a cycle of unsatisfied new floors is refused. Irreversible writers persist a monotone first-write barrier before acknowledging the first incompatible write. Unknown barrier status fails closed, and canary aborts follow the same rollback restrictions as full deployments. Default retirement grace is seven continuous days of empty fresh known demand and zero traffic; renewed demand or a missing report restarts the interval. Authorized emergency overrides can waive only enumerated policy findings, never structural Reject, incomplete reachability, coordination failures, or irreversible barriers.
Adoption, extractor diagnostics, and command results
Observe is read-only and shadow preserves host exit status. First activation of gate atomically persists an immutable baseline digest and scoped findings with owner and acknowledgements expiring in 30 days. If persistence fails, gate activation is refused. init, reruns, branch checkout, and level changes do not reset the baseline. A deliberate baseline replacement requires an authorized signer, reason, old and new digests, expiry, and an appended audit event. Acknowledgement renewal also appends an event; expired acknowledgements refuse enforcement even for old findings. Unsupported ecosystems remain Unknown: observe/shadow report diagnostics successfully; gate/native must satisfy their policy.
Historical releases with unavailable source or failed extraction remain Unknown nodes. Unknown nodes do not establish accretion edges. Source bundles include every imported schema, build option, and generated input an extractor needs; all are hashed. An extractor inventories exported declarations using stable source ranges. Known unsupported constructs become opaque slots; parser failure or incomplete declaration inventory prevents a complete extraction claim. False-break rate reports use independently adjudicated candidate breaks as the denominator, include the adjudication source and sample count, and report false_break_rate_ppm:null (Unknown) when that count is zero; otherwise the value is floor(1000000 * false_breaks / adjudicated_breaks).
All commands emit an envelope before human rendering. It contains schema version, command, structural assurance, policy decision, tier_reports, slots, coverage, checker digest, known consumer ids, an explicit false undeclared-consumer coverage flag, and diagnostics. Deploy commands additionally populate the typed deployment member with stage, revision hashes, gate decision, and lease digest; other commands use null. Coverage uses numerator and denominator with null ratio for an empty domain. Diagnostics have stable code, severity, source path when known, slot ids, and a reason. Exit 0 means the operation completed and policy accepted (or observe/shadow intentionally report only); exit 1 means a computed policy refusal; exit 2 means malformed input, missing required local files, or execution failure. An inconclusive check is a policy refusal when required, not a passing test.
Registry proof encoding and publication records
v1 deliberately uses a full hash-chain proof rather than an underspecified compact Merkle proof. Each log_entry has zero-based sequence, the previous entry’s canonical digest, a typed event payload, signer id, signature algorithm, and signature. The first entry’s previous is the sentinel sha256: followed by 64 zero digits; this sentinel does not identify a contract. The head is the last entry’s canonical digest, or the sentinel for an empty log. A registry_proof contains entries in increasing sequence with no gaps. Verification rehashes every entry, validates each predecessor link and signature, and verifies any caller checkpoint as an exact prefix. Two supplied heads are consistent only if the shorter authenticated chain is an exact prefix of the longer. Compact proofs require a separately versioned format; no logarithmic proof-size claim is made for v1.
All Ed25519 public keys decode to 32 bytes and signatures to 64 bytes. Bootstrap entries are verified with caller-authorized namespace authority keys. Each later entry is verified with the active owner at that sequence, except recovery entries, which require the predesignated recovery key. Ordinary rotation’s incoming-key new_signature signs the canonical entry with outer signature and nested new_signature removed; the outgoing key signs the entry with only outer signature removed, including that incoming signature. Ownership updates apply after the entry. Recovery names the old key and the first compromised sequence, not later than the recovery entry; submissions from that key at or after that sequence are flagged and cannot satisfy current policy. Historical validation discloses that later recovery was not known at its recorded snapshot. Losing both keys does not permit an unsigned bypass.
A publication names authority, lineage, contract and artifact digests, parent contract hashes, stability, bridge status, and adapter hashes. Parent hashes must belong to that authority/lineage except an explicitly declared predecessor lineage recorded as an unbridged or adapted boundary. The first lineage publication has no same-lineage parents. Subsequent candidates accrete all same-lineage parents and ancestors. Competing children mark the accepted ancestry forked until an explicit all-parent merge. Experimental retractions and advisories are authenticated log events referencing the affected publication; a pinned artifact remains available. Registry availability is a prerequisite: missing raw artifacts remain a reported failure, rather than being implied available by an append-only metadata log.
Contract sunsets list dates and output slot names projected to disappear. They are immutable within a lineage, and introducing an earlier disappearance is a break. earliest_break returns the least listed date or null. A schedule is a disclosed future service-retirement risk, not permission to mutate a content-addressed contract or remove stable-lineage slots. Current structural checks stay clock-free; deploy policy evaluates the schedule with explicit time and uses a new lineage or retirement rules for actual removal.
Semantic checks additionally enforce interval ordering, default type membership, uniquely named slots/laws/relations, sorted set fields, manifest completeness matching unresolved usage, and publication/sidecar authority consistency. Coverage has numerator ≤ denominator; ratio_ppm is floor(1000000 * numerator / denominator), or null when denominator is zero. Lossless adapters have empty lost_slots and a non-null reverse; lossy adapters list every accepted loss. Source/target adapter digests must match a binding’s actual endpoint contracts. Attestations and observations must cover every demanded slot for which their policy is required. Public keys, timestamps, and decoded base64 lengths are checked semantically; JSON Schema alone does not establish signatures or canonical identity.
JSON Schema
The v1 protocol schema, mirrored from schemas/wild-v1.schema.json. Structural examples live in schemas/examples-v1.json.
Wild design
Mirrored from docs/wild-design.md — the design document backing the specodelic specs.
Design standard
Mirrored from docs/design-standard.md — how designs are proposed, reviewed, and ratified in this repo.
wild
id: wild kind: intent statement: THE wild SHALL let software components, first-party or third-party, be composed on machine-checked contracts, so that compatibility is determined autonomously and verifiably instead of asserted by version numbers.
Wild
Purpose
This is a normative design specification; only the prototype and corpus gate scenarios explicitly identified below are implemented. Shared wire formats and decision rules are defined in wild v1 formats and the v1 schema.
Umbrella spec. Contracts form a category: objects are contract revisions, morphisms are accretions (provides grow, requires shrink), and breaks cross lineages through adapters. Assemblies of components compose on top of that category and yield a certificate any independent verifier can re-check. The other specs refine one concern each: wild.core (contracts and accretion), wild.tiers (verdict pipeline), wild.compose (assemblies, resolution, certificates), wild.registry (log, ownership, lock), wild.bridge (adapters, overlays, third parties), wild.adopt (brownfield adoption), wild.deploy (rollout), wild.extract (extractors and law harness).
Constraints
| id | kind | expr | traces_to |
|---|---|---|---|
| compatibility_computed | invariant | no compatibility verdict is derived from a version string; version strings are metadata and attestation input only | [[wild]] |
| decision_autonomous | invariant | given contracts and demand, the composition verdict is computed without human input; human judgment enters only as attestation | [[wild]] |
| decision_verifiable | invariant | every composition verdict ships a certificate that an independent verifier can re-check | [[wild]] |
| offline_verifiable | invariant | verification uses the v1 certificate bundle and caller-supplied assembly commitment, policy, trust roots, and evaluation time defined in docs/wild-formats-v1.md; no network or registry write access | [[wild]] |
| language_blind | invariant | the core operates on the Contract IR only; ecosystem knowledge lives in extractors | [[wild]] |
| category_structure | invariant | contract accretion is reflexive and transitive; assembly composition is a partial operation on compatible, explicitly identified interfaces and obeys identity and associativity wherever defined | [[wild]] |
| honest_scope | invariant | a verdict states its tier and its coverage and never claims more than was checked | [[wild]] |
| no_silent_downgrade | invariant | lost coverage cannot increase assurance; expired attestations cease satisfying attestation policy without erasing independently valid structural or law results | [[wild]] |
| checker_versioned | invariant | every recorded verdict names the checker version; changing the checker never rewrites an existing verdict | [[wild]] |
| output_envelope | invariant | every command emits the v1 JSON envelope with assurance, decision, tier_reports, slots, coverage, checker, and disclosed consumers; the human rendering is derived from it | [[wild]] |
| honest_verdict_labels | invariant | a verdict names structural assurance, law method, evidence scope, and attestation policy result; the bare word compatible is never emitted | [[wild]] |
| open_world_disclosed | advisory | every report lists known consumers and states that undeclared consumers are not covered | [[wild]] |
Model
States
requestedresolvedcertifiedverifiedrefused
Transitions
| id | from | to | guard |
|---|---|---|---|
| resolve | requested | resolved | [[wild.decision_autonomous]] ∧ [[wild.compatibility_computed]] |
| certify | resolved | certified | [[wild.decision_verifiable]] |
| verify | certified | verified | [[wild.offline_verifiable]] ∧ [[wild.checker_versioned]] |
| refuse_unresolved | requested | refused | [[wild.honest_scope]] |
| refuse_stale | resolved | refused | [[wild.no_silent_downgrade]] |
| refuse_invalid | certified | refused | [[wild.honest_scope]] |
Properties
| id | kind | derives_from | generator | predicate |
|---|---|---|---|---|
| version_string_never_decides | unit | [[wild.compatibility_computed]] | release_labelled_patch_that_removes_a_slot() | verdict == Reject regardless of label |
| verdict_needs_no_human | unit | [[wild.decision_autonomous]] | contracts_and_demand() | compute(c, d) completes with no interactive input |
| verdict_has_certificate | unit | [[wild.decision_verifiable]] | arbitrary_composition_verdict() | certificate present ∧ verify(certificate) == verdict |
| verification_is_offline | unit | [[wild.offline_verifiable]] | verify_with_network_and_registry_disabled() | verify(certificate) completes |
| core_has_no_ecosystem_imports | unit | [[wild.language_blind]] | core_module_dependency_graph() | no dependency edge to any extractor |
| category_laws_hold | law | [[wild.category_structure]] | arbitrary_contract_chain(length: 3) | identity: compose(id, f) == f associativity: compose(compose(f, g), h) == compose(f, compose(g, h)) |
| verdict_states_its_scope | unit | [[wild.honest_scope]] | arbitrary_verdict() | verdict has structural assurance, law methods, evidence scope, attestation status, and coverage |
| lost_coverage_lowers_verdict | unit | [[wild.no_silent_downgrade]] | assembly_gaining_an_uncontracted_dependency() | coverage(after) < coverage(before) ∧ assurance(after) ≤ assurance(before) |
| verdict_names_checker | unit | [[wild.checker_versioned]] | verdict_recorded_then_checker_upgraded() | recorded.checker == old ∧ recorded unchanged |
| envelope_matches_human | unit | [[wild.output_envelope]] | arbitrary_check_result() | parse(render_human(r)) agrees with envelope(r) |
| bare_compatible_never_emitted | unit | [[wild.honest_verdict_labels]] | arbitrary_passing_result() | output names structural assurance, law method, and evidence scope ∧ not equals "compatible" |
| unknown_consumers_disclosed | unit | [[wild.open_world_disclosed]] | report_with_known_consumers([a, b]) | report states undeclared consumers are not covered |
Notes
Value proposition: determine composition across modules, components, and packages, first or third party, autonomously and verifiably. Autonomy comes from computing verdicts over contracts; verifiability from certificates re-checked offline by a separate verifier; the category structure is what lets verdicts compose (transitivity of accretion, associativity of assembly composition).
What the evidence says (toy simulations with assumed parameters, not data about real registries): the accretion relation needed four rule fixes before it passed exhaustive reflexivity and transitivity checks; with truthful labels, lineage resolution and semver-with-duplicates coincide, so the gain is machine-checked labels; undeclared behavior stays the weak spot and is only reached through laws and evidence. These limits are why honest_scope and open_world_disclosed exist.
Design acceptance cases
These cases define future runtime behavior. They are not claims that the current prototypes implement the v1 protocol. Executable document and prototype gates are under Requirements.
Rule: Compatibility computed
The system SHALL satisfy compatibility_computed as defined in the Constraints table and the v1 format reference.
Acceptance case: Version string never decides
- GIVEN the fixture domain
release_labelled_patch_that_removes_a_slot() - WHEN the
compatibility_computedcheck runs - THEN
verdict == Reject regardless of label
Rule: Decision autonomous
The system SHALL satisfy decision_autonomous as defined in the Constraints table and the v1 format reference.
Acceptance case: Verdict needs no human
- GIVEN the fixture domain
contracts_and_demand() - WHEN the
decision_autonomouscheck runs - THEN
compute(c, d) completes with no interactive input
Rule: Decision verifiable
The system SHALL satisfy decision_verifiable as defined in the Constraints table and the v1 format reference.
Acceptance case: Verdict has certificate
- GIVEN the fixture domain
arbitrary_composition_verdict() - WHEN the
decision_verifiablecheck runs - THEN
certificate present ∧ verify(certificate) == verdict
Rule: Offline verifiable
The system SHALL satisfy offline_verifiable as defined in the Constraints table and the v1 format reference.
Acceptance case: Verification is offline
- GIVEN the fixture domain
verify_with_network_and_registry_disabled() - WHEN the
offline_verifiablecheck runs - THEN
verify(certificate) completes
Rule: Language blind
The system SHALL satisfy language_blind as defined in the Constraints table and the v1 format reference.
Acceptance case: Core has no ecosystem imports
- GIVEN the fixture domain
core_module_dependency_graph() - WHEN the
language_blindcheck runs - THEN
no dependency edge to any extractor
Rule: Category structure
The system SHALL satisfy category_structure as defined in the Constraints table and the v1 format reference.
Acceptance case: Category laws hold
- GIVEN the fixture domain
arbitrary_contract_chain(length: 3) - WHEN the
category_structurecheck runs - THEN identity:
compose(id, f) == fassociativity:compose(compose(f, g), h) == compose(f, compose(g, h))
Rule: Honest scope
The system SHALL satisfy honest_scope as defined in the Constraints table and the v1 format reference.
Acceptance case: Verdict states its scope
- GIVEN the fixture domain
arbitrary_verdict() - WHEN the
honest_scopecheck runs - THEN
verdict has structural assurance, law methods, evidence scope, attestation status, and coverage
Rule: No silent downgrade
The system SHALL satisfy no_silent_downgrade as defined in the Constraints table and the v1 format reference.
Acceptance case: Lost coverage lowers verdict
- GIVEN the fixture domain
assembly_gaining_an_uncontracted_dependency() - WHEN the
no_silent_downgradecheck runs - THEN
coverage(after) < coverage(before) ∧ assurance(after) ≤ assurance(before)
Rule: Checker versioned
The system SHALL satisfy checker_versioned as defined in the Constraints table and the v1 format reference.
Acceptance case: Verdict names checker
- GIVEN the fixture domain
verdict_recorded_then_checker_upgraded() - WHEN the
checker_versionedcheck runs - THEN
recorded.checker == old ∧ recorded unchanged
Rule: Output envelope
The system SHALL satisfy output_envelope as defined in the Constraints table and the v1 format reference.
Acceptance case: Envelope matches human
- GIVEN the fixture domain
arbitrary_check_result() - WHEN the
output_envelopecheck runs - THEN
parse(render_human(r)) agrees with envelope(r)
Rule: Honest verdict labels
The system SHALL satisfy honest_verdict_labels as defined in the Constraints table and the v1 format reference.
Acceptance case: Bare compatible never emitted
- GIVEN the fixture domain
arbitrary_passing_result() - WHEN the
honest_verdict_labelscheck runs - THEN
output names structural assurance, law method, and evidence scope ∧ not equals "compatible"
Rule: Open world disclosed
The system SHALL satisfy open_world_disclosed as defined in the Constraints table and the v1 format reference.
Acceptance case: Unknown consumers disclosed
- GIVEN the fixture domain
report_with_known_consumers([a, b]) - WHEN the
open_world_disclosedcheck runs - THEN
report states undeclared consumers are not covered
Acceptance case: Historical certificate does not authorize current use
- GIVEN an attestation was valid at certificate creation but is now expired
- WHEN the caller requests current verification with the later evaluation time
- THEN historic checks remain immutable and current attestation policy refuses
Requirements
Requirement: Spec corpus integrity
The spec corpus SHALL stay lint-clean and reference-closed, so every constraint, property, and model row in the corpus remains checkable by the specodelic toolchain.
Scenario: Spec corpus stays lint-clean and reference-closed
- GIVEN the dual-format corpus under
openspec/specs - WHEN
spk lint openspecandspecodelic graph openspecrun - THEN lint reports no issues and no warnings across all nine files
- AND the reference graph reports no dangling references
- AND the gate executes this behavior as a declared contract test
Requirement: Ecosystem gate wiring
The three ecosystem gates (ah, pretender, testaruda) SHALL be wired as hard gates, so quality checks are machine-enforced rather than advisory.
Scenario: Gates wired and standard true
- GIVEN the wired gate configs (
.espectacular/config.toml,justfile,lefthook.yml,pretender.toml,testaruda.toml) - WHEN the wiring gate runs
ah check,pretender check,spk lint openspec, andtestaruda select --safe - THEN the three gate configs exist on disk and parse clean
- AND they carry the standard sections and follow the hardcoded-gate pattern
- AND the openspec spec corpus is lint-clean and reference-closed
- AND the gated tests run clean
- AND the gate executes this behavior as a declared contract test
Requirement: Wild design contract
The design corpus SHALL expose this capability’s constraints as normative, self-contained rules with acceptance cases, and SHALL link to a structurally valid shared v1 schema without claiming future runtime behavior is implemented.
Scenario: Wild design is self-contained
- GIVEN this spec,
docs/wild-formats-v1.md, andschemas/wild-v1.schema.json - WHEN the design contract gate checks normative rule coverage, local references, and the shared schema
- THEN every constraint has a corresponding rule and acceptance case
- AND both referenced files exist and the schema is valid JSON Schema draft 2020-12
- AND this capability is discoverable by strict OpenSpec validation
wild-core
id: wild.core kind: intent statement: THE wild core SHALL represent each software contract as a content-addressed set of typed slots and decide accretion between revisions as a category with checkable laws.
Wild core
Purpose
This is a normative design specification; only the prototype and corpus gate scenarios explicitly identified below are implemented. Shared wire formats and decision rules are defined in wild v1 formats and the v1 schema.
The Contract IR and the accretion relation. A contract has slots with polarity (out provides, in requires), openness, limits, defaults, laws, and facets. Revision v' accretes v when provides grow and requires shrink. Accretions form a thin category (a preorder); restricting to a consumer’s demand is a functor. A non-accretion must start a new lineage.
Constraints
| id | kind | expr | traces_to |
|---|---|---|---|
| identity_content_addressed | invariant | revision.id == hash(canonical(contract)); equal ids imply identical contracts | [[wild.core]] |
| canonical_form_stable | invariant | canonical(c) is independent of slot order, whitespace, extractor, host, and clock | [[wild.core]] |
| hash_algorithm_in_identity | invariant | an identity names its hash algorithm; identities under different algorithms are never equal | [[wild.core]] |
| lineage_name_versionless | invariant | lineage.name is namespaced, non-empty, and has no version component | [[wild.core]] |
| name_meaning_immutable | invariant | within a lineage, slot name, facet, polarity, and semantic meaning are immutable; types may evolve only by the variance rules in docs/wild-formats-v1.md; law definitions are immutable and law sets only grow | [[wild.core]] |
| slot_shapes_closed | invariant | v1 slot shape ∈ {scalar, record, sum, sequence, map, function, opaque}; adding a shape requires a new IR schema version, not merely a new contract hash | [[wild.core]] |
| accretion_monotone | invariant | accretes(v, v') iff every old output remains with a subtype, each retained input accepts a supertype, no new required input appears, tombstones persist, and defaults, limits, laws, and facets satisfy docs/wild-formats-v1.md | [[wild.core]] |
| polarity_openness_declared | invariant | every record and sum declares open or closed (default closed); a closed output sum growing, opening, or becoming unrestricted is a break; an input sum growing is an accretion; an input sum losing tolerance is a break | [[wild.core]] |
| limits_are_slots | invariant | declared limits (size, cardinality, timeout) are slots; tightening a provided limit or loosening a required limit is a break | [[wild.core]] |
| defaults_are_slots | invariant | defaults and environment assumptions are slots; a changed provided default is a break | [[wild.core]] |
| opaque_is_frozen | invariant | any change to an opaque slot is a break | [[wild.core]] |
| facets_independent | invariant | compat(v, v') is the conjunction over facets of compat_facet(v, v'); facets ∈ {api, abi, layout, serialization, behavior, dialect, environment, license}; adding a facet kind requires a new IR schema version | [[wild.core]] |
| data_artifacts_have_contracts | invariant | content files, templates, and generated feature files consumed by code carry a contract checked like an API, including arity and size limits | [[wild.core]] |
| tombstones_preserve_names | invariant | a dropped requires leaves a tombstone; re-adding the name must accrete the tombstoned slot | [[wild.core]] |
| accretion_is_category | invariant | accretions have identities and compose; composing accretions yields an accretion; the relation is reflexive and transitive | [[wild.core]] |
| check_against_ancestors | invariant | a candidate revision is checked against every ancestor in its lineage, not only its predecessor | [[wild.core]] |
| demand_restriction_functorial | invariant | restricting a contract to a demand set preserves accretion and composes: restrict(restrict(c, D1), D2) == restrict(c, D1 ∩ D2) | [[wild.core]] |
| break_requires_new_lineage | invariant | a non-accretion may be published only under a new lineage name | [[wild.core]] |
| stability_tiers | invariant | lineage stability ∈ {stable, experimental, deprecated}; only experimental lineages may be retracted | [[wild.core]] |
| sunset_computable | invariant | a contract with a sunset schedule exposes the earliest date at which its provides shrink, queryable before that date | [[wild.core]] |
| fork_merge_pushout | invariant | a merge is published only if its contract accretes every branch ancestor and has no conflicting meaning, default, limit, or law definition; unresolved conflicts list names and are refused; an unmerged fork has no implicit newest revision | [[wild.core]] |
Model
States
draftedcanonicalidentifiedaccretivelineage_breakrejected
Transitions
| id | from | to | guard |
|---|---|---|---|
| canonicalize | drafted | canonical | [[wild.core.canonical_form_stable]] |
| identify | canonical | identified | [[wild.core.identity_content_addressed]] ∧ [[wild.core.hash_algorithm_in_identity]] |
| accrete | identified | accretive | [[wild.core.accretion_monotone]] ∧ [[wild.core.check_against_ancestors]] |
| break | identified | lineage_break | [[wild.core.break_requires_new_lineage]] |
| reject | identified | rejected | violation of [[wild.core.name_meaning_immutable]] or invalid v1 IR |
Properties
| id | kind | derives_from | generator | predicate |
|---|---|---|---|---|
| hash_matches_content | unit | [[wild.core.identity_content_addressed]] | arbitrary_contract() | id(c) == hash(canonical(c)) |
| canonical_is_order_independent | unit | [[wild.core.canonical_form_stable]] | arbitrary_contract(), permutation_of_slots() | canonical(c) == canonical(permute(c)) |
| algorithms_never_collide | unit | [[wild.core.hash_algorithm_in_identity]] | same_bytes_hashed_with_two_algorithms() | id_a != id_b |
| versioned_lineage_name_rejected | unit | [[wild.core.lineage_name_versionless]] | lineage_name_with_version_suffix("acme.billing.v2") | check(name) == failed |
| redefined_meaning_rejected | unit | [[wild.core.name_meaning_immutable]] | (r, r') with a changed slot meaning or a narrowed input type | check(r, r') == failed; variance-safe type refinement with unchanged meaning passes |
| unknown_shape_rejected | unit | [[wild.core.slot_shapes_closed]] | slot_with_shape("tensor") | check(slot) == failed |
| removed_provide_is_break | unit | [[wild.core.accretion_monotone]] | contract_pair_with(provide_removed: true) | accretes(v, v') == false |
| closed_output_growth_is_break | unit | [[wild.core.polarity_openness_declared]] | closed_output_sum_with_added_variant() | accretes == false; the same addition in input position yields true |
| tightened_limit_is_break | unit | [[wild.core.limits_are_slots]] | provided_limit_lowered(500 → 200) | accretes == false |
| changed_default_is_break | unit | [[wild.core.defaults_are_slots]] | provided_default_changed(30 → 5) | accretes == false |
| opaque_change_is_break | unit | [[wild.core.opaque_is_frozen]] | opaque_slot_with_changed_content() | accretes == false |
| facet_break_blocks_compat | unit | [[wild.core.facets_independent]] | pair_with_break_in_exactly_one_facet() | compat == failed |
| feature_file_arity_checked | unit | [[wild.core.data_artifacts_have_contracts]] | template_defining_21_fields_fed_20_inputs() | check == failed |
| tombstone_blocks_name_reuse | unit | [[wild.core.tombstones_preserve_names]] | drop_then_readd_input_with_narrower_type() | check(readd) == failed |
| accretion_category_laws | law | [[wild.core.accretion_is_category]] | arbitrary_contract_chain(length: 3) | identity: accretes(v, v) and compose(id, f) == f associativity: compose(compose(f, g), h) == compose(f, compose(g, h)) |
| skipped_ancestor_break_caught | unit | [[wild.core.check_against_ancestors]] | chain_v1_v2_v3_where_v3_breaks_v1_only() | check(v3) == failed |
| restriction_functor_laws | law | [[wild.core.demand_restriction_functorial]] | arbitrary_contract(), two_demand_sets() | identity: restrict(c, all_slots) == c associativity: restrict(restrict(c, D1), D2) == restrict(c, D1 ∩ D2) |
| break_in_lineage_rejected | unit | [[wild.core.break_requires_new_lineage]] | breaking_revision_under_same_lineage() | publish == rejected |
| retracting_stable_rejected | unit | [[wild.core.stability_tiers]] | retract_request_on_stable_lineage() | retract == rejected |
| scheduled_shrink_reported | unit | [[wild.core.sunset_computable]] | contract_with_sunset(date: d) | earliest_break(c) == d |
| colliding_merge_refused | unit | [[wild.core.fork_merge_pushout]] | two_forks_defining_same_name_differently() | merge == refused ∧ colliding names listed |
Notes
Exhaustive small-scope testing (76 single-slot states, 438,976 triples) found four rule gaps in an early checker: optional inputs becoming required, open/closed flips, unrestricted versus restricted sums, and dropped names returning with a new meaning. They are encoded above as polarity_openness_declared and tombstones_preserve_names. The relation is a conjunction over names, so the single-name result extends to many slots by construction; this was argued, not tested.
The category is thin (at most one morphism between two revisions), so associativity and identity hold structurally; the properties guard the implementation, not the mathematics.
Design acceptance cases
These cases define future runtime behavior. They are not claims that the current prototypes implement the v1 protocol. Executable document and prototype gates are under Requirements.
Rule: Identity content addressed
The system SHALL satisfy identity_content_addressed as defined in the Constraints table and the v1 format reference.
Acceptance case: Hash matches content
- GIVEN the fixture domain
arbitrary_contract() - WHEN the
identity_content_addressedcheck runs - THEN
id(c) == hash(canonical(c))
Rule: Canonical form stable
The system SHALL satisfy canonical_form_stable as defined in the Constraints table and the v1 format reference.
Acceptance case: Canonical is order independent
- GIVEN the fixture domain
arbitrary_contract(), permutation_of_slots() - WHEN the
canonical_form_stablecheck runs - THEN
canonical(c) == canonical(permute(c))
Rule: Hash algorithm in identity
The system SHALL satisfy hash_algorithm_in_identity as defined in the Constraints table and the v1 format reference.
Acceptance case: Algorithms never collide
- GIVEN the fixture domain
same_bytes_hashed_with_two_algorithms() - WHEN the
hash_algorithm_in_identitycheck runs - THEN
id_a != id_b
Rule: Lineage name versionless
The system SHALL satisfy lineage_name_versionless as defined in the Constraints table and the v1 format reference.
Acceptance case: Versioned lineage name rejected
- GIVEN the fixture domain
lineage_name_with_version_suffix("acme.billing.v2") - WHEN the
lineage_name_versionlesscheck runs - THEN
check(name) == failed
Rule: Name meaning immutable
The system SHALL satisfy name_meaning_immutable as defined in the Constraints table and the v1 format reference.
Acceptance case: Redefined meaning rejected
- GIVEN the fixture domain
(r, r')with a changed slot meaning or a narrowed input type - WHEN the
name_meaning_immutablecheck runs - THEN
check(r, r') == failed; variance-safe type refinement with unchanged meaning passes
Rule: Slot shapes closed
The system SHALL satisfy slot_shapes_closed as defined in the Constraints table and the v1 format reference.
Acceptance case: Unknown shape rejected
- GIVEN the fixture domain
slot_with_shape("tensor") - WHEN the
slot_shapes_closedcheck runs - THEN
check(slot) == failed
Rule: Accretion monotone
The system SHALL satisfy accretion_monotone as defined in the Constraints table and the v1 format reference.
Acceptance case: Removed provide is break
- GIVEN the fixture domain
contract_pair_with(provide_removed: true) - WHEN the
accretion_monotonecheck runs - THEN
accretes(v, v') == false
Rule: Polarity openness declared
The system SHALL satisfy polarity_openness_declared as defined in the Constraints table and the v1 format reference.
Acceptance case: Closed output growth is break
- GIVEN the fixture domain
closed_output_sum_with_added_variant() - WHEN the
polarity_openness_declaredcheck runs - THEN
accretes == false; the same addition in input position yields true
Rule: Limits are slots
The system SHALL satisfy limits_are_slots as defined in the Constraints table and the v1 format reference.
Acceptance case: Tightened limit is break
- GIVEN the fixture domain
provided_limit_lowered(500 → 200) - WHEN the
limits_are_slotscheck runs - THEN
accretes == false
Rule: Defaults are slots
The system SHALL satisfy defaults_are_slots as defined in the Constraints table and the v1 format reference.
Acceptance case: Changed default is break
- GIVEN the fixture domain
provided_default_changed(30 → 5) - WHEN the
defaults_are_slotscheck runs - THEN
accretes == false
Rule: Opaque is frozen
The system SHALL satisfy opaque_is_frozen as defined in the Constraints table and the v1 format reference.
Acceptance case: Opaque change is break
- GIVEN the fixture domain
opaque_slot_with_changed_content() - WHEN the
opaque_is_frozencheck runs - THEN
accretes == false
Rule: Facets independent
The system SHALL satisfy facets_independent as defined in the Constraints table and the v1 format reference.
Acceptance case: Facet break blocks compat
- GIVEN the fixture domain
pair_with_break_in_exactly_one_facet() - WHEN the
facets_independentcheck runs - THEN
compat == failed
Rule: Data artifacts have contracts
The system SHALL satisfy data_artifacts_have_contracts as defined in the Constraints table and the v1 format reference.
Acceptance case: Feature file arity checked
- GIVEN the fixture domain
template_defining_21_fields_fed_20_inputs() - WHEN the
data_artifacts_have_contractscheck runs - THEN
check == failed
Rule: Tombstones preserve names
The system SHALL satisfy tombstones_preserve_names as defined in the Constraints table and the v1 format reference.
Acceptance case: Tombstone blocks name reuse
- GIVEN the fixture domain
drop_then_readd_input_with_narrower_type() - WHEN the
tombstones_preserve_namescheck runs - THEN
check(readd) == failed
Rule: Accretion is category
The system SHALL satisfy accretion_is_category as defined in the Constraints table and the v1 format reference.
Acceptance case: Accretion category laws
- GIVEN the fixture domain
arbitrary_contract_chain(length: 3) - WHEN the
accretion_is_categorycheck runs - THEN identity:
accretes(v, v)andcompose(id, f) == fassociativity:compose(compose(f, g), h) == compose(f, compose(g, h))
Rule: Check against ancestors
The system SHALL satisfy check_against_ancestors as defined in the Constraints table and the v1 format reference.
Acceptance case: Skipped ancestor break caught
- GIVEN the fixture domain
chain_v1_v2_v3_where_v3_breaks_v1_only() - WHEN the
check_against_ancestorscheck runs - THEN
check(v3) == failed
Rule: Demand restriction functorial
The system SHALL satisfy demand_restriction_functorial as defined in the Constraints table and the v1 format reference.
Acceptance case: Restriction functor laws
- GIVEN the fixture domain
arbitrary_contract(), two_demand_sets() - WHEN the
demand_restriction_functorialcheck runs - THEN identity:
restrict(c, all_slots) == cassociativity:restrict(restrict(c, D1), D2) == restrict(c, D1 ∩ D2)
Rule: Break requires new lineage
The system SHALL satisfy break_requires_new_lineage as defined in the Constraints table and the v1 format reference.
Acceptance case: Break in lineage rejected
- GIVEN the fixture domain
breaking_revision_under_same_lineage() - WHEN the
break_requires_new_lineagecheck runs - THEN
publish == rejected
Rule: Stability tiers
The system SHALL satisfy stability_tiers as defined in the Constraints table and the v1 format reference.
Acceptance case: Retracting stable rejected
- GIVEN the fixture domain
retract_request_on_stable_lineage() - WHEN the
stability_tierscheck runs - THEN
retract == rejected
Rule: Sunset computable
The system SHALL satisfy sunset_computable as defined in the Constraints table and the v1 format reference.
Acceptance case: Scheduled shrink reported
- GIVEN the fixture domain
contract_with_sunset(date: d) - WHEN the
sunset_computablecheck runs - THEN
earliest_break(c) == d
Rule: Fork merge pushout
The system SHALL satisfy fork_merge_pushout as defined in the Constraints table and the v1 format reference.
Acceptance case: Colliding merge refused
- GIVEN the fixture domain
two_forks_defining_same_name_differently() - WHEN the
fork_merge_pushoutcheck runs - THEN
merge == refused ∧ colliding names listed
Acceptance case: Canonical identity rejects ambiguous JSON
- GIVEN a contract JSON document with a duplicate object key or floating-point value
- WHEN canonicalization runs
- THEN the input is refused before hashing; permuted valid slot arrays yield identical bytes
Acceptance case: Variance preserves semantic identity
- GIVEN an input integer slot changes from interval [0,10] to [0,20] with unchanged meaning
- WHEN accretion is checked
- THEN the refinement passes; changing meaning or narrowing to [0,5] rejects
Acceptance case: Tombstone reactivation cannot introduce a requirement
- GIVEN a previously removed input is present only as a tombstone
- WHEN the candidate reintroduces it as required
- THEN accretion rejects even when its type accepts the old domain
Requirements
Requirement: Prototype accretion pipeline
The prototype tier pipeline SHALL run the round-1 accretion scenarios end to end and emit a machine-readable verdict record per scenario, so declared round-1 outcomes remain executable while wild itself is unbuilt; the prototype uses a smaller type model and does not establish full v1 conformance.
Scenario: Prototype accretion pipeline reports round-1 verdicts
- GIVEN the round-1 scenario fixtures encoded in
prototype/wild_sim.py - WHEN the prototype simulation runs
- THEN it exits 0 and emits a JSON array of verdict records, each carrying an
idand a decisiontracematching the declared expected terminal state - AND known undeclared-behavior escapes remain reported rather than being silently converted to passing safety claims
- AND the gate executes this behavior as a declared contract test
Requirement: Wild core design contract
The design corpus SHALL expose this capability’s constraints as normative, self-contained rules with acceptance cases, and SHALL link to a structurally valid shared v1 schema without claiming future runtime behavior is implemented.
Scenario: Wild core design is self-contained
- GIVEN this spec,
docs/wild-formats-v1.md, andschemas/wild-v1.schema.json - WHEN the design contract gate checks normative rule coverage, local references, and the shared schema
- THEN every constraint has a corresponding rule and acceptance case
- AND both referenced files exist and the schema is valid JSON Schema draft 2020-12
- AND this capability is discoverable by strict OpenSpec validation
wild-tiers
id: wild.tiers kind: intent statement: THE wild tier pipeline SHALL decide each revision’s verdict through checks ordered by cost, where structural checks can reject, executable law checks disclose their method, and observations and attestations never override structural rejection.
Wild tiers
Purpose
This is a normative design specification; only the prototype and corpus gate scenarios explicitly identified below are implemented. Shared wire formats and decision rules are defined in wild v1 formats and the v1 schema.
Checks run in cost order: identity, shape, laws, evidence, attestation. Identity and shape decide declared structure. Law results distinguish proof, exhaustive finite enumeration, and sampling; a passing sample proves only that sample. Evidence and signed attestations are separate scoped claims. The verdict product and policy evaluation are defined in docs/wild-formats-v1.md.
Constraints
| id | kind | expr | traces_to |
|---|---|---|---|
| fail_fast_ordering | invariant | tiers run in order identity < shape < laws < evidence < attestation; a run stops at the first Reject | [[wild.tiers]] |
| exact_tiers_pure | invariant | identity and shape are pure functions of canonical contracts and checker version; law evaluation is reproducible only with the implementation digest, harness digest, seed, fixture digests, and resource limits in the v1 bundle | [[wild.tiers]] |
| verdict_lattice | invariant | structural assurance forms the lattice Reject < Unknown < PassDeclared; executable laws, observations, and attestations are separate scoped records; assembly assurance is the structural meet and policy checks every binding as defined in docs/wild-formats-v1.md | [[wild.tiers]] |
| policy_names_min_tier | invariant | each context has a v1 policy naming structural floor, allowed law methods, required law ids, evidence thresholds, and any required attestations; missing or failed required checks refuse the operation | [[wild.tiers]] |
| rejection_explains | invariant | a Reject names the tier, the slot or law, and the rule that failed | [[wild.tiers]] |
| laws_cumulative | invariant | laws(v') ⊇ ⋃ laws(ancestors); every ancestor law passes against the v' implementation | [[wild.tiers]] |
| law_runs_deterministic | invariant | the same complete harness inputs yield the same law result; seed, implementation and harness digests, fixtures, budgets, and method are recorded; timeout, crash, or nondeterminism is inconclusive and cannot pass required policy | [[wild.tiers]] |
| evidence_cannot_override_exact | invariant | observations may add scoped evidence to a structural Pass; they cannot override a structural Reject or a law counterexample | [[wild.tiers]] |
| evidence_confidence_conservative | advisory | reported confidence is the minimum over contributing observations, never a product | [[wild.tiers]] |
| contradiction_triggers_repair | invariant | observed behavior contradicting the declared contract creates a repair draft; the contract is never edited silently | [[wild.tiers]] |
| attestation_scoped | invariant | an attestation names its signer, its scope (lineage and slots), and its claim | [[wild.tiers]] |
| attestation_expiring | invariant | an attestation carries issue time and expiry and is bound to artifact and contract digests; at evaluation_time ≥ expiry the attestation status is Unknown while independent checks remain unchanged | [[wild.tiers]] |
| verdict_cache_keyed | invariant | structural cache keys include old and new contract hashes and checker version; law cache keys also include implementation, harness, fixtures, seed, method, and budgets; policy evaluation includes demand, policy digest, evidence digests, trust roots, and evaluation time and is never reused past claim expiry | [[wild.tiers]] |
| verdict_recorded_immutable | invariant | recorded check results are immutable; new inputs append new records; current policy decisions are recomputed from those records and claim validity at evaluation time | [[wild.tiers]] |
Model
States
draftidentifiedshape_checkedlaw_checkedpublishedobservedattestedrejected
Transitions
| id | from | to | guard |
|---|---|---|---|
| identify | draft | identified | [[wild.tiers.exact_tiers_pure]] |
| shape_check | identified | shape_checked | [[wild.tiers.fail_fast_ordering]] ∧ preserves wild-core accretion_monotone |
| law_check | shape_checked | law_checked | [[wild.tiers.laws_cumulative]] |
| publish | law_checked | published | [[wild.tiers.policy_names_min_tier]] ∧ requires wild-registry registry_append_only |
| observe | published | observed | [[wild.tiers.evidence_cannot_override_exact]] |
| attest | observed | attested | [[wild.tiers.attestation_expiring]] |
| repair | observed | draft | [[wild.tiers.contradiction_triggers_repair]] |
| reject_identity | identified | rejected | [[wild.tiers.rejection_explains]] |
| reject_shape | shape_checked | rejected | [[wild.tiers.rejection_explains]] |
| reject_laws | law_checked | rejected | [[wild.tiers.rejection_explains]] |
| revise | rejected | draft | [[wild.tiers.verdict_recorded_immutable]] |
Properties
| id | kind | derives_from | generator | predicate |
|---|---|---|---|---|
| first_reject_stops_run | unit | [[wild.tiers.fail_fast_ordering]] | revision_failing_identity_and_laws() | tiers_run == [identity] ∧ verdict == Reject |
| exact_tiers_ignore_side_inputs | unit | [[wild.tiers.exact_tiers_pure]] | same_inputs_with_varied_clock_and_network() | verdict(a) == verdict(b) |
| verdict_lattice_laws | law | [[wild.tiers.verdict_lattice]] | three_arbitrary_verdicts() | identity: meet(v, PassDeclared) == v associativity: meet(meet(a, b), c) == meet(a, meet(b, c)) |
| below_policy_refused | unit | [[wild.tiers.policy_names_min_tier]] | verdict_PassDeclared_under_policy_requiring_laws() | decision == refused |
| reject_names_rule | unit | [[wild.tiers.rejection_explains]] | arbitrary_rejected_revision() | report has tier ∧ slot_or_law ∧ rule |
| ancestor_law_failure_rejected | unit | [[wild.tiers.laws_cumulative]] | revision_violating_an_ancestor_law() | law_check == failed |
| law_run_reproducible | unit | [[wild.tiers.law_runs_deterministic]] | (contract, impl, seed) run twice | run(a) == run(b) |
| evidence_never_overrides_reject | unit | [[wild.tiers.evidence_cannot_override_exact]] | shape_Reject_plus_clean_traffic_replay() | verdict == Reject |
| confidence_is_minimum | unit | [[wild.tiers.evidence_confidence_conservative]] | observations_with_confidences([0.99, 0.90]) | confidence == 0.90 |
| contradiction_creates_draft | unit | [[wild.tiers.contradiction_triggers_repair]] | observed_behavior_outside_declared_contract() | repair_draft_created ∧ contract_unchanged |
| attestation_without_scope_rejected | unit | [[wild.tiers.attestation_scoped]] | attestation_missing_scope() | check(a) == failed |
| expired_attestation_is_unknown | unit | [[wild.tiers.attestation_expiring]] | attestation_with_past_expiry() | attestation_status(a) == Unknown ∧ independent_assurance unchanged |
| cache_key_includes_checker | unit | [[wild.tiers.verdict_cache_keyed]] | same_pair_under_two_checker_versions() | keys differ ∧ no cross-hit |
| recorded_verdict_unchanged | unit | [[wild.tiers.verdict_recorded_immutable]] | verdict_recorded_then_rerun_under_new_checker() | old record unchanged ∧ new record appended |
Notes
Evidence is graded because failures are correlated, so confidence is the minimum, never a product. Simulation round 1 (12 scenarios): six shape breaks were caught at tier 1, two behavior changes at tier 2 through laws, one at tier 3 through canary replay, one safe input widening was correctly passed, and two undeclared behavior changes escaped. Escapes of undeclared behavior are the known residual of this design.
Design acceptance cases
These cases define future runtime behavior. They are not claims that the current prototypes implement the v1 protocol. Executable document and prototype gates are under Requirements.
Rule: Fail fast ordering
The system SHALL satisfy fail_fast_ordering as defined in the Constraints table and the v1 format reference.
Acceptance case: First reject stops run
- GIVEN the fixture domain
revision_failing_identity_and_laws() - WHEN the
fail_fast_orderingcheck runs - THEN
tiers_run == [identity] ∧ verdict == Reject
Rule: Exact tiers pure
The system SHALL satisfy exact_tiers_pure as defined in the Constraints table and the v1 format reference.
Acceptance case: Exact tiers ignore side inputs
- GIVEN the fixture domain
same_inputs_with_varied_clock_and_network() - WHEN the
exact_tiers_purecheck runs - THEN
verdict(a) == verdict(b)
Rule: Verdict lattice
The system SHALL satisfy verdict_lattice as defined in the Constraints table and the v1 format reference.
Acceptance case: Verdict lattice laws
- GIVEN the fixture domain
three_arbitrary_verdicts() - WHEN the
verdict_latticecheck runs - THEN identity:
meet(v, PassDeclared) == vassociativity:meet(meet(a, b), c) == meet(a, meet(b, c))
Rule: Policy names min tier
The system SHALL satisfy policy_names_min_tier as defined in the Constraints table and the v1 format reference.
Acceptance case: Below policy refused
- GIVEN the fixture domain
verdict_PassDeclared_under_policy_requiring_laws() - WHEN the
policy_names_min_tiercheck runs - THEN
decision == refused
Rule: Rejection explains
The system SHALL satisfy rejection_explains as defined in the Constraints table and the v1 format reference.
Acceptance case: Reject names rule
- GIVEN the fixture domain
arbitrary_rejected_revision() - WHEN the
rejection_explainscheck runs - THEN
report has tier ∧ slot_or_law ∧ rule
Rule: Laws cumulative
The system SHALL satisfy laws_cumulative as defined in the Constraints table and the v1 format reference.
Acceptance case: Ancestor law failure rejected
- GIVEN the fixture domain
revision_violating_an_ancestor_law() - WHEN the
laws_cumulativecheck runs - THEN
law_check == failed
Rule: Law runs deterministic
The system SHALL satisfy law_runs_deterministic as defined in the Constraints table and the v1 format reference.
Acceptance case: Law run reproducible
- GIVEN the fixture domain
(contract, impl, seed)run twice - WHEN the
law_runs_deterministiccheck runs - THEN
run(a) == run(b)
Rule: Evidence cannot override exact
The system SHALL satisfy evidence_cannot_override_exact as defined in the Constraints table and the v1 format reference.
Acceptance case: Evidence never overrides reject
- GIVEN the fixture domain
shape_Reject_plus_clean_traffic_replay() - WHEN the
evidence_cannot_override_exactcheck runs - THEN
verdict == Reject
Rule: Evidence confidence conservative
The system SHALL satisfy evidence_confidence_conservative as defined in the Constraints table and the v1 format reference.
Acceptance case: Confidence is minimum
- GIVEN the fixture domain
observations_with_confidences([0.99, 0.90]) - WHEN the
evidence_confidence_conservativecheck runs - THEN
confidence == 0.90
Rule: Contradiction triggers repair
The system SHALL satisfy contradiction_triggers_repair as defined in the Constraints table and the v1 format reference.
Acceptance case: Contradiction creates draft
- GIVEN the fixture domain
observed_behavior_outside_declared_contract() - WHEN the
contradiction_triggers_repaircheck runs - THEN
repair_draft_created ∧ contract_unchanged
Rule: Attestation scoped
The system SHALL satisfy attestation_scoped as defined in the Constraints table and the v1 format reference.
Acceptance case: Attestation without scope rejected
- GIVEN the fixture domain
attestation_missing_scope() - WHEN the
attestation_scopedcheck runs - THEN
check(a) == failed
Rule: Attestation expiring
The system SHALL satisfy attestation_expiring as defined in the Constraints table and the v1 format reference.
Acceptance case: Expired attestation is unknown
- GIVEN the fixture domain
attestation_with_past_expiry() - WHEN the
attestation_expiringcheck runs - THEN
attestation_status(a) == Unknown ∧ independent_assurance unchanged
Rule: Verdict cache keyed
The system SHALL satisfy verdict_cache_keyed as defined in the Constraints table and the v1 format reference.
Acceptance case: Cache key includes checker
- GIVEN the fixture domain
same_pair_under_two_checker_versions() - WHEN the
verdict_cache_keyedcheck runs - THEN
keys differ ∧ no cross-hit
Rule: Verdict recorded immutable
The system SHALL satisfy verdict_recorded_immutable as defined in the Constraints table and the v1 format reference.
Acceptance case: Recorded verdict unchanged
- GIVEN the fixture domain
verdict_recorded_then_rerun_under_new_checker() - WHEN the
verdict_recorded_immutablecheck runs - THEN
old record unchanged ∧ new record appended
Acceptance case: Same contract different implementation requires new law checks
- GIVEN two implementation artifacts have the same contract hash but different bytes
- WHEN a law result cached for the first artifact is requested for the second
- THEN the law cache misses and policy cannot reuse the first acceptance
Acceptance case: Expiry preserves independent structural checks
- GIVEN a valid PassDeclared binding has an attestation expiring at 2026-10-06T15:00:00Z
- WHEN evaluation occurs exactly at that timestamp
- THEN attestation status is Unknown; structural assurance remains PassDeclared; policy requiring attestation refuses
Acceptance case: Timeout never becomes law pass
- GIVEN a required sampled law reaches its resource budget without completing
- WHEN the harness returns a result
- THEN status is inconclusive and policy refuses
Acceptance case: Version claim cannot satisfy structural policy
- GIVEN an uncontracted dependency has only a patch version label
- WHEN policy requires PassDeclared
- THEN the label remains metadata, assurance is Unknown, and policy refuses
Requirements
Requirement: Wild tiers design contract
The design corpus SHALL expose this capability’s constraints as normative, self-contained rules with acceptance cases, and SHALL link to a structurally valid shared v1 schema without claiming future runtime behavior is implemented.
Scenario: Wild tiers design is self-contained
- GIVEN this spec,
docs/wild-formats-v1.md, andschemas/wild-v1.schema.json - WHEN the design contract gate checks normative rule coverage, local references, and the shared schema
- THEN every constraint has a corresponding rule and acceptance case
- AND both referenced files exist and the schema is valid JSON Schema draft 2020-12
- AND this capability is discoverable by strict OpenSpec validation
Requirement: Protected local checking context
An enforced local check SHALL receive its base, obligations, scope, policy, checker, test/law harnesses, environment, fixtures, budgets, and evaluation time from a trusted invocation outside candidate control. Candidate-proposed changes SHALL be evaluated against the accepted context first. An authorized obligation transition SHALL bind old/new commitments and be labelled intentional change rather than backward compatibility.
Scenario: Candidate edits its own judge
- GIVEN a candidate deletes a law, narrows demand, or changes the policy or checker
- WHEN trusted enforcement evaluates the candidate
- THEN it retains the accepted context, reports the proposed change, and cannot accept by using the weaker candidate settings
Scenario: Authorized bug-fix changes an old obligation
- GIVEN an external authority record accepts a named old-to-new obligation transition for a bug fix
- WHEN the candidate passes the replacement requirements and unchanged obligations
- THEN its disposition is accepted intentional change with affected consumers recorded, not backward-compatible success
Requirement: Evidence is bound and method labelled
Local evidence SHALL bind actual implementation and harness bytes, suite, fixtures, environment, scope, seed, and budgets. Current policy SHALL be evaluated afresh. Ordinary build/test success SHALL NOT become structural assurance or a v1 law result without the required harness guarantees. A sandbox that cannot enforce required restrictions SHALL yield inconclusive law evidence.
Scenario: Same contract but changed implementation
- GIVEN an implementation changes bytes without changing its extracted contract
- WHEN checking considers a previous executable law result
- THEN that evidence cannot satisfy the new artifact’s law requirement
Scenario: Unsupported law isolation
- GIVEN the available runner cannot prevent an accepted law from reading ambient files or the network
- WHEN that law is required by policy
- THEN its result is inconclusive and the local outcome is unknown unless another definite failure already requires rejection
wild-compose
id: wild.compose kind: intent statement: THE wild composer SHALL decide whether components at given revisions compose into a well-formed assembly, select revisions by deterministic lineage lookup within the supported model, and emit a certificate an independent verifier can re-check.
Wild compose
Purpose
This is a normative design specification; only the prototype and corpus gate scenarios explicitly identified below are implemented. Shared wire formats and decision rules are defined in wild v1 formats and the v1 schema.
An assembly is components plus bindings from required slots to provided slots. It is well-formed when every required slot is bound by a compatible provide. Substituting a component by an accretion of itself preserves well-formedness, which is what makes resolution a lookup instead of a search. Verdicts carry certificates that a separate verifier checks from content hashes.
Constraints
| id | kind | expr | traces_to |
|---|---|---|---|
| assembly_is_bindings | invariant | an assembly is a set of component revisions plus bindings from each required slot to a provided slot | [[wild.compose]] |
| binding_well_formed | invariant | a binding is well-formed iff the v1 subtype relation holds for provider output and consumer input, limits and defaults satisfy demand, and facets and relations pass; an open provider sum binds only to an open consumer | [[wild.compose]] |
| required_slots_bound | invariant | every required input of every component is bound by a well-formed binding | [[wild.compose]] |
| substitution_preserves_assembly | invariant | replacing a component with an accretion of itself keeps a well-formed assembly well-formed | [[wild.compose]] |
| scoped_substitution | invariant | scoped replacement preserves every demanded output AND validates all required inputs of the replacement and its transitive dependency closure; restricting demand never hides newly introduced required inputs | [[wild.compose]] |
| resolution_by_lineage | invariant | for a finite registry snapshot with one accepted tip per lineage, resolve traverses dependency closure using deterministic newest-tip lookup; missing tips, unmerged forks, singleton conflicts, or relation failures refuse selection without backtracking; dependency cycles reach a fixed point and are checked as a whole | [[wild.compose]] |
| resolver_deterministic | invariant | the same registry snapshot and demand yield the same selection and certificate | [[wild.compose]] |
| lineage_copies_listed | invariant | when consumers demand different lineages of one package, each lineage is resolved separately and the copies are listed | [[wild.compose]] |
| scoped_merge_proposed | invariant | a consumer may be proposed a newer lineage when its demand accretes there; the move is a proposal and is never applied automatically | [[wild.compose]] |
| boundary_needs_adapter | invariant | values crossing between lineages need a registered adapter; otherwise the boundary is reported unbridged | [[wild.compose]] |
| singleton_declared | invariant | a component declared singleton appears under exactly one lineage per assembly; a violation is a composition failure | [[wild.compose]] |
| relation_slots | invariant | v1 equal and less_equal relations over declared scalar slots are checked after closure; missing values, incomparable types, and failed relations refuse composition; the resolver does not search older revisions to satisfy relations | [[wild.compose]] |
| certificate_lists_bindings | invariant | the v1 certificate names the assembly commitment, component instances, bindings, demanded slots, policy, checker, and content-addressed proof records; the bundle contains every referenced contract and proof | [[wild.compose]] |
| certificate_complete | invariant | verification compares the certificate assembly hash to the caller-supplied expected commitment, reconstructs closure from all component manifests, and rejects missing roots, components, demands, or required bindings | [[wild.compose]] |
| certificate_tamper_evident | invariant | a corrupted hash or dropped binding fails verification; a substituted provider verifies only if it is compatible with the consumer's demand | [[wild.compose]] |
| verifier_reads_only_certificate | invariant | the verifier reads the v1 bundle, caller-supplied assembly commitment, policy, trust roots, and evaluation time; it never calls the resolver or network | [[wild.compose]] |
| verification_linear | advisory | verification performs O(B + S + P) indexed visits over bindings B, reachable contract/schema nodes S, and proof bytes P, excluding explicitly budgeted proof execution; benchmarking reports all three sizes and checker version | [[wild.compose]] |
| coverage_reported | invariant | a composition verdict reports the share of bindings verified per tier; bindings to uncontracted providers are Unknown | [[wild.compose]] |
| verdict_is_meet | invariant | assembly structural assurance is the meet of binding assurance; required law, evidence, and attestation policy is evaluated for every binding; empty assemblies have PassDeclared assurance and vacuous coverage | [[wild.compose]] |
| composition_is_category | invariant | compose is disjoint union of component instances and bindings with matching exposed interfaces; it is defined only when bindings, singleton constraints, and relations pass; empty assembly is identity and associativity holds where both sides are defined | [[wild.compose]] |
Model
States
demandedresolvedcertifiedverifiedunbridgedrefused
Transitions
| id | from | to | guard |
|---|---|---|---|
| resolve | demanded | resolved | [[wild.compose.resolution_by_lineage]] ∧ [[wild.compose.resolver_deterministic]] |
| certify | resolved | certified | [[wild.compose.certificate_lists_bindings]] |
| verify | certified | verified | [[wild.compose.certificate_complete]] ∧ [[wild.compose.verifier_reads_only_certificate]] |
| flag_boundary | resolved | unbridged | [[wild.compose.boundary_needs_adapter]] |
| bridge | unbridged | certified | [[wild.compose.certificate_lists_bindings]] ∧ requires a wild-bridge adapter_is_morphism |
| refuse_unbound | resolved | refused | [[wild.compose.required_slots_bound]] |
| refuse_invalid | certified | refused | [[wild.compose.binding_well_formed]] |
Properties
| id | kind | derives_from | generator | predicate |
|---|---|---|---|---|
| assembly_lists_every_binding | unit | [[wild.compose.assembly_is_bindings]] | arbitrary_assembly() | bindings cover all required slots |
| open_provider_needs_open_consumer | unit | [[wild.compose.binding_well_formed]] | open_provider_sum_bound_to_closed_consumer() | well_formed == false |
| unbound_required_slot_rejected | unit | [[wild.compose.required_slots_bound]] | assembly_with_one_unbound_required_input() | well_formed == false |
| accretion_substitution_sound | unit | [[wild.compose.substitution_preserves_assembly]] | well_formed_assembly_and_accepted_accretion() | well_formed(after) == true |
| scoped_substitution_sound | unit | [[wild.compose.scoped_substitution]] | assembly_and_change_accreting_on_used_slots() | well_formed(after) == true |
| resolution_is_chain_max | unit | [[wild.compose.resolution_by_lineage]] | finite_snapshot_with_unique_tips_and_demand() | selection == accepted tips ∧ backtracking_nodes == 0 or refusal lists violated constraints |
| resolution_reproducible | unit | [[wild.compose.resolver_deterministic]] | same_snapshot_resolved_twice() | selection(a) == selection(b) ∧ cert(a) == cert(b) |
| copies_are_listed | unit | [[wild.compose.lineage_copies_listed]] | consumers_on_two_lineages_of_one_package() | report lists both copies |
| merge_is_a_proposal | unit | [[wild.compose.scoped_merge_proposed]] | consumer_whose_demand_accretes_in_newer_lineage() | proposal listed ∧ selection unchanged |
| unbridged_boundary_reported | unit | [[wild.compose.boundary_needs_adapter]] | value_crossing_lineages_without_adapter() | status == unbridged |
| second_lineage_of_singleton_fails | unit | [[wild.compose.singleton_declared]] | singleton_resolved_under_two_lineages() | composition == failed |
| timeout_relation_checked | unit | [[wild.compose.relation_slots]] | backend_idle_timeout_below_balancer_timeout() | composition == failed |
| certificate_names_all_fields | unit | [[wild.compose.certificate_lists_bindings]] | arbitrary_certificate() | each binding has consumer ∧ provider ∧ demand |
| missing_binding_rejected | unit | [[wild.compose.certificate_complete]] | certificate_with_one_binding_dropped() | verify == rejected |
| corruption_detected | unit | [[wild.compose.certificate_tamper_evident]] | certificate_with_last_hash_digit_changed() | verify == rejected |
| verifier_has_no_resolver_dependency | unit | [[wild.compose.verifier_reads_only_certificate]] | verifier_module_dependency_graph() | no edge to resolver |
| verification_cost_linear | unit | [[wild.compose.verification_linear]] | certificates_of_size([100, 1000, 10000]) | indexed visits ≤ k * (bindings + schema_nodes + proof_bytes) for recorded checker constant k |
| uncontracted_binding_is_unknown | unit | [[wild.compose.coverage_reported]] | assembly_with_one_uncontracted_provider() | binding.verdict == Unknown ∧ coverage lists it |
| verdict_equals_meet | unit | [[wild.compose.verdict_is_meet]] | bindings_with_mixed_verdicts() | assembly.assurance == meet(binding.assurance) ∧ policy checks each binding |
| assembly_composition_laws | law | [[wild.compose.composition_is_category]] | three_assemblies_with_jointly_compatible_interfaces() | identity: compose(empty, a) == a associativity: compose(compose(a, b), c) == compose(a, compose(b, c)) |
Notes
Simulation evidence (toy model, assumed parameters): 30,000 random four-component assemblies, 10,215 accepted accretions, zero assemblies broken by substitution; 22% of changes rejected by the full check were harmless to the specific assembly, which is the case for scoped_substitution. In a synthetic ecosystem (30 packages, 8 versions each), lineage resolution broke zero dependencies and needed no search, while a single-version semver resolver found no solution in 16.5% to 99% of cases depending on break rate and mislabelling. With truthful labels, lineage resolution and semver-with-duplicates coincide, so the contribution is machine-checked labels. A verifier re-checked about 41 bindings per assembly in about 1 ms and rejected all 750 corrupted-hash and 750 dropped-binding certificates.
Known limits: the wiring rule was tightened after the first run found 21 unsound cases involving open sums; that is a model decision, recorded in binding_well_formed. Assemblies in the tests had four components and four names (small-scope).
Design acceptance cases
These cases define future runtime behavior. They are not claims that the current prototypes implement the v1 protocol. Executable document and prototype gates are under Requirements.
Rule: Assembly is bindings
The system SHALL satisfy assembly_is_bindings as defined in the Constraints table and the v1 format reference.
Acceptance case: Assembly lists every binding
- GIVEN the fixture domain
arbitrary_assembly() - WHEN the
assembly_is_bindingscheck runs - THEN
bindings cover all required slots
Rule: Binding well formed
The system SHALL satisfy binding_well_formed as defined in the Constraints table and the v1 format reference.
Acceptance case: Open provider needs open consumer
- GIVEN the fixture domain
open_provider_sum_bound_to_closed_consumer() - WHEN the
binding_well_formedcheck runs - THEN
well_formed == false
Rule: Required slots bound
The system SHALL satisfy required_slots_bound as defined in the Constraints table and the v1 format reference.
Acceptance case: Unbound required slot rejected
- GIVEN the fixture domain
assembly_with_one_unbound_required_input() - WHEN the
required_slots_boundcheck runs - THEN
well_formed == false
Rule: Substitution preserves assembly
The system SHALL satisfy substitution_preserves_assembly as defined in the Constraints table and the v1 format reference.
Acceptance case: Accretion substitution sound
- GIVEN the fixture domain
well_formed_assembly_and_accepted_accretion() - WHEN the
substitution_preserves_assemblycheck runs - THEN
well_formed(after) == true
Rule: Scoped substitution
The system SHALL satisfy scoped_substitution as defined in the Constraints table and the v1 format reference.
Acceptance case: Scoped substitution sound
- GIVEN the fixture domain
assembly_and_change_accreting_on_used_slots() - WHEN the
scoped_substitutioncheck runs - THEN
well_formed(after) == true
Rule: Resolution by lineage
The system SHALL satisfy resolution_by_lineage as defined in the Constraints table and the v1 format reference.
Acceptance case: Resolution is chain max
- GIVEN the fixture domain
finite_snapshot_with_unique_tips_and_demand() - WHEN the
resolution_by_lineagecheck runs - THEN
selection == accepted tips ∧ backtracking_nodes == 0 or refusal lists violated constraints
Rule: Resolver deterministic
The system SHALL satisfy resolver_deterministic as defined in the Constraints table and the v1 format reference.
Scope reconciliation: registry-mode newest-tip selection is retained unchanged; local validation accepts a host-selected pinned assembly and makes no newest-tip claim.
Acceptance case: Resolution reproducible
- GIVEN the fixture domain
same_snapshot_resolved_twice() - WHEN the
resolver_deterministiccheck runs - THEN
selection(a) == selection(b) ∧ cert(a) == cert(b)
Rule: Lineage copies listed
The system SHALL satisfy lineage_copies_listed as defined in the Constraints table and the v1 format reference.
Acceptance case: Copies are listed
- GIVEN the fixture domain
consumers_on_two_lineages_of_one_package() - WHEN the
lineage_copies_listedcheck runs - THEN
report lists both copies
Rule: Scoped merge proposed
The system SHALL satisfy scoped_merge_proposed as defined in the Constraints table and the v1 format reference.
Acceptance case: Merge is a proposal
- GIVEN the fixture domain
consumer_whose_demand_accretes_in_newer_lineage() - WHEN the
scoped_merge_proposedcheck runs - THEN
proposal listed ∧ selection unchanged
Rule: Boundary needs adapter
The system SHALL satisfy boundary_needs_adapter as defined in the Constraints table and the v1 format reference.
Acceptance case: Unbridged boundary reported
- GIVEN the fixture domain
value_crossing_lineages_without_adapter() - WHEN the
boundary_needs_adaptercheck runs - THEN
status == unbridged
Rule: Singleton declared
The system SHALL satisfy singleton_declared as defined in the Constraints table and the v1 format reference.
Acceptance case: Second lineage of singleton fails
- GIVEN the fixture domain
singleton_resolved_under_two_lineages() - WHEN the
singleton_declaredcheck runs - THEN
composition == failed
Rule: Relation slots
The system SHALL satisfy relation_slots as defined in the Constraints table and the v1 format reference.
Acceptance case: Timeout relation checked
- GIVEN the fixture domain
backend_idle_timeout_below_balancer_timeout() - WHEN the
relation_slotscheck runs - THEN
composition == failed
Rule: Certificate lists bindings
The system SHALL satisfy certificate_lists_bindings as defined in the Constraints table and the v1 format reference.
Acceptance case: Certificate names all fields
- GIVEN the fixture domain
arbitrary_certificate() - WHEN the
certificate_lists_bindingscheck runs - THEN
each binding has consumer ∧ provider ∧ demand
Rule: Certificate complete
The system SHALL satisfy certificate_complete as defined in the Constraints table and the v1 format reference.
Acceptance case: Missing binding rejected
- GIVEN the fixture domain
certificate_with_one_binding_dropped() - WHEN the
certificate_completecheck runs - THEN
verify == rejected
Rule: Certificate tamper evident
The system SHALL satisfy certificate_tamper_evident as defined in the Constraints table and the v1 format reference.
Acceptance case: Corruption detected
- GIVEN the fixture domain
certificate_with_last_hash_digit_changed() - WHEN the
certificate_tamper_evidentcheck runs - THEN
verify == rejected
Rule: Verifier reads only certificate
The system SHALL satisfy verifier_reads_only_certificate as defined in the Constraints table and the v1 format reference.
Acceptance case: Verifier has no resolver dependency
- GIVEN the fixture domain
verifier_module_dependency_graph() - WHEN the
verifier_reads_only_certificatecheck runs - THEN
no edge to resolver
Rule: Verification linear
The system SHALL satisfy verification_linear as defined in the Constraints table and the v1 format reference.
Acceptance case: Verification cost linear
- GIVEN the fixture domain
certificates_of_size([100, 1000, 10000]) - WHEN the
verification_linearcheck runs - THEN
indexed visits ≤ k * (bindings + schema_nodes + proof_bytes) for recorded checker constant k
Rule: Coverage reported
The system SHALL satisfy coverage_reported as defined in the Constraints table and the v1 format reference.
Acceptance case: Uncontracted binding is unknown
- GIVEN the fixture domain
assembly_with_one_uncontracted_provider() - WHEN the
coverage_reportedcheck runs - THEN
binding.verdict == Unknown ∧ coverage lists it
Rule: Verdict is meet
The system SHALL satisfy verdict_is_meet as defined in the Constraints table and the v1 format reference.
Acceptance case: Verdict equals meet
- GIVEN the fixture domain
bindings_with_mixed_verdicts() - WHEN the
verdict_is_meetcheck runs - THEN
assembly.assurance == meet(binding.assurance) ∧ policy checks each binding
Rule: Composition is category
The system SHALL satisfy composition_is_category as defined in the Constraints table and the v1 format reference.
Acceptance case: Assembly composition laws
- GIVEN the fixture domain
three_assemblies_with_jointly_compatible_interfaces() - WHEN the
composition_is_categorycheck runs - THEN identity:
compose(empty, a) == aassociativity:compose(compose(a, b), c) == compose(a, compose(b, c))
Acceptance case: Scoped change adds an unbound dependency
- GIVEN the replacement preserves demanded output a and introduces required input b
- WHEN scoped substitution evaluates the replacement closure
- THEN it refuses when b has no compatible provider
Acceptance case: Deleting a root subtree changes the commitment
- GIVEN the caller supplies the expected assembly hash for roots a and b
- WHEN a certificate omits root b and its entire subtree
- THEN verification refuses the commitment mismatch before evaluating bindings
Acceptance case: Missing proof cannot establish law assurance
- GIVEN a policy requires a law result whose implementation blob is absent
- WHEN offline verification evaluates the bundle
- THEN it reports Unknown or inconclusive and refuses that policy, without network access
Acceptance case: Empty assembly coverage is vacuous
- GIVEN an assembly has no roots, components, or bindings
- WHEN composition runs
- THEN assurance is PassDeclared; coverage is 0/0 with null ratio
Acceptance case: Unmerged forks do not have a newest revision
- GIVEN two accepted fork tips are incomparable
- WHEN lineage lookup runs
- THEN it refuses with both tip hashes until an explicit accretive merge is recorded
Acceptance case: Relation failure does not trigger hidden search
- GIVEN the accepted tips violate a declared timeout relation but older revisions would pass
- WHEN resolution completes closure and checks relations
- THEN it refuses with the relation id; no older candidate is selected
Requirements
Requirement: Wild compose design contract
The design corpus SHALL expose this capability’s constraints as normative, self-contained rules with acceptance cases, and SHALL link to a structurally valid shared v1 schema without claiming future runtime behavior is implemented.
Scenario: Wild compose design is self-contained
- GIVEN this spec,
docs/wild-formats-v1.md, andschemas/wild-v1.schema.json - WHEN the design contract gate checks normative rule coverage, local references, and the shared schema
- THEN every constraint has a corresponding rule and acceptance case
- AND both referenced files exist and the schema is valid JSON Schema draft 2020-12
- AND this capability is discoverable by strict OpenSpec validation
Requirement: Validate a host-selected local assembly
Local update evaluation SHALL validate the explicit assembly selected by the host lock rather than invoke registry newest-tip selection. It SHALL account for all roots, components, required inputs, transitive dependencies, declared singletons, and relations using existing v1 structural rules. Unknown entries SHALL remain in coverage and SHALL refuse policies requiring complete structure. The local report SHALL NOT claim native registry ancestry or constitute a v1 registry certificate.
Scenario: New provider dependency is not hidden by demand restriction
- GIVEN a candidate preserves the consumer’s demanded output but adds an unsatisfied required dependency
- WHEN the host-selected assembly is checked
- THEN delivery is refused even though the root’s demanded output signature is unchanged
Scenario: Unknown dependency remains visible
- GIVEN the lock contains a required dependency with no usable contract
- WHEN the local assembly is evaluated under policy requiring declared structure
- THEN that entry remains in the closure and coverage with Unknown assurance and delivery is refused
Scenario: Local pin does not claim newest lineage tip
- GIVEN a valid explicitly pinned host assembly and no Wild registry
- WHEN local structural checking succeeds
- THEN the report identifies its local scope and makes no registry-tip or publication claim
wild-registry
id: wild.registry kind: intent statement: THE wild registry SHALL record revisions in an append-only, signed, auditable log and bind them to host ecosystem artifacts without altering those artifacts.
Wild registry
Purpose
This is a normative design specification; only the prototype and corpus gate scenarios explicitly identified below are implemented. Shared wire formats and decision rules are defined in wild v1 formats and the v1 schema.
The shared memory of the system: a authenticated hash-chained log with full v1 prefix proofs of signed revisions, adapters, advisories, and attestations. Consumers pin hashes from it. Host ecosystems (npm, Cargo, PyPI, Maven, containers) are never modified; a sidecar record ties a host artifact digest to a revision hash.
Constraints
| id | kind | expr | traces_to |
|---|---|---|---|
| registry_append_only | invariant | the registry is a authenticated hash-chained log with full v1 prefix proofs; no revision is deleted or mutated after append | [[wild.registry]] |
| consistency_proofs | invariant | any two log heads can be checked for consistency by a proof, so a mirror can be audited | [[wild.registry]] |
| signature_required | invariant | every submitted revision carries a signature by the lineage owner key | [[wild.registry]] |
| namespace_ownership | invariant | each authority-qualified lineage name maps to one active owner key at a log sequence; bootstrap requires a trusted namespace authority signature and public names never shadow a configured private authority | [[wild.registry]] |
| key_rotation_signed | invariant | normal key rotation requires outgoing and incoming key signatures; compromise recovery requires the recovery key designated at namespace bootstrap, revokes the compromised key at an explicit sequence, and never rewrites historical entries | [[wild.registry]] |
| lock_pins_hashes | invariant | every contracted v1 lock entry pins authority, lineage, contract hash, and artifact digest; unresolved host entries preserve their locator with Unknown status; tags and aliases are not identities | [[wild.registry]] |
| sidecar_binds_artifact_digest | invariant | a signed v1 sidecar binds host ecosystem, artifact locator, artifact digest, contract hash, extractor digest, and registry sequence; fetching bytes with a different artifact digest is rejected even if the contract is unchanged | [[wild.registry]] |
| ecosystem_untouched | invariant | wild never replaces or mutates the host ecosystem's package, tag, or version; it adds a sidecar record | [[wild.registry]] |
| advisories_never_delete | invariant | yanking or flagging a revision appends an advisory edge; the revision stays resolvable by hash | [[wild.registry]] |
| retraction_only_experimental | invariant | experimental retraction appends a notice and removes the revision from new tip selection; hash lookup retains bytes and notice; stable retraction is refused; no candidate yields Unknown | [[wild.registry]] |
| mirror_equivalence | invariant | a mirror serving the same authenticated snapshot yields the same verdicts and certificates as the origin for identical caller policy, trust roots, and evaluation time | [[wild.registry]] |
| verification_needs_no_write | invariant | reading, resolving, and verifying never require write access to the registry | [[wild.registry]] |
Model
States
submittedsignedappendedadvisedretracted
Transitions
| id | from | to | guard |
|---|---|---|---|
| sign | submitted | signed | [[wild.registry.signature_required]] ∧ [[wild.registry.namespace_ownership]] |
| append | signed | appended | [[wild.registry.registry_append_only]] |
| advise | appended | advised | [[wild.registry.advisories_never_delete]] |
| retract | appended | retracted | [[wild.registry.retraction_only_experimental]] ∧ per wild-core stability_tiers |
Properties
| id | kind | derives_from | generator | predicate |
|---|---|---|---|---|
| rewrite_of_appended_rejected | unit | [[wild.registry.registry_append_only]] | log_with_attempted_rewrite() | append(log, rewrite) == rejected |
| inconsistent_heads_detected | unit | [[wild.registry.consistency_proofs]] | two_heads_from_forked_logs() | consistency_check == failed |
| unsigned_revision_rejected | unit | [[wild.registry.signature_required]] | submission_without_signature() | sign == rejected |
| foreign_owner_rejected | unit | [[wild.registry.namespace_ownership]] | publish_to_lineage_with_different_key() | sign == rejected |
| rotation_needs_outgoing_key | unit | [[wild.registry.key_rotation_signed]] | rotation_signed_with_new_key_only() | rotation == rejected |
| alias_in_lock_rejected | unit | [[wild.registry.lock_pins_hashes]] | lockfile_entry_using_tag("latest") | check(lock) == failed |
| digest_mismatch_rejected | unit | [[wild.registry.sidecar_binds_artifact_digest]] | sidecar_pointing_at_a_different_artifact() | check(sidecar) == rejected |
| host_artifact_unchanged | unit | [[wild.registry.ecosystem_untouched]] | publish_with_wild_enabled() | host_artifact(before) == host_artifact(after) |
| yanked_revision_still_resolves | unit | [[wild.registry.advisories_never_delete]] | yanked_revision() | resolve_by_hash == found ∧ advisory attached |
| stable_retraction_rejected | unit | [[wild.registry.retraction_only_experimental]] | retract_request_on_stable_lineage() | retract == rejected |
| mirror_matches_origin | unit | [[wild.registry.mirror_equivalence]] | same_log_served_by_origin_and_mirror() | verdicts(origin) == verdicts(mirror) |
| read_only_credentials_suffice | unit | [[wild.registry.verification_needs_no_write]] | resolve_and_verify_with_read_only_access() | completes |
Notes
Failure cases behind this spec: left-pad (an unpublished artifact broke builds), mutable tags (a repointed action tag), dependency confusion (public names shadowing internal ones), and signing-key rotation breaking installs. Registry ownership of names is a governance problem the tool can enforce but not solve (typosquatting remains out of scope).
Design acceptance cases
These cases define future runtime behavior. They are not claims that the current prototypes implement the v1 protocol. Executable document and prototype gates are under Requirements.
Rule: Registry append only
The system SHALL satisfy registry_append_only as defined in the Constraints table and the v1 format reference.
Acceptance case: Rewrite of appended rejected
- GIVEN the fixture domain
log_with_attempted_rewrite() - WHEN the
registry_append_onlycheck runs - THEN
append(log, rewrite) == rejected
Rule: Consistency proofs
The system SHALL satisfy consistency_proofs as defined in the Constraints table and the v1 format reference.
Acceptance case: Inconsistent heads detected
- GIVEN the fixture domain
two_heads_from_forked_logs() - WHEN the
consistency_proofscheck runs - THEN
consistency_check == failed
Rule: Signature required
The system SHALL satisfy signature_required as defined in the Constraints table and the v1 format reference.
Acceptance case: Unsigned revision rejected
- GIVEN the fixture domain
submission_without_signature() - WHEN the
signature_requiredcheck runs - THEN
sign == rejected
Rule: Namespace ownership
The system SHALL satisfy namespace_ownership as defined in the Constraints table and the v1 format reference.
Acceptance case: Foreign owner rejected
- GIVEN the fixture domain
publish_to_lineage_with_different_key() - WHEN the
namespace_ownershipcheck runs - THEN
sign == rejected
Rule: Key rotation signed
The system SHALL satisfy key_rotation_signed as defined in the Constraints table and the v1 format reference.
Acceptance case: Rotation needs outgoing key
- GIVEN the fixture domain
rotation_signed_with_new_key_only() - WHEN the
key_rotation_signedcheck runs - THEN
rotation == rejected
Rule: Lock pins hashes
The system SHALL satisfy lock_pins_hashes as defined in the Constraints table and the v1 format reference.
Acceptance case: Alias in lock rejected
- GIVEN the fixture domain
lockfile_entry_using_tag("latest") - WHEN the
lock_pins_hashescheck runs - THEN
check(lock) == failed
Rule: Sidecar binds artifact digest
The system SHALL satisfy sidecar_binds_artifact_digest as defined in the Constraints table and the v1 format reference.
Acceptance case: Digest mismatch rejected
- GIVEN the fixture domain
sidecar_pointing_at_a_different_artifact() - WHEN the
sidecar_binds_artifact_digestcheck runs - THEN
check(sidecar) == rejected
Rule: Ecosystem untouched
The system SHALL satisfy ecosystem_untouched as defined in the Constraints table and the v1 format reference.
Acceptance case: Host artifact unchanged
- GIVEN the fixture domain
publish_with_wild_enabled() - WHEN the
ecosystem_untouchedcheck runs - THEN
host_artifact(before) == host_artifact(after)
Rule: Advisories never delete
The system SHALL satisfy advisories_never_delete as defined in the Constraints table and the v1 format reference.
Acceptance case: Yanked revision still resolves
- GIVEN the fixture domain
yanked_revision() - WHEN the
advisories_never_deletecheck runs - THEN
resolve_by_hash == found ∧ advisory attached
Rule: Retraction only experimental
The system SHALL satisfy retraction_only_experimental as defined in the Constraints table and the v1 format reference.
Acceptance case: Stable retraction rejected
- GIVEN the fixture domain
retract_request_on_stable_lineage() - WHEN the
retraction_only_experimentalcheck runs - THEN
retract == rejected
Rule: Mirror equivalence
The system SHALL satisfy mirror_equivalence as defined in the Constraints table and the v1 format reference.
Acceptance case: Mirror matches origin
- GIVEN the fixture domain
same_log_served_by_origin_and_mirror() - WHEN the
mirror_equivalencecheck runs - THEN
verdicts(origin) == verdicts(mirror)
Rule: Verification needs no write
The system SHALL satisfy verification_needs_no_write as defined in the Constraints table and the v1 format reference.
Acceptance case: Read only credentials suffice
- GIVEN the fixture domain
resolve_and_verify_with_read_only_access() - WHEN the
verification_needs_no_writecheck runs - THEN
completes
Acceptance case: Private namespace cannot be shadowed
- GIVEN a lock pins authority private.example and lineage acme.billing
- WHEN a public registry publishes the same lineage spelling
- THEN resolution retains the pinned authority and refuses public substitution
Acceptance case: Recovery follows the predesignated key
- GIVEN the owner key is compromised and a recovery key was designated at bootstrap
- WHEN a replacement key is submitted without outgoing-owner authorization
- THEN it is accepted only through the authenticated recovery entry; forged recovery refuses
Acceptance case: Retraction preserves pinned bytes
- GIVEN an experimental tip is retracted
- WHEN a pinned hash is read and a new unconstrained lookup runs
- THEN hash lookup returns bytes and notice; new lookup excludes the retracted tip and returns Unknown if no candidate exists
Requirements
Requirement: Wild registry design contract
The design corpus SHALL expose this capability’s constraints as normative, self-contained rules with acceptance cases, and SHALL link to a structurally valid shared v1 schema without claiming future runtime behavior is implemented.
Scenario: Wild registry design is self-contained
- GIVEN this spec,
docs/wild-formats-v1.md, andschemas/wild-v1.schema.json - WHEN the design contract gate checks normative rule coverage, local references, and the shared schema
- THEN every constraint has a corresponding rule and acceptance case
- AND both referenced files exist and the schema is valid JSON Schema draft 2020-12
- AND this capability is discoverable by strict OpenSpec validation
wild-bridge
id: wild.bridge kind: intent statement: THE wild bridge SHALL connect incompatible lineages through checked adapters and SHALL describe uncontracted third-party software through labelled overlays, without raising its verdict above what was evidenced.
Wild bridge
Purpose
This is a normative design specification; only the prototype and corpus gate scenarios explicitly identified below are implemented. Shared wire formats and decision rules are defined in wild v1 formats and the v1 schema.
Where accretion ends, adapters begin. A break ships as a new lineage plus an explicitly directed adapter when one can be built; adapters are morphisms that compose, declare what they lose, and pass round-trip laws. Third-party software without contracts is handled by overlays, tests-as-laws, and legacy version claims recorded at the weakest tier.
Constraints
| id | kind | expr | traces_to |
|---|---|---|---|
| break_requires_adapter | invariant | a new lineage derived from an old one declares either registered directed adapters or unbridged status with a reason; publication of an unbridged lineage is allowed, but demanded cross-lineage boundaries without adapters refuse composition | [[wild.bridge]] |
| adapter_is_morphism | invariant | an adapter names source and target revision hashes and its artifact digest; A → B followed by B → C composes to A → C; identity and associativity hold for the declared mappings and observable equivalence | [[wild.bridge]] |
| adapter_composition_coherent | invariant | a composed adapter and any direct adapter must agree on the recorded law-suite domain modulo declared loss; a counterexample refuses coherence, and sample agreement is labelled sampled rather than universal equality | [[wild.bridge]] |
| adapter_loss_declared | invariant | every adapter declares lossless or lists the slots it loses | [[wild.bridge]] |
| adapter_round_trip_law | invariant | a lossless adapter declares a reverse adapter and round-trip equality on its declared domain in both directions; validation labels proof, exhaustive, or sampled coverage and never promotes samples to universal losslessness | [[wild.bridge]] |
| unknown_fields_preserved | invariant | read-modify-write preserves unknown slots as opaque payloads except losses explicitly enumerated in a lossy adapter; a consumer requiring any declared lost slot refuses that adapter | [[wild.bridge]] |
| adapter_draft_generated | invariant | adapt(old, new) emits a draft covering every derivable mapping and a TODO for each slot it cannot derive | [[wild.bridge]] |
| adapter_validated_on_samples | invariant | a draft adapter is publishable only when all mappings are resolved, losses and law method are declared, and its required validation suite passes; unresolved mappings are not publishable | [[wild.bridge]] |
| adapter_forms_closed | invariant | adapter form ∈ {facade_library, wire_proxy, data_upcaster, component_wrapper}; adding a form requires a new wire schema version | [[wild.bridge]] |
| opt_in_cross_lineage | invariant | a consumer whose demand accretes in a newer lineage may adopt it without an adapter; adoption is opt-in per consumer | [[wild.bridge]] |
| overlay_contracts | invariant | a consumer may publish an overlay contract for an uncontracted upstream, bound to the upstream's artifact digest and labelled inferred | [[wild.bridge]] |
| inferred_is_conservative | invariant | inferred contracts report the observed domain and do not claim a complete upstream schema; known unsupported constructs are opaque and absent observations remain Unknown; observations alone cannot establish PassDeclared structural assurance | [[wild.bridge]] |
| legacy_semver_as_attestation | invariant | a legacy version bump is an unverified metadata claim unless its publisher signs a scoped, expiring v1 attestation; it never establishes structural or law assurance | [[wild.bridge]] |
| tests_are_default_laws | invariant | for an uncontracted upstream, the dependent's passing integration tests are recorded as laws of the dependent | [[wild.bridge]] |
| uncontracted_edges_unknown | invariant | an uncontracted edge has Unknown structural assurance; a digest-bound explicit overlay may establish declared assurance for covered slots, while tests add only method-labelled law evidence for their exercised domain | [[wild.bridge]] |
| standards_are_lineages | invariant | revisions of protocols and schemas published by standards bodies are lineages and are checked by the same accretion relation | [[wild.bridge]] |
Model
States
break_foundadapter_draftedadapter_validatedadapter_publishedconsumer_migrated
Transitions
| id | from | to | guard |
|---|---|---|---|
| draft_adapter | break_found | adapter_drafted | [[wild.bridge.adapter_draft_generated]] |
| validate | adapter_drafted | adapter_validated | [[wild.bridge.adapter_validated_on_samples]] ∧ [[wild.bridge.adapter_round_trip_law]] |
| publish_adapter | adapter_validated | adapter_published | [[wild.bridge.adapter_loss_declared]] ∧ [[wild.bridge.adapter_forms_closed]] |
| migrate | adapter_published | consumer_migrated | [[wild.bridge.opt_in_cross_lineage]] |
Properties
| id | kind | derives_from | generator | predicate |
|---|---|---|---|---|
| break_without_adapter_disclosed | unit | [[wild.bridge.break_requires_adapter]] | new_lineage_without_registered_adapter() | publish records unbridged ∧ cross_lineage_binding == refused |
| adapter_category_laws | law | [[wild.bridge.adapter_is_morphism]] | arbitrary_adapter_chain(length: 3) | identity: compose(id, a) == a associativity: compose(compose(a, b), c) == compose(a, compose(b, c)) |
| composed_matches_direct | unit | [[wild.bridge.adapter_composition_coherent]] | adapters_a_b_and_direct_ab_disagreeing() | check == failed ∧ mismatch reported |
| lossy_adapter_must_list_loss | unit | [[wild.bridge.adapter_loss_declared]] | adapter_with_dropped_slot_declared_lossless() | check == failed |
| lossless_needs_round_trip | unit | [[wild.bridge.adapter_round_trip_law]] | lossless_adapter_failing_round_trip() | validate == failed |
| round_trip_keeps_unknown_slots | unit | [[wild.bridge.unknown_fields_preserved]] | record_with_slots_outside_demand() | unknown_slots(after) == unknown_slots(before) minus explicitly accepted declared losses |
| draft_marks_underivable_slots | unit | [[wild.bridge.adapter_draft_generated]] | contract_pair_with_one_unmappable_slot() | draft has exactly one TODO |
| unvalidated_adapter_unpublishable | unit | [[wild.bridge.adapter_validated_on_samples]] | draft_adapter_failing_laws() | publish_adapter == rejected |
| unknown_adapter_form_rejected | unit | [[wild.bridge.adapter_forms_closed]] | adapter_declaring_form("magic") | check == failed |
| unaffected_consumer_adopts_unaided | unit | [[wild.bridge.opt_in_cross_lineage]] | break_in_slot_a_consumer_never_uses() | consumer_can_adopt == true ∧ adoption requires consent |
| overlay_is_labelled_inferred | unit | [[wild.bridge.overlay_contracts]] | overlay_for_uncontracted_upstream() | overlay.label == inferred ∧ overlay.digest == upstream.digest |
| unobserved_slots_are_opaque | unit | [[wild.bridge.inferred_is_conservative]] | traffic_covering_half_of_the_api() | coverage names observed domain ∧ unobserved domain == Unknown |
| semver_never_above_attestation | unit | [[wild.bridge.legacy_semver_as_attestation]] | dependency_without_contract_declaring_patch() | claim.source == legacy_version ∧ structural_assurance == Unknown |
| tests_become_laws | unit | [[wild.bridge.tests_are_default_laws]] | dependent_with_passing_integration_test_on_uncontracted_upstream() | dependent.laws includes the test |
| uncovered_edge_is_unknown | unit | [[wild.bridge.uncontracted_edges_unknown]] | edge_to_uncontracted_provider_without_overlay_or_law() | edge.assurance == Unknown |
| spec_revision_checked_like_package | unit | [[wild.bridge.standards_are_lineages]] | protocol_revision_that_removes_a_feature_added_in_the_prior_revision() | accretes == false |
Notes
Evidence behind this spec: simulation round 1 showed that a dependent with an integration law catches a mislabelled change in an uncontracted upstream, and one without such a law does not (hence tests_are_default_laws); consumers who never used a removed slot could adopt the new lineage unaided (hence opt_in_cross_lineage). Catalog cases: PodSecurityPolicy replacement and ISO 20022 translation (lossy adapters), unknown-field dropping on read-modify-write, and a protocol spec that removed a feature added one revision earlier.
Known limits: overlays and inferred contracts are only as good as their evidence; adapters between genuinely incompatible models (AngularJS to Angular) may be infeasible, in which case the break stays unbridged and is reported.
Design acceptance cases
These cases define future runtime behavior. They are not claims that the current prototypes implement the v1 protocol. Executable document and prototype gates are under Requirements.
Rule: Break requires adapter
The system SHALL satisfy break_requires_adapter as defined in the Constraints table and the v1 format reference.
Acceptance case: Break without adapter disclosed
- GIVEN the fixture domain
new_lineage_without_registered_adapter() - WHEN the
break_requires_adaptercheck runs - THEN
publish records unbridged ∧ cross_lineage_binding == refused
Rule: Adapter is morphism
The system SHALL satisfy adapter_is_morphism as defined in the Constraints table and the v1 format reference.
Acceptance case: Adapter category laws
- GIVEN the fixture domain
arbitrary_adapter_chain(length: 3) - WHEN the
adapter_is_morphismcheck runs - THEN identity:
compose(id, a) == aassociativity:compose(compose(a, b), c) == compose(a, compose(b, c))
Rule: Adapter composition coherent
The system SHALL satisfy adapter_composition_coherent as defined in the Constraints table and the v1 format reference.
Acceptance case: Composed matches direct
- GIVEN the fixture domain
adapters_a_b_and_direct_ab_disagreeing() - WHEN the
adapter_composition_coherentcheck runs - THEN
check == failed ∧ mismatch reported
Rule: Adapter loss declared
The system SHALL satisfy adapter_loss_declared as defined in the Constraints table and the v1 format reference.
Acceptance case: Lossy adapter must list loss
- GIVEN the fixture domain
adapter_with_dropped_slot_declared_lossless() - WHEN the
adapter_loss_declaredcheck runs - THEN
check == failed
Rule: Adapter round trip law
The system SHALL satisfy adapter_round_trip_law as defined in the Constraints table and the v1 format reference.
Acceptance case: Lossless needs round trip
- GIVEN the fixture domain
lossless_adapter_failing_round_trip() - WHEN the
adapter_round_trip_lawcheck runs - THEN
validate == failed
Rule: Unknown fields preserved
The system SHALL satisfy unknown_fields_preserved as defined in the Constraints table and the v1 format reference.
Acceptance case: Round trip keeps unknown slots
- GIVEN the fixture domain
record_with_slots_outside_demand() - WHEN the
unknown_fields_preservedcheck runs - THEN
unknown_slots(after) == unknown_slots(before) minus explicitly accepted declared losses
Rule: Adapter draft generated
The system SHALL satisfy adapter_draft_generated as defined in the Constraints table and the v1 format reference.
Acceptance case: Draft marks underivable slots
- GIVEN the fixture domain
contract_pair_with_one_unmappable_slot() - WHEN the
adapter_draft_generatedcheck runs - THEN
draft has exactly one TODO
Rule: Adapter validated on samples
The system SHALL satisfy adapter_validated_on_samples as defined in the Constraints table and the v1 format reference.
Acceptance case: Unvalidated adapter unpublishable
- GIVEN the fixture domain
draft_adapter_failing_laws() - WHEN the
adapter_validated_on_samplescheck runs - THEN
publish_adapter == rejected
Rule: Adapter forms closed
The system SHALL satisfy adapter_forms_closed as defined in the Constraints table and the v1 format reference.
Acceptance case: Unknown adapter form rejected
- GIVEN the fixture domain
adapter_declaring_form("magic") - WHEN the
adapter_forms_closedcheck runs - THEN
check == failed
Rule: Opt in cross lineage
The system SHALL satisfy opt_in_cross_lineage as defined in the Constraints table and the v1 format reference.
Acceptance case: Unaffected consumer adopts unaided
- GIVEN the fixture domain
break_in_slot_a_consumer_never_uses() - WHEN the
opt_in_cross_lineagecheck runs - THEN
consumer_can_adopt == true ∧ adoption requires consent
Rule: Overlay contracts
The system SHALL satisfy overlay_contracts as defined in the Constraints table and the v1 format reference.
Acceptance case: Overlay is labelled inferred
- GIVEN the fixture domain
overlay_for_uncontracted_upstream() - WHEN the
overlay_contractscheck runs - THEN
overlay.label == inferred ∧ overlay.digest == upstream.digest
Rule: Inferred is conservative
The system SHALL satisfy inferred_is_conservative as defined in the Constraints table and the v1 format reference.
Acceptance case: Unobserved slots are opaque
- GIVEN the fixture domain
traffic_covering_half_of_the_api() - WHEN the
inferred_is_conservativecheck runs - THEN
coverage names observed domain ∧ unobserved domain == Unknown
Rule: Legacy semver as attestation
The system SHALL satisfy legacy_semver_as_attestation as defined in the Constraints table and the v1 format reference.
Acceptance case: Semver never above attestation
- GIVEN the fixture domain
dependency_without_contract_declaring_patch() - WHEN the
legacy_semver_as_attestationcheck runs - THEN
claim.source == legacy_version ∧ structural_assurance == Unknown
Rule: Tests are default laws
The system SHALL satisfy tests_are_default_laws as defined in the Constraints table and the v1 format reference.
Acceptance case: Tests become laws
- GIVEN the fixture domain
dependent_with_passing_integration_test_on_uncontracted_upstream() - WHEN the
tests_are_default_lawscheck runs - THEN
dependent.laws includes the test
Rule: Uncontracted edges unknown
The system SHALL satisfy uncontracted_edges_unknown as defined in the Constraints table and the v1 format reference.
Acceptance case: Uncovered edge is unknown
- GIVEN the fixture domain
edge_to_uncontracted_provider_without_overlay_or_law() - WHEN the
uncontracted_edges_unknowncheck runs - THEN
edge.assurance == Unknown
Rule: Standards are lineages
The system SHALL satisfy standards_are_lineages as defined in the Constraints table and the v1 format reference.
Acceptance case: Spec revision checked like package
- GIVEN the fixture domain
protocol_revision_that_removes_a_feature_added_in_the_prior_revision() - WHEN the
standards_are_lineagescheck runs - THEN
accretes == false
Acceptance case: Infeasible adapter leaves a disclosed boundary
- GIVEN a new lineage cannot be adapted to its predecessor
- WHEN it is published with unbridged status and reason
- THEN publication succeeds but composition across the unbridged demanded boundary refuses
Acceptance case: Lossless requires both directions
- GIVEN an A to B adapter has no reverse mapping
- WHEN it claims lossless round-trip validation
- THEN validation refuses the incomplete claim
Acceptance case: Declared loss affects consumer selection
- GIVEN an adapter loses slot x and preserves unknown slot y
- WHEN a consumer demands x
- THEN composition refuses that adapter; consumers accepting declared loss retain y through read-modify-write
Requirements
Requirement: Wild bridge design contract
The design corpus SHALL expose this capability’s constraints as normative, self-contained rules with acceptance cases, and SHALL link to a structurally valid shared v1 schema without claiming future runtime behavior is implemented.
Scenario: Wild bridge design is self-contained
- GIVEN this spec,
docs/wild-formats-v1.md, andschemas/wild-v1.schema.json - WHEN the design contract gate checks normative rule coverage, local references, and the shared schema
- THEN every constraint has a corresponding rule and acceptance case
- AND both referenced files exist and the schema is valid JSON Schema draft 2020-12
- AND this capability is discoverable by strict OpenSpec validation
wild-adopt
id: wild.adopt kind: intent statement: THE wild adoption layer SHALL let an existing project adopt contract versioning in stages, without changing its package manager, registry, or release process.
Wild adoption
Purpose
This is a normative design specification; only the prototype and corpus gate scenarios explicitly identified below are implemented. Shared wire formats and decision rules are defined in wild v1 formats and the v1 schema.
How existing, uncontracted software joins. The ladder is observe, shadow, gate, native. Each level adds enforcement; none requires rewriting the host ecosystem. Legacy version strings are kept as weak evidence. First enforcement runs in baseline mode, because stricter checking surfaces latent breaks that older tools hid.
Constraints
| id | kind | expr | traces_to |
|---|---|---|---|
| history_reconstructed | invariant | adopt(project) extracts each available historical release; missing source or extraction failure is preserved as an Unknown history node and cannot establish an accretion edge; version strings never establish edges | [[wild.adopt]] |
| past_claims_audited | invariant | each historical release reports declared version bump against computed verdict; disagreements are listed | [[wild.adopt]] |
| adoption_levels_ordered | invariant | levels are ordered observe < shadow < gate < native; a project enters level n+1 only from level n | [[wild.adopt]] |
| observe_is_read_only | invariant | level observe writes nothing to source, manifest, registry, or CI configuration | [[wild.adopt]] |
| shadow_never_blocks | invariant | level shadow emits verdicts but never changes a build exit status | [[wild.adopt]] |
| gate_scoped_to_new_changes | invariant | level gate rejects newly introduced breaks and expired baseline acknowledgements; baseline ids are immutable and cannot be reset implicitly by init, retries, or stepping down and up | [[wild.adopt]] |
| baseline_ack_expires | invariant | each baseline break has an owner, issue time, expiry, and stable finding id; default expiry is 30 days; renewal requires a signed reason and new expiry and appends an audit event rather than replacing history | [[wild.adopt]] |
| first_run_is_baseline | invariant | first enforcement atomically records a baseline digest, existing findings, and 30-day acknowledgements owned by the initiating identity; it tolerates existing breaks only after baseline persistence succeeds; persistence failure refuses enforcement activation | [[wild.adopt]] |
| lock_import_lossless | invariant | importing a host lockfile yields one lineage and hash per resolved dependency; unresolvable entries become Unknown, never dropped | [[wild.adopt]] |
| demand_derived_from_code | invariant | demand includes statically resolved usage and declared dynamic usage; unresolved reflection, plugins, or dynamic calls mark demand incomplete and block safe-removal and scoped-substitution claims; manual reductions require signed scoped expiring overrides and remain disclosed | [[wild.adopt]] |
| safe_update_advice | invariant | for a host version range, wild reports per candidate version whether demanded slots stay compatible; it never overrides the host resolver's choice; advice/check/observe never modify the manifest or host selection, and only explicit authorized update evaluation may apply a proposed manifest in an isolated workspace, with the host resolver selecting under that manifest | [[wild.adopt]] |
| consumer_demand_trackable | invariant | per slot, wild reports known consumers; removal_candidate(slot) is derived only when known demand is empty and all known demand manifests are complete and fresh; it is advisory and never authorizes removal within a stable lineage | [[wild.adopt]] |
| integration_points_share_core | invariant | CLI, CI action, pre-commit hook, and ecosystem plugins call one core and emit the same envelope | [[wild.adopt]] |
| init_needs_no_edits | invariant | init in a supported ecosystem produces extractor configuration, a baseline, and a CI hook without user edits | [[wild.adopt]] |
| unsupported_ecosystem_degrades | invariant | unsupported extraction yields Unknown assurance with scoped observations or metadata claims when available; observe and shadow succeed with diagnostics, while gate/native refuse any unmet required policy | [[wild.adopt]] |
| adoption_progress_reported | advisory | status reports level, share of dependencies per tier, and open acknowledgements | [[wild.adopt]] |
Model
States
unmanagedobservedshadowedgatednative
Transitions
| id | from | to | guard |
|---|---|---|---|
| observe | unmanaged | observed | [[wild.adopt.observe_is_read_only]] ∧ [[wild.adopt.history_reconstructed]] |
| shadow | observed | shadowed | [[wild.adopt.shadow_never_blocks]] |
| gate | shadowed | gated | [[wild.adopt.gate_scoped_to_new_changes]] ∧ [[wild.adopt.first_run_is_baseline]] |
| go_native | gated | native | [[wild.adopt.init_needs_no_edits]] ∧ preserves wild-registry ecosystem_untouched and sidecar_binds_artifact_digest |
| step_down | gated | shadowed | [[wild.adopt.adoption_levels_ordered]] |
Properties
| id | kind | derives_from | generator | predicate |
|---|---|---|---|---|
| history_graph_from_contracts | unit | [[wild.adopt.history_reconstructed]] | git_history_with_mislabeled_semver() | lineage_graph == computed_accretion_graph |
| semver_disagreement_listed | unit | [[wild.adopt.past_claims_audited]] | release_tagged_patch_that_removes_a_slot() | audit lists the release |
| level_skip_rejected | unit | [[wild.adopt.adoption_levels_ordered]] | project_at_observe_requesting_gate() | transition == rejected |
| observe_writes_nothing | unit | [[wild.adopt.observe_is_read_only]] | repo_snapshot_before_and_after_observe() | snapshot(before) == snapshot(after) |
| shadow_exit_status_unchanged | unit | [[wild.adopt.shadow_never_blocks]] | build_with_a_computed_break_in_shadow() | exit_status == host_exit_status |
| baseline_break_tolerated_new_rejected | unit | [[wild.adopt.gate_scoped_to_new_changes]] | repo_with_old_break_then_new_break() | old == tolerated ∧ new == rejected |
| expired_ack_rejects | unit | [[wild.adopt.baseline_ack_expires]] | acknowledged_break_past_expiry() | check(ack) == rejected |
| first_run_rejects_nothing_old | unit | [[wild.adopt.first_run_is_baseline]] | repo_with_many_latent_breaks_first_run() | rejections == 0 ∧ baseline lists all |
| lock_entries_all_accounted | unit | [[wild.adopt.lock_import_lossless]] | lockfile_with_unresolvable_entry() | count(imported) == count(lock) ∧ entry.verdict == Unknown |
| demand_matches_usage | unit | [[wild.adopt.demand_derived_from_code]] | consumer_using_slots([a, b]) | demand == {a, b} |
| advice_leaves_resolver_alone | unit | [[wild.adopt.safe_update_advice]] | range_with_one_incompatible_candidate() | advice flags candidate ∧ host_choice unchanged |
| zero_demand_slot_removable | unit | [[wild.adopt.consumer_demand_trackable]] | slot_with_no_known_consumers() | removal_candidate(slot) == true ∧ advisory_only ∧ no stored flag |
| same_envelope_everywhere | unit | [[wild.adopt.integration_points_share_core]] | same_change_via_cli_action_and_hook() | envelope(cli) == envelope(action) == envelope(hook) |
| init_works_unedited | unit | [[wild.adopt.init_needs_no_edits]] | fresh_repo_in_supported_ecosystem() | init leaves a runnable baseline and CI hook |
| unsupported_degrades_not_errors | unit | [[wild.adopt.unsupported_ecosystem_degrades]] | project_in_unsupported_language() | result.assurance == Unknown ∧ observe_exit_status == ok |
| status_lists_tier_shares | unit | [[wild.adopt.adoption_progress_reported]] | project_with_mixed_dependencies() | status lists level ∧ per-tier shares ∧ open acknowledgements |
Notes
Lesson from the catalog: pip’s stricter resolver in 2020 exposed conflicts older installers hid, so first enforcement must not reject legacy breaks (first_run_is_baseline). Baseline acknowledgements expire so old breaks cannot be silenced forever.
Known limits: a removable slot means no known consumer demands it, not that none exists (see open_world_disclosed in wild). Extractor noise on first runs is the main adoption risk and is reported in wild.extract.
Design acceptance cases
These cases define future runtime behavior. They are not claims that the current prototypes implement the v1 protocol. Executable document and prototype gates are under Requirements.
Rule: History reconstructed
The system SHALL satisfy history_reconstructed as defined in the Constraints table and the v1 format reference.
Acceptance case: History graph from contracts
- GIVEN the fixture domain
git_history_with_mislabeled_semver() - WHEN the
history_reconstructedcheck runs - THEN
lineage_graph == computed_accretion_graph
Rule: Past claims audited
The system SHALL satisfy past_claims_audited as defined in the Constraints table and the v1 format reference.
Acceptance case: Semver disagreement listed
- GIVEN the fixture domain
release_tagged_patch_that_removes_a_slot() - WHEN the
past_claims_auditedcheck runs - THEN
audit lists the release
Rule: Adoption levels ordered
The system SHALL satisfy adoption_levels_ordered as defined in the Constraints table and the v1 format reference.
Acceptance case: Level skip rejected
- GIVEN the fixture domain
project_at_observe_requesting_gate() - WHEN the
adoption_levels_orderedcheck runs - THEN
transition == rejected
Rule: Observe is read only
The system SHALL satisfy observe_is_read_only as defined in the Constraints table and the v1 format reference.
Acceptance case: Observe writes nothing
- GIVEN the fixture domain
repo_snapshot_before_and_after_observe() - WHEN the
observe_is_read_onlycheck runs - THEN
snapshot(before) == snapshot(after)
Rule: Shadow never blocks
The system SHALL satisfy shadow_never_blocks as defined in the Constraints table and the v1 format reference.
Acceptance case: Shadow exit status unchanged
- GIVEN the fixture domain
build_with_a_computed_break_in_shadow() - WHEN the
shadow_never_blockscheck runs - THEN
exit_status == host_exit_status
Rule: Gate scoped to new changes
The system SHALL satisfy gate_scoped_to_new_changes as defined in the Constraints table and the v1 format reference.
Acceptance case: Baseline break tolerated new rejected
- GIVEN the fixture domain
repo_with_old_break_then_new_break() - WHEN the
gate_scoped_to_new_changescheck runs - THEN
old == tolerated ∧ new == rejected
Rule: Baseline ack expires
The system SHALL satisfy baseline_ack_expires as defined in the Constraints table and the v1 format reference.
Acceptance case: Expired ack rejects
- GIVEN the fixture domain
acknowledged_break_past_expiry() - WHEN the
baseline_ack_expirescheck runs - THEN
check(ack) == rejected
Rule: First run is baseline
The system SHALL satisfy first_run_is_baseline as defined in the Constraints table and the v1 format reference.
Acceptance case: First run rejects nothing old
- GIVEN the fixture domain
repo_with_many_latent_breaks_first_run() - WHEN the
first_run_is_baselinecheck runs - THEN
rejections == 0 ∧ baseline lists all
Rule: Lock import lossless
The system SHALL satisfy lock_import_lossless as defined in the Constraints table and the v1 format reference.
Acceptance case: Lock entries all accounted
- GIVEN the fixture domain
lockfile_with_unresolvable_entry() - WHEN the
lock_import_losslesscheck runs - THEN
count(imported) == count(lock) ∧ entry.verdict == Unknown
Rule: Demand derived from code
The system SHALL satisfy demand_derived_from_code as defined in the Constraints table and the v1 format reference.
Acceptance case: Demand matches usage
- GIVEN the fixture domain
consumer_using_slots([a, b]) - WHEN the
demand_derived_from_codecheck runs - THEN
demand == {a, b}
Rule: Safe update advice
The system SHALL satisfy safe_update_advice as defined in the Constraints table and the v1 format reference.
Scope reconciliation: advice/check/observe never modify the manifest or host selection. Only explicit update evaluation may apply an authorized proposed manifest in isolation; Cargo selects under that manifest.
Acceptance case: Advice leaves resolver alone
- GIVEN the fixture domain
range_with_one_incompatible_candidate() - WHEN the
safe_update_advicecheck runs - THEN
advice flags candidate ∧ host_choice unchanged
Rule: Consumer demand trackable
The system SHALL satisfy consumer_demand_trackable as defined in the Constraints table and the v1 format reference.
Acceptance case: Zero demand slot removable
- GIVEN the fixture domain
slot_with_no_known_consumers() - WHEN the
consumer_demand_trackablecheck runs - THEN
removal_candidate(slot) == true ∧ advisory_only ∧ no stored flag
Rule: Integration points share core
The system SHALL satisfy integration_points_share_core as defined in the Constraints table and the v1 format reference.
Acceptance case: Same envelope everywhere
- GIVEN the fixture domain
same_change_via_cli_action_and_hook() - WHEN the
integration_points_share_corecheck runs - THEN
envelope(cli) == envelope(action) == envelope(hook)
Rule: Init needs no edits
The system SHALL satisfy init_needs_no_edits as defined in the Constraints table and the v1 format reference.
Acceptance case: Init works unedited
- GIVEN the fixture domain
fresh_repo_in_supported_ecosystem() - WHEN the
init_needs_no_editscheck runs - THEN
init leaves a runnable baseline and CI hook
Rule: Unsupported ecosystem degrades
The system SHALL satisfy unsupported_ecosystem_degrades as defined in the Constraints table and the v1 format reference.
Acceptance case: Unsupported degrades not errors
- GIVEN the fixture domain
project_in_unsupported_language() - WHEN the
unsupported_ecosystem_degradescheck runs - THEN
result.assurance == Unknown ∧ observe_exit_status == ok
Rule: Adoption progress reported
The system SHALL satisfy adoption_progress_reported as defined in the Constraints table and the v1 format reference.
Acceptance case: Status lists tier shares
- GIVEN the fixture domain
project_with_mixed_dependencies() - WHEN the
adoption_progress_reportedcheck runs - THEN
status lists level ∧ per-tier shares ∧ open acknowledgements
Acceptance case: Reinitialization cannot erase baseline findings
- GIVEN a project has an immutable baseline with an expired acknowledgement
- WHEN init is rerun or enforcement is stepped down and up
- THEN the baseline id remains unchanged and the expired finding still refuses enforcement
Acceptance case: Dynamic calls prevent safe removal advice
- GIVEN reflection leaves a known consumer demand manifest incomplete
- WHEN a slot has no statically identified consumers
- THEN removal_candidate is not asserted and scoped substitution is refused
Acceptance case: Unavailable history remains visible
- GIVEN historical release source is missing
- WHEN adoption reconstructs history
- THEN the release remains an Unknown node and no accretion edge is inferred across it
Acceptance case: Unsupported ecosystem respects enforcement policy
- GIVEN extraction is unsupported and policy requires PassDeclared
- WHEN observe and gate modes evaluate the same project
- THEN observe returns diagnostics with exit 0; gate refuses with exit 1
Requirements
Requirement: Wild adopt design contract
The design corpus SHALL expose this capability’s constraints as normative, self-contained rules with acceptance cases, and SHALL link to a structurally valid shared v1 schema without claiming future runtime behavior is implemented.
Scenario: Wild adopt design is self-contained
- GIVEN this spec,
docs/wild-formats-v1.md, andschemas/wild-v1.schema.json - WHEN the design contract gate checks normative rule coverage, local references, and the shared schema
- THEN every constraint has a corresponding rule and acceptance case
- AND both referenced files exist and the schema is valid JSON Schema draft 2020-12
- AND this capability is discoverable by strict OpenSpec validation
Requirement: Standalone local compatibility check
Wild SHALL check supplied base/candidate bundles for a named consumer scope without requiring registry publication, upstream contract adoption, historical reconstruction, or activation of adoption gate/native modes. It SHALL use v1 envelopes and the local-1 report contract, write only explicitly requested report artifacts, and preserve host manifests, lockfiles, source, and CI configuration.
Scenario: First result in an existing repository
- GIVEN supported local bundles and an explicit check request with no Wild registry or adoption history
- WHEN wild check evaluates the requested boundary
- THEN it reports structural assurance, law methods, scope, coverage, and stable diagnostics
- AND project files and adoption level remain unchanged
Scenario: A result separates policy from execution
- GIVEN a required analysis gap, a known structural break, and a malformed request in three separate runs
- WHEN checks finish
- THEN the local outcomes are respectively unknown, reject, and error with exits 1, 1, and 2
- AND all refuse policy acceptance without calling missing evidence a structural counterexample
Requirement: Separate authored obligations from extracted facts
Wild SHALL accept human- or agent-authored obligation drafts using the same local-1 format and authority rules, store them separately from mined facts, and preserve accepted obligations when re-extracting candidate code. Authorship SHALL NOT raise assurance. Prose without an executable or structural predicate SHALL remain unverified, and contradictions with extracted facts SHALL remain visible.
Scenario: Regeneration cannot erase intent
- GIVEN an accepted law and a candidate that regenerates its contracts without that law
- WHEN the candidate is checked
- THEN the original law is still evaluated and the proposed deletion is reported separately
Scenario: Human and agent predicates receive equal checking
- GIVEN otherwise identical executable obligations with human and agent origin labels
- WHEN the same checker evaluates them on identical committed inputs
- THEN their assurance and law results match while provenance retains the different origins
Requirement: Explicit authorized update planning
Wild SHALL provide a separate local update mode that records an exact target, original range, proposed manifest edit, base/configuration commitments, and allowed actions. Advice/check/observe SHALL retain their read-only host-selection behavior. Evaluation SHALL require external project authority bound to the plan before applying any edit in isolation; missing authority SHALL NOT be inferred from compatibility evidence.
Scenario: Plan without changing the application
- GIVEN a candidate excluded by the original Cargo range
- WHEN wild update plan runs
- THEN it writes only the requested proposal and identifies the exact range change and pending checks
- AND the original manifest, lockfile, source, and host selection are unchanged
Scenario: Candidate self-authorization fails
- GIVEN a candidate supplies an authority file not committed by the trusted invocation
- WHEN update evaluation starts
- THEN it refuses before applying the planned edit
Requirement: Real host resolution and update delivery
Wild SHALL evaluate the authorized plan in isolation using actual Cargo resolution, inspect the selected target and complete dependency closure, build/test with a fixed lock, and evaluate protected obligations on those artifacts. It SHALL deliver a pinned diff only after every required check succeeds and output persistence completes. Missing required evidence SHALL remain unknown; runtime/platform/provenance/license/organization constraints SHALL NOT be silently relaxed with the version range.
Scenario: Compatible release outside the old range
- GIVEN a frozen registry target excluded by the original manifest that removes only an unused function in a completely supported scope
- WHEN an authorized manifest change resolves that exact target and all required closure, build, test, and contract checks pass
- THEN the output contains a delivered pinned direct-update diff and evidence for the actual artifacts
- AND the original worktree remains unchanged
Scenario: Permitted patch breaks a consumer
- GIVEN a patch release allowed by the old range removes a demanded function
- WHEN the actual selected target is evaluated
- THEN the update is refused with the violated demand and no delivered-update claim
Scenario: Cargo selects a different artifact
- GIVEN a plan for a specific source and release
- WHEN actual resolution selects a different source or release
- THEN evaluation refuses and records both requested and actual identities
Scenario: Environment constraint survives range relaxation
- GIVEN an otherwise compatible target requires an unsupported Rust version or violates a required provenance policy
- WHEN the manifest-range change is evaluated
- THEN the relevant constraint refuses delivery independently of compatibility
Scenario: Failed persistence or stale base cannot deliver
- GIVEN checks pass but the output cannot be durably written or an input commitment no longer matches
- WHEN delivery is finalized
- THEN the result is error or refusal with the cause and does not claim a delivered update
Requirement: Direct updates and migrations remain distinct
Wild SHALL classify manifest/lock-only changes as direct updates and supplied consumer/adapter changes as migrations. Both SHALL satisfy protected intended outcomes. Authorized obligation changes SHALL be recorded as intentional transitions and SHALL NOT count as backward-compatible direct updates. The first implementation SHALL accept supplied migration patches without requiring automatic migration generation.
Scenario: Consumer repair is a migration
- GIVEN an update passes only after a supplied consumer-code patch
- WHEN the original intended outcomes and new closure pass validation
- THEN the result includes that patch and reports migration rather than direct compatibility
Scenario: Removed assertion is not preserved behavior
- GIVEN a migration deletes a protected consumer test or obligation
- WHEN evaluation runs without a separately authorized intent transition
- THEN the original obligation remains required and the deletion cannot make delivery pass
wild-deploy
id: wild.deploy kind: intent statement: THE wild deployer SHALL decide, from declared floors and observed live revisions, when each service may deploy, so that continuous deployment needs no manual ordering or lockstep release.
Wild deploy
Purpose
This is a normative design specification; only the prototype and corpus gate scenarios explicitly identified below are implemented. Shared wire formats and decision rules are defined in wild v1 formats and the v1 schema.
Rollout rules on top of published revisions. Accretion makes old consumers safe against new providers, but a consumer that starts using a new slot needs its provider live first. This spec turns that into a computed gate, plus safe rollback and lineage retirement.
Constraints
| id | kind | expr | traces_to |
|---|---|---|---|
| deploy_requires_published_revision | invariant | a revision is deployable only if it is published in the registry and passed tiers identity, shape, and laws | [[wild.deploy]] |
| floor_declared | invariant | for each demanded provider on a totally ordered accepted ancestry, floor is the least revision covering demand; incomparable covering minima require an explicit pinned covering revision and cannot be represented by a guessed scalar floor | [[wild.deploy]] |
| provider_live_before_consumer | invariant | a consumer may deploy only when every provider revision reachable by its traffic satisfies its floor, all required policy passes, and a coordination lease protects the live snapshot; one new canary instance does not satisfy the floor for traffic reaching old instances | [[wild.deploy]] |
| gate_order_derived | invariant | a deploy plan orders services by a topological order of floor edges; manual ordering is not accepted | [[wild.deploy]] |
| floor_cycle_rejected | invariant | only unsatisfied floor prerequisites create ordering edges; existing dependency cycles whose floors are already satisfied are allowed; an unsatisfied prerequisite cycle is refused with members listed and simultaneous deployment is not offered | [[wild.deploy]] |
| gate_decision_pure | invariant | the gate is a pure function of floors, routing, live snapshot, policy, coordination generation, and explicit evaluation time; it performs no clock or network reads | [[wild.deploy]] |
| live_state_fresh | invariant | reports include observed_at, ttl_seconds, generation, and every traffic-reachable revision; at evaluation_time ≥ observed_at + ttl_seconds or on missing/future-dated reports state is Unknown and blocks; default ttl is 60 seconds | [[wild.deploy]] |
| rolling_overlap_safe | invariant | during a roll, old and new revisions serve concurrently only when the new revision accretes the old one; a non-accretion is never rolled in place | [[wild.deploy]] |
| lineages_served_concurrently | invariant | a break ships as a new lineage while the old lineage keeps serving until retirement | [[wild.deploy]] |
| retire_on_zero_demand | invariant | retirement requires empty known demand, fresh complete consumer reports, zero routed traffic, and a policy grace period (default seven days) continuously satisfied; missing reports or renewed demand restart the grace period; registry bytes remain | [[wild.deploy]] |
| canary_traffic_bounded | invariant | canary traffic share never exceeds the policy maximum | [[wild.deploy]] |
| evidence_required_to_promote | invariant | promotion requires every binding to satisfy the v1 policy, fresh complete live state, and a valid coordination lease; structural Reject or relevant law counterexample is never promoted | [[wild.deploy]] |
| rollback_respects_floors | invariant | provider rollback checks floors of all live and in-flight consumers plus irreversible writes under the same coordination lease; generation change or lease loss aborts and requires revalidation; otherwise violating consumers roll back first | [[wild.deploy]] |
| irreversible_edges_declared | invariant | irreversible writers persist a monotone first-write barrier before acknowledging such writes; after the barrier rollback past it is refused, including canary and rolling aborts; unknown barrier status fails closed | [[wild.deploy]] |
| emergency_override_recorded | invariant | an authorized override names exact overridable policy findings, signer, reason, and expiry in a log entry; structural Reject, Unknown reachability, lease loss, and irreversible-write barriers are never overridable | [[wild.deploy]] |
| deploy_envelope | invariant | every deploy command emits an envelope with stage, revision hashes, and gate verdict | [[wild.deploy]] |
| stage_durations_reported | advisory | each deployment reports time spent per stage from commit to live | [[wild.deploy]] |
| deploy_impact_estimated | advisory | before the gate runs, the plan lists the known consumers each deployment affects | [[wild.deploy]] |
Model
States
committedcheckedgatedcanaryrollingliverolled_backcontracted
Transitions
| id | from | to | guard |
|---|---|---|---|
| check | committed | checked | [[wild.deploy.deploy_requires_published_revision]] ∧ requires wild-registry registry_append_only |
| gate | checked | gated | [[wild.deploy.provider_live_before_consumer]] ∧ [[wild.deploy.gate_decision_pure]] |
| start_canary | gated | canary | [[wild.deploy.canary_traffic_bounded]] |
| promote | canary | rolling | [[wild.deploy.evidence_required_to_promote]] |
| finish_roll | rolling | live | [[wild.deploy.rolling_overlap_safe]] |
| abort_canary | canary | rolled_back | [[wild.deploy.rollback_respects_floors]] ∧ [[wild.deploy.irreversible_edges_declared]] |
| abort_roll | rolling | rolled_back | [[wild.deploy.rollback_respects_floors]] ∧ [[wild.deploy.irreversible_edges_declared]] |
| rollback_live | live | rolled_back | [[wild.deploy.rollback_respects_floors]] ∧ [[wild.deploy.irreversible_edges_declared]] |
| retry | rolled_back | committed | [[wild.deploy.deploy_requires_published_revision]] |
| contract | live | contracted | [[wild.deploy.retire_on_zero_demand]] ∧ [[wild.deploy.live_state_fresh]] |
Properties
| id | kind | derives_from | generator | predicate |
|---|---|---|---|---|
| unpublished_revision_not_deployed | unit | [[wild.deploy.deploy_requires_published_revision]] | revision_absent_from_registry() | deploy == rejected |
| floor_is_least_covering_revision | unit | [[wild.deploy.floor_declared]] | lineage_chain_with_demand() | floor == min(r in chain where demand ⊆ provides(r)) |
| consumer_waits_for_provider | unit | [[wild.deploy.provider_live_before_consumer]] | consumer_floor_above_live_provider() | gate == blocked |
| plan_order_is_topological | unit | [[wild.deploy.gate_order_derived]] | random_dag_of_floor_edges() | for each edge (p, c): index(p) < index(c) |
| cycle_reported_with_members | unit | [[wild.deploy.floor_cycle_rejected]] | floor_edges_forming_a_cycle() | plan == rejected ∧ members listed |
| gate_ignores_clock | unit | [[wild.deploy.gate_decision_pure]] | same_explicit_evaluation_inputs_with_varied_host_clock() | gate(a) == gate(b) |
| stale_report_blocks | unit | [[wild.deploy.live_state_fresh]] | live_report_past_ttl() | gate == blocked ∧ state == Unknown |
| accretion_roll_has_no_failures | unit | [[wild.deploy.rolling_overlap_safe]] | rolling_update_of_accretion_pair() | no contract-incompatibility failures on the declared demand domain; unrelated operational failures excluded |
| lineages_overlap_until_retired | unit | [[wild.deploy.lineages_served_concurrently]] | break_shipped_as_new_lineage() | served(old) ∧ served(new) until retire |
| retire_blocked_while_demanded | unit | [[wild.deploy.retire_on_zero_demand]] | old_lineage_with_one_known_consumer() | retire == rejected |
| canary_share_capped | unit | [[wild.deploy.canary_traffic_bounded]] | canary_request_above_policy_max() | share ≤ policy_max |
| exact_reject_not_promotable | unit | [[wild.deploy.evidence_required_to_promote]] | shape_Reject_with_clean_canary() | promote == rejected |
| rollback_below_floor_blocked | unit | [[wild.deploy.rollback_respects_floors]] | provider_rollback_below_a_live_floor() | rollback == blocked ∧ consumers listed first |
| irreversible_rollback_blocked | unit | [[wild.deploy.irreversible_edges_declared]] | irreversible_revision_after_first_write() | rollback == rejected |
| override_needs_expiry | unit | [[wild.deploy.emergency_override_recorded]] | override_without_expiry() | override == rejected |
| envelope_has_stage_and_hashes | unit | [[wild.deploy.deploy_envelope]] | arbitrary_deploy_result() | envelope has stage ∧ revision hashes ∧ gate verdict |
| durations_listed_per_stage | unit | [[wild.deploy.stage_durations_reported]] | completed_deployment() | report lists duration for each stage |
| impact_lists_consumers | unit | [[wild.deploy.deploy_impact_estimated]] | plan_for_provider_with_known_consumers() | plan lists affected consumers before gate |
Notes
Simulation findings behind these rules (toy model, assumed durations): an additive roll of 20 instances produced no failed requests, an uncoordinated break failed roughly a third of calls hitting the changed slot, manual expand/contract took about four working days end to end, and only a small minority of random deploy orders were safe, hence the derived order. Median lead time matched a modern canary pipeline (about 0.8 hours); the gains were in the tail (waiting on consumers) and in user-impact minutes (about 2.4 times lower than the canary baseline across nine sensitivity runs). Escaped undeclared-behavior defects occurred at the same rate as in the canary baseline.
Known limits: the gate trusts the live-revision reports it receives; stale or missing reports fail closed. Retirement is only safe against known consumers. Data written by a new revision is outside accretion unless declared irreversible.
Design acceptance cases
These cases define future runtime behavior. They are not claims that the current prototypes implement the v1 protocol. Executable document and prototype gates are under Requirements.
Rule: Deploy requires published revision
The system SHALL satisfy deploy_requires_published_revision as defined in the Constraints table and the v1 format reference.
Acceptance case: Unpublished revision not deployed
- GIVEN the fixture domain
revision_absent_from_registry() - WHEN the
deploy_requires_published_revisioncheck runs - THEN
deploy == rejected
Rule: Floor declared
The system SHALL satisfy floor_declared as defined in the Constraints table and the v1 format reference.
Acceptance case: Floor is least covering revision
- GIVEN the fixture domain
lineage_chain_with_demand() - WHEN the
floor_declaredcheck runs - THEN
floor == min(r in chain where demand ⊆ provides(r))
Rule: Provider live before consumer
The system SHALL satisfy provider_live_before_consumer as defined in the Constraints table and the v1 format reference.
Acceptance case: Consumer waits for provider
- GIVEN the fixture domain
consumer_floor_above_live_provider() - WHEN the
provider_live_before_consumercheck runs - THEN
gate == blocked
Rule: Gate order derived
The system SHALL satisfy gate_order_derived as defined in the Constraints table and the v1 format reference.
Acceptance case: Plan order is topological
- GIVEN the fixture domain
random_dag_of_floor_edges() - WHEN the
gate_order_derivedcheck runs - THEN
for each edge (p, c): index(p) < index(c)
Rule: Floor cycle rejected
The system SHALL satisfy floor_cycle_rejected as defined in the Constraints table and the v1 format reference.
Acceptance case: Cycle reported with members
- GIVEN the fixture domain
floor_edges_forming_a_cycle() - WHEN the
floor_cycle_rejectedcheck runs - THEN
plan == rejected ∧ members listed
Rule: Gate decision pure
The system SHALL satisfy gate_decision_pure as defined in the Constraints table and the v1 format reference.
Acceptance case: Gate ignores clock
- GIVEN the fixture domain
same_explicit_evaluation_inputs_with_varied_host_clock() - WHEN the
gate_decision_purecheck runs - THEN
gate(a) == gate(b)
Rule: Live state fresh
The system SHALL satisfy live_state_fresh as defined in the Constraints table and the v1 format reference.
Acceptance case: Stale report blocks
- GIVEN the fixture domain
live_report_past_ttl() - WHEN the
live_state_freshcheck runs - THEN
gate == blocked ∧ state == Unknown
Rule: Rolling overlap safe
The system SHALL satisfy rolling_overlap_safe as defined in the Constraints table and the v1 format reference.
Acceptance case: Accretion roll has no failures
- GIVEN the fixture domain
rolling_update_of_accretion_pair() - WHEN the
rolling_overlap_safecheck runs - THEN
no contract-incompatibility failures on the declared demand domain; unrelated operational failures excluded
Rule: Lineages served concurrently
The system SHALL satisfy lineages_served_concurrently as defined in the Constraints table and the v1 format reference.
Acceptance case: Lineages overlap until retired
- GIVEN the fixture domain
break_shipped_as_new_lineage() - WHEN the
lineages_served_concurrentlycheck runs - THEN
served(old) ∧ served(new) until retire
Rule: Retire on zero demand
The system SHALL satisfy retire_on_zero_demand as defined in the Constraints table and the v1 format reference.
Acceptance case: Retire blocked while demanded
- GIVEN the fixture domain
old_lineage_with_one_known_consumer() - WHEN the
retire_on_zero_demandcheck runs - THEN
retire == rejected
Rule: Canary traffic bounded
The system SHALL satisfy canary_traffic_bounded as defined in the Constraints table and the v1 format reference.
Acceptance case: Canary share capped
- GIVEN the fixture domain
canary_request_above_policy_max() - WHEN the
canary_traffic_boundedcheck runs - THEN
share ≤ policy_max
Rule: Evidence required to promote
The system SHALL satisfy evidence_required_to_promote as defined in the Constraints table and the v1 format reference.
Acceptance case: Exact reject not promotable
- GIVEN the fixture domain
shape_Reject_with_clean_canary() - WHEN the
evidence_required_to_promotecheck runs - THEN
promote == rejected
Rule: Rollback respects floors
The system SHALL satisfy rollback_respects_floors as defined in the Constraints table and the v1 format reference.
Acceptance case: Rollback below floor blocked
- GIVEN the fixture domain
provider_rollback_below_a_live_floor() - WHEN the
rollback_respects_floorscheck runs - THEN
rollback == blocked ∧ consumers listed first
Rule: Irreversible edges declared
The system SHALL satisfy irreversible_edges_declared as defined in the Constraints table and the v1 format reference.
Acceptance case: Irreversible rollback blocked
- GIVEN the fixture domain
irreversible_revision_after_first_write() - WHEN the
irreversible_edges_declaredcheck runs - THEN
rollback == rejected
Rule: Emergency override recorded
The system SHALL satisfy emergency_override_recorded as defined in the Constraints table and the v1 format reference.
Acceptance case: Override needs expiry
- GIVEN the fixture domain
override_without_expiry() - WHEN the
emergency_override_recordedcheck runs - THEN
override == rejected
Rule: Deploy envelope
The system SHALL satisfy deploy_envelope as defined in the Constraints table and the v1 format reference.
Acceptance case: Envelope has stage and hashes
- GIVEN the fixture domain
arbitrary_deploy_result() - WHEN the
deploy_envelopecheck runs - THEN
envelope has stage ∧ revision hashes ∧ gate verdict
Rule: Stage durations reported
The system SHALL satisfy stage_durations_reported as defined in the Constraints table and the v1 format reference.
Acceptance case: Durations listed per stage
- GIVEN the fixture domain
completed_deployment() - WHEN the
stage_durations_reportedcheck runs - THEN
report lists duration for each stage
Rule: Deploy impact estimated
The system SHALL satisfy deploy_impact_estimated as defined in the Constraints table and the v1 format reference.
Acceptance case: Impact lists consumers
- GIVEN the fixture domain
plan_for_provider_with_known_consumers() - WHEN the
deploy_impact_estimatedcheck runs - THEN
plan lists affected consumers before gate
Acceptance case: Mixed rollout does not satisfy a new floor
- GIVEN a provider routes 90 percent of requests to revision r1 and 10 percent to r2; a consumer requires a slot first provided by r2
- WHEN the consumer deploy gate runs
- THEN it blocks until all reachable routes cover the floor or the consumer is pinned exclusively to covering instances
Acceptance case: Clock is an explicit evaluation input
- GIVEN a report observed at 15:00:00Z has ttl_seconds 60
- WHEN the pure gate receives evaluation time 15:01:00Z
- THEN the report is Unknown and deployment blocks regardless of the host clock
Acceptance case: Concurrent rollback invalidates the gate
- GIVEN a gate was accepted at coordination generation 12
- WHEN provider rollback advances the generation before consumer route activation
- THEN activation aborts and revalidates; the old approval cannot authorize it
Acceptance case: Canary writes can prevent abort rollback
- GIVEN a canary persisted an irreversible first-write barrier
- WHEN the canary attempts rollback below the barrier
- THEN rollback refuses just as it would after full promotion
Acceptance case: Satisfied dependency cycle does not block rollout
- GIVEN two services depend on each other and both live providers already cover every floor
- WHEN the deploy plan computes unsatisfied prerequisites
- THEN it has no cyclic ordering edges and can proceed subject to policy and lease
Requirements
Requirement: Prototype deployment simulation
The prototype deployment simulation SHALL run its overlap, deploy-order, pipeline-sensitivity, and checker-cost models, so the assumptions behind the design remain runnable while wild itself is unbuilt; this gate does not establish runtime floor, lease, TTL, or rollback conformance.
Scenario: Prototype deployment simulation runs clean
- GIVEN the deployment scenarios encoded in
prototype/wild_cd_sim.py - WHEN the deployment simulation runs
- THEN it exits 0 and produces non-empty output
- AND the gate executes this behavior as a declared contract test
Requirement: Wild deploy design contract
The design corpus SHALL expose this capability’s constraints as normative, self-contained rules with acceptance cases, and SHALL link to a structurally valid shared v1 schema without claiming future runtime behavior is implemented.
Scenario: Wild deploy design is self-contained
- GIVEN this spec,
docs/wild-formats-v1.md, andschemas/wild-v1.schema.json - WHEN the design contract gate checks normative rule coverage, local references, and the shared schema
- THEN every constraint has a corresponding rule and acceptance case
- AND both referenced files exist and the schema is valid JSON Schema draft 2020-12
- AND this capability is discoverable by strict OpenSpec validation
wild-extract
id: wild.extract kind: intent statement: THE wild extraction layer SHALL turn schemas, source code, and data artifacts of any ecosystem into Contract IR through pluggable, deterministic extractors that never drop a construct silently.
Wild extract
Purpose
This is a normative design specification; only the prototype and corpus gate scenarios explicitly identified below are implemented. Shared wire formats and decision rules are defined in wild v1 formats and the v1 schema.
The language-blind core sees only IR. Everything ecosystem-specific lives in extractors (schemas, source APIs, feature files, templates) and in law harnesses that run recorded properties against an implementation. Anything an extractor cannot express becomes an opaque, frozen slot and is reported.
Constraints
| id | kind | expr | traces_to |
|---|---|---|---|
| extractor_contract | extension_point | for every conforming extractor E: extract(source) yields ContractIR, is deterministic, and reports coverage listing every unextracted construct | [[wild.extract]] |
| law_harness | extension_point | run(suite, implementation, seed, fixtures, budgets) yields the v1 LawResult; it declares proof, exhaustive, or sampled method and returns pass, counterexample, or inconclusive with all content digests | [[wild.extract]] |
| extraction_total | invariant | every parsed declaration relevant to an exported contract maps to a typed or opaque slot; unsupported syntax yields a source-range diagnostic and incomplete extraction, never an invented complete contract | [[wild.extract]] |
| extractor_deterministic | invariant | the same supplied source bundle, extractor artifact digest, options, and IR version yield the same canonical IR bytes; imported schemas and generated artifacts must be supplied and hashed as inputs | [[wild.extract]] |
| extractor_isolated | invariant | extractors read only the source they are given and perform no network or write access | [[wild.extract]] |
| ir_versioned | invariant | emitted IR names its schema version; the core refuses IR of an unknown version | [[wild.extract]] |
| data_plane_extractors | invariant | schemas, templates, and feature files have extractors under the same contract as code extractors | [[wild.extract]] |
| ecosystems_pluggable | invariant | supporting a new ecosystem requires an extractor only, with no change to the core | [[wild.extract]] |
| extractor_coverage_reported | advisory | each extraction reports the share of constructs mapped to opaque slots | [[wild.extract]] |
| failure_reported | effect | an unreadable source emits a failure report naming the source and the cause | [[wild.extract]] |
| extractor_noise_reported | advisory | each extractor reports false breaks / independently adjudicated candidate breaks, sample size, history range, and adjudication source; zero adjudications yield Unknown, not a zero rate | [[wild.extract]] |
Model
States
source_readparsedmappedreportedfailed(emits: [[wild.extract.failure_reported]])
Transitions
| id | from | to | guard |
|---|---|---|---|
| parse | source_read | parsed | [[wild.extract.extractor_isolated]] |
| map | parsed | mapped | [[wild.extract.extraction_total]] |
| report | mapped | reported | [[wild.extract.extractor_deterministic]] ∧ [[wild.extract.ir_versioned]] |
| fail_read | source_read | failed | source unreadable under [[wild.extract.extractor_isolated]] |
| fail_parse | parsed | failed | violation of [[wild.extract.extraction_total]] |
| fail_map | mapped | failed | violation of [[wild.extract.extractor_deterministic]] or [[wild.extract.ir_versioned]] |
Properties
| id | kind | derives_from | generator | predicate | observes |
|---|---|---|---|---|---|
| extractor_reports_coverage | unit | [[wild.extract.extractor_contract]] | extractor_output_with_unmapped_construct() | coverage lists the construct | |
| harness_deterministic_given_seed | unit | [[wild.extract.law_harness]] | harness_run_twice_with_same_seed() | result(a) == result(b) or result.status == inconclusive with nondeterminism diagnostic | |
| no_silent_drop | unit | [[wild.extract.extraction_total]] | source_with_unsupported_construct() | slot_for(construct) is opaque | |
| same_source_same_bytes | unit | [[wild.extract.extractor_deterministic]] | source_extracted_twice() | bytes(a) == bytes(b) | |
| extractor_has_no_side_effects | unit | [[wild.extract.extractor_isolated]] | extractor_run_with_network_and_writes_blocked() | extract completes ∧ no write attempted | |
| unknown_ir_version_refused | unit | [[wild.extract.ir_versioned]] | ir_with_version("99") | core == refused | |
| feature_file_extracts_like_code | unit | [[wild.extract.data_plane_extractors]] | feature_file_with_known_arity() | ir.arity == known_arity | |
| new_ecosystem_needs_no_core_change | unit | [[wild.extract.ecosystems_pluggable]] | extractor_for_new_ecosystem_added() | core_diff == empty | |
| opaque_share_reported | unit | [[wild.extract.extractor_coverage_reported]] | source_with_known_opaque_count(3 of 10) | report.opaque_share == 0.3 | |
| unreadable_source_reported | unit | [[wild.extract.failure_reported]] | source_path_that_does_not_exist() | report names the source ∧ the cause | [[wild.extract.failure_reported]] |
| noise_rate_reported | unit | [[wild.extract.extractor_noise_reported]] | extraction_run_over_known_history() | report has false_break_rate_ppm and adjudicated_breaks; zero denominator yields null |
Notes
The IR is a common denominator, so extraction is lossy by nature; opaque slots are frozen, which can raise false breaks. That is why noise is measured and reported rather than hidden. Facet-specific extraction (ABI, layout, serialization) arrives as additional extractors under the same contract.
The shared v1 IR, canonical form, consumer manifest, lockfile, sidecar, certificate, and law-result formats are normative in docs/wild-formats-v1.md and schemas/wild-v1.schema.json. Ecosystem-specific extraction must declare its supported syntax and demand-analysis limits before it can claim complete coverage.
Design acceptance cases
These cases define future runtime behavior. They are not claims that the current prototypes implement the v1 protocol. Executable document and prototype gates are under Requirements.
Rule: Extractor contract
The system SHALL satisfy extractor_contract as defined in the Constraints table and the v1 format reference.
Acceptance case: Extractor reports coverage
- GIVEN the fixture domain
extractor_output_with_unmapped_construct() - WHEN the
extractor_contractcheck runs - THEN
coverage lists the construct
Rule: Law harness
The system SHALL satisfy law_harness as defined in the Constraints table and the v1 format reference.
Acceptance case: Harness deterministic given seed
- GIVEN the fixture domain
harness_run_twice_with_same_seed() - WHEN the
law_harnesscheck runs - THEN
result(a) == result(b) or result.status == inconclusive with nondeterminism diagnostic
Rule: Extraction total
The system SHALL satisfy extraction_total as defined in the Constraints table and the v1 format reference.
Acceptance case: No silent drop
- GIVEN the fixture domain
source_with_unsupported_construct() - WHEN the
extraction_totalcheck runs - THEN
slot_for(construct) is opaque
Rule: Extractor deterministic
The system SHALL satisfy extractor_deterministic as defined in the Constraints table and the v1 format reference.
Acceptance case: Same source same bytes
- GIVEN the fixture domain
source_extracted_twice() - WHEN the
extractor_deterministiccheck runs - THEN
bytes(a) == bytes(b)
Rule: Extractor isolated
The system SHALL satisfy extractor_isolated as defined in the Constraints table and the v1 format reference.
Acceptance case: Extractor has no side effects
- GIVEN the fixture domain
extractor_run_with_network_and_writes_blocked() - WHEN the
extractor_isolatedcheck runs - THEN
extract completes ∧ no write attempted
Rule: Ir versioned
The system SHALL satisfy ir_versioned as defined in the Constraints table and the v1 format reference.
Acceptance case: Unknown ir version refused
- GIVEN the fixture domain
ir_with_version("99") - WHEN the
ir_versionedcheck runs - THEN
core == refused
Rule: Data plane extractors
The system SHALL satisfy data_plane_extractors as defined in the Constraints table and the v1 format reference.
Acceptance case: Feature file extracts like code
- GIVEN the fixture domain
feature_file_with_known_arity() - WHEN the
data_plane_extractorscheck runs - THEN
ir.arity == known_arity
Rule: Ecosystems pluggable
The system SHALL satisfy ecosystems_pluggable as defined in the Constraints table and the v1 format reference.
Acceptance case: New ecosystem needs no core change
- GIVEN the fixture domain
extractor_for_new_ecosystem_added() - WHEN the
ecosystems_pluggablecheck runs - THEN
core_diff == empty
Rule: Extractor coverage reported
The system SHALL satisfy extractor_coverage_reported as defined in the Constraints table and the v1 format reference.
Acceptance case: Opaque share reported
- GIVEN the fixture domain
source_with_known_opaque_count(3 of 10) - WHEN the
extractor_coverage_reportedcheck runs - THEN
report.opaque_share == 0.3
Rule: Failure reported
The system SHALL satisfy failure_reported as defined in the Constraints table and the v1 format reference.
Acceptance case: Unreadable source reported
- GIVEN the fixture domain
source_path_that_does_not_exist() - WHEN the
failure_reportedcheck runs - THEN
report names the source ∧ the cause
Rule: Extractor noise reported
The system SHALL satisfy extractor_noise_reported as defined in the Constraints table and the v1 format reference.
Acceptance case: Noise rate reported
- GIVEN the fixture domain
extraction_run_over_known_history() - WHEN the
extractor_noise_reportedcheck runs - THEN
report has false_break_rate_ppm and adjudicated_breaks; zero denominator yields null
Acceptance case: Incomplete parser cannot claim complete inventory
- GIVEN unsupported syntax prevents inventory of exported declarations
- WHEN extraction runs
- THEN it emits source-range diagnostics with incomplete coverage, not a fabricated complete contract
Acceptance case: No adjudications means unknown false-break rate
- GIVEN history has zero independently adjudicated candidate breaks
- WHEN the noise report is generated
- THEN the rate is Unknown and the denominator is reported as zero
Requirements
Requirement: Wild extract design contract
The design corpus SHALL expose this capability’s constraints as normative, self-contained rules with acceptance cases, and SHALL link to a structurally valid shared v1 schema without claiming future runtime behavior is implemented.
Scenario: Wild extract design is self-contained
- GIVEN this spec,
docs/wild-formats-v1.md, andschemas/wild-v1.schema.json - WHEN the design contract gate checks normative rule coverage, local references, and the shared schema
- THEN every constraint has a corresponding rule and acceptance case
- AND both referenced files exist and the schema is valid JSON Schema draft 2020-12
- AND this capability is discoverable by strict OpenSpec validation
Requirement: Bounded deterministic Rust extraction
The local extractor SHALL implement the rust-cargo-local-1 profile defined in this change’s design, bind every result to supplied source/build inputs and extractor identity, and emit existing v1 contracts plus separate provenance and completeness records. It SHALL perform no network access or writes to the source bundle. Equivalent supported declaration structure SHALL yield identical semantic contract bytes independently of checkout location. Unknown declaration inventory SHALL prevent complete extraction claims. The profile’s signature subset SHALL treat String as a supported owned-text scalar (text-owned) and &str and &String as a supported borrowed-text scalar (text-borrowed), each emitted without interval fields; mutable text references, bare str, and other text-like constructs SHALL remain unsupported and disclosed. A public enum without cfg gating SHALL inventory each of its variants as a named slot under the enum’s qualified meaning (<crate>::<Enum>::<Variant>) instead of a single opaque enum item, following the identity law (crate identity plus qualified path, never line numbers); cfg-gated variants and generic public enums SHALL keep the honest gap. Impl blocks SHALL be accounted per construct: public inherent impl methods SHALL inventory as type-qualified opaque slots (<crate>::<module>::<Type>::<method>), plain-private impl items SHALL carry no public API surface, and trait impls together with restricted-visibility (pub(crate)/pub(in)) impl items SHALL keep named unsupported-construct gaps; impl bodies SHALL be walked so demands inside them are never silently dropped.
Scenario: Repeated extraction and formatting
- GIVEN two bundles with equivalent supported declarations, with only whitespace and checkout location different
- WHEN the pinned extractor processes both under the same profile and build context
- THEN semantic contract bytes match while raw input identities and source provenance remain accurately distinct
Scenario: Generated export cannot disappear
- GIVEN a macro or build script can generate exported declarations unavailable to the profile
- WHEN extraction runs
- THEN it reports the construct and incomplete inventory and does not invent a complete contract
Scenario: Changed build input requires new extraction
- GIVEN a prior report and changed feature selection, target, toolchain, or dependency source
- WHEN the prior extraction is submitted for the new bundle
- THEN input binding fails and a fresh extraction is required
Scenario: Text-taking public functions become genuine slots
- GIVEN a provider whose public functions take or return text (arguments of
&str,String, or&String, and aStringreturn) - WHEN extraction runs
- THEN the functions surface as function-type slots whose arguments and results carry the
text-borrowed/text-ownedscalars with no interval fields,&Stringnormalizes totext-borrowed, and the report claims complete inventory with no diagnostics
Scenario: Mutable and bare text stays unsupported
- GIVEN a provider with a public function taking
&mut str(or barestr,char,Cow<str>) - WHEN extraction runs
- THEN the report retains the unsupported-construct gap, the function surfaces as an opaque slot, and inventory is incomplete
Scenario: Public enum variants become named slots
- GIVEN a provider whose public enum declares two variants and a consumer that constructs a dep-qualified variant
- WHEN extraction runs
- THEN each variant inventories as a named slot under the enum’s qualified meaning, the single opaque enum item does not appear, the variant construction resolves as supported demand, and the extraction claims complete inventory with no diagnostics
Scenario: Trait impls and restricted impl items are disclosed per construct
- GIVEN a provider with an inherent impl exposing a public method, a private method, and a
pub(crate)method, plus two trait impls on the same type - WHEN extraction runs
- THEN the public method inventories as a type-qualified opaque slot, the private method carries no public API surface, and the report retains named unsupported-construct gaps for the
pub(crate)method and each trait impl — with no blanket impl-block gap
Requirement: Explicit consumer demand coverage
The extractor SHALL resolve supported direct consumer usages to provider slots and SHALL disclose every unsupported usage mechanism encountered in the selected source domain. Macro invocations in expression or statement position whose head is a whitelisted std macro with a closed, argument-confined expansion and whose token trees parse as a comma-separated expression list SHALL be part of the supported demand profile: their arguments SHALL be descended and any demands found there recorded like direct calls, and they SHALL NOT emit an incomplete-demand gap. Any other macro invocation in either position — an unlisted head, or a whitelisted head whose tokens do not parse as an expression list — SHALL keep the incomplete-demand disclosure rather than being silently skipped. A whitelisted macro invocation whose format string implicitly captures an identifier that names a provider item SHALL keep the incomplete-demand disclosure as well. A method call whose receiver resolves in the bounded shapes — a path expression resolving through the bounded demand rules, or a call expression whose head resolves to an inventoried constructor or free function with a recorded syntactic return type — SHALL create the demand <crate>::<Type>::<method>: resolution against the inventoried impl-method or typed slots yields supported demand, and a method absent from the inventory SHALL keep the incomplete-demand gap naming the full path. A method-call receiver outside the bounded shapes (a multi-hop chain beyond one resolved hop, field access, macro output, or an unknown identifier) SHALL keep the incomplete-demand gap naming the receiver. Enum-variant demand paths SHALL resolve as supported demand when the variant is inventoried; unknown variant paths SHALL keep the incomplete-demand gap naming the path. Incomplete demand SHALL prevent scoped-substitution acceptance. Restricting consumer demand SHALL NOT discard required inputs of any selected provider or its transitive dependencies.
Scenario: Used and unused removals differ
- GIVEN a complete supported consumer demands function a but not function b
- WHEN a candidate removes b while retaining a and all required dependency bindings
- THEN the scoped structural check can pass although a whole-provider accretion check reports the removal
Scenario: Hidden usage blocks a scoped claim
- GIVEN the consumer contains an unresolved macro, a method call whose receiver is outside the bounded resolution shapes, or a function-pointer flow
- WHEN the known direct demand would otherwise pass
- THEN the report retains the gap and refuses scoped acceptance with Unknown structural assurance
Scenario: Argument-confined std macro does not block a scoped claim
- GIVEN a consumer whose code contains a whitelisted std macro invocation in statement position (e.g.
println!("v={}", 1);) alongside a direct dependency-qualified provider call - WHEN extraction runs
- THEN the std macro emits no incomplete-demand gap and the provider call still resolves to a provider slot
Scenario: Demands inside supported macro arguments are recorded
- GIVEN a whitelisted macro invocation in expression or statement position whose arguments reference provider functions (e.g.
assert_eq!(a(), b())) and no other consumer code calls those functions - WHEN extraction runs
- THEN the demands for a and b are recorded exactly like direct calls
Scenario: Unsupported macro remains disclosed
- GIVEN a macro invocation in expression or statement position with an unlisted head, or a whitelisted macro whose tokens do not parse as a comma-separated expression list
- WHEN extraction runs
- THEN the report retains the incomplete-demand gap and refuses scoped acceptance with Unknown structural assurance
Scenario: format_args! does not block a scoped claim
- GIVEN a consumer whose code contains a routed
format_args!invocation with positional arguments (e.g.writer.write_fmt(format_args!("hello {}", "world"));) alongside a direct dependency-qualified provider call - WHEN extraction runs
- THEN the
format_args!invocation emits no incomplete-demand gap and the provider call still resolves to a provider slot
Scenario: Demands inside format_args! arguments are recorded
- GIVEN a routed
format_args!invocation with positional arguments referencing provider functions (e.g.writer.write_fmt(format_args!("v={} plus {}", add_one(1), 2));) and no other consumer code callsadd_one - WHEN extraction runs
- THEN the demand for
add_oneis recorded exactly like a direct call
Scenario: Demands inside format_args! named-argument values are recorded
- GIVEN a routed
format_args!invocation whose named-argument value references a provider function (e.g.take_args(format_args!("{x} then {x}", x = add_one(1)));) and no other consumer code callsadd_one - WHEN extraction runs
- THEN the demand for
add_oneis recorded exactly like a direct call and no incomplete-demand gap is emitted
Scenario: Format capture naming a provider item is disclosed
- GIVEN a consumer with a whitelisted macro invocation whose format string implicitly captures an identifier naming a provider value item — directly (
use provider::MAX;followed byprintln!("max={MAX}");) or through a consumer-side alias (use provider::MAX as LIMIT;followed bytake_args(format_args!("{LIMIT}"));) — and no other consumer code references that provider item - WHEN extraction runs
- THEN the report retains the incomplete-demand gap and refuses scoped acceptance with Unknown structural assurance
Scenario: Resolved method call becomes supported demand
- GIVEN a consumer whose method call’s receiver is a call resolving to an inventoried same-crate constructor with a recorded syntactic return type (e.g.
Meter::new().tick()wherenewreturnsMeter) - WHEN extraction runs
- THEN the demand
Meter::tickis recorded and resolves against the inventoried type-qualified impl-method slot with no incomplete-demand gap
Scenario: Method absent from inventory keeps gap
- GIVEN a consumer whose method call’s receiver resolves in the bounded shapes but whose method is absent from the inventory (e.g.
Meter::new().tock()) - WHEN extraction runs
- THEN the report retains the incomplete-demand gap naming the full
<crate>::<Type>::<method>path and refuses scoped acceptance with Unknown structural assurance
Scenario: Unbounded method receiver keeps gap
- GIVEN a consumer with a multi-hop method chain beyond one resolved hop (e.g.
Meter::new().tick().untick()) - WHEN extraction runs
- THEN the report retains the incomplete-demand gap naming the receiver, and the one-hop demand inside the chain is still recorded
Scenario: Variant demand paths resolve
- GIVEN a consumer that constructs a dep-qualified inventoried variant (e.g.
provider::Mode::Slow(1)) and a same-crate inventoried variant in expression position (e.g.let f = Flavor::Sour;) - WHEN extraction runs
- THEN both demands are recorded as supported and no incomplete-demand gap is emitted
Scenario: Unknown variant paths keep the gap
- GIVEN a consumer referencing
provider::Mode::Hugeand a same-crateFlavor::Salty, neither inventoried - WHEN extraction runs
- THEN the report retains the incomplete-demand gap naming each path and refuses scoped acceptance with Unknown structural assurance
112 integration failures vs. an accretive-contract versioning tool
Verdicts (about the proposed tool, not the world):
- S: detectable or preventable mechanically if the design is adopted
- P: partly; needs an extra facet (ABI, behavior, dialect, environment), laws, or adapters
- N: outside versioning (governance, business, hardware, coordination)
Examples come from memory and are not individually re-verified. Check specifics before citing.
Tally: S 43, P 57, N 12.
A. Dependency and packaging
| # | Case | Failure | V | Handling |
|---|---|---|---|---|
| 1 | left-pad unpublished | Artifact vanished, builds broke | S | Append-only immutable registry |
| 2 | event-stream takeover | Malicious maintainer shipped code | P | New capabilities show as new requires in the diff; trust is out of scope |
| 3 | Diamond ranges (npm/pip) | Incompatible ranges unsatisfiable | S | Lineage is a chain; take the max |
| 4 | Python 2→3 | Breaking change, no bridge | P | New lineage name plus mandatory adapter; language-level adapters only partly feasible |
| 5 | Caret range, breaking minor | Declared minor actually broke | S | Compatibility computed, not asserted |
| 6 | 0.x semver loophole | “Anything may change” | S | No special-case versions |
| 7 | Yanked crate/gem | Lockfiles reference withdrawn release | P | Never delete; mark with advisory edge |
| 8 | npm peerDependency duplicates (React) | Two copies, hooks break | P | Singleton contract kind; needs runtime check |
| 9 | Rust types across majors | v1 Error ≠ v2 Error | P | Adapter plus declared shared identity |
| 10 | Maven nearest-wins | Silently picks older version | S | Resolver picks max in chain |
| 11 | Dependency confusion | Public package shadows internal name | P | Namespace ownership in registry |
| 12 | Typosquatting | Lookalike package names | N | Social/registry policy |
| 13 | Phantom dependencies | Import works only via hoisting | S | Extracted demands vs declared demands |
| 14 | Floating latest Docker tag | Same tag, different bits | S | Content-addressed revisions |
| 15 | Mutable GitHub Action tags | Tag repointed to malicious commit | S | Hash identity |
| 16 | Lockfile drift between envs | CI ≠ prod | S | Hash-pinned revisions |
B. ABI and platform
| # | Case | Failure | V | Handling |
|---|---|---|---|---|
| 17 | C++ std::string dual ABI (GCC 5) | Link/runtime errors | P | ABI facet separate from API |
| 18 | Rust unstable ABI | dylib mismatch | P | ABI facet; hash must match |
| 19 | glibc symbol versions | “GLIBC_2.xx not found” | P | Symbol versioning is accretion; build floor is a requires |
| 20 | Windows DLL hell | Shared DLL overwritten | S | Content-addressed side-by-side |
| 21 | Java serialVersionUID | Deserialization fails | P | Serialization facet |
| 22 | CPython C-extension ABI | Wheel per minor version | P | abi3 = declared frozen subset |
| 23 | Node native addon ABI | NODE_MODULE_VERSION mismatch | P | Same as 22 |
| 24 | Struct padding/endianness | Layout mismatch across platforms | S | Layout facet in IR |
| 25 | FFI/JNI struct drift | Silent memory corruption | S | Layout hash |
| 26 | Linux “never break userspace” | Rare semantic regressions | P | Behavioral laws |
| 27 | Linux in-kernel API | Out-of-tree modules break | P | Explicit “unstable” lineage |
| 28 | Android targetSdk changes | Same API, new behavior | P | Defaults as slots; behavior laws |
| 29 | Swift pre-5.0 ABI | Apps bundled runtime | P | ABI facet |
C. Schema and serialization
| # | Case | Failure | V | Handling |
|---|---|---|---|---|
| 30 | Protobuf field-number reuse | Old data misread | S | Names/ids never reassigned |
| 31 | proto2 required field | Can never be removed | S | Requires polarity |
| 32 | Protobuf unknown enum value | Old client mishandles | P | Open vs closed sum flag |
| 33 | Avro non-transitive BACKWARD | v1→v3 breaks despite adjacent passes | S | Transitive closure |
| 34 | Avro added field, no default | Old readers fail | S | New provide must be optional |
| 35 | Thrift field id/type change | Wire mismatch | S | Shape diff |
| 36 | JSON int64 in JavaScript | Precision loss | P | Numeric range in scalar facet |
| 37 | null vs absent field | Semantics diverge | P | Presence as slot attribute |
| 38 | additionalProperties:false | Added field breaks strict client | S | Open/closed record flag |
| 39 | NOT NULL column, old writers | Inserts fail | S | Writers’ requires grew |
| 40 | Dropping column, old readers | Queries fail | S | Provides shrank |
| 41 | Column rename | Needs expand/contract | S | New name plus adapter (dual-write) |
| 42 | ORM/DB drift | Model ≠ actual schema | P | Extract both and diff |
| 43 | Parquet/Arrow column reorder | Positional readers break | P | Positional vs named slot flag |
| 44 | CSV header change | Downstream parsers break | S | Shape diff |
| 45 | Date format/timezone in payload | Silent misinterpretation | P | Semantic type facet |
| 46 | XML any / namespaces | Extension collisions | S | Open record with namespaced names |
| 47 | GraphQL field removal | Unknown clients break | P | Only declared demand is knowable |
| 48 | GraphQL enum addition | Exhaustive clients break | S | Output-position sum is closed |
| 49 | OpenAPI vs implementation drift | Spec lies | P | Extract from code and spec; diff |
D. Services and protocols
| # | Case | Failure | V | Handling |
|---|---|---|---|---|
| 50 | /v1→/v2 copies whole API | Coarse bump forces total migration | S | Per-slot compatibility |
| 51 | Twitter API v1.1 / pricing | Access removed | N | Business decision |
| 52 | Google Reader shutdown | Service ended | N | Business decision |
| 53 | Chrome SameSite default | Same cookie, new behavior | P | Defaults as behavior slots |
| 54 | TLS 1.0 removal | Old clients locked out | P | Capability negotiation as requires/provides |
| 55 | HTTP middlebox ossification | Protocol can’t evolve | N | Network reality |
| 56 | DNS flag day | Needs global coordination | N | Coordination |
| 57 | gRPC status/deadline per language | Divergent semantics | P | Cross-language laws |
| 58 | Retry/idempotency change | Duplicate side effects | P | Idempotency as law |
| 59 | Offset→cursor pagination | Different protocol | S | New name plus adapter |
| 60 | Rate-limit tightening | Integrations throttled | P | Non-functional laws |
| 61 | Webhook payload evolution | Receivers unknown | P | Declared demands only |
| 62 | OAuth scope restriction | Capability narrowed | P | Capability as requires |
| 63 | Parsed error strings | Clients depend on text | P | Hyrum: undeclared surface |
| 64 | Unspecified ordering (Go map) | Code relied on order | P | Declare unordered; cannot stop reliance |
| 65 | Performance regression | Complexity change breaks callers | P | Bounds as laws |
| 66 | Token TTL change | Cached tokens expire early | P | Behavior law |
E. Language and library
| # | Case | Failure | V | Handling |
|---|---|---|---|---|
| 67 | Java 9 modules | Illegal reflective access | P | Reflection surface undeclared |
| 68 | Log4j JNDI default | Dangerous default behavior | P | Defaults as slots |
| 69 | Node createCipher removal | API removed | S | Provides shrank |
| 70 | AngularJS→Angular | Rewrite under same brand | P | New lineage; adapter extremely hard |
| 71 | Perl 6 / Raku | Incompatible successor | S | Lineage rename |
| 72 | Swift 2→3 renames | Mass source breakage | S | Rename = adapter (migrator) |
| 73 | Ruby 3 kwargs | Same signature, new semantics | P | Call-semantics law |
| 74 | C undefined behavior | Optimizers exploit UB | N | Language spec problem |
| 75 | JS flatten→flat (MooTools) | Monkey-patching collided with new builtin | P | Open-world extension |
| 76 | Python async keyword | Identifiers became reserved | S | Reserved names are a shared namespace |
| 77 | Go compat promise exceptions | Unkeyed struct literals | P | Closed-record flag |
| 78 | Rust trait impl ambiguity | Added impl/method breaks callers | P | Coherence facet |
| 79 | Scala 2.12 vs 2.13 binary | Incompatible artifacts | S | Artifact suffix = lineage name |
| 80 | Java default-method conflict | Diamond default methods | S | Name collision in merge |
| 81 | Overload ambiguity | Added overload breaks call sites | P | Resolution rules per language |
| 82 | Inference breakage | Return-type change alters inference | P | Language-specific facet |
| 83 | Struct field addition | Breaks positional/exhaustive use | S | Closed-record flag |
| 84 | Floating-point determinism | Differs by platform/flags | N | Hardware/compiler |
| 85 | ICU/Unicode collation | Sort order changes | P | Dialect/environment requires |
| 86 | Regex dialects | PCRE vs RE2 behavior | P | Dialect named in contract |
F. Distributed systems and runtime
| # | Case | Failure | V | Handling |
|---|---|---|---|---|
| 87 | Rolling deploy N/N+1 | Mixed versions coexist | S | Accretion = bidirectional safety |
| 88 | Stale cached objects | Old serialization after deploy | S | Transitive compatibility |
| 89 | Kafka in-flight old messages | Long retention outlives schema | S | Transitive compatibility |
| 90 | Event-sourcing replay | Years-old events | S | Upcasters are adapters |
| 91 | Feature-flag combinatorics | Untested combinations | P | Flags as slots; explosion remains |
| 92 | Mobile long-tail clients | Old apps never update | S | Accretion keeps them working |
| 93 | Root cert expiry (Let’s Encrypt 2021) | Old devices fail TLS | N | Time/trust |
| 94 | Y2038 / int32 time | Overflow | P | Width in scalar facet |
| 95 | Kubernetes API removals | extensions/v1beta1 gone | S | apiVersion lineage plus conversion |
| 96 | Terraform provider upgrade | Resource semantics change | P | Behavior laws |
| 97 | Helm values schema | Values keys change | S | Shape diff |
| 98 | YAML “Norway problem” | Parser dialect differences | P | Dialect named |
| 99 | CRD conversion webhook failure | Conversion bug | P | Adapter law tests |
| 100 | nginx directive removal | Configs refuse to load | S | Provides shrank |
G. Standards, hardware, data, humans
| # | Case | Failure | V | Handling |
|---|---|---|---|---|
| 101 | Mars Climate Orbiter | Units mismatch | P | Units in IR |
| 102 | Ariane 5 | Ariane 4 assumptions reused | P | Environment assumptions as requires |
| 103 | Knight Capital | Reused flag changed meaning mid-deploy | S | Names never change meaning |
| 104 | HL7 v2 | Vendor-specific interpretation | P | Profiles as contracts |
| 105 | Bluetooth/USB interoperability | Implementation quirks | N | Hardware certification |
| 106 | OOXML transitional vs strict | Two dialects | P | Dialect lineage |
| 107 | CSS vendor prefixes/quirks | Browser divergence | N | Implementation diversity |
| 108 | SQL dialects | Portable SQL isn’t | P | Dialect lineage |
| 109 | Emoji version glyphs | Missing characters | N | Client updates |
| 110 | Excel gene names → dates | Auto-typing corrupts data | P | Semantic type facet |
| 111 | EDI X12 versions | Trading-partner mismatch | S | Negotiated adapters |
| 112 | tzdata changes | Future timestamps change meaning | N | Political reality |
What this changes in the design
- Contracts need facets, not one shape: API, ABI/layout, serialization, behavior/defaults, dialect, environment. Most P verdicts live in the last four.
- Defaults and environment are first-class slots. Many failures are same signature, new behavior (53, 68, 73, 28).
- Name identity must be enforced hard (103, 30, 9). A name’s meaning never changes.
- Polarity plus open/closed flags resolve a large cluster (31, 38, 48, 77, 83).
- Open-world demand is irreducible (47, 61, 63, 75). Say so in output rather than pretend otherwise.
- N cases need a different tool: governance, deprecation schedules, coordination.
50 more integration failures (113-162)
Continues the first catalog (rows 1-112). Each row below introduces a failure mechanism not used in the first list.
Verdicts (about the proposed accretive-contract tool): S = mechanically detectable or preventable if adopted. P = partly; needs an extra facet, laws, or adapters. N = outside versioning.
Sourcing: rows 113-122 were checked against web sources this session (linked). Rows 123-162 are from memory and should be verified before citing.
Tally for this batch: S 16, P 33, N 1. Combined with part 1 (162 cases): S 59, P 90, N 13.
A. Verified this session
| # | Case | Failure | V | Handling | Source |
|---|---|---|---|---|---|
| 113 | CrowdStrike Channel File 291 (Jul 2024) | A new template type defined 21 input fields, but the code feeding the interpreter supplied 20; out-of-bounds read crashed ~8.5M hosts. Data shipped outside the code release path | S | Extract arity from both the data schema and the interpreter; a mismatch is a failed accretion check. Data-plane artifacts need contracts too | RCA |
| 114 | Cloudflare outage, 18 Nov 2025 | A DB permissions change made a generated feature file double in size and exceed a hard-coded limit in the proxy | P | Declared limits (cardinality, size) become slots. Undeclared hard-coded limits stay invisible | post-mortem |
| 115 | Cloudflare leap second (Jan 2017) | Code assumed time never goes backwards; a negative duration panicked the DNS software | P | Environment assumptions (monotonic clock) as requires; cannot infer them from code | Cloudflare |
| 116 | Let’s Encrypt drops clientAuth EKU (2026) | Certificates were reused for mTLS client auth, a capability never promised for that purpose | P | Only declared demand is knowable. Consumers must declare the purpose; unknown dual-use remains | Let’s Encrypt |
| 117 | CA/B Forum SC-081 certificate lifetimes | Max validity falls 398→200 days (Mar 2026), 100 (2027), 47 (2029); manual renewal processes break | P | A scheduled sunset is a time-indexed shrink of provides; contracts need a schedule field so the break is computable years ahead | Sectigo |
| 118 | MCP spec 2025-03-26 → 2025-06-18 | JSON-RPC batching was added, then removed one revision later | S | A standard violating accretion between consecutive revisions: the checker’s exact remit | changelog |
| 119 | Redis BSD → RSAL/SSPL → AGPL | License changes forced forks and migrations | P | License as a contract facet (SPDX diff is mechanical; legal meaning is not) | InfoQ |
| 120 | Redis vs Valkey after the fork | Forks diverge: newer RDB files are not interchangeable, so data needs a logical migration | P | Fork = two accretions from a common ancestor; a pushout exists only if no semantic collision, so divergence is detectable but not repairable | migration guide |
| 121 | ChatGPT model retirements (Feb 2026) | GPT-4o and others left ChatGPT; existing chats defaulted to a successor model. API access was unchanged at announcement | P | Mutable aliases are an identity problem (pin by hash: S). Behavior drift of the successor is not | YourStory |
| 122 | Chrome third-party cookies / Privacy Sandbox | A planned replacement stack was built on, then 10 APIs were retired Oct 2025 while cookies stayed | P | Stability tiers: an experimental lineage may be retracted, and the tool should label it so consumers know | Engadget |
B. From memory (verify before citing)
| # | Case | Failure | V | Handling |
|---|---|---|---|---|
| 123 | Bitcoin fork, Mar 2013 | Versions 0.7 and 0.8 disagreed on a database-imposed limit; the chain split | P | Implicit consensus rules defined by an implementation must be declared as contract |
| 124 | Upgradeable smart-contract proxies | New implementation reorders storage variables and corrupts state | S | Layout facet; append-only storage slots |
| 125 | Parity multisig library (2017) | A shared library contract was destroyed, freezing dependent wallets | P | Dependency liveness as requires; irreversible operations flagged |
| 126 | Git SHA-1 → SHA-256 | Hash algorithm is part of object identity; repos are mutually unreadable | P | Hash algorithm belongs in identity; interop needs a bridge adapter |
| 127 | OpenSSL 3.0 providers | Legacy algorithms moved behind a provider not loaded by default | P | Capability set as provides; loading is environment |
| 128 | Kubernetes dockershim removal | Container-runtime interface dropped from kubelet | S | Provides shrank; external adapter (cri-dockerd) existed |
| 129 | Kubernetes PodSecurityPolicy → Pod Security Admission | Replacement is less expressive, so policies cannot be translated exactly | P | Lossy adapter; the tool should report what is lost |
| 130 | Chrome Manifest V2 → V3 | Blocking webRequest capability removed from extensions | S | Provides shrank; resolution is a policy choice |
| 131 | Safari ITP storage caps | Script-writable storage can be purged after days without interaction | P | Durability as a declared guarantee |
| 132 | macOS Catalina drops 32-bit apps | Unmaintained binaries stop running | P | Adapters impossible without a maintainer |
| 133 | Adobe Flash end of life | Plugin platform removed; content stranded | P | Emulators (Ruffle) act as adapters |
| 134 | GitHub master → main | Scripts hard-coded the default branch name | P | Conventions hard-coded instead of declared |
| 135 | PEP 668 externally-managed environments | pip install into system Python now errors | P | Tooling policy change; environment requires |
| 136 | Webpack 5 drops Node polyfills | Bundler had implicitly provided shims | P | Extract implicit provisions from tooling |
| 137 | colors / faker sabotage (2022) | Owner shipped intentionally broken versions | S | Registry rejects a breaking change without a new name |
| 138 | HTTP request smuggling | Front-end and back-end parse message length differently | P | Cross-implementation conformance laws |
| 139 | Gmail/Yahoo bulk-sender rules (2024) | Receivers tightened authentication requirements; mail rejected | P | Receiver’s requires grew; senders may not track them |
| 140 | CPython free-threaded build | Extensions assumed a global interpreter lock | P | Thread-safety facet, opt-in declaration |
| 141 | NumPy 2.0 C-API change | Wheels built against 1.x failed under 2.x | P | ABI facet; build floor as requires |
| 142 | Protobuf generated code vs runtime | Old generated files rejected by newer runtime | S | Generated artifact embeds a required-runtime range |
| 143 | PostgreSQL major upgrades | On-disk format incompatible across majors | S | Each major a lineage; pg_upgrade is the adapter |
| 144 | Elasticsearch / Lucene index lookback | Indices only readable one major back | S | Deliberately non-transitive; checker flags it |
| 145 | Kafka rolling upgrade | Protocol/message-format pins force a two-phase upgrade order | P | Deployment sequencing is outside the contract |
| 146 | Terraform state upgrades | Newer versions write state older ones cannot read; no downgrade | P | Edges can be irreversible; declare reversibility |
| 147 | Python PEP 517 build isolation | Builds that relied on ambient build deps failed | P | Build-time contract |
| 148 | ISO 20022 / MT coexistence | Richer messages truncated when translated to old format | S | Adapter round-trip law detects loss |
| 149 | 3G network sunset | Devices lost connectivity | N | Infrastructure retirement |
| 150 | Excel 1900 leap-year bug | A deliberate bug kept for compatibility | P | Quirk lineage: bug-compat declared, not hidden |
| 151 | OpenSSL 1.1 opaque structs | Code touching struct fields broke | S | Closed/opaque layout flag |
| 152 | Case-insensitive filesystems | Repos with case-colliding paths break on macOS/Windows | P | Filesystem semantics as environment |
| 153 | LB idle timeout vs backend keep-alive | Intermittent 502s from mismatched timeouts | P | Relational constraint across two contracts |
| 154 | Retry amplification | Each layer retries; compatible parts overload the whole | P | Compositional law (retry budget) |
| 155 | JVM DNS caching | Client ignores TTL; stale endpoints | P | Client behavior vs protocol |
| 156 | Repo signing key rotation | Key change breaks installs | P | Trust-anchor lineage |
| 157 | WASI preview1 → preview2 | Module interface model replaced | S | New lineage plus adapter |
| 158 | Sync → async API change | Same name, new calling convention | S | Effect facet (async is a different type) |
| 159 | Ethereum/ETC fork replay | Signed transactions valid on both chains | S | Lineage id inside signed payloads (chain id) |
| 160 | WordPress “Tested up to” | Host compatibility is a human claim | P | Replace assertion with checked compatibility |
| 161 | pip’s stricter resolver (2020) | Enforcement exposed conflicts old installers hid | S | Adoption needs baseline/grandfather mode |
| 162 | Old client read-modify-write | Typed clients drop unknown newer fields on update | S | Round-trip law: preserve unknown fields |
What this batch adds to the design
- Data-plane artifacts need contracts (113, 114): content files, feature files, templates.
- Declared limits are slots (114): sizes, cardinalities, timeouts.
- Sunset schedules and stability tiers (117, 122): breaks can be computed years ahead, and some lineages are explicitly retractable.
- Standards can violate accretion too (118).
- Adapters need laws (148, 162): lossless round-trip and unknown-field preservation.
- Lineage id belongs in identity (126, 159).
- Relations between contracts (153) and emergent properties (154) are beyond per-contract checking.
- Irreversibility and sequencing (146, 145): edges can be one-way; upgrade order matters.
- Adoption mode (161): first enforcement will surface latent breaks, so a baseline is required.
llms.txt
The machine-readable landing page, mirrored from llms.txt and served at https://wild.charlyvibes.com/llms.txt.