watchdog: signal handoffs off claim()/review() commit prefixes (robust) + codify the convention
Replaces the brittle markdown prose-match ("Gate: … CLAIMED, awaiting Adversary") with detection of
the loops' conventional commit prefixes on origin/main: a new `claim(...)` commit pings the
Adversary; a new `review(...)` commit pings the Builder. Edge-triggered on the origin/main SHA
(append-only — no force-push), no file parsing, can't mis-route. The loops already use these
prefixes consistently; codified as a load-bearing contract in plan.md §6.1 + both prompts so it
stays reliable. INBOX detection unchanged (pushed-state, file-routed).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+28
-34
@@ -225,45 +225,39 @@ heal_orchestrator() {
|
||||
_wd_fetch_origin() { git -C "$1" fetch -q origin 2>/dev/null || true; }
|
||||
_wd_show_pushed() { git -C "$1" show "origin/main:machine-docs/$2" 2>/dev/null || git -C "$1" show "origin/main:$2" 2>/dev/null || true; }
|
||||
|
||||
_wd_awaiting=""; _wd_baselined=""; _wd_last_review=""
|
||||
_wd_adv_inbox_seen=""; _wd_builder_inbox_seen=""
|
||||
handoff_reset() { _wd_awaiting=""; _wd_baselined=""; _wd_last_review=""; _wd_adv_inbox_seen=""; _wd_builder_inbox_seen=""; } # call on phase transition
|
||||
_wd_last_sha=""; _wd_adv_inbox_seen=""; _wd_builder_inbox_seen=""
|
||||
handoff_reset() { _wd_last_sha=""; _wd_adv_inbox_seen=""; _wd_builder_inbox_seen=""; } # call on phase transition
|
||||
# Signal handoffs off the loops' CONVENTIONAL COMMIT PREFIXES on origin/main — NOT by parsing
|
||||
# free-form markdown prose (brittle). The loops consistently prefix every gate claim `claim(...)`
|
||||
# and every verdict/finding `review(...)`. So: a new `claim(` commit pushed => ping the Adversary;
|
||||
# a new `review(` commit => ping the Builder. Edge-triggered on the origin/main SHA (append-only —
|
||||
# the loops never force-push), so it can't double-fire or mis-route. INBOX files are detected
|
||||
# separately (which file changed routes the ping). All reads are of the PUSHED state (what the
|
||||
# receiver pulls).
|
||||
handoff_check() {
|
||||
local idx status review adv_inbox builder_inbox now added ids cur h
|
||||
idx="$(cur_idx)"
|
||||
local head subjects adv_inbox builder_inbox h
|
||||
_wd_fetch_origin "$BUILDER_DIR"
|
||||
status="$(_wd_show_pushed "$BUILDER_DIR" "$(phase_status "$idx")")"
|
||||
review="$(_wd_show_pushed "$BUILDER_DIR" "$(phase_review "$idx")")"
|
||||
head="$(git -C "$BUILDER_DIR" rev-parse origin/main 2>/dev/null || true)"
|
||||
if [[ -n "$head" ]]; then
|
||||
if [[ -z "$_wd_last_sha" ]]; then
|
||||
_wd_last_sha="$head" # baseline silently on first observation / restart
|
||||
elif [[ "$head" != "$_wd_last_sha" ]]; then
|
||||
subjects="$(git -C "$BUILDER_DIR" log --format='%s' "${_wd_last_sha}..origin/main" 2>/dev/null || true)"
|
||||
if printf '%s\n' "$subjects" | grep -qiE '^claim'; then
|
||||
log "handoff: new claim(...) commit on origin/main -> pinging Adversary"
|
||||
ping_session "$ADV_SESSION" "watchdog ping: the Builder pushed a gate CLAIM (claim(...) commit). Pull and verify the claimed gate now."
|
||||
fi
|
||||
if printf '%s\n' "$subjects" | grep -qiE '^review'; then
|
||||
log "handoff: new review(...) commit on origin/main -> pinging Builder"
|
||||
ping_session "$BUILDER_SESSION" "watchdog ping: the Adversary pushed a verdict/finding (review(...) commit). Pull REVIEW and act — proceed if it PASSes your gate, address it if it's a finding."
|
||||
fi
|
||||
_wd_last_sha="$head"
|
||||
fi
|
||||
fi
|
||||
|
||||
adv_inbox="$(_wd_show_pushed "$BUILDER_DIR" "ADVERSARY-INBOX.md")"
|
||||
builder_inbox="$(_wd_show_pushed "$BUILDER_DIR" "BUILDER-INBOX.md")"
|
||||
|
||||
# Gate claims: match ONLY a FORMAL claim line ("Gate: <id> … CLAIMED, awaiting Adversary"), and
|
||||
# edge-trigger on a genuinely-NEW such line (compared whole, so prose mentions / historical
|
||||
# "CLAIMED detail" lines / id mis-parsing can't fire it). The id is just a best-effort label.
|
||||
now="$(printf '%s\n' "$status" | grep -iE 'gate[: ].*claimed.*awaiting[[:space:]]+adversary' | sort -u || true)"
|
||||
if [[ -n "$_wd_baselined" ]]; then
|
||||
added="$(comm -13 <(printf '%s\n' "$_wd_awaiting") <(printf '%s\n' "$now") | grep -vE '^$' || true)"
|
||||
if [[ -n "$added" ]]; then
|
||||
ids="$(printf '%s\n' "$added" | grep -oiE 'gate:?[[:space:]]*[A-Z]{1,3}[0-9]+(\.[0-9]+)*' | sed -E 's/^[Gg]ate:?[[:space:]]*//' | tr '\n' ' ' | tr '[:lower:]' '[:upper:]' || true)"
|
||||
[[ -z "$ids" ]] && ids="a gate"
|
||||
log "handoff: NEW pushed gate claim [$ids] -> pinging Adversary"
|
||||
ping_session "$ADV_SESSION" "watchdog ping: the Builder pushed a gate claim [$ids] in $(phase_status "$idx") — awaiting your verification. Pull and verify now."
|
||||
fi
|
||||
fi
|
||||
_wd_awaiting="$now"; _wd_baselined=1
|
||||
|
||||
# REVIEW change (pushed) -> ping Builder.
|
||||
if [[ -n "$review" ]]; then
|
||||
cur="$(printf '%s' "$review" | md5sum | awk '{print $1}')"
|
||||
if [[ -n "$cur" && "$cur" != "$_wd_last_review" ]]; then
|
||||
[[ -n "$_wd_last_review" ]] && {
|
||||
log "handoff: $(phase_review "$idx") changed (pushed) -> pinging Builder"
|
||||
ping_session "$BUILDER_SESSION" "watchdog ping: the Adversary pushed an update to $(phase_review "$idx") (a verdict or finding). Pull and act now — if it PASSes your gate, proceed; if it's a finding, address it."
|
||||
}
|
||||
_wd_last_review="$cur"
|
||||
fi
|
||||
fi
|
||||
|
||||
# INBOX side-channel (§6.1), detected on the pushed state. Receiver deletes after consuming =>
|
||||
# absent on origin/main => re-arm so the next write re-pings.
|
||||
if [[ -n "$adv_inbox" ]]; then
|
||||
|
||||
Reference in New Issue
Block a user