Canonical Draft Assembly Tool
Three CLI tools each had their own way of stitching a memo back together, so citation numbers collided and the table of contents went stale. Now there is one assembler, and everything else delegates to it.
Changelog - 2025-11-28 (#3)
Canonical Draft Assembly Tool
Type: Refactor / New Feature Priority: HIGH
Summary
Created cli/assemble_draft.py as the single source of truth for assembling 4-final-draft.md from section files. All CLI tools that modify sections now delegate to this tool, ensuring consistent formatting:
Citation renumbering (no collisions across sections)
Citation consolidation (all references at document end)
Table of Contents generation (accurate, with anchor links)
Problem
Multiple CLI tools had their own reassemble_final_draft() functions with inconsistent behavior:
cli/improve_section.py- Simple concatenation, no citation handling, no TOCcli/improve_team_section.py- Simple concatenation, no citation handling, no TOCsrc/agents/key_info_rewrite.py- Had citation handling but was duplicating logic
This caused formatting issues when using CLI tools:
Citations appeared at section level with number collisions
TOC was missing or outdated after section modifications
Inconsistent output quality between main workflow and CLI tools
Solution
New Tool: cli/assemble_draft.py
Canonical assembly function that handles all formatting invariants:
# Standalone usage
python -m cli.assemble_draft "Sava"
python -m cli.assemble_draft "Sava" --version v0.0.2
python -m cli.assemble_draft output/Sava-v0.0.2
# Programmatic usage
from cli.assemble_draft import assemble_final_draft
final_path = assemble_final_draft(artifact_dir, console)Assembly steps:
Load
header.md(company trademark) if existsLoad all sections from
2-sections/in orderRenumber citations globally ([^1], [^2]... sequentially)
Consolidate all citation references into ONE block at document end
Remove any existing TOC to prevent duplication
Generate fresh Table of Contents with anchor links
Save polished
4-final-draft.md
Updated CLI Tools
All tools now delegate to the canonical assembler:
cli/improve_section.py
def reassemble_final_draft(artifact_dir: Path, console: Console) -> Path:
from cli.assemble_draft import assemble_final_draft as canonical_assemble
console.print("\n[bold]Reassembling final draft...[/bold]")
return canonical_assemble(artifact_dir, console)cli/improve_team_section.py
Same delegation pattern
src/agents/key_info_rewrite.py
Same delegation pattern (removed 60+ lines of duplicated logic)
Files Changed
| File | Change |
cli/assemble_draft.py | Created - canonical assembly tool |
cli/improve_section.py | Refactored reassemble_final_draft() to delegate |
cli/improve_team_section.py | Refactored reassemble_final_draft() to delegate |
src/agents/key_info_rewrite.py | Refactored reassemble_final_draft() to delegate |
Testing
# Test standalone assembly
python -m cli.assemble_draft "Sava"
# Output: ✓ Final draft assembled: output/Sava-v0.0.1/4-final-draft.md
# Words: 8,945 | Citations: 38
python -m cli.assemble_draft "Sava" --version v0.0.2
# Output: ✓ Final draft assembled: output/Sava-v0.0.2/4-final-draft.md
# Words: 10,704 | Citations: 43Related Changes
This changelog is part of a series of improvements made on 2025-11-28:
2025-11-28_01.md- Initial Sava memo generation2025-11-28_02.md- Entity disambiguation system2025-11-28_03.md- Canonical draft assembly tool (this file)
Also created today:
cli/improve_team_section.py- Sequential team research toolcontext-vigilance/Containerizing-Risk-Assessments-and-Diligence-Skepticism.md- Spec for separating conviction from skepticism content