Back to the plannerMachine Learning LabSource on GitHub

How final cut works

A repair or replace planner built on tabular Q-learning, written from scratch in TypeScript, and checked cell by cell against an exact solver. No libraries, no server, a table of 198 numbers.

The problem

"Is it worth fixing my car" and "50% rule appliance" are common searches. The usual answer compares one bill with the item's value, or with half the price of a new one. A $4,000 repair on a car worth $2,500 fails that test, so the advice is to scrap it.

That test looks at one bill and forgets the rest. An old car will break again, and so will its replacement, just less often. Weighing those future bills is the textbook machine replacement problem, and its best answer is a threshold that moves with age and condition: fix bills under some amount, replace above it.

The model

One step is one year. State · age 0 to 10+ (11) × condition good, worn or failing (3) × this year's bill none, small or major (3) = 99 states. Actions · keep and pay the bill, or replace.

keep · cost = bill + downtime
replace · cost = price − max(0, resale − bill) + downtime
resale = price · (1 − loss)age · (1, 0.8 or 0.5 by condition)

A broken item sells as is, so its resale drops by the bill it needs. Downtime is paid on any breakdown, whatever you decide. Replacing starts the next year from a new item in good condition.

Each year the condition can slip one step, more likely as it ages, and never improves after a repair. The chance of a small or major bill depends on condition and climbs with age at the rate you pick (low, med or high), capped at 95% a year. Bill amounts are drawn evenly from your ranges.

Reward · minus the year's cost divided by the replacement price, so every item lands on the same scale. There is no end state. Each simulated life runs for your horizon and then stops, and the learner still looks ahead past the last year, since the item does not vanish when the simulation does.

The learner

Every life starts in a random one of the 99 states, so the rare ones, like a failing item under a year old, get visited too. Each year the learner nudges one table entry toward a better estimate.

Q(s, a) ← Q(s, a) + α · [ r + γ · maxa′ Q(s′, a′) − Q(s, a) ]

s is the situation, a the call, r the reward, s′ next year. The bracket is the gap between what the learner expected and what it now believes.

The bold director is Q-learning, as above. It learns the value of always making the best call, even while it explores. The cautious director is SARSA, which uses the call it will actually make next, random tries included.

bold (Q-learning) · target = r + γ · maxa′ Q(s′, a′)
cautious (SARSA) · target = r + γ · Q(s′, a′taken)

Here they end up close, because a wrong call costs money but never ends the story. SARSA reached 90% agreement more slowly on the phone preset and about as fast on the others.

knobdefaultwhat it does
alpha0.02Step size. Small, because bills are random and a big step chases noise.
gamma1 / (1 + rate)Discount. Set by your discount rate, 0.952 at 5%.
epsilon1.0 → 0.1Chance of trying the other call. Starts fully random.
decay0.9995 per lifeEpsilon is multiplied by this after every simulated life.

Rehearsal wraps after 150,000 lives, about ten seconds at steady speed, because each life is only a handful of table updates.

The exact check

The same model is small enough to solve exactly. Value iteration uses the expected bill for each size and the full transition probabilities, and sweeps all 99 states until nothing moves by more than 10−10.

V(s) ← maxa [ −cost(s, a) / price + γ · Σs′ P(s′ | s, a) · V(s′) ]

The cut list outlines every cell where the learner's call differs from this answer, and the honesty panel counts the matches. The verdict sentence also comes from the solver. Because the bill only changes this year's cost, the exact rule has a closed form.

K = price · (1 + γ · (E[V after keeping] − E[V after replacing]))
keep if max(bill, resale) < K, otherwise replace

If the resale alone is above K, sell now even without a bill. For the car preset, K by age and condition:

conditionnew4 years8 years
good$15,000$10,550$8,250
worn$11,100$5,900$4,500
failing$6,450$3,350$3,050

At 9 years and worn, K is about $4,350 against a resale of $2,800. The $4,000 repair that the 50% rule would refuse is worth paying, just.

Real results

Measured by running the same code in Node, 20 seeds, default knobs, 150,000 lives each. Agreement counts all 99 cells, untried ones as misses.

presetbold, mediancautious, medianlives to 90%, bold
Car96% (94 to 98)97% (94 to 99)65,000
Phone91% (88 to 94)90% (86 to 92)95,000
Laptop94% (91 to 97)94% (90 to 97)75,000
Fridge98% (96 to 100)98% (97 to 99)45,000

Costs for the car preset, 9 years old and worn, over 10 years at 5%, averaged over 3,000 simulated futures shared by every plan, minus the resale at the end.

Exact plan$16,530
Learned plan, after 150,000 livesabout $16,940
Drive till it dies$16,720
50% rule$17,660
Replace every 6 years$20,050

The exact plan saves about $1,130 over the 50% rule here. The learned plan costs about $400 more than the exact one, even at 96% agreement, because it only knows a bill is major, not whether it is $2,000 or $5,000. On the phone, laptop and fridge presets the gap was under $50.

Failure modes

Big steps. With α = 0.1 the car agreement after 150,000 lives ranged from 89% to 95%. Random bills keep shoving the table around, and the cells near the threshold flip back and forth.

No exploration. Letting ε fall to 0 barely mattered (94% to 95% on the car). Random starting states already reach every cell, and a table that starts at zero when every real outcome is a cost makes untried calls look good, so the learner tries them.

Near ties. Most disagreements sit where keeping and replacing cost almost the same. They look alarming on the cut list and barely move the bill.

Limits

Only as good as your numbers, not financial advice. The breakdown curves are a simple shape scaled by one low, med or high choice, not data from any make or model. Condition never improves after a repair, ages stop at 10+, the bill in a year is one lump, and the replacement is assumed to behave like a new copy of the same thing at today's price.

The plan is for owning one of these going forward. The horizon only sets how far the cost comparison looks, so a shorter horizon does not make the plan cash out early. Everything runs in your browser, and your numbers are saved only in its local storage.