H-385: address CDP spike review blockers

Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
2026-08-20 22:53:26 +08:00
co-authored by multica-agent
parent 8095392f7f
commit 1330585ccc
5 changed files with 150 additions and 98 deletions
+8 -7
View File
@@ -17,9 +17,9 @@ The spike starts only loopback listeners and uses generated, one-day self-signed
### Connection and schema
Clark is launched directly with `--remote-debugging-address=127.0.0.1`. The runner waits on `/json/version`, discovers the ready startup page through `/json/list`, connects to that target's `webSocketDebuggerUrl`, and navigates to a controlled loopback fixture. The fixture runs in a separate process and waits for a CDP trigger before generating test traffic. This avoids `clarkserve`'s current `0.0.0.0` default; a protected gateway and short-lived credentials remain required outside a local Spike.
Clark is launched directly with `--remote-debugging-address=127.0.0.1`. The runner waits on `/json/version`, discovers the startup page through `/json/list`, connects to its `webSocketDebuggerUrl`, and navigates to the already-listening loopback fixture before triggering test traffic. This avoids `clarkserve`'s current `0.0.0.0` default; a protected gateway and short-lived credentials remain required outside a local Spike.
Every JSONL line has `schema_version`, `session_id`, `target_id`, and `kind`. HTTP records use `request_id`; WebSocket records use the CDP `requestId` as `connection_id`. Kind-specific fields are nested under `request`, `response`, `headers`, `body`, or `error`. Query strings are removed, sensitive headers are replaced by `[REDACTED]`, WebSocket payloads are never persisted, and bodies over the configured limit are represented by `{state:"omitted",reason:"size_limit",bytes:N}`.
Every JSONL line has `schema_version`, `session_id`, `target_id`, and `kind`. HTTP records use `request_id`; WebSocket records use the CDP `requestId` as `connection_id`. Kind-specific fields are nested under `request`, `response`, `headers`, `body`, or `error`. Query strings are removed, sensitive headers are replaced by `[REDACTED]`, and WebSocket payloads are never persisted. Response bodies are safe by default: a fetched body is recorded as `{state:"fetched",storage:"omitted",reason:"default_body_policy",bytes:N}` with no content; oversize and unavailable bodies retain distinct structured states.
### Coverage and limits
@@ -29,17 +29,18 @@ Every JSONL line has `schema_version`, `session_id`, `target_id`, and `kind`. HT
| Failed HTTP request | Pass | Unused loopback port produces `loadingFailed`; error text retained. |
| HTTPS without MITM | Pass | Direct browser connection to local TLS fixture; no network intermediary. |
| WebSocket lifecycle and frames | Pass | Created, handshake, sent, received, and closed share one `connection_id`; payload omitted. |
| `getResponseBody` success | Pass | Called after `loadingFinished` for controlled responses. |
| Body size limit | Pass | 2 KiB fixture is not persisted with the 1 KiB default. |
| `getResponseBody` success | Pass | Called after `loadingFinished`; fetched bytes are recorded but content is omitted by default. |
| Sensitive response body | Pass | Random secret fixture is fetched; serialized JSONL is asserted not to contain its value. |
| Body size limit | Pass | 2 KiB fixture is reported as `size_limit` and not persisted with the 1 KiB default. |
| Body unavailable | Pass | Calling on the failed request returns the original CDP error as structured `cdp_error`. |
| Target close | Pass | Target connection closes; browser process remains alive. |
| Client disconnect | Pass | A second CDP client disconnects; browser process remains alive. |
| CDP disconnect/reconnect | Pass | Browser-side target close triggers the real socket `close` callback; the browser stays alive and a new target accepts a verified CDP command. |
| Cookie / Authorization / Set-Cookie | Pass | `Network.*ExtraInfo` values are redacted before JSONL serialization. |
| Cache-specific body availability | Not covered | Cache behavior varies by response/cache mode; retain optional-body semantics in M1. |
| Sustained high-rate WebSocket | Not covered | M0 stores metadata only; add frame/event caps before M1 load testing. |
| Multi-target/session isolation | Not covered | Explicitly M1 scope. |
| Top-level loopback navigation | Intermittent | This build can report `Inspector.detached: Render process gone` before the request reaches the fixture; rerun preserves the same local reproduction condition. |
| Startup `Page.navigate` | Intermittent | This build can report `Inspector.detached: Render process gone`; the exact startup failure is bounded and recorded. |
The resource numbers are a one-time `ps` snapshot of the browser process tree, not a benchmark. Repeat under the intended container limits before setting capacity targets.
The runner restarts Clark at most three times only for the observed `Inspector.detached` startup failure. Every failed attempt is retained in `attempt_failures`; other errors fail immediately.
The runner restarts Clark at most three times only from the local startup navigation/readiness block, and only after CDP reports the exact detached reason `Render process gone.`. Every failed attempt is retained in `attempt_failures`; a timeout without that reason and every post-startup error fail immediately with the original message.