feat(approvals): persist unresolved requests - #17
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces persistence for unresolved fallback approvals by saving them to a JSON file (approval_requests.json) and loading them upon initialization. Key changes include adding _load_pending_locked and _persist_pending_locked helper functions, updating pruning and resolution logic to trigger persistence, and updating the test suite to verify that resolved requests survive process restarts. The review feedback highlights three main improvement opportunities: validating that the loaded requests field is indeed a list to prevent potential TypeError crashes, preventing duplicate request_id entries when rebuilding the session index, and replacing unnecessary copy.deepcopy calls with a shallow copy to reduce performance overhead.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
Code Review Roast 🔥Verdict: No Issues Found | Recommendation: Merge Well. I warmed up the flamethrower, laid out the previous review's list of grievances — the corrupted-JSON crash, the duplicate-ID ghost entries, the pointless per-field What got fixed
🏆 Best part: 💀 Worst part: The lazy 📊 Overall: Like a to-do list where someone actually crossed everything off before the standup — suspicious, but I'll take it. Correctness / Safety FindingsNo correctness or safety findings. Every issue from the previous pass (list validation, duplicate-ID dedup, dropped Ponytail ReviewPonytail: Lean already. Ship. The diff removed the Ponytail net: 0 lines. Suggested Minimal PatchNo patch needed. Final Merge GuidanceCan merge as-is. Files Reviewed (2 files)
Previous Review Summary (commit 79e9234)Current summary above is authoritative. Previous snapshots are kept for context only. Previous review (commit 79e9234)Verdict: 1 Issue Found | Recommendation: Address test gap before merge Overview
Issue Details (click to expand)
🏆 Best part: The 💀 Worst part: The 📊 Overall: Like a chef who seasons the steak but forgets to salt the fries — the main course is solid, the garnish has a gap. Correctness / Safety FindingsNo correctness or safety findings beyond the three already raised by gemini-code-assist ( Ponytail Review
Ponytail net: -8 lines. Suggested Minimal Patch
Final Merge GuidanceCan merge after the pending-survival test is added and the three gemini suggestions are applied. The persistence implementation is sound; the gaps are coverage and defensive validation, not correctness. Reviewed by minimax-m3 · Input: 67.4K · Output: 6.1K · Cached: 625.7K |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 79e9234a9b
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
… dispatch hook Two log-spam bugs found in live gateway logs: 1. gateway_routing UNIQUE-constraint spam (261 warnings in one errors.log): early builds of the NousResearch#59203 routing-index migration created gateway_routing with 'session_key TEXT PRIMARY KEY' and no scope column. _reconcile_columns() ADDs the missing scope column but SQLite cannot ALTER a primary key, so the shipped composite PRIMARY KEY (scope, session_key) never lands on those databases. Both write paths then fail on every save: - save_gateway_routing_entry: 'ON CONFLICT clause does not match any PRIMARY KEY or UNIQUE constraint' - replace_gateway_routing_entries: 'UNIQUE constraint failed: gateway_routing.session_key' whenever the same session_key exists under another scope (e.g. test-suite scopes leaked into a live DB). New _heal_gateway_routing_pk() rebuilds the table once with the composite key, preserving rows (newest wins on collisions, NULL scope coalesced to ''). Same one-time-heal pattern as the NousResearch#51646 active- column repair. Verified E2E against a copy of a real affected state.db. 2. pre_gateway_dispatch warned ''GatewayRunner' object has no attribute 'session_store'' and silently dropped the hook for every message on partially-initialized runners (bare object.__new__ runners in tests, and any future init-order change). Pass getattr(self, 'session_store', None) so the hook always fires (pitfall #17 pattern). Both regression tests fail without their fixes (sabotage-verified).
…attr pattern, skill pitfall #17)
Persist unresolved approval requests across restart
Part of the 2026-07-13 Hermes capability review.
What this PR does
Persists the existing request-ID-based fallback approval state machine to
approval_requests.jsonunder the active profile. Pending and resolved requests reload lazily after restart, retain scope/expiry/outcome, and remain bound to their existing argument hash.Safety
0600.Implementation
_pending/_pending_by_sessionstate machine.utils.atomic_json_write; no database or dependency added.Verification
Baseline note: the broader
tests/tools/test_approval.pycurrently has one unrelated failure onorigin/main(test_nonrecursive_verification_artifact_cleanup_is_not_dangerous); this branch does not touch that path.Out of scope