|
| 1 | +# [PROPOSAL: DESIGN ONLY - NOT YET IMPLEMENTED] |
| 2 | + |
| 3 | +# Controlled Edit Mode v1: Design Document |
| 4 | + |
| 5 | +**Phase:** Design Proposal |
| 6 | +**Status:** Approved for Implementation (Design Stage Only) |
| 7 | +**Objective:** Enable the C++ agent loop to execute a single code change safely, verify compilation, and immediately exit without introducing autonomous repair loops, planning iterations, or architectural complexity. |
| 8 | + |
| 9 | + |
| 10 | +--- |
| 11 | + |
| 12 | +## 1. Safety Guardrails & Core Constraints |
| 13 | + |
| 14 | +Controlled Edit Mode v1 is governed by seven strict architectural guardrails implemented at the native engine/routing level rather than relying on LLM self-discipline: |
| 15 | + |
| 16 | +1. **Single-File Limit:** Only one target file may be modified. Any tool call specifying a second file is blocked. |
| 17 | +2. **Mandatory Pre-Edit Checkpoint:** Before modifying any file on disk, the system automatically creates a workspace backup via `Services::CheckpointService`. |
| 18 | +3. **Mandatory Post-Edit Build:** Immediately following text replacement, the system triggers a C++ compile run (`cmake --build build`). |
| 19 | +4. **No Automatic Repair:** If compilation fails, the agent is **not** allowed to run another tool or attempt to fix the error. The loop halts immediately. |
| 20 | +5. **No Second Edit:** A session-level boolean flag in `SessionState` prevents execution of more than one edit command. |
| 21 | +6. **Automatic Rollback:** If compilation fails, the orchestrator automatically restores the workspace back to the pre-edit checkpoint before reporting the failure. |
| 22 | +7. **Immediate Stop:** The agent loop terminates immediately after the edit and build sequence is executed, regardless of whether it succeeded or failed. |
| 23 | + |
| 24 | +--- |
| 25 | + |
| 26 | +## 2. Integrated Tool Design: `edit_file` |
| 27 | + |
| 28 | +Rather than exposing multiple low-level tools (`checkpoint`, `replace_text`, `build`, `restore`) to the agent, we consolidate this sequence into a single atomic tool call: `edit_file`. This encapsulates the safety workflow inside the C++ execution engine. |
| 29 | + |
| 30 | +### Tool Signature |
| 31 | +- **Tool Name:** `edit_file` |
| 32 | +- **Arguments (JSON-Formatted):** |
| 33 | + ```json |
| 34 | + { |
| 35 | + "filename": "relative/path/to/file.cpp", |
| 36 | + "old_text": "text_to_be_replaced", |
| 37 | + "new_text": "replacement_text" |
| 38 | + } |
| 39 | + ``` |
| 40 | + *Note: JSON arguments are parsed using `<nlohmann/json.hpp>` to prevent collision with special delimiters like colons (`:`) or newlines (`\n`) within the target code.* |
| 41 | + |
| 42 | +### Execution sequence in C++ Tool Runner |
| 43 | + |
| 44 | +```mermaid |
| 45 | +sequenceDiagram |
| 46 | + participant E as ExecutionEngine |
| 47 | + participant R as CommandRouter (Tool Runner) |
| 48 | + participant C as CheckpointService |
| 49 | + participant F as FileService |
| 50 | + participant B as CommandService (Build) |
| 51 | + participant RP as ReportGenerator |
| 52 | +
|
| 53 | + E-> R: edit_file(JSON_args) |
| 54 | + Note over R: Assert state.has_edited == false |
| 55 | + |
| 56 | + R->>C: create_checkpoint("pre_edit_" + filename) |
| 57 | + C-->>R: Checkpoint ID: <cp_id> |
| 58 | + |
| 59 | + R-> F: replace_text_in_file(filename, old_text, new_text) |
| 60 | + F-->>R: FileEditResult (success, replacements_made) |
| 61 | + |
| 62 | + alt Edit Succeeded |
| 63 | + R->>B: execute("cmake --build build") |
| 64 | + B-->>R: Build Output & Exit Code |
| 65 | + |
| 66 | + alt Build Succeeded (Exit 0) |
| 67 | + Note over R: Set state.build_success = true |
| 68 | + R-->>E: "SUCCESS: Edit applied and compiled successfully" |
| 69 | + else Build Failed (Exit != 0) |
| 70 | + R->>C: restore_checkpoint(<cp_id>) |
| 71 | + Note over R: Set state.build_success = false |
| 72 | + R-->>E: "FAILURE: Compile failed, workspace rolled back" |
| 73 | + end |
| 74 | + else Edit Failed (Text mismatch/missing file) |
| 75 | + Note over R: Set state.build_success = false |
| 76 | + R-->>E: "FAILURE: Text replacement failed" |
| 77 | + end |
| 78 | + |
| 79 | + Note over R: Set state.has_edited = true |
| 80 | + R->>RP: write_report("docs/telemetry/controlled_edit_report.md") |
| 81 | + RP-->>R: Report saved |
| 82 | +``` |
| 83 | + |
| 84 | +--- |
| 85 | + |
| 86 | +## 3. Implementation Footprint (Total: ~100 lines of C++ code) |
| 87 | + |
| 88 | +### 3.1 Session State Updates (`include/core/session_state.h`) |
| 89 | +Add state trackers to the existing `SessionState` struct to track execution context: |
| 90 | +```cpp |
| 91 | +// Add to include/core/session_state.h within struct SessionState: |
| 92 | +bool has_edited{false}; // Prevents execution of a second edit |
| 93 | +bool build_success{false}; // Tracks compilation status of the edit |
| 94 | +std::string edit_file_path{}; // Path of the edited file |
| 95 | +std::string edit_checkpoint_id{}; // Pre-edit checkpoint ID |
| 96 | +std::string edit_build_output{}; // Captured stdout/stderr of build command |
| 97 | +``` |
| 98 | +
|
| 99 | +### 3.2 Tool Registration & Routing (`src/app/command_router.cpp`) |
| 100 | +Add the handler for `edit_file` in the tool execution lambda within `CommandRouter::process_user_input`: |
| 101 | +```cpp |
| 102 | +// Add to src/app/command_router.cpp within the lambda passed to engine.execute: |
| 103 | +} else if (tc.tool == "edit_file") { |
| 104 | + if (agent_.state_.has_edited) { |
| 105 | + tr.out = "Error: An edit has already been performed in this session."; |
| 106 | + tr.exit_code = 1; |
| 107 | + return tr; |
| 108 | + } |
| 109 | +
|
| 110 | + try { |
| 111 | + auto args = nlohmann::json::parse(tc.args); |
| 112 | + std::string filename = args.value("filename", ""); |
| 113 | + std::string old_text = args.value("old_text", ""); |
| 114 | + std::string new_text = args.value("new_text", ""); |
| 115 | +
|
| 116 | + if (filename.empty() || old_text.empty()) { |
| 117 | + tr.out = "Error: Missing required JSON fields ('filename', 'old_text')"; |
| 118 | + tr.exit_code = 1; |
| 119 | + return tr; |
| 120 | + } |
| 121 | +
|
| 122 | + agent_.state_.edit_file_path = filename; |
| 123 | +
|
| 124 | + // 1. Mandatory Pre-Edit Checkpoint |
| 125 | + std::string cp_id = Services::CheckpointService::create_checkpoint( |
| 126 | + "pre_edit_" + Services::FileService::get_relative_path(filename, "."), |
| 127 | + "Controlled edit baseline" |
| 128 | + ); |
| 129 | + agent_.state_.edit_checkpoint_id = cp_id; |
| 130 | +
|
| 131 | + // 2. Perform Edit |
| 132 | + auto edit_res = Services::FileService::replace_text_in_file(filename, old_text, new_text); |
| 133 | + if (!edit_res.success) { |
| 134 | + tr.out = "Edit failed: " + edit_res.message; |
| 135 | + tr.exit_code = 1; |
| 136 | + agent_.state_.has_edited = true; |
| 137 | + agent_.state_.build_success = false; |
| 138 | + return tr; |
| 139 | + } |
| 140 | +
|
| 141 | + // 3. Mandatory Post-Edit Build |
| 142 | + std::string build_out = Services::CommandService::execute("cmake --build build"); |
| 143 | + agent_.state_.edit_build_output = build_out; |
| 144 | + bool compile_ok = (build_out.find("error:") == std::string::npos && |
| 145 | + build_out.find("Error 1") == std::string::npos); |
| 146 | +
|
| 147 | + agent_.state_.has_edited = true; |
| 148 | + agent_.state_.build_success = compile_ok; |
| 149 | +
|
| 150 | + if (compile_ok) { |
| 151 | + tr.out = "SUCCESS: Code modified and build passed."; |
| 152 | + tr.exit_code = 0; |
| 153 | + } else { |
| 154 | + // 4. Automatic Rollback on Compile Failure |
| 155 | + Services::CheckpointService::restore_checkpoint(cp_id); |
| 156 | + tr.out = "FAILURE: Compile failed. Workspace rolled back."; |
| 157 | + tr.exit_code = 2; |
| 158 | + } |
| 159 | + } catch (const std::exception &e) { |
| 160 | + tr.out = std::string("JSON parsing error: ") + e.what(); |
| 161 | + tr.exit_code = 1; |
| 162 | + } |
| 163 | + |
| 164 | + // 5. Generate Report |
| 165 | + write_controlled_edit_report(); |
| 166 | + return tr; |
| 167 | +} |
| 168 | +``` |
| 169 | + |
| 170 | +### 3.3 Engine Loop Termination (`src/services/execution_engine.cpp`) |
| 171 | +We ensure that once `has_edited` is set to `true`, the loop terminates instantly without selecting subsequent tools. |
| 172 | + |
| 173 | +- **In `select_next_tool` (deterministic / LLM branches):** |
| 174 | + If `has_edited` is set, return an empty `ToolCall` to immediately break the execution loop. |
| 175 | + ```cpp |
| 176 | + // Add at the beginning of select_next_tool and select_next_tool_llm: |
| 177 | + if (evidence.has_fact_containing("edit_file")) { |
| 178 | + return {}; // Halts the execution engine immediately |
| 179 | + } |
| 180 | + ``` |
| 181 | +
|
| 182 | +- **In `check_completion`:** |
| 183 | + Once an edit is performed, the goal is checked as complete (so that the engine stops and records the outcome). |
| 184 | + ```cpp |
| 185 | + // Add to check_completion: |
| 186 | + if (type == CodeChange && evidence.has_fact_containing("edit_file")) { |
| 187 | + return true; |
| 188 | + } |
| 189 | + ``` |
| 190 | + |
| 191 | +--- |
| 192 | + |
| 193 | +## 4. Telemetry Report Schema |
| 194 | + |
| 195 | +Upon completion of the edit phase, the router writes a telemetry report to `docs/telemetry/controlled_edit_report.md`. This report logs the details of the modification and build outcome. |
| 196 | + |
| 197 | +### Report Template |
| 198 | +```markdown |
| 199 | +# Controlled Edit Mode v1: Run Report |
| 200 | + |
| 201 | +- **Timestamp:** [ISO-8601 Timestamp] |
| 202 | +- **Target File:** `[filepath]` |
| 203 | +- **Checkpoint ID:** `[cp_id]` |
| 204 | +- **Edit Status:** [SUCCESS / FAILURE] |
| 205 | +- **Compilation Status:** [PASSED / FAILED] |
| 206 | +- **Automatic Rollback Triggered:** [YES / NO] |
| 207 | + |
| 208 | +## Modification Diff Detail |
| 209 | +```diff |
| 210 | +-[old_text] |
| 211 | ++[new_text] |
| 212 | +``` |
| 213 | + |
| 214 | +## Compilation Diagnostic Output |
| 215 | +```text |
| 216 | +[Captured compile output] |
| 217 | +``` |
| 218 | +``` |
| 219 | + |
| 220 | +--- |
| 221 | + |
| 222 | +## 5. Summary of Safety Benefits |
| 223 | + |
| 224 | +- **Minimal Abstraction footprint:** The design requires no modifications to planners, goal-routing schemas, or search-ranking layers. It operates strictly as a sequential utility inside the `CommandRouter` tool runner. |
| 225 | +- **Atomic Operations:** Workspace safety is guaranteed. Even if the agent fails to compile, the pre-edit checkpoint restores the files, preventing any broken code from being checked in or left on disk. |
| 226 | +- **Runaway Prevention:** Zero repair-loop logic means the agent will never enter an infinite compile-edit-fail cycle. |
0 commit comments