diff --git a/.github/workflows/intake-canary.yml b/.github/workflows/intake-canary.yml index cb12301..a9a3890 100644 --- a/.github/workflows/intake-canary.yml +++ b/.github/workflows/intake-canary.yml @@ -134,16 +134,22 @@ jobs: fi # Shape guard: a 200 that is not the expected envelope is also a - # canary fault, not a healthy pipeline. - if ! jq -e '.data | type == "array"' "$ROUTER_BODY" >/dev/null 2>&1; then - { - echo "status=canary_broken" - echo "detail=n8n returned HTTP 200 but the response had no .data array. API shape changed." - echo "slack=${REMIND}" - } >> "$GITHUB_OUTPUT" - echo "::error::Unexpected response shape from the executions API." - exit 1 - fi + # canary fault, not a healthy pipeline. Both bodies are validated so + # a malformed DRC response cannot produce a non-numeric streak and + # silently suppress the Slack alert. + for _body_check in "$ROUTER_BODY:Event Router" "$DRC_BODY:DRC Agent Loop"; do + _file="${_body_check%%:*}" + _label="${_body_check##*:}" + if ! jq -e '.data | type == "array"' "$_file" >/dev/null 2>&1; then + { + echo "status=canary_broken" + echo "detail=n8n returned HTTP 200 for ${_label} but the response had no .data array. API shape changed." + echo "slack=${REMIND}" + } >> "$GITHUB_OUTPUT" + echo "::error::Unexpected response shape from the executions API (${_label})." + exit 1 + fi + done # --- Consecutive-error streak, newest first ---------------------- # Chosen over "any error in the last N hours" so the signal SELF-CLEARS: @@ -179,10 +185,11 @@ jobs: exit 1 fi - AGE_H=$(( ( $(date -u +%s) - $(date -u -d "$LATEST_AT" +%s) ) / 3600 )) + AGE_S=$(( $(date -u +%s) - $(date -u -d "$LATEST_AT" +%s) )) + AGE_H=$(( AGE_S / 3600 )) echo "Event Router last execution age: ${AGE_H}h (threshold ${SILENCE_THRESHOLD_HOURS}h)" - if [ "$AGE_H" -gt "$SILENCE_THRESHOLD_HOURS" ]; then + if [ "$AGE_S" -gt $(( SILENCE_THRESHOLD_HOURS * 3600 )) ]; then { echo "status=pipeline_down" echo "detail=Event Router has been SILENT for ${AGE_H}h (threshold ${SILENCE_THRESHOLD_HOURS}h). No GitHub events are arriving - webhook deleted, or workflow deactivated." diff --git a/.github/workflows/n8n-health-check.yml b/.github/workflows/n8n-health-check.yml index c4b50cf..2eac639 100644 --- a/.github/workflows/n8n-health-check.yml +++ b/.github/workflows/n8n-health-check.yml @@ -1,8 +1,8 @@ -name: n8n Pipeline Health Check +name: n8n Reachability Check # SCOPE LIMIT - READ BEFORE TRUSTING THIS WORKFLOW'S GREEN. # This checks REACHABILITY ONLY: that n8n Cloud is serving HTTP. -# It CANNOT detect a broken pipeline, and has already failed to twice +# It CANNOT detect a broken pipeline, and has already failed twice # (2026-07-23 Normalise Issue Payload, 2026-08-22 HMAC secret unset). # * The DRC probe below hits the "Route Health Ping" IF node, which returns # Pong 200 BEFORE the auth gate and before any real work. A Pong proves