Video calling, screen sharing, call page, tabbed settings, auto-reconnect#6
Merged
Merged
Conversation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…rack management - Connections reused on renegotiation instead of recreated - Perfect negotiation: polite/impolite by peer ID comparison - onnegotiationneeded handler for addTrack/removeTrack flows - Unified video management: start_video/stop_video_share - ontrack redesign: routes audio to <audio> elements, video to callback - Camera and screen share mutually exclusive via VideoSource enum Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…trols Full call page replaces chat when in voice channel. Participant tiles show peer-ID-derived gradient avatars or video. Grid and focus layout modes with click-to-focus. Control strip: mute, deafen, camera, screen share, disconnect. Frosted glass controls, speaking glow, staggered tile animations. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
SpeakingDetector polls AnalyserNodes at 60ms intervals. Participant tiles show green pulse glow when peer is speaking. Local mic also analysed for self-feedback. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove unused `wasm_bindgen::JsCast` import from participant_tile.rs - Remove stale `roles::*` re-export from components/mod.rs (server_settings module is not declared) - Prefix unused `roles` variable with `_` in app.rs - Add `#[allow(dead_code)]` to `RoleManager` component props (Leptos codegen artifact) - Add `#[allow(dead_code)]` to `UiState::show_server_settings` and `UiState::settings_tab` fields - Add `#[allow(clippy::too_many_arguments)]` to `render_tile` in call_page.rs - Replace `let _ = state.pc.remove_track(...)` with a bare call (let_unit_value) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The local user's camera/screen share stream was passed to VoiceManager for remote peers but never shown on their own participant tile. Add a local_video_stream signal inside CallPage, set it when camera or screen share starts, clear it on all stop paths, and pass it to the local tile's render_tile calls. Also add a track.onended listener for when the browser's "Stop sharing" button is used. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Two issues fixed: 1. set_src_object received &SendWrapper<MediaStream> instead of &MediaStream — explicit deref now ensures correct type 2. play() called before DOM element fully mounted — deferred to next microtask via set_timeout(Duration::ZERO) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…s, navigation 1. Screen share onended now calls stop_video_share on VoiceManager 2. create_offer sets making_offer flag to prevent onnegotiationneeded race 3. Audio elements tracked per-peer and removed from DOM on disconnect 4. Remove dead acquire_microphone methods 5. Text channel click closes call page 6. local_video_stream moved to global VoiceState (survives component remount) 7. voice_participants_map cleared on disconnect 8. Remote video defaults to object-fit:cover (not contain) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Two bugs: 1. ontrack handler silently dropped video tracks when ev.streams() was empty (common during renegotiation when SDP lacks a=msid). Now creates a MediaStream from the track as fallback. 2. onnegotiationneeded handler didn't guard against duplicate offers when making_offer was already true. Added early return check. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1. Rewrite SettingsPanel as tabbed (Profile/Server/Roles) with breadcrumb 2. Delete server_settings.rs (merged into settings.rs) 3. Seed voice_participants_map from client state on rejoin 4. Add local user to participants map on voice join Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The component renders .tab-btn but CSS targeted .settings-tab. Fixed selector, added accent glow on active underline, proper spacing, hover state, and consistent breadcrumb header styling. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Two tests launching different browser engines to verify P2P sync works across browser types. Both pass — confirms the relay handles cross-browser WebSocket connections correctly. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When the WebSocket connection to the relay drops (low battery, network switch, tab backgrounding), the network layer now automatically retries with exponential backoff (1s → 2s → 4s → ... → 30s cap). Backoff resets on successful node start and on peer connection. Commands queue during reconnect and are processed on the next successful connection. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When the WebSocket connection to the relay drops (low battery, network switch, tab backgrounding), the network layer now automatically retries with exponential backoff (1s → 2s → 4s → ... → 30s cap). Backoff resets on successful peer connection. Commands queue during reconnect and are processed on the next successful connection. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… cleanup, screen-share styling 1. Reset connected_subscribed on 'reconnecting' sentinel so topics are re-subscribed after network reconnect 2. Filter local peer from remote_participants to prevent double tile 3. Full cleanup of old voice channel before joining a new one 4. Default remote video to screen-share styling (object-fit: contain) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The grid rendering filter was fixed in the previous commit but the header count display still had +1. Removed since local is already in voice_participants_map. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…imer leak, dead code 1. close_all() now calls close_connection() per peer to remove <audio> elements 2. SpeakingDetector recreated after close_all() so speaking works on rejoin 3. set_interval timer cleaned up with on_cleanup to prevent stacking 4. Removed dead _handle_camera clone 5. Removed dead show_server_settings signal 6. Audio source nodes stored in shared map instead of leaked via mem::forget Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
intendednull
pushed a commit
that referenced
this pull request
Apr 5, 2026
Fixes from three-agent deep review (PR comments, research papers, plan analysis): **Critical: Equivocation detection** - Added ChainStatus::Forked variant for same-seq-different-hash - Added Equivocation Detection section in Section 4 with freeze/ propagate/alert response protocol - Referenced 2P-BFT-Log paper (arXiv:2307.08381) **Governance fixes** - Default vote threshold changed from Unanimous to Majority (PR #4) - Bootstrap sequence updated for majority default - Auto-apply mechanics clarified: no separate event, state change inferred during materialization (PR #5) - Vote structurally references proposal via EventHash field (PR #6) - KickMember/RevokeAdmin now clean up pending votes and re-evaluate all proposals (cascade thresholds) via cleanup_votes_and_reevaluate and reevaluate_all_proposals helpers - SetVoteThreshold re-evaluates all pending proposals - 5 new governance tests for vote cleanup and threshold cascading **Permission fixes** - GrantPermission/RevokePermission/RenameServer/SetServerDescription require is_admin check directly (not via ManageRoles permission) - SendMessages permission now enforced for Message/EditMessage/ DeleteMessage/Reaction events (was defined but never checked) - Permission enum has doc comments explaining each variant **Type fixes** - Channel.pinned_messages: HashSet<String> → HashSet<EventHash> - Event struct has explicit #[derive(Clone, Debug, Serialize, Deserialize)] - Archival tolerance design goal reworded for append-only model **Incremental apply safety** - Added soft-dep arrival re-materialization note: when a previously missing dep arrives and creates new causal edges, re-materialize from the DAG to maintain consistency **Appendix A: Known Issues and Future Work** - Hash-grinding on governance events - Optimized incremental apply after soft-dep arrival - SyncProvider permission evaluation - Versioning strategy - Dynamic channel model https://claude.ai/code/session_015u9tV4Abp1kKXvCVZ5iMfv
This was referenced Apr 24, 2026
intendednull
added a commit
that referenced
this pull request
Apr 26, 2026
lifecycle, fix IrohBlobStore spec drift, track 4 new follow-ups Round 2 review (two fresh agents) verified all 15 round-1 fixes land cleanly with no regressions, then surfaced 8 new findings (0 critical, 3 medium, 5 low) by widening scope to cross-component interactions, perf, and API surface. Fixed inline (trivial doc / spec): - Add an "Actor coordination signal" row to the spec decision tree + CLAUDE.md table covering tokio::sync::watch / oneshot / broadcast / Notify, with the explicit rule that tokio::sync::Mutex is forbidden for business state on the same terms as std/parking_lot Mutex. Closes the spec gap that left contributors without guidance on async channels. (round-2 #3) - Reconcile spec § 184 with the corrected IrohBlobStore comment (round-1 fixed the code, missed the spec). The blob store is not an iroh-callback boundary — it's an interim stub. The relay- status timestamp Mutex stays in the iroh boundary list. (round-2 #4) - Document the web `_event_loop` drop pattern in `crates/web/src/app.rs` so future readers see explicitly that the actor System is process- scoped on web (page reload tears everything down) and that any actor needing pre-close cleanup must route via `beforeunload`, not Drop. (round-2 #8) Tracked as new follow-ups in spec § Follow-up work: - F5. SearchActor head-of-line + rebuild-storm fix. Rebuild blocks Query in FIFO order; the rebuild Effect has no debounce. Fix is chunked-Rebuild + Debounce<Rebuild> wrap. (round-2 #1, #2 — Med) - F6. Browser-tier coverage for SearchIndexHandle consumers. The spawn_local + Effect path has no wasm-pack test. (round-2 #6) - F7. Sealed ClientSpawner to narrow the system() API surface, rather than exposing the full SystemHandle. (round-2 #7) - F8. Search-query debouncing-flicker fix via generation tag or Leptos Resource migration. (round-2 #5) Each follow-up has a "Trigger:" line naming the dedicated PR title. `just check` green: clippy zero warnings, 1003+ tests pass, WASM compile clean. Loop terminates here per the user's two-round cap; no Critical issues remain. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
intendednull
pushed a commit
that referenced
this pull request
Apr 28, 2026
Synthesises findings from three parallel review agents (technical, factual research, security audit). Major changes: Factual corrections: - NixOS 25.11 (not 25.05); pin nixpkgs by hash, not channel name. - Hetzner pricing updated for 2026-04-01 hike: CAX21 ARM €7.99/mo preferred over CPX21 AMD €11.99/mo (better $/perf, project already targets aarch64). Volume €0.57, Storage Box €3.20, Primary IP €0.50 (not Floating IP, which is €3.00 and not in Phase-1 budget). - Cost total €12.26 vs €20 cap. - Cloudflare WSS-proxy claim corrected (proxy works fine for WSS; real reasons to keep relay direct are 100s idle timeout + binary TCP/9090). Security additions: - Phase 0 reframed as compromise response: leaked password is permanently public; auth-log audit gates whether the relay key is migrated at all. - CI = root on prod stated honestly; forced-command is no defence against malicious closures. Required mitigations: manual approval gate, closure signing pinned in trusted-public-keys, action SHA pinning, scoped permissions. - agenix host-key threat model documented; rekey procedure; bootstrap chicken-and-egg sequence; sops-nix as upgrade path for high-value secrets needing online revocation. - LUKS encryption on Hetzner Volume. - restic in append-only mode; offline DR secrets (restic password, Storage Box key, LUKS recovery key) listed; backup-failure email path. - New "Security baseline" section: hardware-token 2FA on Hetzner + Cloudflare + GitHub; CAA records; OpenTofu state encryption; systemd hardening defaults (`systemd-analyze security` ≤ 3.0); break-glass key separate from CI key. Operational additions: - New "Host configuration baseline" section: time sync, swap, Nix GC, journald limits, sshd hardening, mount ordering, NixOS version-bump procedure. - Caddy footguns explicit: WASM MIME directive, Brotli requires xcaddy build, admin API disabled. Phase reordering: - Phase 1 now includes backups + a verified restore drill before cutover (closes regression vs goal #6). - Phase 2 cutover gates on the Phase-0 audit conclusion + atomicity invariant (one host holds the live key at any moment). New runbooks/appendices: - Appendix C: relay key migration runbook (stream through age, never write to laptop disk, integrity-check via SHA-256, shred source). Tooling research updates: - Cachix risk note: attic upstream stalled; celler is the actively-maintained fork. - nh and clan-core added to rejected alternatives with current rationale. - §10 commits to Caddy-on-VM as long-term answer (CDN via Cloudflare proxy toggle), drops the speculative "Phase 2 move to Pages" stepping-stone shortcut. Firewall fix: - Port 9091 dropped from edge firewall (loopback never traverses edge); rate limit added on TCP/9090; IPv6 rules stated. https://claude.ai/code/session_01PPGTBSaKd4c6iPCDmFNtoM
This was referenced Apr 28, 2026
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.
Summary
Video / Call Page
Network Resilience
Settings
Bug Fixes (11 issues found and fixed across 2 deep-review rounds)
Tests
Test plan
just checkpasses (fmt + clippy + test + WASM)🤖 Generated with Claude Code