[object Object]

← back to Homesonspec

Poller: notify() must never be able to fail its caller

471d1568d5d3d46464f81476059eade94c83ee37 · 2026-09-13 16:25:48 -0700 · Steve

My previous commit moved notify() BEFORE the log/state write so alert_delivered
lands in latest.json for fleet-health-rollup. That made bookkeeping able to break
the measurement: a throw in the new cncp_post shell-out would cost the observation
AND leave a stale state file, which then re-fires the same "change" next run.
_shared/alert_receipt.sh states this rule in its own header; I violated it.

Wrapped in try/catch returning false. Proven on the LIVE path with a clean runtime
dir (previousState=null forces stateChanged=true so notify actually runs):
state persisted, alert_delivered=true, real runtime dir untouched.

Noted honestly: the success path is proven; the catch is belt-and-braces, since a
missing helper makes `bash -c '. helper && …'` exit nonzero rather than throw.

Two earlier attempts at this test were vacuous and are recorded so they are not
repeated: --fixture skips notify entirely (`&& !fixturePath`), and repointing HOME
breaks ipa-status's key lookup before notify is ever reached.

TK-11155

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BPS3gnB4H5MQKmWcHKvuf6

Files touched

Diff

commit 471d1568d5d3d46464f81476059eade94c83ee37
Author: Steve <steve@designerwallcoverings.com>
Date:   Sun Sep 13 16:25:48 2026 -0700

    Poller: notify() must never be able to fail its caller
    
    My previous commit moved notify() BEFORE the log/state write so alert_delivered
    lands in latest.json for fleet-health-rollup. That made bookkeeping able to break
    the measurement: a throw in the new cncp_post shell-out would cost the observation
    AND leave a stale state file, which then re-fires the same "change" next run.
    _shared/alert_receipt.sh states this rule in its own header; I violated it.
    
    Wrapped in try/catch returning false. Proven on the LIVE path with a clean runtime
    dir (previousState=null forces stateChanged=true so notify actually runs):
    state persisted, alert_delivered=true, real runtime dir untouched.
    
    Noted honestly: the success path is proven; the catch is belt-and-braces, since a
    missing helper makes `bash -c '. helper && …'` exit nonzero rather than throw.
    
    Two earlier attempts at this test were vacuous and are recorded so they are not
    repeated: --fixture skips notify entirely (`&& !fixturePath`), and repointing HOME
    breaks ipa-status's key lookup before notify is ever reached.
    
    TK-11155
    
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01BPS3gnB4H5MQKmWcHKvuf6
---
 ops/apple-review-poller.mjs | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/ops/apple-review-poller.mjs b/ops/apple-review-poller.mjs
index 7d1f0bda..cebb7fed 100644
--- a/ops/apple-review-poller.mjs
+++ b/ops/apple-review-poller.mjs
@@ -67,6 +67,12 @@ function notify(state, outcome) {
     '-e', 'display notification ' + JSON.stringify(message) + ' with title "Homes on Spec"',
   ]);
 
+  // HARD RULE, mirroring _shared/alert_receipt.sh: notifying must NEVER be able to fail the
+  // caller. This runs BEFORE the log/state write (so alert_delivered lands in latest.json for
+  // fleet-health-rollup), which means a throw here would cost us the observation itself and
+  // leave a stale state file that re-fires the same "change" next run. Bookkeeping must not
+  // be able to break the measurement.
+  try {
   const helper = `${process.env.HOME}/.claude/skills/_shared/cncp_post.sh`;
   const posted = spawnSync('/bin/bash', [
     '-c',
@@ -75,6 +81,9 @@ function notify(state, outcome) {
   ], { encoding: 'utf8', timeout: 30_000 });
 
   return posted.status === 0;
+  } catch {
+    return false; // could not deliver; the caller still records and persists its observation
+  }
 }
 
 // Only an APPROVED outcome may disarm this monitor.

← 043c09b7 Apple review poller: stop disarming itself while awaiting Ap  ·  back to Homesonspec  ·  Publish a fleet-health heartbeat: this poller was invisible ed938c0f →