Skip to content

fix(network): say how long capture has been running when the network log is empty - #660

Open
filip131311 wants to merge 3 commits into
mainfrom
filip/network-capture-window
Open

fix(network): say how long capture has been running when the network log is empty#660
filip131311 wants to merge 3 commits into
mainfrom
filip/network-capture-window

Conversation

@filip131311

Copy link
Copy Markdown
Collaborator

Fixes #633.

The problem

view-network-logs installs the fetch() interceptor the first time it runs, so traffic the app issued before that is never recorded. The empty result then said:

No network traffic captured. Make sure the app is running and making HTTP requests. Network interception is active — it captures fetch() calls.

"Network interception is active" describes a state the call itself had just created. An agent reads that as a verdict — the app made no requests — which is a wrong answer, not a missing feature.

Reproduced live

iPhone 17 Pro sim + RN app. Connected the debugger, then fired three fetches before touching any network tool:

evaluate → {"fired":3,"interceptorInstalledBefore":false}
evaluate → {"completed":["https://example.com/ -> 200", "... -> 200", "... -> 200"],
            "interceptorInstalled":false}
view-network-logs → "No network traffic captured. … Network interception is active …"
evaluate → {"interceptorInstalledNow":true}     ← flipped by the call that printed the message

Three completed HTTP 200s, reported as nothing.

There is a second path to the same wrong answer, not in the report: debugger-reload-metro (or any JS reload) destroys the interceptor and every captured entry__argent_network_log ceases to exist — after which the same misleading message describes data the tool previously held.

The fix

The interceptor stamps when it started; the read script returns the elapsed window, computed app-side from two app-side clock reads, so no host/device clock comparison is involved.

The empty result quotes that number instead of picking a threshold:

  • recording for 2 ms → you have learned nothing yet
  • recording for 14 min → this is a real empty result

Same sentence, no branch, no cliff where an agent's conclusion flips.

Three states the old message could not distinguish are now separate:

State Why it matters
window just opened the reported bug
window of unknown length an interceptor left by an earlier session has no timestamp — defaulting it to "now" would report 0 ms forever, reintroducing the same lie
nothing recording at all injection is swallowed as non-fatal in two places, so a runtime where it failed was reporting "interception is active"

That last case is why the interceptorInstalled check moved up to the count read.

Also folded in, because they make an empty log ambiguous in exactly the same way:

  • Only fetch() is patched. An app using XMLHttpRequest directly — including axios, whose RN adapter is XHR-based — shows nothing at all. Now stated in the message and the description.
  • Metro's own traffic is filtered out, undocumented until now. The match is literal on localhost/127.0.0.1 at the Metro port, so a device reaching Metro over a LAN IP still shows it. Documented rather than widened — widening would hide a user's own API served on the same port.
  • network-inspector-connect does not exist. The "interceptor not installed" path told agents to call a tool that appears nowhere else in the tree. That path is reachable only when the runtime reloads between the count read and the page read, so it now says that.

Verified on the device, all four branches

Scenario Output
issue's exact repro (3 × 200 before capture) fetch() interception has been recording for 2 ms — …
12 s window, genuinely quiet … recording for 12.0 s — …
stale interceptor from the pre-fix build (installedAt: null, hit for real) … start time is unknown (it was installed by an earlier session) …
log removed, injection skipped … fetch() interception is NOT installed …
traffic after arming === NETWORK LOGS (page 1/1, 1 total) === — unchanged, Metro request still filtered

Scope

Deliberately not included: arming capture at debugger-connect. It is a silent behaviour change for every debugger user (patches globalThis.fetch, pins up to 2000 response bodies in the app heap) and it does not close the hole — traffic before connect, and after any reload, is still lost, so honest messaging is required either way. Worth its own PR; I'll file a follow-up.

Checks

  • 3096 tests pass (298 files); 10 new, of which 7 fail against the pre-fix source — the 3 that pass on both are invariance checks
  • new tests hit execute directly, because the existing integration harness synthesizes read-script payloads in TypeScript and so cannot exercise this logic
  • SpiderShield average 9.10 (threshold 9.0), view-network-logs 10.0; description kept a static literal, since extract-tools.mjs rejects interpolation
  • skills gate 10.0; prettier, eslint, both typechecks clean

…mpty

view-network-logs installs the fetch() interceptor the first time it runs, so
traffic the app issued before that is never recorded. The empty result said
'Network interception is active', which reads as a verdict — the app made no
requests — when it actually described a state the call had just created.

The interceptor now stamps when it started and the read script returns the
elapsed window, computed app-side so no host/device clock comparison is
involved. The empty result quotes that number instead of picking a threshold:
'recording for 2 ms' reads as 'you have learned nothing yet', 'recording for
14 min' reads as a real empty result, and the same sentence covers both.

Three things the log could not previously distinguish are now separate: a
window that just opened, a window of unknown length (an interceptor left by an
earlier session has no timestamp — defaulting that to 'now' would report 0 ms
forever), and nothing recording at all. That last case is why the check moved
to the count read: injection is swallowed as non-fatal in two places, so a
runtime where it failed was reporting 'interception is active'.

Also names the two silent exclusions that make an empty log ambiguous — only
fetch() is patched, so an XHR-based client such as axios shows nothing, and
Metro's own traffic is filtered out — and replaces the suggestion to reconnect
with 'network-inspector-connect', a tool that does not exist.
The test-ui-flow skill told agents to drive the app and then verify with
view-network-logs, which is exactly the order that loses the requests.
An npm version difference added 'peer' markers during a local install; this
change touches no dependencies.
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.

view-network-logs: interception only starts at the first call, so earlier traffic is lost and the empty result reads as "the app made no requests"

1 participant