autonomous-sdlc-harness 0.4.2 → 0.6.0
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/dist/commands/init.js +113 -16
- package/dist/commands/init.js.map +1 -1
- package/dist/config/check.js +28 -6
- package/dist/config/check.js.map +1 -1
- package/dist/config/model.js +64 -5
- package/dist/config/model.js.map +1 -1
- package/dist/core/pluginIdentity.js +2 -0
- package/dist/core/pluginIdentity.js.map +1 -1
- package/dist/core/writer.js +10 -5
- package/dist/core/writer.js.map +1 -1
- package/dist/core/yamlScalar.js +14 -0
- package/dist/core/yamlScalar.js.map +1 -0
- package/dist/doctor/checks.js +454 -23
- package/dist/doctor/checks.js.map +1 -1
- package/dist/generators/githubWorkflows.js +125 -20
- package/dist/generators/githubWorkflows.js.map +1 -1
- package/dist/generators/repoRoot.js +17 -8
- package/dist/generators/repoRoot.js.map +1 -1
- package/dist/remote/githubActions.js +110 -7
- package/dist/remote/githubActions.js.map +1 -1
- package/dist/retrieval/pythonBackend.js +114 -0
- package/dist/retrieval/pythonBackend.js.map +1 -0
- package/dist/retrieval/setup.js +8 -0
- package/dist/retrieval/setup.js.map +1 -1
- package/package.json +1 -1
- package/templates/README.md +1 -1
- package/templates/github/workflows/harness-control.yml +184 -0
- package/templates/github/workflows/harness-resume.yml +9 -0
- package/templates/github/workflows/harness-run.yml +127 -12
- package/templates/github/workflows/harness-trigger.yml +144 -0
- package/templates/repo/gitignore +5 -0
- package/templates/scripts/README.md +1 -1
- package/templates/scripts/autonomous-watcher.sh +121 -249
- package/templates/scripts/create-worktree.sh +52 -10
- package/templates/scripts/docs-search-server.sh +88 -17
- package/templates/scripts/lib/harness-run-lib.sh +614 -14
- package/templates/scripts/remote-run.sh +3684 -144
- package/templates/scripts/scratch-run.sh +54 -73
- package/templates/state-dir/README-root.md +1 -1
- package/templates/state-dir/scratch/README.md +4 -2
- package/templates/state-dir/user_reviews/README.md +2 -2
|
@@ -210,17 +210,10 @@
|
|
|
210
210
|
# OWN. Skipped for such a record: the vanished-process reconcile, the cap
|
|
211
211
|
# count, the stall watchdog, both halves of the usage gate, and the lane's
|
|
212
212
|
# idle release.
|
|
213
|
-
# *
|
|
214
|
-
#
|
|
215
|
-
#
|
|
216
|
-
#
|
|
217
|
-
# after a PARK_LOOP_CLEAR); a RESUME -> `dispatch --resume pause`; a PAUSE on
|
|
218
|
-
# a `running` record -> `remote-run.sh pause`. Each is chain 0, takes no cap
|
|
219
|
-
# slot and consults no lane; only a sent dispatch changes the record or
|
|
220
|
-
# removes a file, so a refusal or a `gh` failure is one log line and the
|
|
221
|
-
# next pass retries. The kill switch defers the two resumes; the pause relay
|
|
222
|
-
# runs ahead of it, the one action that still runs under the brake, because
|
|
223
|
-
# it starts nothing.
|
|
213
|
+
# * NOTHING IS RELAYED. The user's commands send pause, resume and answer to
|
|
214
|
+
# GitHub themselves through `remote-run.sh`, so no file in a mirror is a
|
|
215
|
+
# request this script acts on: the parked, paused and park-loop passes skip
|
|
216
|
+
# a remote record outright, sending nothing and changing nothing.
|
|
224
217
|
#
|
|
225
218
|
# A remote run's local working copy is a MIRROR that `remote-run.sh sync`
|
|
226
219
|
# fills; it is stopped through `remote-run.sh stop`.
|
|
@@ -383,7 +376,12 @@
|
|
|
383
376
|
# and the next job no `resumed` for it: a chained continuation is not an
|
|
384
377
|
# event the user acts on. classify_run_exit's `paused` arm notifies only a
|
|
385
378
|
# `user` pause; job mode sends the others once it has decided. Their titles
|
|
386
|
-
# carry HARNESS_REMOTE_SLUG when set.
|
|
379
|
+
# carry HARNESS_REMOTE_SLUG when set. Each job-mode event except `failed` is
|
|
380
|
+
# also passed to `remote-run.sh report` as it happens, and `failed` once,
|
|
381
|
+
# when the job ends `failed`; `report` comments on the run's pull request or
|
|
382
|
+
# issue and moves its state label when `forge` is `github`; `autonomous-notify.sh`
|
|
383
|
+
# is unchanged, and `completed` is reported by the workflow's `deliver` step
|
|
384
|
+
# after the push.
|
|
387
385
|
# * THE INTERACTIVE-TEST PHASE IS SKIPPED, not run: a runner has no browser
|
|
388
386
|
# wiring, application dependencies or QA credentials for it. With
|
|
389
387
|
# `phases.qa` true, the task and user_review launch prompts gain one clause
|
|
@@ -704,17 +702,12 @@
|
|
|
704
702
|
# the same tick still launches under MAX_PARALLEL_RUNS=1, its
|
|
705
703
|
# back-dated mirror logs draw no stall line, and a `rejected`
|
|
706
704
|
# event in its stream drops no PAUSE
|
|
707
|
-
# remote
|
|
708
|
-
# in the mirror's clarifications/feat_x
|
|
709
|
-
#
|
|
710
|
-
#
|
|
711
|
-
#
|
|
712
|
-
#
|
|
713
|
-
# dispatch and PAUSE / RESUME / PAUSE_ACK gone; `running` with
|
|
714
|
-
# the mirror's PAUSE -> ONE `-f action=pause` dispatch, PAUSE
|
|
715
|
-
# gone and pause_relayed_at set. With AUTONOMOUS_STOP present
|
|
716
|
-
# only the pause is sent; with a recorder exiting non-zero
|
|
717
|
-
# every file and status stays
|
|
705
|
+
# remote passes from that record: `parked` with question_1.md and answer_1.md
|
|
706
|
+
# in the mirror's clarifications/feat_x/; `park_loop` plus
|
|
707
|
+
# PARK_LOOP_CLEAR; `paused` with the mirror's RESUME; `running`
|
|
708
|
+
# with the mirror's PAUSE -> each tick sends no `gh` call, does
|
|
709
|
+
# NOT launch the stub, and leaves every mirror file and the
|
|
710
|
+
# record's status as they were
|
|
718
711
|
# unresolvable printf 'x' > "$d/harness.config.json"
|
|
719
712
|
# -> one line on stderr, exit 1, nothing under "$d/sdlc-harness"
|
|
720
713
|
|
|
@@ -1162,12 +1155,33 @@ unset USAGE_LANE_ENABLED_RETIRED
|
|
|
1162
1155
|
# Every lifecycle event goes out through here, so a notifier that is missing or
|
|
1163
1156
|
# not executable costs one log line instead of ending a pass. Best-effort by
|
|
1164
1157
|
# contract: the notifier itself never fails its caller.
|
|
1158
|
+
# JOB MODE ONLY: the event is also passed to `remote-run.sh report` via
|
|
1159
|
+
# job_report. `failed` is not reported here: run_job reports it once its
|
|
1160
|
+
# automatic resumes are ruled out.
|
|
1165
1161
|
notify() {
|
|
1166
1162
|
if [ ! -x "$NOTIFY" ]; then
|
|
1167
1163
|
log "notify: '$NOTIFY' is not executable — '${1:-?}' event for '${2:-?}' not delivered"
|
|
1164
|
+
else
|
|
1165
|
+
"$NOTIFY" "$@" || true
|
|
1166
|
+
fi
|
|
1167
|
+
[ "$JOB_MODE" = 1 ] || return 0
|
|
1168
|
+
[ "${1:-}" != "failed" ] || return 0
|
|
1169
|
+
job_report "$1" "$2" "${3:-}"
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
# job_report <event> <branch> [<log>] — the only route to GitHub. The detail is
|
|
1173
|
+
# withheld: it names local slash commands, and `report` words its comment from
|
|
1174
|
+
# the registry record itself.
|
|
1175
|
+
job_report() {
|
|
1176
|
+
if [ ! -r "$REMOTE_RUN" ]; then
|
|
1177
|
+
log "notify: '$REMOTE_RUN' is not readable — '${1:-?}' event for '${2:-?}' not reported on GitHub"
|
|
1168
1178
|
return 0
|
|
1169
1179
|
fi
|
|
1170
|
-
"$
|
|
1180
|
+
if [ -n "${3:-}" ]; then
|
|
1181
|
+
bash "$REMOTE_RUN" report "$1" "$2" --repo "$MAIN_REPO" >>"$3" 2>&1 || true
|
|
1182
|
+
else
|
|
1183
|
+
bash "$REMOTE_RUN" report "$1" "$2" --repo "$MAIN_REPO" >/dev/null 2>&1 || true
|
|
1184
|
+
fi
|
|
1171
1185
|
}
|
|
1172
1186
|
|
|
1173
1187
|
# -----------------------------------------------------------------------------
|
|
@@ -1297,18 +1311,14 @@ notify() {
|
|
|
1297
1311
|
# bound of the next control poll, this job's or the next
|
|
1298
1312
|
# chained one's. Set at start (see JOB MODE) and advanced
|
|
1299
1313
|
# by every successful poll
|
|
1300
|
-
# execution `github-actions` on a record
|
|
1314
|
+
# execution `github-actions` on a remote record — one
|
|
1315
|
+
# launch_remote_run wrote through
|
|
1316
|
+
# lib/harness-run-lib.sh's `hr_remote_record_init` — and
|
|
1301
1317
|
# absent on a local one. Fixed for the run's life: a later
|
|
1302
1318
|
# pass reads this field, never `execution.target`
|
|
1303
1319
|
# remote_dispatched_at
|
|
1304
1320
|
# the epoch second launch_remote_run's `remote-run.sh
|
|
1305
1321
|
# dispatch` returned 0; empty after a failed dispatch
|
|
1306
|
-
# park_loop_clear_pending
|
|
1307
|
-
# `1` on a remote record clear_park_loops returned to
|
|
1308
|
-
# `parked`, so the next answer relay sends
|
|
1309
|
-
# `--park-loop-clear`; cleared once that relay is sent
|
|
1310
|
-
# pause_relayed_at the epoch second the pause relay sent a remote record's
|
|
1311
|
-
# `remote-run.sh pause`
|
|
1312
1322
|
# -----------------------------------------------------------------------------
|
|
1313
1323
|
# The bodies are lib/harness-run-lib.sh's THE RUN REGISTRY, shared with every
|
|
1314
1324
|
# script that reads or writes this file; these wrappers bind them to $REGISTRY.
|
|
@@ -1561,7 +1571,7 @@ print_status() {
|
|
|
1561
1571
|
}
|
|
1562
1572
|
|
|
1563
1573
|
# The global kill switch — checked before every launch and at the top of every
|
|
1564
|
-
# pass
|
|
1574
|
+
# pass.
|
|
1565
1575
|
# NEVER removed here; see the header.
|
|
1566
1576
|
kill_switch_active() {
|
|
1567
1577
|
[ -f "$GLOBAL_STOP" ]
|
|
@@ -2069,26 +2079,15 @@ launch_run() {
|
|
|
2069
2079
|
# launch_remote_run <branch> <worktree> <log_path> <engine_kind>
|
|
2070
2080
|
#
|
|
2071
2081
|
# launch_run's bookkeeping for a remote drop (REMOTE DISPATCH in the header):
|
|
2072
|
-
# the same fields written and cleared, plus `execution` and an empty pid
|
|
2082
|
+
# the same fields written and cleared, plus `execution` and an empty pid — the
|
|
2083
|
+
# one list is lib/harness-run-lib.sh's `hr_remote_record_init` — then
|
|
2073
2084
|
# `remote-run.sh dispatch` in place of the window and the spawn. `running` is
|
|
2074
2085
|
# written only once the dispatch returned 0, so a record never claims a run
|
|
2075
2086
|
# GitHub was not asked for.
|
|
2076
2087
|
launch_remote_run() {
|
|
2077
2088
|
local branch="$1" worktree="$2" log_path="$3" engine_kind="$4" out rc first
|
|
2078
2089
|
|
|
2079
|
-
|
|
2080
|
-
registry_set "$branch" log_path "$log_path"
|
|
2081
|
-
registry_set "$branch" engine "$engine_kind"
|
|
2082
|
-
registry_set "$branch" execution github-actions
|
|
2083
|
-
registry_set "$branch" started_at "$(date '+%Y-%m-%dT%H:%M:%S')"
|
|
2084
|
-
registry_set "$branch" pid ""
|
|
2085
|
-
registry_set "$branch" remote_dispatched_at ""
|
|
2086
|
-
registry_set "$branch" stall_restarts 0
|
|
2087
|
-
registry_set "$branch" stall_warned ""
|
|
2088
|
-
registry_set "$branch" stall_killing ""
|
|
2089
|
-
registry_set "$branch" paused_by "" usage_resume_at ""
|
|
2090
|
-
registry_set "$branch" resume_kind ""
|
|
2091
|
-
registry_set "$branch" park_loop_cycles 0
|
|
2090
|
+
hr_remote_record_init "$REGISTRY" "$branch" "$worktree" "$log_path" "$engine_kind"
|
|
2092
2091
|
|
|
2093
2092
|
log "dispatching '$branch' (engine=$engine_kind) to GitHub Actions via remote-run.sh (log: $log_path)"
|
|
2094
2093
|
out="$(bash "$REMOTE_RUN" dispatch "$branch" --engine "$engine_kind" --resume none --chain 0 --repo "$MAIN_REPO" 2>&1)"
|
|
@@ -2230,7 +2229,7 @@ classify_run_exit() {
|
|
|
2230
2229
|
registry_set "$branch" pause_reason "$reason" status paused
|
|
2231
2230
|
log "run '$branch' paused (PAUSE honored, reason $reason) — rc=$rc"
|
|
2232
2231
|
if [ "$reason" = "user" ]; then
|
|
2233
|
-
notify paused "$branch" "$log_path" "paused as you asked — run /autonomous-sdlc-harness:branch-resume $branch to continue"
|
|
2232
|
+
notify paused "$branch" "$log_path" "paused as you asked — run /autonomous-sdlc-harness:branch-resume $branch to continue; $(hr_github_resume_route "$branch" "$(registry_get "$branch" engine)")"
|
|
2234
2233
|
fi
|
|
2235
2234
|
return 0
|
|
2236
2235
|
fi
|
|
@@ -2321,7 +2320,7 @@ classify_run_exit() {
|
|
|
2321
2320
|
registry_set "$branch" status park_loop
|
|
2322
2321
|
log "run '$branch' park loop — $cycles consecutive resumes made no progress; not resuming it again (clear: $clar_dir/PARK_LOOP_CLEAR)"
|
|
2323
2322
|
if [ "$JOB_MODE" = "1" ]; then
|
|
2324
|
-
notify park_loop "$branch" "$log_path" "$cycles no-progress resumes — run /autonomous-sdlc-harness:branch-status $branch to see the question, then clear the park loop"
|
|
2323
|
+
notify park_loop "$branch" "$log_path" "$cycles no-progress resumes — run /autonomous-sdlc-harness:branch-status $branch to see the question, then clear the park loop; $(hr_github_answer_route "$branch" "$(registry_get "$branch" engine)" clear)"
|
|
2325
2324
|
else
|
|
2326
2325
|
notify park_loop "$branch" "$log_path" "$cycles no-progress resumes — create $clar_dir/PARK_LOOP_CLEAR to clear"
|
|
2327
2326
|
fi
|
|
@@ -2336,7 +2335,7 @@ classify_run_exit() {
|
|
|
2336
2335
|
registry_set "$branch" status parked
|
|
2337
2336
|
log "run '$branch' parked (clarification waiting) — rc=$rc"
|
|
2338
2337
|
if [ "$JOB_MODE" = "1" ]; then
|
|
2339
|
-
notify parked "$branch" "$log_path" "answer with /autonomous-sdlc-harness:branch-answer $branch"
|
|
2338
|
+
notify parked "$branch" "$log_path" "answer with /autonomous-sdlc-harness:branch-answer $branch; $(hr_github_answer_route "$branch" "$(registry_get "$branch" engine)")"
|
|
2340
2339
|
else
|
|
2341
2340
|
notify parked "$branch" "$log_path" "See $clar_dir"
|
|
2342
2341
|
fi
|
|
@@ -2421,7 +2420,8 @@ begin_park_resume() {
|
|
|
2421
2420
|
# Returns 0 when it resumed, 1 when there was nothing to do, 10 when it deferred
|
|
2422
2421
|
# for the cap and 11 when it deferred for the kill switch — the same three-way
|
|
2423
2422
|
# vocabulary the inbox pass returns, so a caller that already distinguishes them
|
|
2424
|
-
# needs no second one. A remote record returns
|
|
2423
|
+
# needs no second one. A remote record returns 1 and logs nothing: its answers
|
|
2424
|
+
# reach GitHub through the user's own command (REMOTE DISPATCH).
|
|
2425
2425
|
#
|
|
2426
2426
|
# THE PARK IS THE UNIT. A partly answered park is not resumed, and a resume
|
|
2427
2427
|
# consumes every answered pair at once: resuming on a subset would leave pairs
|
|
@@ -2435,6 +2435,7 @@ begin_park_resume() {
|
|
|
2435
2435
|
resume_parked_run() {
|
|
2436
2436
|
local branch="$1"
|
|
2437
2437
|
local worktree log_path
|
|
2438
|
+
record_is_remote "$branch" && return 1
|
|
2438
2439
|
worktree="$(registry_get "$branch" worktree)"
|
|
2439
2440
|
log_path="$(registry_get "$branch" log_path)"
|
|
2440
2441
|
[ -n "$worktree" ] || return 1
|
|
@@ -2469,13 +2470,6 @@ resume_parked_run() {
|
|
|
2469
2470
|
|
|
2470
2471
|
[ -n "$log_path" ] || log_path="$LOGS_DIR/$branch.log"
|
|
2471
2472
|
|
|
2472
|
-
# A remote run is relayed, not re-launched: no cap slot, no lane (REMOTE
|
|
2473
|
-
# DISPATCH). The pairs stay in the mirror, which the next `sync` replaces.
|
|
2474
|
-
if record_is_remote "$branch"; then
|
|
2475
|
-
relay_remote_answers "$branch" "$clar_dir" "$log_path" "$answered_set"
|
|
2476
|
-
return
|
|
2477
|
-
fi
|
|
2478
|
-
|
|
2479
2473
|
local current
|
|
2480
2474
|
current="$(running_count)"
|
|
2481
2475
|
if [ "$current" -ge "$MAX_PARALLEL_RUNS" ]; then
|
|
@@ -2505,48 +2499,6 @@ resume_parked_run() {
|
|
|
2505
2499
|
return 0
|
|
2506
2500
|
}
|
|
2507
2501
|
|
|
2508
|
-
# remote_relay_call <log_path> <remote-run.sh argument>...
|
|
2509
|
-
#
|
|
2510
|
-
# One relay's `remote-run.sh` call, from the main checkout, its output appended
|
|
2511
|
-
# to <log_path>. Returns the script's exit code (0 sent, 2 refused, 3 `gh`
|
|
2512
|
-
# failed) and leaves its first output line in REMOTE_RELAY_FIRST for the
|
|
2513
|
-
# caller's one log line.
|
|
2514
|
-
remote_relay_call() {
|
|
2515
|
-
local log_path="$1" out rc
|
|
2516
|
-
shift
|
|
2517
|
-
out="$(bash "$REMOTE_RUN" "$@" --repo "$MAIN_REPO" 2>&1)"
|
|
2518
|
-
rc=$?
|
|
2519
|
-
[ -z "$out" ] || printf '%s\n' "$out" >>"$log_path"
|
|
2520
|
-
REMOTE_RELAY_FIRST="$(printf '%s\n' "$out" | sed -n '1p')"
|
|
2521
|
-
return "$rc"
|
|
2522
|
-
}
|
|
2523
|
-
|
|
2524
|
-
# relay_remote_answers <branch> <clar_dir> <log_path> <answered_set>
|
|
2525
|
-
#
|
|
2526
|
-
# resume_parked_run's remote arm: the answered set sent as a chain-0 `--resume
|
|
2527
|
-
# answer` dispatch, with `--park-loop-clear` while clear_park_loops has left
|
|
2528
|
-
# `park_loop_clear_pending` set. 0 dispatched; 1 refused or `gh` failed, the
|
|
2529
|
-
# record left `parked` and every file where it is, so the next pass retries.
|
|
2530
|
-
relay_remote_answers() {
|
|
2531
|
-
local branch="$1" clar_dir="$2" log_path="$3" answered_set="$4" rc
|
|
2532
|
-
local -a plc=()
|
|
2533
|
-
[ "$(registry_get "$branch" park_loop_clear_pending)" = "1" ] && plc=(--park-loop-clear)
|
|
2534
|
-
remote_relay_call "$log_path" dispatch "$branch" --engine "$(registry_get "$branch" engine)" \
|
|
2535
|
-
--resume answer --answers-from "$clar_dir" --indexes "$answered_set" ${plc[@]+"${plc[@]}"} --chain 0
|
|
2536
|
-
rc=$?
|
|
2537
|
-
if [ "$rc" -ne 0 ]; then
|
|
2538
|
-
log "remote-run.sh dispatch --resume answer for '$branch' failed (exit $rc): ${REMOTE_RELAY_FIRST:-no output} — leaving it parked"
|
|
2539
|
-
return 1
|
|
2540
|
-
fi
|
|
2541
|
-
log "relayed the answers ($answered_set) of parked remote run '$branch' to GitHub Actions"
|
|
2542
|
-
registry_set "$branch" status running
|
|
2543
|
-
registry_set "$branch" resumed_at "$(date '+%Y-%m-%dT%H:%M:%S')"
|
|
2544
|
-
registry_set "$branch" resume_kind answer
|
|
2545
|
-
registry_set "$branch" park_loop_clear_pending ""
|
|
2546
|
-
notify resumed "$branch" "$log_path" "answered clarification(s) #$answered_set, dispatched"
|
|
2547
|
-
return 0
|
|
2548
|
-
}
|
|
2549
|
-
|
|
2550
2502
|
# Every `parked` record, offered to the resume above. The kill switch skips the
|
|
2551
2503
|
# WHOLE pass rather than each record, so an operator's brake costs one log line
|
|
2552
2504
|
# in tick() instead of one per parked branch; the cap is per-record, because a
|
|
@@ -2572,14 +2524,15 @@ EOF
|
|
|
2572
2524
|
# run's working copy; the file is removed so the clear is spent once. Answering a
|
|
2573
2525
|
# question never releases the hold — only this file does. A missing working copy
|
|
2574
2526
|
# or an unresolvable state directory leaves the record held. A remote record is
|
|
2575
|
-
#
|
|
2576
|
-
#
|
|
2527
|
+
# skipped: its hold is cleared by the user's own answer or resume command, which
|
|
2528
|
+
# sends `--park-loop-clear` to the job (REMOTE DISPATCH).
|
|
2577
2529
|
clear_park_loops() {
|
|
2578
2530
|
registry_init
|
|
2579
2531
|
local b worktree state_rel clear_file
|
|
2580
2532
|
while IFS= read -r b; do
|
|
2581
2533
|
[ -n "$b" ] || continue
|
|
2582
2534
|
[ "$(registry_get "$b" status)" = "park_loop" ] || continue
|
|
2535
|
+
record_is_remote "$b" && continue
|
|
2583
2536
|
worktree="$(registry_get "$b" worktree)"
|
|
2584
2537
|
[ -n "$worktree" ] || continue
|
|
2585
2538
|
[ -d "$worktree" ] || {
|
|
@@ -2595,7 +2548,6 @@ clear_park_loops() {
|
|
|
2595
2548
|
rm -f "$clear_file"
|
|
2596
2549
|
registry_set "$b" park_loop_cycles 0
|
|
2597
2550
|
registry_set "$b" status parked
|
|
2598
|
-
record_is_remote "$b" && registry_set "$b" park_loop_clear_pending 1
|
|
2599
2551
|
log "park loop cleared for '$b' (PARK_LOOP_CLEAR found) — back to parked"
|
|
2600
2552
|
done <<EOF
|
|
2601
2553
|
$(registry_branches)
|
|
@@ -2647,12 +2599,12 @@ begin_pause_resume() {
|
|
|
2647
2599
|
#
|
|
2648
2600
|
# Resume one paused run if a RESUME trigger has landed in its working copy.
|
|
2649
2601
|
# Return codes, the missing-working-copy outcome and the kill-switch/cap ordering
|
|
2650
|
-
# are resume_parked_run's, for the same reasons. A remote record
|
|
2651
|
-
#
|
|
2652
|
-
# nothing removed.
|
|
2602
|
+
# are resume_parked_run's, for the same reasons. A remote record returns 1 and
|
|
2603
|
+
# logs nothing, as there.
|
|
2653
2604
|
resume_paused_run() {
|
|
2654
2605
|
local branch="$1"
|
|
2655
2606
|
local worktree log_path
|
|
2607
|
+
record_is_remote "$branch" && return 1
|
|
2656
2608
|
worktree="$(registry_get "$branch" worktree)"
|
|
2657
2609
|
log_path="$(registry_get "$branch" log_path)"
|
|
2658
2610
|
[ -n "$worktree" ] || return 1
|
|
@@ -2683,23 +2635,6 @@ resume_paused_run() {
|
|
|
2683
2635
|
|
|
2684
2636
|
[ -n "$log_path" ] || log_path="$LOGS_DIR/$branch.log"
|
|
2685
2637
|
|
|
2686
|
-
# A remote run is relayed, not re-launched: no cap slot, no lane (REMOTE
|
|
2687
|
-
# DISPATCH). The sentinels go only once the dispatch was sent.
|
|
2688
|
-
if record_is_remote "$branch"; then
|
|
2689
|
-
local rc
|
|
2690
|
-
remote_relay_call "$log_path" dispatch "$branch" --engine "$(registry_get "$branch" engine)" \
|
|
2691
|
-
--resume pause --chain 0
|
|
2692
|
-
rc=$?
|
|
2693
|
-
if [ "$rc" -ne 0 ]; then
|
|
2694
|
-
log "remote-run.sh dispatch --resume pause for '$branch' failed (exit $rc): ${REMOTE_RELAY_FIRST:-no output} — leaving it paused"
|
|
2695
|
-
return 1
|
|
2696
|
-
fi
|
|
2697
|
-
log "relayed the RESUME of paused remote run '$branch' to GitHub Actions"
|
|
2698
|
-
begin_pause_resume "$branch" "$state_abs"
|
|
2699
|
-
notify resumed "$branch" "$log_path" "after pause, dispatched"
|
|
2700
|
-
return 0
|
|
2701
|
-
fi
|
|
2702
|
-
|
|
2703
2638
|
local current
|
|
2704
2639
|
current="$(running_count)"
|
|
2705
2640
|
if [ "$current" -ge "$MAX_PARALLEL_RUNS" ]; then
|
|
@@ -2742,39 +2677,6 @@ $(registry_branches)
|
|
|
2742
2677
|
EOF
|
|
2743
2678
|
}
|
|
2744
2679
|
|
|
2745
|
-
# THE PAUSE RELAY (REMOTE DISPATCH). A `running` remote record whose mirror
|
|
2746
|
-
# holds `<state_dir>/PAUSE` — a user's pause — is sent `remote-run.sh pause`;
|
|
2747
|
-
# on exit 0 the mirror's PAUSE goes and `pause_relayed_at` is stamped, and on
|
|
2748
|
-
# any other exit both stay for the next pass. Called from `tick` ahead of the
|
|
2749
|
-
# kill switch, because a pause starts nothing; it consults neither the cap nor
|
|
2750
|
-
# the lane.
|
|
2751
|
-
relay_remote_pauses() {
|
|
2752
|
-
registry_init
|
|
2753
|
-
local b wt state_rel rc log_path
|
|
2754
|
-
while IFS= read -r b; do
|
|
2755
|
-
[ -n "$b" ] || continue
|
|
2756
|
-
record_is_remote "$b" || continue
|
|
2757
|
-
[ "$(registry_get "$b" status)" = "running" ] || continue
|
|
2758
|
-
wt="$(registry_get "$b" worktree)"
|
|
2759
|
-
[ -n "$wt" ] && [ -d "$wt" ] || continue
|
|
2760
|
-
state_rel="$(run_state_dir "$wt")" || continue
|
|
2761
|
-
[ -f "$wt/$state_rel/PAUSE" ] || continue
|
|
2762
|
-
log_path="$(registry_get "$b" log_path)"
|
|
2763
|
-
[ -n "$log_path" ] || log_path="$LOGS_DIR/$b.log"
|
|
2764
|
-
remote_relay_call "$log_path" pause "$b"
|
|
2765
|
-
rc=$?
|
|
2766
|
-
if [ "$rc" -ne 0 ]; then
|
|
2767
|
-
log "remote-run.sh pause for '$b' failed (exit $rc): ${REMOTE_RELAY_FIRST:-no output} — PAUSE left in the mirror"
|
|
2768
|
-
continue
|
|
2769
|
-
fi
|
|
2770
|
-
rm -f "$wt/$state_rel/PAUSE"
|
|
2771
|
-
registry_set "$b" pause_relayed_at "$(date +%s)"
|
|
2772
|
-
log "relayed the PAUSE of remote run '$b' to GitHub Actions"
|
|
2773
|
-
done <<EOF
|
|
2774
|
-
$(registry_branches)
|
|
2775
|
-
EOF
|
|
2776
|
-
}
|
|
2777
|
-
|
|
2778
2680
|
# -----------------------------------------------------------------------------
|
|
2779
2681
|
# THE STALENESS WATCHDOG. The header states what this pass heals that the
|
|
2780
2682
|
# reconcile pass cannot see, why a stale mtime ALONE never kills, why the
|
|
@@ -3023,29 +2925,27 @@ reject_preserving_status() {
|
|
|
3023
2925
|
# remote_commit_and_push <branch> <worktree> <log_path> <file> <fname> <dest> <rel> <subject> <what>
|
|
3024
2926
|
#
|
|
3025
2927
|
# The remote arm's commit-and-push, BLOCKING (REMOTE DISPATCH in the header):
|
|
3026
|
-
# 0 = <
|
|
2928
|
+
# 0 = <rel> is committed and origin/<branch> carries HEAD; 1 = it is not, and
|
|
3027
2929
|
# fail_before_launch has already run, so the caller dispatches nothing. The
|
|
3028
|
-
#
|
|
3029
|
-
#
|
|
2930
|
+
# library's staging, identical-re-drop skip and landed test (THE ARTIFACT
|
|
2931
|
+
# PLACEMENT in lib/harness-run-lib.sh) with the local arm's wrappers; the push
|
|
2932
|
+
# stays a separate statement from the commit. <dest> is the caller's.
|
|
3030
2933
|
remote_commit_and_push() {
|
|
3031
2934
|
local branch="$1" worktree="$2" log_path="$3" file="$4" fname="$5"
|
|
3032
|
-
local dest="$6" rel="$7" subject="$8" what="$9"
|
|
2935
|
+
local dest="$6" rel="$7" subject="$8" what="$9" rc=0
|
|
3033
2936
|
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
log "the $what for '$branch' is already committed (identical re-drop) — skipping the commit, pushing anyway"
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
2937
|
+
hr_commit_placed "$COMMIT_ON_BRANCH" "$worktree" "$rel" "$subject" >>"$log_path" 2>&1 || rc=$?
|
|
2938
|
+
case "$rc" in
|
|
2939
|
+
3) log "the $what for '$branch' is already committed (identical re-drop) — skipping the commit, pushing anyway" ;;
|
|
2940
|
+
0) log "committed the $what for '$branch' ($subject)" ;;
|
|
2941
|
+
*)
|
|
2942
|
+
log "commit-on-branch.sh could not commit the $what for '$branch' — not dispatching (see $log_path)"
|
|
2943
|
+
fail_before_launch "$branch" "$file" "$fname" "(commit-on-branch.sh could not commit the $what — nothing dispatched; see $log_path)"
|
|
2944
|
+
return 1
|
|
2945
|
+
;;
|
|
2946
|
+
esac
|
|
3044
2947
|
|
|
3045
|
-
"$PUSH_BRANCH" "$worktree" >>"$log_path" 2>&1
|
|
3046
|
-
head="$(git -C "$worktree" rev-parse --verify --quiet HEAD)" || head=""
|
|
3047
|
-
upstream="$(git -C "$worktree" rev-parse --verify --quiet "refs/remotes/origin/$branch")" || upstream=""
|
|
3048
|
-
if [ -z "$head" ] || [ "$head" != "$upstream" ]; then
|
|
2948
|
+
if ! hr_push_landed "$PUSH_BRANCH" "$worktree" "$branch" >>"$log_path" 2>&1; then
|
|
3049
2949
|
log "push-branch.sh did not bring origin/$branch to HEAD after the $what for '$branch' — not dispatching (see $log_path)"
|
|
3050
2950
|
fail_before_launch "$branch" "$file" "$fname" "(push-branch.sh did not push the $what to origin/$branch — nothing dispatched; the job checks out origin/$branch; see $log_path)"
|
|
3051
2951
|
return 1
|
|
@@ -3067,18 +2967,8 @@ remote_commit_and_push() {
|
|
|
3067
2967
|
# ^(.+)_review(_[0-9]+)?\.md$ -> user_review engine, reuse-else-recreate
|
|
3068
2968
|
# ^(.+)_docs\.md$ -> docs engine, a fresh working copy
|
|
3069
2969
|
#
|
|
3070
|
-
# The
|
|
3071
|
-
#
|
|
3072
|
-
# cannot end in more than one of `_task_prompt.md` / `_review[_<n>].md` /
|
|
3073
|
-
# `_docs.md`, so a branch whose own name contains `review` or `task_prompt`
|
|
3074
|
-
# cannot be mis-routed — `foo_review_task_prompt.md` is the task engine on branch
|
|
3075
|
-
# `foo_review`, and `foo_task_prompt_review.md` is the review engine on branch
|
|
3076
|
-
# `foo_task_prompt`. POSIX leftmost-longest matching of the greedy `(.+)` derives
|
|
3077
|
-
# the right branch from a round-suffixed name: `foo_review_2.md` -> branch `foo`
|
|
3078
|
-
# (the `_2` is consumed by the optional `(_[0-9]+)?`), while
|
|
3079
|
-
# `foo_review_2_review.md` -> branch `foo_review_2`. THE WATCHER DERIVES ONLY THE
|
|
3080
|
-
# BRANCH, never the round: the engine resolves the latest round itself, inside
|
|
3081
|
-
# the working copy, which is why nothing here has to remember one.
|
|
2970
|
+
# The library owns these patterns and their order: `hr_inbox_route_var` in
|
|
2971
|
+
# lib/harness-run-lib.sh, whose comment states why they cannot mis-route.
|
|
3082
2972
|
#
|
|
3083
2973
|
# A filename matching none of the three is logged and ARCHIVED rather than left
|
|
3084
2974
|
# where it is, so it is not re-logged on every pass for as long as the watcher
|
|
@@ -3091,24 +2981,13 @@ process_inbox_file() {
|
|
|
3091
2981
|
|
|
3092
2982
|
# (1) Route the filename to its pairing and derive <branch> — see above.
|
|
3093
2983
|
local branch engine_kind
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
branch="$(printf '%s' "$fname" | sed -nE 's/^(.+)_review(_[0-9]+)?\.md$/\1/p')"
|
|
3099
|
-
if [ -n "$branch" ]; then
|
|
3100
|
-
engine_kind="user_review"
|
|
3101
|
-
else
|
|
3102
|
-
branch="$(printf '%s' "$fname" | sed -nE 's/^(.+)_docs\.md$/\1/p')"
|
|
3103
|
-
if [ -n "$branch" ]; then
|
|
3104
|
-
engine_kind="docs"
|
|
3105
|
-
else
|
|
3106
|
-
log "rejecting '$fname': not a <branch>_task_prompt.md / <branch>_review[_<n>].md / <branch>_docs.md file — skipping"
|
|
3107
|
-
mv "$file" "$ARCHIVE_DIR/rejected_$(date '+%Y%m%d%H%M%S')_$fname" 2>/dev/null || rm -f "$file"
|
|
3108
|
-
return 0
|
|
3109
|
-
fi
|
|
3110
|
-
fi
|
|
2984
|
+
if ! hr_inbox_route_var "$fname"; then
|
|
2985
|
+
log "rejecting '$fname': not a <branch>_task_prompt.md / <branch>_review[_<n>].md / <branch>_docs.md file — skipping"
|
|
2986
|
+
mv "$file" "$ARCHIVE_DIR/rejected_$(date '+%Y%m%d%H%M%S')_$fname" 2>/dev/null || rm -f "$file"
|
|
2987
|
+
return 0
|
|
3111
2988
|
fi
|
|
2989
|
+
branch="$HR_INBOX_BRANCH"
|
|
2990
|
+
engine_kind="$HR_INBOX_KIND"
|
|
3112
2991
|
|
|
3113
2992
|
# The central log every step below appends to. A branch derived from a FILENAME
|
|
3114
2993
|
# cannot contain a `/`, so this name needs no sanitizing — unlike the
|
|
@@ -3278,10 +3157,11 @@ process_inbox_file() {
|
|
|
3278
3157
|
|
|
3279
3158
|
# (3a) Copy the dropped prompt into the working copy, then archive the inbox
|
|
3280
3159
|
# file so it is not processed again.
|
|
3281
|
-
local prompt_rel=
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
|
|
3160
|
+
local prompt_rel prompt_dest prompt_subject prompt_rc=0
|
|
3161
|
+
prompt_rel="$(hr_task_prompt_rel "$state_rel" "$branch")"
|
|
3162
|
+
prompt_dest="$worktree/$prompt_rel"
|
|
3163
|
+
prompt_subject="$(hr_task_prompt_subject "$branch")"
|
|
3164
|
+
hr_place_artifact "$worktree" "$file" "$prompt_rel"
|
|
3285
3165
|
mv "$file" "$ARCHIVE_DIR/$(date '+%Y%m%d%H%M%S')_$fname" 2>/dev/null || rm -f "$file"
|
|
3286
3166
|
log "copied the prompt -> $prompt_dest; archived the inbox file"
|
|
3287
3167
|
|
|
@@ -3296,13 +3176,14 @@ process_inbox_file() {
|
|
|
3296
3176
|
#
|
|
3297
3177
|
# Only the prompt is staged, by explicit path — never `git add -A` or
|
|
3298
3178
|
# `git add .`, matching the no-blanket-add rule every unattended commit point
|
|
3299
|
-
# in this family follows. The
|
|
3179
|
+
# in this family follows. The nothing-staged pre-check is what makes
|
|
3300
3180
|
# an identical re-drop of an already-committed prompt a no-op instead of an
|
|
3301
3181
|
# empty commit; when there IS a diff, the WRAPPER does the real staging and
|
|
3302
3182
|
# the commit, so this commit point inherits its protected-branch refusal
|
|
3303
3183
|
# rather than re-implementing it. The wrapper stages paths RELATIVE TO THE
|
|
3304
|
-
# REPOSITORY TOP, so it is handed the repo-relative path
|
|
3305
|
-
#
|
|
3184
|
+
# REPOSITORY TOP, so it is handed the repo-relative path. The placement
|
|
3185
|
+
# itself lives in lib/harness-run-lib.sh (THE ARTIFACT PLACEMENT), shared
|
|
3186
|
+
# with a job that starts a run.
|
|
3306
3187
|
#
|
|
3307
3188
|
# A FAILURE AT EITHER STEP IS LOGGED AND THE RUN LAUNCHES ANYWAY: a prompt
|
|
3308
3189
|
# commit that did not land has to be VISIBLE, and it must never be the reason
|
|
@@ -3313,20 +3194,18 @@ process_inbox_file() {
|
|
|
3313
3194
|
# dispatch instead (REMOTE DISPATCH in the header).
|
|
3314
3195
|
if [ "$remote" = 1 ]; then
|
|
3315
3196
|
remote_commit_and_push "$branch" "$worktree" "$log_path" "$file" "$fname" \
|
|
3316
|
-
"$prompt_dest" "$prompt_rel" "
|
|
3197
|
+
"$prompt_dest" "$prompt_rel" "$prompt_subject" "task prompt" || return 0
|
|
3317
3198
|
else
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
log "the task prompt for '$branch' is already committed (identical re-drop) — skipping the commit"
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
log "WARNING: could not commit the task prompt for '$branch' — launching anyway (its working-tree-clean precondition may be dishonest; see $log_path)"
|
|
3329
|
-
fi
|
|
3199
|
+
hr_commit_placed "$COMMIT_ON_BRANCH" "$worktree" "$prompt_rel" "$prompt_subject" >>"$log_path" 2>&1 || prompt_rc=$?
|
|
3200
|
+
case "$prompt_rc" in
|
|
3201
|
+
3) log "the task prompt for '$branch' is already committed (identical re-drop) — skipping the commit" ;;
|
|
3202
|
+
0)
|
|
3203
|
+
log "committed the task prompt for '$branch' ($prompt_subject)"
|
|
3204
|
+
"$PUSH_BRANCH" "$worktree" >>"$log_path" 2>&1 ||
|
|
3205
|
+
log "WARNING: push-branch.sh failed after the task-prompt commit for '$branch' — continuing"
|
|
3206
|
+
;;
|
|
3207
|
+
*) log "WARNING: could not commit the task prompt for '$branch' — launching anyway (its working-tree-clean precondition may be dishonest; see $log_path)" ;;
|
|
3208
|
+
esac
|
|
3330
3209
|
fi
|
|
3331
3210
|
elif [ "$engine_kind" = "docs" ]; then
|
|
3332
3211
|
# (2c) Docs path: the task path's strategy exactly — a FRESH working copy off
|
|
@@ -3354,26 +3233,24 @@ process_inbox_file() {
|
|
|
3354
3233
|
# rationale is stated once, above.
|
|
3355
3234
|
local docs_rel="$state_rel/docs_catalog/${branch}_docs.md"
|
|
3356
3235
|
local docs_dest="$worktree/$docs_rel"
|
|
3357
|
-
|
|
3358
|
-
|
|
3236
|
+
local docs_subject="chore: add docs checklist for $branch" docs_rc=0
|
|
3237
|
+
hr_place_artifact "$worktree" "$file" "$docs_rel"
|
|
3359
3238
|
mv "$file" "$ARCHIVE_DIR/$(date '+%Y%m%d%H%M%S')_$fname" 2>/dev/null || rm -f "$file"
|
|
3360
3239
|
log "copied the docs checklist -> $docs_dest; archived the inbox file"
|
|
3361
3240
|
if [ "$remote" = 1 ]; then
|
|
3362
3241
|
remote_commit_and_push "$branch" "$worktree" "$log_path" "$file" "$fname" \
|
|
3363
|
-
"$docs_dest" "$docs_rel" "
|
|
3242
|
+
"$docs_dest" "$docs_rel" "$docs_subject" "docs checklist" || return 0
|
|
3364
3243
|
else
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
log "the docs checklist for '$branch' is already committed (identical re-drop) — skipping the commit"
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
log "WARNING: could not commit the docs checklist for '$branch' — launching anyway (see $log_path)"
|
|
3376
|
-
fi
|
|
3244
|
+
hr_commit_placed "$COMMIT_ON_BRANCH" "$worktree" "$docs_rel" "$docs_subject" >>"$log_path" 2>&1 || docs_rc=$?
|
|
3245
|
+
case "$docs_rc" in
|
|
3246
|
+
3) log "the docs checklist for '$branch' is already committed (identical re-drop) — skipping the commit" ;;
|
|
3247
|
+
0)
|
|
3248
|
+
log "committed the docs checklist for '$branch' ($docs_subject)"
|
|
3249
|
+
"$PUSH_BRANCH" "$worktree" >>"$log_path" 2>&1 ||
|
|
3250
|
+
log "WARNING: push-branch.sh failed after the docs-checklist commit for '$branch' — continuing"
|
|
3251
|
+
;;
|
|
3252
|
+
*) log "WARNING: could not commit the docs checklist for '$branch' — launching anyway (see $log_path)" ;;
|
|
3253
|
+
esac
|
|
3377
3254
|
fi
|
|
3378
3255
|
else
|
|
3379
3256
|
# (2b) Review path: REUSE the branch's existing working copy when it is
|
|
@@ -3466,7 +3343,7 @@ process_inbox_file() {
|
|
|
3466
3343
|
log "copied the review -> $review_dest; archived the inbox file"
|
|
3467
3344
|
if [ "$remote" = 1 ]; then
|
|
3468
3345
|
remote_commit_and_push "$branch" "$worktree" "$log_path" "$file" "$fname" \
|
|
3469
|
-
"$review_dest" "$review_rel" "
|
|
3346
|
+
"$review_dest" "$review_rel" "$(hr_user_review_subject "$branch")" "user review" || return 0
|
|
3470
3347
|
fi
|
|
3471
3348
|
fi
|
|
3472
3349
|
|
|
@@ -3735,8 +3612,7 @@ usage_gate() {
|
|
|
3735
3612
|
local b status pb ra wt lp state_rel="" state_abs=""
|
|
3736
3613
|
while IFS= read -r b; do
|
|
3737
3614
|
[ -n "$b" ] || continue
|
|
3738
|
-
# The auto-resume side skips a remote run: its job gates itself
|
|
3739
|
-
# resume_paused_run relays only a user's RESUME.
|
|
3615
|
+
# The auto-resume side skips a remote run: its job gates itself.
|
|
3740
3616
|
record_is_remote "$b" && continue
|
|
3741
3617
|
status="$(registry_get "$b" status)"
|
|
3742
3618
|
pb="$(registry_get "$b" paused_by)"
|
|
@@ -3921,11 +3797,8 @@ EOF
|
|
|
3921
3797
|
}
|
|
3922
3798
|
|
|
3923
3799
|
# -----------------------------------------------------------------------------
|
|
3924
|
-
# One pass. The
|
|
3925
|
-
#
|
|
3926
|
-
# one action that still runs under the brake, because it starts nothing (see
|
|
3927
|
-
# REMOTE DISPATCH) — then the reconcile that frees capacity for the passes that
|
|
3928
|
-
# read the cap.
|
|
3800
|
+
# One pass. The kill switch first, so an operator's brake beats everything
|
|
3801
|
+
# else, then the reconcile that frees capacity for the passes that read the cap.
|
|
3929
3802
|
# -----------------------------------------------------------------------------
|
|
3930
3803
|
tick() {
|
|
3931
3804
|
# Drop the library's per-process cache so an edit to `harness.config.json` is
|
|
@@ -3935,8 +3808,6 @@ tick() {
|
|
|
3935
3808
|
hr_config_reset
|
|
3936
3809
|
hr_config_load "$MAIN_REPO" || :
|
|
3937
3810
|
|
|
3938
|
-
relay_remote_pauses
|
|
3939
|
-
|
|
3940
3811
|
if kill_switch_active; then
|
|
3941
3812
|
log "global kill switch active — not launching or resuming runs this pass"
|
|
3942
3813
|
# A braked watcher must not sit on the machine-level lane: it is starting
|
|
@@ -4342,14 +4213,14 @@ run_job() {
|
|
|
4342
4213
|
# run over rather than waiting on nothing.
|
|
4343
4214
|
decision=wait-poller
|
|
4344
4215
|
detail="usage limit reached; the in-job usage wait passed its bound (REMOTE_WAIT_MAX_SECS=${REMOTE_WAIT_MAX_SECS}s past the reset) without a resume"
|
|
4345
|
-
notify paused "$branch" "$log_path" "usage limit: the in-job wait passed ${REMOTE_WAIT_MAX_SECS}s after the reset without a resume — run /autonomous-sdlc-harness:branch-resume $branch to continue"
|
|
4216
|
+
notify paused "$branch" "$log_path" "usage limit: the in-job wait passed ${REMOTE_WAIT_MAX_SECS}s after the reset without a resume — run /autonomous-sdlc-harness:branch-resume $branch to continue; $(hr_github_resume_route "$branch" "$(registry_get "$branch" engine)")"
|
|
4346
4217
|
break
|
|
4347
4218
|
fi
|
|
4348
4219
|
;;
|
|
4349
4220
|
*)
|
|
4350
4221
|
job_auto_resume "$branch" "$worktree" "$log_path" "$state_abs" "an overload self-pause" && continue
|
|
4351
4222
|
detail="paused itself on API overload; automatic resumes exhausted"
|
|
4352
|
-
notify paused "$branch" "$log_path" "paused itself on API overload — run /autonomous-sdlc-harness:branch-resume $branch to continue"
|
|
4223
|
+
notify paused "$branch" "$log_path" "paused itself on API overload — run /autonomous-sdlc-harness:branch-resume $branch to continue; $(hr_github_resume_route "$branch" "$(registry_get "$branch" engine)")"
|
|
4353
4224
|
break
|
|
4354
4225
|
;;
|
|
4355
4226
|
esac
|
|
@@ -4377,6 +4248,7 @@ run_job() {
|
|
|
4377
4248
|
# A reason recorded for a pause the run finished before honouring.
|
|
4378
4249
|
[ "$final" = "paused" ] || registry_set "$branch" pause_reason ""
|
|
4379
4250
|
[ -n "$detail" ] || detail="the run ended $final in this job"
|
|
4251
|
+
[ "$final" != "failed" ] || job_report failed "$branch" "$log_path"
|
|
4380
4252
|
job_write_status "$branch" "$remote_status" "$decision" "$detail"
|
|
4381
4253
|
echo "job: $final $decision"
|
|
4382
4254
|
exit 0
|