zuvo:content-fix — Apply Content Audit Fixes
Read content-audit JSON findings. Classify by safety tier. Apply mechanical fixes. Verify build. Report.
Scope: Post-audit fix application for content file quality findings.
Out of scope: SEO fixes (zuvo:seo-fix), content writing, spelling corrections, link target changes.
Mandatory File Loading
Read these files before any work begins:
Dispatch follows ../../shared/includes/execution-policy.md through env-compat. Reuse existing
authorization within that policy; session restrictions take precedence. Run each required gate
and report its actual independence or an unmet requirement.
../../shared/includes/env-compat.md-- Agent dispatch and environment adaptation../../shared/includes/content-fix-registry.md-- Canonical fix_type, safety, contracts../../shared/includes/fix-output-schema.md-- JSON report contract../../shared/includes/content-check-registry.md-- Check slugs reference../../shared/includes/backlog-protocol.md-- Backlog fingerprint dedup../../shared/includes/verification-protocol.md-- Build verification rules../../shared/includes/run-logger.md-- Run logging contract../../shared/includes/retrospective.md-- Retrospective protocol../../shared/includes/knowledge-prime.md-- Project knowledge priming../../shared/includes/knowledge-curate.md-- Learning extraction after work../../shared/includes/no-pause-protocol.md-- HARD rule: no mid-batch pauses
Print the checklist:
CORE FILES LOADED:
1. env-compat.md -- [READ | MISSING -> STOP]
2. content-fix-registry.md -- [READ | MISSING -> STOP]
3. fix-output-schema.md -- [READ | MISSING -> STOP]
4. content-check-registry.md -- [READ | MISSING -> STOP]
5. backlog-protocol.md -- [READ | MISSING -> STOP]
6. verification-protocol.md -- [READ | MISSING -> STOP]
7. run-logger.md -- [READ | MISSING -> STOP]
8. retrospective.md -- [READ | MISSING -> STOP]
9. ../../shared/includes/knowledge-prime.md -- READ/MISSING
10. ../../shared/includes/knowledge-curate.md -- READ/MISSING
11. ../../shared/includes/no-pause-protocol.md -- READ/MISSING (HARD: no mid-batch pauses)
If any file is missing, STOP.
Safety Gates (NON-NEGOTIABLE)
GATE 1 — Write Scope
Allowed write targets:
- Content files from the audit manifest (files listed in audit JSON findings)
zuvo/audits/for the fix report (.mdand.json)memory/backlog.mdfor backlog updates
FORBIDDEN:
- Installing packages or dependencies
- Writing to files not referenced by audit findings
- Modifying config files, build scripts, or non-content files
- Deleting files
GATE 2 — Dirty File Check
Before modifying any file:
git status --porcelain -- <file>— check for BOTH staged and unstaged changes- If the file has ANY uncommitted changes (staged or unstaged): mark finding
as
NEEDS_REVIEW - Do not modify dirty files
GATE 3 — Stale Audit Protection
If audit JSON timestamp is >24h old:
- Default mode (SAFE only): proceed with warning
--automode: require user confirmation before mutating--dry-runmode: proceed with warning
GATE 4 — PROVISIONAL Audit Handling
If audit JSON result is "PROVISIONAL" (has INSUFFICIENT DATA blocking
gates):
- Default mode (SAFE only): proceed normally — SAFE fixes are safe regardless of incomplete gates
--automode: restrict to SAFE fixes only (do not apply MODERATE). Warn: "Audit is PROVISIONAL — restricting to SAFE fixes. Re-run content-audit with --live-url for full coverage."
Arguments
| Argument | Behavior |
|---|---|
| (default) | Apply SAFE fixes only (encoding-strip, markdown-fix, typography-fix) |
--auto |
Apply SAFE + MODERATE fixes (encoding-mojibake, artifact-remove) |
--dry-run |
Show what would be fixed, change nothing |
--finding CC1-nbsp-present,CC2-broken-italic |
Fix specific findings by stable ID |
--fix-type encoding-strip,markdown-fix |
Fix specific fix_type categories |
[json-path] |
Use specific JSON file instead of latest |
Knowledge Prime
Run the knowledge prime protocol from knowledge-prime.md:
WORK_TYPE = "implementation"
WORK_KEYWORDS = <keywords from user request>
WORK_FILES = <files being touched>
Phase 0: Load Findings
0.1 Locate audit JSON
- If
[json-path]provided: use that file - Otherwise: glob
zuvo/audits/content-audit-*.json, select most recent by timestamp - If no JSON found: "No audit JSON found. Run
zuvo:content-auditfirst." STOP.
0.2 Validate schema
Check version field. Supported: "1.0", "1.1".
Required fields:
version, skill, timestamp, result, score.overall, findings[]
Required per finding: id, dimension, check, status, fix_type, fix_params
0.3 Check freshness
Read timestamp. Apply GATE 3 if >24h old.
0.4 Print summary
AUDIT: content-audit [date] ([age]) | Grade: [A-D] ([score]%) | [N] findings
SAFE: [N] findings (auto-fixable)
MODERATE: [N] findings (fixable with --auto)
MANUAL: [N] findings (advisory only)
Phase 1: Detect Framework & Classify
1.1 Stack detection
Same inline detection as content-audit Phase 0.1.
1.2 Classify findings
For each finding with a non-null fix_type:
| fix_type | Safety | Default mode | --auto mode |
|---|---|---|---|
encoding-strip |
SAFE | Apply | Apply |
markdown-fix |
SAFE | Apply | Apply |
typography-fix |
SAFE | Apply | Apply |
encoding-mojibake |
MODERATE | Skip | Apply |
artifact-remove |
MODERATE | Skip | Apply |
Findings with fix_type: null are MANUAL — never auto-applied.
Phase 2: Apply Fixes
2.0 Pre-flight per file
Before modifying any file:
- Save a snapshot of the original content (in memory, for rollback)
- Check GATE 2 (dirty file check)
- If multiple findings target the same file: batch all fixes into one edit
2.1 SAFE fixes (auto-applied)
For each SAFE finding:
encoding-strip:
- Replace NBSP (U+00A0) with regular space (U+0020)
- Remove zero-width characters (U+200B, U+200C, U+200D, U+FEFF)
- Remove BOM marker from file start
- Remove soft hyphens (U+00AD)
- Remove replacement characters (U+FFFD) — flag for manual review
- Scope: body content AND frontmatter string fields
- Skip content inside fenced code blocks
markdown-fix:
- Close unclosed
*or_at paragraph end (append matching marker) - Fix split italic:
* *text*→*text* - Remove orphan
\lines (stack-aware: only for Hugo/Goldmark)
typography-fix:
- Collapse 2+ spaces to 1 (outside code blocks, tables, indentation)
- Fix
..→.(preserve...ellipsis) - Fix
,,→,
2.2 MODERATE fixes (with --auto only)
encoding-mojibake:
- Replace garbled sequences using the mojibake signature table from
content-fix-registry.md - Skip matches inside fenced code blocks (may be intentional examples)
- Verify each replacement produces valid UTF-8
artifact-remove:
- Remove WordPress shortcodes: extract inner content where possible
- Remove PHP tags:
<?php ... ?>blocks entirely - Remove
<font>tags: keep inner text - Remove excessive inline styles (>50 chars)
- Joomla paths (
/images/stories/,index.php?option=com_): do NOT auto-replace — target path is unknown. Mark asNEEDS_REVIEWwith evidence and suggested manual action. These are always flagged for human review even in--automode.
2.3 MANUAL findings
Never auto-applied. Appear in report as advisory with suggested changes:
- Spelling corrections
- Content duplication resolution
- Frontmatter rewrites
- Link target changes
Phase 3: Build Verification
Detect project build command:
package.jsonscripts:build,astro build,next build- Hugo:
hugobinary - If no build command: skip, note in report
Build verification follows verification-protocol.md:
build_result: PASSrequires exit code 0build_result: FAILfor any non-zero exit code
Build failure → rollback per-file snapshots from Phase 2.0.
Phase 4: Adversarial Review (MANDATORY — do NOT skip)
# Scoped review patch on stdout — the git index is NEVER touched (no staging).
# PATH args = the content files this run fixed (Phase 2.0 snapshot list).
# Quote each SEPARATELY — never one space-joined string or a bare $FILES: zsh does
# not word-split an unquoted expansion, so the helper gets the whole list as ONE
# path, matches nothing and exits 2. Use "${FILES[@]}" for an array.
# With NO PATH args the helper reviews the WHOLE dirty tree, untracked files
# included, and that content is sent to the external providers — always scope it.
# `|| _prc=$?` (never `; _prc=$?`): under `set -e` the plain form aborts the shell
# at the assignment, so exit 3 and the BLOCKED branch would never be reached.
# The BLOCKED branch ends in `false`, so the block's own exit status is non-zero:
# printing alone lets a `set -e` / `if ! …` caller sail past a review that never
# ran. `false`, not `exit`, so an inlining caller's shell is not killed.
if [ -x "$HOME/.zuvo/build-review-patch" ]; then
_prc=0; _patch=$("$HOME/.zuvo/build-review-patch" "<fixed-file-1>" "<fixed-file-2>") || _prc=$?
if [ "$_prc" -eq 3 ]; then echo "adversarial review: skipped (no changes)"
elif [ "$_prc" -ne 0 ]; then echo "BLOCKED: build-review-patch failed (rc=$_prc). Adversarial review did NOT run; do NOT proceed to commit and do NOT report this skill complete" >&2; false
else printf '%s\n' "$_patch" | ~/.zuvo/adversarial-review --mode code; fi
else
~/.zuvo/adversarial-review --mode code --files "<changed files>"
fi
If adversarial-review is not in PATH: ~/.zuvo/adversarial-review (stable; the versioned cache path breaks after any release)
Wait for complete output. Fix CRITICAL immediately. WARNING (localized) → fix.
Phase 5: Report
5.1 Report template
CONTENT FIX REPORT -- [project name]
----
Findings: [N] total | [N] fixed | [N] needs review | [N] manual
Grade: [before] -> [estimated after] (confirmed fixes only)
Build: [PASS | FAIL (rolled back N) | NOT VERIFIED]
----
FIXED (SAFE — auto-applied):
F1: Stripped 42 NBSP characters content/post-1.md [VERIFIED]
F2: Closed unclosed italic content/post-3.md:18 [VERIFIED]
FIXED (MODERATE — applied with --auto):
F3: Fixed mojibake: Ä… → ą (12 occurrences) content/post-5.md [VERIFIED]
NEEDS REVIEW:
F4: encoding-strip on dirty file content/draft.md
Reason: File has uncommitted changes
MANUAL (advisory):
F5: Spelling correction needed content/about.md:7
Suggestion: "forumują" → "formują"
Run: <ISO-8601-Z> content-fix <project> - - <VERDICT> <N-fixes> fix <NOTES> <BRANCH> <SHA7> <INCLUDES> <TIER>
NEXT STEPS:
1. Review NEEDS_REVIEW items
2. Apply MANUAL fixes manually
3. Re-audit: zuvo:content-audit
Retrospective (REQUIRED)
Follow the retrospective protocol from retrospective.md.
Gate check → structured questions → TSV emit → markdown append.
If gate check skips: print "RETRO: skipped (trivial session)" and proceed.
Append via wrapper (REQUIRED). Never >> directly to ~/.zuvo/runs.log — the wrapper is the gate that verifies a retro entry exists for this run. Order: retro bash executed → wrapper invoked → completion claimed.
printf '%b\n' "$RUN_LINE" | ~/.zuvo/append-runlog
Expected stdout: OK: appended to runs.log (retro verified for <skill> on <project>). If exit 2 with RETRO_REQUIRED — go execute the retro bash from retrospective.md first; never bypass with ZUVO_SKIP_RETRO_GATE=1. After the wrapper succeeds, print a Logs: evidence line (tail -1 ~/.zuvo/retros.log, grep -c "^<!-- RETRO -->" ~/.zuvo/retros.md, tail -1 ~/.zuvo/runs.log) before claiming completion. Printing the markdown retro section without executing the bash leaves all three log files empty.
5.2 Save JSON report
Write to zuvo/audits/content-fix-YYYY-MM-DD.json conforming to
fix-output-schema.md v1.1. Auto-increment -2.json for same-day runs.
Knowledge Curation
After work is complete, run the knowledge curation protocol from knowledge-curate.md:
WORK_TYPE = "implementation"
CALLER = "zuvo:content-fix"
REFERENCE = <git SHA or relevant identifier>
5.3 Update backlog
Per shared/includes/backlog-protocol.md:
| Finding status | Backlog action |
|---|---|
| FIXED | Remove row by fingerprint |
| NEEDS_REVIEW | If exists: increment Seen. If new: add as OPEN |
| MANUAL | Add as OPEN with category content-manual |
Fingerprint format: {file}|{dimension}|{check}