Skip to content
C.W.K.
Stream
Lesson 02 of 04 · published

Wake on Evidence

~13 min · observability, edge-triggering, state-machines, coordination

Level 0Loose Note
0 XP0/36 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete

Five Wakes for Nothing

The backstop timers from the last lesson are the floor, not the plan. The plan is to look at an obligation when something happened: a worker's turn ended, a session vanished, a blocker was reported. The engine learns those things from its adapters, which watch each enrolled chat and report its status through Engine.observe_session.

The first version of that function was simple. On any observation of idle, disconnected or exited, it pulled every matching obligation's due to now. Three days into production, the 2026-09-30 review read the log and found that five of the chief's early wakes, on 2026-09-29 and 2026-09-30, each followed an adapter's host event that rewrote engine_obligations.due within five seconds. None of them was a worker finishing anything. Every one was an adapter that had just restarted and, on its first cycle, reported the status the engine already had stored. An adapter does that by design: it does not know what the engine remembers, so it says what it sees. The engine heard "idle" and treated it as news.

An Observation Is Not an Event

The repair is one comparison, and the reasoning behind it is worth more than the code. observe_session now computes changed = stored != new and acts only on a real transition. Repeating the stored status still refreshes the row's timestamp, but it changes nothing else and wakes nobody. The docstring keeps the incident on the record: "repeating the stored status changed nothing and must not wake the chief (five of the early wakes of 2026-09-29/30 were exactly that)."

For that comparison to work from the very first reading, a new enrollment starts in status unknown rather than the column default idle, and a retired session that enrolls again is reset to unknown as well. Its first real observation is therefore a transition, never a repeat.

Which Transitions Owe a Review

Even a real transition is not automatically evidence. Here is exactly what the engine does, for each active binding on the session whose obligation is pending and not parked:

  • To disconnected or exited: the obligation's due becomes MIN(due, now) at once, and the engine queues a session_disconnected or session_exited notification for Dad listing the bound items. A worker that vanished while holding work is something Dad hears about.
  • To idle, on an obligation the chief has never reviewed (its reviewed column is still empty): the review is pulled forward. A turn ended and nobody has looked yet; that is enough.
  • To idle, on an obligation the chief has reviewed before: the review is pulled forward only if the worker left a note on that dispatch after the last review. No new note, no wake. The chief already looked at everything this worker had said.
  • To busy, waiting or unknown: no review. (In Coop, waiting is the adapter's own delivery state, watching for a report, not the worker waiting on anyone.)

The idle check can rely on notes because of an ordering the adapter guarantees: it commits a turn's reports and notes before it reports the turn's end. By the time the engine sees the idle transition, anything that turn said is already in engine_notes. Reports do not need this path at all. A blocked report pulls its own obligation to now the moment it is stored, and a done, released or abandoned report resolves it outright.

One more reading never wakes anything: the chat's native activity (working, idle, needs input, unknown). observe_activity is documented as "Records only; it never wakes the chief or touches work." It exists so the chief and Dad can see what the chat is doing, which is a different question from whether a decision is owed.

Evidence, Then the Backstop

Put the two lessons together and you get the architecture's sentence in full: a review is owed on evidence, never on a repeated observation. An idle transition with something new to read asks for one. A lost session asks at once and tells Dad. A blocked report asks at once. Behind all of it stands the backstop, two hours after a managed acceptance and three after a CLI take, and the chief's own deferral is respected in between.

Notice what is not on that list: elapsed time as a reason to close, idle as a reason to close, silence as a reason to close. Evidence decides when the chief looks. It never decides what the chief concludes; that is the next lesson.

A review is owed on evidence, never on a repeated observation. If the same reading arriving twice can trigger the same work twice, you have built a system whose behavior depends on how often its sensors restart. Trigger on the change, then ask whether the change carries anything the decider has not seen.

Code

Excerpt from Coop's Engine.observe_session (trimmed to the wake decision; comments as in the source)·python
now=time.time()
changed=session['status']!=status
...
if changed and status in ('idle','disconnected','exited'):
    active=[dict(r) for r in conn.execute("SELECT * FROM engine_bindings WHERE session_id=? AND state='active'",(session_id,))]
    for binding in active:
        obligation=conn.execute("SELECT * FROM engine_obligations WHERE binding_id=? AND status='pending' AND parked=0",(binding['id'],)).fetchone()
        if not obligation:
            continue
        if status=='idle' and obligation['reviewed'] is not None:
            # The adapter commits a turn's reports and notes before it
            # reports the turn's end, so a review is owed only when
            # that turn left something the chief has not seen.
            fresh=conn.execute('SELECT 1 FROM engine_notes WHERE dispatch_id=? AND created>? LIMIT 1',
                               (binding['dispatch_id'],obligation['reviewed'])).fetchone()
            if not fresh:
                continue
        conn.execute('UPDATE engine_obligations SET due=MIN(due,?) WHERE id=?',(now,obligation['id']))
    if active and status in ('disconnected','exited'):
        self._enqueue(conn,None,None,'attention',{'reason':'session_'+status,'session_id':session_id,
            'items':[{'kind':b['kind'],'id':b['item_id']} for b in active]})
A minimal sketch of the same decision as a pure function, replayed against the cases that matter·python
def review_now(stored, new, reviewed, newest_note):
    """Does this observation pull an unparked obligation's review forward?

    stored, new  -- the session status before and after the observation
    reviewed     -- when the chief last looked (None: never)
    newest_note  -- when the worker last left a note on this dispatch (None: never)
    """
    if stored == new:
        return False                      # a repeat is not evidence
    if new in ('disconnected', 'exited'):
        return True                       # a lost session: look at once
    if new != 'idle':
        return False                      # busy, waiting, unknown: nothing to judge
    if reviewed is None:
        return True                       # never looked at: the turn's end is enough
    return newest_note is not None and newest_note > reviewed

cases = [
    ('adapter restart repeats idle', ('idle', 'idle', 100.0, 50.0),   False),
    ('turn ends, never reviewed',    ('busy', 'idle', None, None),    True),
    ('turn ends, nothing new said',  ('busy', 'idle', 100.0, 90.0),   False),
    ('turn ends with a fresh note',  ('busy', 'idle', 100.0, 140.0),  True),
    ('session exits',                ('idle', 'exited', 100.0, None), True),
    ('session goes busy',            ('idle', 'busy', None, None),    False),
]
for name, args, expected in cases:
    got = review_now(*args)
    assert got == expected, name
    print(f'{name:30} -> {got}')

External links

Exercise

Find a trigger in your own setup that reacts to a status: a CI webhook, a health check that pages someone, a file watcher, a cron job that checks "is it done yet". Write down what happens when the same status is reported twice in a row, for example after the watcher restarts. Then write a small function in the shape of the sketch above that takes the stored status, the new one and whatever 'new evidence' means in your case, and replay at least four cases through it, including a restart that repeats the stored status.
Hint
The hard part is naming the evidence. For a CI trigger it might be a new commit since the last run; for a pager it might be a different error than the one already acknowledged. If you cannot name anything that distinguishes the second report from the first, the second report should do nothing.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign in — Please sign in to comment.

No comments yet — be the first.