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.
From the one-job investigation (grounded on Neuron + the code-intelligence field; adversary verdict revise-the-plan). Everything below is built to these.
Not the clean three-tier stack we first drew — the measurements forced a sharper cut.
One MCP call — plato_reach_graph backward on the file about to change.
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.”Not four products — four questions to one map. The roadmap, not this build. Each inherits the same fence.
“Functional” means all four hold on the repo that matters.
cat-file-batch (target <60s); lazy background server until then.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).
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.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.