Brings over the uncommitted agent-mei work (Mac checkout, Sep 22) plus box follow-ups (Oct 17: agent_mei action namespace in keymap/zed.rs, MEI_BRIDGE.md, RENAME_AGENT_MEI.md, unmetered receipts report 0 uJ). joule_core, JOULE_CODE_* and JouleDB names unchanged. *.bak.* scratch files excluded.
98 lines
8.8 KiB
Markdown
98 lines
8.8 KiB
Markdown
# Architecture & Integration
|
||
|
||
> Generated 2026-06-14. How `agent_mei_panel` wires together internally, to the Joule host, and to its 16 external deps. file:line against audited HEAD.
|
||
|
||
## Component map
|
||
|
||
```
|
||
crates/zed/src/main.rs:770 agent_mei_panel::init(cx)
|
||
crates/zed/src/zed.rs:704 AgentMeiPanel::load(...) (initialize_panels)
|
||
│
|
||
init(cx) [agent_mei_panel.rs:84] AgentMeiPanel (struct :177) owns:
|
||
├─ control::init_control_server(cx) l0_cache: L0Cache (joule-code-cascade)
|
||
├─ observe_new<Workspace> → ToggleFocus l3_model: Option<Arc<L3Model>> (jouleclaw-runtime/loader)
|
||
└─ observe_new<Editor> → LocalFimDelegate cascade_gate: CascadeGate (cascade_gate.rs / joule-code-jcp)
|
||
hooks: HookRegistry (hooks.rs)
|
||
methodology: MethodologyTracker (methodology.rs)
|
||
session_mgr: SessionManager (sessions.rs)
|
||
energy_counter: EnergyCounter (jouleclaw-energy)
|
||
```
|
||
|
||
## 1. Cascade data flow
|
||
|
||
Entry **`submit_prompt`** (`agent_mei_panel.rs:1600`). Each tier guarded by `authorize_tier(tier, intent)`; first to close wins.
|
||
|
||
```
|
||
submit_prompt :1600
|
||
├─ resolve_at_mentions → pending_context :1608
|
||
├─ ensure_ledger_loaded / ensure_l2_loaded :1618 (rehydrate L0/L2 across sessions)
|
||
├─ L0 authorize_tier(L0) → l0_cache.try_resolve :1628 hit → note_close(L0,0) → RETURN :1646
|
||
├─ L1 attempt_l1_deterministic :1834 parse_substitution; buffer.set_text → record_tier_edit(L1)
|
||
└─ attempt_l2_then_l3 :1673
|
||
├─ L2 embed (GGUF as encoder) → cosine ≥ threshold → replay prior edit → record_tier_edit(L2)
|
||
├─ L3 attempt_l3_then_l4 :1883
|
||
│ energy_before; document_symbols (LSP) on fg :1927
|
||
│ background: load_l3_model → codebase_index.search → format_symbol_context →
|
||
│ harness_prompt → l3_generate :1958
|
||
│ FILE blocks → apply_multi_file_edit; else parse_edit;
|
||
│ empty → send_to_l4; else review? stage_pending_edit : buffer.set_text + record_l3_edit
|
||
└─ L4 send_to_l4 :2462
|
||
authorize_tier(L4) DENY → "L4 denied by grant" RETURN ← no-phone-home seam
|
||
thread.send(ContentBlock) over ACP :2491
|
||
(close captured later via thread subscription — see §risks)
|
||
```
|
||
|
||
**Edit review** (`stage_pending_edit:2178` → `accept_pending_edit:2231` → `apply_staged_now:2204`): staging records a `PendingEdit`; buffers untouched until Accept (`set_text` + `record_l3_edit`). Reject just drops it. Control protocol exposes the same (`accept`/`reject`).
|
||
|
||
**Energy** (`bracket_energy:2443`): `after − before` from `energy_uj_now`; `Estimator` → `measured_uj = None` (honest). Counter from `host_energy_counter:3850` — Apple IOReport (aarch64), NVML/RAPL (linux), else `None`.
|
||
|
||
**Sealing** (`record_tier_edit:2542`, the shared close path): bracket energy → `build_coding_op` → `append_to_ledger:686` (hash-chained COSE_Sign1) → `note_methodology_op` → `l0_cache.insert` → `record_review` → `note_close` → `index_for_l2` → `attest_applied_edit:3039` (sandbox). Also folds the op into the active session via `record_active_op:728`.
|
||
|
||
**L4 close is asymmetric:** sealed not in `send_to_l4` but in the **thread subscription** (`:1123-1136`) — on `AcpThreadEvent`, `captured_op:3137` walks the thread's diffs into a `CodingOp`, then `append_to_ledger` + `l0_cache.insert`. (See risk #1.)
|
||
|
||
## 2. Joule integration seams
|
||
|
||
- **Init:** `main.rs:770` `agent_mei_panel::init(cx)` (the `zed.rs:5337` init is in `mod test` only — no production double-init).
|
||
- **Panel load:** `zed.rs:704` `AgentMeiPanel::load` in `initialize_panels`, added via `add_panel_when_ready` alongside the other dock panels.
|
||
- **Joule APIs touched:** `workspace::Workspace` (panel host, actions, `impl Panel`); `project::Project` (`agent_server_store`, `document_symbols` LSP, `open_buffer`, worktrees); `agent_servers`/`acp_thread`/`agent-client-protocol` (ACP connection + L4 send + diff subscription); `editor::Editor` (prompt + FIM provider); `language::Buffer`/`multi_buffer` (edit application); `lsp` (symbol context); macOS `sandbox` (Seatbelt for the agent's `run` tool).
|
||
|
||
## 3. External dependency boundary (16 git deps, pinned `4132daa`)
|
||
|
||
| Dep | Used by | Purpose | Status |
|
||
|---|---|---|---|
|
||
| `joule-code-cargo` | panel, methodology | `CodingOp`, `Edit`, `Anchor`, `SignedOp` | Core |
|
||
| `joule-code-cascade` | panel, cascade_gate | `L0Cache`, `Request`, `Stage` | Core |
|
||
| `joule-code-receipt` | panel | `Energy`, `Provenance`, `Receipt` | Core |
|
||
| `joule-code-schema` | panel, gate, methodology, sessions | `Tier`, `ContentId`, `ALG_ED25519` | Core |
|
||
| `joule-code-jcp` | cascade_gate | `JcpGate` — tier auth + sealed receipts | Core (gate) |
|
||
| `jcp-bridge` | tool_gate | `LocalToolGate` — per-tool-call auth | Core (gate) |
|
||
| `joule-code-identity` | sessions, panel | `Identity`, `ActorKind` — did:key principals | Used |
|
||
| `joule-code-spec` | methodology | `cite`, `coverage`, `Clause`, `SignedSpec` | Used |
|
||
| `joule-code-review` | methodology, panel | two-stage review ledger | Used |
|
||
| `joule-code-release` | methodology | `certify`, `ReleaseCertificate` — ship door | Used (via `ship_summary`) |
|
||
| `joule-code-joulecontract` | methodology | `frame_check` — out-of-frame edit gate | Used |
|
||
| `joulecontract-schema` | methodology | `Contract`, `Rigor` | **Thin** (inert frame contract only) |
|
||
| `jouleclaw-energy` | panel | `EnergyCounter` + IOReport/NVML/RAPL | Core |
|
||
| `jouleclaw-runtime` | panel | `generate`, `embed`, `cosine_similarity` | Core (L3) |
|
||
| `jouleclaw-loader-gguf` | panel | GGUF reader/tokenizer + safetensors Mellum | Core (L3) |
|
||
| `joule-code-conformance` (dev) | tests | `verify_pack` over C1–C4 vectors | Test-only |
|
||
|
||
**Flags:** `joule-code-release`'s discharge gate is hardcoded `false` (`ship_summary:2985`) — ship door un-passable; `jcp-bridge`/`ToolGate` only active under `JOULE_CODE_AGENT_TOOLS`; Mellum surface only via `JOULE_CODE_L3_ENGINE=mellum`.
|
||
|
||
## 4. Subsystem wiring
|
||
|
||
- **`authorize_tier`** `:2611` is the single junction composing **hooks** (PreTool, deny-wins, `:2623`) + **cascade_gate** (JCP grant + lifetime ceiling, `:2629`). Every tier passes through it.
|
||
- **`record_tier_edit`** `:2542` is the close junction fanning into methodology, sessions, L0 cache, L2 index, reviews, sandbox attestation.
|
||
- **`control_dispatch`** `:2261` is the headless seam — the control server (`control.rs:185`) and MCP bridge (`run_mcp_bridge`) drive the same panel methods a human action would.
|
||
- **methodology** ← `note_methodology_op:943` signs+cites+frame-checks each op, exports to `.joule/*.json`. **sessions** ← `ensure_session_mgr` builds the manager with `cascade_gate.grant()`; worktrees back background sessions (`active_session_worktree` → agent cwd). **tool_gate** ← passed as the `authorize_tool` closure into `local_agent::run_agent_loop`.
|
||
|
||
## 5. Integration risks / danglers
|
||
|
||
1. **L4 close depends on the thread subscription firing** (`:1123-1136`). If the subscription is dropped on reconnect (`:1141`) or no diff event fires, the L4 turn produces no ledger op and no L0 entry — a silently lost close (unlike synchronous L0–L3). *(See FINDINGS P1.)*
|
||
2. **Release/ship door structurally un-passable** — `contract_discharged = false` hardcoded (`:2985`); the full release certificate can't be reached (only merge-via-`verified` can).
|
||
3. **Session grant ↔ live gate is descriptor-only** — `SessionGrant` is sealed into the open receipt but not bound to the live `CascadeGate` (`sessions.rs:25-27`); sessions with different declared grants are gated identically.
|
||
4. **Heavy env-var gating — accountability is opt-in.** Out of the box (no `JOULE_CODE_GRANT`/`_LIFETIME_UJ`/`_AGENT_TOOLS`/`JOULECLAW_L3_MODEL`/`_REVIEW_EDITS`/`_CONTROL_SOCK`) the cascade runs **ungated and L4-reachable** — no-phone-home is a configuration, not a default.
|
||
5. **`session_mgr` silently absent outside a git repo** — `ensure_session_mgr` returns early; `record_active_op` no-ops; closed ops hit the ledger but never fold into a session chain, with no surfaced warning.
|
||
6. **`joulecontract-schema` near-vestigial** — only builds an inert frame contract.
|
||
7. **RAPL counter fragile by design** — selected only if a read succeeds; normal Linux user → `None` → 0-J receipts that look honest but carry no measurement and no "unavailable" signal.
|
||
8. **FIM provider attaches per-editor at `observe_new` time** (set-once); editors opened before a model is configured stay no-op for the session.
|