Skip to content

Night-shift re-invocation guarantee: presence-aware wake policy + heartbeat floor #15405

Description

@neo-fable

Context

Operator directive, 2026-07-18, completing the stop-hook investigation: "we also must honor night shift mode. if no operator is online, it would be bad if the team idles out." This is the third leg of the set #15401 (dialogue quadrant) + #15404 (autonomous material-artifact stop key) — both of which explicitly scope re-invocation OUT. The hook audit (48h log, converged independently by two seats) proved the structural fact this ticket owns: a Stop hook can refuse a stop but cannot create a turn. Every allowed stop — dialogue, clean-terminal, material-artifact, or the harness force-override ceiling — is PERMANENT while nothing re-invokes the seat. With wakes currently disabled, #15404's healthy duty cycle (work → artifact → rest) becomes a slow fleet shutdown: each seat earns one legitimate rest and never returns.

The Problem

Night shift is currently a manual operator act (wakes toggled by hand) with no liveness floor:

  1. No presence-aware policy. The wake daemon is on or off globally, by hand. When the operator walks away without flipping it, the fleet's turn supply dies with the dialogue: every seat's last turn ends in a (correct) allowed stop, and no autonomous turn ever begins. The observed fleet-wide mid-lane idling was exactly this — 155/155 allows in 24h rode operatorInLoop=true while wakes were off.
  2. No daemon liveness guarantee. If the wake daemon dies at 03:00, heartbeat pulses stop, the fleet sleeps, and NOTHING alerts — the FM cockpit's wake-telltale (the shipped S2 axis) surfaces daemon state to a human who, at night, is not watching. The NightShiftLeasedDriver contract's three-heartbeat critical-failure detection cannot fire when heartbeat DELIVERY itself is the dead component (learn/agentos/wake-substrate/NightShiftLeasedDriver.md §4.1 explicitly scopes this out: "does not reclassify upstream wake skips").
  3. The noise objection that disabled wakes is solved but unconsumed. The #15376 sender-principal-class semantics (merged) make agent chatter durable-quiet by default with wake as a deliberate election, per the D#15372 AC-7 ruling ("the preferred sending mode is NOT a wake prompt which arrives too late as noise"). The disable predates the fix.

