Skip to content

Serialize Hermes inbox doorbells with typed steering #77

Description

@pranaypratyush

Problem

The durable inbox path can ring a Hermes persistent TUI without taking the task's Hermes delivery lock. Direct typed Hermes steering takes that lock. A doorbell or watcher re-ring can therefore run concurrently with typed slash/key delivery or persistent-TUI lifecycle activity and mutate the same composer without serialization.

Observed behavior

The PR 68 standards review identified the missing lock and found that the existing test only asserted that a doorbell was emitted. Current main still documents the omission in bin/fm-task-inbox-lib.sh.

Expected invariant

All Hermes input mutations for one task—typed steering, inbox doorbells, and watcher re-rings—are serialized by the same delivery owner. The durable inbox record remains the source of truth; a doorbell is only a transport hint. A failed or ambiguous delivery preserves the record and never acknowledges it as handled.

Evidence and causal boundary

  • Current main explicitly says Hermes inbox doorbells do not take .hermes-delivery.lock at bin/fm-task-inbox-lib.sh:187-201; it then performs composer inspection and submission at :216-227.
  • Direct Hermes steering acquires that lock before state checks and input preparation at bin/fm-send.sh:886-907.
  • The standards review identifies the same unsynchronized path and missing concurrency regression at data/pr68-standards-impact/report.md:16-23.
  • The inbox record/acknowledgement contract remains in bin/fm-task-inbox-lib.sh; this issue concerns only the Hermes transport serialization boundary.

The causal boundary is the shared Hermes delivery lock in Firstmate's sender and inbox-ring paths. A live interleaving has not been forced, but the source-level lock omission is proven and the relevant test gap is explicit.

Impact

A supervisor message can interleave with a human or lifecycle command, be submitted with corrupted ordering, or trigger duplicate/re-ring behavior. The durable record then remains harder to reconcile with what the worker actually received.

Relationship to existing work

PR #68 is merged and owns the durable local inbox; its review recorded this follow-up rather than resolving it. PR #71 is merged and fixes the OMP worker inbox path, not Hermes locking. PRs #70 and #72 cover remote lifecycle reports and Herdr away-mode composer admission respectively. Open issue #74 owns stale supervision summaries, not input serialization. No issue in the complete dnth/firstmate history covers this Hermes race.

Acceptance criteria

  1. Inbox doorbells and watcher re-rings acquire the same task-scoped Hermes delivery lock used by typed steering before any composer read or input mutation.
  2. The lock is released on success, refusal, signal interruption, and backend error; no path acknowledges the durable record merely because a doorbell was attempted.
  3. Concurrent typed and inbox operations have deterministic ownership and do not interleave payload bytes or Enter actions.
  4. Portable tests cover lock contention, failed submission, and durable-record preservation; a live opt-in test covers a persistent Hermes TUI without changing unrelated harness behavior.
  5. /exit, key operations, and non-Hermes inbox transports retain their existing contracts.

Deterministic regression scenario

Start a disposable Hermes task with a blocking fake delivery adapter. Hold the Hermes delivery lock with a typed operation, attempt an inbox doorbell and a watcher re-ring, and assert they wait or return a bounded refusal without touching the composer. Release the lock, perform one delivery, and assert the exact durable record is handled once. Repeat with a failed submission and assert the record remains pending for a later re-ring.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions