Move 0 of the fabric arc. Before the map learns to read shell scripts and, later, a practice's actual truth, this contract fixes the rules every new language must obey — so an edge is always real, a blind spot always confesses, and no dialect ever has to negotiate meaning with another. Five scouts surveyed the field first; an independent reviewer graded the result twice (7 → revise → 8.5/10, BUILD). Four calls are yours. Everything else is settled or fenced.
The concrete thing to hold: a line in our CI config that runs a test script. Today that wire is invisible to the map. Here is its whole life under the contract.
ADOPT (architecture): per-dialect extractors feeding one queryable substrate — CodeQL (extractor per language, per-language schemas into shared query machinery) and Meta's Glean. The field's at-scale practice is shared substrate + thin join — exactly our split. ADOPT (shapes): in-toto's digest-binding ("subjects matched purely by digest" — fetched verbatim); SCIP-over-LSIF's human-readable string keys (debuggability won); SPDX 3.0's completeness-as-first-class-metadata precedent.
DIVERGE (justified): the field over-approximates unresolvables (Joern's external stubs with sound propagation; Bazel's select-union). We carry the same candidate set as fence doors, never as edges — our consumers make trust decisions; a laundered edge is our false green. The doors ARE the union, labeled.
REJECT: universal semantic unification (OWL usability failure — fetched; scoped-protocol wins — SCIP half fetched, LSP half synthesis, the reject stands on fetched legs). The named anti-pattern, now cited from the source's own bytes: scip.proto's occurrence symbol field is literally annotated "(optional)" and the protocol has NO field for unresolved references — a failed resolution is an absent field, silently. That silence is what our fence replaces.
KILL-CHECK: fires nothing. GUAC aggregates but its gaps are absence-of-data, not structured fences; CodeQL exposes extraction errors as diagnostics OUTSIDE the queryable database. No candidate covers per-edge receipts + first-class fences + pluggable dialects.
G-M0-1 [M]: a fence citing an axis outside its dialect's declared enum → registration throws. Deliberate-break fixture included.
G-M0-2 [M]+[J]: axis ids are dialect-namespaced. Machine leg rejects (a) a fence whose namespace isn't its own dialect, (b) an enum containing another dialect's namespaced member. Bare homonyms allowed — the live example: "computed-path" exists today in two of our own modules meaning two things; forcing global uniqueness would be the ontology trap itself. Judgment leg: new-dialect registration includes the lead's one-page review with the negotiated-meaning question answered in writing.
Generalizes the closed-enum throw discipline already live in the flow lens (frozen enum + membership validation that names the rejected family explicitly).
DialectExtractor {
id // 'import-js' | 'scip' | 'shell' | 'neuron-projection'
edges(pin) -> ProvenEdge[] // ONLY provably-real (never-lie floor; no heuristic class)
fences(pin) -> Fence[] // named blindness, per-target where extractable
blindAxes() -> BlindAxis[] // this dialect's OWN closed frozen enum
fixtures: { mustFire, mustNotFire, deliberateBreak } // gate-run at every merge
}
Fence {
axisId // namespaced <dialectId>/<axis>
at: {file,line} | {scope} // SITE fence, or SCOPE fence for traversal-bound
// blindness with no source location (e.g. a depth cap)
// — a fence with no site NEVER invents one
doors: [{to?, why}] // the labeled over-approximation
grepPattern // fences carry their handle
}
Dual face: the canonical face is "enumerate your edges and fences at this pin"; a dialect may compute lazily inside (our CI parser answers point questions today and keeps doing so — the retrofit wraps it in an enumerator; the existing gate consumer keeps its face through a shim, zero behavior change, proven the same two ways move 1 demands). A dialect that can't enumerate isn't a dialect yet — it ships fence-only.
G-M0-4 [M]: every dialect's fixtures run at gate time; a dialect whose deliberate-break does NOT go red is vacuous and fails — both fence directions (missed real edge AND real consumer swept into blind) mandatory.
SourceReceipt { file, line, quote, contentHash } // parsed-source dialects
DeclaredReceipt { pointer, pointerKind: 'pr'|'commit'|'test-run'|'transcript',
verifiedDate } // declared-record dialects
Stated honestly (review catch): neither existing engine carries receipts today — import edges are bare from→to pairs; the C# engine discards occurrence positions and dedups references. Move 1 BUILDS receipt derivation for both, with deterministic licensing rules (import: first matching import line; C#: first occurrence in file-then-line order). Receipts are additive — excluded from the zero-behavior-change byte-diff. If any existing edge's receipt proves underivable, that is move 1's KILL clause (contract redesign) — never a silent edge-set shrink, never a fabricated receipt.
G-M0-3 [M]: completeness is per receipt kind — all four source fields, or all three declared fields. A receipt matching neither kind fully is rejected.
Node keys are repo-qualified: a registered repo short-name plus a per-class canonical key (repo-relative path for files; fact id for facts; leg id for gates). No dialect mints a new node class OR repo name without a registered one-page key scheme, lead-ratified. Key schemes name THINGS, never meanings — the only cross-dialect agreement the contract permits. The envelope carries a per-repo pin map, never a single pin.
Weighed and rejected — the field's strongest alternative shape for epistemic labeling: Bazel/Buck2 expose separate query surfaces per resolution stage. Rejected: our dialects form no resolution pipeline — a pinned snapshot is already the single named state, so staged surfaces would multiply query APIs without adding states we possess. What we adopt is the principle: the resolution state is always NAMED, never implied — here, by the pin map on every envelope.
G-M0-6 [M]: declared-record staleness fails closed — a claim whose verified-date predates newer evidence renders "[STALE — last verified date]"; the deliberate-break (serve it present-tense) must go RED. A record appended without an evidence pointer is rejected at write time. Arms at first declared-record dialect registration, not at move 1 — a gate demanding unbuilt machinery would force scope creep or a forbidden skip.
G-M0-5 [J]: this spec's own bar — independent graded review ≥8/10 with an outward frame-fitness lens empowered to reject the intent itself. Two passes: 7/10 REVISE (nine findings, all verified against disk before folding) → 8.5/10 BUILD (conditions folded, independently re-verified).
Working name: the Fabric Arc. Candidates if you want them: Fabric (what it is), Loom (what it does — weaves fact to surface). Or yours. One word settles it.
Carried from the fabric plan, still formally open: after shell, the next language the map learns is a veterinary practice's actual truth — with the mechanical spine already ratified (a projection edge is real only when the build recorded "fact X filled slot Y"; agreement without that record is fenced, never proven).
The grade bar is met (8.5/10, BUILD, conditions folded and independently re-verified). On your word, move 1 starts: retrofit both engines, zero behavior change, twin proofs.
It stays a use-case the contract must not preclude — nothing built, sequencing deferred under your memory-testimony ruling until the fabric reaches that domain concretely. Your call here is narrow: confirm this holding position is right, or strike the board-question material from the contract entirely.
Decisions: proven-or-fenced · algebra-not-meanings · two receipt kinds · repo-qualified names
Gates: G-M0-1 axis membership · G-M0-2 anti-ontology · G-M0-3 no naked edges · G-M0-4 fixture vacuity · G-M0-5 this review · G-M0-6 declared staleness
Your calls: name · dialect #3 · ratify · board holding
Risks: ontology creep · can't enumerate · fence mirage
SCAI (in-toto's attribute predicate) — 15-minute read before move 1; fold or dismiss in writing. Sigstore graph tooling — same. GUAC's actual GraphQL schema — fetch before treating "no fence primitive" as discharged. The RDF-economics paper — re-fetch before that framing enters canon. The tipping-point boundary — falsify against real dialect accumulation at moves 2/4.
Canonical source: docs/ai/SPEC-move0-dialect-contract.md (Markdown wins on any disagreement). Provenance: five-leg frontier scan, lead-adjudicated, internal receipts grep-verified on disk; graded 7 → folds verified → 8.5 BUILD; board-question fold from the Robert-approved Neuron handoff; call #4 reframed under intent/ruling/memory-testimony (ratified in-chat 2026-07-05).