The Architectural Reality

  • Wake delivery + idle-out recovery: owned historically by #10671 (CLOSED — the substrate exists: Orchestrator heartbeat sweeps active WAKE_SUBSCRIPTION identities per pulse). The daemon: ai/daemons/wake/daemon.mjs; PID surface: memory-core config wakeDaemon.dataDir + wake-daemon.pid (already consumed by FleetManager.wakeStateOptions in ai/services/fleet/devFleetServer.mjs).
  • The night-shift ownership contract: NightShiftLeasedDriver.md (#10763, CLOSED) — driver leases, obligations, three-heartbeat critical failure. All of it presupposes pulses arriving; §6: "a maintainer harness is night-shift reachable only when its route is active."
  • Operator presence signal already exists: who_is_online classifies @tobiu from activity recency (AgentIdentity accountType human, the #15378 stamp substrate). Presence-awareness needs no new sensor — only a policy consumer.
  • Class-suppression: MailboxService sender-class wake-suppression defaults (#15376, merged) — the noise-floor mechanism a re-enabled daemon rides.
  • The stop-economics pair: #15401 + #15404 define WHEN a seat may rest; this ticket defines WHO WAKES IT UP.

The Fix

Three thin, composable pieces (one PR each is plausible; bundle-by-default unless implementation splits naturally):

  1. Presence-aware wake policy (the mode switch becomes automatic). A policy leaf the daemon reads at pulse time: operator-activity recency > threshold (e.g. 30–45 min without operator-class activity) ⇒ night-shift mode — heartbeat pulses flow to all active subscriptions regardless of the manual quiet toggle; operator active ⇒ the manual setting governs (his noise budget, his hours). The policy consumes the existing presence signal; no new sensor. Manual override always wins in both directions (an explicit operator "wakes off, full stop" is respected — the policy fills the ABSENCE of a decision, never fights one).
  2. The heartbeat floor. In night-shift mode, a seat with an active subscription that has produced no turn in N minutes receives one heartbeat wake (mailbox-drain + lane-continue per the leased-driver obligations). Cadence conservative (e.g. 20–30 min) — the point is the floor's existence, not frequency; #15404's material-artifact key keeps the woken turn honest.
  3. The daemon dead-man guarantee. The wake daemon's own liveness gets an external watchdog: a launchd/cron-level respawn OR at minimum a stale-PID detector that (a) surfaces loudly in the FM cockpit wake-telltale AND (b) writes a [critical-failure]-class A2A broadcast on recovery so the morning operator sees the outage window. A dead wake daemon at night must never be silent.

Contract Ledger Matrix

Target Surface Source of Authority Proposed Behavior Fallback Docs Evidence
wake daemon pulse policy ai/daemons/wake/daemon.mjs + memory-core wakeDaemon config subtree presence-aware mode resolution at pulse time (manual override > policy > default) absent presence data ⇒ current manual behavior unchanged (fail-open to today) daemon JSDoc + NightShiftLeasedDriver.md amendment this investigation's audit-log analysis
operator presence read who_is_online / activity-recency substrate (#15378 stamps) read-only consumption; threshold configurable unreadable ⇒ treat operator as PRESENT (conservative: no auto-night-mode) policy leaf JSDoc existing roster classification
heartbeat floor Orchestrator heartbeat sweep (#10671 substrate) per-seat quiet-time floor in night mode only subscription inactive ⇒ seat unreachable (unchanged; the OpenCode gap is #15394's) same subscription-sweep precedent
daemon liveness watchdog PID file + FM wake-telltale (FleetManager.wakeStateOptions) external respawn or loud stale-PID surfacing + recovery broadcast watchdog itself dead ⇒ cockpit telltale still shows stale PID (existing) ops note S2 axis shipped surface

Acceptance Criteria

  • Night-shift mode engages automatically after the operator-inactivity threshold and disengages on operator return; manual overrides win in both directions — unit-tested on a pure policy function with injected clock/presence.
  • In night mode, a quiet active-subscription seat receives a heartbeat within the floor cadence; in day mode with wakes manually off, NO heartbeat fires (the policy never fights an explicit decision) — both pinned.
  • Daemon death during night mode is externally detected: stale PID surfaces in the cockpit telltale AND a recovery broadcast records the outage window — witnessed with a killed-daemon fixture.
  • #15376 class-suppression semantics unchanged: night-mode heartbeats are wake-class pulses, agent chatter stays durable-quiet — regression-pinned.
  • NightShiftLeasedDriver.md gains the delivery-floor amendment (§6 note: the reachability precondition this ticket guarantees) — doc AC.
  • Post-merge validation: one full night window (operator offline ≥ 4h) with ≥ 2 seats showing wake-driven turns and zero manual intervention — recorded on this ticket.

Out of Scope

  • The stop-hook quadrants (#15401 / #15404 own stop economics; this ticket never touches the hook).
  • OpenCode wake delivery (#15394 owns the adapter; until it lands, Phoebe's seat is reachable only by polling — a named, tracked gap).
  • Wake-noise policy changes beyond consuming the shipped #15376 defaults.
  • A dedicated driver-lease API (NightShiftLeasedDriver §6 substrate constraints stand).

Avoided Traps

  • Hook-side "night mode" (rejected): making the hook stricter at night cannot help — refusal without re-invocation ends at the harness force-override ceiling and then sleeps anyway. The lever is turn CREATION.
  • Operator-prose presence detection (rejected): presence = activity recency from the stamp substrate, never NLP over messages.
  • Always-max heartbeats (rejected): the floor is a floor; #15404's artifact economics + class-suppression keep the duty cycle honest without pinging seats that are mid-turn.

Decision Record impact

none — composes shipped substrate (#10671 sweep, #15376 classes, #15378 stamps, S2 telltale) under one policy; amends NightShiftLeasedDriver.md documentation only.

Related

Live latest-open sweep: checked latest 12 open issues at 2026-07-18T03:02Z; no equivalent (the #15401/#15404 pair scopes re-invocation out explicitly). A2A in-flight claim sweep at 03:03Z: no competing claim on this scope.

Origin Session ID: 89818500-8a12-4162-b41f-8947703b1b06

Retrieval Hint: "night shift presence-aware wake policy heartbeat floor dead-man daemon re-invocation"

Metadata

Metadata

Assignees

Labels

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions