Do not build on this repository. Do not treat
SPEC.mdas a current CIC contract. It is kept public and read-only as a record of an attempt.Abandoned on 2026-08-10 by the owner's decision, stated as: "it turned out to be a wrong concept." No further rationale was recorded, and none is invented here.
This was not abandoned because it was broken. At the point it stopped, the corpus was green and the known defects were being closed in the open:
docs/spec-defects.mdcatalogues 19 specification defects, 9 of them marked fixed in model 0.2, each with the reasoning. The hardest one —INV-033, which demanded that a canonical object carry its own model version while §2.1 left nowhere to put it — was resolved rather than patched: the version became a property of the hand-off frame, not a member of the object.What was rejected is the shape of the model, not the state of the work. The CIC primitive language continues as
atomic → aggregate → domain compositionincic-primitives.The ontology and its execution:
Node { values, origin, primitives }· every primitive being itself a recursive CIC node · the schema-positionvaluesdiscriminator · theorigintruth table ·sealed_fromtemplate materialisation · this repository's restructuring of Access · its canonical YAML shape · the materializer pipeline's semantics.A structural constraint worth understanding before anyone proposes it again:
origincannot be a primitive. Every primitive is a node, every node has anorigin, so anoriginthat were a primitive would need one of its own, without end. It is the fixed point that terminates the recursion, and a fixed point cannot be a member of the set it terminates (SPEC.md§6.2).The input-hardening layer, which knows nothing about the ontology above it. Measured 2026-08-12, counting model-specific identifiers per file:
file lines model references rust/src/value.rs377 0 rust/src/error.rs114 1 rust/src/canonical.rs282 13 rust/src/node.rs202 25 rust/src/materialize.rs645 65
value.rsrefuses duplicate mapping keys at the event level, refuses anchors and aliases before a tree exists (measured amplification: 393 bytes → 12,345,678 nodes in 2.7 s), enforces string keys and preserves insertion order. That layer is portable. The pipeline above it is not —materialize.rs, the largest file, is written in the rejected ontology throughout.Reusable as method rather than content: the error model (code + invariant + stage + object path), a conformance harness that cannot report success with zero vectors, byte-exact comparison, and the boundary type whose constructor is private so that only the validator can produce one.
Two independent implementations, written from the specification rather than from each other, found two real divergences the conformance corpus could not see: on a duplicate mapping key Go rejected the document while Rust silently took the last value; on aliases they disagreed in the other direction. Neither case appeared in any vector. They became
INV-041andINV-042.A corpus proves what it contains. Only differential execution finds what nobody thought to write down.
Into a separate repository of its own — not here, and not inside
cic-primitives. Rebuilding it in place would recreate exactly the everything-in-one-model repository this one became.
mainis 28 commits behinddevel.devel(4918240) carries the furthest state: the second implementation, the canonical serialization work, and the later defect closures. Neither branch is maintained.
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.