## Implementation Plan: Structural Markdown Preservation in AI Correction/Modification ### Overview The AI correction (`correction.py`) and modification (`ai_modifier.py`) services currently send raw Markdown content to the LLM, which can corrupt code blocks, tables, headings, and other structures. The previous fix (#84) only added stronger prompt hints—insufficient. This plan implements structural enforcement by extracting all Markdown structures before the AI call, replacing them with placeholders, and reinserting them after. A post-processing validation step ensures no structures were altered. ### Detailed Changes **1. Create `devplacepy/services/markdown_protector.py`** - `extract_markdown_structures(text: str) -> Tuple[str, List[Dict]]` - Scans text for: fenced code blocks, inline code, tables, headings, blockquotes, horizontal rules, images, links, ordered/unordered/task lists, emoji shortcodes, mentions. - Replaces each with a unique placeholder (e.g., `{{MARKDOWN_STRUCTURE_0}}`). - Returns cleaned text and a ordered list of dicts: `{'type': 'fenced_code', 'original': '```python\n...```'}`. - `restore_markdown_structures(text: str, structures: List[Dict]) -> str` - Replaces placeholders in order with the original structures. - `validate_markdown_preservation(original: str, corrected: str, strict: bool = True) -> bool` - Compares structural elements by type and count (fenced blocks, tables, headings, etc.). - If any count differs, returns `False`. **2. Modify `devplacepy/services/correction.py` – `_run_correction` function (lines ~187-217)** - Before AI call: `cleaned, structures = extract_markdown_structures(text)` - Send `cleaned` to AI (system prompt remains as-is or slightly adjusted). - After AI response: `restored = restore_markdown_structures(ai_output, structures)` - Validate: if `not validate_markdown_preservation(text, restored)`, return original `text`. - Use `restored` as final output. **3. Modify `devplacepy/services/ai_modifier.py` – `_run_modification` function (lines ~76-110)** - Same extraction/restoration/validation pattern. **4. Add integration tests in `tests/unit/services/test_markdown_protector.py`** - Test extraction/restoration round-trip for all structure types. - Test full pipeline with a mock AI that returns corrupted output, verify that original structures are preserved. **5. Update existing tests (`tests/unit/services/correction.py`, `ai_modifier.py`)** - Remove the useless prompt-string tests. - Replace with tests that call the real `_run_correction` with a mocked AI returning a broken code block, asserting the final output matches input. **6. Fix environment issue for test command** - Ensure commands run inside a virtual environment: ```bash python3 -m venv .venv source .venv/bin/activate pip install -e '.[dev]' -q make test-unit ``` - Lint command similarly: `ruff check .` within the same venv. ### Definition of Done - [ ] `devplacepy/services/markdown_protector.py` exists with `extract_markdown_structures`, `restore_markdown_structures`, and `validate_markdown_preservation` functions. - [ ] `correction.py:_run_correction` extracts structures before AI call and reinserts them after, with fallback to original if validation fails. - [ ] `ai_modifier.py:_run_modification` applies the same structural extraction/restoration/validation. - [ ] New integration tests cover: extraction/restoration round-trips (all structure types), full pipeline with mock AI producing corrupt output. - [ ] Existing unit tests in `tests/unit/services/correction.py` and `ai_modifier.py` are replaced with meaningful pipeline tests. - [ ] Test command passes: `python3 -m venv .venv && source .venv/bin/activate && pip install -e '.[dev]' -q && make test-unit` exits with 0. - [ ] Lint command passes: `ruff check .` exits with 0 (run in same virtual environment). - [ ] Branch rebased onto the latest base branch with no merge conflicts before final submission.