Skip to content

Debugging a Bad Week Without Rewriting History

Lesson 5 logged four real weeks against a fixed Week 1 baseline: 55 hours, 52, 48, 43, automation climbing from 14.6% to 58.1%. Every one of those numbers was correct. This lesson is about the week it wasn't, because eventually one of yours won't be either, and the wrong move here is worse than the mistake that caused it.

A mistake that passes every guard

Here is Week 3 again, logged a second time, from scratch, by someone glancing at last week's notes while filling in this week's numbers:

bash
python3 .claude/skills/transformation-tracker/scripts/log_week.py \
  --week 3 --total-hours 48 --automated-hours 22 --active-clients 4 \
  --revenue-ratio 1.05 --recurring-pct 15.0 \
  --automated-this-week "Onboarding checklist" --bottleneck "Reporting"

Look closely at --revenue-ratio 1.05. Week 2's revenue ratio was 1.05. Week 3's real revenue ratio, the one that actually shipped in Lesson 5, was 1.15. Somebody's eye slid one row up the page while they were typing, and they carried Week 2's number into Week 3's command.

The script has no way to know that. It runs:

week 3 logged. automation_index: 45.83% time_saved_vs_baseline: 7.0 hours/week revenue_efficiency_multiple: 1.2031x client_capacity_score: 1.5278x recurring_revenue_pct: 15.0%

Nothing here throws an error. 1.05 is a perfectly ordinary revenue ratio; Week 2 already used it. automated-hours sits well inside total-hours. Week 1 exists, so the baseline check passes. Every guard condition Lesson 3 walked through, the no-overwrite check, the automated-hours bounds check, the Week 1 requirement, is a rule about the shape of a number. None of them are a rule about whether the number is the right one, because the script has no way to know what you meant to type. It only knows what you typed.

Compare the wrong output to the surrounding weeks

revenue_efficiency_multiple: 1.2031x sitting next to Week 2's 1.11x and Week 4's 1.60x looks completely reasonable. It is between the two. Nothing about it stands out on a table. The real Week 3 value, computed correctly from the actual 1.15 ratio, is 1.3177x, using the exact formula from Lesson 4: (revenue_ratio / total_hours) / (baseline_revenue_ratio / baseline_hours), or (1.15/48) / (1.0/55). The gap between 1.2031 and 1.3177 is real, and it is small enough that a plausible-but-wrong number is harder to catch than an error the script would have rejected outright, because nothing here is flagging it.

Why this is the harder bug, not the easier one

A bug that crashes gets fixed the same day, because it announces itself. This is the opposite kind. The Week 3 row above will sit in transformation-log.jsonl looking completely normal for as long as nobody goes back and rechecks the source numbers against the printed ones. report.py --table will render it next to three correct weeks and nothing in the formatting will distinguish it. That is the actual lesson underneath the mistake: a script that validates the shape of a number was never going to catch an error in its value, and no amount of tightening the guard conditions changes that, because the guards cannot see your notes from last week. Only you can.

What the guard conditions can and cannot see

The naive fix: just run it again correctly

The instinct is obvious. Re-run the same command with the right number:

bash
python3 .claude/skills/transformation-tracker/scripts/log_week.py \
  --week 3 --total-hours 48 --automated-hours 22 --active-clients 4 \
  --revenue-ratio 1.15 --recurring-pct 15.0 \
  --automated-this-week "Onboarding checklist" --bottleneck "Reporting"

This refuses. Exactly the same guard that protects a real accidental double-run protects a corrected one:

week 3 is already logged. This script only appends; it will not overwrite a prior week.

Exit code 1. Nothing gets written. This is the append-only rule from Lesson 2's CLAUDE.md reading doing precisely what it was built to do, and it does not know the difference between "I am trying to cheat my own trend line" and "I made a typo and want to fix it." Both look identical from the script's side: a second --week 3 submission. The guard that makes the log trustworthy is the same guard that makes the honest fix impossible through log_week.py alone.

The real fix: hand-edit the one line

This repo's CLAUDE.md states the sanctioned fix in substance: fix a mistake by editing the JSONL line directly, not by re-running. transformation-log.jsonl is plain text, one JSON object per line. Open it, find the Week 3 line, and change the one field that was wrong.

Open the log and find the Week 3 line

transformation-log.jsonl is append-only from the script's side, not from yours. A text editor can change any line in the file; the script simply refuses to be the one that does it for you.

Change revenue_ratio from 1.05 to 1.15

This is the field that was actually wrong. Everything else on the Week 3 line, total_hours, automated_hours, active_clients, recurring_revenue_pct, was correct the first time.

Save the file

No script runs. No command confirms the edit. The correctness of this step depends entirely on you having changed the right field to the right value, because nothing checks your work here the way log_week.py's guards checked the original submission.

That looks like the fix is done. It is not.

The gotcha: one field you hand-edited, one you didn't

revenue_efficiency_multiple is not computed fresh every time something reads the log. It was calculated once, at the moment Week 3 was originally logged, using the wrong 1.05 ratio, and that result, 1.2031, was written into the same line as a stored field. Hand-editing revenue_ratio to 1.15 does nothing to revenue_efficiency_multiple sitting a few fields over on that same line. Nothing in this design recalculates a derived field when you touch the input it was built from. The file only knows what you wrote into it.

A half-fixed line is a new, quieter version of the same bug

After editing only revenue_ratio, the Week 3 line reads revenue_ratio: 1.15 next to revenue_efficiency_multiple: 1.2031, a value computed from 1.05. The input is now correct and the output is now wrong in a new way: it disagrees with its own row. This is arguably worse than the original mistake, because the original mistake was at least internally consistent, wrong input, wrong-but-matching output. Now the row contradicts itself, and a reader would have to recompute the formula by hand to notice.

The complete fix requires calculating revenue_efficiency_multiple yourself, the same formula from Lesson 4, using the corrected inputs: (revenue_ratio / total_hours) / (baseline_revenue_ratio / baseline_hours), or (1.15 / 48) / (1.0 / 55), which comes out to 1.3177. That value has to be hand-edited into the same line, alongside the corrected revenue_ratio. Skip that second edit and the log is still wrong, just wrong in a way that is harder to spot than the first version, because now it looks edited rather than simply mistaken.

Why the script doesn't just fix this for you

This is a real, current limitation of the design, worth naming plainly rather than working around it in this lesson. report.py reads whatever is stored on each line and prints it; it does not recompute revenue_efficiency_multiple, automation_index, or any other derived metric from the raw inputs at read time. Storing the computed value once, at log time, rather than recalculating it on every report, was a reasonable choice for a script that is supposed to run in under a second on a plain text file with no dependencies. It also means a hand-edit anywhere upstream of a derived field requires a second, manual, easy-to-forget hand-edit downstream of it, and nothing in this repo checks that the two agree. A future version of this skill could have report.py recompute every derived field from the stored raw inputs on every run, instead of trusting whatever number was written at log time. This course ships the tool as it actually behaves today, not a hypothetical fixed version of it, because teaching around a real gap is worse than naming it.

Quick check — You hand-edit a wrong revenue_ratio on a logged week's JSONL line and save the file. Is the fix complete?

What this week actually teaches

A script that refuses to overwrite history is doing its job even when that refusal is inconvenient. The honest fix was never going to be "run the command again." It was always going to be a deliberate, visible hand-edit, in a plain text file you can open and read, of exactly the fields that were wrong, and only the fields that were wrong. That second part is the one this lesson exists to catch you on: a derived field does not know its input changed. You have to tell it.

Continue to Lesson 09

One bad week, fixed by hand, correctly. Lesson 9 runs the same weekly loop nine more times and shows what changes when there's real range in the data to read.

Have a question about this lesson?

Reply here and it goes straight to Rod. Same as replying to one of his emails.