Skip to content

@moq/watch: source network stats from the connection, not navigator#1386

Merged
kixelated merged 4 commits into
mainfrom
claude/remove-hardcoded-watch-stats-AfO6H
May 7, 2026
Merged

@moq/watch: source network stats from the connection, not navigator#1386
kixelated merged 4 commits into
mainfrom
claude/remove-hardcoded-watch-stats-AfO6H

Conversation

@kixelated
Copy link
Copy Markdown
Collaborator

The stats panel's network row was driven by navigator.connection, which
on most browsers reports a coarse effectiveType ("4G") and synthetic
downlink/rtt values that have nothing to do with the actual MoQ session.
Replace it with the bandwidth and RTT signals that the connection
already exposes (PROBE for recv bandwidth and RTT, QUIC stats for send
bandwidth), plumbed through MultiBackend.network.

The stats panel's network row was driven by navigator.connection, which
on most browsers reports a coarse effectiveType ("4G") and synthetic
downlink/rtt values that have nothing to do with the actual MoQ session.
Replace it with the bandwidth and RTT signals that the connection
already exposes (PROBE for recv bandwidth and RTT, QUIC stats for send
bandwidth), plumbed through MultiBackend.network.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 6, 2026

Review Change Stack

Walkthrough

Adds a public Connection interface and a ProviderProps.connection Peekable, passes connection from the top-level element through Stats -> StatsPanel -> StatsItem, refactors NetworkProvider to poll the provided connection for recv/send bandwidth and RTT (with new formatting helpers), and replaces RTT-only wiring in MultiBackend/Sync with the established connection signal so jitter is computed from conn.rtt.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely summarizes the main change: replacing navigator-based network stats with connection-owned stats in the watch module.
Description check ✅ Passed The description is directly related to the changeset, explaining the motivation and technical approach for sourcing network stats from the connection instead of navigator.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/remove-hardcoded-watch-stats-AfO6H
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch claude/remove-hardcoded-watch-stats-AfO6H

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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 `@js/ui-core/src/stats/providers/network.ts`:
- Around line 21-24: Replace the raw window.setInterval usage in NetworkProvider
with the inherited signals Effect: instead of assigning this.updateInterval =
window.setInterval(...), call
this.signals.interval(NetworkProvider.POLLING_INTERVAL_MS,
this.updateDisplayData.bind(this)) so the subscription is managed by
BaseProvider's signals; remove the manual clearInterval call and any
this.updateInterval bookkeeping in the cleanup() method since signals.interval()
handles teardown automatically.
🪄 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: bdb78bd9-15ac-4f5f-9c6d-022264004091

📥 Commits

Reviewing files that changed from the base of the PR and between 71d90d3 and 80d22fc.

📒 Files selected for processing (8)
  • js/ui-core/src/stats/components/StatsItem.tsx
  • js/ui-core/src/stats/components/StatsPanel.tsx
  • js/ui-core/src/stats/index.tsx
  • js/ui-core/src/stats/providers/network.ts
  • js/ui-core/src/stats/types.ts
  • js/watch/src/backend.ts
  • js/watch/src/element.ts
  • js/watch/src/ui/element.tsx

Comment thread js/ui-core/src/stats/providers/network.ts Outdated
claude and others added 3 commits May 7, 2026 09:10
Lets BaseProvider's Effect manage the polling timer instead of tracking
the interval id by hand.
… network props

Rather than flattening connection.rtt/recvBandwidth/sendBandwidth into
separate Signals on MoqWatch and threading them through MultiBackendProps
and a NetworkBackend interface, expose the established connection signal
directly:

- Stats UI reads from connection.established (the only consumer of
  recv/send bandwidth) and pulls the inner signals on demand.
- Sync takes the established connection signal and reads RTT internally
  for "real-time" jitter computation.
- MultiBackend no longer has rtt or NetworkBackend in its API.

Network metrics aren't a backend concern; the backend just consumes the
connection that already owns them.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
js/watch/src/sync.ts (2)

90-92: ⚡ Quick win

Extract the RTT multiplier into a named constant.

This avoids an inline magic number in core jitter math.

Proposed update
 const MIN_JITTER = 20 as Time.Milli;
 const FALLBACK_JITTER = 100 as Time.Milli;
+const RTT_RETRANSMIT_MULTIPLIER = 1.25;
@@
-			const jitter = Math.max(MIN_JITTER, this.#minRtt * 1.25) as Time.Milli;
+			const jitter = Math.max(MIN_JITTER, this.#minRtt * RTT_RETRANSMIT_MULTIPLIER) as Time.Milli;
As per coding guidelines, "Avoid using magic numbers; use named constants instead".
🤖 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 `@js/watch/src/sync.ts` around lines 90 - 92, Replace the inline multiplier
1.25 in the jitter calculation with a named constant to avoid the magic number:
introduce a constant (e.g., RTT_MULTIPLIER = 1.25) near the top of the module or
inside the class, then use it in the expression that computes jitter (currently
using MIN_JITTER and this.#minRtt) so the line becomes Math.max(MIN_JITTER,
this.#minRtt * RTT_MULTIPLIER) and keep the rest (this.jitter.set(jitter))
unchanged.

13-13: ⚡ Quick win

Add a doc comment for the new public SyncProps.connection field.

This keeps the public API self-describing at the type level.

Proposed update
 export interface SyncProps {
 	latency?: Latency | Signal<Latency>;
+	/** Established connection signal used to read RTT in "real-time" mode. */
 	connection?: Signal<Moq.Connection.Established | undefined>;
 	audio?: Time.Milli | Signal<Time.Milli | undefined>;
 	video?: Time.Milli | Signal<Time.Milli | undefined>;
 }
As per coding guidelines, "Document public APIs with clear docstrings or comments".
🤖 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 `@js/watch/src/sync.ts` at line 13, Add a concise doc comment above the public
SyncProps.connection field describing its purpose and semantics: explain that
connection is an optional Signal that holds a Moq.Connection.Established or
undefined, when it will be set/cleared, and how consumers should use it (e.g.,
subscribe/react to changes or check for undefined before use); reference the
exact field name SyncProps.connection and its type
Signal<Moq.Connection.Established | undefined> so the public API is
self-describing.
🤖 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.

Nitpick comments:
In `@js/watch/src/sync.ts`:
- Around line 90-92: Replace the inline multiplier 1.25 in the jitter
calculation with a named constant to avoid the magic number: introduce a
constant (e.g., RTT_MULTIPLIER = 1.25) near the top of the module or inside the
class, then use it in the expression that computes jitter (currently using
MIN_JITTER and this.#minRtt) so the line becomes Math.max(MIN_JITTER,
this.#minRtt * RTT_MULTIPLIER) and keep the rest (this.jitter.set(jitter))
unchanged.
- Line 13: Add a concise doc comment above the public SyncProps.connection field
describing its purpose and semantics: explain that connection is an optional
Signal that holds a Moq.Connection.Established or undefined, when it will be
set/cleared, and how consumers should use it (e.g., subscribe/react to changes
or check for undefined before use); reference the exact field name
SyncProps.connection and its type Signal<Moq.Connection.Established | undefined>
so the public API is self-describing.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6452bcfd-27fb-40a9-a461-dfbc8a88356b

📥 Commits

Reviewing files that changed from the base of the PR and between 246bac4 and 1976c83.

📒 Files selected for processing (10)
  • js/moq-boy/src/index.ts
  • js/ui-core/src/stats/components/StatsItem.tsx
  • js/ui-core/src/stats/components/StatsPanel.tsx
  • js/ui-core/src/stats/index.tsx
  • js/ui-core/src/stats/providers/network.ts
  • js/ui-core/src/stats/types.ts
  • js/watch/src/backend.ts
  • js/watch/src/element.ts
  • js/watch/src/sync.ts
  • js/watch/src/ui/element.tsx
🚧 Files skipped from review as they are similar to previous changes (7)
  • js/ui-core/src/stats/components/StatsPanel.tsx
  • js/watch/src/ui/element.tsx
  • js/ui-core/src/stats/index.tsx
  • js/ui-core/src/stats/components/StatsItem.tsx
  • js/ui-core/src/stats/providers/network.ts
  • js/ui-core/src/stats/types.ts
  • js/watch/src/element.ts

@kixelated kixelated enabled auto-merge (squash) May 7, 2026 18:12
@kixelated kixelated merged commit bdda6bd into main May 7, 2026
1 check passed
@kixelated kixelated deleted the claude/remove-hardcoded-watch-stats-AfO6H branch May 7, 2026 18:17
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.

2 participants