Plato · Substrate spec · v1 draft · for red-pen

The Trustworthy Wiring-Map

An agent is about to change one file in a repo too big to hold in its head. Grep is noisy — and blind to how real code is wired (a component referenced by a string, a page that mounts an island by name). So it greps, sees “no importers,” ships, and two pages break that it never knew existed. Plato answers one question — what does changing this break? — with either a clean, commit-pinned list or an honest “I can’t see your consumers here — fall back to grep.” Never a third answer. That honesty is the product.

Draft for Robert’s annotation · not approved · no building yet
01

The spine — what the evidence locked

From the one-job investigation (grounded on Neuron + the code-intelligence field; adversary verdict revise-the-plan). Everything below is built to these.

The asset
A trustworthy map of the true wiring
Not a feature — a substrate. Every file and every real producer→consumer edge, pinned to a commit, honest about what it can’t see. Every other Plato question is a query on this one map.
Query #1
Blast-radius: “what breaks if I change X?”
The highest-frequency structural question in an agent’s edit loop, and the one whose wrong answer does the most damage. Making it honest forces all four trust gates at once — so we lead with it, and the same map serves the rest.
The seal
Currency rides inside every answer
Not a separate job. A blast-radius from a stale map is itself a lie — so every answer carries a commit-pinned proof the caller recomputes. Mutation-tested: tamper the hash → red; drift the pin → red.
The unlock
The fence, not completeness
We will never see every edge in a real repo. “Functional” = see the edge, or say “I can’t see this” — loudly, on the right axis. A map that admits its blind spots beats one that hides them.
02

The map — two layers that fail in opposite ways

Not the clean three-tier stack we first drew — the measurements forced a sharper cut.

R1 (the non-negotiable): a backward-reach query never returns a bare “0 consumers.” It returns the real consumers, or “consumers unknown — wired by <class>, fall back to grep.” A confident “nothing depends on this” when Plato is actually blind is the cardinal sin.
cannot lie
Currency
The integrity floor. Recomputes a git blob hash; fails closed on pin-drift or content mismatch. Proven RED on deliberate breaks. This layer is done.
the build
Reachability
The product. Blast-radius (backward) is query #1. Can lie today — silently returns 0 on registry-wired files — so it must be fenced before it ships. This is the work. (§03, §05)
03

Query #1, beat by beat

One MCP call — plato_reach_graph backward on the file about to change.

  1. Pin to HEAD. Read live HEAD; build (or warm-cache-hit) the snapshot at that exact commit. The answer is stamped with this pin.
  2. Walk the real edges backward. Every committed producer→consumer import edge that reaches the target — direct and transitive. Excludes the comment/prose noise grep includes.
  3. Fence what it can’t see — the load-bearing step. Before answering, name the inbound-edge classes the static graph can’t represent for this file (string-registry, .astro-host, dynamic-import). If the file is in a blind class and reach is 0, return “consumers unknown — fall back,” never “0 consumers.” This is the difference between a tool and a trap.
  4. Seal with currency. Attach the commit-pinned proof so the caller can recompute and confirm the answer reflects HEAD right now.
  5. Answer, or admit blindness. A clean consumer set where it can see; an honest fence where it can’t. Both are trustworthy; a confident wrong 0 is not.
↘ go deeper — the verified failure this fixes
Recomputed from raw (read-only on Neuron): FAQAccordion.tsx backward reach = 0 on a live shipped component. FAQ.astro imports only SectionWrapper.astro + a type — it does not import FAQAccordion.tsx. The wire is a string-keyed registry in packages/renderer/src/page-builder.ts (FAQAccordion: "FAQAccordion.tsx", ~7 .tsx islands among 28 entries). A static graph cannot see a string — so the “.astro-frontmatter-parser” fix two assessments proposed recovers zero of these edges. The fix is a fence, not a parser. The fence must be inbound-axis-aware: today the 0 carries an UNKNOWN_OUTBOUND frontier (the file’s own imports — wrong axis), which an agent reads as “safe.”
04

The family the same map unlocks

Not four products — four questions to one map. The roadmap, not this build. Each inherits the same fence.

R1
“What did this change actually rewire?”
The structural diff (edges added/removed), not the line diff. Catches an agent quietly routing the renderer into the git layer.
R2
“Does the real wiring still match the intended?”
Conformance / drift. State a boundary once; the map flags the commit that violates it. Structural QC on a fast-moving codebase.
R3
“What’s built but wired to nothing?”
Dead code + fake gates — the false-green detector, once it learns to fence.
R4
“Where do I start?”
The map is the onboarding artifact — load-bearing pieces + data flow, not blind grepping.
05

The four gates — where each stands on Neuron (measured)

“Functional” means all four hold on the repo that matters.

G1Never lies
Passes. Currency fail-closed, mutation-tested. One-line gap: the graph face returns no pin — add it.
G2Complete-or-fenced
Fails as a silent lie — the gate that makes it rip-out-grade. Build the inbound-aware fence. The fix is a fence, not an edge-parser.
G3Fast
Fails. Cold build 258–384s on Neuron. Route through cat-file-batch (target <60s); lazy background server until then.
G4One sharp job
Ship only backward-reach, currency + fence mandatory. Orphan / false-green stays an internal CLI. Scope is the silence.
↘ go deeper — gate contracts the builder reads

G1. handleGraph (src/mcp/server.mjs ~199–210) returns completeness_label but no pin/currency_label — add both so no face is usable without a freshness anchor. DOD: a test asserts every MCP face returns a recomputable pin; drop the pin → RED.

G2. Enumerate the inbound-blind edge classes the static graph cannot represent: (a) string registry (object-literal Name: "*.tsx" shape, e.g. page-builder.ts) → REGISTRY_WIRED; (b) .astro-host; (c) dynamic-import. The backward-reach result emits an inbound-completeness label distinct from UNKNOWN_OUTBOUND. Contract: a 0-reach for a file in any blind class returns “consumers unknown — <class>, fall back,” never “0.” Files: src/adapters/code-repo/graph-filter.mjs, src/witness/edge-completeness.mjs, the handleReachGraph path. DOD: FAQAccordion.tsx returns the inbound fence; remove the registry detector → silent 0 returns → test RED.

G3. Route snapshot build through src/git/cat-file-batch.mjs + reuse the parse cache (replace per-file git show). Target <60s cold. Interim: lazy background-built server, never a synchronous cold call on Neuron.

G4. Headline MCP surface = plato_reach_graph backward, currency proof + inbound-completeness label mandatory. plato gates → opt-in internal CLI until its ci-timed-step.sh / $@ passthrough fence lands.

Rollback: additive behind the existing surface; the fence has a flagged off-switch; the perf path falls back to buildVerifiedSnapshot on any cat-file-batch error (the existing runStdioServer try/catch already does this).

06

Honest hard problems

The unbounded residual
The fence covers a bounded class (registry + .astro + dynamic). A consumer that fails to resolve for a reason not on the list still returns a silent 0. Mitigation: an inbound-completeness label + conservative default — never a bare 0.
Perf may not reach <60s
cat-file-batch alone may not be enough on 2,778 nodes. Fallback: lazy background-built server so an agent never waits on a cold synchronous call.
The family isn’t free
Each later query needs its own fence-check — a conformance rule is only as honest as the graph’s completeness. Cheap (shared substrate), not free.
“Passes on itself” ≠ done
The substrate looked done because we proved it on Plato-on-Plato (tiny, clean, fresh). Gate every claim on Neuron from here on.
07

How we’ll know it works

One end-to-end task on Neuron, after the fence + perf land — all three must hold: (1) a real shared module (proof-lineage.ts) returns its true blast radius plus a currency proof whose hash I recompute from git and that matches; (2) a registry-wired island (FAQAccordion.tsx) returns the fence — “consumers unknown, fall back” — not “0 consumers”; (3) a commit to a throwaway clone’s HEAD (never the real tree) makes the prior proof go STALE (red) and the new query re-pins. Real answer where it can see; loud where it can’t; never stale-as-current.

08

Your calls — the red-pen targets

C1
Lead with blast-radius; demote the false-green detector to an internal CLI.
Reorders your current branch (you’re on the vacuity / false-green line). Evidence: 881 orphans at ~86% phantom on Neuron — right category, wrong lead. Recommend: yes.
C2
Ship the fence first; edge-recovery later.
A fenced “I can’t see this” is the never-lie floor; recovering the real registry / .astro edges is a value-add upgrade on top. Recommend: yes.
C3
Sequence perf (cat-file-batch) before or parallel to the fence.
Nothing is “reachable” until cold build drops toward <60s. Recommend: parallel.
C4
Frame the spec as “build the trustworthy map,” blast-radius as query #1, family as roadmap.
That’s this document. Recommend: yes.