Files
hermes-agent/hermes_state_mutation_reset.py
David Dudok de Wit dbd772ba43 fix(state): exclude workers across the complete conversation lineage
A worker on a physical transcript fences its logical FIFO and second registrations. Explicit reset revokes only unlinked unknown workers, preserving live and admission-linked fences.

Reported-by: itsflownium (https://github.com/NousResearch/hermes-agent/pull/106742#issuecomment-6050777316)

Validation: tests/hermes_state/test_worker_lineage_exclusion.py, tests/gateway/test_unknown_resolution_physical_worker.py

Implementation and additional regression probes were AI-assisted with GPT-6 Astra.

(cherry picked from commit b31ed5232056100c55568d67a0c8ab6426886d4f)
2026-10-08 09:10:26 -07:00

44 lines
2.4 KiB
Python

"""Prepare and publish a local reset inside the mutation receipt transaction."""
import json
import uuid
import time
from hermes_state_local import POLICY_PREFIX
from hermes_state_local_lineage import advance_local_target, validate_local_lineage
from hermes_state_mutation_guards import require_target_advanceable
from hermes_state_runtime import RuntimeStoreError
def reset_in_transaction(db, conn, session_id, payload):
saved = conn.execute('SELECT value FROM state_meta WHERE key=?',
(POLICY_PREFIX + session_id,)).fetchone()
if saved is None:
raise RuntimeStoreError('runtime_coordination_required')
receipt = json.loads(saved[0])
target = validate_local_lineage(conn, receipt)
from hermes_state_runtime_workers import discard_orphan_workers_on_reset, runtime_lineage
discard_orphan_workers_on_reset(conn, runtime_lineage(conn, session_id))
require_target_advanceable(db, conn, list({session_id, target}))
parent = conn.execute('SELECT * FROM sessions WHERE id=?', (target,)).fetchone()
policy = receipt['policy']
from gateway.session import SessionEntry
previous = SessionEntry.from_dict(receipt['entry'])
from gateway.session_lifecycle import _now
now = _now()
child_id = uuid.uuid4().hex
entry = SessionEntry(previous.session_key, child_id, now, now,
origin=previous.origin, platform=previous.platform, chat_type=previous.chat_type,
display_name=previous.display_name, is_fresh_reset=True)
db._publish_child_session_row(conn, parent, parent_session_id=target,
child_session_id=child_id, source=policy['source'], model=policy['model'],
model_config={'_reset_from': target}, system_prompt=None,
cwd=policy['cwd'], profile_name=parent['profile_name'])
conn.execute("UPDATE sessions SET ended_at=?,end_reason='session_reset' WHERE id=?", (time.time(), target))
db._bump_conversation_generation(conn, target, 'session_reset')
advance_local_target(conn, target, child_id, entry=entry.to_dict())
conn.execute('UPDATE sessions SET runtime_generation=runtime_generation+1 WHERE id=?', (session_id,))
generation = conn.execute('SELECT runtime_generation FROM sessions WHERE id=?', (session_id,)).fetchone()[0]
# advance_local_target already advances the logical owner's revision.
return set(), {'target_session_id': child_id, 'previous_target_session_id': target,
'execution_generation': generation}