Skip to content

chore: finish channel migration — repair build, test gates, docs#10

Open
YellowSnnowmann wants to merge 6 commits into
tinyhumansai:mainfrom
YellowSnnowmann:chore/finish-channel-migration
Open

chore: finish channel migration — repair build, test gates, docs#10
YellowSnnowmann wants to merge 6 commits into
tinyhumansai:mainfrom
YellowSnnowmann:chore/finish-channel-migration

Conversation

@YellowSnnowmann

@YellowSnnowmann YellowSnnowmann commented Jul 17, 2026

Copy link
Copy Markdown

Summary

Finishing slices for the OpenHuman channel migration into this crate, batched
in dependency order. The migration itself (Phases 0–6) already largely landed;
this closes the critical build break and hardens three acceptance-gate test
holes, then refreshes the stale plan docs.

Commits, in order:

  1. fix(deps): revert hmac to 0.12 to repair broken build — the dependabot
    hmac 0.13 bump requires digest 0.11, but the hash stack is still on
    digest 0.10 (sha2 0.10, sha1 0.10), so Hmac<Sha256>/Hmac<Sha1> fail
    their bounds and the call sites still use the 0.12 new_from_slice API. This
    left main red (CI failing on HEAD). Reverts to hmac 0.12 and prunes the
    orphaned 0.13 lock entry. This must land first — the rest build on it.
  2. test(delivery): cover durability negotiation across all capability keys
    the negotiation suite only exercised 4 of 13 DurableFinalDeliveryCapability
    variants. Adds exhaustive downgrade/preserve coverage, an advertised-as-false
    case, the Disabled short-circuit, multi-missing reporting, and the full
    OutboundPayload→requirement mapping.
  3. test(controllers): assert connect schema advertises every auth mode — ties
    ChannelAuthMode to the connect controller schema via an exhaustive match
    (a new variant fails to compile until registered) plus Display/FromStr
    round-trip checks, so the enum and the client-facing schema can't drift.
  4. test(relay): add WebSocket loopback acceptance tests — real in-process
    tokio-tungstenite loopback covering newline-delimited frame sequencing,
    upgrade-token accept/reject at the handshake, and reconnect through
    WebSocketRelayDialer (previously only the in-memory mock was exercised).
  5. docs: refresh migration state to reflect ported providers — the plan and
    porting docs predated the provider port; corrects porting.md, adds a dated
    addendum to the execution plan, and adds the remaining-work plan as the
    source of truth.

API Or Behavior Changes

None. Commit 1 is a dependency revert; commits 2–4 are tests only; commit 5 is
docs only. No public API or runtime behavior changes.

Tests

Run locally with cargo +1.96.1 (1.96 is required by libsqlite3-sys 0.38):

  • cargo fmt --check
  • cargo clippy --all-targets -- -D warnings
  • cargo clippy --all-targets --all-features -- -D warnings
  • cargo build --all-targets
  • cargo build --all-targets --all-features
  • cargo test (949 passed)
  • cargo test --all-features
  • cargo test --features relay-websocket (relay loopback 3/3)

Documentation

docs/porting.md and docs/spec/tinychannels-execution-plan.md updated to
match the current provider state; docs/spec/tinychannels-migration-remaining-plan.md
added as the source of truth for the remaining finishing work (durable
WhatsApp Web session storage and the non-relay scope_id session-key
switchover).

Summary by CodeRabbit

  • Bug Fixes

    • Improved Telegram group mention handling, including cases where the bot username is unavailable or the message does not directly mention the bot.
    • Preserved clearer error reporting when Yuanbao authentication requests fail.
  • Documentation

    • Updated provider portability documentation to reflect recently migrated channel integrations and remaining limitations.
    • Added a maintained plan outlining migration progress, remaining work, sequencing, and acceptance criteria.

