A shared system for reconstructing task-specific working theories from durable, contested evidence — and for identifying the observations that would most improve them.
This repository implements the first two stages of the LOOM v0.3 recursive build specification: Stage 0 — Kernel & Genesis — and Stage 1 — Evidence & offline D1.
The specification is in genesis/. It is not documentation about this
code. It is input to it: on ingestion the corpus becomes the first content in
its own substrate, its N-series becomes ratified law, its P-series becomes recorded
proposals that are pointedly not law, its open questions become the ignorance map,
and the places where this implementation already departs from it become the record's
first divergences.
loom init
loom ingest # the corpus becomes data for the system it specifies
loom verify # run the verifier catalog, record the runs
loom extract # P0/P2/P3 over the tree and the change graph
loom law # Gate G0 · 1 — what is ratified vs. proposed?
loom questions --blocking D1 # Gate G0 · 2 — what unknowns block the wedge?
loom divergences # Gate G0 · 3 — where do spec and code diverge?
loom backtest # mine labeled pairs from history, calibrate D1
loom detect # run the wedge over the working tree
loom selfmodel # what the record can measure about itself
Build with cargo build --release; the binary is loom.
§14's Stage 0 is: act log + CAS + projection engine; identity lattice +
canonicalizer; batch P0/P2/P3 on frozen snapshots; jj via CLI; ingest the Genesis
Record. Gate G0 is AC-KRN-*, AC-CANON-*, AC-GEN-1, plus the requirement that
Stage-0 LOOM answer three questions about its own development.
| Stage-0 requirement | Status |
|---|---|
| Signed, content-addressed, append-only act log | built (loom-core) |
| Content-addressed blob store | built |
| Deterministic projection engine | built; merge is associative/commutative/idempotent under test |
| Felicity conditions, machine-readable grounds | built; 25 kernel acceptance tests |
Identity lattice, syntax_id / resolved_id |
built (loom-canon) |
| Batch P0 / P3 | built (loom-extract) — provisional, see DIV-P0-PROVISIONAL |
| Batch P2 co-change | built, with lift, decay, stratification, direction, N11 filtering |
| jj via CLI | not built — history is read through git, see DIV-SUBSTRATE-JJ |
Genesis ingestion, AC-GEN-1 |
built (loom-genesis) |
| Gate G0's three questions | answered by the record, from the record |
Stage 1 is: full L1 with lineage; D1 candidates + scorer; V1 backtests with
pretraining-leakage controls; LOOM continuously ingests its own repo. Gate G1 is
AC-DET-1 on an external corpus and AC-SELF-1 on LOOM itself.
| Stage-1 requirement | Status |
|---|---|
| D1 candidate generation | built (loom-detect) — skeleton equality, deciding nothing |
| Calibrated relation scorer | built; uncalibrated it withholds delivery entirely |
| Backtest with leakage controls | built — V1 is undefined in the corpus, see DIV-V1-INTERPRETED |
| Evaluation on an external corpus | not done — fixture only, see DIV-NO-EXTERNAL-CORPUS |
| Continuous re-extraction | built; an unchanged tree produces no acts |
| Full L1 | partial — P1 asserted and P4 observed absent, see DIV-L1-INCOMPLETE |
AC-SELF-1 on LOOM itself |
built and verified against fixtures |
The gaps are not footnotes. They are propositions in the log, and
loom divergences prints them without being asked.
| Crate | What it is |
|---|---|
loom-core |
The kernel. Acts, canonical encoding, blob store, ledger, projection, felicity, quotation-only reflection, lineage economics, warrant labeling. |
loom-canon |
The identity lattice. Rust and Markdown canonicalizers, syntax_id, skeleton and behaviour fingerprints, the N11 cosmetic rule. |
loom-extract |
L1 evidence. Batch P0 structural, P2 co-change, P3 shape over frozen snapshots. |
loom-detect |
D1. Candidate generation, the relation scorer, calibration, and the backtest that fits it. |
loom-genesis |
Stage-0 ingestion and the registry v0 predicate declarations. |
loom-cli |
loom. |
Each is a named failure mode in §17, blocked by the schema rather than by policy — because policy that lives in prose is policy nobody runs.
Infelicitous acts (AC-KRN-1). A write that cannot come off is refused before
it is signed, with a machine-readable code: an attestation with no lineage, a
verifier run against a binding that does not exist, a DECIDE that records neither
an alternative nor an admission that none was weighed. Acts arriving in a pack
from elsewhere cannot be refused at write time, so they are quarantined with their
grounds — never silently dropped.
Reflection by live reference (AC-KRN-2). Subject has no variant naming
current state; predicates in the self. family must take a content hash of a
frozen object. The system speaks about snapshots of itself, never about itself
in flight. Content addressing supplies the Gödel-numbering; quotation-only
reference blocks liar-style fixed points structurally.
Norms without a ratifying act (AC-GOV-3). Twenty attestations of a regularity
produce zero norms. Norm objects enter a projection through exactly one door —
RATIFY, by an office that holds the power — and that act may cite the very
evidence that could not create it alone. Where it does, the record flags
GOV-DESCRIPTIVE-ONLY-BASIS, so the one-way porosity is visible rather than
assumed.
Corroboration that launders one source into many (P5, AC-IFC-2). Effective
evidence counts independent causal roots after collapsing shared lineage. Wash one
claim through nine restatements and it is still one observation. Strip the
provenance to look independent and it counts for less, not more: unrecorded lineage
is presumed correlated.
And one thing it refuses to pretend: a chain is proof-carrying only when every
leaf is verifier-grade. Interior nodes get no vote, so a chain of impeccable
reasoning over an LLM's reading of a comment is an argument however it is dressed
(AC-PCR-1). A verifier that does not exist appears in the chain as Absent and
makes it an argument — absence is represented, never defaulted (AC-KRN-4).
The same rule bites in the other direction, which is where it earns its keep.
loom why AC-LOCK-1 could truthfully report proof-carrying — the corpus really
does contain that text at those bytes, and that is a checkable structural fact. But
someone asking "why?" about a criterion is asking what standing it has, not whether
the document exists. So the chain answers the question that was asked, and the
missing verifier appears in it:
acceptance_criterion — AC-LOCK-1
claim: every served projection emits a lockfile; DECIDE without lockfile is infelicitous.
label: argument-carrying
· every served projection emits a lockfile; DECIDE without lockfile is … — structural fact
· is AC-LOCK-1 satisfied? — ABSENT: no verifier in the catalog decides whether AC-LOCK-1 holds
The product wedge is incomplete fix propagation: a repair lands in one place and
should have landed in two. §13 separates two jobs that are usually run together —
skeleton similarity generates candidates, a calibrated relation scorer decides
— and loom-detect is on one side of that line or the other throughout.
The rule the crate is built around:
An uncalibrated scorer reports a raw score and refuses to report a probability.
A weighted sum of structural features is a number between zero and one. Calling it
a probability before anyone has checked it against labeled outcomes is most of what
goes wrong with detectors, and the fix is not a better weighting — it is refusing to
say the word. Run loom detect on a fresh record and every finding comes back
withheld, with its raw score and the reason. Delivery strata are gated on Wilson
lower bounds over a minimum sample count (N6), so twenty-for-twenty is 0.84, not
1.0; and a calibration fitted for different weights does not transfer to new ones.
loom backtest is what earns the probability. It asks the only question that
matters: standing at the moment a fix landed, knowing only what was knowable then,
would the detector have named the place the fix failed to reach? Ground truth comes
from the repository's future — the same fix shape arriving somewhere else, later —
computed over canonicalized patches, so "the same repair" survives two functions
having no context in common.
V1 is one of the identifiers the corpus cites and never defines, so the harness is
this implementation's reading of the requirement, filed as DIV-V1-INTERPRETED. Its
leakage controls are recorded with every result rather than asserted in a comment:
· candidates drawn from the tree at the fix commit's parent, never the working tree
· features computed from that same parent tree
· co-change accumulated strictly from commits before the fix commit
· labels drawn strictly from commits after the fix commit, never fed to the scorer
· calibration fitted on one half of anchor commits, precision reported on the other
· scorer is deterministic arithmetic over structural features: no pretraining
corpus exists to leak from
That last line matters and is not a boast. The risk class "pretraining leakage" names is genuinely absent here, and saying so is not the same as being safe — the live risk is temporal, and it is easy to commit by accident, which is why the other five controls exist.
On a fixture with planted ground truth — including decoys that share the helper and
the co-change history but never receive the fix, so the data is not separable —
held-out precision is 333,333 ppm against a base rate of 142,857 ppm. That is a
measurement of the machinery on a corpus we wrote. It is not evidence about real
repositories, and DIV-NO-EXTERNAL-CORPUS says so.
AC-SELF-1 wants coverage and calibration answers that are queryable, current and
honest. The first two are structural: the model is computed from a projection and
names the frozen snapshot it measured, so it cannot drift from what the record holds.
The third is why everything countable is counted. loom selfmodel on this
repository, before any extraction:
blind regions
· 2 declared world(s) never observed: dev, ci
· 5 extraction tier(s) have produced nothing: P1/asserted, P2/inferred, …
· 12 of 26 acceptance criteria have no verifier; their status is unknown, not satisfied
· 45 verifier binding(s) exist but have never run
· 1 detector(s) uncalibrated and therefore delivering nothing: D1/fix-propagation
boundary map — what the substrate does not hold at all
· the substrate holds what was written down. It does not hold the reasoning that
produced the corpus, the alternatives weighed before the N-series was fixed, or
any tacit competence of its authors.
· 9 identifier(s) the corpus cites are defined in documents the record does not hold
· no runtime witness: every commitment in this record is unsettled
· 24 recorded divergence(s) are what the record knows it got wrong; it cannot
enumerate what it does not know it got wrong.
Every number there is a count, not a claim. A self-model whose figures are typed in by the same hand writing the prose is a mood, and the tests check it against fixtures where each number is one we chose in advance.
Run the commands; the answers come from the log. In summary, as of ingestion:
Ratified vs. proposed. Twelve N-series kernel laws in force. Twelve P-series
proposals recorded and not law, each labeled awaiting-ratification and sitting on
the docket under Q-P-RATIFY. Twenty-six predicate declarations ratified with the
kernel per Appendix C — none of which ships an invented authority half-life, because
Q-DECAY is open.
Unknowns blocking D1. Seven, most of them created by building rather than found
in the corpus: Q-PAIR-SUBJECT (D1 is a claim about pairs, and §2.4's lattice has
no subject for one), Q-EXTERNAL-CORPUS, Q-SCORER-WEIGHTS (the scorer's weights
are policy sitting in a source file, unratified), and Q-DELTA-ABSENT.
Divergences. Twelve between corpus and implementation, twelve acceptance
criteria with no verifier bound, and nine identifiers the corpus cites but never
defines. The most consequential is DIV-DELTA-ABSENT: five sections declare that
the v0.2 normative delta governs on conflict, and Appendix B defers to its text over
its own restatement — but the delta is not in the corpus. Every N-series
ratification here therefore rests on a summary of law whose authoritative text the
record does not hold. The system reports this about its own foundations, at
ingestion, without being asked.
The docket currently runs ~490 minutes against a 90-minute weekly budget. The budget
is provisional (Q-BUDGET) and the overflow valves — consolidation and
threshold-raising proposals — are Stage 5. The record says so rather than trimming
the number until it fits.
L2–L6 exist as schema, not as machinery: lazy belief compilation, belief lockfiles, commitments and settlement, the observation planner, consolidation and doctrines, offices beyond the founding three, the runtime lens. There is no MCP surface, no daemon, no shadow PR artifact, and no P1 asserted or P4 observed extraction — so two of the five evidence tiers produce nothing and the laundering paths they open are untested.
loom divergences --verbose enumerates the criteria this leaves unverified. None of
them is reported as passing.
.loom/ is git-ignored: it holds a signing key, and it is reproducible from the
corpus with loom init && loom ingest --as-of <ms>. Fixing --as-of makes
ingestion deterministic for a given key — same corpus, same speaker, same act ids.
The log is JSON Lines and the blob store is a hash-sharded directory tree, both
readable with cat. That is firewall 3 (model/substrate) rather than a convenience:
institutional state that only one program can read is institutional state that
program owns.