From ccd74633d27d5ab3a84dcf27ce45ccc5a6256504 Mon Sep 17 00:00:00 2001 From: Jen Breese-Kauth Date: Wed, 15 Jul 2026 11:18:46 -0700 Subject: [PATCH 01/10] TVM: fix to edge case --- .../time-value-money-calculator/page.tsx | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/app/interactives/time-value-money-calculator/page.tsx b/app/interactives/time-value-money-calculator/page.tsx index 46dfc13..1f9a459 100644 --- a/app/interactives/time-value-money-calculator/page.tsx +++ b/app/interactives/time-value-money-calculator/page.tsx @@ -53,6 +53,12 @@ const CONSTRAINTS = { // Ceiling above which a solved output is "Too large to display" const OUTPUT_OVERFLOW_CEILING = 1e15 +// Cash-flow signs are valid (M1 handles all-same-sign) but no economically +// meaningful rate exists: the only mathematical root sits below the -100% +// display floor, so the scan finds no bracket in the sensible range. +const MSG_NO_MEANINGFUL_RATE = + "No interest rate could be calculated for these inputs. Try adjusting your values, or double-check the cash flow amounts and timing." + interface FieldError { field: string message: string @@ -399,8 +405,9 @@ export default function Page() { } if (bracketLo === null) - // M3 - throw new Error("No interest rate produces these values. Check that your cash flows include both a negative and a positive amount.") + // Signs are already known to be mixed, so this is the + // "root exists only at a nonsensical rate" case, not a sign problem. + throw new Error(MSG_NO_MEANINGFUL_RATE) let solvedG = (bracketLo + bracketHi) / 2 if (bracketLo !== bracketHi) { @@ -459,7 +466,7 @@ export default function Page() { // The high side is intentionally uncapped. -100% exactly is allowed: it // is the legitimate total-loss result when fv = 0. if (solveFor === "RATE" && calculatedValue < -100) - throw new Error("No interest rate produces these values. Check that your cash flows include both a negative and a positive amount.") + throw new Error(MSG_NO_MEANINGFUL_RATE) // M5: output overflow ceiling — never render scientific notation if ( From 50c72b0c34d5889a1f060364cc9e46b293adc72c Mon Sep 17 00:00:00 2001 From: Jen Breese-Kauth Date: Wed, 15 Jul 2026 11:28:12 -0700 Subject: [PATCH 02/10] fixup --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index defbd45..aad380e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ Releases are identified by deploy date. ## [Unreleased] +### [2026-07-15] + +- TVM interest-rate tab now reports that no meaningful rate could be calculated, instead of a misleading cash-flow-signs error, when the only root falls below the -100% floor (#___). + ## [2026-07-10] First tracked production release. Promotes the accumulated calculator work from From 8de9bcd7277132158f14ae9d756b97f27d2ee454 Mon Sep 17 00:00:00 2001 From: Jen Breese-Kauth Date: Thu, 16 Jul 2026 14:53:53 -0700 Subject: [PATCH 03/10] Add Run, Observe, Propose, Verify debugging skill A four-phase change/debug loop tailored to this repo's manual-verification workflow (no test suite; per-file calculator math). Co-Authored-By: Claude Opus 4.8 (1M context) --- .../run-observe-propose-verify/SKILL.md | 98 +++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 .claude/skills/run-observe-propose-verify/SKILL.md diff --git a/.claude/skills/run-observe-propose-verify/SKILL.md b/.claude/skills/run-observe-propose-verify/SKILL.md new file mode 100644 index 0000000..bb5487f --- /dev/null +++ b/.claude/skills/run-observe-propose-verify/SKILL.md @@ -0,0 +1,98 @@ +--- +name: run-observe-propose-verify +description: >- + A disciplined loop for diagnosing bugs and validating changes: Run the code, + Observe the actual behavior, Propose a minimal fix rooted in evidence, then + Verify the fix by re-running and comparing against a known-good baseline. Use + when debugging unexpected behavior, changing financial math or validation + logic, or before calling any nontrivial change "done" — especially in this + repo, which has no automated test suite and relies on manual verification. +--- + +# Run, Observe, Propose, Verify (ROPV) + +A four-phase loop for changing code with confidence. The rule is simple: **never +propose a fix from a theory alone, and never call a change done without +re-observing it.** Evidence bookends every change. + +This repo has no test suite (see `CLAUDE.md`) and its financial math is a +sensitive surface with a history of edge-case regressions. That makes the +observe/verify halves non-optional here, not ceremony. + +## When to use + +- A calculator produces wrong or surprising numbers. +- You're editing financial math, a solver, validation rules, or currency/input + handling. +- You've made any nontrivial change and are about to say it works. +- You're reviewing someone else's change and want to confirm the claimed effect. + +Skip it for pure copy/styling tweaks with no runtime behavior to observe. + +## The loop + +### 1. Run +Get the code executing so you can see real behavior, not imagined behavior. + +- `yarn dev` and open the affected calculator in the browser, OR +- `yarn build:local` to confirm it compiles, and `yarn lint`. +- Reproduce the exact scenario in question: the specific inputs, frequency, + edge value (zero rate, very high rate, cross-compounding frequency, empty + field). + +Write down the inputs you used. A repro you can't restate is not a repro. + +### 2. Observe +Record what actually happens, precisely — before forming any theory. + +- Capture the actual output (the number, the date, the error). +- Capture what you *expected* and where that expectation comes from (a + hand-calculation, another calculator, a known-good commit). +- Note the delta. "Bi-weekly total interest is ~8% high" is an observation; + "the divisor is wrong" is already a guess — keep them separate. +- Localize: does it affect one frequency or all? One tab or both? That narrows + cause to a shared helper vs. per-file logic. In these calculators, each + `app/interactives//page.tsx` owns its own math — a bug in one usually + does **not** exist in the others; confirm per file. + +### 3. Propose +Only now form a fix, and make it the smallest change that the observation +justifies. + +- State the root cause in one sentence, tied to the observed delta. +- Prefer a one-line/one-value fix over a rewrite. If the fix is large, your + diagnosis is probably incomplete — go back to Observe. +- Predict, out loud, what the corrected output should be *before* you run it. +- Check whether the same root cause appears in sibling calculators; fix each + only after confirming it's actually present there (don't assume). + +### 4. Verify +Re-run and confirm the prediction. This closes the loop. + +- Re-run the exact repro from step 1. Confirm the new output matches the + predicted value, not just "looks different." +- Test the boundaries around it: zero, very large, empty input, the adjacent + compounding frequencies, both tabs. +- Confirm you didn't regress the cases that were already correct. +- Re-run `yarn lint` (and `yarn build:local` if you touched more than one file). +- Report faithfully: state the before/after numbers and the exact inputs. If a + case still fails or you skipped a check, say so. + +## Reporting template + +``` +Repro: +Observed: (expected from ) +Cause: +Fix: +Verified: ; boundaries checked: +``` + +## Anti-patterns + +- Proposing a fix before running the code ("this should be it" — verify it *is*). +- Verifying only the one case you fixed and declaring victory. +- A large refactor offered as a bug fix — a symptom of a skipped Observe phase. +- Assuming a fix in one calculator applies to the `-v2` or sibling versions + without checking each file. +- Calling it done on a green compile alone; compiling is not behaving. From a6cfe455419648c8e6ee0bed5e8c68f1c044bed7 Mon Sep 17 00:00:00 2001 From: Jen Breese-Kauth Date: Thu, 16 Jul 2026 14:54:36 -0700 Subject: [PATCH 04/10] Add CLAUDE.md project guidance Co-Authored-By: Claude Opus 4.8 (1M context) --- CLAUDE.md | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..2d2ad5e --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,53 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## What this is + +Educational financial-decision-making prototype for early-career professionals, built with Stanford GSB's Initiative for Financial Decision Making (IFDM). It's a Next.js **static site** of interactive financial calculators, each designed to be embedded via `