mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-07 02:51:50 +00:00
chore: add unchanged refresh hygiene proof harness
This commit is contained in:
parent
cb855b84a3
commit
1ee3ed0185
3 changed files with 184 additions and 0 deletions
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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"
|
||||
Loading…
Add table
Add a link
Reference in a new issue