Files
multi-agent-mux/.agents/reports/planner-reviewer-claude-01/report-fcb16ed6.md
T
Godopu 6208a7fda3 feat(hermes): modernize hermes agent adapter and skills support
- Add --yolo and --accept-hooks headless auto-approval flags to spawn_spec and resume_spec
- Define Hermes TUI input delimiters (input_prompt='❯', input_rule_pattern='─{10,}')
- Refactor verify_artifact and discover in hermes.py using session started_at timestamps
- Fix HERDR_EPOCH capture timing before spawn in create_session.sh to prevent epoch race
- Update reconcile.sh for hermes drift-C multi-candidate and sibling claimed exclusion
- Add Hermes contract, epoch filtering, and C-ambiguous unit tests (140 passed)
- Add agent evaluation report and final review reports for Hermes support
2026-08-28 20:17:04 +09:00

7.7 KiB

🔍 Cross-Code Review — Hermes Agent Support Implementation, Follow-Up (Job fcb16ed6)

  • Reviewer: planner-reviewer-claude-01
  • Target diff: revised implementation of plan-28f9b565.md, superseding the diff reviewed in job 685bb381 ([VERDICT: PASS], with 2 non-blocking findings). This diff addresses both of those findings plus adds two proactive fixes not previously flagged.
  • Method: same as the prior review — read every changed file's live post-diff state directly (branch support-hermes), traced call chains, ran bash -n syntax checks, and ran the actual test suite.

1. Disposition of my Previous Review's Findings (job 685bb381)

