Skip to content

fix(pulse): unblock the event loop, bound two child spawns, hoist the cron parse - #1736

Open
elhoim wants to merge 5 commits into
danielmiessler:mainfrom
elhoim:fix/pulse-modules
Open

fix(pulse): unblock the event loop, bound two child spawns, hoist the cron parse#1736
elhoim wants to merge 5 commits into
danielmiessler:mainfrom
elhoim:fix/pulse-modules

Conversation

@elhoim

@elhoim elhoim commented Aug 3, 2026

Copy link
Copy Markdown

5 commits, one per fix, so each can be cherry-picked independently. Each was verified to apply cleanly onto 47df8ee by itself.

Commit Fix
d3d7f20 stop hypotheses blocking the event loop
2ce4dc2 drain stderr and bound the atlas insights spawn
44815ef parse the cron expression once per scan, not once per minute
c7dbe94 fail loud on an output target this build no longer handles
8d92c6b stop the menubar rendering "NaNd" for a down sidecar

Five defects in the Pulse server modules. Two are regressions of bugs this same release fixed elsewhere.

  • modules/hypotheses.ts:180execFileSync with a 120s timeout inside an HTTP handler blocks Bun's single-threaded event loop; /healthz, the dashboard and hook validation all stall behind it. Matches the async shape this release already applied to modules/bunker.ts.
  • modules/atlas.ts:48stderr: "pipe" never drained and no timeout, so >64KB on stderr deadlocks the request and wedged children accumulate on every uncached poll. Matches the modules/work.ts fix from this same release: drain both streams concurrently under a kill timer.
  • lib.ts:348mostRecentOccurrence re-parsed the cron expression on every one of up to 10,080 minute-steps. The parse, not the field test, was the whole cost. Hoisted out of the loop; matchesCron's public signature is unchanged.
  • lib.ts:468telegram was removed from OutputTarget with no default: branch, so a config upgraded from an older version keeps those jobs, sends nothing, and still reports success. Now logs an error.
  • modules/menubar.ts:352 — a clamped value was used for tsMs but the raw NaN reached agoFrom, rendering "Hermes sidecar down — NaNd". Clamps once and uses it for both.

modules/upgrades.ts is in the diff for one reason only: making graduateHypothesis async requires its caller to await. Not a drive-by.


Testing. Commands and output are in the per-file notes above. I did not do a fresh-system install verification (contributing step 3) — these are targeted fixes verified per-file, not an install run.

elhoim added 5 commits August 3, 2026 07:01
execFileSync with a 120s timeout inside an HTTP handler blocks Bun's single
thread; /healthz, the dashboard and hook validation all stall behind it, risking
a supervisor SIGKILL. Same shape this release already applied to modules/bunker.ts.

modules/upgrades.ts changes only because graduateHypothesis becomes async and
its caller must await it.
stderr was piped and never read with no timeout, so >64KB deadlocks the request
and wedged children accumulate on every uncached poll. Matches the modules/work.ts
fix from this same release.
…nute

mostRecentOccurrence re-parsed on every one of up to 10,080 minute-steps; the
parse, not the field test, was the whole cost. matchesCron's signature is unchanged.
telegram was removed from OutputTarget with no default branch, so a config
upgraded from an older version keeps those jobs, sends nothing, and still
reports the dispatch as a success.
The clamped value was used for tsMs but the raw NaN still reached agoFrom.
@elhoim
elhoim force-pushed the fix/pulse-modules branch from b1fdac7 to 8d92c6b Compare August 3, 2026 07:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant