Skip to content

feat(L5): cost-of-debt pricing engine + financing instruments (ADR-0013, #616)#641

Merged
PipFoweraker merged 1 commit into
mainfrom
l5-finance-instruments
Jul 15, 2026
Merged

feat(L5): cost-of-debt pricing engine + financing instruments (ADR-0013, #616)#641
PipFoweraker merged 1 commit into
mainfrom
l5-finance-instruments

Conversation

@PipFoweraker

Copy link
Copy Markdown
Owner

Lane L5 · ADR-0013 · closes #616, fixes #566. Design-surface lane — Pip reviews, do not auto-merge.

What

One data-driven pricing engine for all liabilities plus the standing-offer raise flow, and the #566 fix — all money-side (the doom-streams lane owns doom conversion; this branch never touches doom_system or ledger→doom).

1. Pricing engine (FinanceEngine.price, ADR-0013 thesis)

rate = base × org_factor × counterparty_factor + leverage·penalty − (rep/100)·relief, clamped and snapped to the 0.001 save-safe grid (probe-verified against the real full-precision JSON save path — calibration open-Q #2), so minted entries survive save/load. Coefficients live in data/balance/defaults.json financing.* (file-swappable per L9).

2. Instruments (data-driven table)

id counterparty factory cash range term base rate non-cash availability
bank_loan bank loan $30–80k 3.5 mo (~77 ticks) 0.008/tick finance-rep ≥15, leverage <3
credit_line bank loan $60–160k 4 mo 0.010 finance-rep ≥45, leverage <1.5
vc_equity vc equity $120–400k — (not debt) 0 equity dilution 12% + board seat for-profit, hype ≥25
grant_strings government funding_strings $25–70k 4 mo 0.0025 agenda narrowing (governance bill) safety-rep ≥25
philanthropy philanthropist philanthropy $15–45k — (gift) 0 safety-rep ≥30, 35% appearance (scarce by design)
desperation shadow desperation_payroll severity 2.5 mo 0.008 secret liability always (last resort)

3. Offer generation with optionality (ADR-0012)

generate_offers() mints 2–3 concurrent standing offers with an expiry_turn; better standing → richer/cheaper menu. Seed-deterministic (WS-0). New actions seek_financing / accept_financing_offer / pay_bills expose the flow; accepted offers mint entries carrying the quoted terms (menu is honest). Non-cash terms mint inert ledger riders (equity/board seat = DQ-7 stub; agenda = the governance strings bill).

4. Fix #566

  • Reputation crash (50→7.5) was uncapped rep damage → now capped per bill (max_rep_per_bill).
  • "Magnitudes don't reconcile" → the ledger_default note now records principal_billed = paid_from_cash + shortfall; only the shortfall converts to (capped) doom/rep.
  • Adds the "pay the bill" early-repayment interaction (Ledger.pay_entry / pay_soonest_payable).

No regression

The sweep's take_loan path routes Ledger.loan directly and is unchanged — L1 medians byte-identical: do_nothing 14, safety_lean 16.5, reserve_heavy 19, greedy 7, loan_desperation 7, random_walk 8; MORTALITY_CHECK max_months=45 → PASS.

Tests

test_finance_engine.gd (22 tests, 69 asserts): pricing determinism + input-sensitivity, availability gating, standing-offer optionality/expiry, quoted-term minting, #566 regression (capped default + reconciled magnitudes), early repayment, save-safe rates. Gates green: quick 355 · integration 14 · simulation 93 · L1 sweep unchanged.

Deferred / boundary

  • Typed reputation + org type + hype are read from context with graceful fallback to scalar reputation / nonprofit default (their first-class GameState fields are owed by the ADR-0010 typed-attention and DQ-4 char/org-creation lanes).
  • Standing offers are transient (not serialized) in v1 — a save/load drops any pending menu; the player re-seeks.
  • Bot policy redesign to use the offer menu belongs to another lane; sweep policies are untouched.

🤖 Generated with Claude Code

…13, #616)

One data-driven pricing engine for all liabilities. FinanceEngine.price()
computes terms from org type + counterparty + typed reputation + current
leverage (ADR-0013's thesis); generate_offers() mints 2-3 concurrent STANDING
offers with expiry (ADR-0012) so a raise is a campaign with optionality — better
standing buys a richer, cheaper menu. Instruments (bank loan, revolving credit,
VC equity, directed grant, philanthropy, desperation lever) live in
data/balance/defaults.json "financing.*"; coefficients (org/counterparty/rep/
leverage factors) are file-swappable. Non-cash terms (equity dilution scalar,
board-seat stub, agenda strings) mint ledger riders. Computed interest is snapped
to the 0.001 save-safe grid so minted entries survive save/load.

Additive by construction: the sweep's take_loan path routes Ledger.loan directly
and is unchanged — the L1 medians are byte-identical (do_nothing 14, safety_lean
16.5, reserve_heavy 19, greedy 7, loan_desperation 7, random_walk 8; MORTALITY
PASS max 45). Bots keep exercising instruments via the existing levers; the new
seek_financing/accept_financing_offer/pay_bills actions expose the engine to the
game/UI without touching the calibrated sweep policies.

Fix #566 (loan billing zeroes money AND crashes reputation): the reputation crash
(50->7.5) was uncapped rep damage — now capped per bill (max_rep_per_bill), and
the "magnitudes don't reconcile" is fixed by reconciling the default note
(principal_billed = paid_from_cash + shortfall; only the shortfall converts to
capped doom/rep). Adds the "pay the bill" early-repayment interaction
(Ledger.pay_entry / pay_soonest_payable).

BOUNDARY: money-side only — no doom_system or ledger->doom conversion touched
(owned by the doom-streams lane). Non-cash riders are inert standing terms.

Tests: test_finance_engine.gd (22) — pricing determinism + input sensitivity,
availability gating, standing-offer optionality/expiry, quoted-term minting, #566
regression (capped default + reconciled magnitudes), early repayment, save-safe
rates. Gates green: quick 355, integration 14, simulation 93; L1 sweep unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

PipFoweraker added a commit that referenced this pull request Jul 15, 2026
…5 structural finding

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@PipFoweraker
PipFoweraker merged commit ef06ec1 into main Jul 15, 2026
15 of 16 checks passed
@PipFoweraker
PipFoweraker deleted the l5-finance-instruments branch July 15, 2026 00:45
PipFoweraker added a commit that referenced this pull request Jul 15, 2026
…gen on calibrated base

Correction round (PR #642): the earlier work branched a stale origin/main (58a5a17,
pre-calibration). Rebased onto true main (4a0f4ae calibration + ef06ec1 #641 L5
finance).

Harness unification (fixes the two-month-runners smell):
- Extracted the calibrator's run loop (test_l1_month_sweep.gd _run/_answer_windows)
  VERBATIM into l1_month_driver.gd — one shared driver. Parity verified: the
  calibrator's regenerated docs/balance/L1_sweep_runs.csv is BYTE-IDENTICAL to the
  tracked calibration copy, so the extraction is outcome-neutral and the calibration
  table stands unchanged.
- test_l1_month_sweep.gd now delegates to the driver (LegacyPolicyAdapter); its
  policies + reporting are untouched. Deleted the parallel month_runner.gd.
- reactive_adapter.gd bridges reactive policies (ReactivePolicy) to the driver, with
  the opening-prefix override seam for EE-10.
- Renamed the reactive policy loan_desperation -> loan_desperation_reactive to avoid
  colliding with the calibrator's loan_desperation.

Regenerated ALL data on calibrated constants (runs now last months, so strategy
expresses):
- Policy headline (docs/balance/POLICY_SWEEP.md): safety_lean 18.5 mo best, passive
  14.0 (== calibrator do_nothing, cross-harness anchor), fundraise_first 14.0 beats
  loan_desperation_reactive 13.0, capability_rush 6.0 worst. T9 floor HOLDS for all
  reactive standard lines (measured, not gated).
- Desperation solver: the lever does NOT pay — firing earlier/more is monotonically
  worse (lever@always -2.5 mo) and converts doom deaths into ledger deaths (1 -> 12).
  fundraise_first now uses the L5 raise-as-campaign flow (seek/accept offer, pay_bills).
- Opening book v0: winners over-index on money-in (fundraise_small +1.56, apply_grant);
  losers on hire_capability_researcher (-2.11), take_loan, desperation_lever —
  cross-validating the solver.

Doc caveats rewritten to the true base. Full suite green (quick 365 / sim 93 /
integration 14).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
PipFoweraker added a commit that referenced this pull request Jul 15, 2026
Verified current main (post #636/#638/#639/#640/#641/#643 merge stack)
launches clean headless, plays a full month through the End Turn ->
MonthController path, and passes the fast unit gate CI runs
(345 tests, 0 failures, 36/36 files). Nine-stream doom, finance offers,
and flight recorder all pass their unit suites with no wiring gaps
found. No code changes needed -- green light for tomorrow.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
PipFoweraker added a commit that referenced this pull request Jul 15, 2026
…r (unified harness) (#642)

* feat(balance): EE-9 reactive-policy framework + solver + EE-10 opening-book miner

Tooling-only balance instruments (tests/manual, excluded from CI). No gameplay
code changed.

EE-9 · Reactive rule-policy framework (reactive_policy.gd): a policy = ordered
(condition -> action) rules evaluated at the plan phase (action priority) and per
response window (verb), reading a features snapshot (cash, runway, doom, reserve,
ledger load, offers). Declarative + parameterized so future sweeps vary the dials.

Named policies (sweep_policies.gd): fundraise_first (the new standard finance line
— fundraise by default, loan only when runway < N months), balanced_operator,
scout_heavy (proxy pending DQ-18 scouting), loan_desperation (naive foil), plus the
five exploit-sweep dispositions re-expressed as reactive policies (unit-tested to
reproduce the old _choose_actions priority — the "keep existing policies working"
regression link).

MonthRunner: deterministic headless driver of the real L1 month loop (plan ->
day-tick playback -> window auto-pause -> boundary), shared by all three instruments.

test_l1_month_sweep.gd — month-grain sibling of the exploit sweep (kept untouched).
test_desperation_solver.gd — EE-9 solver-bot isolating the desperation lever (DQ-25).
test_opening_book_miner.gd — EE-10: random opening prefix + fixed continuation,
feature -> outcome deciles, raw CSV.

Framework unit tests + full suite + determinism verified green. Outputs carry a
prominent pre-migration caveat and a one-line regenerate command (DQ-21 re-run).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* refactor(balance): unify EE-9/EE-10 onto the calibrator's harness; regen on calibrated base

Correction round (PR #642): the earlier work branched a stale origin/main (58a5a17,
pre-calibration). Rebased onto true main (4a0f4ae calibration + ef06ec1 #641 L5
finance).

Harness unification (fixes the two-month-runners smell):
- Extracted the calibrator's run loop (test_l1_month_sweep.gd _run/_answer_windows)
  VERBATIM into l1_month_driver.gd — one shared driver. Parity verified: the
  calibrator's regenerated docs/balance/L1_sweep_runs.csv is BYTE-IDENTICAL to the
  tracked calibration copy, so the extraction is outcome-neutral and the calibration
  table stands unchanged.
- test_l1_month_sweep.gd now delegates to the driver (LegacyPolicyAdapter); its
  policies + reporting are untouched. Deleted the parallel month_runner.gd.
- reactive_adapter.gd bridges reactive policies (ReactivePolicy) to the driver, with
  the opening-prefix override seam for EE-10.
- Renamed the reactive policy loan_desperation -> loan_desperation_reactive to avoid
  colliding with the calibrator's loan_desperation.

Regenerated ALL data on calibrated constants (runs now last months, so strategy
expresses):
- Policy headline (docs/balance/POLICY_SWEEP.md): safety_lean 18.5 mo best, passive
  14.0 (== calibrator do_nothing, cross-harness anchor), fundraise_first 14.0 beats
  loan_desperation_reactive 13.0, capability_rush 6.0 worst. T9 floor HOLDS for all
  reactive standard lines (measured, not gated).
- Desperation solver: the lever does NOT pay — firing earlier/more is monotonically
  worse (lever@always -2.5 mo) and converts doom deaths into ledger deaths (1 -> 12).
  fundraise_first now uses the L5 raise-as-campaign flow (seek/accept offer, pay_bills).
- Opening book v0: winners over-index on money-in (fundraise_small +1.56, apply_grant);
  losers on hire_capability_researcher (-2.11), take_loan, desperation_lever —
  cross-validating the solver.

Doc caveats rewritten to the true base. Full suite green (quick 365 / sim 93 /
integration 14).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs(balance): regenerate desperation-solver report with dose-response bullet

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* balance(EE-9/EE-10): regenerate on nine-stream doom (post-#643); caveats -> stream base

Merged origin/main (74074c8, ADR-0015 nine-stream doom). Framework is orthogonal to
the doom internals — clean merge, no conflicts, and all three instruments ran clean
against stream-based doom (no breakage). Refreshed numbers + caveats now read "on
nine-stream doom (post-#643)" instead of "pre-migration".

Ordering is migration-robust:
- Policy sweep: safety_lean 18.0 best, balanced_operator 16.0, fundraise_first 14.5
  (still beats loan_desperation_reactive 13.0), passive 14.5 (~= calibrator do_nothing
  14.0, cross-harness anchor holds), capability_rush 7.0 / loan_hoard 5.0 worst. T9
  HOLDS for all reactive standard lines.
- Desperation solver: the trap SURVIVED and got STEEPER on stream doom — lever@always
  now -5.0 median months (was -2.5), doom->ledger death conversion total (2 -> 12/12).
  Added two bullets to DESPERATION_SOLVER.md so the divergence isn't misread: the
  solver (isolates the mechanic) is the trap's instrument; the opening book's
  near-neutral lone-lever signal is a lever washed out among random picks, not a
  contradiction.
- Opening book: winners over-index on money-in + doom-down (apply_grant +1.67,
  fundraise_big, publish_paper); losers on safety_research, take_loan,
  hire_capability_researcher.

Determinism re-verified (policy sweep identical across runs). Full suite green
(quick 355 / sim 93 / integration 14).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
PipFoweraker added a commit that referenced this pull request Jul 15, 2026
Developer-facing architecture map (audience: future junior dev). Maps each
major system to its code and deciding ADR(s), with honest built/partial/designed
status. Preserves the prior funder pitch at ARCHITECTURE_FUNDERS.md.

Written against the L1 wave (month engine #636, nine-stream doom #643, finance
#641, calibration #638, honest CI #640). Surfaces coherence-check findings in §7.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant