Orchestrata Ultimate / Specs / 111-live-code-substrate
111-live-code-substrate: Live Multi-Agent Code Substrate
SPEC-111 turns SPEC-110's in-memory code-intelligence platform from a per-operation tool into a live, resident substrate that multiple agents edit concurrently and safely. It adds five things SPEC-110 does not have:
At a glance
| Item | Value |
|---|---|
| Spec directory | specs/111-live-code-substrate/ |
| Status line in the spec | Draft |
| Requirement IDs defined | 45 |
With a @traces citation in src/ |
0 (0.0%) |
With a @traces citation in tests/ |
1 (2.2%) |
| Tracked files | 3 |
| RTM page | 111-live-code-substrate |
Reading this spec
This spec turns the in-memory code-intelligence platform of spec 110 from a per-operation tool into a live, resident substrate that several agents can edit concurrently and safely. Today an agent edit is a batch round trip: dispatch, work blind against files, return, re-parse, run gates, discover problems, redispatch. That loop causes the multi-hour turnaround and half-applied refactors such as the SPEC-109 gw to slot incident. The substrate collapses the loop so correctness feedback arrives as the edit happens.
It adds five things. A resident forest daemon keeps the lossless CST forest loaded for the whole session, so the cold parse cost of about 9 seconds is paid once. A multi-agent delta and merge model gives each agent an isolated, structurally shared copy of its subtree; agents only propose deltas against a base version, and deltas merge into the canonical forest through a governed, conflict-checked merge queue (described as git for ASTs). Streaming quality gates run review, lint, type-check and blast-radius per delta. A basedpyright oracle runs over in-memory buffers, never disk, as a read-only source of diagnostics and navigation. Agent-steering observability makes every node change observable, so a supervisor can detect and halt a stuck or diverging agent. The design rests on the immutability of libcst.Module: transforms return new trees, unchanged nodes are shared, and immutable data is race-free under free-threading, on Python 3.14t.
The architecture section covers the daemon, working copies, the delta model, the merge queue, the change stream, streaming gates, the oracle, checkpoint and crash recovery, steering hooks and a deterministic Prolog write-gate with an escalation loop. The 45 requirement IDs follow the functional requirement groups: REQ-111-FR1 to FR9 and NFR1. Examples: exactly one resident forest per session; checkouts are structurally shared, so concurrent checkouts of disjoint subtrees add memory proportional only to their deltas; a stale but conflict-free delta is rebased and re-validated while a conflicting one is rejected with a machine-readable reason; every applied change publishes agent id, delta id, node path and before and after hashes; a type-sensitive delta is refused if the oracle fails on the speculative post-merge forest; divergence signals are exposed as metrics; an agent gets a bounded number of retries; and a warm subtree checkout takes under 50 ms.
The spec's status line reads Draft, and no code module cites it. The requirements traceability matrix lists every ID. It tracks 3 files. No src/ symbol cites any of the 45 requirements, so measured trace coverage is 0.0%, and in tests/, 1 requirement is cited by a test-side @traces. All 45 requirements have no citing symbol, the largest groups being REQ-111-FR3 (8), REQ-111-FR9 (8) and REQ-111-FR6 (5); the behaviour may still exist in code that was never annotated.
Requirements
Checkbox is the state recorded in the requirements checklist; Traced by is the count of src/ symbols whose @traces names the ID.
| ID | Done | Requirement | Traced by |
|---|---|---|---|
REQ-111-FR1-001 |
no | The daemon holds exactly one resident CodemodWorkspace.forest for the session lifetime and serves subtree checkouts without re-parsing unchanged modules |
none |
REQ-111-FR1-002 |
no | The resident forest stays consistent with external on-disk edits via debounced watch + hash-gated incremental reparse (only changed modules) | none |
REQ-111-FR1-003 |
no | A checkout never triggers a full-forest reparse; cold parse occurs at most once per daemon lifetime | none |
REQ-111-FR1-004 |
no | The resident AST daemon publishes the AST snapshot from its warm cache as the single writer (atomic, byte-compatible with the CLI), on publish and after debounced changes; post-edit hooks spawn no serializer while a daemon is live (ADR-0097) |
none |
REQ-111-FR2-001 |
no | An agent checkout returns an immutable subtree handle plus its base version id | none |
REQ-111-FR2-002 |
no | Checkouts are structurally shared (no deep copy); N concurrent checkouts of disjoint subtrees add memory proportional only to their deltas | none |
REQ-111-FR2-003 |
no | An agent cannot mutate canonical forest state; the only write path is a delta submission | none |
REQ-111-FR3-001 |
no | A delta is a ChangeSet carrying its base version id and node-level edits |
none |
REQ-111-FR3-002 |
no | The merge queue is the single writer to the canonical forest and serializes application | none |
REQ-111-FR3-003 |
no | On submit, the merge queue detects structural conflicts (overlapping node ranges) AND semantic conflicts (cross-delta dependencies via the CIG) | none |
REQ-111-FR3-004 |
no | A stale-but-conflict-free delta is rebased onto the current base and re-validated; a conflicting delta is rejected with a machine-readable reason | none |
REQ-111-FR3-005 |
no | Merge application is atomic (txn.commit_changes) with ConcurrentEditError on a lost update |
none |
REQ-111-FR3-006 |
no | Every delta primitive captures its own inverse at construction; delta.invert() is total and byte-exact; non-invertible primitives are inadmissible (rope §2) |
none |
REQ-111-FR3-007 |
no | delta.describe() renders a structural + textual diff as a pure function with zero forest mutation (rope §2/§6) |
none |
REQ-111-FR3-008 |
no | Each delta records base version tokens of nodes it read/edits; the governor rejects-and-recomputes any delta whose base moved before merge (rope §6, optimistic concurrency) | none |
REQ-111-FR4-001 |
no | Every applied CodeChange publishes through the async observer mesh with (agent id, delta id, node path, before/after hash) |
none |
REQ-111-FR4-002 |
no | Observers can subscribe to a single agent, a subtree, or the whole forest | none |
REQ-111-FR5-001 |
no | On each delta, the substrate runs review, lint, type, and blast-radius gates scoped to the delta and streams findings as they complete | none |
REQ-111-FR5-002 |
no | A delta failing a hard gate (type error, banned construct) is not merged | none |
REQ-111-FR5-003 |
no | Gate results cite the specific node(s) and requirement/standard violated | none |
REQ-111-FR5-004 |
no | Before admitting a type-sensitive delta, the oracle runs on the speculative post-merge forest (side-effect-free dry run) and the delta is refused if it fails type-check (rope §6) | none |
REQ-111-FR6-001 |
no | The oracle is driven over LSP didChange with in-memory buffer text = the delta's emitted .code; it does not read the buffer from disk |
none |
REQ-111-FR6-002 |
no | The oracle exposes diagnostics, hover, definition, references and performs no writes | none |
REQ-111-FR6-003 |
no | Oracle diagnostics are a strict superset of the current pyright gate (no type-coverage regression) | none |
REQ-111-FR6-004 |
no | Reference resolution is two-stage (textual/symbol sieve → oracle semantic confirm) returning tri-state {definite, not-a-match, unsure}; unsure is surfaced to the governor, never force-applied (rope §3) |
none |
REQ-111-FR6-005 |
no | Oracle type results cached per CST node id with provenance (inferred-exact|inferred-fallback|unknown); a delta depending on an unknown-typed symbol is not auto-mergeable (rope §4) |
none |
REQ-111-FR7-001 |
no | The substrate checkpoints the canonical forest on a bounded interval and on every merge | none |
REQ-111-FR7-002 |
no | A checkpoint is byte-exact: restoring it and emitting module.code reproduces the pre-crash source exactly |
none |
REQ-111-FR7-003 |
no | Disk source files remain the canonical, hash-verifiable ground truth; the forest is reconstructable from disk at any time | none |
REQ-111-FR8-001 |
no | A supervisor can subscribe to the combined change + findings stream for any agent | none |
REQ-111-FR8-002 |
no | The substrate exposes divergence signals (node-edit churn, non-decreasing findings, growing blast-radius, reddening tests) as observable metrics | none |
REQ-111-FR8-003 |
no | The supervisor can halt or message an agent mid-edit through the volk event mesh | none |
REQ-111-FR9-001 |
no | Every node mutation (write/create/delete) in a delta is evaluated by an exhaustive, deterministic Prolog inference gate before the delta is admissible; identical facts always yield the identical verdict | none |
REQ-111-FR9-002 |
no | The gate rulebase (arch boundaries, banned constructs, absolute-import, os.environ.get, trace-coverage, constitutional constraints) is declared as Prolog rules the agent can query/introspect before editing |
none |
REQ-111-FR9-003 |
no | On rejection the gate returns machine-readable feedback via explain.pl (failing rule(s), offending node(s), why-not proof) sufficient to correct the mutation |
none |
REQ-111-FR9-004 |
no | The agent receives feedback and gets a bounded, configurable N retries to resubmit a corrected delta; each retry re-runs the gate | none |
REQ-111-FR9-005 |
no | The agent is instructed and able to run a code + test validation workflow (affected code + blast-radius-selected tests) against its working-copy between retries | none |
REQ-111-FR9-006 |
no | On exhausted retries / unrecoverable verdict, the substrate escalates via the governance escalation path with the full attempt + feedback history | none |
REQ-111-FR9-007 |
no | Gate evaluation is incremental — only mutated nodes and dependent CIG facts re-derived, not the whole forest | none |
REQ-111-FR9-008 |
no | Every gate verdict, retry count, and escalation is published on the change/findings stream for real-time supervisor visibility | none |
REQ-111-NFR1-001 |
no | Warm subtree checkout completes in < 50 ms | none |
REQ-111-NFR1-002 |
no | Per-delta streaming gate first-finding latency < 500 ms for a single-function delta | none |
REQ-111-NFR1-003 |
no | Concurrent editing is race-free by construction (immutable shared nodes); no lock guards reader traversal | none |
REQ-111-NFR1-004 |
no | Resident forest RSS stays within a documented, measured budget | none |
REQ-111-NFR1-005 |
no | Checkpoint write does not block editing (async / copy-on-write snapshot) | none |
Code that traces this spec
No src/ symbol cites a requirement of this spec.
Checklists
checklists/requirements.md
The requirement list above comes from this file; 0 of 45 checkbox items are ticked.
Other tracked files
specs/111-live-code-substrate/features/rope-lessons.md
Full spec text
Verbatim from specs/111-live-code-substrate/spec.md; headings are pushed down two levels.
SPEC-111: Live Multi-Agent Code Substrate
Metadata
- Spec ID: 111-live-code-substrate
- Title: Live Multi-Agent Code Substrate (Resident Forest · Delta/Merge Concurrency · Streaming Oracle Gates · Agent Steering)
- Author: Mohamed (with Claude Opus orchestration)
- Status: Draft
- Created: 2026-08-03
- Priority: P0
- Version: 0.1.0
- Extends: SPEC-110 (In-Memory Code Intelligence Platform), SPEC-109 (Rename Engine), SPEC-065 (LSP Tool)
- Related: SPEC-033 (governed build factory — merge queue), SPEC-021 (turn capture — observability), SPEC-106 (canonical KG schema)
- Components: refactor.codemod.substrate, refactor.codemod.delta, refactor.codemod.oracle, refactor.codemod.stream, refactor.codemod.checkpoint
- Dependencies: libcst>=1.8.6, basedpyright>=1.39.9, watchfiles, janus-swi>=1.5.3, xxhash>=3.0.0
1. Overview
What
SPEC-111 turns SPEC-110's in-memory code-intelligence platform from a per-operation tool into a live, resident substrate that multiple agents edit concurrently and safely. It adds five things SPEC-110 does not have:
- A resident forest daemon — the lossless CST forest (SPEC-110) is loaded once and kept warm for the lifetime of a session, incrementally synced to disk changes, so no operation pays the cold parse cost (~9 s) more than once.
- A multi-agent delta/merge concurrency model — each agent receives an isolated, structurally-shared copy of its subtree and may only propose deltas (
ChangeSets) against a base version. Agents never mutate a shared tree. Deltas are merged into the canonical forest through a governed, conflict-checked merge queue (MVCC / "git-for-ASTs"). - Streaming quality gates — review, lint, type-check, and blast-radius run per delta as the agent edits, not at the end of a batch. Findings stream back in real time.
- A type/nav oracle — basedpyright driven over in-memory buffers (never disk) as a read-only diagnostics/navigation source, feeding the streaming gates.
- Agent-steering observability — every node change is observable; a supervisor reads the change + findings stream to detect a stuck or diverging agent and correct or halt it in real time.
Why
Today, an agent editing code is a batch round-trip: dispatch → agent works blind against files → return → re-parse → run gates → discover problems → redispatch. That loop is the source of the multi-hour agent turnaround, and of half-applied refactors (the SPEC-109 gw→slot incident: 54 test failures from a missed rewrite, >1 day recovery). The wait was never the editing — it was the blind batch.
The substrate collapses the loop: agents edit an observable in-memory tree, every change is reviewed/linted/type-checked/blast-radiused as it happens, and only conflict-free, gate-passing deltas merge. The result is real-time correctness feedback and safe parallelism, on a Python 3.14t free-threaded runtime whose GIL is genuinely off.
How
The immutability of libcst.Module is the load-bearing property: transforms return new trees, unchanged nodes are structurally shared, and immutable data is race-free under free-threading by construction. That makes "each agent gets a copy of its subtree" nearly free in RAM and safe without locks. Deltas are the unit of change; a governed merge queue (modeled on SPEC-033) is the single writer to the canonical forest; Memgraph's MVCC write-conflict-retry (already in-stack) is the precedent for optimistic-concurrency resolution.
2. Goals / Non-Goals
Goals
- One resident forest per session, warm-synced to disk, never re-parsed cold after startup.
- Safe concurrent editing by N agents with zero shared mutable state.
- Per-delta streaming gates: review (standards), lint (ruff), types (basedpyright), blast-radius (CIG).
- basedpyright as a read-only oracle over in-memory buffers.
- Byte-exact durability: crash-safe checkpoints; disk stays canonical and reconstructable.
- Real-time supervisor visibility into agent progress / divergence.
Non-Goals
- Replacing SPEC-110's forest/CIG/transform/review/txn machinery (this spec composes it, does not rewrite it).
- Adopting rope or any external refactoring engine as a dependency (SPEC-110 + SPEC-109 + the AST toolkit are a superset for our needs; see §7).
- Making memory the source of truth. Disk remains canonical; the forest is a fast, hash-verified derived mirror.
- The steering policy intelligence (what signal means "wrong path") — SPEC-111 provides the observable substrate; the policy is deferred research (§8).
3. Architecture
┌────────────────────── Resident Forest Daemon (session-long) ──────────────────────┐
disk ◀──sync──│ canonical CST forest (SPEC-110 CodemodWorkspace) + CIG + parse cache │
▲ │ ▲ merge (single writer) │ subtree checkout (immutable) │
│ checkpoint│ │ ▼ │
(JSON snapshot)│ ┌─────────────────┐ ┌──────────────────────────────────────────────────┐ │
│ │ │ Merge Queue │◀─delta─│ Agent working-copy A (subtree, structurally shared)│ │
│ │ │ (MVCC/conflict/ │◀─delta─│ Agent working-copy B ... │ │
│ │ │ rebase, SPEC-33)│ └──────────────────────────────────────────────────┘ │
│ │ └─────────────────┘ │ every CodeChange │
│ └───────────────────────────────────────────┼───────────────────────────────────────┘
│ ▼
│ ┌─────────────── Observable change stream (AsyncObserver) ─────────┐
│ │ per delta → review pass · ruff · basedpyright oracle · BlastRadius│
│ └────────────┬──────────────────────────────────┬───────────────────┘
│ ▼ ▼
│ findings stream Supervisor (steering)
└── crash recovery ◀── checkpoint codec stuck/divergence detection
3.1 Resident Forest Daemon
Extends CodemodDaemon (SPEC-110) to hold ONE CodemodWorkspace.forest resident for the session. watchfiles.awatch + hash-gated load_or_analyze (existing ast_live_sync.py) keep it consistent with external disk edits (git pull, another process). Open question (§8): confirm/upgrade the daemon to hold the forest across calls rather than reload per operation.
3.2 Agent Working-Copies (subtree checkout)
An agent requests a subtree (e.g. session.cli.tasks); the daemon returns an immutable handle. Because libcst nodes are immutable and structurally shared, the "copy" duplicates nothing but the path to the subtree root. Agents hold their base version id for optimistic concurrency.
3.3 Delta Model
An agent produces edits by applying TransformPasses to its copy, yielding a ChangeSet (SPEC-110) — a description of edits against a base version, never a direct mutation of canonical state. Deltas are the only thing an agent may submit.
3.4 Governed Merge Queue
The single writer to the canonical forest. On submit, it: (a) checks the delta's base version against canonical (staleness), (b) detects structural conflicts (overlapping node ranges) and semantic conflicts (via the CIG — e.g. delta A renames a symbol delta B calls), (c) rebases a stale-but-clean delta onto the new base or rejects it, (d) applies clean deltas atomically via txn.commit_changes (existing, with ConcurrentEditError detection). Modeled on SPEC-033's MergeQueue.
3.5 Observable Change Stream
Every applied CodeChange publishes through the existing AsyncObservable/AsyncObserver mesh. This is the spine of both the streaming gates and steering.
3.6 Streaming Gates (per delta)
- Review:
ReviewPass/PrologSemanticReview+ Key-Rulestandardson the delta only. - Lint:
ruffon the changed nodes' emitted.code(millisecond-fast). - Types: the basedpyright oracle (§3.7) on the delta's emitted buffers.
- Blast-radius:
BlastRadiusvia the CIG — which tests/modules this delta impacts, live.
3.7 basedpyright Oracle
basedpyright (already a declared dep) driven via the existing lsp_client.py over textDocument/didChange with in-memory buffer text = the delta's emitted .code. Read-only: diagnostics, hover, definition, references. Never reads disk; the forest is the buffer source. Distinct from the writer (SPEC-110/109) — the oracle never mutates.
3.8 Checkpoint / Crash Recovery
Periodic + on-merge checkpoint of the canonical forest to a durable snapshot (byte-exact, since module.code round-trips). On restart, reload from the snapshot without a cold re-parse. Disk files remain the ultimate canonical, hash-verifiable source.
3.9 Steering Hooks
The supervisor subscribes to the change + findings streams and computes divergence signals (repeated edits to the same node, findings not decreasing, blast-radius growing, tests reddening) to correct or halt an agent. SPEC-111 ships the hooks and signals; the decision policy is §8 research.
3.10 Deterministic Prolog Write-Gate + Escalation Loop
The hard, deterministic enforcement layer. Every node mutation in a delta — write/replace, create/insert, delete/remove — passes through an exhaustive Prolog inference gate (janus-swi, the project's "deterministic-first" doctrine) before the delta is admissible. This is the node-granularity extension of the existing governance stack (PrologSemanticReview from SPEC-110, governance.prolog_gate / GovernancePrologClient.may_execute, the constitutional rulebase).
The loop is know → attempt → gated → feedback → retry → escalate:
- Know (rules are introspectable). The gate's rulebase — the invariants a mutation must satisfy (architectural boundaries, banned constructs, import rules, trace-coverage, constitutional constraints) — is declared as Prolog rules the agent can query before editing. The agent knows the conditions it must cross; the gate is not a black box.
- Gated (deterministic verdict). On each mutation the gate evaluates the mutated node(s) + their CIG blast-radius facts and returns a deterministic verdict (same facts → same verdict). Evaluation is incremental — only mutated nodes and dependent facts are re-derived, not the whole forest.
- Feedback (why-not proof). On rejection the gate returns machine-readable feedback via
explain.pl(the proof-tree / why-not meta-interpreter,may_execute_explained): the failing rule(s), the offending node(s), and the proof of why — sufficient for the agent to correct the mutation, not just "denied". - Retry (bounded). The agent receives the feedback and gets a bounded N retries to resubmit a corrected delta; each retry re-runs the gate.
- Run-and-test (the agent validates, not guesses). Between retries the agent is instructed and able to run a code + test workflow — execute the affected code and the blast-radius-selected tests (FR-005 /
affected_tests) against its working-copy — so a resubmission is validated, not hopeful. - Escalate. When retries are exhausted or the verdict is unrecoverable, the substrate escalates through the governance escalation path (
escalation_handler/pipeline_escalation) to a higher-tier model / governor / human, carrying the full attempt + feedback history.
Every gate verdict, retry, and escalation is published on the change/findings stream (§3.5, §3.9) so the supervisor sees the enforcement loop in real time.
4. User Stories
- US-001 (Resident substrate): As the orchestrator, I load the codebase once and keep it warm, so every subsequent code operation is sub-second, not a 9 s re-parse.
- US-002 (Safe parallel editing): As the orchestrator, I hand N agents disjoint subtrees and they edit concurrently without corrupting each other or the canonical tree.
- US-003 (Delta proposals): As an agent, I propose a delta against my subtree and cannot mutate canonical state directly.
- US-004 (Governed merge): As the orchestrator, only conflict-free, gate-passing deltas merge; stale-but-clean deltas rebase automatically; conflicting deltas are rejected with a reason.
- US-005 (Streaming review/lint/types): As a reviewer, each delta is reviewed, linted, and type-checked as it is proposed — not at the end of a batch.
- US-006 (Live blast-radius): As the orchestrator, I see which tests a delta impacts the moment it is proposed.
- US-007 (Oracle): As the substrate, I get basedpyright diagnostics/nav over in-memory buffers with no disk writes.
- US-008 (Crash safety): As the operator, a power loss costs at most one checkpoint interval; the tree restores byte-exact.
- US-009 (Steering): As a supervisor, I detect a stuck or diverging agent in real time and correct or halt it.
5. Functional Requirements (authoritative REQ ids)
FR-001: Resident Forest Daemon
- REQ-111-FR1-001: The daemon SHALL hold exactly one
CodemodWorkspace.forestresident for the session lifetime and serve subtree checkouts without re-parsing unchanged modules. - REQ-111-FR1-002: The daemon SHALL keep the resident forest consistent with external on-disk edits via debounced watch + hash-gated incremental reparse (only changed modules).
- REQ-111-FR1-003: A checkout SHALL never trigger a full-forest reparse; cold parse SHALL occur at most once per daemon lifetime.
- REQ-111-FR1-004: The resident AST daemon (
scripts/ast_daemon.py) SHALL publish the on-disk AST snapshot (plans/ast-<name>.json) from its warm cache, byte-compatible with a CLIserialize --incrementalof the same tree, as the SINGLE writer of that artifact in a served checkout (atomic temp +os.replace, writes coalesced), on apublishsocket request and after every debounced source change, recording the last publish time and content hash in its status; post-edit hooks SHALL NOT spawn a serializer while a daemon is live (ADR-0097).
FR-002: Agent Working-Copies
- REQ-111-FR2-001: An agent checkout SHALL return an immutable subtree handle plus its base version id.
- REQ-111-FR2-002: Checkouts SHALL be structurally shared (no deep copy); N concurrent checkouts of disjoint subtrees SHALL add memory proportional only to their deltas, not to N × forest size.
- REQ-111-FR2-003: An agent SHALL NOT be able to mutate canonical forest state; the only write path is a delta submission.
FR-003: Delta / Merge
- REQ-111-FR3-001: A delta SHALL be a
ChangeSetcarrying its base version id and the set of node-level edits. - REQ-111-FR3-002: The merge queue SHALL be the single writer to the canonical forest and SHALL serialize application.
- REQ-111-FR3-003: On submit, the merge queue SHALL detect structural conflicts (overlapping node ranges) AND semantic conflicts (cross-delta dependencies via the CIG).
- REQ-111-FR3-004: A stale-but-conflict-free delta SHALL be rebased onto the current base and re-validated; a conflicting delta SHALL be rejected with a machine-readable reason.
- REQ-111-FR3-005: Merge application SHALL be atomic (
txn.commit_changes) withConcurrentEditErroron a lost update. - REQ-111-FR3-006: Every delta primitive SHALL capture its own inverse at construction (the old subtree for a
ReplaceNode/RemoveNode), sodelta.invert()is total and byte-exact. A primitive that cannot produce its inverse SHALL be rejected as inadmissible. (rope §2 lesson — noNotImplementedErrorundos.) - REQ-111-FR3-007:
delta.describe()SHALL render a structural + textual diff as a PURE function with zero forest mutation, so the queue/governor previews a delta before admitting it. (rope §2/§6.) - REQ-111-FR3-008: Each delta SHALL record the base version tokens (content hash / monotonic rev) of every node it read or edits; the merge governor SHALL reject-and-recompute any delta whose recorded base moved underneath it before merge. (rope §6 — optimistic concurrency; the multi-agent core.)
FR-004: Observable Stream
- REQ-111-FR4-001: Every applied
CodeChangeSHALL publish through the async observer mesh with (agent id, delta id, node path, before/after hash). - REQ-111-FR4-002: Observers SHALL be able to subscribe to a single agent, a subtree, or the whole forest.
FR-005: Streaming Gates
- REQ-111-FR5-001: On each delta, the substrate SHALL run review, lint, type, and blast-radius gates scoped to the delta and stream findings as they complete (not blocked on the slowest).
- REQ-111-FR5-002: A delta failing a hard gate (type error, banned construct) SHALL NOT be merged.
- REQ-111-FR5-003: Gate results SHALL cite the specific node(s) and requirement/standard violated.
- REQ-111-FR5-004: Before admitting a type-sensitive delta, the substrate SHALL run the basedpyright oracle on the SPECULATIVE post-merge forest (a side-effect-free dry run, possible because deltas are pure) and refuse the delta if the speculative merge fails type-check. (rope §6 — preview-before-apply.)
FR-006: basedpyright Oracle
- REQ-111-FR6-001: The oracle SHALL be driven over LSP
didChangewith in-memory buffer text = the delta's emitted.code; it SHALL NOT read the buffer from disk. - REQ-111-FR6-002: The oracle SHALL expose diagnostics, hover, definition, and references and SHALL NOT perform writes.
- REQ-111-FR6-003: Oracle diagnostics SHALL be a strict superset of the current pyright gate (no regression in type coverage).
- REQ-111-FR6-004: Reference/occurrence resolution SHALL be two-stage (cheap textual/symbol-index sieve → oracle-confirmed semantic match) and SHALL return a tri-state result
{definite, not-a-match, unsure};unsureoccurrences SHALL be surfaced to the governor, never force-applied. (rope §3.) - REQ-111-FR6-005: Oracle type results SHALL be cached per CST node id with a confidence/provenance tag (
inferred-exact|inferred-fallback|unknown); a delta whose safety depends on anunknown-typed symbol SHALL NOT be auto-mergeable. (rope §4 — confidence lattice.)
FR-007: Checkpoint / Recovery
- REQ-111-FR7-001: The substrate SHALL checkpoint the canonical forest on a bounded interval and on every merge.
- REQ-111-FR7-002: A checkpoint SHALL be byte-exact: restoring it and emitting
module.codeSHALL reproduce the pre-crash source exactly. - REQ-111-FR7-003: Disk source files SHALL remain the canonical, hash-verifiable ground truth; the forest SHALL be reconstructable from disk at any time.
FR-008: Steering Hooks
- REQ-111-FR8-001: A supervisor SHALL be able to subscribe to the combined change + findings stream for any agent.
- REQ-111-FR8-002: The substrate SHALL expose divergence signals (node-edit churn, non-decreasing findings, growing blast-radius, reddening tests) as observable metrics.
- REQ-111-FR8-003: The supervisor SHALL be able to halt or message an agent mid-edit through the existing volk event mesh.
FR-009: Deterministic Prolog Write-Gate + Escalation Loop
- REQ-111-FR9-001: Every node mutation (write/replace, create/insert, delete/remove) in a delta SHALL be evaluated by an exhaustive, deterministic Prolog inference gate before the delta is admissible for merge; identical facts SHALL always yield the identical verdict.
- REQ-111-FR9-002: The gate rulebase (architectural boundaries, banned constructs, absolute-import rule,
os.environ.getrule, trace-coverage, constitutional constraints, etc.) SHALL be declared as Prolog rules the agent can QUERY/introspect before editing, so the admissibility conditions are known, not opaque. - REQ-111-FR9-003: On rejection the gate SHALL return machine-readable feedback via the
explain.plwhy-not meta-interpreter: the failing rule(s), the offending node(s), and the proof of why — sufficient for an agent to correct the mutation. - REQ-111-FR9-004: The agent SHALL receive the gate feedback and be granted a bounded, configurable N retries to resubmit a corrected delta; each retry re-runs the gate against the corrected mutation.
- REQ-111-FR9-005: The agent SHALL be instructed and able to run a code + test validation workflow (execute the affected code and the blast-radius-selected tests from FR-005) against its working-copy between retries, so a resubmission is validated rather than guessed.
- REQ-111-FR9-006: When retries are exhausted or the verdict is unrecoverable, the substrate SHALL escalate through the governance escalation path (
escalation_handler/pipeline_escalation) carrying the full attempt + feedback history to a higher-tier model / governor / human. - REQ-111-FR9-007: Gate evaluation SHALL be incremental — only mutated nodes and their dependent CIG facts re-derived per mutation, not the whole forest.
- REQ-111-FR9-008: Every gate verdict, retry count, and escalation SHALL be published on the change/findings stream (FR-004/FR-008) so the supervisor observes the enforcement loop in real time.
6. Non-Functional Requirements
- REQ-111-NFR1-001: Warm subtree checkout SHALL complete in < 50 ms.
- REQ-111-NFR1-002: Per-delta streaming gate first-finding latency SHALL be < 500 ms for a single-function delta.
- REQ-111-NFR1-003: Concurrent editing SHALL be race-free by construction (immutable shared nodes); no lock SHALL guard reader traversal.
- REQ-111-NFR1-004: Resident forest RSS for this repo SHALL stay within a documented budget (measured baseline: full live
ast≈ 1 GB; libcst forest budget to be measured and pinned). - REQ-111-NFR1-005: Checkpoint write SHALL not block editing (async/copy-on-write snapshot).
7. Relationship to existing specs (no duplication)
- SPEC-110 owns the forest, CIG, transform/review passes,
txnwrite-back, observability primitives, daemon skeleton. SPEC-111 composes these into a resident, multi-agent, streaming service. - SPEC-109 owns cross-file rename/move +
lsp_client. SPEC-111 reuseslsp_clientto drive the oracle. - SPEC-065 owns the LSP tool surface. SPEC-111's oracle is its live, in-memory-buffer application.
- SPEC-033 owns the governed merge queue + DAG scheduler; SPEC-111's delta merge is modeled on it.
- rope is studied for design lessons (delta/change objects, undo history, occurrence finding, restructure, staleness detection) but NOT adopted — SPEC-110/109 + the AST toolkit already cover its operation set (rename, move, extract-method, extract-class, inline, organize-imports) plus generators rope lacks; the only gaps (extract-variable, change-signature, introduce-parameter) are cheap local
TransformPasses. Seefeatures/rope-lessons.md.
8. Open Questions / Deferred Research
- Daemon residency: ✅ RESOLVED (2026-08-03) — the forest is ALREADY resident.
CodemodDaemon"parses the workspace once at startup" and keeps it;CodemodServer.serve(socket_path, workspace)holdsself._workspaceand serves all Unix-socket requests against that held instance (no per-call reload);FileWatcher(inotify) exists to trigger incremental re-parse via callback. FR-001 is therefore a wiring/confirmation task, not a build — the remaining work is confirming the watcher→incremental-reparse callback is wired end-to-end into the running daemon, then adding the subtree-checkout + multi-agent delta API (FR-002/FR-003) on top. Sizing: ~day, not week. - Steering policy: what change/findings signal reliably distinguishes "wrong path" from "exploring"? SPEC-111 ships the observable signals; the policy is separate research.
- Semantic-conflict completeness: how far does CIG-based semantic-conflict detection go before it needs the type oracle in the loop?
- Checkpoint codec: forest→JSON snapshot for sub-second warm restart vs. relying on disk files + parse cache. Measure the restart delta before building the codec.
9. Traceability
All code implementing this spec SHALL carry @traces(spec="111", story="US-00N", reqs=["REQ-111-..."]). The requirements checklist (checklists/requirements.md) is the authoritative REQ-id source; every REQ SHALL trace to at least one test before it is marked complete.