@cohortapp/agent-sdk 2.18.13 → 2.18.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/maestro.mjs +38 -1
- package/docs/runbooks/fleet-rollout.md +14 -7
- package/docs/runbooks/recovery-and-failover.md +18 -0
- package/lib/cadence-failure-class.mjs +245 -0
- package/lib/claude-bin.mjs +26 -7
- package/lib/cli/doctor-checks.mjs +149 -1
- package/lib/diagnostics/alerts.mjs +33 -0
- package/lib/engine/agents/usage.mjs +45 -0
- package/lib/engine/budget.mjs +293 -29
- package/lib/engine/cli.mjs +54 -5
- package/lib/engine/loop.mjs +30 -0
- package/lib/engine/output/json.mjs +26 -0
- package/lib/engine/wire/errors.mjs +179 -0
- package/lib/engine/wire/search.mjs +44 -8
- package/lib/org/quota.mjs +27 -0
- package/lib/session/config.mjs +4 -0
- package/lib/session/identity.mjs +71 -7
- package/lib/session/launch-failure.mjs +251 -0
- package/lib/session/resume-target.mjs +86 -0
- package/lib/telemetry/collect.mjs +129 -0
- package/lib/upgrade/pinned-drift.mjs +467 -0
- package/package.json +1 -1
- package/scaffold/config/alerts.yaml +7 -0
- package/scripts/ci/check-cadence-prompts-exist.mjs +96 -0
- package/scripts/ci/check.mjs +3 -0
- package/scripts/daemon/cadence-consumer.mjs +281 -34
- package/scripts/emergency-stop.sh +114 -13
- package/scripts/fleet/rollout.mjs +10 -3
- package/scripts/healthcheck.sh +131 -33
- package/scripts/resume-operations.sh +101 -6
- package/scripts/session/supervisor.mjs +198 -5
package/scripts/healthcheck.sh
CHANGED
|
@@ -1,24 +1,109 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
2
|
# Health Check — Verifies all Maestro agent subsystems are operational
|
|
3
|
-
# Usage: ./scripts/healthcheck.sh
|
|
4
|
-
# Exit codes: 0 = healthy, 1 = degraded, 2 = critical
|
|
3
|
+
# Usage: ./scripts/healthcheck.sh [--ignore-emergency-stop] [--offline] [--help]
|
|
4
|
+
# Exit codes: 0 = healthy, 1 = degraded (warnings only), 2 = critical (errors)
|
|
5
|
+
#
|
|
6
|
+
# A refusal NAMES what blocked it. The summary always prints a `Blocking:`
|
|
7
|
+
# line listing the id of every failed check (and a `Warnings:` line for the
|
|
8
|
+
# soft ones), because the operator's next question after "1 errors" is always
|
|
9
|
+
# "which one?" — and on 2026-09-24 answering it cost a re-run with a filter
|
|
10
|
+
# while a seat stayed halted.
|
|
11
|
+
#
|
|
12
|
+
# --ignore-emergency-stop
|
|
13
|
+
# Demote check 1 (the .emergency-stop flag) from ERROR to NOTE. It is meant
|
|
14
|
+
# for one caller: resume-operations.sh, whose whole job is to lift that
|
|
15
|
+
# flag. Counting the flag as a reason not to lift the flag deadlocked the
|
|
16
|
+
# only tool that can lift it (a seat sat halted from 2026-09-24T08:16Z
|
|
17
|
+
# until it was cleared by hand).
|
|
18
|
+
#
|
|
19
|
+
# SCOPE, PLAINLY. This is a PUBLIC CLI flag. Any caller, script or operator
|
|
20
|
+
# can pass it; nothing refuses it, and nothing here pretends to. An earlier
|
|
21
|
+
# draft of this header said the exemption "is refused to everyone else" —
|
|
22
|
+
# it never was. The scoping is convention plus this comment, and a gate that
|
|
23
|
+
# exists only in a comment is exactly the thing this file was repaired for.
|
|
24
|
+
#
|
|
25
|
+
# What keeps it honest is scope, not exclusivity:
|
|
26
|
+
# - It demotes exactly ONE check. Every other check runs at full severity,
|
|
27
|
+
# so an exempted run still cannot green-light a broken seat.
|
|
28
|
+
# - It is off by default, so an operator running healthcheck on a halted
|
|
29
|
+
# seat is still told it is halted — the first thing they need to know.
|
|
30
|
+
# - It is explicit, greppable, and reviewable at its single call site.
|
|
31
|
+
# - The demotion is ANNOUNCED in the output ([NOTE] ...). That line is the
|
|
32
|
+
# receipt resume-operations.sh checks before it trusts the verdict, so a
|
|
33
|
+
# run where the flag was silently swallowed is caught rather than obeyed.
|
|
34
|
+
# Requiring a second token (an env var alongside the flag) would add another
|
|
35
|
+
# thing to forge, not a boundary: anyone who can run this script can set an
|
|
36
|
+
# env var. The real boundary is permission to execute it at all.
|
|
37
|
+
#
|
|
38
|
+
# The alternatives are worse on their merits, not on access control:
|
|
39
|
+
# - Dropping the check outright, or having it always ignore the flag, is
|
|
40
|
+
# wrong for the same reason as above: a halted seat must say so.
|
|
41
|
+
# - Re-ordering resume (remove flag, then check) is worse still: it lifts
|
|
42
|
+
# the stop on a genuinely broken seat and only then discovers it is
|
|
43
|
+
# broken, which is the failure the stop flag exists to prevent.
|
|
44
|
+
#
|
|
45
|
+
# --offline (or MAESTRO_HEALTHCHECK_SKIP_NETWORK=1)
|
|
46
|
+
# Record check 6 as SKIPPED instead of reaching the network. Not a weakening:
|
|
47
|
+
# the check is neither counted healthy nor counted failed, and the summary
|
|
48
|
+
# says it was skipped.
|
|
5
49
|
|
|
6
50
|
set -e
|
|
7
51
|
|
|
8
52
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
9
|
-
|
|
53
|
+
AGENT_DIR="$(dirname "$SCRIPT_DIR")"
|
|
10
54
|
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
11
|
-
HEALTHY=0
|
|
12
55
|
WARNINGS=0
|
|
13
56
|
ERRORS=0
|
|
57
|
+
BLOCKING="" # space-separated ids of failed checks
|
|
58
|
+
SOFT="" # space-separated ids of warned checks
|
|
59
|
+
|
|
60
|
+
IGNORE_STOP_FLAG=0
|
|
61
|
+
SKIP_NETWORK=0
|
|
62
|
+
case "${MAESTRO_HEALTHCHECK_SKIP_NETWORK:-0}" in 1 | true | yes) SKIP_NETWORK=1 ;; esac
|
|
63
|
+
|
|
64
|
+
while [ $# -gt 0 ]; do
|
|
65
|
+
case "$1" in
|
|
66
|
+
--ignore-emergency-stop) IGNORE_STOP_FLAG=1 ;;
|
|
67
|
+
--offline) SKIP_NETWORK=1 ;;
|
|
68
|
+
-h | --help)
|
|
69
|
+
sed -n '2,/^$/p' "${BASH_SOURCE[0]}" | sed 's/^# \{0,1\}//'
|
|
70
|
+
exit 0
|
|
71
|
+
;;
|
|
72
|
+
*)
|
|
73
|
+
echo "healthcheck: unknown argument: $1" >&2
|
|
74
|
+
echo "Usage: healthcheck.sh [--ignore-emergency-stop] [--offline]" >&2
|
|
75
|
+
exit 2
|
|
76
|
+
;;
|
|
77
|
+
esac
|
|
78
|
+
shift
|
|
79
|
+
done
|
|
80
|
+
|
|
81
|
+
# fail <id> <message> — record a blocking condition under a stable id.
|
|
82
|
+
fail() {
|
|
83
|
+
echo "[FAIL] $2"
|
|
84
|
+
BLOCKING="$BLOCKING $1"
|
|
85
|
+
ERRORS=$((ERRORS + 1))
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
# warn <id> <message> — record a soft condition under a stable id.
|
|
89
|
+
warn() {
|
|
90
|
+
echo "[WARN] $2"
|
|
91
|
+
SOFT="$SOFT $1"
|
|
92
|
+
WARNINGS=$((WARNINGS + 1))
|
|
93
|
+
}
|
|
14
94
|
|
|
15
95
|
echo "Maestro Health Check — $TIMESTAMP"
|
|
16
96
|
echo "======================================="
|
|
17
97
|
|
|
18
98
|
# Check 1: Emergency stop flag
|
|
19
|
-
if [ -f "$
|
|
20
|
-
|
|
21
|
-
|
|
99
|
+
if [ -f "$AGENT_DIR/.emergency-stop" ]; then
|
|
100
|
+
if [ "$IGNORE_STOP_FLAG" -eq 1 ]; then
|
|
101
|
+
echo "[NOTE] Emergency stop flag is active — not counted (--ignore-emergency-stop)"
|
|
102
|
+
else
|
|
103
|
+
echo "[STOP] Emergency stop flag is active"
|
|
104
|
+
BLOCKING="$BLOCKING emergency-stop-flag"
|
|
105
|
+
ERRORS=$((ERRORS + 1))
|
|
106
|
+
fi
|
|
22
107
|
else
|
|
23
108
|
echo "[OK] No emergency stop flag"
|
|
24
109
|
fi
|
|
@@ -30,22 +115,20 @@ fi
|
|
|
30
115
|
# in .env strips the var and falls back to Keychain OAuth).
|
|
31
116
|
if [ -n "${ANTHROPIC_API_KEY:-}" ]; then
|
|
32
117
|
echo "[OK] Environment variable: ANTHROPIC_API_KEY"
|
|
33
|
-
elif [ -f "$
|
|
118
|
+
elif [ -f "$AGENT_DIR/.env" ] && grep -qE "^MAESTRO_PREFER_SUBSCRIPTION_AUTH=(1|true|yes)$" "$AGENT_DIR/.env"; then
|
|
34
119
|
echo "[OK] Anthropic auth: subscription mode (.env: MAESTRO_PREFER_SUBSCRIPTION_AUTH=1)"
|
|
35
|
-
elif [ -f "$
|
|
120
|
+
elif [ -f "$AGENT_DIR/.env" ] && grep -qE "^ANTHROPIC_API_KEY=." "$AGENT_DIR/.env"; then
|
|
36
121
|
echo "[OK] Anthropic auth: ANTHROPIC_API_KEY in .env"
|
|
37
122
|
else
|
|
38
|
-
|
|
39
|
-
ERRORS=$((ERRORS + 1))
|
|
123
|
+
fail "anthropic-auth" "Anthropic auth not configured (.env needs either ANTHROPIC_API_KEY or MAESTRO_PREFER_SUBSCRIPTION_AUTH=1)"
|
|
40
124
|
fi
|
|
41
125
|
|
|
42
126
|
# Check 3: Key directories exist and are writable
|
|
43
127
|
for dir in logs outputs knowledge/memory config; do
|
|
44
|
-
if [ -d "$
|
|
128
|
+
if [ -d "$AGENT_DIR/$dir" ] && [ -w "$AGENT_DIR/$dir" ]; then
|
|
45
129
|
echo "[OK] Directory writable: $dir"
|
|
46
130
|
else
|
|
47
|
-
|
|
48
|
-
ERRORS=$((ERRORS + 1))
|
|
131
|
+
fail "dir:$dir" "Directory missing or not writable: $dir"
|
|
49
132
|
fi
|
|
50
133
|
done
|
|
51
134
|
|
|
@@ -54,8 +137,7 @@ for repo in company-web innovation-lab partner-framework company-legal regulator
|
|
|
54
137
|
if [ -d "$HOME/$repo" ]; then
|
|
55
138
|
echo "[OK] Source repo accessible: ~/$repo"
|
|
56
139
|
else
|
|
57
|
-
|
|
58
|
-
WARNINGS=$((WARNINGS + 1))
|
|
140
|
+
warn "repo:$repo" "Source repo not found: ~/$repo"
|
|
59
141
|
fi
|
|
60
142
|
done
|
|
61
143
|
|
|
@@ -64,45 +146,61 @@ for app in Slack WhatsApp Safari; do
|
|
|
64
146
|
if [ -d "/Applications/$app.app" ] || [ -d "$HOME/Applications/$app.app" ]; then
|
|
65
147
|
echo "[OK] Application installed: $app"
|
|
66
148
|
else
|
|
67
|
-
|
|
68
|
-
WARNINGS=$((WARNINGS + 1))
|
|
149
|
+
warn "app:$app" "Application not found: $app"
|
|
69
150
|
fi
|
|
70
151
|
done
|
|
71
152
|
|
|
72
153
|
# Check 6: Network connectivity
|
|
73
|
-
if
|
|
154
|
+
if [ "$SKIP_NETWORK" -eq 1 ]; then
|
|
155
|
+
echo "[SKIP] Network: not probed (--offline)"
|
|
156
|
+
elif curl -s --max-time 5 https://api.anthropic.com > /dev/null 2>&1; then
|
|
74
157
|
echo "[OK] Network: Anthropic API reachable"
|
|
75
158
|
else
|
|
76
|
-
|
|
77
|
-
ERRORS=$((ERRORS + 1))
|
|
159
|
+
fail "network" "Network: Cannot reach Anthropic API"
|
|
78
160
|
fi
|
|
79
161
|
|
|
80
|
-
# Check 7: Disk space
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
162
|
+
# Check 7: Disk space. Ordered most-severe-first: the previous order tested
|
|
163
|
+
# >90 before >95, so the critical branch could never be reached and disk was
|
|
164
|
+
# warn-only in practice. Reaching it is a REAL severity change with a real
|
|
165
|
+
# consequence — resume-operations.sh refuses on any exit 2, so a seat above
|
|
166
|
+
# 95% can no longer be resumed until space is freed. That is deliberate, and
|
|
167
|
+
# it is not the deadlock this trio was repaired for: unlike the stop flag
|
|
168
|
+
# (which only resume could lift), a full disk is named, actionable, and
|
|
169
|
+
# fixable without running this script. Both branches — >95 blocking and >90
|
|
170
|
+
# warning — are pinned in resume-operations.test.mjs, at the healthcheck and
|
|
171
|
+
# at the resume gate, because they are the only severities that changed.
|
|
172
|
+
DISK_FREE=$(df -h "$AGENT_DIR" | awk 'NR==2{print $5}' | tr -d '%')
|
|
173
|
+
if [ "$DISK_FREE" -gt 95 ]; then
|
|
174
|
+
fail "disk" "Disk usage: ${DISK_FREE}% — critically low"
|
|
175
|
+
elif [ "$DISK_FREE" -gt 90 ]; then
|
|
176
|
+
warn "disk" "Disk usage: ${DISK_FREE}% — consider cleanup"
|
|
88
177
|
else
|
|
89
178
|
echo "[OK] Disk usage: ${DISK_FREE}%"
|
|
90
179
|
fi
|
|
91
180
|
|
|
92
181
|
# Check 8: Config files present
|
|
93
182
|
for config in priorities.yaml environment.yaml contacts.yaml; do
|
|
94
|
-
if [ -f "$
|
|
183
|
+
if [ -f "$AGENT_DIR/config/$config" ]; then
|
|
95
184
|
echo "[OK] Config present: $config"
|
|
96
185
|
else
|
|
97
|
-
|
|
98
|
-
ERRORS=$((ERRORS + 1))
|
|
186
|
+
fail "config:$config" "Config missing: $config"
|
|
99
187
|
fi
|
|
100
188
|
done
|
|
101
189
|
|
|
102
|
-
# Summary
|
|
190
|
+
# Summary. `Blocking:` / `Warnings:` are the machine-readable contract:
|
|
191
|
+
# resume-operations.sh parses `Blocking:` to name the condition it refused on.
|
|
103
192
|
echo ""
|
|
104
193
|
echo "======================================="
|
|
105
194
|
echo "Results: $ERRORS errors, $WARNINGS warnings"
|
|
195
|
+
# `if`, not `[ ... ] && echo` — but NOT for the reason first written here,
|
|
196
|
+
# which was false. `set -e` does NOT abort on a false short-circuit: bash
|
|
197
|
+
# exempts a failing command that is not the last in an && list. MEASURED:
|
|
198
|
+
# bash -c 'set -e; n=0; [ "$n" -gt 0 ] && echo hi; exit 0' → exit 0
|
|
199
|
+
# The genuine hazard is only that a false && list leaves status 1, which a
|
|
200
|
+
# script inherits if it is the last command run. The explicit exits below
|
|
201
|
+
# make that moot here; `if` is kept because it says what is meant.
|
|
202
|
+
if [ "$ERRORS" -gt 0 ]; then echo "Blocking:$BLOCKING"; fi
|
|
203
|
+
if [ "$WARNINGS" -gt 0 ]; then echo "Warnings:$SOFT"; fi
|
|
106
204
|
|
|
107
205
|
if [ "$ERRORS" -gt 0 ]; then
|
|
108
206
|
echo "Status: CRITICAL — fix errors before operating"
|
|
@@ -3,12 +3,34 @@
|
|
|
3
3
|
# Usage: ./scripts/resume-operations.sh
|
|
4
4
|
#
|
|
5
5
|
# Reverses emergency-stop.sh:
|
|
6
|
-
# 1. Verifies health check passes.
|
|
6
|
+
# 1. Verifies health check passes — EXCLUDING the stop flag itself.
|
|
7
7
|
# 2. Removes the .emergency-stop flag.
|
|
8
8
|
# 3. Reloads every installed `ai.maestro.<agent>-*` (and legacy
|
|
9
9
|
# `ai.adaptic.<agent>-*`) launchd job.
|
|
10
10
|
#
|
|
11
11
|
# Agent first-name slug resolved from config/agent.json (SOT).
|
|
12
|
+
#
|
|
13
|
+
# THE DEADLOCK THIS SCRIPT USED TO HAVE. healthcheck.sh counts an active
|
|
14
|
+
# .emergency-stop flag as an ERROR; this script ran it bare and exited on any
|
|
15
|
+
# non-zero. So the one tool whose entire purpose is lifting the stop could
|
|
16
|
+
# never lift it — Eli Rosenberg's seat sat halted from 2026-09-24T08:16Z until
|
|
17
|
+
# the flag was removed by hand. Two independent faults produced that:
|
|
18
|
+
#
|
|
19
|
+
# (a) The stop flag was its own veto. Fixed by passing
|
|
20
|
+
# `--ignore-emergency-stop`, which demotes that ONE check to a note.
|
|
21
|
+
# It is a PUBLIC CLI flag — nothing refuses it to another caller, and
|
|
22
|
+
# nothing here pretends to (healthcheck.sh's header says so plainly).
|
|
23
|
+
# What makes it safe is scope, not exclusivity: it demotes exactly one
|
|
24
|
+
# check, every other check still gates the resume, and step 1b below
|
|
25
|
+
# VERIFIES that the healthcheck on this disk actually honoured it
|
|
26
|
+
# rather than assuming the two files are the same vintage.
|
|
27
|
+
# (b) DEGRADED was treated as failure. healthcheck exits 1 for warnings and
|
|
28
|
+
# 2 for errors; `if ! healthcheck` refused on both, so seven warnings
|
|
29
|
+
# about optional repos and an uninstalled Slack.app were enough to keep
|
|
30
|
+
# a seat halted. Warnings are "operational with limitations" by
|
|
31
|
+
# healthcheck's own contract — they are reported loudly and resumed.
|
|
32
|
+
# Only CRITICAL (exit 2) still refuses, and the refusal names which
|
|
33
|
+
# condition blocked it.
|
|
12
34
|
|
|
13
35
|
set -e
|
|
14
36
|
|
|
@@ -46,19 +68,92 @@ if [ ! -f "$AGENT_DIR/.emergency-stop" ]; then
|
|
|
46
68
|
launchctl load "$plist" 2>/dev/null && loaded=$((loaded + 1))
|
|
47
69
|
fi
|
|
48
70
|
done
|
|
49
|
-
[ "$loaded" -gt 0 ] && echo
|
|
71
|
+
# `if`, not `[ "$loaded" -gt 0 ] && echo ...` — but NOT for the reason
|
|
72
|
+
# first written here, which was wrong and would have seeded a wrong rule.
|
|
73
|
+
# `set -e` does not abort on the false short-circuit: bash exempts a
|
|
74
|
+
# failing command that is not the last in an && list. MEASURED:
|
|
75
|
+
# bash -c 'set -e; n=0; [ "$n" -gt 0 ] && echo hi; exit 0' → exit 0
|
|
76
|
+
# and the pre-fix script (which had `exit 0` on the next line) also
|
|
77
|
+
# exited 0 on a seat with nothing to load. The real hazard is narrower
|
|
78
|
+
# and has nothing to do with `set -e`: a false && list leaves status 1,
|
|
79
|
+
# so a script whose LAST command is one exits 1. `exit 0` follows today;
|
|
80
|
+
# the `if` keeps this line harmless if it ever stops following.
|
|
81
|
+
if [ "$loaded" -gt 0 ]; then echo "Loaded $loaded missing launchd job(s)"; fi
|
|
50
82
|
exit 0
|
|
51
83
|
fi
|
|
52
84
|
|
|
53
85
|
echo "[$TIMESTAMP] RESUMING OPERATIONS (agent=$AGENT_FIRST)" | tee -a "$LOG_FILE"
|
|
54
86
|
|
|
55
|
-
# 1. Run health check first
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
87
|
+
# 1. Run health check first — with the stop flag exempted, since lifting it is
|
|
88
|
+
# this script's entire job. Every OTHER check still gates the resume.
|
|
89
|
+
echo "Running health check (emergency-stop flag exempted)..."
|
|
90
|
+
set +e
|
|
91
|
+
HEALTH_OUTPUT=$("$SCRIPT_DIR/healthcheck.sh" --ignore-emergency-stop 2>&1)
|
|
92
|
+
HEALTH_STATUS=$?
|
|
93
|
+
set -e
|
|
94
|
+
echo "$HEALTH_OUTPUT"
|
|
95
|
+
|
|
96
|
+
# 1b. Prove the exemption was HONOURED before trusting the verdict.
|
|
97
|
+
#
|
|
98
|
+
# Fault (a)'s fix is version-coupled: it only works if the healthcheck.sh
|
|
99
|
+
# next to this script understands --ignore-emergency-stop. A seat that
|
|
100
|
+
# pins framework files (.maestroignore) can carry the new resume script
|
|
101
|
+
# beside a pre-fix healthcheck, which has no argument parsing at all — it
|
|
102
|
+
# swallows the flag, still counts the stop as an error, and prints no
|
|
103
|
+
# `Blocking:` line. MEASURED on that exact pairing: the deadlock is back,
|
|
104
|
+
# and the refusal reads "(healthcheck named no condition; see output
|
|
105
|
+
# above)" — worse than the original, because it names nothing to fix.
|
|
106
|
+
# The seats most likely to be halted are the ones most likely to be
|
|
107
|
+
# pinned, so this has to be detected and named rather than inferred.
|
|
108
|
+
#
|
|
109
|
+
# We are past the `[ -f .emergency-stop ]` guard, so a healthcheck that
|
|
110
|
+
# honoured the flag MUST have printed the NOTE line. Its absence means
|
|
111
|
+
# the exemption did not take: stale, missing, or not executable.
|
|
112
|
+
if ! printf '%s\n' "$HEALTH_OUTPUT" | grep -q '^\[NOTE\] Emergency stop flag' ||
|
|
113
|
+
printf '%s\n' "$HEALTH_OUTPUT" | grep -q '^Blocking:.*emergency-stop-flag'; then
|
|
114
|
+
echo ""
|
|
115
|
+
echo "REFUSING TO RESUME — scripts/healthcheck.sh is stale."
|
|
116
|
+
echo " --ignore-emergency-stop was ignored (healthcheck exit $HEALTH_STATUS): it did"
|
|
117
|
+
echo " not report '[NOTE] Emergency stop flag ... not counted', so its verdict still"
|
|
118
|
+
echo " counts the very flag this script exists to lift. Resuming on that verdict"
|
|
119
|
+
echo " would be resuming on a health check nobody read."
|
|
120
|
+
echo " Fix: run 'maestro upgrade' on this seat, then confirm .maestroignore is not"
|
|
121
|
+
echo " pinning scripts/healthcheck.sh, and that the file exists and is executable."
|
|
122
|
+
echo " The .emergency-stop flag has been LEFT IN PLACE."
|
|
123
|
+
echo "[$TIMESTAMP] Resume REFUSED — healthcheck.sh stale (exemption ignored, status $HEALTH_STATUS)" >> "$LOG_FILE"
|
|
59
124
|
exit 1
|
|
60
125
|
fi
|
|
61
126
|
|
|
127
|
+
if [ "$HEALTH_STATUS" -ge 2 ]; then
|
|
128
|
+
# Name the blocking condition. The operator should never have to re-run
|
|
129
|
+
# the health check with a filter to learn which of "1 errors" stopped them.
|
|
130
|
+
BLOCKING=$(printf '%s\n' "$HEALTH_OUTPUT" | sed -n 's/^Blocking://p' | tr -s ' ' | sed 's/^ //')
|
|
131
|
+
[ -n "$BLOCKING" ] || BLOCKING="(healthcheck named no condition; see output above)"
|
|
132
|
+
echo ""
|
|
133
|
+
echo "REFUSING TO RESUME — health check is CRITICAL."
|
|
134
|
+
echo " Blocking condition(s): $BLOCKING"
|
|
135
|
+
# Re-list the failing lines under the refusal, RE-PREFIXED. The whole
|
|
136
|
+
# health output is echoed above, so the previous `grep '^\[FAIL\]'` here
|
|
137
|
+
# emitted bytes indistinguishable from it — deleting the line left the
|
|
138
|
+
# test that claimed to pin it green. The ` FAIL: ` prefix is produced
|
|
139
|
+
# only here, which is what makes that assertion load-bearing.
|
|
140
|
+
printf '%s\n' "$HEALTH_OUTPUT" | sed -n 's/^\[FAIL\] / FAIL: /p'
|
|
141
|
+
echo " The .emergency-stop flag has been LEFT IN PLACE."
|
|
142
|
+
echo " Fix the condition(s) above, then re-run: $0"
|
|
143
|
+
{
|
|
144
|
+
echo "[$TIMESTAMP] Resume REFUSED — blocking: $BLOCKING"
|
|
145
|
+
} >> "$LOG_FILE"
|
|
146
|
+
exit 1
|
|
147
|
+
fi
|
|
148
|
+
|
|
149
|
+
if [ "$HEALTH_STATUS" -eq 1 ]; then
|
|
150
|
+
DEGRADED=$(printf '%s\n' "$HEALTH_OUTPUT" | sed -n 's/^Warnings://p' | tr -s ' ' | sed 's/^ //')
|
|
151
|
+
echo ""
|
|
152
|
+
echo "NOTE: health check is DEGRADED — resuming anyway (warnings are not faults)."
|
|
153
|
+
echo " Warning condition(s): $DEGRADED"
|
|
154
|
+
echo "[$TIMESTAMP] Resume proceeding DEGRADED — warnings: $DEGRADED" >> "$LOG_FILE"
|
|
155
|
+
fi
|
|
156
|
+
|
|
62
157
|
# 2. Remove stop flag.
|
|
63
158
|
rm "$AGENT_DIR/.emergency-stop"
|
|
64
159
|
echo "[$TIMESTAMP] Stop flag removed" >> "$LOG_FILE"
|