The normative specification of the CIC object model, its conformance vectors, and two independent reference implementations, in Go and in Rust.
SPEC.md is the authority. The implementations are subordinate
to it: where an implementation disagrees with the specification, the
implementation is wrong.
Model version 0.2. SPEC.md declares it; TestVersionIdentity holds every
other declaration in the repository to that number, because 0.2 was once
written into SPEC.md and propagated nowhere else.
| Component | Status |
|---|---|
SPEC.md — 44 numbered invariants |
written, normative |
conformance/ — 31 vectors |
executed against Go on every CI run |
docs/spec-vector-map.md |
37 invariants vector-covered, 5 declared unvectorizable with a reason each |
tools/check_spec_vectors.py |
runs and passes; negative-tested |
go/ |
implemented — corpus, fuzz, mutation, adversarial and CLI golden tests |
rust/ |
implemented — corpus, reader, rejection and CLI golden tests |
mk/rust.mk |
present; digest-pinned toolchain, make rust.quality |
| Docker build / CI | runs; make ci is the same pipeline locally and in Actions |
Both implementations pass all 31 vectors, and neither was written from the
other: the Rust one was written from SPEC.md and the corpus, deliberately not
from go/. Two implementations that share an author's reading share that
reading's mistakes, and their agreement then proves nothing.
§8.8.1 defines the canonical serialization byte for byte, and §8.8.2 the member order. Both runners compare bytes, and the two implementations produce byte-identical objects on all 13 materialization vectors.
Before that was written they produced zero identical objects while agreeing
on every one semantically, and both were conformant — INV-030 alone only
constrains an implementation to agree with itself. A digest taken over a
canonical object now has a defined input.
Two properties are being frozen, and both need to be frozen before code exists rather than distilled from it afterwards:
- The recursive node model — primitives are not metadata attached to a
node; they are CIC nodes themselves, which is what makes
network.values.mtu.access.readan addressable, hashable, governable object rather than a path into a YAML blob. - Closed semantics — notably
origin's four permitted forms, and the three-rule object closure that leaves no way to smuggle an uninterpreted object graph past the model.
Spec, vectors and both implementations live in one repository on purpose. A semantic change then arrives as a single change — SPEC + vectors + Go + Rust — and it becomes physically awkward to alter one implementation's behaviour without the corpus and the other implementation noticing. That mutual check is the reason there are two implementations rather than one.
SPEC.md the normative specification
spec/ machine-readable schemas for the model itself
conformance/ the falsifiable part — YAML in, YAML out
materialization/ authoring input -> canonical object
invalid/ input that MUST be rejected
validation/ canonical object -> accept / reject
docs/
spec-vector-map.md every invariant -> its vectors, or why it has none
decision-delta.md what this model changes in D-003 / D-011
migration-surface.md the measured file list this model would change
branch-decision.md why base-repo wasm/main
rust-gate-extraction.md line-referenced recipe for mk/rust.mk
go/ reference implementation
rust/ reference implementation
make ci runs the whole pipeline and is what CI runs — there is no separate
command, so a green badge and a green local run mean the same thing.
| Target | What it does |
|---|---|
make ci |
the full pipeline: gates, spec checks, Go build/test/coverage |
make check |
Python/YAML quality gate |
make manifest-verify |
MANIFEST.sha256 describes the tracked tree exactly |
make docs.link-check |
internal documentation links resolve |
make golang.quality |
Go gate over go/ |
make golang.coverage-threshold |
fails below COVERAGE_MIN (90%) |
make rust.quality |
the Rust gate: pin, fmt, clippy, coverage, cargo deny |
make conformance |
run the corpus against every present implementation |
make verify |
fuzz, mutation and adversarial suites |
tools/check_spec_vectors.py runs in CI and fails if SPEC.md and the vector
corpus drift apart — if an invariant claims a vector that does not exist, or a
vector claims an invariant that does not. It checks the mapping; it does not
run vectors.
SPEC.md§2 (node model) and §4 (the discriminator) — the two sections everything else depends onSPEC.md§5 (origin) and its truth tableconformance/README.md— the vector formatdocs/decision-delta.md— what this changes and what it would otherwise have lost silently
CC-BY-NC-SA-4.0 — see LICENSE.md.