Finding Status this round
§4.1: multi-agent-mux-resume/SKILL.md doc example was stale (didn't include --no-restore-cwd --yolo --accept-hooks) Fixed. Now reads hermes) CMD_FULL="hermes --resume $UUID --no-restore-cwd --yolo --accept-hooks" ;; — verified it matches resume_session.sh's real fallback string exactly (modulo the illustrative literal binary name, consistent with how the doc renders every other agent's row).
§4.2: _sibling_claimed_uuids set on the hermes row in reconcile.sh but never read by hermes.py::verify_artifact() (unlike agy's adapter-level pattern) Not touched directlyhermes.py::verify_artifact() still doesn't read ctx.row. This is unchanged from the prior diff and remains a minor architectural-parity note, not a live bug (the explicit loop-level if uuid in sibling_claimed: continue in reconcile.sh still enforces it correctly on its own, confirmed again this round — see §3). Still non-blocking.

2. New Changes Beyond the Prior Diff (not requested by my previous review — found and verified independently)

2.1 hermes.py::discover() rewritten to return multiple candidates (previously LIMIT 1)

def discover(self, ctx: DiscoveryContext) -> list:
    ...
    if ctx.epoch:
        rows = conn.execute("SELECT id FROM sessions WHERE cwd=? AND started_at >= ? ORDER BY started_at DESC LIMIT 20", ...)
    else:
        rows = conn.execute("SELECT id FROM sessions WHERE cwd=? ORDER BY started_at DESC LIMIT 20", ...)
    ...
    candidates = []
    for (cand,) in rows:
        if cand and self.verify_artifact(cand, ctx):
            candidates.append(cand)
    return candidates

This is a genuine, previously-unflagged fix: the old discover() used fetchone()/LIMIT 1, making hermes the only adapter whose discover() could never surface more than one candidate — inconsistent with grok.py/agy.py/cline.py, whose discover() methods already return every verified candidate. Checked for regression risk: grepped every call site of .discover( across the repo — the only real caller is workspace_uuid.py:81 (for cand in adapter.discover(ctx):), which already iterates rather than indexing, so it handles 0/1/many candidates identically regardless of agent. No caller assumes a single-element list. This change makes hermes consistent with the rest of the framework rather than introducing risk.

The new test_hermes_verify_artifact_spawn_epoch_timing_f1 test specifically exercises discover() with a mix of old (started_at < epoch) and fresh rows and asserts only the fresh one survives — I re-ran it directly, passes.

2.2 create_session.sh: HERDR_EPOCH capture moved earlier, before spawn()

+HERDR_EPOCH=$(date +%s)
+NOW_ISO=$(date -u +'%Y-%m-%dT%H:%M:%SZ')
+
 spawn
 ...
-HERDR_EPOCH=$(date +%s)
-NOW_ISO=$(date -u +'%Y-%m-%dT%H:%M:%SZ')

This closes a real timing edge case in Rev.2's own epoch-based fix that neither my review nor the plan itself had caught: previously HERDR_EPOCH was captured after spawn(), wait_for_tui_ready, and pane-metadata resolution — all of which can take multiple seconds. Since HERDR_EPOCH becomes herdr_session_epoch in the registry and flows into ctx.epoch for the new started_at >= ctx.epoch check, a late-captured epoch could end up later than the freshly-spawned session's own started_at, causing the epoch guard to falsely reject the very session it was meant to validate — self-defeating. Capturing it immediately before spawn() guarantees HERDR_EPOCH <= started_at for the session about to be created.

Verified this is safe for every agent, not just hermes: HERDR_EPOCH is a single shared line (not gated by $AGENT), consumed generically by verify_session_uuid's epoch = row.get("herdr_session_epoch", 0) for all agents. For claude/agy/grok, whose verify_artifact() implementations use os.path.getmtime(path) < ctx.epoch, an earlier epoch can only make that check more lenient (smaller epoch → less likely to be > a file's mtime), never more restrictive — so this is a strictly safe, general robustness improvement, not a hermes-only special case. grep -rn "HERDR_EPOCH" confirms its only consumer (create_session.sh:346, feeding lib.sh's YAML-write step) is unaffected by the earlier capture point — it only needs the variable to exist by the time it's read, which it still does.


3. Re-Verification of Everything from the Prior (Already-PASSed) Review

Re-traced and re-confirmed unchanged/still-correct (identical diff hash 974a367 for reconcile.sh vs. the prior review — no regression risk here, but re-verified functionally with the fuller test run below):

  • Core C-ambiguous epoch fix (verify_artifact row-level started_at check + reconcile.sh's started_at >= ? SQL filter + sibling-exclusion loop) — still correct, still passes its dual-direction regression test.
  • --yolo --accept-hooks / --no-restore-cwd wiring across spawn_spec/resume_spec/create_session.sh/resume_session.sh/both SKILL.md files — consistent everywhere, no drift.
  • input_prompt/input_placeholder/input_rule_pattern/ready_tokens — unchanged, still correct.

bash -n on create_session.sh (re-checked after the epoch-timing edit) — valid.


4. Test Suite — Functional Verification

.venv/bin/python -m pytest tests/test_a4_adapter_contract.py -q -v
→ 19 passed (17 from before + 2 new: test_hermes_verify_artifact_spawn_epoch_timing_f1, test_hermes_reconcile_full_block_integration)

.venv/bin/python -m pytest tests/ -q
→ 441 passed in 625.89s (0:10:25), exit code 0

I ran the full suite myself (not the diff's own claims) rather than sampling only the adapter-contract file, given this diff touches session-creation timing (create_session.sh) which is broader-surface than the previous diff. 441 passed vs. 439 in the previous review — the +2 matches exactly the two new hermes regression tests added in this diff, and there are zero failures.


5. Findings Carried Forward (non-blocking, unchanged from job 685bb381)

  • _sibling_claimed_uuids is still set-but-unread at the hermes.py adapter level (§1 above). Still recommend either removing the unused field or moving the check into verify_artifact() for architectural parity with agy's pattern — purely a consistency/future-proofing item, not a live defect.

No new findings beyond that one. No design rework is warranted — this round demonstrably improved on the already-PASSed implementation rather than introducing regressions.


6. Verdict

Both items from my previous review are now closed (one fully fixed, one confirmed still non-blocking and unchanged), and the two additional changes in this diff (discover() multi-candidate parity, HERDR_EPOCH pre-spawn capture) are correct, well-targeted fixes to real edge cases in the underlying epoch-based design — verified independently via call-site tracing and the full test suite, not accepted on the diff's own say-so. No correctness defects found; no escalation warranted.

[VERDICT: PASS]