The Opposite of Noise
Every lesson in this track so far took something away from Dad's attention: a job that is not a turn, a report that waits its turn, a mirror that copies only its own, a line about one item that rings once. Quiet has a failure of its own, though. A line that asks Dad to decide something rings once, sinks under the next twenty, and the decision waits for a reminder nobody sends. On 2026-10-26 a reply Pippa had drafted in Herald, the engine behind her voice on YouTube, had waited 38.7 hours for his approve. Its one Telegram line came when she wrote it, was buried under Coop notices, and nothing ever said it again. Dad, in Granada:
"스캔할 때 승인 안 된 답글 있으면 계속 알려줘야 해, 치프도 알아야 하고. 안 그럼 까먹고 몇날 며칠 갈 수도 있어."
"When a scan finds a reply that hasn't been approved, you have to keep telling me, and the Chief has to know too. Otherwise I'll forget and it can go on for days."
— 아빠 (Dad), 2026-10-26, translated from Korean
So the answer is the inverse of the last lesson's settle window: one line that does not go away until the decision is made.
One Root, Four Gates
services/waiting_for_dad.py asks one question of every place where work waits for Dad's decision, and the question is a class. WaitingSource is an abstract root with one method, waiting(), which returns every item that waits as a WaitingItem: its source, an id, a one-line label, a link, the time it started waiting, and whether Dad himself is holding it. Four children answer it today:
HeraldDrafts: Herald drafts waiting for his approve, read from Herald's own summary. A draft he held is reported as held.JournalEntries: Pippa Journal entries waiting for his approve, approved but not yet published, or whose publish failed; held entries likewise.SiteEscalations: cwk-site comments and Soul Stream posts that Maia's review handed to him and that neither he nor Maia has decided.CoopParked: Coop obligations the chief parked for Dad, read from Coop's ownparkedflag and never worked out again here.
A new gate is one more child and one more row in SOURCES; nothing that reads the list changes. The module's docstring names the rule it follows, the family's Fifth Rule (non-object-oriented architecture is a sin): one parent that says what every gate must answer, children that each know how their own gate is read, and consumers that know only the parent.
One Living Message
refresh() reads every source at once and tries to keep one reminder on Telegram. While anything waits, it sends a fresh message listing everything, oldest first, each item with its age and link, and then deletes the previous reminder, so the message on Dad's phone is normally the latest and does not pile up. Two limits remain in the code. The Telegram helper cuts every message at 4,000 characters and there is no second page, so on a very long list the header still counts every item while the last items, and the unread note, fall off the end. And the delete's answer is not checked: if Telegram refuses it, the old reminder stays on the phone while the state already points at the new one, and nothing tries that delete again. What happens depends on what changed since the last one:
| What changed | What Dad's phone gets |
|---|---|
| Something new started waiting | A new reminder at once, with sound |
Nothing new, and the last reminder is 55 minutes old (REPEAT_S, a little under the hourly Herald scan) | A new reminder, with sound |
| Something only left the list, and the last reminder is under 55 minutes old | A replacement without sound; the hourly clock stays where it was (past 55 minutes the same change counts as a repeat: with sound, and the clock restarts) |
| Nothing waits any more | The last reminder is deleted and nothing is sent |
| Any of these between 23:00 and 08:00 where Dad is | Sent without sound |
"Where Dad is" means the zone his device last reported (dad_location.dad_clock_zone), with Seoul as the fallback; that week he was in Spain, and a Seoul night is a Granada afternoon. If a send fails, the old reminder stays and the next tick tries again. Items Dad holds himself are his own decision to wait, so they stay out of the reminder. The reminder is in Korean, because Dad reads it; the second code block below shows one.
An Unreadable Gate Is Not an Empty One
Three sibling engines and a hosted database can each fail on their own. When a source cannot be read in time, read_sources keeps that source's last known items and names it in the reminder as unread. It never guesses empty. An empty answer from a broken gate would delete the reminder, and the one decision that should stay in sight would vanish exactly when something else had gone wrong. Lesson 1 of this track made the same choice for approval snapshots: an unavailable snapshot is unknown, never an empty queue.
The Chief Knows, in One Line
Dad asked for the Chief to know as well, and the sanctuary rule (Track 2, lesson 6, "The Chief Is a Sanctuary") decided how. A stored reminder row would sit in the replay, repeat every hour, and cost every later turn. So nothing is stored. chief_line() builds one line from the last refresh, and master_chief.turn_context_block adds it to the turn's own context, after the origin line and the reasoning note and before the turn's notes, only when something waits. The line counts items by source, gives the oldest age, the ids and anything Dad holds, says how long ago it was checked and which gates were unread, and stays within 400 characters (CHIEF_LINE_BUDGET), dropping the ids first when it must. It reads the state file the last refresh wrote, so nothing on the turn's path touches the network, and the cached prefix does not move, because the turn context rides with the current message only (Track 3, lesson 7, "One Prefix From Every Doorway").
When Dad Answers
A reminder that outlives the decision is noise again, so an item has to leave the list where Dad's answer lands. For Herald, the Journal and the site, his decision in their own app is the answer, and the next read no longer finds the item. For Coop the path is longer. Dad answers the Chief, the Chief relays his words to the work with a coop reply, and until 2026-10-26 a reply settled nothing about the park: the reminder kept listing #662 and #666 every hour after Dad had answered both. The fix is Coop's (cwkCoop ae26639). A reply on the work from anyone but its bound worker unparks the pending parked obligation in the same transaction, keeps its review time and records the disposition as answered; a later park is Dad's again, and at start the engine unparks any park a reply has already answered. Pippa's side (b4703081) only wrote the rule down and tested it: CoopParked keeps reading Coop's flag and never works it out for itself, so the reminder, the Chief's line and Coop's own context agree.
No Model Anywhere
Nothing here calls a model. The re-check rides the sources' own scheduled ticks: at the end of every cron run the heartbeat calls after_tick, which starts a background refresh when the run was one of four (SOURCE_TICKS: Herald's comment scan, the Journal's rethink gate and Maia's two reviews) and never raises into the cron. The heartbeat's crons run only on the Pippa machine (Track 2, lesson 7, "The Room Is a Role, Not a Mac"), so there is one reminder, not one per Mac. PIPPA_WAITING_FOR_DAD=0 closes every seam, and under the test runner they stay shut unless a test opens them.