Skip to content

Commit 1ef01ad

Browse files
committed
docs: add controlled edit mode proposals
1 parent db09abc commit 1ef01ad

2 files changed

Lines changed: 346 additions & 0 deletions

File tree

Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
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.
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
# [PROPOSAL: DESIGN ONLY - NOT YET IMPLEMENTED]
2+
3+
# Controlled Edit Mode: Feasibility & Verification Report
4+
5+
**Date:** 2026-06-26
6+
**Subject:** Executable Proof of Workspace & Build Lifecycle Safety
7+
8+
---
9+
10+
## 1. File Lifecycle Verification
11+
12+
We verified the agent's core File IO and editing services by piping sequential commands directly into the `cursor-agent` binary.
13+
14+
### Executed Command Sequence
15+
```bash
16+
echo "write:test_lifecycle.txt Hello World\nread:test_lifecycle.txt\nreplace:test_lifecycle.txt:World:Antigravity\nread:test_lifecycle.txt\nexit" | ./build/bin/cursor-agent
17+
```
18+
19+
### Captured Console Evidence
20+
```text
21+
local · llama3.2:3b
22+
23+
[offline · llama3.2:3b | llama3.2:3b]
24+
> File 'test_lifecycle.txt' written successfully (11 bytes)
25+
> Hello World
26+
> Successfully replaced 1 occurrence(s)
27+
> Hello Antigravity
28+
> Goodbye
29+
Agent run completed
30+
```
31+
32+
### Verification
33+
- **Create & Write:** Checked that `write:test_lifecycle.txt` successfully wrote the file to disk.
34+
- **Read:** Checked that `read:test_lifecycle.txt` returned the exact contents `Hello World`.
35+
- **Text Replacement:** Checked that `replace:test_lifecycle.txt:World:Antigravity` matched and replaced the target token.
36+
- **Verify Edit:** Read it back to confirm it now contains `Hello Antigravity`.
37+
- **Delete:** The file was safely cleaned up using the shell (`rm test_lifecycle.txt`).
38+
39+
---
40+
41+
## 2. Build Lifecycle & Recovery Verification
42+
43+
We simulated a broken edit cycle to verify the agent's workspace checkpointing, compile failure detection, and automatic restore capabilities.
44+
45+
### 2.1 Checkpoint Creation (Baseline)
46+
Before introducing any errors, we created a baseline workspace checkpoint `test_cp` via the interactive CLI:
47+
```bash
48+
echo "/checkpoint create test_cp \"initial clean state\"\nexit" | ./build/bin/cursor-agent
49+
```
50+
**Output:**
51+
```text
52+
Creating checkpoint 'test_cp'...
53+
Checkpoint created with ID: 5d57002d
54+
Available checkpoints:
55+
5d57002d - test_cp (217 files, 5296 KB)
56+
```
57+
58+
### 2.2 Introducing Compile Failure
59+
We appended a syntax error to the end of `src/main.cpp`:
60+
```bash
61+
echo "invalid_syntax_error_here;" >> src/main.cpp
62+
```
63+
64+
We then ran the build to verify compiler failure detection:
65+
```bash
66+
cmake --build build --config Release
67+
```
68+
**Output (Exit Code: 2):**
69+
```text
70+
[ 28%] Building CXX object CMakeFiles/cursor-agent.dir/src/main.cpp.o
71+
/Users/bniladridas/Desktop/cursor/src/main.cpp:655:1: error: a type specifier is required for all declarations
72+
655 | invalid_syntax_error_here;
73+
| ^
74+
1 error generated.
75+
make[2]: *** [CMakeFiles/cursor-agent.dir/src/main.cpp.o] Error 1
76+
```
77+
78+
### 2.3 Restoring Workspace
79+
We restored the workspace back to checkpoint `5d57002d` using the C++ restore handler:
80+
```bash
81+
echo "/checkpoint restore 5d57002d\nexit" | ./build/bin/cursor-agent
82+
```
83+
**Output:**
84+
```text
85+
Restoring from checkpoint 5d57002d...
86+
Note: A backup will be created automatically before restore.
87+
Successfully restored from checkpoint 5d57002d
88+
```
89+
90+
### 2.4 Verify Clean Build
91+
We verified the file was completely reverted:
92+
```bash
93+
git diff src/main.cpp
94+
# Output: (empty, 0 differences)
95+
```
96+
97+
We then compiled the project again to ensure it successfully builds:
98+
```bash
99+
cmake --build build --config Release
100+
# Output: (completed successfully, 100% build target built)
101+
```
102+
103+
---
104+
105+
## 3. Loop Safety & Runaway Mitigation
106+
107+
We audited the C++ orchestrator loop to document early-termination and runaway mitigation conditions:
108+
109+
1. **Unconditional Iteration Cap:**
110+
- **Condition:** `iteration_count >= MAX_ITERATIONS` in `execution_engine.cpp:1027`.
111+
- **Threshold:** Capped hard at **20 iterations**. The agent loop can never exceed this limit regardless of LLM prompts.
112+
2. **Confidence-Based Termination:**
113+
- **Condition:** `ConfidenceService::should_stop(combined_confidence, 0.2)` in `execution_engine.cpp:1190`.
114+
- **Behavior:** If the compiler returns multiple failures, the build confidence scores drop (`cr.score = 0.25`). The average confidence score decreases with each attempt. If it falls below `0.2`, the engine halts immediately and flags `InsufficientEvidence`.
115+
3. **Execution Safety / Substring Filtering:**
116+
- **Condition:** `CommandService::is_dangerous_command` checks all inputs.
117+
- **Behavior:** Commands containing blocked tokens (e.g. `rm`, `sudo`, `dd`) are automatically rejected prior to invocation.
118+
119+
### Recommended Safety Guardrail for Controlled Edit Mode
120+
To make Controlled Edit Mode even safer, the `ToolRunner` can automatically restore the workspace to the last clean checkpoint *any time* the build fails, ensuring the workspace is never left in a broken state if the agent exits.

0 commit comments

Comments
 (0)