Commit Graph

8 Commits

Author SHA1 Message Date
embwl0x 7d066c3c56 fix(state): deduplicate session system prompts 2026-08-03 20:37:17 +05:30
kshitij ae17163e92 refactor(state): drop unreachable regex guard in trigger migration
Simplify-pass fold: to_drop names come from the literal update_names\nallowlist via IN binding, so the [A-Za-z0-9_]+ fullmatch could never\nfail — and if it somehow did, its `continue` would miscount (the\nskipped trigger stayed in len(to_drop)/the log while CREATE TRIGGER\nIF NOT EXISTS silently kept the broad variant). Delete the guard and\nits function-local re import; keep the invariant as a comment.
2026-08-03 20:30:32 +05:30
Jasmine Naderi b66111fc58 fix(state): quarantine CJK when ensure soft-fails after OF migration
_ensure_fts_cjk_schema never raises on OperationalError; post-condition
after dropping messages_fts_cjk_update now requires a narrowed UPDATE
trigger or durable fts_cjk_stale + unavailable. Covers the production
soft-fail path the raise-only handler missed.
2026-08-03 20:30:32 +05:30
yuzilongleif-collab a5ce909bba fix(state): fail closed on CJK trigger migration 2026-08-03 20:30:32 +05:30
Jasmine Naderi dab7c88604 fix(state): narrow FTS UPDATE triggers with AFTER UPDATE OF + migration
Retarget #73639 onto the SessionDB mixin split (hermes_state_common /
hermes_state_schema). Fresh installs create UPDATE OF content/tool_*
triggers; existing broad AFTER UPDATE triggers are inspected and
replaced under schema init without an FTS rebuild (WHEN clauses already
guarded content correctness; OF skips non-content status writes that
saturated disk I/O on large state.db).

Tests: tests/test_fts_update_of_narrowing.py (4)
2026-08-03 20:30:32 +05:30
Adolanium b2d5995fc6 fix(state): do not stamp empty FTS after interrupted optimize-storage demote
Demote wrote the empty v23 schema via executescript inside BEGIN IMMEDIATE,
which commits early and can leave trash + empty indexes without rebuild
markers. Re-run then tore down trash and stamped fts_storage_version with
docsize=0, permanently losing historical session search.

Stage markers with the demote, create schema only after they are durable,
heal empty-index bookkeeping on resume, and refuse settle until the base
index is populated. Settle refusal returns ok=False instead of raising,
and resume fails fast if the base v23 table cannot be re-created.

Orphan-marker repair only resets a missing fts_rebuild_progress to 0 once
the index is known empty: the chunk worker replays its whole selected id
range without an anti-join, so a partially indexed DB that lost only its
progress key is first reset to a known-empty surface, then rebuilt.

Ported onto the SessionDB mixin split (hermes_state_search.py /
hermes_state_schema.py).
2026-08-02 21:36:11 +05:30
RelaxJonh b6ca4fc856 fix(state): heal session_model_usage PK unconditionally to restore token/cost accounting
Installs whose state.db reached schema_version >= 22 before the task
dimension was added carry a 5-column PRIMARY KEY on
session_model_usage. The column reconciler ADDs task as a bare
nullable, but SQLite cannot ALTER a primary key, and the version-gated
v22 rebuild is unreachable (current_version < 22 already false), so
the composite 6-column key never lands. Every upsert in
_record_model_usage then fails with 'ON CONFLICT clause does not match
any PRIMARY KEY or UNIQUE constraint', aborting the enclosing write
transaction — token/cost accounting permanently dead (#73823).

Add an idempotent _heal_session_model_usage_pk() modeled on
_heal_gateway_routing_pk(), run unconditionally from _init_schema on
every open. Salvaged from #73838 with fix-ups:

- ported to SessionSchemaMixin in hermes_state_schema.py (the schema
  code moved out of hermes_state.py in 21c7ae8563; the PR targeted the
  old location)
- rebuild wrapped in a PRAGMA foreign_keys=OFF/ON window: the
  connection enables FKs before _init_schema and OR IGNORE does NOT
  suppress FK violations, so a single orphaned usage row (session
  pruned while accounting was broken) would have aborted the heal
- COALESCE('') on the nullable reconciler-added task column (and the
  billing columns) during the copy
- stale-v22+ regression tests: rebuilt PK + restored upsert, orphan
  rows survive the FK window, healthy-DB no-op, no legacy leftover

Fixes #73823
2026-07-31 23:18:12 -07:00
teknium1 21c7ae8563 refactor: split SessionDB into Search/Schema/Portability mixins (mechanical move, ~2.9K LOC out of hermes_state.py) 2026-07-29 10:14:19 -07:00