Skip to content

fix(gateway): add trusted sender envelope for shared sessions - #69980

Open
xiaoyaner0201 wants to merge 26 commits into
NousResearch:mainfrom
xiaoyaner0201:fix/shared-session-trusted-sender-uid-v2
Open

fix(gateway): add trusted sender envelope for shared sessions#69980
xiaoyaner0201 wants to merge 26 commits into
NousResearch:mainfrom
xiaoyaner0201:fix/shared-session-trusted-sender-uid-v2

Conversation

@xiaoyaner0201

@xiaoyaner0201 xiaoyaner0201 commented Jul 23, 2026

Copy link
Copy Markdown

Summary

  • add a verified sender envelope for shared multi-user gateway turns when adapters provide trusted source.user_id / source.user_id_alt
  • preserve Slack's <@UID> mention target while extending trusted sender IDs to Discord/Telegram-style shared sessions
  • strip forged leading verified-sender envelopes from user text in every shared session, including no-trusted-UID fallback turns
  • keep DM/per-user sessions quiet and fall back to the old unverified display-name prefix when no trusted sender ID is available
  • keep verified sender envelopes out of incomplete/hidden-reasoning fallback transcripts while preserving them for the live model turn
  • make the verified claim sound: refuse cross-sender pending aggregation so no participant's content is ever rendered under another participant's authenticated ID
  • preserve global arrival order once a refused/cross-sender FIFO tail exists, including interleaved A→B→A media
  • retain empty-media PHOTO follow-ups from failed media-download paths instead of losing a helper slot replacement

Scope update — blocking review resolved

The earlier revision deferred cross-sender batching to #69961. Per the blocking review on this PR, the sender-identity guard now lands with this change; the scope note is withdrawn.

merge_pending_message_event now returns bool: True when the event was absorbed, False when the merge was refused because the pending slot belongs to a different sender (pending_merge_sender_conflict). A False return transfers ownership back to the caller, which must give the event its own turn. Every call site was audited and updated; refused events go to the runner's canonical per-session FIFO (_enqueue_fifo), never to a parallel store.

The guard is deliberately conservative. user_id_alt and user_id are compared independently; a match on either proves the same sender, and a conflict is reported only when at least one comparable pair exists and all comparable pairs differ. Missing identity means "unknown", so merging behaves exactly as before. Same-sender albums, photo bursts, and text follow-ups are unchanged. In per-user/DM sessions the guard is unreachable by construction, since build_session_key already appends the sender ID under isolate_user.

Behavior beyond the core guard, driven by review iterations:

  • refusals bypass the busy-queue cap, so the refusal itself never costs the incoming sender a message
  • once overflow exists, later arrivals append or merge only at the true FIFO tail and cannot overtake an earlier participant's turn
  • helper slot replacement is distinguished from in-place merge at both occupied-head and overflow-tail sites, retaining PHOTO-typed events whose media download produced media_urls=[]
  • /stop, /new, and /reset clear both pending tiers (adapter head slot and runner FIFO), so refused work is not left executable after an interrupt
  • shutdown forensics serialize the runner FIFO per-event via flush_queued_events_to_file, preserving FIFO order, session key, and JSON-safe SessionSource attribution
  • debounce state racing a control command is split on an immutable text boundary: the pre-command prefix is discarded while a same-sender post-command suffix and the latest message metadata survive
  • three-sender (Alice/Bob/Carol) debounce ordering is preserved rather than collapsed

Test Plan

Final published and fresh-context Sol-reviewed head edf643f638c6a89f16c43106fd52adf7ffd915ef, tree 0efc104532cc4643cd3035ddb473cb9c5f181549, additively reconciled with upstream main at 43717123ca1566a073270c5a61431e2e0e4a0211:

  • changed-feature suite: 95 passed, 0 failed across 7 files
  • reviewer-authored teardown/retry/legacy/identity probes: passed
    • real adapter head + overflow recovered FIRST → SECOND → THIRD with session identity/source and no consumed files left behind
    • a transient append failure retried without allowing later same-session FIFO events to overtake it
    • legacy/new shutdown files recovered in established order while an unsalvageable legacy payload remained available for manual recovery
    • conflicting stable IDs with equal raw IDs were refused; same-stable, asymmetric alt/raw, identity-free same-DM, and disjoint-namespace cases matched the accepted contract
  • adjacent suite: 80 passed, 5 failed; the same 5 failures reproduced on an exact origin/main archive (1 shutdown-forensics diagnostic-spawn failure and 4 local DNS/proxy-sensitive media-download failures)
  • changed-production-file Ruff: passed
  • git diff --check: passed
  • fresh-context independent exact-tree review using gpt-5.6-sol / openai-codex: PASS with 0 P0 / 0 P1 / 0 P2
  • full suite: not run / UNVERIFIED on this final tree; it is not being described as green

