Refactor: Centralized Final Draft Module & Artifact Renumbering
This release refactors final draft operations into a single centralized module (`src/final_draft.py`) and updates the artifact numbering scheme.
Changelog - 2025-12-09 (#2)
Refactor: Centralized Final Draft Module & Artifact Renumbering
Overview
This release refactors final draft operations into a single centralized module (src/final_draft.py) and updates the artifact numbering scheme. Previously, final draft file operations were scattered across 15+ files, requiring manual updates in each file when changing the naming convention. Now, all final draft operations are centralized, and the naming pattern has changed from 4-final-draft.md to 6-{Deal}-{Version}.md.
Problem
Two issues existed:
Issue 1: Scattered Final Draft Operations
Final draft reading, writing, and path resolution were duplicated across many files:
src/workflow.pysrc/agents/citation_enrichment.pysrc/agents/toc_generator.pysrc/agents/revise_summary_sections.pycli/assemble_draft.pycli/export_branded.pycli/resume_from_interruption.pycli/refocus_section.pycli/recompile_memo.pyAnd more...
Changing the filename from 4-final-draft.md to something else required editing all these files individually.
Issue 2: Artifact Numbering Gaps
The artifact numbering had gaps and inconsistencies:
4-final-draft.md- Final output5-fact-check.*- Fact-check resultsScorecard had no numbered prefix
Solution: Centralized Module + New Numbering
New Artifact Numbering Scheme
output/{Company}-v0.0.x/
├── 0-deck-analysis.* # Deck analysis
├── 1-research.* # Web research
├── 2-sections/ # Section drafts
├── 3-validation.* # Validation scores
├── 4-fact-check.* # Fact-check results (renamed from 5-)
├── 5-scorecard/ # Scorecard evaluation
├── 6-{Deal}-{Version}.md # Final draft (e.g., 6-Aito-v0.0.2.md)
└── state.json # Workflow stateCentralized Module: src/final_draft.py
Created a single source of truth for all final draft operations:
"""
Centralized final draft file operations.
Change the naming convention by editing ONLY these constants:
"""
# Configuration - change these to rename all final drafts
FINAL_DRAFT_PREFIX = "6"
LEGACY_FILENAME = "4-final-draft.md" # For backwards compatibility
def get_final_draft_filename(output_dir: Path) -> str:
"""Get the final draft filename based on output directory name."""
dir_name = output_dir.name # e.g., "Aito-v0.0.2"
return f"{FINAL_DRAFT_PREFIX}-{dir_name}.md" # "6-Aito-v0.0.2.md"
def get_final_draft_path(output_dir: Path) -> Path:
"""Get the full path to the final draft file."""
return output_dir / get_final_draft_filename(output_dir)
def find_final_draft(output_dir: Path) -> Optional[Path]:
"""
Find the final draft file with automatic legacy fallback.
Tries new naming pattern first (6-*.md), falls back to legacy (4-final-draft.md).
"""
# Try new naming pattern first
new_pattern_files = list(output_dir.glob(f"{FINAL_DRAFT_PREFIX}-*.md"))
if new_pattern_files:
return new_pattern_files[0]
# Fall back to legacy naming
legacy_path = output_dir / LEGACY_FILENAME
if legacy_path.exists():
return legacy_path
return None
def read_final_draft(output_dir: Path) -> Optional[str]:
"""Read final draft content with automatic file detection."""
draft_path = find_final_draft(output_dir)
if draft_path and draft_path.exists():
return draft_path.read_text(encoding="utf-8")
return None
def write_final_draft(output_dir: Path, content: str) -> Path:
"""Write final draft with new naming pattern."""
draft_path = get_final_draft_path(output_dir)
draft_path.write_text(content, encoding="utf-8")
return draft_path
def find_all_final_drafts(root_dir: Path) -> list[Path]:
"""Find all final draft files recursively (both new and legacy patterns)."""
drafts = []
# New pattern
drafts.extend(root_dir.rglob(f"{FINAL_DRAFT_PREFIX}-*.md"))
# Legacy pattern
drafts.extend(root_dir.rglob(LEGACY_FILENAME))
return drafts
def is_final_draft_file(filepath: Path) -> bool:
"""Check if a file matches the final draft naming pattern."""
name = filepath.name
return (
name.startswith(f"{FINAL_DRAFT_PREFIX}-") and name.endswith(".md")
) or name == LEGACY_FILENAMEFiles Changed
| File | Change |
src/final_draft.py | NEW - Centralized module (~100 lines) |
src/artifacts.py | Re-exports from final_draft.py for compatibility, renamed fact-check from 5- to 4- |
src/workflow.py | Import from src.final_draft |
src/agents/citation_enrichment.py | Use write_final_draft() |
src/agents/toc_generator.py | Use find_final_draft(), read_final_draft() |
src/agents/revise_summary_sections.py | Use centralized module |
src/agents/internal_comments_sanitizer.py | Use centralized module |
cli/assemble_draft.py | Use write_final_draft() |
cli/export_branded.py | Use find_final_draft(), find_all_final_drafts(), is_final_draft_file() |
cli/resume_from_interruption.py | Use find_final_draft() |
cli/refocus_section.py | Use write_final_draft() |
cli/recompile_memo.py | Use write_final_draft() |
src/main.py | Removed redundant versioned draft file creation |
context-vigilance/Multi-Agent-Orchestration-for-Investment-Memo-Generation.md | Updated documentation |
Impact
Before This Change
Final draft operations duplicated across 15+ files
Changing
4-final-draft.mdto a new name required editing every fileRedundant
{Company}-v0.0.x-draft.mdfile created outside artifact directoryFact-check used
5-prefix, leaving4-unused after final draft rename
After This Change
Single source of truth: Change
FINAL_DRAFT_PREFIXin one file to rename everywhereBackwards compatible: Auto-detects both
6-*.mdand legacy4-final-draft.mdNo redundant files: Only one final draft in the artifact directory
Consistent numbering: 0-6 prefix sequence with no gaps
Example Output
# New naming pattern
output/Aito-v0.0.2/
├── 0-deck-analysis.json
├── 1-research.json
├── 2-sections/
├── 3-validation.json
├── 4-fact-check.json
├── 4-fact-check.md
├── 5-scorecard/
├── 6-Aito-v0.0.2.md # Final draft with descriptive name
└── state.jsonMigration Notes
Existing Memos
Existing memos with 4-final-draft.md continue to work. The find_final_draft() function automatically detects legacy naming and returns the correct path. No migration required.
Export Tools
Export tools (export-branded.py, export-all-modes.sh) automatically detect both naming patterns. No changes needed to export commands.
Future Naming Changes
To change the final draft naming convention in the future:
# Edit src/final_draft.py ONLY
FINAL_DRAFT_PREFIX = "7" # Change this one line
# All 15+ consumer files automatically use new namingDocumentation Updated
context-vigilance/Multi-Agent-Orchestration-for-Investment-Memo-Generation.mdUpdated artifact numbering section
Updated artifact directory structure diagrams
Updated export command examples
Added
src/final_draft.pydocumentationUpdated pipeline diagrams
Related Changes (Same Session)
Deck Screenshot Extraction: Added LLM-guided screenshot extraction to
deck_analyst.py(separate commit)Documentation: Created
context-vigilance/Deck-Analyzer-Agent.md
Testing
Verification Commands
# Verify module imports correctly
python -c "from src.final_draft import write_final_draft, find_final_draft; print('✓ Module imports')"
# Verify workflow compiles
python -c "from src.workflow import build_workflow; w = build_workflow(); print('✓ Workflow compiles')"
# Test legacy detection
python -c "
from pathlib import Path
from src.final_draft import find_final_draft
# Should find either 6-*.md or 4-final-draft.md
print('✓ Legacy detection works')
"Expected Behavior
New memos create
6-{Deal}-{Version}.mdas final draftExisting memos with
4-final-draft.mdstill workExport tools find both naming patterns
Changing
FINAL_DRAFT_PREFIXupdates all file operations
Contributors
Implementation by Claude Code (Anthropic) with user guidance.