Repository navigation
Conversation
|
Heads-up: the config slice of this PR (per-profile If this draft ends up wanting to land the config part on its own first (smaller, no infra dependency), #96302 is that slice already reviewed — feel free to lift from it or ping me. Otherwise ignore and carry on here. |
matrix.process_edits was documented and tested as working via config.yaml, but _YAML_LOWER_KEYS (the apply_yaml_config_fn hook that turns config.yaml's matrix: block into env vars) never listed it, so setting matrix.process_edits: true in config.yaml silently did nothing — only the MATRIX_PROCESS_EDITS env var actually worked. Add the missing tuple entry (mirroring process_notices) and a test that drives the real _apply_yaml_config bridge instead of only asserting against a hand-constructed PlatformConfig(extra=...).
The initial edit option used a global boolean and trusted the relation inside m.new_content. An edit could therefore change another author's input, route a correction into a different thread, or enter the active turn through the gateway's interrupt or steering policy. Configure corrections with exact room IDs and boolean values, defaulting to no enabled rooms. Validate the original event's room and author with the receiving adapter's client, then use its original thread relation. Apply the current sender, room, notice and mention policies. Typed edits must supply genuine replacement content because mautrix serialization can manufacture m.new_content. Encrypted validation uses the existing client crypto and replacement reader. Queue corrections through the existing pending slot and FIFO, replacing pending edits to the same original in their existing position. Recheck both events and current authorisation in shared turn preparation, so cold and recursive queued turns reject withdrawn corrections even after cache eviction. Edited commands remain external conversational text. Append the correction as a new user turn with its original event ID. Earlier model messages and the system prompt remain unchanged. Keep the existing opening-event reply anchor for final delivery in a queued chain. Two parameterised invariants reproduce the original policy, routing and active-turn failures. Six additional rows reproduce a withdrawn pending replacement after cache eviction. All 50 rows pass with the repair, and the adjacent gateway gate passes 766 tests across 39 files.
With busy_input_mode: queue, the base adapter debounces ordinary text that arrives during a turn and merges the buffer into the pending slot when the slot holds an event from the same sender. A Matrix correction waiting in that slot is a text event from the same sender, so the user's next message was appended to it. At turn start the adapter compares the queued correction with the server's copy of the edit. The merged text no longer matched, so the gateway dropped both the correction and the new message without a reply. Debounced text is now never merged with an event that waits for a turn boundary. The text stays in the debounce buffer while the correction occupies the slot, and the existing flush at the end of each turn moves it into the slot as its own turn. When a correction arrives while text is already buffered, the adapter flushes the buffer first, so that text runs before the correction, in the order the user sent them.
Edit handling and turn-start validation resolved a correction's context with the original event ID. _resolve_message_context records that ID as the thread's latest event, which bot messages without an explicit reply target use for their reply fallback, and it sends a read receipt for it. Each correction therefore moved the thread's fallback target back to the original and sent a receipt for an older event. The edit handler did this before it checked the sender's authorisation. _resolve_message_context now accepts record=False, which leaves the thread trackers and the read receipt to the caller. The correction handler resolves the context this way and checks authorisation first. Only an accepted correction marks its thread and sends a read receipt, and the receipt is for the edit event. Turn-start validation records nothing.
A correction event's message ID is the ID of the m.replace event. Clients display a replacement as the original message and do not show the edit event itself, so the processing, success and failure reactions that the adapter placed on the edit were invisible. Corrections now use the original event as the reaction target.
The bridge test set MATRIX_PROCESS_EDITS before applying the YAML configuration and then asserted that the value was unchanged. apply_yaml_bridge never overwrites a variable that is already set, so the test would also pass if a process_edits bridge row came back. The test now starts with the variable unset and asserts that it stays unset. With a bridge row restored, it fails.
The edit follow-up section did not say which message a correction's reply refers to. A correction's reply is a Matrix reply to the original message when the correction starts its own turn or runs before the end of a queued chain. When the correction is the last queued message to run after a busy turn, the gateway sends the reply as a Matrix reply to the message that started that turn, as it does for every queued message. Document this, and document that corrections are never merged with other messages, that the model receives the corrected text as typed, and that processing reactions appear on the original message.
The effective-state parent added requires_mention as the sixth field of the tuple from _resolve_message_context. The correction handler still unpacked six fields, so every accepted edit raised ValueError before an event was built, and no correction reached the gateway. Unpack the new field as well. The handler does not use requires_mention itself: _build_inbound_event reads it from the same context and records matrix_requires_mention on the correction as it does for other messages.
The effective-state parent removed fetch_mention_context and take_turn_channel_context from the adapter, and the gateway now calls use_turn_context on the snapshot from fetch_inbound_context. The correction tests stubbed all three methods, so monkeypatch failed on the missing attributes, and a None snapshot would fail in the core. Drop the stubs so turn preparation uses the adapter's real snapshot and prepare_turn_context. The hook looks up the session through the runner's session store, so the cold runners get a SessionStore in tmp_path, and the room identity fake has room_state instead of the removed members_digest.
The effective-state parent moved the Matrix client helpers into client_events.py, which provides Method with its own stand-in for environments without mautrix. The correction module still had a private try/except that fell back to read_context's re-export. Import Method from client_events, as the other Matrix context modules do, so the plugin has one fallback definition.
A correction must wait for a turn boundary and take its own turn. The
busy-session handler already queues a turn-boundary event through the
FIFO. The runner has a second route to a running session:
_hm_handle_running_session_message, reached from _handle_message when
the runner has a running turn for the session but the adapter has no
session guard. That route ignored _queue_at_turn_boundary.
The state is reachable in production. The CLI handoff runs its
synthetic turn through _handle_message directly, so the adapter has no
guard for that session for the whole turn. Auto-resume after a restart
claims the pending-agent sentinel before its task reaches
handle_message, and expects inbound messages in that window to reach
this route. A correction arriving then was merged into the pending text
while the agent was starting, and in interrupt or steer mode it was
delivered into the running turn.
Skip the pending-agent merge for turn-boundary events and send them
through the queue-mode branch, which uses the same FIFO as the busy
handler. The drain check still comes first, as in the busy handler.
The new test builds a correction with the real Matrix adapter and passes
it to the real runner while the session has a running turn and no
adapter guard. Before the change it failed in three of four modes: the
pending-agent case produced "earlier text\nlatest correction", interrupt
mode called interrupt("latest correction"), and steer mode steered the
correction into the turn. Queue mode already queued it.
The effective-state parent now contains NousResearch#125648, which quotes the triggering event once per threaded response. A send anchored on an event that Hermes has already answered in the thread is a continuation: it sets is_falling_back and points at the latest event in the thread. A correction that waits behind a paused turn runs as the last message of the queued chain. Its answer is anchored on the message that started the paused turn, as for every queued message, and the first response already answered that message. The native test still expected both responses to be genuine replies to that message, so the plain and encrypted enabled cases failed with is_falling_back true and m.in_reply_to pointing at the first response. The client now expects the first response to quote the blocked message and each later response to fall back to the response before it, in the expected order. The Matrix guide describes the correction's reply in that case as a thread message after the running turn's answer.
…b it In busy_text_mode queue, text that arrives during a turn waits in a per-session debounce buffer. _flush_text_debounce_now moves the buffer into the adapter's pending slot, but only when the slot is empty or its event may absorb the text. Two senders' texts may not merge, and since the Matrix edit follow-ups a queued correction absorbs no text at all. When the slot could not absorb the buffer, the flush returned without moving it and cancelled its timer. The buffer then waited for the next flush. _queue_text_debounce made that loss visible. A message from a different sender first flushes the buffer. When the flush failed and the slot could not absorb the new message either, the function returned without storing it, and nothing logged the drop. Threads are shared between their participants by default, so in queue mode a correction followed by texts from two people lost the second text. On main the same happened to a third sender's text while the slot contained text from someone else. The unflushed buffer also broke arrival order: text sent between two corrections ran after the second one, because the second correction went to the runner's FIFO while the text stayed in the buffer. When the slot cannot absorb the buffer, hand the buffered event to the runner's _queue_or_replace_pending_event, which appends it to the FIFO behind the slot with the same cap and album rules as other busy follow-ups. The adapter already reaches the runner through gateway_runner for delivery scope and live-adapter lookups. The buffer is then empty, so the next sender starts a fresh buffer instead of reaching the drop. Each sender's burst still runs as one turn, in arrival order. An adapter without a runner keeps the previous behaviour, because it has no FIFO. The platform-neutral test sends text from two senders while the slot contains a third sender's text, and while it is empty. Before the change, "three" was missing in both rows and a buffer stayed stranded with no timer. The Matrix test covers a pending correction followed by text from Alice and Bob, and from Bob and Carol, with and without the timer firing between them. Before the change the second message was lost in all four rows.
Text that the user sends after one correction and before another must run between them. Before the previous commit, the text stayed in the debounce buffer because the first correction in the pending slot could not absorb it, while the second correction went to the runner's FIFO. The observed order was $edit1, $edit2, $text. The debounce flush now hands the text to the FIFO behind the first correction, and the flush before the second correction's busy handling runs first, so the order is $edit1, $text, $edit2. This test asserts that order. It failed on the parent of the previous commit with [$edit1, $edit2, $text].
A correction's m.new_content has no reply fallback, so a leading quote in it is the user's own text. After the merge of the effective-state parent, three conditions in the adapter strip a quote only when reply_fallback is true and _has_reply_fallback recognises a legacy fallback. The existing quote-on-reply row starts with "> quoted line", which _has_reply_fallback rejects because it has no sender pill, so that row passed even with reply_fallback removed from the conditions. Add rows whose body quotes Bob with a pill and a blank line, which is the shape of a legacy fallback, for an original that is a reply and for one in a thread. With "reply_fallback and" removed from the three conditions, both rows fail with "my answer" in place of the full quoted body. The two older rows pass under that mutation.
The guide said that a correction's reply quotes the original message, except for the last queued message after a busy turn. That is wrong in both session shapes. In a thread, a send anchored on a message that Hermes has already answered is a thread continuation: it has no quote and falls back to the latest message in the thread. People usually correct a message that Hermes has answered, so an idle correction is normally a continuation too. The reply quotes the original only when Hermes has not answered it yet, for example when the edit adds a missing mention. Outside a thread the continuation rule does not apply. The reply quotes the original, and the last queued message after a busy turn quotes the message that started that turn, as for every queued message. Describe the two cases separately.
iainlane
force-pushed
the
feat/matrix-receipts-lifecycle
branch
2 times, most recently
from
October 1, 2026 12:48
e2502e7 to
1470db3
Compare
Cached text can contain an opaque marker. Exercise normal and restored queue execution with the actual model request path so the test detects transcript substitution, role changes and profile owner leaks before the request reaches the model.
An accepted leftover /steer can arrive while provisional pending input has already filled the queue. The drain ignored FIFO admission failure, so it dropped the correction while keeping the provisional input. The branch that prioritised a steer over a queued event also restored that event directly without releasing its provisional dispatch reservation. Retain an unadmitted steer for the next turn. Check each pending input through the recognised-command guard before combining the remaining text, so a residual command is discarded without losing the correction. Restore deferred FIFO events through the existing dispatch helper, which releases reservations while preserving order. Three assertion failures reproduce the lost correction with ordinary provisional text, the residual /help safety case, and the restored FIFO state on the parent. The FIFO contract releases each returned dispatch before measuring queue depth, as the caller does in normal operation. All eight contracts in the existing file pass after the fix. Integrate the pending-admission correction with the current pinned channel-input constructor. The drain now uses the actual FIFO admission result, preserves unadmitted steering text and releases a deferred event reservation through the existing restore helper. The complete original regression contracts and assertions remain unchanged.
A steer accepted by the running agent can return unconsumed while earlier queued input and provisional dispatches fill the pending queue. Admission then fails when the drain moves the steer to its own turn. Dropping that accepted input loses the correction and its processing completion. Restore the tracked steer through the existing pending-dispatch helper and park its lifecycle before transferring completion ownership. Restoration preserves accepted input, while the admission threshold still rejects new messages. The earlier queued event keeps its own dispatch and runs first; the restored steer retains its message identity and completes with its own turn or with cancellation if the queue is stopped. The regression drives the real runner and adapter with a scripted model, queued input and a full set of provisional reservations. It checks model input, admission rejection, processing outcomes and retained reservations for successful delivery and /stop.
The receipt teardown contract observed the former text-only flush call. The current adapter writes a complete pending snapshot before clearing its slots, so that observer missed a successful write. Wrap the actual snapshot writer and retain the completion, ordering and empty-slot assertions. The wrapper still writes the real snapshot. Supply joined room members for the current Matrix authorization check. Combine the native feedback settings with the existing paused-queue configuration in one display section, and retain the additive auxiliary configuration fixture required by the unread tool. These fixtures use the current adapter and configuration paths without replacing their behaviour assertions. The fixture contribution is split between the receipt and unread layers. Record its complete rationale in the receipt history. The current source uses the real snapshot observer, the original membership assertions and the consumed auxiliary fixture, with one parsed YAML display document. The paused-context public fixture selects input mode `queue` and text mode `interrupt`. Busy follow-ups enter the runner FIFO because interruption requires effective input mode `interrupt`. The queued-context consumer checks retained quoted context, the preceding prompt prefix and eventual dispatch; its contract does not require adapter debounce or coalescing. This accepts direct FIFO admission as the adaptation of the former queued-text fixture. Normal-mode steer cases keep their explicit override. This records contributor credit and the public fixture adaptation without changing the source tree.
Native SimpleX chat items include the quoted message separately from incoming content. The receiver retained that raw payload but omitted the incoming item ID and quote fields when constructing MessageEvent. The shared batcher therefore treated replies to different targets as unquoted input, and the prompt could omit the quoted text. Populate the existing reply fields before batching or direct dispatch. Keep the incoming item ID separate from the quoted target. Use a shared message context identity when the local target ID is unavailable, or an identity specific to the incoming item when neither target ID exists. Derive ownership and author data from the quoted direction, including an unknown group author, and reuse the normaliser for deferred voice input. Two parameterised native-payload invariants reproduce the missing event metadata and batching boundaries on the exact prerequisite. They also check complete prompt framing and deferred file replay on the repair. Retain the captured UTC timestamp when normalising native SimpleX reply context. Keep the dataclass import, complete quote normaliser and incoming identity handling from this contribution.
iainlane
force-pushed
the
feat/matrix-receipts-lifecycle
branch
from
October 5, 2026 22:25
24630f5 to
961ee80
Compare
iainlane
added a commit
to iainlane/hermes-agent
that referenced
this pull request
Oct 5, 2026
A started input can be deferred into the FIFO overflow and rescued by a later turn. After the rescued turn finishes, the runner clears its durable active-turn marker before reporting processing completion. Cancellation during that storage await skips the completion hook, so the input remains marked as processing even though its turn has finished. Run rescued-input completion in the marker cleanup finally block. Keep both awaits after the generation-scoped session and lease releases, and retain the adapter-owned marker handoff and marker token comparison. Extend the marker cancellation contract with the actual adapter start and defer lifecycle followed by FIFO rescue. Both normal and rescued turns release ownership and admit a successor; the successful rescued input also reports exactly one successful completion after cleanup cancellation. Historical attribution for original source 51c0ecf6197ce1489fb31bdcbddfb64c3d2ba125 (audit record 755). Public PR NousResearch#126283 already includes this cancellation correction in 48902ee. This empty commit records the missing original contribution credit. The source tree is unchanged.
iainlane
force-pushed
the
feat/matrix-receipts-lifecycle
branch
from
October 6, 2026 03:25
4918941 to
9c46997
Compare
Native SimpleX reply tests compare complete events and prompts after the common gateway batches incoming text. The gateway records the additional message IDs in a merged event and JSON-escapes quoted text in the prompt. The imported tests omitted those IDs and placed literal newlines inside the quotation. Include the second message ID in coalesced expected events and use JSON encoding for the complete expected quote. Keep the split-event cases and whole-event and whole-prompt comparisons unchanged. The canonical 40-case run reproduced 24 merged-event assertion failures and 16 prompt assertion failures on the unadapted tests. The native reply additions introduced formatter changes in the reply context, extended event construction and their fixtures. Format those scopes and remove the extra blank pair at the fixture insertion boundary. Keep unrelated inherited formatting unchanged. Complete module ASTs, parameter populations and assertions remain identical to the accepted 155-case source, so its behaviour evidence remains applicable.
The complete feedback and edit source adds a second auxiliary-config argument to the shared native gateway fixture. Native collection fails before the unread controls can run. Keep the single additive argument that the controls fixture already provides. The incoming edit and lifecycle contracts also read optional mock-call records and assign dynamic fixture fields as statically declared methods. Check that the required calls occurred before reading their arguments, use the real profile-hook registry, and bind fixture replacements through monkeypatch. All original behaviour assertions remain in place. The complete changed production, unit and native harness type comparison has no new diagnostics after the defining-owner correspondence checks. The native collection syntax error is removed; collection-only execution is diagnostic evidence, not a test pass. Source and contributor reconciliation for original 726 (1655eb9d3aa2d693af7f8685185c80850408d82d). The original message above records the composed correction and its historical checks. This contribution preserves its complete credit after the source repairs were incorporated into their separate public owners. The five edit-follow-up fixtures use direct awaited-call guards and the real ProfileHookRegistries on NousResearch#126312. The lifecycle, deferred-input and feedback fixtures use the declared typed and monkeypatch adaptations on NousResearch#126283. These complete unit definitions are also present in its current composed tree. The native auxiliary configuration fixture has one argument and its consumer on NousResearch#126398. The NousResearch#126283 native harness has no auxiliary fixture or consumer, so it requires no corresponding argument. This is source and credit attribution across those owners. It adds no product or fixture patch, and records no fresh test, type, SDK or native execution. The complete original message and both literal contributor dates are preserved.
iainlane
force-pushed
the
feat/matrix-receipts-lifecycle
branch
from
October 6, 2026 08:34
83f8dec to
d830be3
Compare
iainlane
added a commit
to iainlane/hermes-agent
that referenced
this pull request
Oct 6, 2026
A started input can be deferred into the FIFO overflow and rescued by a later turn. After the rescued turn finishes, the runner clears its durable active-turn marker before reporting processing completion. Cancellation during that storage await skips the completion hook, so the input remains marked as processing even though its turn has finished. Run rescued-input completion in the marker cleanup finally block. Keep both awaits after the generation-scoped session and lease releases, and retain the adapter-owned marker handoff and marker token comparison. Extend the marker cancellation contract with the actual adapter start and defer lifecycle followed by FIFO rescue. Both normal and rescued turns release ownership and admit a successor; the successful rescued input also reports exactly one successful completion after cleanup cancellation. Historical attribution for original source 51c0ecf6197ce1489fb31bdcbddfb64c3d2ba125 (audit record 755). Public PR NousResearch#126283 already includes this cancellation correction in 48902ee. This empty commit records the missing original contribution credit. The source tree is unchanged.
iainlane
added a commit
to iainlane/hermes-agent
that referenced
this pull request
Oct 6, 2026
A started input can be deferred into the FIFO overflow and rescued by a later turn. After the rescued turn finishes, the runner clears its durable active-turn marker before reporting processing completion. Cancellation during that storage await skips the completion hook, so the input remains marked as processing even though its turn has finished. Run rescued-input completion in the marker cleanup finally block. Keep both awaits after the generation-scoped session and lease releases, and retain the adapter-owned marker handoff and marker token comparison. Extend the marker cancellation contract with the actual adapter start and defer lifecycle followed by FIFO rescue. Both normal and rescued turns release ownership and admit a successor; the successful rescued input also reports exactly one successful completion after cleanup cancellation. Historical attribution for original source 51c0ecf6197ce1489fb31bdcbddfb64c3d2ba125 (audit record 755). Public PR NousResearch#126283 already includes this cancellation correction in 48902ee. This empty commit records the missing original contribution credit. The source tree is unchanged.
iainlane
force-pushed
the
feat/matrix-receipts-lifecycle
branch
from
October 6, 2026 09:55
d830be3 to
8eed870
Compare
iainlane
added a commit
to iainlane/hermes-agent
that referenced
this pull request
Oct 6, 2026
The complete feedback and edit source adds a second auxiliary-config argument to the shared native gateway fixture. Native collection fails before the unread controls can run. Keep the single additive argument that the controls fixture already provides. The incoming edit and lifecycle contracts also read optional mock-call records and assign dynamic fixture fields as statically declared methods. Check that the required calls occurred before reading their arguments, use the real profile-hook registry, and bind fixture replacements through monkeypatch. All original behaviour assertions remain in place. The complete changed production, unit and native harness type comparison has no new diagnostics after the defining-owner correspondence checks. The native collection syntax error is removed; collection-only execution is diagnostic evidence, not a test pass. Source and contributor reconciliation for original 726 (1655eb9d3aa2d693af7f8685185c80850408d82d). The original message above records the composed correction and its historical checks. This contribution preserves its complete credit after the source repairs were incorporated into their separate public owners. The five edit-follow-up fixtures use direct awaited-call guards and the real ProfileHookRegistries on NousResearch#126312. The lifecycle, deferred-input and feedback fixtures use the declared typed and monkeypatch adaptations on NousResearch#126283. These complete unit definitions are also present in its current composed tree. The native auxiliary configuration fixture has one argument and its consumer on NousResearch#126398. The NousResearch#126283 native harness has no auxiliary fixture or consumer, so it requires no corresponding argument. This is source and credit attribution across those owners. It adds no product or fixture patch, and records no fresh test, type, SDK or native execution. The complete original message and both literal contributor dates are preserved.
The adapter's processing-start hook and topic recovery can await before message dispatch. A handler installed on entry can disappear during that await, so the earlier presence check does not make either dispatch call safe. The turn-marker handoff also had no declared state on MessageEvent. Declare the marker as an event-local field that resets when dataclasses replace an event. Select and validate the current handler at each dispatch boundary. Background selection remains after the start hook and inside the pending reservation scope. When no handler is installed, background dispatch reports failure through the existing notification and cleanup paths. Inline dispatch errors preserve command restoration and clarify lifecycle handling. The scoped type comparison removes the three background findings and the sibling inline optional call, with 48 inherited findings unchanged and no introduced findings. The canonical lifecycle, marker and withdrawal run passes 137 cases. The separate command and clarify run passes 19 cases, including handler removal during real awaited topic recovery. Scoped Ruff reports no lint findings; unrelated inherited formatter changes remain.
The fake HTTP API discarded the client_session supplied by the Matrix adapter, so disconnect closed a mock while the real aiohttp session was left open. A reconnect test also replaced disconnect with a stub and left its new connection open after checking the guard. Strict resource warnings expose both leaks. Preserve the supplied session in the fake API. Use a wrapping disconnect spy in the reconnect test and disconnect the replacement client after the existing call assertion. The fake API and reconnect fixture predate this branch, so this focused fixture maintenance is separate from the corrections folded into their campaign contributors. Production code and all original assertions are unchanged. Apply the published fake-API session and reconnect cleanup to this consumer fixture. Preserve its additional Matrix types, membership, encryption and account assertions.
Cached auxiliary-client teardown is mixed into the large routing module. The worker-loop lifetime correction needs to await only the transports owned by a terminating worker, without expanding that routing module. Move the three transport-close functions into a lifecycle sibling and import the close function at its existing callers. Their full function ASTs and the remaining routing-module statements are unchanged.
Tool dispatch keeps one event loop per executor thread so cached async clients can reuse their transports between calls. The thread-local cache stored only the loop, so ending an executor left the loop and its selector sockets open. Auxiliary clients also remained cached after their owner thread exited. Temporary workers used inside an already running event loop also closed their loops before finishing generators and cached transports. Give each worker a Runner owner with a finalizer attached to its thread-local lifetime. Cancel remaining tasks and finish generators before closing cached clients on that loop. Wait for their close tasks, then let Runner shut down the executor and close the loop. Clients that belong to other live loops remain cached and open. The regression uses actual executor threads and SDK HTTP connections to a local server. It checks reuse between calls, generator cleanup before client closure, closed worker resources, and an unaffected main-thread client in both worker modes. Timeout cancellation still runs inside the worker loop, and executor shutdown remains nonblocking for the caller. The existing fake timeout executor now also closes the test coroutine which it deliberately never submits.
iainlane
force-pushed
the
feat/matrix-receipts-lifecycle
branch
from
October 9, 2026 10:04
f3fbf84 to
d8d4fea
Compare
iainlane
added a commit
to iainlane/hermes-agent
that referenced
this pull request
Oct 9, 2026
A started input can be deferred into the FIFO overflow and rescued by a later turn. After the rescued turn finishes, the runner clears its durable active-turn marker before reporting processing completion. Cancellation during that storage await skips the completion hook, so the input remains marked as processing even though its turn has finished. Run rescued-input completion in the marker cleanup finally block. Keep both awaits after the generation-scoped session and lease releases, and retain the adapter-owned marker handoff and marker token comparison. Extend the marker cancellation contract with the actual adapter start and defer lifecycle followed by FIFO rescue. Both normal and rescued turns release ownership and admit a successor; the successful rescued input also reports exactly one successful completion after cleanup cancellation. Historical attribution for original source 51c0ecf6197ce1489fb31bdcbddfb64c3d2ba125 (audit record 755). Public PR NousResearch#126283 already includes this cancellation correction in 48902ee. This empty commit records the missing original contribution credit. The source tree is unchanged.
iainlane
added a commit
to iainlane/hermes-agent
that referenced
this pull request
Oct 9, 2026
The complete feedback and edit source adds a second auxiliary-config argument to the shared native gateway fixture. Native collection fails before the unread controls can run. Keep the single additive argument that the controls fixture already provides. The incoming edit and lifecycle contracts also read optional mock-call records and assign dynamic fixture fields as statically declared methods. Check that the required calls occurred before reading their arguments, use the real profile-hook registry, and bind fixture replacements through monkeypatch. All original behaviour assertions remain in place. The complete changed production, unit and native harness type comparison has no new diagnostics after the defining-owner correspondence checks. The native collection syntax error is removed; collection-only execution is diagnostic evidence, not a test pass. Source and contributor reconciliation for original 726 (1655eb9d3aa2d693af7f8685185c80850408d82d). The original message above records the composed correction and its historical checks. This contribution preserves its complete credit after the source repairs were incorporated into their separate public owners. The five edit-follow-up fixtures use direct awaited-call guards and the real ProfileHookRegistries on NousResearch#126312. The lifecycle, deferred-input and feedback fixtures use the declared typed and monkeypatch adaptations on NousResearch#126283. These complete unit definitions are also present in its current composed tree. The native auxiliary configuration fixture has one argument and its consumer on NousResearch#126398. The NousResearch#126283 native harness has no auxiliary fixture or consumer, so it requires no corresponding argument. This is source and credit attribution across those owners. It adds no product or fixture patch, and records no fresh test, type, SDK or native execution. The complete original message and both literal contributor dates are preserved.
iainlane
force-pushed
the
feat/matrix-receipts-lifecycle
branch
from
October 9, 2026 15:16
d8d4fea to
52e9d3a
Compare
iainlane
added a commit
to iainlane/hermes-agent
that referenced
this pull request
Oct 9, 2026
A started input can be deferred into the FIFO overflow and rescued by a later turn. After the rescued turn finishes, the runner clears its durable active-turn marker before reporting processing completion. Cancellation during that storage await skips the completion hook, so the input remains marked as processing even though its turn has finished. Run rescued-input completion in the marker cleanup finally block. Keep both awaits after the generation-scoped session and lease releases, and retain the adapter-owned marker handoff and marker token comparison. Extend the marker cancellation contract with the actual adapter start and defer lifecycle followed by FIFO rescue. Both normal and rescued turns release ownership and admit a successor; the successful rescued input also reports exactly one successful completion after cleanup cancellation. Historical attribution for original source 51c0ecf6197ce1489fb31bdcbddfb64c3d2ba125 (audit record 755). Public PR NousResearch#126283 already includes this cancellation correction in 48902ee. This empty commit records the missing original contribution credit. The source tree is unchanged.
iainlane
added a commit
to iainlane/hermes-agent
that referenced
this pull request
Oct 9, 2026
The complete feedback and edit source adds a second auxiliary-config argument to the shared native gateway fixture. Native collection fails before the unread controls can run. Keep the single additive argument that the controls fixture already provides. The incoming edit and lifecycle contracts also read optional mock-call records and assign dynamic fixture fields as statically declared methods. Check that the required calls occurred before reading their arguments, use the real profile-hook registry, and bind fixture replacements through monkeypatch. All original behaviour assertions remain in place. The complete changed production, unit and native harness type comparison has no new diagnostics after the defining-owner correspondence checks. The native collection syntax error is removed; collection-only execution is diagnostic evidence, not a test pass. Source and contributor reconciliation for original 726 (1655eb9d3aa2d693af7f8685185c80850408d82d). The original message above records the composed correction and its historical checks. This contribution preserves its complete credit after the source repairs were incorporated into their separate public owners. The five edit-follow-up fixtures use direct awaited-call guards and the real ProfileHookRegistries on NousResearch#126312. The lifecycle, deferred-input and feedback fixtures use the declared typed and monkeypatch adaptations on NousResearch#126283. These complete unit definitions are also present in its current composed tree. The native auxiliary configuration fixture has one argument and its consumer on NousResearch#126398. The NousResearch#126283 native harness has no auxiliary fixture or consumer, so it requires no corresponding argument. This is source and credit attribution across those owners. It adds no product or fixture patch, and records no fresh test, type, SDK or native execution. The complete original message and both literal contributor dates are preserved.
iainlane
force-pushed
the
feat/matrix-receipts-lifecycle
branch
from
October 10, 2026 00:25
52e9d3a to
dc28111
Compare
iainlane
added a commit
to iainlane/hermes-agent
that referenced
this pull request
Oct 10, 2026
A started input can be deferred into the FIFO overflow and rescued by a later turn. After the rescued turn finishes, the runner clears its durable active-turn marker before reporting processing completion. Cancellation during that storage await skips the completion hook, so the input remains marked as processing even though its turn has finished. Run rescued-input completion in the marker cleanup finally block. Keep both awaits after the generation-scoped session and lease releases, and retain the adapter-owned marker handoff and marker token comparison. Extend the marker cancellation contract with the actual adapter start and defer lifecycle followed by FIFO rescue. Both normal and rescued turns release ownership and admit a successor; the successful rescued input also reports exactly one successful completion after cleanup cancellation. Historical attribution for original source 51c0ecf6197ce1489fb31bdcbddfb64c3d2ba125 (audit record 755). Public PR NousResearch#126283 already includes this cancellation correction in 48902ee. This empty commit records the missing original contribution credit. The source tree is unchanged.
iainlane
added a commit
to iainlane/hermes-agent
that referenced
this pull request
Oct 10, 2026
The complete feedback and edit source adds a second auxiliary-config argument to the shared native gateway fixture. Native collection fails before the unread controls can run. Keep the single additive argument that the controls fixture already provides. The incoming edit and lifecycle contracts also read optional mock-call records and assign dynamic fixture fields as statically declared methods. Check that the required calls occurred before reading their arguments, use the real profile-hook registry, and bind fixture replacements through monkeypatch. All original behaviour assertions remain in place. The complete changed production, unit and native harness type comparison has no new diagnostics after the defining-owner correspondence checks. The native collection syntax error is removed; collection-only execution is diagnostic evidence, not a test pass. Source and contributor reconciliation for original 726 (1655eb9d3aa2d693af7f8685185c80850408d82d). The original message above records the composed correction and its historical checks. This contribution preserves its complete credit after the source repairs were incorporated into their separate public owners. The five edit-follow-up fixtures use direct awaited-call guards and the real ProfileHookRegistries on NousResearch#126312. The lifecycle, deferred-input and feedback fixtures use the declared typed and monkeypatch adaptations on NousResearch#126283. These complete unit definitions are also present in its current composed tree. The native auxiliary configuration fixture has one argument and its consumer on NousResearch#126398. The NousResearch#126283 native harness has no auxiliary fixture or consumer, so it requires no corresponding argument. This is source and credit attribution across those owners. It adds no product or fixture patch, and records no fresh test, type, SDK or native execution. The complete original message and both literal contributor dates are preserved.
iainlane
added a commit
to iainlane/hermes-agent
that referenced
this pull request
Oct 11, 2026
The complete feedback and edit source adds a second auxiliary-config argument to the shared native gateway fixture. Native collection fails before the unread controls can run. Keep the single additive argument that the controls fixture already provides. The incoming edit and lifecycle contracts also read optional mock-call records and assign dynamic fixture fields as statically declared methods. Check that the required calls occurred before reading their arguments, use the real profile-hook registry, and bind fixture replacements through monkeypatch. All original behaviour assertions remain in place. The complete changed production, unit and native harness type comparison has no new diagnostics after the defining-owner correspondence checks. The native collection syntax error is removed; collection-only execution is diagnostic evidence, not a test pass. Source and contributor reconciliation for original 726 (1655eb9d3aa2d693af7f8685185c80850408d82d). The original message above records the composed correction and its historical checks. This contribution preserves its complete credit after the source repairs were incorporated into their separate public owners. The five edit-follow-up fixtures use direct awaited-call guards and the real ProfileHookRegistries on NousResearch#126312. The lifecycle, deferred-input and feedback fixtures use the declared typed and monkeypatch adaptations on NousResearch#126283. These complete unit definitions are also present in its current composed tree. The native auxiliary configuration fixture has one argument and its consumer on NousResearch#126398. The NousResearch#126283 native harness has no auxiliary fixture or consumer, so it requires no corresponding argument. This is source and credit attribution across those owners. It adds no product or fixture patch, and records no fresh test, type, SDK or native execution. The complete original message and both literal contributor dates are preserved.
iainlane
added a commit
to iainlane/hermes-agent
that referenced
this pull request
Oct 11, 2026
The complete feedback and edit source adds a second auxiliary-config argument to the shared native gateway fixture. Native collection fails before the unread controls can run. Keep the single additive argument that the controls fixture already provides. The incoming edit and lifecycle contracts also read optional mock-call records and assign dynamic fixture fields as statically declared methods. Check that the required calls occurred before reading their arguments, use the real profile-hook registry, and bind fixture replacements through monkeypatch. All original behaviour assertions remain in place. The complete changed production, unit and native harness type comparison has no new diagnostics after the defining-owner correspondence checks. The native collection syntax error is removed; collection-only execution is diagnostic evidence, not a test pass. Source and contributor reconciliation for original 726 (1655eb9d3aa2d693af7f8685185c80850408d82d). The original message above records the composed correction and its historical checks. This contribution preserves its complete credit after the source repairs were incorporated into their separate public owners. The five edit-follow-up fixtures use direct awaited-call guards and the real ProfileHookRegistries on NousResearch#126312. The lifecycle, deferred-input and feedback fixtures use the declared typed and monkeypatch adaptations on NousResearch#126283. These complete unit definitions are also present in its current composed tree. The native auxiliary configuration fixture has one argument and its consumer on NousResearch#126398. The NousResearch#126283 native harness has no auxiliary fixture or consumer, so it requires no corresponding argument. This is source and credit attribution across those owners. It adds no product or fixture patch, and records no fresh test, type, SDK or native execution. The complete original message and both literal contributor dates are preserved.
This branch has not been deployed
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.
Stack
All PRs in this section target
main. This diagram records logical mergeorder. Every prerequisite must merge before its dependent. Each linked PR
lists its other dependencies.
In this diagram, nesting means the parent PR must merge before its child.
fix(gateway): preserve quoted and speech context across pending merges #131009
fix(gateway): release turn ownership before marker cleanup #130341
fix(simplex): preserve native reply context #133509
fix(tools): close cached transports when async worker threads exit #135482
Summary
Configure automatic Matrix feedback per profile through YAML:
read_receipts: immediatekeeps the current arrival-time receipt.read_receipts: after_processingsends the receipt after a turn thatsucceeded or failed, and skips a turn that was stopped or cancelled.
read_receipts: disabledsuppresses automatic receipts.send_read_receipts: false, the switch that WhatsApp and BlueBubblesalready read, also disables automatic Matrix receipts, whatever
read_receiptssays.reactions: falsedisables processing reactions. Approval and pickerreactions remain available.
The existing scoped
MATRIX_REACTIONSoverride keeps precedence.Receipt timing has no environment setting. The adapter resolves both
settings from its owning profile without a process-wide YAML bridge.
In
after_processingmode, the receipt goes to the latest input thatthe turn processed. Batched messages, queued photo merges, steers and
redirects that the model consumed, and a mention that claims a parked
voice note all move the receipt to that input. Original reply anchors
and ledger identities do not change. Input that the model did not
consume (a steer that arrived after the last tool batch, or input that
arrived after the model result) runs as its own turn and is
acknowledged there.
/queueand accepted/steerwait for the turnthat processes them; other inline commands are acknowledged on their
own, without changing the active turn's reactions.
Current captured-source compatibility
Current head:
dc2811135e5f3a3bdc670ad69b8973c412b33806. Source tree:17cbd07a02f324f851cf134cd90b055f93ef6a03.I rebased this branch onto the captured upstream revision
3637c512fc3211bdccb61b7140d09ac1018508babecause local compositionreproduced concrete conflicts in the inbound facade, platform extraction,
stream annotations and adapter context modules. The extracted methods keep
the complete current upstream bodies and existing message-processing
contracts. Source notes retain the platform-specific Matrix and Discord
content. Current UTC, timeout and annotation conventions remain intact.
These changes use the fixed captured revision; they do not follow an
advancing main branch.
All 450 current contributions remain in order, with their literal author
and committer identities, dates, time zones and complete original message
prefixes. Fifteen meaningful empty credit records remain. Existing
published admission, pending-snapshot, Matrix client/session and worker-loop
fixture corrections are preserved. Resolution rationale is appended only
to the contributions which introduce the relevant source.
The full execution reproduced missing global bindings after the platform
processing method moved to its sibling module. The introducing extraction
now imports the three current facade helpers at execution time. The whole
method body remains unchanged. The merged-event field also keeps its three
quoted forward references because its enclosing class precedes the event
class. Both corrections are included at their true introducing
contributions; every later complete module variant has an exact inverse.
Current validation and qualification
The initial complete 137-file execution is retained as a failing control.
After the source correction, all twenty affected complete files freshly
pass 495 cases under the canonical runner, installed SDK, isolated home,
zero retries and four strict warning categories. Those files include the
queue, processing lifecycle, startup replay, shutdown, native restoration
and Matrix feedback paths which failed in the control.
The other 117 successful complete children are reused after the exact
two-module source inverse and unchanged test-input comparison. The
source-qualified result is 4,190 passes and eighteen existing skips across
137 complete file outcomes. This is a qualified combination of executions,
not a fresh simultaneous execution on the final source. All captured
tracked Python and runner inputs are authenticated before and after each
execution, and the capture-only runner modification is restored exactly.
Ninety-seven complete children have no resource warnings. Forty expose the
same pre-existing shutdown-warning fixture scopes as the preceding
accepted public source. Most warnings concern unclosed test databases;
three unchanged complete test modules also emit an event-loop and two
socket warnings at shutdown. Those files and their full child output
remain explicitly qualified. The source comparison preserves their whole
original fixture and assertion modules, with only the recorded upstream
UTC spelling change in one file. This is not a globally resource-clean
claim, and no warning category or assertion is weakened.
The complete 306-path source-qualified static comparison reports 3,489
inherited findings. Fresh complete checks replace the two modified modules;
the other 304 checked sources remain byte-exact. Full literal diagnostic
spans, relative columns, whole statement ASTs and occurrence counts match
for 3,479 findings. Ten complete enclosing-statement findings require
explicit qualification through the unchanged defining media methods,
base contracts, pending alias or original Feishu and stream signatures.
They are not claimed as literal whole-class AST matches. No introduced
finding remains. Ruff and changed-line whitespace pass; the same 250
formatter paths retain inherited differences.
The earlier delivery evidence below keeps its historical source scope.
Hosted CI approval, maintainer acceptance and live homeserver execution
remain separate.
Previous fixed1744 source compatibility and retention
Current head:
52e9d3ada04519d4e06b1067201f83978ea39d72. Source tree:2fce3c3ff1dd3769e9d5b24966495e5044af27e9.The concrete catalogue and extracted turn conflicts require the captured
upstream revision
1744a19e0df568c647e4f3ff9c37f2a284a282fb.Both that fixed revision and the earlier
99a45ecc17cc51c0488ec3b8ccf7eaf483f7203djoin cleanly with this source.These are exact local source comparisons, not a claim about an advancing
branch.
Keep the complete upstream Spotify catalogue migration, plugin opt-in
defaults and current Matrix rows in their original order. The complete
catalogue joins reuse independently reviewed historical source variants.
The two upstream nullable session-key annotations are retained when the
turn execution methods move into their defining sibling module. All other
captured upstream joins are automatic.
All 450 preceding contributions remain in order with literal author and
committer fields, dates, time zones, other headers and complete message
prefixes. All fifteen meaningful empty records remain. The original
447-contribution feature and attribution sequence, the published fixture
maintenance contribution, and both complete worker-loop lifetime
contributions remain included. The original room-store fixture still
recovers every historical module byte-for-byte when removed.
The published pending native snapshot cleanup
is included in its actual introducing contribution 265. Both complete
historical module variants preserve every assertion, including later
restored-event and decoding contracts. The published
admission fixture cleanup is included at
contribution 167. Its two existing finally blocks release the owning
SessionStore after intake finishes. Removing only each fixture correction
recovers every complete historical module byte-for-byte; complete function
AST comparisons preserve all other statements and assertions.
The separate pending Matrix caller and profile snapshot finalizers were
already present throughout this branch's complete historical variants.
The later consumer-only shutdown lease testcase is absent throughout the
branch. No duplicate finalizer or future testcase is added.
Previous fixed1744 validation and limits
A fresh canonical strict-warning run against the captured upstream
composition passes 4,190 cases across 136 complete passing files.
Fourteen existing cases are skipped within those files. The separate crypto
file skips all four cases and contributes no passing coverage. Zero retries
were used. All 8,539 actual Python and runner inputs were authenticated
before and after execution, and the canonical runner was restored exactly.
The subsequently corrected admission file was run separately: all three
cases pass, and its complete successful child output has no unclosed
resource warnings at interpreter exit. Every other authenticated input is
byte-for-byte identical to the fresh 137-file composition.
The resulting complete-file union contains 97 files with clean shutdown
output and 40 files with existing fixture resource warnings. Of those
40 test modules, 39 are byte-for-byte identical to the preceding published
source. The heartbeat module differs only by two captured upstream unused unpacked
variable renames; their literal inverse recovers the complete original
module byte-for-byte.
The full child outputs and exact resource counts remain recorded. This is
not a claim that all 137 files release every resource.
The original 138-file gate remains non-green. The complete failures in
tests/agent/test_context_compressor.pyandtests/tui_gateway/test_tui_gateway_server.pyremain excluded from thepassing scope above. Their partial passes do not count as complete passing
coverage. Other platform, live-service, encrypted Matrix and hosted evidence
remains bound to its recorded historical revision.
The full 306-path static comparison reports 3,474 existing diagnostics.
Of these, 3,470 match the maximum preceding-or-captured-upstream complete
lexical and statement counters. Four complete-source correspondences
prove the upstream Discord class annotation and unused-local changes,
and the upstream nullable session-message contract. No introduced finding
remains. The affected admission file was checked separately; both existing
full diagnostic spans and statements are unchanged. The other 305 source
paths are byte-for-byte identical to the complete static check. Ruff passes.
All 250 formatter paths remain inherited. The nonzero type and formatter
results are qualified, not claimed as passes. No new global or hosted CI
readiness claim follows from this delivery.
Previous captured delivery
The following section describes the preceding published source and its
validation. Its counts and head do not describe the current composition.
Previous source compatibility and retention
Current head:
d8d4fead851db57aacdff17731b81b0b10112fd3. Source tree:f47e5772b478b959c61252cadefc62a059f093c0.Compose the complete captured branch with the necessary upstream revision
302c5d9f679333ae957c256d76a3dff35120f4e0. Preserve every originalfeature, defining scope and contributor record through the actual module,
context, voice, reply, ownership and adapter joins. Both the fixed upstream
revision and the earlier
99a45ecc17cc51c0488ec3b8ccf7eaf483f7203djoin cleanly with this source. This records those exact operands; it does
not claim compatibility with an advancing branch.
Bounded cancellation now keeps captured provisional input until a delayed
task completes. Reconciliation restores eligible inputs oldest first and
runs once across both completion paths. Withdrawn, claimed and durably
persisted input keeps its existing exclusions. Real SQLite controls prove
that delayed non-durable input is recovered and durable input is excluded;
the chain case preserves aliases and FIFO order. The unchanged source
reproduced two lost-input assertion failures with 14 passing controls.
The corrected complete snapshot file passes all 16 cases.
The original 447 contributions remain in order with literal authors,
committers, dates, time zones, other headers and complete message prefixes.
Their twelve original meaningful empty records remain. Three additional
source-free attribution records are preserved and explicitly qualified.
Fixture and source corrections are included in their actual introducing
contributions with factual appendices. The published room-store teardown
fixture is included at original contribution 15. Both room helpers retain
their complete original ASTs; removing only that fixture restores each
complete historical module byte-for-byte. All original assertion contracts,
parameter cases and decorators are retained; the reply excerpt expectation
uses the existing JSON escaping contract.
Three credited published records follow that original sequence: the
#126281 fixture maintenance, whose fake API
and reconnect scopes predate the adopted range, and both complete
#135482 worker-loop lifetime contributions.
The maintenance changes only the applicable fixture scopes. The core
contributions apply through clean three-way patches. No unrelated provider
ancestry is copied. The final history contains 450 contributions.
Previous validation and limits
The original 138-file strict SDK run was non-green: 4,890 cases passed,
238 failed, 18 were skipped, and two files exceeded their deadlines.
Those receipts remain available. Required current API, resource ownership,
reservation persistence and mock-chain fixtures were corrected without
removing their original assertions. The two original mock-chain hangs also
reproduced on the captured original source before their fixture repairs.
Source-qualified complete-file results contain 4,190 passes across 136
complete passing files, with 18 skipped cases under the existing guards.
A separate crypto file has four skips and contributes no passing coverage.
These results combine actual complete-file executions, exact source and
runner bindings, and explicit whole-module formatting, annotation and
existing-guard bridges. They include the fresh complete cache and pin
contracts, both complete Slack files, and the complete Matrix and reaction
files with the published core correction. A fresh complete Matrix file
passes all 264 cases after the room-store teardown addition. Its complete
successful child output contains no SQLite or unclosed-resource warnings
at interpreter exit. The installed mautrix dependency emits one existing
DeprecationWarning. The earlier summary-only output did not establish
zero warnings at interpreter exit. The other 135 passing complete files
remain source-qualified; this is not a new whole-suite run.
Two unchanged upstream resource-failure files remain non-green:
tests/agent/test_context_compressor.pyandtests/tui_gateway/test_tui_gateway_server.py. Their complete originaland current failures are recorded, and their affected original methods
are preserved. Their partial passing cases are excluded from the passing
scope above. This delivery does not claim a passing complete 138-file gate.
The full current type comparison reports 3,603 existing diagnostics.
Of those, 3,584 match the maximum original-or-upstream complete-statement
counter exactly. Nineteen finite correspondences prove complete methods,
current enum and provider bindings, class member unions, annotation
aliases, or literal fixture statements shifted by resource cleanup.
No unqualified new diagnostic remains. Ruff passes. The same 250 inherited
formatter paths remain; no new unformatted path is introduced. These
nonzero type and formatter results are qualified, not claimed as passes.
Earlier native, live-service, encrypted Matrix, platform, hosted and broad
validation evidence below remains tied to its recorded source revision.
No new live-service, hosted CI, global or review-ready
claim follows from this delivery.
Earlier recorded delivery and validation
The following evidence remains bound to its stated historical revisions.
Earlier final-delivery regression formatting and split contribution credit
Recorded head:
8eed870e00c9a40f24334aa6f41f91cef0ed26aa. Committed source tree:559f763c380f3a683eefbb4d63030593e59cfda0.Format the complete final-delivery regression without changing its AST,
parameters, decorators or assertions. The layout change is included at
contribution 82. Every byte outside that test function remains unchanged;
its remaining formatter differences belong to the earlier unchanged prefix.
The scoped lint check passes. Independent complete-module AST comparison
connects this layout to the previously accepted 85-case native gate and
scoped type comparison. Neither gate was rerun for formatting.
The signed prefix of 81 contributions is unchanged. Contributions 82 through
148 preserve their complete author and committer fields, dates, time zones,
encoding and messages. Their only source change is the regression layout.
Contribution 149 preserves the complete 929-byte PRIMARY message and both
literal metadata fields from
1655eb9d3aa2d693af7f8685185c80850408d82d.Its appendix identifies the existing public source across these three owners:
fixtures, with the reviewed typed fixture adaptations.
2f2989f133ea0b6eac50c82f1d96fcd2ee5e8bb3: edit fixtures and the real profilehook registry.
4c04f0ae9aba6ef067a2d17537787636bf499e73: the native gateway fixture hasexactly one auxiliary configuration argument and its fixture and consumer.
The final contribution records attribution for source already published
across those owners. All five original file changes and ten complete unit
fixture definitions were compared, including their explicit adaptations.
The original message describes historical verification. This credit update
claims no fresh native Matrix run or broader runtime
acceptance. This branch's native fixture has no auxiliary configuration
fixture or consumer, so that fixture argument remains with #126398.
All 68 new signatures were verified locally, and their exact hosted payloads,
signatures, trees and parent relationships were checked. Review the
scoped refresh and complete credit carrier.
Historical fixture contracts and primary committer credit
Recorded head:
d830be3ea12d9f0b7a10d26e7c80fc1c92e314ed. Committed source tree:4395c1464aa5d24cc8618a995ccaa127baec1f4e. This update corrects four gateway test fixtures to match the existing adapter and runner interfaces. Context fixtures use the existing monkeypatch fixture for legacy attributes; queue fixtures use the nominal runner type and its typed methods; the pending-steer adapter returnsSendResultthrough the full adapter send contract. Production behaviour, assertions and parametrised cases are unchanged. The adapter fixture correction is also published in #131009.The corrections are included at their original introducing contributions, positions 10, 11, 82 and 144. The signed prefix of nine contributions is unchanged. The 139 rewritten contributions preserve complete author fields, dates, time zones, encoding and messages, including meaningful empty contributions. Exactly 34 selected primary records correct their corresponding literal committer fields. Other committer fields remain unchanged. Unresolved primary-record gaps remain qualified; this comparison does not establish fidelity to every original record.
The paired native validation passed the same 85 cases before and after the fixture changes: 21 context-reference cases, 19 FIFO cases, 30 pending-admission cases, five busy-follow-up cases and ten pending-steer cases. Every setup, call and teardown passed, with zero failures, errors or skips. Both runs used the canonical runner, strict asynchronous warnings, two workers and zero retries.
The seven-file paired Ty comparison reported 55 diagnostics before the corrections and 45 afterwards. Exactly ten targeted occurrences were removed, with zero introduced diagnostics. The remaining 35 production and ten fixture diagnostics are inherited. The scoped Ruff lint check of the four changed fixtures passed. The final formatter diff contains the same 57 inherited edit blocks across three files and no introduced residuals; the formatter still exits one.
Two final context-fixture call-layout changes affect only whitespace. Independent review confirmed complete module ASTs, test populations and historical source associations. The native and type evidence applies through that equivalence; neither check was rerun after those layout changes. The historical SimpleX validation below continues to describe its own source and scope. No whole-project type gate, fresh broader test gate or live Matrix server run is claimed by this update.
All 139 new signatures were verified locally. Their exact hosted payloads, signatures, trees and parent relationships were checked before this description update. Review the fixture and credit update. The older composition and validation sections below describe their recorded historical heads.
Changes that apply to every platform
The receipts depend on when the gateway runs the processing hooks, and
those hooks belong to the shared runner. The following changes
therefore affect every adapter that implements
on_processing_startand
on_processing_complete(Slack, Discord, Telegram, Signal, Feishu,Matrix and others). Each has a test on a Telegram or Slack adapter in
tests/gateway/test_processing_lifecycle.py.follow-up starts. Previously the first message completed only after
the whole chain, so cancelling the follow-up also suppressed the
earlier message's success reaction and receipt.
refused final send produces FAILURE, and a cancelled one CANCELLED.
interrupt input goes to the FIFO. The agent can no longer consume
it, so the completed turn must not acknowledge it.
message's hooks and reply anchor. When a follow-up is already queued,
the steer waits behind it; before, it was dropped.
message's start, the message completes exactly once: with the outcome
of the turn that read it, as FAILURE when that turn raises an error or
its text is refused, or as CANCELLED when it is dropped before a turn
runs it (
/stop,/new,/reset, or a merge that replaces it in thepending slot).
they complete. When the adapter is torn down (gateway shutdown,
startup abort, or removal of a served profile in a multiplex
gateway), it first cancels its tasks, then completes everything
still recorded as CANCELLED, wherever the message waits, and takes
those messages out of its pending slots. The pending slots are
flushed to disk for recovery before that. If cancelling overruns
its time bound, the completion still runs under a bound of its own;
a message completed this way is never started again.
adapter starts a new message itself and the runner steers,
redirects or interrupts with it. The message completes with the
turn that read it.
follow-up already waiting (a photo burst, or text on the
pending-sentinel and Telegram grace paths), completes with the turn
that later runs that follow-up, including a
/goalcontinuation,heartbeat or internal notification. If
/stopleaves it in theoverflow FIFO and the next message's turn rescues it, that turn
completes it.
steer, the leftover's own turn owns them from that point, whether it
runs straight away, waits in the FIFO or is parked at the recursion
cap. The original handler (for example one still sending a
/steeracknowledgement) cannot complete them, and the leftover's turn does
not report a second start. If that turn never runs, the gateway
completes them as described above.
platform message), a steered, redirected or interrupting message
completes when its handler returns, as on
main, unless the modelreturns it as a leftover steer while its handler is still running;
then it completes with its leftover's turn. On an adapter without
its own start hook (A2A, Google Chat, webhook), a started message is
neither attached nor parked, so its handler completes it, as on
main./stop,/new, shutdown) completes as CANCELLED. A turn interrupted by newinput still completes with the chain that answers that input, as
before. An inactivity timeout usually returns a failed result, so the
turn completes with the delivery outcome of its timeout notice, as on
main.on_inline_processing_complete.It runs after the command's work, so
/stop,/newand/resetcancel the turn before any acknowledgement.
The following are unchanged from
main: a failed turn whose failurenotice was delivered completes as SUCCESS, and a plain-text approval
whose routing raises falls through to busy handling.
Contributor credit
Includes Zoltán Žiak's authored commit from #96302, with
configuration, profile scope and tests adapted on top. No comments or
reviews were posted on the contributor's PR.
Historical composition and validation
This continuation combines the published queue, deletion and cleanup
prerequisites with Matrix edit handling, processing lifecycle ownership,
pending-input restoration and profile-scoped recovery. The unchanged
historical prefix is
02e311576cc9b2294c0576814fd8ab74293a1205.The frozen composition at
ba7dcbd69fa4a6ddf1270d3cb90979e24b13b207passed the complete 42-filerestoration gate: 1,621 cases, two workers, zero retries, strict runtime
warnings and the original 300-second limit for each file. Its separate
speech-model boundary file passed all ten cases. The model boundary checks
that only the intended deferred inputs enter the model conversation.
The preceding public-source gate has 1,304 passing cases across 36 complete
files. This is a qualified combination of 1,091 cases from 35 unchanged
files and a fresh complete Slack file with 213 cases after a test-bootstrap
location correction. It is not a fresh run of all 36 files.
The capacity integration preserves the published steer-capacity
correction and all eight original regression cases from
#131009. The source also keeps this layer's message copies, voice transcript
metadata and lifecycle ownership. When the pending queue is full, an
already accepted tracked steer remains queued behind the selected event;
its processing lifecycle completes when that steer runs or is cancelled.
Two added cases exercise that path through the model and adapter for normal
completion and
/stop.The lifecycle coverage also includes a tracked steer whose acknowledgement
is still in flight when its own follow-up fails. Processing feedback ends
once with that follow-up's failure after the original handler returns.
The causal gate ran all ten cases in the complete pending-steer file
against the original production source. Eight cases failed assertions and
two passed, with no errors or skips. Both added tracked cases reproduced
the accepted steer being lost after the pending queue became full; the
later completion and stop outcomes were not reached on that source.
The final source passed all 164 cases across six complete files covering
internal-event pins, pending admission, steer draining, processing
lifecycles, queue consumption and queued follow-up hooks. These include
all eight original capacity cases, both added tracked normal/stop cases
and the restored tracked acknowledgement-in-flight failure case. The
canonical runner used two workers, zero retries, strict runtime warnings
and the original 300-second limit for each file.
The accepted final unsigned source is
a708c47bc3f30b102a3374975b5038746be98935, with tree32f758fcf234c48d8793293636be6648bb0d42e6. Signing preserves that tree;the accepted 145-commit signed head is
961ee805ee0abbd92addea5cdc66d62fe1eb7973.The composition adds 145 commits after the unchanged historical prefix:
142 reconstructed contributor commits, the existing speech-model boundary
commit, a copy of the published capacity correction and the tracked-steer
integration. The 142 reconstructed commits preserve the author and committer fields,
timestamps, timezones and encoding from the selected saved archival
records. This comparison does not establish fidelity to every primary
original record. The first original message is
retained in full as the exact prefix of its final message, with the existing
435-byte repair rationale appended. The other 141 messages are unchanged.
The capacity copy preserves its original author, committer and full message.
All 145 signed payloads at
961ee805ee0abbd92addea5cdc66d62fe1eb7973preserve the selected saved records' literal author, committer, date,
timezone and full message, apart from the described existing first-message
repair note. Each signature was verified locally and its exact payload,
signature, tree and parent were checked on GitHub.
Historical validation
Earlier descriptions recorded broad unit, configuration and type checks,
and a Docker-backed 13-case Matrix receipt gate. Those receipts belong to
their recorded predecessor sources. They do not establish a new native
Synapse run for this continuation. The current checks above identify their
exact source and scope.
This PR remains a draft. Prerequisite merge order is specified in the Stack
section. No upstream merge or successful execution against current
mainis claimed.
Public fixture credit follow-on
A further credit-only commit retains the complete 777-byte primary
rationale and the original author and committer identities, dates and
timezones for the queued-context fixture contribution. It appends the
public fixture adaptation rationale without changing the source tree or
rewriting the preceding 145 commits. The receipt teardown and membership
checks remain in this composition; the unread fixture and its consumer
remain in their separate prerequisite.
The public paused-context fixture selects
queueinput andinterrupttext. Ordinary active-session text therefore enters the runner FIFO; this
configuration does not request interruption of the active agent. Explicit
steer consumers keep their normal-mode overrides. Debounce timing, text
coalescing and pending storage differ between these paths. The current 164-case gate above applies to this unchanged source tree.
Historical results remain limited to their recorded sources. This follow-on
adds no production or test changes and requires no new native run.
That follow-on was published at
4918941e1b2562d783e6ed7824a676fd8cdcff14, with the same tree32f758fcf234c48d8793293636be6648bb0d42e6. At that endpoint, the acceptedlocal and hosted proofs covered the preceding 145 commits. The additional
commit had its own local signature verification and exact hosted payload,
signature, tree and direct parent checks. These remain historical proof
scopes after the metadata correction below.
Compare the credit-only follow-on.
Primary committer metadata correction
Three selected archival records had different committer timestamps from
their primary originals. The commits at positions 122, 138 and 139 now
preserve the literal committer fields from primary originals
67031b79a519d569c02ac58cbb737f29e38d4e57,540f50cd2dd0539ad4653d668d8bc37a3ca51997and447d4b0c43632afb48504ce97f9a6a4ac27e176arespectively.The correction rewrites positions 122 through 146 and retains the signed
prefix through
d129fec35638ea7bb180cfcfd1f8fd23f2ea5c81unchanged. Everysource tree, author field, encoding and complete commit message remains
unchanged. Empty contribution commits are retained. The 25 rewritten
commits have fresh local signature verification and exact hosted payload,
signature, tree and parent checks. The preceding 121 commits retain their
existing raw objects and signatures; they were not signed again.
The metadata correction was published at
9c469978125dae8c1a928d077f4101df558aeb11, with tree32f758fcf234c48d8793293636be6648bb0d42e6. The source validation abovecontinues to apply to that unchanged tree. This metadata correction makes
no source or test changes and requires no test rerun. Historical native
results remain limited to their recorded source and image scopes.
Compare the metadata correction.
Native SimpleX reply context
The SimpleX adapter now preserves native quote context in the existing
MessageEventreply fields before shared text batching. The incoming itemID remains separate from the quoted target. Direct and group replies use
the same normalisation path, including deferred voice delivery.
This consumer depends on #133509. That PR remains
an independent native-reply contribution with its own prerequisites. This
consumer preserves the native contribution's complete message and literal
author and committer fields. A separate fixture commit adapts the expected
merged message IDs and JSON quotation to the gateway contracts in this
composition. The fixture commit also formats the new SimpleX code.
The canonical test run passed all 155 cases: 71 SimpleX, 50 shared
text-batching and 34 active-session merge cases. There were no failures,
errors or skips. That run exercised unsigned source
9001b3bab592fa576230cb72506181707050c10f, with tree183fd3b2bcc929296c03ea705211ef199d2eeb0d. The final source differs only informatting. Independent review compared both complete module syntax trees,
including all parametrisations and assertions, and confirmed equivalence.
The 155-case result is reused on that basis. The tests were not rerun after
formatting.
The independently reviewed paired Ty diagnostic comparison on the tested
source retained the same seven
adapter diagnostics and introduced none. Both Ty commands exited one.
Independent review confirmed that the formatting successor preserves the
complete diagnostic statements, scopes and types, so the Ty evidence is
reused. The fresh scoped Ruff check on the formatted source reported no diagnostics
and exited zero. The complete formatter diff retained 98 inherited groups:
69 in the adapter and 29 in its test file. The formatter exited one.
Independent review classified every group and found no introduced
formatting findings. The inherited formatting and type debt remain.
No live SimpleX daemon or native outbound quote emission was exercised.
The earlier Docker and whole-contribution qualifications remain unchanged.
The two-node SimpleX continuation is published at
83f8dec5caef2a605f8687d095e0a040d726a485,with tree
3a0b6fcf292a2a44422720490bf7091f25fabcc9. The preceding 146commit OIDs remain unchanged. Only the native contribution and its separate
fixture and formatting composition received new signatures. The two new
hosted payloads, signatures, trees and parents were verified before this
body update. The earlier prefix verification remains limited to its saved
publication scope. See the two-node SimpleX continuation.
Callback and turn-marker typing repair
Processing-start hooks and Telegram topic recovery can await before dispatch. A handler present on entry can disappear during that await. Both background and inline dispatch now select the current callback at their own call boundary and report an explicit error if the callback is absent. Background selection remains inside the pending reservation scope after the processing-start hook. The existing failure notification, marker reset, delivery and command-restoration paths remain intact.
The event's turn-marker handoff is now a declared private field. Its default is false, and
dataclasses.replaceresets it for the copied event. The field remains outside constructor, representation and equality data.This update adds one logical contribution after the complete 149-commit prefix. All prior commit identities, literal author and committer headers, dates and complete messages remain unchanged.
The paired check of the three production modules reports 52 findings before and 48 afterwards. It removes the three assigned background findings and the related inline optional-call finding, with no introduced finding. The remaining 48 findings are inherited; this is not a claim that the modules are type-clean.
The canonical lifecycle, lease and withdrawal run passes 137 cases. A separate complete command and clarification run passes 19 cases. The two runs contain 156 distinct cases, with every setup, call and teardown passing. Focused runs on the old production code reproduce the absent-handler and marker defects. The final marker line wrap preserves the complete module AST, so the saved runtime and type results remain associated with the final source.
Saved scoped Ruff checks report no lint findings. Reconstruction of the complete saved formatter output confirms that the new declarations and tests add no formatter debt; the remaining formatter changes are inherited. No fresh checker execution after the final whitespace-only wrap is claimed.
Actual Matrix room/thread execution and the remaining campaign obligations require their own acceptance.