#2020 feat(nurture): arm needs-help-after-a-failed-run (NEEDS HELP)
Opened by keeb · 9/4/2026
Parent: the product-nurture epic. Arms whiteboard flow #6 — NEEDS HELP.
A workflow run, model method run, or any command failed, and then
nothing happened. They hit a wall and walked away. This is the highest-value
message in the set and the hardest to qualify, because it is the only one that
cannot be answered from a rollup.
Qualification
needs_help_failure: a cli_invocation with result_status = 'error',
followed by ≥3 days with no further activity on any bound device.
occurrenceKey is the UTC date of the failing invocation, with a 30-day
cooldown. Someone who gets stuck twice, months apart, is legitimately asked
twice; someone stuck once is asked once.
Why this one needs swamp.events
cli_daily filters result_status = 'success' by construction, so it can
never see a failure. This flow reads swamp.events directly, filtered on the
materialized result_status column — never a properties parse, which is
banned everywhere and would be ruinous here.
That makes this the most expensive read in the epic. It is affordable only because identification is a nightly batch. Two guards:
- The read is bounded by a day floor placed inside the branch, so it prunes
whole monthly partitions (
swamp.eventsisPARTITION BY toYYYYMM). - The static sweep from A2 must cover this module specifically — a per-identity raw-events read reaching a request path is the #1317/#1586 failure, and this is the one module in the epic shaped like the bait.
Record rows-read and bytes-read for this query on the issue before arming.
Copy risk
The message names the command that failed. That is what makes it useful and what makes it dangerous: if the identification is off by one invocation, the email tells someone their working command failed. Verify the named command against the actual event for the first cohort, by hand, one row at a time.
And "need help?" is a promise. Name the address that receives the replies, and confirm someone is reading it, before this ships.
Verification
- Fixtures: a failure followed by activity on day 1 (must not qualify); a
failure followed by silence through day 3 (qualifies); a failure on a
collective:grain (must not appear). - A captured-SQL assertion:
result_status = 'error'on the materialized column, a day floor inside the branch, and noJSON*(properties, …). - In production: for every recipient in the first cohort, confirm the named command matches a real failed invocation and that no later activity exists.
In Progress
Click a lifecycle step above to view its details.