The dependabot bump to hmac 0.13 (PR tinyhumansai#4) requires digest 0.11, but the
sha2/sha1 hashes remain on 0.10 (digest 0.10), so Hmac<Sha256>/Hmac<Sha1>
no longer satisfy their trait bounds and every call site still uses the
0.12 new_from_slice API. This left main red (CI failure on the current
HEAD) and unbuildable at relay/auth.rs, providers/linq.rs, and
providers/yuanbao/{sign,cos}.rs.

Revert to hmac 0.12 to match the hash stack the code targets and prune the
orphaned 0.13 entry from the lockfile. Moving the whole SHA stack to
digest 0.11 is left as a separate coordinated bump.
The negotiation suite only exercised Text/Media/ReplyTo/Thread. Add
exhaustive coverage over every DurableFinalDeliveryCapability variant
(downgrade-when-unsupported and preserve-when-supported), an
advertised-as-false case, the Disabled short-circuit, multi-missing
reporting, and the full OutboundPayload->requirement mapping.
Nothing tied ChannelAuthMode to the connect controller schema, whose
authMode description hardcodes the wire-name list; a new auth mode could
ship without appearing in the schema and only fail at runtime. Add a
parity test with an exhaustive match (new variants fail to compile until
registered) that also checks Display/FromStr round-trips and that the
connect schema description advertises each wire name.
The relay-websocket transport had only URL/token/config unit tests;
real framed I/O, upgrade authorization, and reconnect went through the
in-memory mock. Add in-process tokio-tungstenite loopback tests that
dial the real WebSocketRelayIo and assert newline-delimited frame
sequencing (batched connector frames decoded in order plus a gateway
frame echoed back), upgrade-token accept/reject at the handshake, and
reconnect through WebSocketRelayDialer.
The execution plan (2026-07-04) and porting.md predate the provider
port: 16 providers now live in src/providers/ behind the src/host/
service boundary, and OpenHuman consumes them as re-export shims. Correct
porting.md's 'Not Yet Ported' section, add a dated addendum to the
execution plan, and add the remaining-work plan as the source of truth
for the finishing slices.
@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The changes update migration documentation, pin hmac to version 0.12, refine two provider code paths, and add coverage for delivery negotiation, controller auth-mode schemas, and relay WebSocket framing, authorization, and reconnect behavior.

Changes

Migration validation

Layer / File(s) Summary
Migration status and remaining-work plan
docs/porting.md, docs/spec/tinychannels-...md
Documentation now describes the host-boundary migration state, verified progress, remaining work slices, sequencing, constraints, open questions, and non-goals.
Dependency and provider compatibility fixes
Cargo.toml, src/providers/telegram/..., src/providers/yuanbao/...
The hmac dependency is set to 0.12; Telegram optional username handling and Yuanbao error formatting are adjusted without changing reported behavior.
Delivery and controller contract coverage
src/delivery/test.rs, src/controllers/definitions_tests.rs
Tests cover durable capability negotiation, payload capability mapping, and all ChannelAuthMode wire names in the connect schema.
Relay WebSocket loopback coverage
src/relay/test.rs
Feature-gated tests validate authorized framing, rejected upgrades, and reconnect handshakes over real WebSocket connections.

Estimated code review effort: 3 (Moderate) | ~30 minutes

Suggested reviewers: senamakel

Poem

A rabbit hops through tests so bright,
WebSockets loop through day and night.
HMAC settles, docs align,
Durable paths now clearly shine.
Thump-thump! The migration’s fine.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: finishing the channel migration by fixing the build, adding test coverage, and updating docs.
Docstring Coverage ✅ Passed Docstring coverage is 85.71% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Comment @coderabbitai help to get the list of available commands.

CI runs clippy on the current stable toolchain (1.97), which flags two
pre-existing lints that older clippy did not: a question_mark rewrite in
telegram/channel_recv.rs and a redundant reference in a format! argument
in yuanbao/sign.rs. Apply clippy's own suggestions (an ? early-return and
dropping the &) so `cargo clippy --all-targets --all-features -- -D warnings`
is clean on stable. No behavior change.
@YellowSnnowmann
YellowSnnowmann marked this pull request as ready for review July 17, 2026 12:36

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (2)
src/delivery/test.rs (1)

657-666: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Assert the complete capability map.

Checking only the expected entry allows accidental extra requirements to pass, potentially causing unnecessary BestEffort downgrades.

