Hidden state machines in Chorslo

Seven places where a mode lives in scattered flags, timers or status text. Six have a failure you can reach today. Each gets a version with named states that removes it.

Claude audit of main at 9bbcb99. Every failure below is traced by reading the code. Nothing was run or reproduced on a wall.

Streaks

A broken streak keeps showing its old number.

Today

The wall shows the count and never reads the date. The product doc says a broken streak "just stops showing."

Explicit

One rule decides alive or broken. The wall and the save both use it, so the wall only shows a streak that is alive.

Question for you: "yesterday" means the calendar day. A weekday-only routine reads Friday as two days ago on Monday, so its streak restarts every week and can never reach 7. Is that what you want?

Token counter

After a reward game, the token counter never settles.

Today

Until that kid's next earn, the wall skips app updates and replays the count-up whenever the balance changes.

Explicit

Events move it forward. The seven timers and their guessed durations go away.

Fun task

An abandoned fun task comes back in the next routine.

Today

The timer returns with a fresh countdown, and Done submits the old task. The closed stale-task ticket fixed this for regular tasks only.

Explicit

One rule covers every screen that holds a task. A failed save goes back to the task with Done still there.

Wake-up

A failed wake-up save still celebrates, then leaves a dead button.

Today

At 10:00 the gate lapses and Good Morning covers the whole wall until someone dismisses it.

Explicit

A failed save returns to a live button. Good Morning needs a saved wake-up.

Mission screen

Exit an untimed Mission, reload the wall, and Done is refused on every tap.

Today

The Mission is paused on the server. The wall forgot the kid exited, so it shows Done with no Resume. Starting and ending Screen Time does the same as a reload.

Explicit

One function names the screen. The stage and the update check read the same answer.

Parent access

Coming back to the admin tab restarts 26 separate parent checks.

Today

While they run, Token Log blanks and reloads and Store setup drops unsaved edits. A network blip reads as signed out.

Explicit

One answer, read by every page. A recheck keeps the page on screen. A failed check gets a retry, with no login redirect.

Your call before any build: when a recheck fails, does the page stay up or come down?

Mission day

A Mission day has 9 statuses, and "finished" is spelled 4 different ways.

Today

No failure traced. The cost lands on the next change: two expiry lists already leave out selected, and the write to completed accepts any starting status.

Explicit

The 16 allowed moves, written once. Anything else fails loudly. This table is the audit's reconstruction and needs a check against production rows first.

Also found

WhereTodayExplicit versionSize
Today's task listA task added or a day changed at 3pm reaches the wall at the next reload or midnight. Cleanup is hand-written in six database functions.One sync function that every routine edit calls.M
Token balanceThree separate calculations of the expected balance. On Nov 7 the app's copy stopped at 1,000 rows and showed a false mismatch.One total in the database, read by the banner, the Fix button and the script.S to M
Give and take tokensNo request ID, so a retry after a dropped response can apply twice. The "retry the same request" pattern is hand-built about a dozen times elsewhere.One shared command hook, then a request ID on the token commands.S, then M
PurchasesThe browser picks which accept command to run, and every refusal comes back as a bare "false".One resolve command that names its refusal reason.S to M
Mission cancel"Cancel the run, give the Mission back" is copied in six database functions. Two more skip the second half.One cancel function.M
Routine editorNew routines save in order with retry. Saved routines send unordered writes and fail silently.One save queue for both.M
Reward gamesSeven games each rebuild wait, play, settle, report once. Pick a Box can restart its reveal on a background refresh.A stable callback first, then one shared lifecycle.S, then M
Strip viewThe "which screen" ladder is written twice and kept in sync by a comment and tests that read source text.One function and a switch that must cover every case.S
Overlay queueSteps are typed. The queue mechanics live inside the page component.A small reducer with real tests.M
Routine completion"Finished on time" exists only in one tap's response. A lost response means no celebration, streak or reward game.A stored completion row.M to L
Routine deleteThe docs say never delete a routine directly. The database allows it and deletes the streaks with it.Revoke delete and guard the two lifecycle columns.S
Station channelFree text. A typo means the frame quietly never updates.A database check on the two valid values.S

Three parts of the repo already work this way and are the pattern to copy: the Screen Time alert reducer (screenTimeAlertContracts.ts), the Done button flow (taskDoneFlow.ts) and kid archiving (admin_kid_lifecycle). About 60 other places were checked and left alone.

Copy your picks

Pick Build, Later or Skip on any of the seven above, then paste the result into the chat with Claude.

Nothing picked yet.