fix(state): rebuild legacy gateway_routing PK; guard session_store in dispatch hook - #73541
Merged
Conversation
… 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 #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 #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).
Contributor
૮ >ﻌ< ა ci reviewran on 49e13fd ℹ️ InfoDesktop E2E visual evidence · View test artifacts · View job1 visual diff. inline evidence upload failed. Failed to upload diff-665a0833239e-onboarding-overlay-diff.png with gh image (exit code 1): Error uploading /home/runner/work/_temp/e2e-evidence/diff-665a0833239e-onboarding-overlay-diff.png: step 0 (get upload token): uploadToken not found on repo page — do you have write access to NousResearch/hermes-agent? (or, if NousResearch enforces SAML SSO, authorize at https://github.com/orgs/NousResearch/sso) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Heals live databases stuck with the pre-scope
gateway_routingPRIMARY KEY, ending per-save "routing save failed" warning spam, and guards thepre_gateway_dispatchhook'ssession_storeaccess so the hook always fires.Root cause: early builds of the #59203 routing-index migration created
gateway_routingwithsession_key TEXT PRIMARY KEYand noscopecolumn. The declarative column reconciler ADDs the missingscopecolumn, but SQLite cannot ALTER a primary key — so the shipped compositePRIMARY KEY (scope, session_key)never lands on those databases and every routing save fails:save_gateway_routing_entry→ON CONFLICT clause does not match any PRIMARY KEY or UNIQUE constraintreplace_gateway_routing_entries→UNIQUE constraint failed: gateway_routing.session_keywhenever the same session_key exists under another scopeOne live errors.log carried 261 of these warnings; the store silently falls back to sessions.json every time.
Changes
hermes_state.py: new_heal_gateway_routing_pk()— detects the legacy PK viaPRAGMA table_info, rebuilds the table once with the composite key, preserves rows (newest wins on collisions, NULL scope coalesced to''). Wired into_init_schema()right after_reconcile_columns(). Same one-time-heal pattern as the [Bug]: Gateway Memory Loss — INSERT omitsactivecolumn inhermes_state.py#51646active-column repair.gateway/run.py:pre_gateway_dispatchkwargs now passgetattr(self, "session_store", None)— a partially-initialized runner previously raised inside the dispatch try-block, logging'GatewayRunner' object has no attribute 'session_store'and dropping the hook for every message.TestGatewayRoutingPkHeal(4 cases: rebuild, both write paths post-heal, NULL-scope coalesce, idempotence on modern shape) + hook-fires-without-session_store regression. All fail without their fixes (sabotage-verified).Validation
scripts/run_tests.sh tests/test_hermes_state.py tests/gateway/test_session.py tests/gateway/test_session_store_lock_io.py→ 626 passed, 0 failed.tests/gateway/test_pre_gateway_dispatch.py→ 6 passed.Infographic