| name | audit-correct |
| description | Phase 4: Apply corrections to DOCX |
| user-invocable | false |
| disable-model-invocation | true |
Phase 4: Correct
Apply approved corrections to the DOCX file via lxml XML manipulation.
What This Phase Does
- Back up the original DOCX
- Apply corrections in order:
a. Cross-reference resolution (fill
[_] placeholders)
b. Small caps for journal/periodical names (run-splitting)
c. Small caps for book titles (italic -> small caps)
d. Signal italic fixes
e. Id. chain corrections
f. Terminal period additions
g. Other typeface fixes
- Write corrected DOCX
Run-Splitting Approach
When formatting a substring within a larger run:
- Find the run containing the target text
- Split into 3 runs: prefix (original) + target (new format) + suffix (original)
- Clone
rPr from original run via deepcopy
- Add new formatting only to target run
- Set
xml:space="preserve" on all <w:t> elements
Critical Gotchas
NBSP Variants
All search operations MUST handle \xa0 (non-breaking space):
def find_in_run(text, target):
if target in text:
return text.find(target)
nbsp_target = target.replace(' ', '\xa0')
if nbsp_target in text:
return text.find(nbsp_target)
import re
pattern = re.escape(target).replace(r'\ ', r'[\s\xa0]')
m = re.search(pattern, text)
return m.start() if m else -1
footnoteRef Space Run Bug
The run after <w:footnoteRef/> often contains the full footnote text, not just a space. When replacing entire footnote content, keep ONLY the footnoteRef run and add an explicit space run.
Cross-Run Text
supra note 10 spans italic + roman runs. Target the specific run containing the text you need to change (e.g., just "note 10" in the roman run).
Multi-Split Footnotes
Some footnotes need multiple formatting changes in the same run (e.g., FN91: italic the letter title AND small-caps the annual report title, both in one roman run). Process splits sequentially left-to-right:
- First split creates 3 new runs from the original
- Second split finds target text in one of the NEW runs and splits again
- The
find_run() search re-scans the footnote element each time, so it finds the new runs
Example: Jamie Dimon, Chairman & CEO Letter to Shareholders, in JPMorgan Chase & Co., 2023 Annual Report 1 (2024)
- Split 1: "Chairman & CEO Letter to Shareholders" → italic (creates 3 runs)
- Split 2: "JPMorgan Chase & Co., 2023 Annual Report" → small caps (splits the third run from Split 1)
Italic Spillover Cleanup
After all substantive fixes, clean up trailing/leading spaces in italic runs. Word displays these fine, but they cause Gemini annotation issues on re-audit:
if text.endswith(' ') and is_italic:
t.text = text.rstrip(' ')
## Iron Law: Verify Every Fix
After each category of corrections, verify the fix was applied by reading back the modified XML. Silent failures from NBSP, run boundaries, or wrong-run targeting are common.
Skipping read-back verification is NOT HELPFUL — silent failures from NBSP or run boundaries mean the user's document still has errors.
Correction Facts
- NBSP characters and run boundaries cause silent failures and wrong-run targeting — code that "applied" is not code that worked. A fix reported without XML read-back is an unverified claim presented as a correction.
- Verification batched to the end can't attribute a failure to the fix that caused it; verify after each category.
- Every footnote has a unique run structure — a pattern that worked on the last footnote proves nothing about this one.
- One XML corruption destroys the whole document; skipping the backup gambles the user's manuscript to save seconds.
Gate: Exit Correct
Before proceeding to Verify phase:
Next Phase
Read ${CLAUDE_SKILL_DIR}/../../../../skills/bluebook-audit/skills/audit-verify/SKILL.md and follow its instructions.