Publication was a normal non-force fast-forward from f0ec41764ad7611c6b8f057878b56a264084faf8 to the exact reviewed tip. Git fetch, ls-remote, and GitHub PR read-back all returned the same final head.

After publication, upstream main advanced by 4 disjoint commits to 36cb5ae5530a75def7df3195e49b7a4aa2add482. Those commits touch 14 paths with no overlap with this PR's 11 paths, git merge-tree --write-tree origin/main HEAD is clean, and GitHub still reports the PR as mergeable. The exact-tree review remains anchored to the published tree and its merged base above; the later disjoint drift is reported separately rather than silently presented as reviewed.

Acceptance status

  • code gate: PASS on exact head/tree edf643f638 / 0efc104532
  • CI-ready: yes for focused review, with the adjacent exact-base attribution and full-suite UNVERIFIED caveat disclosed
  • GitHub state: OPEN / MERGEABLE / BLOCKED, with no reported checks or maintainer review decision
  • merge-train eligibility: not established
  • review mode: 11 files, +2516/-85, touching gateway/session-state/message-delivery and shutdown recovery; this requires one-to-one maintainer review rather than low-risk batch handling
  • remaining gate: maintainer review/decision; this does not imply merge, release, or issue completion

Refs #69961

Supersedes #69963 because GitHub did not synchronize that PR object after the fork branch advanced past a09e6db230b064d61c7d34b1630bce0e09872f51; the fork ref is current at this replacement branch.

@alt-glitch alt-glitch added type/feature New feature or request P3 Low — cosmetic, nice to have comp/gateway Gateway runner, session dispatch, delivery platform/discord Discord bot adapter platform/slack Slack app adapter platform/telegram Telegram bot adapter sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state needs-decision Awaiting maintainer decision before any implementation labels Jul 23, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

Related to #69961 and closed predecessor #69963. This is the narrower shared-session-only sender-attribution design; #13939 is the broader default-on all-context proposal. Flagging the scope choice for maintainer review; neither is a duplicate.

@xiaoyaner0201
xiaoyaner0201 force-pushed the fix/shared-session-trusted-sender-uid-v2 branch from 3cc6e75 to be01c1f Compare July 29, 2026 20:35
@xiaoyaner0201

Copy link
Copy Markdown
Author

Rebased onto current main to clear the merge conflict — the PR was showing DIRTY.

What drifted: tests/gateway/test_image_input_routing_runtime.py gained
test_prepare_route_identity_check_keeps_event_loop_responsive upstream (via 8c50aac /
91546b8) while this branch appended its own tests to the same tail of the file. The
conflict was purely additive — both test blocks are kept verbatim, nothing was dropped or
rewritten.

  • base: e23d158f48370d40e9e6f0f78244f8b6741af740
  • new head: be01c1f25da744343bd2aa2b3e4579ca5482a3d4
  • tree: 028f2f1cf7a1f7a07b393f6ceb7913cceea96ec6

Verified on the rebased tree with the canonical runner:

scripts/run_tests.sh tests/gateway/test_shared_group_sender_prefix.py \
  tests/gateway/test_image_input_routing_runtime.py \
  tests/gateway/test_incomplete_gateway_turns.py \
  tests/gateway/test_session_race_guard.py -q

=== Summary: 4 files, 35 tests passed, 0 failed (100% complete) in 16.8s ===

That includes the upstream event-loop test that caused the conflict, so the merge
resolution is behaviourally confirmed rather than just syntactically clean. Full suite not
run in this pass — unverified, not claimed green.


On the triage note about aggregation: it's correct, and I've reproduced it. Detail is in
my comment on #69961.
Short version — merge_pending_message_event (gateway/platforms/base.py:2435) mutates
existing.text / existing.media_urls in place without ever consulting event.source, so
a merged turn keeps the first sender's SessionSource while carrying a second sender's
content under that verified envelope. The PHOTO+TEXT path is the worst case: the incoming
text replaces the empty pending text outright.

I'm working that fix on a separate chain and will send it as its own PR rather than growing
this one, since this PR is already reviewable as the envelope itself. Happy to fold it in
here instead if you'd prefer a single change — your call.

…search#69961)

merge_pending_message_event folds a follow-up event into the pending slot
without consulting event.source, so a second participant's text/media is
absorbed into the first participant's turn and rendered under the FIRST
sender's [Verified sender: ...] envelope in shared multi-user sessions.

Adds 14 behavioural tests asserting the invariant that every fragment of a
pending turn must originate from the sender named by that turn's source,
and that refusing to merge must never cost a message. Tests only — no
production change; the guard implementation lands separately.

7 of 14 fail on real assertions at this head.
…search#69961)

In a shared group session several senders share one session_key, so
merge_pending_message_event could splice one human's text or photos into
another human's pending turn. The combined turn was then rendered under a
single [Verified sender: ...] envelope, claiming an author it did not have.

Add module-level pending_merge_sender_conflict(existing, event), resolving
identity as source.user_id_alt or source.user_id — the same precedence
_can_merge_text_debounce_events already uses for the debounce buffer. A
conflict is reported only when BOTH sides resolve and differ; a missing
identity on either side means "unknown", never "different", so a refusal can
never cost a message.

merge_pending_message_event now returns bool: True = absorbed, False =
refused. On refusal the caller owns the event and must give it its own turn.
_queue_or_replace_pending_event falls through to the FIFO; adapter-level
sites with no FIFO park the event via _defer_refused_pending_event, bounded
by _REFUSED_PENDING_MAX, and get_pending_message promotes it once the slot
drains. Debounce-flush call sites are same-sender by construction and left
unchanged.

The guard is unreachable in per-user/DM sessions: build_session_key appends
user_id_alt or user_id under isolate_user, so distinct senders cannot share
a session_key. No config surface, no envelope format change.
@teknium1

Copy link
Copy Markdown
Contributor

Thanks for narrowing this to shared sessions and preserving the existing Slack mention target.

Problems

  • Blocking: the verified claim is not sound while pending media/photo events can cross sender boundaries. gateway/platforms/base.py:2460-2485 merges incoming text and media into the existing pending event without comparing event.source; gateway/platforms/base.py:5697-5700 invokes that path for queued photos. The surviving event source is then what the new gateway/run.py envelope uses, so later participant content can be presented under the first participant's authenticated ID. The linked Add trusted sender UID envelope for shared gateway sessions #69961 discussion identifies this same boundary.

Suggested changes

  • Land the sender-identity guard/queue behavior with this change, preserving same-sender album handling while preventing cross-sender coalescing in shared sessions.
  • Add PHOTO+TEXT and PHOTO+PHOTO cross-sender regressions that assert separate source-attributed model turns.

This is an automated hermes-sweeper review.

@teknium1 teknium1 added sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform area/sessions Session lifecycle, resume, persistence, history labels Jul 30, 2026
@xiaoyaner0201

Copy link
Copy Markdown
Author

Thanks for the review — the blocking issue is now fixed in this PR rather than deferred, and the scope note has been withdrawn from the description.

Head: be01c1f25da744343bd2aa2b3e4579ca5482a3d4d20737bf0e07389c70870639da3602bf0dffbf16 (tree 227e886dd182cfaae8583b2e8c3fb10405fae343). Eight additive commits, fast-forward only — no amend, squash, rebase, or force-push; all previously published history is intact.

On the blocking finding

You were right that the verified claim was unsound: merge_pending_message_event coalesced text and media into the existing pending event without comparing event.source, and the surviving source is what the envelope renders. Reproducing it first showed the PHOTO+TEXT case is actually worse than described — the incoming sender's text was absorbed into the first sender's event, so the second participant's words shipped under the first participant's authenticated ID with no trace of the real author.

merge_pending_message_event now returns bool. False means the merge was refused on sender conflict and ownership of the event transfers back to the caller, which must give it its own turn. Every call site was audited and updated; refused events land in the runner's canonical per-session FIFO rather than any parallel store.

