Skip to content

feat(hermes): prove the message boundary of a one-shot turn (issue #5 proposal 1) - #8

Merged
askclaw-vesper merged 2 commits into
mainfrom
feat/hermes-message-boundary
Aug 20, 2026
Merged

askclaw-vesper merged 2 commits into
mainfrom
feat/hermes-message-boundary

Conversation

@askclaw-vesper

Copy link
Copy Markdown
Collaborator

Implements issue #5, proposal 1 (Hermes message-boundary check). Stacked on #7 — merge that first; this branch will be updated.

Problem

The README promises the "final active message" from state.db, but nothing bounded which message is the turn: the adapter took the max-id active assistant row, absorbing late or foreign writes silently.

What changes (adapter, fail-closed)

  • Window bound: every row in the matched session must carry a timestamp inside the invocation window. A row outside it — late finalization write, reused/continued session, concurrent writer — means the boundary between "the turn" and "later activity" is unproven: completion refused.
  • Continuation bound: the turn is the final ACTIVE text-bearing assistant message; an active user row after it means the session continued beyond this turn: completion refused.
  • Recorded span: the proof gains message_boundary (first_message_id, final_message_id, message_count) so review sees exactly which rows bounded the turn.

Explicit exception rules (documented in the technical reference)

Normal one-shot noise that stays accepted: interim active assistant drafts before the final message (tool narration, superseded text — the contract fixture itself writes one) and inactive tail rows (compaction ghosts). Everything else about the boundary fails closed.

Canary (from the proposal)

Fixture with a later ACTIVE assistant message (timestamped outside the window) → turn rejected, ProtocolError, no ledger commit, completed_turns empty (test_late_assistant_message_fails_closed). Matrix additions: continued-session user row, unusable timestamp, boundary-record contents.

Tests

  • New fake knobs: FAKE_LATE_ASSISTANT, FAKE_FOLLOWUP_USER.
  • Full suite: 277 passed; scripts/verify.py{"ok": true}.

…proposal 1)

The README promises the "final active message" from state.db, but
nothing bounded WHICH message is the turn. Now every row in the
matched session must carry a timestamp inside the invocation window —
a row outside it (late finalization write, reused/continued session,
concurrent writer) fails closed. The turn remains the final ACTIVE
text-bearing assistant message; interim active drafts and inactive
ghost tails are documented as normal one-shot noise, while an active
user row after the final assistant message (a continued session)
fails closed. The accepted span (first/final message id, row count)
is recorded in the proof as message_boundary.

Canary: fixture with a later ACTIVE assistant message outside the
window → turn rejected, no ledger commit (plus the continued-session
and unusable-timestamp matrix rows).
@askclaw-vesper
askclaw-vesper force-pushed the feat/hermes-message-boundary branch from a3ded15 to 91418ef Compare August 20, 2026 05:33

@adaptcom adaptcom Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confidence Score: 4/5

Summary

Adds fail-closed message-boundary proof to the Hermes adapter (window bound, continuation bound, recorded span) with strong test coverage; verify passes. Low risk, but stacked on #7 and one tail-row class escapes the fail-closed claim.

Important Files Changed

File Overview
src/multi_agent_dialogue/adapters/hermes.py Window and continuation boundary checks; message_boundary span added to proof
examples/fakes/bin/fake-hermes New FAKE_LATE_ASSISTANT and FAKE_FOLLOWUP_USER fixture knobs
tests/test_real_contracts.py Canary, matrix, and proof-record tests for the boundary
docs/technical-reference.md Documents boundary rules and accepted one-shot noise
src/multi_agent_dialogue/config.py From stacked PR #7: evidence_versions parsing and support set
src/multi_agent_dialogue/evidence.py From stacked PR #7: strict version acceptance validation
src/multi_agent_dialogue/engine.py From stacked PR #7: passes accepted_versions to validation
src/multi_agent_dialogue/adapters/base.py From stacked PR #7: imports EVIDENCE_VERSION from evidence
schemas/protocol.schema.json From stacked PR #7: evidence_versions schema property
tests/test_config.py From stacked PR #7: evidence_versions parse tests
tests/test_evidence.py From stacked PR #7: version validation tests

Re-run review · View in Adapt

Comment thread src/multi_agent_dialogue/adapters/hermes.py Outdated
Comment thread src/multi_agent_dialogue/adapters/hermes.py
Comment thread src/multi_agent_dialogue/adapters/hermes.py Outdated
Comment thread src/multi_agent_dialogue/adapters/hermes.py Outdated
Review follow-up: the tail bound now rejects ANY active row after the
final assistant message (tool/system/empty-stub included), not just
user follow-ups; the unusable-timestamp raise chains properly; the
dead empty-session fallback is gone; message_count renamed to
session_row_count so the recorded span fields agree (the count covers
every session row, including an inactive ghost tail).
@askclaw-vesper
askclaw-vesper merged commit 4c4763e into main Aug 20, 2026
2 checks passed
@askclaw-vesper
askclaw-vesper deleted the feat/hermes-message-boundary branch August 20, 2026 06:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant