Context
Split from #15405 (night-shift re-invocation guarantee) per the honest-close-target discipline — the same shape as the #15379→#15407 precedent, and mechanically forced by the PR-body rule (every ready agent PR carries Resolves #N; the decision contract is complete and reviewable NOW while the wiring/watchdog arc is a separate implementation phase with its own config-contract question).
Scope (this leaf)
ai/daemons/orchestrator/scheduling/nightShiftPolicy.mjs — resolveHeartbeatMode, the pure three-tier hierarchy from #15405's Contract Ledger:
- An explicit operator setting wins outright in both directions — the policy never overrides
manualEnabled: true OR false ("wakes off, full stop" is respected); it fills only the ABSENCE of a decision.
- Presence-aware fills the unset gap (
policyMode: 'presence-aware'): operator inactivity ≥ threshold (default 40 min) flips night-shift heartbeats ON; a present operator stays quiet by default.
- Blindness is presence: a missing/garbage presence signal never auto-activates night mode.
Total function (injected clock, garbage-threshold fallback to the default, safe empty call, unknown policy modes degrade to legacy-manual quiet); greppable mode strings (manual-on/manual-off/night-shift/day-quiet) for pulse-log forensics. Deliberately NO config touch — the tri-state config contract, pipeline wiring, dead-man watchdog, and full-night validation remain #15405's retained ACs per its implementation entry map.
Acceptance Criteria
Out of Scope
Everything #15405 retains (pipeline wiring at the swarmHeartbeat enabled-map seam, the tri-state config leaf under ADR-0019 + template-parity gates, the launchd/cron dead-man watchdog, the full-night post-merge validation window).
Related
Split-from: #15405 (retains the wiring arc; entry map on the ticket) · siblings: #15401/#15404 (the stop-economics pair this floor serves) · #15414 (wake-dispatch coalescing — SEPARATE by the recorded fold-or-separate call; composes at the config-discipline level only).
Decision Record impact: none (pure leaf; the ADR-0019 gate fires at #15405's wiring commit, which this leaf deliberately excludes).
Live latest-open sweep: checked latest 10 open issues at 2026-07-18T03:52Z; no equivalent. A2A in-flight claim sweep: my own [lane-claim]/[pr-opened] on this scope (MESSAGE:f3fb5bff); no competing claim.
Origin Session ID: 89818500-8a12-4162-b41f-8947703b1b06
Retrieval Hint: "resolveHeartbeatMode pure night-shift decision contract three-tier explicit-wins"
Context
Split from
#15405(night-shift re-invocation guarantee) per the honest-close-target discipline — the same shape as the#15379→#15407precedent, and mechanically forced by the PR-body rule (every ready agent PR carriesResolves #N; the decision contract is complete and reviewable NOW while the wiring/watchdog arc is a separate implementation phase with its own config-contract question).Scope (this leaf)
ai/daemons/orchestrator/scheduling/nightShiftPolicy.mjs—resolveHeartbeatMode, the pure three-tier hierarchy from#15405's Contract Ledger:manualEnabled: trueORfalse("wakes off, full stop" is respected); it fills only the ABSENCE of a decision.policyMode: 'presence-aware'): operator inactivity ≥ threshold (default 40 min) flips night-shift heartbeats ON; a present operator stays quiet by default.Total function (injected clock, garbage-threshold fallback to the default, safe empty call, unknown policy modes degrade to legacy-manual quiet); greppable
modestrings (manual-on/manual-off/night-shift/day-quiet) for pulse-log forensics. Deliberately NO config touch — the tri-state config contract, pipeline wiring, dead-man watchdog, and full-night validation remain#15405's retained ACs per its implementation entry map.Acceptance Criteria
>=boundary; the blindness battery null/undefined/NaN/string; legacy byte-preservation incl. typo'd-mode-degrades-quiet; garbage-threshold fallback; the empty-call no-throw contract).#15405's wiring lands.Out of Scope
Everything
#15405retains (pipeline wiring at theswarmHeartbeatenabled-map seam, the tri-state config leaf under ADR-0019 + template-parity gates, the launchd/cron dead-man watchdog, the full-night post-merge validation window).Related
Split-from:
#15405(retains the wiring arc; entry map on the ticket) · siblings:#15401/#15404(the stop-economics pair this floor serves) ·#15414(wake-dispatch coalescing — SEPARATE by the recorded fold-or-separate call; composes at the config-discipline level only).Decision Record impact: none (pure leaf; the ADR-0019 gate fires at
#15405's wiring commit, which this leaf deliberately excludes).Live latest-open sweep: checked latest 10 open issues at 2026-07-18T03:52Z; no equivalent. A2A in-flight claim sweep: my own
[lane-claim]/[pr-opened]on this scope (MESSAGE:f3fb5bff); no competing claim.Origin Session ID: 89818500-8a12-4162-b41f-8947703b1b06
Retrieval Hint: "resolveHeartbeatMode pure night-shift decision contract three-tier explicit-wins"