diff --git a/.claude/CODEMAP_v0.8.25_dead_code.md b/.claude/CODEMAP_v0.8.25_dead_code.md deleted file mode 100644 index 62cda215..00000000 --- a/.claude/CODEMAP_v0.8.25_dead_code.md +++ /dev/null @@ -1,622 +0,0 @@ -# CODEMAP v0.8.25 Dead Code Analysis - -## Scope - -Target files: - -1. `crates/tui/src/cycle_manager.rs` -2. `crates/tui/src/seam_manager.rs` -3. `crates/tui/src/core/coherence.rs` -4. `crates/tui/src/core/capacity.rs` -5. `crates/tui/src/core/capacity_memory.rs` -6. `crates/tui/src/core/engine/capacity_flow.rs` -7. `crates/tui/src/commands/cycle.rs` -8. `crates/tui/src/tools/recall_archive.rs` - -## Pre-flight baseline - -- **Branch**: `work/v0.8.25...origin/work/v0.8.25`. -- **Working tree before codemap write**: pre-existing untracked files under `.claude/`, `pass/`, `scripts/maintenance/`, and `smoke.txt`; no tracked code edits observed before this report. -- **Baseline test command**: `cargo test --workspace --all-features`. -- **Baseline result**: failed with one observed test failure: `mcp::tests::mcp_connection_supports_streamable_http_event_stream_responses` panicked on `Connection reset by peer` against localhost. Observed summary: `2518 passed; 1 failed; 2 ignored`. -- **Interpretation**: baseline is not green. The failing test is in MCP streamable HTTP, outside the target cycle/seam/coherence/capacity files. Treat subsequent claims as source-trace findings, not as a green-CI proof. - -## Executive summary - -| File | Verdict | Phase-1 classification | Short answer | -|---|---|---|---| -| `cycle_manager.rs` | LIVE | LIVE, STATE-MUTATING, DESIGN-LOAD-BEARING; PRACTICAL LOAD-BEARING UNPROVEN | Hard-cycle restart is wired into the engine, UI, session state, and archive/recall path. It is not ordinary-turn behavior because the default trigger is near the 1M-token wall. | -| `seam_manager.rs` | PARTIALLY LIVE | GHOST / LIVE BUT REPLACEABLE | The engine constructs and calls it, but `[context].enabled` defaults false. When opted in, it appends `` blocks and can supply Flash cycle briefings. | -| `core/coherence.rs` | LIVE | LIVE BUT REPLACEABLE | Pure reducer feeding footer/runtime state from compaction and capacity events. Small, visible, and actively referenced. | -| `core/capacity.rs` | PARTIALLY LIVE | GHOST / LIVE BUT REPLACEABLE | Controller is constructed and checkpoint methods are called every turn, but default config disables observations and interventions. Opt-in path is real and destructive. | -| `core/capacity_memory.rs` | PARTIALLY LIVE | GHOST support module | Only writes after capacity interventions, which are opt-in. However startup/resume rehydrate reads the latest record unconditionally. | -| `core/engine/capacity_flow.rs` | PARTIALLY LIVE | GHOST / LIVE BUT REPLACEABLE | The turn loop calls all checkpoints, event helpers, and rehydration. With default capacity disabled, most intervention paths no-op except compaction/coherence event helpers. | -| `commands/cycle.rs` | LIVE | LIVE BUT REPLACEABLE | `/cycles`, `/cycle `, and `/recall ` are registered built-in slash commands and produce user-visible output. | -| `tools/recall_archive.rs` | PARTIALLY LIVE | LIVE BUT STRANDED FROM PARENT TOOL SURFACE | `/recall` uses it directly and sub-agent full surface registers it. The parent Agent/Plan registry does not appear to expose `recall_archive` as a model-callable tool. | - -## Cross-cutting call graph - -### Ordinary TUI turn - -1. `tui/ui.rs::build_engine_config` forwards `app.cycle_config()` and `CapacityControllerConfig::from_app_config(config)` into `EngineConfig`. -2. `Engine::new` constructs: - - `CapacityController::new(config.capacity.clone())`. - - `seam_manager: Option` when a `DeepSeekClient` exists; its `enabled` flag comes from `[context].enabled.unwrap_or(false)`. -3. `Engine::handle_send_message` increments `turn_counter`, calls `capacity_controller.mark_turn_start`, then calls `handle_deepseek_turn`. -4. `handle_deepseek_turn` calls: - - auto/manual compaction checks; - - `run_capacity_pre_request_checkpoint`; - - hard context-overflow recovery; - - `layered_context_checkpoint`; - - streaming/model/tool execution; - - `run_capacity_post_tool_checkpoint`; - - `run_capacity_error_escalation_checkpoint`. -5. After a completed turn, `handle_send_message` calls `maybe_advance_cycle`. - -### UI event flow - -- `EngineEvent::CycleAdvanced` updates `app.cycle_count`, pushes `CycleBriefing`, inserts a system separator into history, and sets a status message. -- `EngineEvent::CoherenceState` updates `app.coherence_state`; `footer_coherence_spans` renders only active intervention states, suppressing `Healthy` and `GettingCrowded`. -- `EngineEvent::CapacityDecision` is telemetry-only in the TUI. -- `EngineEvent::CapacityIntervention` and `CapacityMemoryPersistFailed` become status messages. -- Compaction events set `app.is_compacting`, status messages, and also drive coherence transitions through `capacity_flow` helpers. - -### Runtime API event flow - -`runtime_threads.rs` consumes the same engine events and persists/streams them as runtime records: - -- `CycleAdvanced` becomes a runtime `context_cycle` item. -- `CoherenceState` updates `ThreadRecord.coherence_state` and emits `coherence.state`. -- `CapacityDecision`, `CapacityIntervention`, and `CapacityMemoryPersistFailed` are persisted as runtime items. -- Compaction events become context-compaction lifecycle items. - -## Strings and config surface - -### User-visible strings and commands - -- `/cycles`, `/cycle `, and `/recall ` are registered in `commands/mod.rs` and dispatched to `commands/cycle.rs`. -- Sidebar shows `cycles: N (active: N+1)` once `app.cycle_count > 0`. -- The TUI history renderer recognizes assistant `` blocks and renders them as `HistoryCell::ArchivedContext`. -- Footer status item `coherence` is in default `StatusItem::default_footer`, but visible spans are intentionally empty for `Healthy` and `GettingCrowded`. -- `docs/CONFIGURATION.md` documents a compact `coherence` chip, although current footer code only renders intervention states. -- `docs/CONFIGURATION.md`, `config.example.toml`, and `docs/capacity_controller.md` document `[capacity]` as opt-in. -- `docs/CONFIGURATION.md` and `config.example.toml` document `[context]` seam keys as opt-in. - -### Config schema findings - -- `[capacity]` is a real top-level config table: `Config.capacity: Option`, parsed from TOML and environment-overridden via `DEEPSEEK_CAPACITY_*`. -- `[context]` is a real top-level config table: `Config.context: ContextConfig`, including `enabled`, `project_pack`, thresholds, `cycle_threshold`, `seam_model`, and `per_model`. -- `cycle_manager.rs` claims `[cycle.per_model]` in comments, but current `Config` does not expose a top-level `[cycle]` table. Active cycle config comes from `CycleConfig::default()` in `App::new`, direct CLI `main.rs`, and runtime-thread engine construction. -- `ContextConfig.per_model` exists but the observed `Engine::new` construction of `SeamConfig` reads only the top-level `[context]` threshold fields; no observed path applies per-model context threshold overrides. -- The hard cycle threshold used by `maybe_advance_cycle` comes from `EngineConfig.cycle`, not `[context].cycle_threshold`. TUI uses `app.cycle_config()`, which is initialized to `CycleConfig::default()`. - ---- - -# File findings - -## 1. `crates/tui/src/cycle_manager.rs` - -### Entry points - -- **Engine hard-cycle path**: `Engine::maybe_advance_cycle` calls `should_advance_cycle`, `produce_briefing`, `archive_cycle`, `StructuredState::capture`, and `build_seed_messages`. -- **Seam integration**: `maybe_advance_cycle` prefers `SeamManager::produce_flash_briefing` when a seam manager exists, falling back to `cycle_manager::produce_briefing`. -- **Recall path**: `tools/recall_archive.rs` uses `open_archive` to read JSONL archives written by `archive_cycle`. -- **UI command path**: `commands/cycle.rs` depends on `CycleBriefing` and `CycleConfig::threshold_for` through `App` state. - -### UI surface - -- **Direct**: no direct ratatui rendering in this file. -- **Indirect**: - - `CycleBriefing` is sent via `Event::CycleAdvanced`. - - TUI displays a cycle separator and status message. - - Sidebar displays cycle count once nonzero. - - `/cycles` and `/cycle ` display stored briefings. - -### State mutation - -- `archive_cycle` writes `~/.deepseek/sessions//cycles/.jsonl`. -- `maybe_advance_cycle` uses this module to build seed messages, then replaces `self.session.messages`, increments `session.cycle_count`, updates `session.current_cycle_started`, pushes `session.cycle_briefings`, clears `session.compaction_summary_prompt`, refreshes system prompt, and emits `SessionUpdated`/`CycleAdvanced`. -- `StructuredState::capture` reads todo/plan/sub-agent/working-set state but does not mutate it. - -### Runtime activation - -- **Default active but rare**. `CycleConfig::default()` has `enabled = true` and threshold `768_000` tokens. -- The engine calls `maybe_advance_cycle` after every completed turn, but `should_advance_cycle` returns false until the active input estimate reaches the smaller of configured threshold and model-window-minus-response-headroom. -- In practice, this is a near-wall safety path for long sessions, not normal-turn behavior. - -### Tests - -- Unit tests cover default config, per-model override logic, trigger threshold behavior, in-flight guard, carry-forward extraction, briefing cap, archive write/open, and seed-message construction. -- Tests are mostly isolated unit tests, but they validate on-disk archive format consumed by `recall_archive`. -- No observed integration test forces a full live `maybe_advance_cycle` through the streaming engine. - -### Strings/keys - -- User-visible concepts: `Cycle State (Auto-Preserved)`, ``, cycle archive JSONL, cycle handoff status strings in engine, `/cycle`, `/cycles`, `/recall` consumers. -- Comment claims `[cycle.per_model]` config. - -### Config schema - -- `CycleConfig` is serializable and has `per_model`, but current `Config` does not include a top-level cycle field. -- TUI/runtime/CLI construction uses `CycleConfig::default()` rather than parsed `[cycle]` config. -- `ContextConfig.cycle_threshold` is separate and feeds `SeamConfig`, not `CycleConfig`. - -### Verdict - -**LIVE**. - -This is not dead code: it is wired into post-turn engine behavior, mutates live session state, writes archives used by recall, and has UI/runtime event surfaces. It is rare-path and partly misdocumented/config-stranded, but not safe to delete. - -### Recommendation - -- **Keep for now** unless the product decision is to remove hard-cycle restart entirely. -- Fix or remove the stale `[cycle.per_model]` documentation/comment, or add real `[cycle]` config parsing. -- Consider adding an integration test that lowers the cycle threshold and verifies `maybe_advance_cycle` swaps messages and emits `CycleAdvanced`. - -## 2. `crates/tui/src/seam_manager.rs` - -### Entry points - -- `Engine::new` constructs `SeamManager` when a `DeepSeekClient` exists, using `[context]` config values. -- `Engine::layered_context_checkpoint` calls `seam_level_for`, `verbatim_window_start`, `collect_seam_texts`, `produce_soft_seam`, and `recompact`. -- `Engine::maybe_advance_cycle` calls `collect_seam_texts`, `produce_flash_briefing`, and `reset`. -- TUI history parsing consumes the `` blocks produced by this file. - -### UI surface - -- Produces assistant text blocks of the form `...`. -- `tui/history.rs` parses those blocks into `HistoryCell::ArchivedContext`, rendered as dim/italic archived context rows. -- Engine emits status messages while producing and completing seams. -- If used for cycle briefing, output indirectly appears in `/cycles` and `/cycle ` through `CycleBriefing`. - -### State mutation - -- Appends assistant messages to `self.session.messages` via `layered_context_checkpoint`. -- Tracks `SeamMetadata` in `active_seams` and clears it on hard-cycle reset. -- Reports cost through `cost_status::report` for seam/briefing calls. -- Does not remove original messages; design is append-only. - -### Runtime activation - -- **Default inactive**. `SeamConfig::default()` has `enabled = true`, but actual engine construction overrides this from `api_config.context.enabled.unwrap_or(false)`. -- `config.example.toml` and docs set `[context].enabled = false` by default. -- `layered_context_checkpoint` is called before each API request, but returns immediately when no seam manager exists, `enabled` is false, thresholds are not reached, or there is not enough history before the verbatim window. -- When `[context].enabled = true`, it is real runtime behavior. - -### Tests - -- Tests cover pure seam threshold ordering, lifetime-vs-active request token distinction, hard-cycle threshold constants, and verbatim window logic. -- Tests do not appear to run the full engine with `[context].enabled = true` and a mocked Flash response. - -### Strings/keys - -- User/model-visible XML: ``. -- Config keys documented under `[context]`: `enabled`, `verbatim_window_turns`, `l1_threshold`, `l2_threshold`, `l3_threshold`, `cycle_threshold`, `seam_model`. -- `ContextConfig.per_model` exists, but no observed wiring applies per-model seam thresholds in `Engine::new`. - -### Config schema - -- `[context]` is real and documented. -- `enabled` defaults false in app behavior. -- `seam_model` and thresholds are read by `Engine::new` into `SeamConfig`. -- `per_model` appears parsed but stranded from the observed `SeamConfig` construction. - -### Verdict - -**PARTIALLY LIVE**. - -The manager is wired and functional when opted in, but default sessions do not produce seams. It is a ghost subsystem by default, not dead. - -### Recommendation - -- Do not delete without an explicit product decision to remove experimental seams. -- If keeping, wire or remove `[context].per_model` and add an engine-level opt-in test. -- If replacing, preserve the `` UI parser compatibility until saved sessions with seam blocks are considered disposable. - -## 3. `crates/tui/src/core/coherence.rs` - -### Entry points - -- `capacity_flow.rs` imports `CoherenceState`, `CoherenceSignal`, and `next_coherence_state`. -- `emit_coherence_signal` calls `next_coherence_state` and emits `Event::CoherenceState`. -- Compaction events and capacity decision/intervention events generate coherence signals. -- TUI `App` stores `coherence_state`; runtime `ThreadRecord` persists it. - -### UI surface - -- `CoherenceState::label()` and `description()` provide user-facing labels/descriptions. -- TUI footer renders active intervention states via `footer_coherence_spans`: - - `RefreshingContext` - - `VerifyingRecentWork` - - `ResettingPlan` -- `Healthy` and `GettingCrowded` are suppressed in the footer, though runtime state still stores them. -- Runtime API emits `coherence.state` events and persists thread coherence. - -### State mutation - -- This module is pure. It mutates no state itself. -- Engine stores the reducer output in `self.coherence_state` and emits events. -- TUI and runtime persistence then update app/thread state. - -### Runtime activation - -- Active in ordinary sessions through compaction events: manual compaction, auto compaction, and emergency context recovery all call compaction event helpers that emit coherence signals. -- Capacity-driven states are only active when the capacity controller produces snapshots/interventions; default capacity is disabled, so capacity-specific coherence transitions are mostly dormant. - -### Tests - -- Unit tests cover reducer transitions for capacity decisions/interventions and compaction start/complete/fail. -- Runtime-thread tests cover persistence of `CoherenceState` in thread detail. - -### Strings/keys - -- Labels: `healthy`, `getting crowded`, `refreshing context`, `verifying recent work`, `resetting plan`. -- Descriptions are user-facing and flow through `Event::CoherenceState`. -- Config/UI key: `StatusItem::Coherence` / `tui.status_items = ["coherence"]`. - -### Config schema - -- No direct config table in this module. -- UI visibility is controlled indirectly by `tui.status_items`; `coherence` is part of the default footer item list. - -### Verdict - -**LIVE**. - -Small live reducer with runtime and UI surfaces. Capacity-specific branches are partially dormant by default, but compaction-driven coherence is live. - -### Recommendation - -- Keep. -- If simplifying, fold the reducer into event handling only after verifying runtime API/state compatibility. -- Align docs with the footer behavior: `Healthy`/`GettingCrowded` may exist in state but are not normally rendered as chips. - -## 4. `crates/tui/src/core/capacity.rs` - -### Entry points - -- `CapacityControllerConfig::from_app_config` converts parsed `[capacity]` TOML to runtime config. -- `Engine::new` constructs `CapacityController::new(config.capacity.clone())`. -- `handle_send_message` calls `capacity_controller.mark_turn_start` each turn. -- `capacity_flow.rs` calls `observe_pre_turn`, `observe_post_tool`, `last_snapshot`, `decide`, `mark_intervention_applied`, and `mark_replay_failed`. - -### UI surface - -- No direct UI rendering in this file. -- Decisions/interventions emitted by `capacity_flow` become TUI status messages, coherence state changes, and runtime API items. -- `GuardrailAction::as_str()` and `RiskBand::as_str()` feed event payloads. - -### State mutation - -- Mutates controller runtime state: rolling slack/tool/ref windows, last snapshot, cooldown/intervention/replay counters. -- Does not mutate session messages directly; `capacity_flow` performs message/session mutations based on decisions. - -### Runtime activation - -- **Default inert**. `CapacityControllerConfig::default().enabled = false`. -- `observe_pre_turn`/`observe_post_tool` return `None` when disabled, making decisions `NoIntervention`. -- Engine still calls the checkpoints every turn, so it is wired but no-ops in default sessions. -- Opt-in via `[capacity].enabled = true` or `DEEPSEEK_CAPACITY_ENABLED` re-arms the policy. - -### Tests - -- Unit tests cover disabled behavior, opt-in behavior, risk policy decisions, cooldowns, model priors, and config defaults. -- Engine tests cover opt-in pre-request refresh, post-tool replay, error escalation, and disabled-by-default behavior preserving messages. -- Tests explicitly document why default disabled exists: active interventions can clear or rewrite the transcript. - -### Strings/keys - -- Guardrail action strings include `no_intervention`, `targeted_context_refresh`, `verify_with_tool_replay`, `verify_and_replan`. -- Risk strings include low/medium/high. -- Config keys documented and parsed under `[capacity]`; env overrides use `DEEPSEEK_CAPACITY_*`. - -### Config schema - -- Real and documented in `config.example.toml`, `docs/CONFIGURATION.md`, and `docs/capacity_controller.md`. -- Default is disabled in code, docs, and tests. - -### Verdict - -**PARTIALLY LIVE**. - -The code is wired into every turn but intentionally inert by default. Opt-in path is real and load-bearing for users who enable it, but default product behavior treats it as an experimental guardrail. - -### Recommendation - -- Do not delete blindly; it has explicit opt-in docs/tests. -- If product direction is “capacity should stay off forever,” deprecate config first, then remove after a compatibility window. -- If keeping, consider isolating destructive behavior behind clearer UI warnings and add integration tests for event emission. - -## 5. `crates/tui/src/core/capacity_memory.rs` - -### Entry points - -- `capacity_flow::persist_capacity_record` calls `append_capacity_record` after opt-in capacity interventions. -- `capacity_flow::rehydrate_latest_canonical_state` calls `load_last_k_capacity_records` on engine startup and resume. -- Engine calls `rehydrate_latest_canonical_state` in `Engine::new` and after loading a session. -- Tests call path-specific append/load helpers. - -### UI surface - -- No direct UI rendering. -- Failed writes emit `Event::CapacityMemoryPersistFailed` from `capacity_flow`, which becomes a TUI status message and runtime item. -- Successful writes only affect future system prompt rehydration through a `memory:///` pointer. - -### State mutation - -- Writes JSONL records to: - - `DEEPSEEK_CAPACITY_MEMORY_DIR` when set; - - otherwise `~/.deepseek/memory/.jsonl`; - - fallback `/.deepseek/memory/.jsonl`. -- Reads latest records and returns deserialized `CapacityMemoryRecord` values. -- Ignores malformed individual JSONL lines while reading. - -### Runtime activation - -- Writes are active only after capacity interventions, and those interventions are disabled by default. -- Reads are attempted on startup/resume regardless of whether capacity is currently enabled. If no records exist, no-op. -- Therefore default sessions without prior opt-in capacity records will never observe visible behavior. - -### Tests - -- Unit tests cover JSONL round trip, candidate fallback writes, and newest-candidate selection. -- Engine tests verify an opt-in replan intervention persists a record. - -### Strings/keys - -- Environment variable: `DEEPSEEK_CAPACITY_MEMORY_DIR`. -- Memory pointer string format: `memory:///` generated in `capacity_flow`. -- JSONL fields: `id`, `ts`, `turn_index`, `action_trigger`, `h_hat`, `c_hat`, `slack`, `risk_band`, `canonical_state`, `source_message_ids`, optional `replay_info`. - -### Config schema - -- No TOML config table directly in this module. -- Path override is environment-only and documented in `docs/capacity_controller.md`. - -### Verdict - -**PARTIALLY LIVE**. - -Support code for an opt-in subsystem. It is not dead because engine startup/resume calls rehydration and opt-in interventions write records, but in default sessions it is usually dormant. - -### Recommendation - -- Keep if capacity controller remains. -- If capacity controller is removed, remove this module with the rehydration hook and docs together. -- If keeping, consider whether rehydration should check capacity enablement or whether historical capacity memory should intentionally survive after disabling. - -## 6. `crates/tui/src/core/engine/capacity_flow.rs` - -### Entry points - -- `turn_loop.rs` calls: - - `run_capacity_pre_request_checkpoint` before request budget checks; - - `run_capacity_post_tool_checkpoint` after tool result handling; - - `run_capacity_error_escalation_checkpoint` after error streak accounting. -- `engine.rs` manual/auto/emergency compaction paths call `emit_compaction_started`, `emit_compaction_completed`, and `emit_compaction_failed`. -- `Engine::new` and session-load paths call `rehydrate_latest_canonical_state`. - -### UI surface - -- Emits: - - `CapacityDecision` telemetry; - - `CapacityIntervention` status-driving events; - - `CapacityMemoryPersistFailed` status-driving events; - - `CoherenceState` events; - - compaction lifecycle events. -- TUI renders capacity interventions as status messages and active coherence states in the footer. -- Runtime API persists these events as thread/item records. - -### State mutation - -- `apply_targeted_context_refresh` can run compaction, trim messages, persist canonical state, merge a canonical prompt into the system prompt, refresh system prompt, and mark intervention cooldown. -- `apply_verify_with_tool_replay` can replay read-only tools, append verification tool-result messages, persist canonical state, merge canonical prompt, refresh system prompt, and mark replay/intervention state. -- `apply_verify_and_replan` persists canonical state, clears `session.messages`, preserves latest user and verification messages, injects replan prompt, refreshes system prompt, and marks intervention. -- `rehydrate_latest_canonical_state` can merge the latest persisted canonical state into the system prompt on startup/resume. - -### Runtime activation - -- Checkpoint functions are called during ordinary turns. -- With default capacity disabled, observations return `None`, decisions no-op, and intervention methods do not run from capacity decisions. -- Compaction event helpers and coherence transitions are live even when capacity is disabled, because compaction paths call them. -- Rehydration is attempted on every engine construction/resume. - -### Tests - -- Engine tests cover opt-in pre-request refresh, opt-in post-tool replay, opt-in error replan, disabled-by-default no mutation, and controller disabled unchanged behavior. -- These tests exercise engine state mutation directly rather than only pure functions. - -### Strings/keys - -- Status strings include capacity refresh failure, verification replay notes, canonical prompt section names, replan instruction, and memory pointers. -- Uses `GuardrailAction` strings from `capacity.rs`. -- Emits user-visible statuses like `Capacity guardrail: context reset to canonical state; replanning step.` - -### Config schema - -- Behavior gated by `EngineConfig.capacity`, which comes from `[capacity]` via `CapacityControllerConfig::from_app_config`. -- Also uses `self.config.compaction` for targeted refresh and `self.config.capacity.profile_window` for observations. - -### Verdict - -**PARTIALLY LIVE**. - -This is central wiring, not isolated dead code. However, its capacity-specific destructive branches are ghost behavior by default due to `[capacity].enabled = false`. The compaction/coherence helper half is live. - -### Recommendation - -- Do not delete without removing or rewriting the capacity controller contract. -- If simplifying default behavior, split live compaction/coherence helpers from opt-in capacity intervention logic so ghost code is easier to reason about. -- Add event-level tests for default compaction coherence if preserving the footer/runtime coherence contract. - -## 7. `crates/tui/src/commands/cycle.rs` - -### Entry points - -- `commands/mod.rs` registers and dispatches: - - `/cycles` -> `cycle::list_cycles`; - - `/cycle` -> `cycle::show_cycle`; - - `/recall` -> `cycle::recall_archive`. -- Command metadata exposes these commands in help/autocomplete. - -### UI surface - -- `/cycles` returns a human-readable list of cycle handoffs or a “No cycle boundaries” message. -- `/cycle ` returns a full briefing or validation errors. -- `/recall ` returns the JSON payload from `RecallArchiveTool` or an error message. -- All are user-invoked slash-command output. - -### State mutation - -- `list_cycles` and `show_cycle` are read-only. -- `recall_archive` is read-only against archive files. -- No App state mutation observed in these functions. - -### Runtime activation - -- Active whenever the user types the commands. -- `/cycles` and `/cycle` only become useful after a hard cycle fires; before then they still produce meaningful empty-state/error output. -- `/recall` depends on archived cycle files; if none exist, the tool reports no prior archives. - -### Tests - -- Unit tests cover empty list, nonexistent cycle, valid list/show rendering, and argument validation. -- Tests do not cover `/recall` wrapper directly, but `RecallArchiveTool` has its own tests. - -### Strings/keys - -- Command names: `/cycles`, `/cycle `, `/recall `. -- User-visible output includes “No cycle boundaries”, “Cycle handoffs”, and `recall_archive failed`. - -### Config schema - -- No direct config reads. -- Reads `app.cycle.threshold_for(&app.model)` for empty-state messaging, but `app.cycle` is currently initialized from default `CycleConfig`. - -### Verdict - -**LIVE**. - -Registered slash commands with user-visible output. Utility depends on rare hard-cycle archives, but command dispatch is live. - -### Recommendation - -- Keep if hard-cycle archives or recall remain. -- If parent model should also get `recall_archive`, add it to `build_turn_tool_registry_builder`; otherwise document `/recall` as the primary parent-session surface. - -## 8. `crates/tui/src/tools/recall_archive.rs` - -### Entry points - -- `/recall ` directly instantiates `RecallArchiveTool` and calls `execute`. -- `ToolRegistryBuilder::with_recall_archive_tool` registers it. -- `with_full_agent_surface` includes `with_recall_archive_tool`, which is used by sub-agent runtime registry construction. -- No observed call to `with_recall_archive_tool` in the parent `Engine::build_turn_tool_registry_builder`; parent Agent mode uses `with_agent_tools`, then review/user-input/parallel/RLM/FIM/web/shell/etc. - -### UI surface - -- Via `/recall`, output is returned to the user as JSON text. -- As a model-callable tool, returns JSON content with `query`, optional `cycle`, `max_results`, `archive_count`, and `hits`. -- Empty archives produce a human-readable no-archive message in the tool result content. - -### State mutation - -- Read-only. Lists archive JSONL files, opens them through `cycle_manager::open_archive`, tokenizes/scans messages, and returns BM25-ranked excerpts. -- Does not write state. - -### Runtime activation - -- User-invoked `/recall` is active in the parent TUI. -- Model-callable parent Agent/Plan surface appears stranded: `with_recall_archive_tool` is not part of the observed parent registry builder. -- Sub-agents using `with_full_agent_surface` do get the tool. -- Requires prior cycle archives written by `archive_cycle`; without archives it returns no-archive output. - -### Tests - -- Tests cover archive listing order, no-archive behavior, matching messages, cycle filter, max result cap, empty query rejection, UTF-8 boundary handling, BM25 relevance, and archive read integration. -- Tests are direct tool tests plus archive-writer integration, not full parent model-call integration. - -### Strings/keys - -- Tool name: `recall_archive`. -- Input keys: `query`, `cycle`, `max_results`. -- Output keys: `query`, `cycle`, `max_results`, `archive_count`, `hits`, `message_index`, `role`, `score`, `excerpt`. -- User command string: `/recall `. - -### Config schema - -- No TOML config. -- Depends on archive path convention from `cycle_manager`: `~/.deepseek/sessions//cycles/*.jsonl`. -- Session namespace comes from `ToolContext::state_namespace`; `/recall` uses `app.current_session_id.unwrap_or("workspace")`. - -### Verdict - -**PARTIALLY LIVE**. - -Live through `/recall` and sub-agent tool registration, but stranded from the observed parent model-callable tool registry. It is not dead, but the model-visible parent path promised by some comments/docs is incomplete. - -### Recommendation - -- If model-call recall is desired, add `with_recall_archive_tool()` to `Engine::build_turn_tool_registry_builder` for appropriate modes and test registry membership. -- If only user-invoked recall is desired, update comments/docs to avoid implying the parent agent can call it. -- Keep archive reader compatibility while hard-cycle archives exist. - ---- - -# Phase-1 opinion - -## Classification table - -| Module | Classification | Why | -|---|---|---| -| Cycle manager | LIVE, STATE-MUTATING, DESIGN-LOAD-BEARING; PRACTICAL LOAD-BEARING UNPROVEN | It owns hard-cycle restart, archive writing, seed-message construction, and carry-forward state. Rare but central when triggered. | -| Seam manager | GHOST / LIVE BUT REPLACEABLE | Opt-in by default; real engine path and UI parser exist. Can be removed only with explicit removal of experimental `[context].enabled` behavior. | -| Coherence reducer | LIVE BUT REPLACEABLE | Visible footer/runtime state, small pure reducer. Easy to refactor, not dead. | -| Capacity controller | GHOST / LIVE BUT REPLACEABLE | Every-turn wiring exists, but disabled by default. Opt-in path is tested and destructive. | -| Capacity memory | GHOST support module | Support for opt-in capacity interventions; startup/resume rehydration is live but usually no-op without prior records. | -| Capacity flow | GHOST / LIVE BUT REPLACEABLE | Every-turn checkpoint calls and compaction/coherence helpers are live; capacity interventions are default-off. | -| Cycle commands | LIVE BUT REPLACEABLE | Registered slash commands; no safe deletion while cycle/recall UX remains. | -| Recall archive tool | LIVE BUT STRANDED FROM PARENT TOOL SURFACE | Live as `/recall` and sub-agent tool, but parent agent registry appears not to include it. | - -## Hypothesis assessment - -Hunter's hypothesis is **partly supported**, but not in the strongest “dead code” form. - -- **Not dead**: The files are compiled, referenced, tested, and in several cases called by the live engine loop or command registry. -- **Quietly stranded/default-off**: Capacity and seam behavior are largely inactive in default sessions. Their expensive/destructive behaviors are opt-in or threshold-gated. -- **Config mismatch**: Cycle configuration is the clearest stranded surface: code comments describe `[cycle.per_model]`, but active construction uses `CycleConfig::default()` and no observed top-level `[cycle]` config schema exists. -- **Recall mismatch**: `recall_archive` is live via `/recall` and sub-agents, but appears absent from the parent model-callable Agent/Plan registry. - -## Deletion/refactor recommendations - -### Safe immediate actions - -- **Documentation/code-comment cleanup**: - - Correct `cycle_manager.rs` comments about `[cycle.per_model]` unless adding real `[cycle]` config parsing. - - Clarify whether `[context].cycle_threshold` affects hard cycles; currently it appears to affect only `SeamConfig`, not `CycleConfig`. - - Clarify that `recall_archive` is available via `/recall` and sub-agents, but not observed in the parent registry. - -### Small refactors worth doing before deletion - -- **Split capacity flow**: Separate always-live compaction/coherence event helpers from default-off capacity interventions. -- **Registry test**: Add tests asserting which registries include `recall_archive`. -- **Config tests**: Add tests proving `[context].per_model` is applied or remove/deprecate it. -- **Cycle integration test**: Add a low-threshold cycle handoff test to validate engine event/state behavior end-to-end. - -### Do not delete yet - -- Do not delete `cycle_manager.rs` or `commands/cycle.rs` unless removing hard-cycle restart and archive UX as a product feature. -- Do not delete `seam_manager.rs` while `[context].enabled` remains documented. -- Do not delete capacity files while `[capacity]` remains documented opt-in behavior. -- Do not delete `recall_archive.rs` while `/recall` remains registered. - -## Phase-2 action gate - -No deletion is recommended from this codemap alone. - -Recommended next step: choose one of these explicit product decisions: - -1. **Keep and fix wiring**: preserve all subsystems, fix config/registry drift, and add integration tests. -2. **Deprecate opt-in ghosts**: mark `[capacity]` and/or `[context].enabled` as deprecated, keep compatibility for one release, then remove. -3. **Remove hard-cycle architecture**: delete cycle, recall, and archive UX together only after accepting loss of saved archive recall and hard-wall restart behavior. - diff --git a/.claude/HANDOFF_v0.8.28_user_issues.md b/.claude/HANDOFF_v0.8.28_user_issues.md deleted file mode 100644 index c836f062..00000000 --- a/.claude/HANDOFF_v0.8.28_user_issues.md +++ /dev/null @@ -1,274 +0,0 @@ -# v0.8.28 — User-Issue Strategy Handoff - -**Audience:** the AI agent picking up post-v0.8.27 user-bug work. -**Scope:** items that didn't make v0.8.27 (deferred P3 / comment-pinged -P2) plus anything new that lands during the v0.8.27 → v0.8.28 inflow -window. - ---- - -## Where you are - -- **Working tree:** `/Volumes/VIXinSSD/whalebro/deepseek-tui` -- **Last shipped:** v0.8.27 (commit `aaccaee6`, tag `v0.8.27`) — - 17 community PRs + a focused user-issue sweep (flicker, wrap, - pager copy-out, context-sensitive Ctrl+C, MCP auto-reload, notify - tool, onboarding localization, paste UX rebuild, /skills filter). - ~25 issues closed in the cycle. See PR #1375 for the full list. -- **Reference docs:** `.claude/HANDOFF_v0.8.26_security.md` for the - release flow shape (same matrix → crates → npm → Homebrew → GHCR). - ---- - -## Hard rules (same as v0.8.27 cycle) - -1. **STOP and ask Hunter** before merging the release PR, tagging, - or publishing to crates.io / npm / Homebrew. -2. No `--no-verify`, no `--no-gpg-sign`, no force push. -3. Don't leak `.private/` content into PRs / CHANGELOG / release notes. -4. v0.8.28 is **NOT** a security release by default. If a new GHSA - arrives mid-cycle, branch a hotfix — don't bundle. -5. Time-box thorny items at 30-45 min. Defer rather than sink the - cycle on one item. - ---- - -## P1 — should ship; clear shape - -### 1. CNB.cool mirror automated push - -**Diagnosis.** v0.8.27 set up the CNB.cool destination repo at -`https://cnb.cool/deepseek-tui.com/DeepSeek-TUI` but the initial -bare-mirror push got 403 ("You do not have permission to push this -repository") with the issued PAT under user `whalebro`. The repo -shows as fresh / not-yet-initialized on the CNB side. - -**Strategy.** - -1. Confirm with CNB which scope the token needs (likely a "Push" - permission separate from default repo read). Re-issue the - PAT with that scope. -2. Verify the manual bare-clone-then-mirror push works once with - the new PAT: - ```bash - git clone --bare https://github.com/Hmbown/DeepSeek-TUI.git /tmp/cnb-init - cd /tmp/cnb-init - git push --mirror https://whalebro:@cnb.cool/deepseek-tui.com/DeepSeek-TUI - ``` -3. Wire up a `mirror-cnb` job in `.github/workflows/release.yml` - that runs on tag push and pushes to CNB automatically. Store the - token as a `CNB_PUSH_URL` GitHub Actions secret so future - releases mirror without manual steps. -4. After CNB has content, add the mirror banner to `README.md` and - `README.zh-CN.md` near the top: - - ``` - > 🇨🇳 国内镜像 / Mainland China mirror: - > https://cnb.cool/deepseek-tui.com/DeepSeek-TUI - > Issues and PRs: please use GitHub. - ``` - -**Cost:** ~30 min once the token has the right scope; ~1-2 hr if -the release.yml automation also needs the multi-platform Action -sorted out. - -### 2. Ctrl+Enter as newline (#1372, follow-up to #1331) - -**Diagnosis.** On Windows + nushell (and possibly some PowerShell -setups), users expect `Ctrl+Enter` to insert a newline. v0.8.27's -keybinding contract is: - -- `Alt+Enter` / `Shift+Enter` / `Ctrl+J` → newline -- `Ctrl+Enter` → force-steer (submit into current turn) - -The reporter for #1372 was on Windows + nushell. Comment-ping in -the issue asks them to try `Alt+Enter` / `Ctrl+J` and confirm -what `KeyEvent` the TUI actually sees via `RUST_LOG=debug`. - -**Strategy.** Add `[tui] ctrl_enter_as_newline` config flag, -default false. When `true`, swap the priority so `Ctrl+Enter` -inserts a newline and `Ctrl+Enter+Ctrl` (or similar) force-steers. -Document the trade-off in `docs/CONFIGURATION.md`. - -**Cost:** ~1 hour. - -### 3. Windows `task_manager` test flake - -**Diagnosis.** `task_manager::tests::persists_and_recovers_task_records` -uses `wait_for_terminal_state(&manager, &task.id, Duration::from_secs(3))` -— that 3s timeout for durable-task recovery is tight under Windows -CI file-I/O load. We saw one intermittent failure during the v0.8.27 -PR run (passed on retry). - -**Strategy.** Bump the timeout to `Duration::from_secs(10)` (or -`Duration::from_secs(if cfg!(windows) { 10 } else { 3 })`). No -functional change; just buys headroom for Windows CI. - -**Cost:** ~10 min. - -### 4. Test flakiness under load (general) - -**Diagnosis.** The full tui test suite (now ~2640 tests) shows -intermittent failures on macOS under load: -- `mcp_connection_supports_streamable_http_event_stream_responses` - (documented flaky; in handoff) -- `refresh_system_prompt_is_noop_when_unchanged` (new flake) -- `save_api_key_for_openrouter_writes_provider_table` (new flake) -- `tools::recall_archive::tests::list_archives_sorts_by_cycle_number` - (new flake) - -All four pass in isolation. Suggests env-var or filesystem state -sharing between tests that contend under parallel pressure. - -**Strategy.** Audit the four tests for shared global state -(env vars, `~/.deepseek/`, tempdir patterns). The most likely -culprit is `unsafe { std::env::set_var(...) }` blocks without -holding a process-wide test mutex. - -**Cost:** 1-2 hours. - ---- - -## P2 — nice-to-have; awaiting reporter feedback - -### 5. #1112 snapshot growth - -v0.8.24 added a 500 MB snapshot cap + retention count + mid-session -pruning (vs startup-only). v0.8.27 cycle comment-pinged the reporter -asking for `du -sh ~/.deepseek/snapshots` on the latest version. -If they confirm growth is bounded, close. If still unbounded, the -likely culprit is iCloud Drive / network-FS interactions; investigate. - -### 6. #1357 input/runtime-hint overlap - -Windows reporter screenshots show input box overlapping the runtime -hint line. Comment-pinged in v0.8.27 cycle asking for terminal -width (`tput cols`), terminal type (Windows Terminal / VSCode / etc), -and the input that triggered the overlap. Likely a reserved-rows -calc bug in `crates/tui/src/tui/widgets/mod.rs` composer layout. - -**Cost:** 1 hr repro + 1 hr fix once reporter responds. - -### 7. #1281 Cmux notifications - -Cmux is a tmux-derivative; `notify_done` doesn't fire inside Cmux. -Comment-pinged asking for `echo "TERM_PROGRAM=$TERM_PROGRAM TMUX=$TMUX"` -output and `[notifications]` config. Likely a one-line addition to -`resolve_method()` in `crates/tui/src/tui/notifications.rs` once we -know what env vars Cmux sets. - -**Cost:** 30 min once reporter responds. - ---- - -## P3 — investigate or defer - -### #1338 Windows panic on Enter mid-run - -The TUI's panic hook writes crash dumps to `~/.deepseek/crashes/` -already. Comment-pinged the reporter asking for the most recent -crash log. Without it the panic location is opaque. Defer until -reporter shares the log; then targeted fix. - -### #1062 Capacity-memory checkpoint cross-session recovery - -Old, complex. Needs scope conversation with Hunter before any work. - -### #1067 glibc version (older Linux distros) - -Static-link via musl build target. Purely a release.yml addition -(add a `x86_64-unknown-linux-musl` target alongside the gnu one). -**Good candidate for v0.8.28** if release.yml work happens anyway -(see Item #1 CNB mirror — both touch the release workflow). - -**Cost:** ~1 hour to add the musl target + update the install script. - -### #1364 Hooks v2 mutation rights + turn-end event - -Real ask. Worth doing as part of a hooks-v2 rework. **Defer to -v0.9.0** — out of scope for a polish release. - -### #1343 Desktop GUI - -Recurring request. v0.9.x territory at the earliest. Comment with -roadmap status if not already. - -### #1394 Prompt-level reliability guidance -Feature/enhancement for prompting (PR #1393). Defer to future release. - ---- - -## Workflow - -### Step 1 — Branch state confirmation - -```bash -cd /Volumes/VIXinSSD/whalebro/deepseek-tui -git checkout main && git pull -git checkout -b work/v0.8.28 -``` - -### Step 2 — Tackle items in priority order (P1 → P2 → P3) - -For each item: -1. Read the issue thread on GitHub for any new reporter info. -2. Implement per the strategy. -3. Add tests (TDD where strategy specifies; verification snapshot otherwise). -4. After each commit: - ```bash - cargo fmt --all - cargo clippy --workspace --all-targets --all-features --locked -- -D warnings - cargo test -p deepseek-tui --bin deepseek-tui --all-features --locked --no-fail-fast \ - 2>&1 | grep "test result:" | tail -3 - ``` -5. Add a CHANGELOG entry under `## [0.8.28]` `### Fixed` / `### Added` / - `### Changed`, crediting the issue + original reporter where applicable. - -### Step 3 — Bump version when ready - -```bash -sed -i '' 's|^version = "0.8.27"|version = "0.8.28"|' Cargo.toml -find crates -maxdepth 2 -name Cargo.toml -exec sed -i '' \ - 's|version = "0.8.27"|version = "0.8.28"|g' {} + -sed -i '' 's|"version": "0.8.27"|"version": "0.8.28"|' \ - npm/deepseek-tui/package.json -sed -i '' 's|"deepseekBinaryVersion": "0.8.27"|"deepseekBinaryVersion": "0.8.28"|' \ - npm/deepseek-tui/package.json -cargo update --workspace --offline -./scripts/release/check-versions.sh -``` - -Add `## [0.8.28] - YYYY-MM-DD` heading at the top of CHANGELOG.md. - -### Step 4 — Preflight + release flow - -Same as v0.8.27 — see PR #1375 and the v0.8.27 ship report for the -exact channel-ship sequence (merge → tag → matrix → crates → npm → -Homebrew → GHCR → CNB mirror → README on main → handoff transition). - -If Item #1 (CNB mirror automation) lands, the CNB mirror push step -becomes automatic on tag push. - ---- - -## Open items that may still arrive - -The v0.8.27 release shipped on 2026-05-10. The 24-48 hour inflow -window after that release may surface fresh issues that should be -prioritized for v0.8.28. Default: any issue with ≥3 unique reporters -or any new flicker / panic / data-loss class bug gets P0 treatment. - ---- - -## Quality bar (unchanged from v0.8.27) - -Apply to every change: - -- CI green (modulo documented flaky) -- No new `unwrap()` / `expect()` outside test code -- No new external network surfaces without `validate_network_policy` -- New env vars or config keys → `config.example.toml` entry + CHANGELOG note -- Behavior changes user-visible → CHANGELOG entry calling out the change - -When in doubt, defer to v0.8.29. A clean release of 4 P1 items beats -a cluttered release of 12 with one regression.