Lossless Changelog
component

Summary

Completed the firm-scoped IO path resolution system, enabling deals to be stored in `io/{firm}/deals/{deal}/` with automatic fallback to the legacy `data/` and `output/` directories. All agents now pass the `firm` parameter through the workflow.

Changelog: Firm-Scoped Path Resolution Implementation

Date: 2025-11-30 Type: Feature Implementation Scope: Path resolution, CLI, agents, state management Status: Complete

Summary

Completed the firm-scoped IO path resolution system, enabling deals to be stored in io/{firm}/deals/{deal}/ with automatic fallback to the legacy data/ and output/ directories. All agents now pass the firm parameter through the workflow.

Changes

New Files

src/paths.py - Centralized Path Resolution

New module with DealContext dataclass and resolution utilities:

PYTHON
@dataclass
class DealContext:
    """Encapsulates resolved paths for a deal."""
    deal_name: str
    firm: Optional[str] = None
    io_root: Path = DEFAULT_IO_ROOT
    deal_dir: Optional[Path] = None
    inputs_dir: Optional[Path] = None
    outputs_dir: Optional[Path] = None
    exports_dir: Optional[Path] = None
    deal_json_path: Optional[Path] = None
    is_legacy: bool = False

Key functions:

  • resolve_deal_context(deal_name, firm, io_root) - Main entry point with priority:

    1. Explicit firm parameter

    2. MEMO_DEFAULT_FIRM environment variable

    3. Auto-detect from io/ directory structure

    4. Legacy fallback (data/{deal}.json + output/{deal}-v*/)

  • get_latest_output_dir_for_deal(ctx) - Gets latest versioned output directory

Modified Files

src/main.py - CLI Enhancements

Added new CLI flags:

BASH
python -m src.main "Handle" --firm hypernova
python -m src.main --deal "Handle" --firm hypernova
  • --firm: Specify firm name for io/{firm}/deals/{deal}/ structure

  • --deal: Alternative to positional argument for deal name

  • Falls back to MEMO_DEFAULT_FIRM env var if no --firm specified

src/state.py - MemoState Extension

Added firm field to MemoState TypedDict:

PYTHON
class MemoState(TypedDict):
    # ... existing fields ...
    firm: Optional[str]  # Firm name for io/{firm}/deals/{deal}/ structure

Updated create_initial_state() to accept and store firm parameter.

src/workflow.py - Firm Parameter Flow

  • generate_memo() now accepts firm parameter

  • Passes firm to create_initial_state()

  • finalize_memo() extracts firm from state for output directory resolution

src/utils.py - Firm-Aware Output Resolution

Updated get_latest_output_dir() signature:

PYTHON
def get_latest_output_dir(
    company_name: str,
    firm: Optional[str] = None,
    io_root: Optional[Path] = None
) -> Path:

Resolution priority:

  1. Firm-scoped: io/{firm}/deals/{company}/outputs/{company}-v*/

  2. Legacy fallback: output/{company}-v*/

src/artifacts.py - Firm-Scoped Artifact Creation

Updated create_artifact_directory():

PYTHON
def create_artifact_directory(
    company_name: str,
    version: str,
    firm: str = None,
    io_root: Path = None
) -> Path:

Creates directories in io/{firm}/deals/{deal}/outputs/ when firm is specified.

All 10 Agents Updated

Each agent now extracts firm from state and passes to get_latest_output_dir():

AgentChange
citation_enrichment.pyAdded firm = state.get("firm")
fact_checker.pyAdded firm = state.get("firm")
link_enrichment.pyAdded firm = state.get("firm")
perplexity_section_researcher.pyAdded firm = state.get("firm")
portfolio_listing_agent.pyAdded firm = state.get("firm")
scorecard_agent.pyAdded firm = state.get("firm")
scorecard_evaluator.pyAdded firm = state.get("firm")
socials_enrichment.pyAdded firm = state.get("firm")
toc_generator.pyAdded firm = state.get("firm")
trademark_enrichment.pyAdded firm = state.get("firm")

.env - Default Firm Configuration

Added environment variable:

BASH
# Default firm for io/{firm}/deals/{deal}/ structure
MEMO_DEFAULT_FIRM=hypernova

Usage

With Default Firm (from .env)

BASH
# Uses MEMO_DEFAULT_FIRM=hypernova from .env
python -m src.main "Handle"

With Explicit Firm

BASH
python -m src.main "Handle" --firm hypernova

Legacy Mode (no firm)

BASH
# Falls back to data/{deal}.json and output/{deal}-v*/
python -m src.main "Fernstone"

Testing Results

Verified path resolution for three scenarios:

PYTHON
# Test 1: Legacy deal (no firm)
get_latest_output_dir('Fernstone')
# ✅ Found: output/Fernstone-v0.0.2

# Test 2: Firm-scoped deal (explicit firm)
get_latest_output_dir('Harmonic', firm='hypernova')
# ✅ Found: io/hypernova/deals/Harmonic/outputs/Harmonic-v0.0.3

# Test 3: Firm auto-detection (no firm specified)
get_latest_output_dir('Harmonic')
# ✅ Found: io/hypernova/deals/Harmonic/outputs/Harmonic-v0.0.3

Commits

  • ca54585 - feat(agents): Add firm parameter support to all agents

  • 05caeda - docs(context-vigilance): Update firm-based IO implementation progress


Remaining Work

Phase 2: CLI Updates (Not Yet Started)

The following CLI scripts still need firm/deal resolution:

  • cli/improve-section.py

  • cli/export_branded.py

  • cli/score_memo.py

  • cli/refocus_section.py

  • cli/recompile_memo.py

Phase 4: Documentation

  • Update README.md with new directory structure

  • Create io/README.md with setup instructions

  • Update CLAUDE.md with new paths


Contributors

Implementation by Claude Code (Anthropic) with user guidance.