The predicate is intentionally conservative: user_id_alt and user_id are compared independently, a match on either proves the same sender, and a conflict is reported only when at least one comparable pair exists and every comparable pair differs. Missing identity is treated as unknown and merges exactly as before, so same-sender albums, photo bursts, and text follow-ups are untouched. In per-user/DM sessions the guard is unreachable by construction, since build_session_key already appends the sender ID under isolate_user.

What the refusal path had to get right

Refusing the merge is the easy half; not losing the refused message is the hard half. Iterative review turned up several ways it could still be dropped, each now covered:

  • refusals bypass the busy-queue cap, so the refusal never costs the incoming sender a message
  • /stop, /new, and /reset clear both tiers (adapter head slot and runner FIFO) — otherwise an interrupt left refused work still executable
  • shutdown forensics serialize the FIFO per-event, preserving order, session key, and JSON-safe SessionSource attribution, instead of collapsing a session's tail to one value
  • debounce state racing a control command is split on an immutable text boundary, discarding the pre-command prefix while preserving a same-sender post-command suffix and the latest message metadata
  • three-sender (Alice/Bob/Carol) debounce ordering is preserved rather than collapsed

Requested regressions

PHOTO+TEXT and PHOTO+PHOTO cross-sender cases both assert separate source-attributed model turns. Also added: asymmetric user_id_alt in both directions, missing-identity fallback, refusal reachability at the busy cap, three-sender debounce ordering, /stop draining both tiers, FIFO survival through shutdown forensics, and per-turn envelope attribution.

Verification

scripts/run_tests.sh tests/gateway/test_shared_group_sender_prefix.py -q
=== Summary: 1 files, 34 tests passed, 0 failed (100% complete) ===

scripts/run_tests.sh tests/gateway/test_session_race_guard.py tests/gateway/test_incomplete_gateway_turns.py tests/gateway/test_image_input_routing_runtime.py -q
=== Summary: 3 files, 31 tests passed, 0 failed (100% complete) ===

scripts/run_tests.sh tests/gateway/test_shutdown_flush.py -q
=== Summary: 1 files, 15 tests passed, 0 failed (100% complete) ===

scripts/run_tests.sh tests/gateway/ -q
=== Summary: 564 files, 11800 tests passed, 25 failed (100% complete) ===

The 25 full-suite failures are a pre-existing baseline unrelated to this change (test_media_download_retry.py 10, test_wecom_callback.py 3, test_slack.py 2, test_slack_download_ssrf.py 2, and 1 each in test_background_command.py, test_session_hygiene.py, test_shutdown_forensics.py, test_systemd_notify.py, test_wecom.py, test_feishu.py, test_telegram_thread_fallback.py, test_matrix.py). Zero failures in any file this PR touches. ruff check on all touched files and git diff --check both pass.

Happy to split the refusal-plumbing commits out of the envelope change if you'd prefer to review them separately.

Resolves the only conflict, in tests/gateway/test_shared_group_sender_prefix.py.
Upstream 3997561 (test prune wave 2) deleted three preprocess tests from that
file while this branch appended the cross-sender aggregation suite to the same
region. Resolution accepts upstream deletions verbatim and keeps every test this
branch added; no assertion was weakened or rewritten.
@alt-glitch alt-glitch added comp/plugins Plugin system and bundled plugins and removed sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data labels Jul 30, 2026
@xiaoyaner0201

Copy link
Copy Markdown
Author

Follow-up: main advanced past this branch's merge base between the review and this update, so GitHub marked the PR DIRTY. Resolved by merging origin/main in — no rebase, amend, or force-push; every previously published commit is still an ancestor.

  • head: d20737bf0e07389c70870639da3602bf0dffbf1613f1bacc67fb72f0632b5dd257aded98fb06146c
  • merge commit: 13f1bacc6
  • PR now reports mergeable: true

What conflicted: exactly one file, tests/gateway/test_shared_group_sender_prefix.py. Upstream 39975613b ("test: prune wave 2 + speed fixes") deleted three preprocess tests from that file, while this branch appended the cross-sender aggregation suite to the same region. The resolution accepts upstream's deletions verbatim and keeps every test this branch added — no assertion was weakened, renamed, or rewritten. No product code conflicted; gateway/platforms/base.py and gateway/run.py auto-merged.

Re-verified on the merged tree bb93d7bfc9d9464659895ca6598aa4bec4aff0d1:

scripts/run_tests.sh tests/gateway/test_shared_group_sender_prefix.py \
  tests/gateway/test_session_race_guard.py tests/gateway/test_incomplete_gateway_turns.py \
  tests/gateway/test_image_input_routing_runtime.py tests/gateway/test_shutdown_flush.py -q
=== Summary: 5 files, 51 tests passed, 0 failed (100% complete) ===

scripts/run_tests.sh tests/gateway/ -q
=== Summary: 570 files, 4468 tests passed, 12 failed (100% complete) ===

The 12 remaining full-suite failures are a strict subset of the pre-merge baseline (the prune removed some of the previously failing cases): test_media_download_retry.py 4, test_wecom_callback.py 2, and 1 each in test_shutdown_forensics.py, test_systemd_notify.py, test_telegram_thread_fallback.py, test_wecom.py, test_feishu.py, test_slack.py. All are pre-existing and unrelated; zero failures in any file this PR touches. ruff check and git diff --check still pass.

@xiaoyaner0201

Copy link
Copy Markdown
Author

Post-publication exact-tree review found two additional loss/order defects in the blocking aggregation repair; both are now fixed by additive fast-forward commits and independently re-reviewed.

Published repair

  • previous public head: 13f1bacc67fb72f0632b5dd257aded98fb06146c
  • new head: 8fd0c5294128f143b14185b430c8d4e1fd45311a
  • tree: cf3bc308e41e526dbaac77f7529da79dbc919656
  • commits: 1a75a2eef and 8fd0c5294
  • publication was fast-forward only; no rebase, amend, squash, or force-push

The first defect was interleaved FIFO ordering: A1 (Alice), B1 (Bob), A2 (Alice) could drain as A1, A2, B1 because A2 merged backward into the occupied head after B1 had entered overflow. Overflow is now authoritative: later arrivals append or merge only at the true tail, preserving A1, B1, A2 while retaining contiguous same-sender album aggregation.

The second defect was silent loss of a PHOTO-typed event with media_urls=[], a real shape after media-download failure. The merge helper can return True both for an in-place merge and for slot replacement; the old tail path treated both as absorption and discarded the replacement held in a temporary dict. Head and tail paths now distinguish those outcomes and enqueue the replacement as its own turn.

Verification

  • TDD RED: 5 A→B→A regressions and 4 empty-media PHOTO regressions failed before their respective production edits
  • focused canonical suite: 74 passed, 0 failed
  • parent exact-tree publication probe: 9 passed, 0 failed
  • full gateway suite: 12 baseline failures across 8 untouched files, exactly matching the prior reviewed baseline; zero touched-file failures
  • changed-file ruff and git diff --check: passed
  • fresh O10 review on the exact final tree: PASS, 0 P0 / 0 P1 / 0 P2, including 20 independent adversarial checks

Current upstream main is 524ab539947aa7a092d749921e0e93913cb683de; a local merge-tree check reports no conflict. The PR remains a 7-file, +1600/-58 gateway/session-state/message-delivery change and should continue through one-to-one maintainer review rather than be treated as a batch candidate.

@GottZ

GottZ commented Aug 3, 2026

Copy link
Copy Markdown

This was generated by AI during triage.

Summary

Two PRs address Issue #69961. PR #69963 adds the shared-session trusted sender envelope, Slack mention preservation, forged-header stripping, and DM quietness; PR #69980 carries that envelope work forward and additionally repairs cross-sender pending aggregation, FIFO ordering, failed-media retention, and related persistence and regression coverage.

Related pull requests

  • fix(gateway): add trusted sender envelope for shared sessions #69963 [closed] best fix — (+135/-12) — verify n/a: adds the shared-session authenticated sender envelope in gateway/run.py, preserves Slack <@uid>, strips forged headers when a trusted ID exists, keeps DMs quiet, and retains the name-prefix fallback. Closed because it was superseded by fix(gateway): add trusted sender envelope for shared sessions #69980, whose synchronized diff includes this envelope work plus the aggregation-boundary repair.
  • fix(gateway): add trusted sender envelope for shared sessions #69980 best fix — (+1600/-58) — verify n/a: adds the trusted envelope across shared sessions and prevents cross-sender text/media coalescing by refusing conflicting merges and routing events through the FIFO, while covering A→B→A ordering, empty-media PHOTO retention, shutdown persistence, control-command cleanup, and regressions. The automated keep-open verdict aligns with retaining this broader salvageable implementation for maintainer review; it is open but not merge-lane eligible.

