diff --git a/starter-kits/delegation-readiness-doctor/README.md b/starter-kits/delegation-readiness-doctor/README.md index 5e61716a3b..6d210bce97 100644 --- a/starter-kits/delegation-readiness-doctor/README.md +++ b/starter-kits/delegation-readiness-doctor/README.md @@ -34,6 +34,7 @@ This starter kit now packages the proof line, not just the kickoff gap, so the s - `scripts/emit-workflow-approval-trigger.sh` — posting-state-aware nudge/approval packet for the repeated fork-workflow approval stall; prints `WORKFLOW_APPROVAL_TRIGGER_ALREADY_POSTED` when the maintainer request is already live so automation does not mistake a reference-only packet for a fresh action - `scripts/sync-reviewer-handoff-baseline.sh` — keeps `latest-reviewer-handoff.md` aligned to the live PR head/base before state-change detection; polls GitHub mergeability before writing so the handoff does not regress to first-response `mergeability unknown` noise - `scripts/refresh-upstream-blocker-packet.sh` — one-command refresh that syncs the reviewer handoff, reruns the state-change detector, PR monitor, CI interpreter, and approval trigger together, then emits a consolidated blocker packet from the same live PR state; prints `UPSTREAM_BLOCKER_PACKET_UNCHANGED` when the blocker signature is materially identical to the previous latest packet so cron can distinguish revalidation from a real transition; unchanged runs restore prior `latest-*` files and delete just-created timestamped component artifacts so approval-wait cron passes do not dirty the workspace with no-movement files +- `scripts/verify-unchanged-refresh-hygiene.sh` — proof harness for the external-wait loop breaker; snapshots canonical `latest-*` hashes and timestamped artifact names, runs the one-command refresh, and proves an unchanged blocker refresh leaves no local artifact churn behind - `scripts/validate-artifact-consistency.sh` — fail-closed consistency check that requires every canonical blocker artifact to record the same live head/base pair before the packet is trusted - `artifacts/latest-current-gap-report.md` — most recent proof packet emitted by the gap verifier - `artifacts/latest-broken-state-roundtrip.md` — canonical blocked-state proof packet with before/after doctor output @@ -57,6 +58,7 @@ bash starter-kits/delegation-readiness-doctor/scripts/emit-workflow-approval-bri bash starter-kits/delegation-readiness-doctor/scripts/emit-workflow-approval-state-change.sh bash starter-kits/delegation-readiness-doctor/scripts/emit-workflow-approval-trigger.sh bash starter-kits/delegation-readiness-doctor/scripts/refresh-upstream-blocker-packet.sh +bash starter-kits/delegation-readiness-doctor/scripts/verify-unchanged-refresh-hygiene.sh ``` Historical kickoff verifier: diff --git a/starter-kits/delegation-readiness-doctor/artifacts/latest-unchanged-refresh-hygiene-proof.md b/starter-kits/delegation-readiness-doctor/artifacts/latest-unchanged-refresh-hygiene-proof.md new file mode 100644 index 0000000000..fd4f245d40 --- /dev/null +++ b/starter-kits/delegation-readiness-doctor/artifacts/latest-unchanged-refresh-hygiene-proof.md @@ -0,0 +1,54 @@ +# Delegation Readiness Doctor — Unchanged Refresh Hygiene Proof + +Generated: 2026-04-23 20:28 CDT + +## Verdict +UNCHANGED_REFRESH_HYGIENE_PROVED + +## What this proves +This verifier guards the external-wait loop breaker: when the upstream blocker packet is materially unchanged, rerunning the one-command refresh must not rewrite canonical `latest-*` artifacts or leave fresh timestamped component artifacts behind. + +## Checks +- Refresh emitted `UPSTREAM_BLOCKER_PACKET_UNCHANGED`: `True` +- Refresh emitted `UNCHANGED_PACKET_HYGIENE`: `True` +- Canonical `latest-*` artifact hashes unchanged: `True` +- Timestamped artifact set unchanged: `True` +- Latest artifact count checked: `17` +- Timestamped artifact count checked: `273` + +## Refresh log excerpt +```text +**BLOCKER_PERSISTS** +Wrote report: /Users/hermesmasteragent/.hermes/hermes-agent/starter-kits/delegation-readiness-doctor/artifacts/workflow-approval-state-change-2026-04-23T20-28-28-0500.md +Latest report: /Users/hermesmasteragent/.hermes/hermes-agent/starter-kits/delegation-readiness-doctor/artifacts/latest-workflow-approval-state-change.md +/Users/hermesmasteragent/.hermes/hermes-agent/starter-kits/delegation-readiness-doctor/artifacts/pr-review-monitor-2026-04-23T20-28-30-0500.md +Wrote report: /Users/hermesmasteragent/.hermes/hermes-agent/starter-kits/delegation-readiness-doctor/artifacts/pr-review-monitor-2026-04-23T20-28-30-0500.md +Latest report: /Users/hermesmasteragent/.hermes/hermes-agent/starter-kits/delegation-readiness-doctor/artifacts/latest-pr-review-monitor.md +/Users/hermesmasteragent/.hermes/hermes-agent/starter-kits/delegation-readiness-doctor/artifacts/ci-result-interpreter-2026-04-23T20-28-33-0500.md +Wrote report: /Users/hermesmasteragent/.hermes/hermes-agent/starter-kits/delegation-readiness-doctor/artifacts/ci-result-interpreter-2026-04-23T20-28-33-0500.md +Latest report: /Users/hermesmasteragent/.hermes/hermes-agent/starter-kits/delegation-readiness-doctor/artifacts/latest-ci-result-interpreter.md +/Users/hermesmasteragent/.hermes/hermes-agent/starter-kits/delegation-readiness-doctor/artifacts/workflow-approval-trigger-2026-04-23T20-28-35-0500.md +WORKFLOW_APPROVAL_TRIGGER_ALREADY_POSTED +Wrote report: /Users/hermesmasteragent/.hermes/hermes-agent/starter-kits/delegation-readiness-doctor/artifacts/workflow-approval-trigger-2026-04-23T20-28-35-0500.md +Latest report: /Users/hermesmasteragent/.hermes/hermes-agent/starter-kits/delegation-readiness-doctor/artifacts/latest-workflow-approval-trigger.md +/Users/hermesmasteragent/.hermes/hermes-agent/starter-kits/delegation-readiness-doctor/artifacts/workflow-approval-brief-2026-04-23T20-28-37-0500.md +Wrote report: /Users/hermesmasteragent/.hermes/hermes-agent/starter-kits/delegation-readiness-doctor/artifacts/workflow-approval-brief-2026-04-23T20-28-37-0500.md +Latest report: /Users/hermesmasteragent/.hermes/hermes-agent/starter-kits/delegation-readiness-doctor/artifacts/latest-workflow-approval-brief.md +/Users/hermesmasteragent/.hermes/hermes-agent/starter-kits/delegation-readiness-doctor/artifacts/upstream-blocker-refresh-2026-04-23T20-28-25-0500.md +UPSTREAM_BLOCKER_PACKET_UNCHANGED +# Delegation Readiness Doctor — Artifact Consistency Check + +- latest-workflow-approval-state-change.md: head=cb855b84a33124e7c0c11df06fc2116cd6afd03e | base=6fdbf2f2d76cf37393e657bf37ceda3d84589200 +- latest-pr-review-monitor.md: head=cb855b84a33124e7c0c11df06fc2116cd6afd03e | base=6fdbf2f2d76cf37393e657bf37ceda3d84589200 +- latest-ci-result-interpreter.md: head=cb855b84a33124e7c0c11df06fc2116cd6afd03e | base=6fdbf2f2d76cf37393e657bf37ceda3d84589200 +- latest-workflow-approval-trigger.md: head=cb855b84a33124e7c0c11df06fc2116cd6afd03e | base=6fdbf2f2d76cf37393e657bf37ceda3d84589200 +- latest-workflow-approval-brief.md: head=cb855b84a33124e7c0c11df06fc2116cd6afd03e | base=6fdbf2f2d76cf37393e657bf37ceda3d84589200 + +CONSISTENT: head=cb855b84a33124e7c0c11df06fc2116cd6afd03e | base=6fdbf2f2d76cf37393e657bf37ceda3d84589200 +UNCHANGED_PACKET_HYGIENE restored_latest=7 removed_timestamped=5 +Skipped report write for unchanged blocker packet: /Users/hermesmasteragent/.hermes/hermes-agent/starter-kits/delegation-readiness-doctor/artifacts/upstream-blocker-refresh-2026-04-23T20-28-25-0500.md +Latest report: /Users/hermesmasteragent/.hermes/hermes-agent/starter-kits/delegation-readiness-doctor/artifacts/latest-upstream-blocker-refresh.md +``` + +## Failure notes +- none diff --git a/starter-kits/delegation-readiness-doctor/scripts/verify-unchanged-refresh-hygiene.sh b/starter-kits/delegation-readiness-doctor/scripts/verify-unchanged-refresh-hygiene.sh new file mode 100755 index 0000000000..245a7c401e --- /dev/null +++ b/starter-kits/delegation-readiness-doctor/scripts/verify-unchanged-refresh-hygiene.sh @@ -0,0 +1,128 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +KIT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" +ARTIFACT_DIR="$KIT_DIR/artifacts" +mkdir -p "$ARTIFACT_DIR" + +TIMESTAMP="$(date +%Y-%m-%dT%H-%M-%S%z)" +REPORT_PATH="$ARTIFACT_DIR/unchanged-refresh-hygiene-proof-$TIMESTAMP.md" +LATEST_PATH="$ARTIFACT_DIR/latest-unchanged-refresh-hygiene-proof.md" +BEFORE_PATH="$(mktemp)" +AFTER_PATH="$(mktemp)" +REFRESH_LOG="$(mktemp)" + +cleanup() { + rm -f "$BEFORE_PATH" "$AFTER_PATH" "$REFRESH_LOG" +} +trap cleanup EXIT + +snapshot_state() { + local output_path="$1" + python - "$ARTIFACT_DIR" "$output_path" <<'PY' +import hashlib +import json +import sys +from pathlib import Path + +artifact_dir = Path(sys.argv[1]) +output_path = Path(sys.argv[2]) +latest_names = sorted(path.name for path in artifact_dir.glob('latest-*.md')) +timestamped_names = sorted( + path.name + for path in artifact_dir.glob('*.md') + if path.name not in latest_names and '-20' in path.name +) +latest_hashes = {} +for name in latest_names: + data = (artifact_dir / name).read_bytes() + latest_hashes[name] = hashlib.sha256(data).hexdigest() +output_path.write_text(json.dumps({ + 'latest_hashes': latest_hashes, + 'timestamped_names': timestamped_names, +}, indent=2, sort_keys=True) + '\n', encoding='utf-8') +PY +} + +snapshot_state "$BEFORE_PATH" + +set +e +bash "$SCRIPT_DIR/refresh-upstream-blocker-packet.sh" >"$REFRESH_LOG" 2>&1 +refresh_status=$? +set -e + +snapshot_state "$AFTER_PATH" + +python - "$BEFORE_PATH" "$AFTER_PATH" "$REFRESH_LOG" "$REPORT_PATH" "$LATEST_PATH" <<'PY' +import json +import shutil +import sys +from datetime import datetime +from pathlib import Path + +before_path = Path(sys.argv[1]) +after_path = Path(sys.argv[2]) +refresh_log_path = Path(sys.argv[3]) +report_path = Path(sys.argv[4]) +latest_path = Path(sys.argv[5]) + +before = json.loads(before_path.read_text(encoding='utf-8')) +after = json.loads(after_path.read_text(encoding='utf-8')) +refresh_log = refresh_log_path.read_text(encoding='utf-8') +unchanged_token = 'UPSTREAM_BLOCKER_PACKET_UNCHANGED' in refresh_log +hygiene_token = 'UNCHANGED_PACKET_HYGIENE' in refresh_log +latest_unchanged = before['latest_hashes'] == after['latest_hashes'] +timestamped_unchanged = before['timestamped_names'] == after['timestamped_names'] + +missing = [] +if not unchanged_token: + missing.append('refresh did not emit UPSTREAM_BLOCKER_PACKET_UNCHANGED') +if not hygiene_token: + missing.append('refresh did not emit UNCHANGED_PACKET_HYGIENE') +if not latest_unchanged: + missing.append('latest-* artifact hashes changed during an unchanged refresh') +if not timestamped_unchanged: + before_set = set(before['timestamped_names']) + after_set = set(after['timestamped_names']) + added = sorted(after_set - before_set) + removed = sorted(before_set - after_set) + missing.append(f'timestamped artifact set changed; added={added}, removed={removed}') + +verdict = 'UNCHANGED_REFRESH_HYGIENE_PROVED' if not missing else 'UNCHANGED_REFRESH_HYGIENE_FAILED' +now = datetime.now().astimezone().strftime('%Y-%m-%d %H:%M %Z') +log_excerpt = '\n'.join(refresh_log.splitlines()[-30:]) +report = f"""# Delegation Readiness Doctor — Unchanged Refresh Hygiene Proof + +Generated: {now} + +## Verdict +{verdict} + +## What this proves +This verifier guards the external-wait loop breaker: when the upstream blocker packet is materially unchanged, rerunning the one-command refresh must not rewrite canonical `latest-*` artifacts or leave fresh timestamped component artifacts behind. + +## Checks +- Refresh emitted `UPSTREAM_BLOCKER_PACKET_UNCHANGED`: `{unchanged_token}` +- Refresh emitted `UNCHANGED_PACKET_HYGIENE`: `{hygiene_token}` +- Canonical `latest-*` artifact hashes unchanged: `{latest_unchanged}` +- Timestamped artifact set unchanged: `{timestamped_unchanged}` +- Latest artifact count checked: `{len(after['latest_hashes'])}` +- Timestamped artifact count checked: `{len(after['timestamped_names'])}` + +## Refresh log excerpt +```text +{log_excerpt} +``` + +## Failure notes +{chr(10).join(f'- {item}' for item in missing) if missing else '- none'} +""" +report_path.write_text(report, encoding='utf-8') +shutil.copyfile(report_path, latest_path) +print(report_path) +print(verdict) +raise SystemExit(0 if not missing else 1) +PY + +printf 'Latest proof: %s\n' "$LATEST_PATH"