Lossless Changelog
component

Fix: Resume Workflow Uses Wrong Paths for Firm-Scoped IO

When resuming a workflow with `cli/resume_from_interruption.py` for firm-scoped deals, the writer agent would use legacy `output/` paths instead of firm-scoped `io/{firm}/deals/{deal}/outputs/` paths.

Changelog - 2025-12-09 (#3)

Fix: Resume Workflow Uses Wrong Paths for Firm-Scoped IO

Problem

When resuming a workflow with cli/resume_from_interruption.py for firm-scoped deals, the writer agent would use legacy output/ paths instead of firm-scoped io/{firm}/deals/{deal}/outputs/ paths.

Error observed:

Error in agent draft: [Errno 2] No such file or directory: 'output/RavenGraph-v0.0.1/2-sections/01-executive-summary.md'

Expected path:

io/dark-matter/deals/RavenGraph/outputs/RavenGraph-v0.0.2/2-sections/01-executive-summary.md

Root Cause

Two bugs in the resume workflow:

  1. cli/resume_from_interruption.py - The firm, outline_name, and scorecard_name values were loaded from the deal config but NOT passed to create_initial_state(). This caused state["firm"] to be None.

  2. src/agents/writer.py - Always created a new version directory, ignoring any existing state["output_dir"] set by the resume script.

Solution

Fix 1: Pass firm context to state (resume_from_interruption.py)

Before:

PYTHON
state = create_initial_state(
    company_name=company_name,
    investment_type=investment_type,
    memo_mode=memo_mode,
    deck_path=deck_path,
    # ... other params
    # MISSING: firm, outline_name, scorecard_name
)

After:

PYTHON
firm = ctx.firm if ctx else None
state = create_initial_state(
    company_name=company_name,
    investment_type=investment_type,
    memo_mode=memo_mode,
    firm=firm,  # NOW PASSED
    deck_path=deck_path,
    # ... other params
    outline_name=outline_name,      # NOW PASSED
    scorecard_name=scorecard_name   # NOW PASSED
)

Fix 2: Respect existing output_dir (writer.py)

Before:

PYTHON
firm = state.get("firm")
safe_name = sanitize_filename(company_name)

if firm:
    # Always creates new version - ignores state["output_dir"]
    version = version_mgr.get_next_version(safe_name)
    output_dir = create_artifact_directory(...)

After:

PYTHON
firm = state.get("firm")
safe_name = sanitize_filename(company_name)

# Check if output_dir already set (e.g., by resume script)
existing_output_dir = state.get("output_dir")
if existing_output_dir:
    output_dir = Path(existing_output_dir)
    print(f"   Using existing output directory: {output_dir}")
    (output_dir / "2-sections").mkdir(parents=True, exist_ok=True)
elif firm:
    # Create new version only when not resuming
    version = version_mgr.get_next_version(safe_name)
    output_dir = create_artifact_directory(...)

Files Changed

FileChange
cli/resume_from_interruption.pyPass firm, outline_name, scorecard_name to create_initial_state()
src/agents/writer.pyCheck for existing state["output_dir"] before creating new version

Verification

After the fix, resume correctly uses firm-scoped paths:

[DEBUG] About to call create_initial_state for RavenGraph (firm=dark-matter)
[DEBUG] create_initial_state completed (state firm=dark-matter)
Using existing output directory: io/dark-matter/deals/RavenGraph/outputs/RavenGraph-v0.0.2

Impact

  • Resume workflow now correctly handles firm-scoped IO paths

  • Writer agent respects pre-set output directories when resuming

  • All 12 agents now respect state["output_dir"] for correct path resolution

  • Fix enables resuming interrupted workflows without path errors


Additional Fix: All Agents Now Respect state["output_dir"]

The Second Bug

After fixing the resume script, agents were still using wrong paths because they called get_latest_output_dir() which returns the newest version - not the version being resumed.

Solution

Added new helper get_output_dir_from_state() in src/utils.py that:

  1. First checks state["output_dir"] (set by resume script)

  2. Falls back to get_latest_output_dir() if not set

Updated 12 agent files to use this helper:

  • citation_enrichment.py

  • fact_checker.py

  • internal_comments_sanitizer.py

  • link_enrichment.py

  • perplexity_section_researcher.py

  • revise_summary_sections.py

  • scorecard_agent.py

  • scorecard_evaluator.py

  • socials_enrichment.py

  • toc_generator.py

  • trademark_enrichment.py

  • validator.py