Duplicates

#69963 is the closed predecessor of #69980 and is superseded by it; #69980 contains the overlapping sender-envelope change and extends it with the cross-sender aggregation and FIFO repairs.

Suggested consolidation

Keep #69980 open with a salvage path: preserve the trusted-envelope and lossless cross-sender FIFO changes, then obtain maintainer review of the 7-file/+1600/-58 implementation; do not recommend merging because no merge-lane best-fix finding is recorded. Close #69963 as duplicate of #69980, consistent with its documented supersession and the structural close edge.

Complex graph

flowchart LR
    classDef open fill:#dbeafe,stroke:#1d4ed8,color:#1e3a8a
    classDef merged fill:#dcfce7,stroke:#15803d,color:#14532d
    classDef closed fill:#e5e7eb,stroke:#6b7280,color:#1f2937
    classDef unverified fill:#f3f4f6,stroke:#9ca3af,color:#374151
    classDef best stroke-width:3px,stroke:#b45309
    classDef target stroke-width:3px,stroke:#4338ca
    I69961(["issue #69961 (open)"])
    subgraph Dup69963 ["PRs duplicating each other"]
        P69963["PR #69963 (closed)"]
        P69980["PR #69980 (open)"]
    end
    P69980 -->|best fix| I69961
    class I69961 open
    class P69963 closed
    class P69980 open
    class P69963 best
    class P69980 best
    class P69980 target
    click I69961 "https://github.com/NousResearch/hermes-agent/issues/69961"
    click P69963 "https://github.com/NousResearch/hermes-agent/pull/69963"
    click P69980 "https://github.com/NousResearch/hermes-agent/pull/69980"
Loading

Graph: solid arrow = fixes / best fix, dashed arrow = partial or unverified (see edge label); boxed group = PRs duplicating each other; amber border = best fix; indigo border = target; gray node = closed (state tag in the node label).

Cross-PR triage: Reviewed 2 pull requests and 1 issue in this complex. Each diff was read against this issue; Assessment working set: 92 kB of PR diffs, 9 kB of issue/PR text, 19 kB of discussion (11 comments), 5 verify verdicts. verdicts reflect diff content, not PR titles. Part of an automated triage batch.

@alt-glitch alt-glitch added P2 Medium — degraded but workaround exists and removed P3 Low — cosmetic, nice to have labels Aug 4, 2026
@xiaoyaner0201

Copy link
Copy Markdown
Author

Published the latest independently reviewed repair/reconciliation tip for #69961.

Exact public artifact

  • head: edf643f638c6a89f16c43106fd52adf7ffd915ef
  • tree: 0efc104532cc4643cd3035ddb473cb9c5f181549
  • reviewed merged base: 43717123ca1566a073270c5a61431e2e0e4a0211
  • publication: normal non-force fast-forward from f0ec41764ad7611c6b8f057878b56a264084faf8; fetch, ls-remote, and GitHub PR read-back all matched the intended head

This final repair chain additionally covers stable-ID precedence and session-aware, retry-safe FIFO shutdown recovery: real adapter-head and overflow events retain session/source attribution, recover in FIRST → SECOND → THIRD order, and do not let a later event overtake an earlier transient append failure. Legacy recovery files remain compatible/manual-salvageable.

Verification

  • changed-feature suite: 95 passed, 0 failed
  • fresh-context independent exact-tree review using gpt-5.6-sol / openai-codex: PASS, 0 P0 / 0 P1 / 0 P2
  • adjacent suite: 80 passed, 5 failed; all 5 reproduced identically on exact upstream main
  • changed-production-file Ruff and git diff --check: passed
  • full suite on this final tree: UNVERIFIED, not claimed green

Upstream main advanced by 4 disjoint commits after publication. They overlap none of this PR's 11 paths, a current merge-tree check is clean, and GitHub still reports OPEN / MERGEABLE / BLOCKED with no maintainer review decision or checks. The remaining gate is one-to-one maintainer review; this is not a merge/release/Issue-completion claim.

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

Labels

area/sessions Session lifecycle, resume, persistence, history comp/gateway Gateway runner, session dispatch, delivery comp/plugins Plugin system and bundled plugins P2 Medium — degraded but workaround exists platform/discord Discord bot adapter platform/slack Slack app adapter platform/telegram Telegram bot adapter sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants