Private
Public Access
0
0
Files
manual_slop/conductor/edit_workflow.md
T
ed e80d2952bc docs(harness+conductor): cover 5 missing styleguides in harvest; cosmetic cleanups
directive_hotswap_harness_20260627/spec.md: added the 5 missing
conductor/code_styleguides/*.md files to the harvest source list
(config_state_owner, workspace_paths, test_sandbox, chroma_cache,
code_path_audit) — the original list named 9 of 14. Added note that
the harvester should verify each contains a harvestable directive
before creating v1.md. Also verified tier2-autonomous.md path
exists (17,940 bytes) for plan Step 2.7.

tech-stack.md: removed duplicate src/paths.py entry (the full
description at line 37 already covers it; the line-73 stub was
redundant).

edit_workflow.md: Key Files section now points to src/project_files.py
for FileItem (moved out of src/models.py per the module taxonomy
refactor) and notes the line ~2748 ref may drift.
2026-07-02 19:05:43 -04:00

210 lines
8.6 KiB
Markdown

# Manual Slop Edit Tool Workflow
## The Problem
The `manual-slop_edit_file` tool requires **exact string matches** (character-for-character). Whitespace differences cause failures. The Python file uses **1-space indentation**.
## The Rules
### 1. ALWAYS Use Small, Incremental Edits
**WRONG:** Replace large blocks (50+ lines)
**RIGHT:** Replace 3-10 lines at a time, verify, repeat
### 2. Verify Before Editing
Before ANY edit to a function you haven't touched recently:
```
1. Run: py_check_syntax on src/<file>.py
2. Get current state with get_file_slice (the exact lines you're about to touch)
3. Read the contract: does this function/field/method's signature, yield shape, or return type have callers I need to update?
```
DO NOT use `git checkout` or `git restore` to "revert" your way to a clean state. That destroys in-progress work. If a previous edit left the file in a broken state, ask the user.
### 3. Reading Before Editing (CRITICAL)
- Use `get_file_slice` to get the EXACT text including all whitespace and EOL
- Copy text directly from the tool output - do NOT reformat
- If using `get_definition`, verify the text matches before editing
- For `set_file_slice`: confirm the exact `start_line` and `end_line` (1-indexed, inclusive) by reading the file first. Off-by-one is a common silent failure.
### 4. The Edit Tool Parameters (snake_case)
```python
{
"path": "src/gui_2.py", # Required: file path
"old_string": "exact text", # Required: must match EXACTLY
"new_string": "replacement", # Required: replacement text
"replace_all": false # Optional: replace all occurrences
}
```
### 5. 1-Space Indentation in Python
- Class methods: ` def` (0 spaces, then 1)
- Method body: ` ` (2 spaces total)
- Nested blocks: ` ` (3 spaces total)
- NO 4-space indentation anywhere in this file
### 6. The Decorator-Orphan Pitfall (Added 2026-06-07)
When inserting new methods **before an existing `@property` def**:
```python
@property
def perf_profiling_enabled(self) -> bool:
...
```
If you anchor on `def perf_profiling_enabled` and insert before it, the `@property` decorator on the line above is left orphaned on the line right before YOUR new method. Now `@property` decorates your method (which is no longer a property), and the original setter `@perf_profiling_enabled.setter` blows up at import with `'function' object has no attribute 'setter'`.
**Fix:** Anchor on a non-decorated landmark, or include the decorator in the replacement:
- `old_string` = ` self._init_actions()\n\n @property\n def perf_profiling_enabled`
- `new_string` = ` self._init_actions()\n\n def your_new(...)\n ...\n\n @property\n def perf_profiling_enabled`
This keeps the `@property` attached to its original method.
### 7. ast.parse() Is Not Enough (Added 2026-06-07)
`py_check_syntax` only confirms `ast.parse()` succeeds. Semantic errors (wrong decorator targets, wrong base class, wrong attribute, missing `self`) are NOT caught. After any multi-line edit, ALWAYS:
1. Import the module: `python -c "from src.app_controller import AppController"`
2. Instantiate the class
3. Call the new method in the way it's expected to be called (`ctrl.foo_ts` for a property, `ctrl.foo_ts()` for a method)
### 8. `set_file_slice` IS Valid for Multi-Line Content (Revised 2026-06-09)
The previous rule ("Do not use set_file_slice for multi-line content") was wrong. `set_file_slice` does literal line replacement by design and is the right tool for 3-10 line surgical edits.
**When to use which tool:**
- **`set_file_slice`** for surgical 3-10 line edits where you know the exact line range. Verify the line range with `get_file_slice` first. The `start_line` and `end_line` are 1-indexed and inclusive. The new content must reproduce the line count exactly (or be a precise replacement of the same N lines).
- **`manual-slop_edit_file`** for exact-string replacement when you don't know the line range, or when the edit has a unique anchor string.
- **`py_update_definition`** for whole-function replacement (AST-detected).
- **`py_add_def`** for adding a new method/class to a class.
- **`py_remove_def`** for removing a method/class.
**The contract-change check (mandatory for any edit that changes a public interface):**
Before any edit, search the codebase for callers of the function/symbol/yield shape you're changing. If your edit changes:
- A function signature (add/remove/rename a parameter)
- A return type or yield shape (e.g. `yield process, gui_script``yield process, gui_script, workspace_path`)
- A class hierarchy (add/remove a base class, change a method's name)
- A module-level function name (rename)
- A public attribute name
...you MUST update ALL callers in the same atomic commit. Use `py_find_usages` to locate them. If you change a contract and don't update callers, you have broken the codebase.
**The whitespace-and-EOL rule (mandatory for set_file_slice):**
The `new_content` must preserve:
- The file's line ending convention (CRLF on Windows, LF on Linux — pick from the surrounding file, not from your text editor's default)
- The indentation of the surrounding code (1 space per level, per `conductor/code_styleguides/python.md` §1)
- The number of lines replaced (`start_line`..`end_line` must equal `len(new_content.splitlines())`)
If you mismatch any of these, the file will fail to parse. Run `py_check_syntax` and a real `import` after every `set_file_slice`.
### 9. No Diagnostic Noise in Production Code (Added 2026-06-09)
`sys.stderr.write(f"[XYZ_DIAG] ...")` lines added to `src/*.py` for debugging are technical debt the moment they ship. If you need to instrument for a one-time investigation:
- Write the diag output to a log file: `tests/artifacts/<test_name>.diag.log`
- Or to a standalone diagnostic script under `/tmp/diag_<name>.py` that imports the production module and exercises it
- Or read the production source with `get_file_slice` and reason about it directly
Do NOT add diag lines to `src/*.py` "temporarily." If you must add them for a single test run, they are part of the same atomic commit as the fix — they do not live uncommitted in the working tree. If you "revert everything," that means the diag lines are also reverted.
## Step-by-Step Workflow for gui_2.py
### Check current state:
```powershell
py_check_syntax path=src/gui_2.py
get_file_slice path=src/gui_2.py start_line=X end_line=Y
```
### For each edit:
1. Make the smallest possible change (3-10 lines)
2. Run `py_check_syntax` to verify
3. If syntax error, immediately report to the user to address.
4. Only proceed if syntax is OK
### If edit fails with "old_string not found":
- The text you're trying to replace doesn't EXACTLY match
- Use `get_file_slice` to get the exact text
- Copy it character-for-character including whitespace and EOL
- Try again with exact match
### If `set_file_slice` produces wrong indentation:
- You wrote the wrong indent in `new_content`. The tool did what you asked.
- Re-read the file with `get_file_slice` to confirm the surrounding indent
- Rewrite the `new_content` with the correct indent
- Do NOT use `git checkout` to "revert"
## Alternative: Update Definition Approach
For large function rewrites, use `py_update_definition`:
```md
name: function_name
path: src/gui_2.py
new_content: complete new function source
```
This replaces the entire function at once using AST detection.
## Context Composition Requirements
### Current Broken State
Files & Media works. Context Composition needs:
1. Add state tracking at start of function:
```python
if not hasattr(self, 'ctx_files_open'):
self.ctx_files_open = True
if not hasattr(self, 'ctx_shots_open'):
self.ctx_shots_open = True
```
2. Files section with collapsing header and child window:
```python
if imgui.collapsing_header("Files", self.ctx_files_open):
imgui.begin_child("ctx_files_child", imgui.ImVec2(-1, 200), True)
# table code here
imgui.end_child()
```
3. Screenshots section with collapsing header and child window:
```python
if imgui.collapsing_header("Screenshots", self.ctx_shots_open):
imgui.begin_child("ctx_shots_child", imgui.ImVec2(-1, 100), True)
# screenshot list here
imgui.end_child()
```
4. Fixed presets bar with push_item_width(150) on the combo
5. Remove the batch action bar entirely (Full/Agg/Sig/Def/None/Sel All/Del buttons)
## Key Files
- `src/gui_2.py` - Main GUI (1-space indentation, CRLF)
- `src/project_files.py` - `FileItem` dataclass (moved out of `src/models.py` per `module_taxonomy_refactor_20260627`); `src/models.py` is now a ~1.5KB re-export shim
- Context Composition function: line ~2748 (verify with `py_get_code_outline` before editing — line refs drift)
## Test Command
```powershell
uv run sloppy.py
```