Proposed assertion
     for (payload, expected) in cases {
         let requirements = required_durable_final_capabilities(&intent(payload.clone()));
+        let mut expected_requirements =
+            crate::channel::DurableFinalDeliveryRequirementMap::new();
+        expected_requirements.insert(expected, true);
         assert_eq!(
-            requirements.get(&expected),
-            Some(&true),
+            requirements,
+            expected_requirements,
             "{payload:?} should require {expected:?}"
         );
-        assert!(!requirements.contains_key(&ReplyTo));
-        assert!(!requirements.contains_key(&Thread));
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/delivery/test.rs` around lines 657 - 666, Update the assertions in the
required_durable_final_capabilities test loop to compare the complete returned
capability map against the expected map for each case, rather than checking only
the expected entry. Preserve the existing validation that ReplyTo and Thread
remain absent, and ensure unexpected capability requirements cause the test to
fail.
src/relay/test.rs (1)

853-913: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Add deadlines to the loopback tests.

The unbounded accept, next, connection, and server-join awaits can hang CI indefinitely after a protocol or connection-close regression. Give each scenario a test-level timeout and abort its server task on timeout.

Also applies to: 915-936, 938-986

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/relay/test.rs` around lines 853 - 913, Wrap the loopback test scenarios,
including roundtrips_frames_in_order_over_a_real_socket and the additional tests
around them, in test-level timeouts covering connection, accept, websocket next,
and server join awaits. On timeout, abort the spawned server task before failing
the test, while preserving the existing assertions and protocol behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/porting.md`:
- Around line 51-75: Update the later current-status paragraph in
docs/porting.md to remove stale claims that provider wire adapters remain
pending, aligning it with the resolved migration described near the provider
portability ladder. Keep only non-relay session-key adoption as pending, while
preserving the existing WhatsApp Web durable-session backend debt if it is still
accurate.

In `@docs/spec/tinychannels-migration-remaining-plan.md`:
- Around line 23-27: Correct the provider inventory/count discrepancy by using
15 providers, matching the enumerated list. Update the source-of-truth summary
in docs/spec/tinychannels-migration-remaining-plan.md, then align the
corresponding progress summaries in docs/porting.md and
docs/spec/tinychannels-execution-plan.md; do not add a provider.
- Around line 56-65: Update the source-of-truth migration plan to mark G0, G1,
G2, G3, and G4 as completed, removing G0’s Blocker status from the ranked table.
Revise the corresponding detailed sections, sequencing guidance, and G1 status
so they describe the post-merge state, while leaving unresolved slices G5, G6,
and G7 as remaining work.

---

Nitpick comments:
In `@src/delivery/test.rs`:
- Around line 657-666: Update the assertions in the
required_durable_final_capabilities test loop to compare the complete returned
capability map against the expected map for each case, rather than checking only
the expected entry. Preserve the existing validation that ReplyTo and Thread
remain absent, and ensure unexpected capability requirements cause the test to
fail.

In `@src/relay/test.rs`:
- Around line 853-913: Wrap the loopback test scenarios, including
roundtrips_frames_in_order_over_a_real_socket and the additional tests around
them, in test-level timeouts covering connection, accept, websocket next, and
server join awaits. On timeout, abort the spawned server task before failing the
test, while preserving the existing assertions and protocol behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7cd1e675-ca3a-49f5-9518-65d8b1d3051f

📥 Commits

Reviewing files that changed from the base of the PR and between cb9c6f8 and 1030d18.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (9)
  • Cargo.toml
  • docs/porting.md
  • docs/spec/tinychannels-execution-plan.md
  • docs/spec/tinychannels-migration-remaining-plan.md
  • src/controllers/definitions_tests.rs
  • src/delivery/test.rs
  • src/providers/telegram/channel_recv.rs
  • src/providers/yuanbao/sign.rs
  • src/relay/test.rs

Comment thread docs/porting.md
Comment on lines +51 to +75
Update 2026-07-17: the provider wire implementations have since been ported.
`src/providers/` now owns dingtalk, discord, email, imessage, irc, lark, linq,
mattermost, qq, signal, slack, telegram, whatsapp, whatsapp_web, and yuanbao.
The app-side dependencies were reduced to a host-owned service boundary
(`src/host/`: HTTP proxy client, approval, voice/STT, pairing, and
conversation-memory contracts) that providers call instead of importing
OpenHuman internals. In OpenHuman the corresponding `channels/providers/*.rs`
files are now one-line re-exports of the crate providers; Telegram keeps only
its host-coupled glue (`remote_control`, `bus`, `approval_surface`).

Per the 2026-07-04 audit, provider portability falls into a ladder:
The original 2026-07-04 portability ladder, now resolved:

- Self-contained today (no cross-module OpenHuman imports): email, irc,
yuanbao, cli, imessage, mattermost, qq, dingtalk, presentation.
- Need only a configured-HTTP-client trait (they import
`build_runtime_proxy_client`): discord, slack, whatsapp, lark, signal.
- Need approval, voice/STT, pairing, and conversation-memory traits first:
telegram.
- Not porting targets (they are the app-side consumers of this crate): the
`runtime/` dispatch engine and the `web` provider.
- Self-contained (no cross-module OpenHuman imports): email, irc, yuanbao,
imessage, mattermost, qq, dingtalk — ported.
- Needed only a configured-HTTP-client trait: discord, slack, whatsapp, lark,
signal — ported via the host proxy-client contract.
- Needed approval, voice/STT, pairing, and conversation-memory traits:
telegram — ported via the host service boundary.
- Not porting targets (app-side consumers of this crate): the `runtime/`
dispatch engine and the `web` provider — unchanged, they stay in OpenHuman.

Remaining provider debt: WhatsApp Web still uses `wacore`'s in-memory session
backend and re-links after restart, pending a rusqlite-backed durable store
(see the remaining-work plan). The finishing slices for the migration are
tracked in [spec/tinychannels-migration-remaining-plan.md](spec/tinychannels-migration-remaining-plan.md).

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Remove the stale provider-migration status.

This section now states that provider wire adapters have been ported, but the file’s later current-status paragraph still says they are pending. Update that status text so the porting document has one authoritative migration state; only non-relay session-key adoption should remain pending.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/porting.md` around lines 51 - 75, Update the later current-status
paragraph in docs/porting.md to remove stale claims that provider wire adapters
remain pending, aligning it with the resolved migration described near the
provider portability ladder. Keep only non-relay session-key adoption as
pending, while preserving the existing WhatsApp Web durable-session backend debt
if it is still accurate.

Comment on lines +23 to +27
- **Phase 6 (providers) mostly complete**: 16 providers live under
`src/providers/` (dingtalk, discord, email, imessage, irc, lark, linq,
mattermost, qq, signal, slack, telegram, whatsapp, whatsapp_web, yuanbao).
In OpenHuman the corresponding files are now **1-line re-exports**
(e.g. `channels/providers/discord.rs` = `pub use tinychannels::providers::discord::*;`).

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Keep the provider count consistent across all migration documents.

Each location claims 16 providers, while the enumerated inventory contains 15. Either add the missing provider everywhere or change all three summaries to 15.

  • docs/spec/tinychannels-migration-remaining-plan.md#L23-L27: correct the source-of-truth inventory/count.
  • docs/porting.md#L51-L53: align the porting summary with the corrected inventory.
  • docs/spec/tinychannels-execution-plan.md#L20-L24: align the progress update with the corrected inventory.
📍 Affects 3 files
  • docs/spec/tinychannels-migration-remaining-plan.md#L23-L27 (this comment)
  • docs/porting.md#L51-L53
  • docs/spec/tinychannels-execution-plan.md#L20-L24
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/spec/tinychannels-migration-remaining-plan.md` around lines 23 - 27,
Correct the provider inventory/count discrepancy by using 15 providers, matching
the enumerated list. Update the source-of-truth summary in
docs/spec/tinychannels-migration-remaining-plan.md, then align the corresponding
progress summaries in docs/porting.md and
docs/spec/tinychannels-execution-plan.md; do not add a provider.

Comment on lines +56 to +65
| ID | Slice | Repo | Effort | Class |
| --- | --- | --- | --- | --- |
| G0 | Repair red `main` (hmac crypto-stack break) | tinychannels | S | Blocker |
| G7 | Session-key `scope_id` switchover for non-relay providers (bug 2) | both | M | Correctness |
| G5 | WhatsApp-Web durable session storage (rusqlite backend) | tinychannels | L | Functional gap |
| G2 | Delivery-durability negotiation tests (all 13 capability keys) | tinychannels | M | Test gate |
| G3 | Controller definitions↔schema parity test | tinychannels | M | Guardrail |
| G4 | Relay WebSocket loopback acceptance tests | tinychannels | M | Phase-5 gate |
| G6 | Delete OpenHuman-side portable duplicate tests | openhuman | M | Cleanup |
| G1 | Rewrite stale plan/porting docs to match reality | both | M | Docs |

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Mark the completed slices as resolved in this source-of-truth plan.

The PR objectives say G0, G2, G3, G4, and the documentation rewrite G1 are completed here, but this plan still presents them as remaining work and keeps G0 labeled a blocker. Update the ranked table, detailed sections, sequencing, and G1 status so the plan reflects the post-merge state.

Also applies to: 67-89, 126-153, 166-172

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/spec/tinychannels-migration-remaining-plan.md` around lines 56 - 65,
Update the source-of-truth migration plan to mark G0, G1, G2, G3, and G4 as
completed, removing G0’s Blocker status from the ranked table. Revise the
corresponding detailed sections, sequencing guidance, and G1 status so they
describe the post-merge state, while leaving unresolved slices G5, G6, and G7 as
remaining work.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant