Skip to main content

Financial Model Validator

Purpose

  1. Validates /fm build outputs after every build operation
  2. Checks format completeness — expected files exist and are non-empty
  3. Runs metric sanity checks — no negative ARR, reasonable LTV:CAC ratios, cash runway logic
  4. Verifies internal reconciliation — P&L net income consistent with cash flow changes
  5. Flags missing or anomalous months in time series data
  6. Reports validation results to the invoking persona agent

Trigger

Event Type: Post /fm build execution

Source: /fm build <scenario> --format <format> command completion

Blocking: Yes (validation must pass before outputs are delivered to user)

Timeout: 15 seconds

Trigger Condition: Any /fm build command that generates output files

Behavior

When Triggered

  1. Receives build output context:

    • Scenario ID and name
    • Format(s) built (xlsx, formula, json, csv, all)
    • Output file paths
    • Build summary metrics (breakeven, M60 ARR, M60 cash, peak burn)
  2. Format Completeness Check:

    • Verify each expected output file exists
    • Verify file size > 0 bytes
    • For XLSX: verify expected sheet count (10 for static, 10 for formula)
    • For JSON: verify valid JSON with required top-level keys (metadata, summary, monthly_data)
    • For CSV: verify header row and expected column count
  3. Metric Sanity Checks:

    MetricValid RangeFlag If
    M60 ARR> $0Negative or zero
    Breakeven MonthM1-M60> M60 (never breaks even)
    Peak Monthly Burn< $0Positive (never burns cash)
    LTV:CAC (enterprise)1.0x - 20.0x< 1.0x or > 20.0x
    LTV:CAC (individual)0.5x - 10.0x< 0.5x or > 10.0x
    Customer Count (M60)> 0Zero or negative
    Cash Position (M60)AnyWarn if negative
    Expense Ratios Sum< 100% at scale> 100%
  4. Reconciliation Checks:

    • Revenue = sum(tier_customers x tier_price x 12) within 1%
    • Cash flow: opening + inflows - outflows = closing within $1
    • Customer math: starting + new - churned = ending (exact)
    • Month-over-month continuity: no gaps in time series
  5. Result Classification:

    ResultAction
    PASSAll checks pass — deliver outputs to user
    WARNSanity check flags present — deliver with warnings
    FAILReconciliation error or missing output — block delivery, report error

Output Format

VALIDATION: financial-model-validator
Scenario: {scenario_id}
Format: {format}
Status: PASS | WARN | FAIL

Format Check: ✅ 4/4 files present
Sanity Check: ✅ 8/8 metrics in range
Reconciliation: ✅ 4/4 balances match

Warnings: (if any)
- M60 cash position is negative (-$234,000) — review burn rate

Errors: (if any)
- Revenue reconciliation gap: 2.3% (threshold: 1%)

Configuration

ParameterDefaultDescription
revenue_tolerance0.01 (1%)Max revenue reconciliation gap
cash_tolerance1.0 ($1)Max cash balance discrepancy
warn_negative_cashtrueWarn on negative M60 cash
block_on_reconciliationtrueFAIL on reconciliation errors

Implementation

def validate_fm_build(scenario_id, format, output_dir):
"""Post-build validation for /fm outputs."""
results = {"format": [], "sanity": [], "reconciliation": []}

# 1. Format completeness
expected_files = get_expected_files(scenario_id, format)
for f in expected_files:
path = os.path.join(output_dir, f)
if not os.path.exists(path):
results["format"].append(("FAIL", f"Missing: {f}"))
elif os.path.getsize(path) == 0:
results["format"].append(("FAIL", f"Empty: {f}"))
else:
results["format"].append(("PASS", f"OK: {f}"))

# 2. Sanity checks (from JSON summary)
if "json" in format or format == "all":
summary = load_json_summary(scenario_id, output_dir)
check_metric_ranges(summary, results)

# 3. Reconciliation (from CSV monthly data)
if "csv" in format or format == "all":
monthly = load_csv_data(scenario_id, output_dir)
check_reconciliation(monthly, results)

return classify_results(results)
  • Engine: coditect_fm.py (ADR-177)
  • Command: /fm (financial-model.md)
  • Skill: financial-model-personas/SKILL.md
  • Agents: cfo.md, fpa-analyst.md, finance-controller.md, financial-analyst.md
  • Workflow: fm-orchestration-workflow.md

Track: N.6.13.4.1 ADR: ADR-177 (Database-Driven Financial Model Engine)