Files
alkhttp/tasks/infra/review-002-fu-stream-error-coverage.md
T
glm-5.3-flash 5acc561eca docs(tasks): re-validate bracketed follow-up into 3 tasks (OAI-18 decision, streaming-coverage residue, doc-gate fix)
The bracketed planning task's five candidates, re-validated against
the post-bulk tree (0a932e5, all 23 bulk tasks done, 446/568 green):

1. OAI-18 -> review-002-fu-oai18-decision: still key-allowlist-only;
   bulk blockers (yaml/path-item) both landed. Task records the
   enforce-vs-scope-the-advert decision framework from review 002.
2. CON-08/CON-09 close() lever: deferred still (documented v1
   contracts unchanged, no consumer pressure) — not tasked.
3. Cross-crate: CF-001..004 all open in alkcall, no alkhttp-side task;
   PRJ-16 guard already documents its defense-in-depth re-scope
   disposition (no work when CF-004 lands).
4. Stale-comment sweep: mostly absorbed by the bulk (SRV-11 comment
   rewritten in-fix); residue = 3 cargo-doc warnings + WsTimeouts
   redundant Default -> review-002-fu-doc-warnings.
5. ADR-045 version audit: clean (1.4.0 + annotations + test pin).

Post-bulk coverage re-pass (95.89% regions, bulk's new code fully
covered: PRJ-16 guard, body cap, router reorder, batch cap, WS
knobs, OAI-11 node budget all exercised) surfaced one unanticipated
residue -> review-002-fu-stream-error-coverage (forward_stream
build-error arm never exercised on a Sub op; PEM read-failure arms;
over-cap poll_write; SSE split-CRLF edge; from_value structural
rejects; WsTimeouts Default).

Bracketed pass itself marked completed (planning consumed).
taskgraph: 69 valid, no cycles; 3 pending.
2026-08-31 05:40:46 +00:00

5.2 KiB

id, name, status, depends_on, scope, risk, impact, level, tags
id name status depends_on scope risk impact level tags
review-002-fu-stream-error-coverage Streaming error-arm coverage — forward_stream invalid input, PEM read-failure, over-cap poll_write mirror (post-bulk coverage gap) pending
narrow low component implementation
infra
review-002
follow-up
coverage

Description

Bracketed follow-up discovery from the post-bulk coverage re-pass (95.89% regions overall; the review-002 bulk's own new code verified fully covered — PRJ-16 guard, body cap, router reorder, batch cap, WS-13/18/19, the OAI-11 memo node-budget all exercised). The residue is small but one item matters more than its line count:

  • forward_stream build-request error arm (forward.rs:1085-1090): a Sub op invoked with an invalid input (undeclared key, non-scalar placeholder value) must produce exactly one error envelope from the stream — the streaming analog of the Once-path error handling. No test drives it: every SSE test (from_jsonschema integration_sse_subscription…, forward.rs's stream family) sends valid input. A regression returning an empty stream (silently swallowing the error) would be invisible — and an empty-200-subscribe is the worst failure shape for a subscriptions consumer.
  • PEM read-failure arms (http_client.rs CaBundleRead/ClientCertRead, sync + async): the parse-failure arms are covered (corrupt_ca_bundle_fails_ca_bundle_parse_with_path, garbage_client_cert_fails_… in client_tls.rs, landed in 6490d15), but the unreadable-file arms (nonexistent path, unreadable permissions) have no test on either build path. The error taxonomy half-documented at HttpClientBuildError's doc block (:214) is half-specified.
  • Over-cap poll_write rejection (byte_adapter.rs:789-798): WS-14's moved check rejects writes above PENDING_BUFFER_CAP with InvalidData before entry to the queue — the "at cap" boundary is tested (tungstenite_write_at_the_cap_is_accepted, 1158) and the framing-level cap-trip is tested both flavors (axum_framing_cap_trip…), but the single-call over-cap rejection itself (the WS-14 acceptance test's own criterion) never runs: no test writes PENDING_BUFFER_CAP + 1.
  • forward_stream SSE-parser residual edges: split-CRLF-across- chunks (the \r + "\n…" case), invalid-UTF8-line drop — the parser edges the bulk's stream arms work next to.
  • from_value structural rejections (openapi_spec.rs:391-398, 416-418): a non-object document, a missing-info, a non-object paths — none ever exercised (all other structural rejects are).
  • Connection-failure arms: protocol_handler accept-path stream_error_to_handler (adapter.rs:597-599) and the read-pump demux-gone break (byte_adapter.rs:374-381) — both are connection-failure semantics with zero direct coverage.
  • Dead-ish: impl Default for WsTimeouts (upgrade.rs:344-351) has zero callers (the extension is constructed explicitly in the one test that uses it) — delete or #[allow(dead_code)] with the reason.

Acceptance Criteria

  • Wire test: Sub op + undeclared key (or non-scalar placeholder value) → the subscriber receives exactly one INVALID_INPUT envelope and the stream ends (upstream receives zero requests)
  • Two PEM read-failure tests: SharedHttpClient::new with a nonexistent CA path → CaBundleRead carrying the path; reload with a nonexistent client-cert path → ClientCertRead
  • One over-cap poll_write test: write_all(PENDING_BUFFER_CAP+1)InvalidData error naming the cap (asserts the WS-14 moved check's rejection leg; the = cap test exists)
  • SSE parser edge tests: CRLF split across chunks (…\r ends chunk 1, \n… opens the next), invalid-UTF8 line dropped
  • from_value structural tests: non-object doc, missing-info, non-object pathsSchemaParse naming the missing member
  • WsTimeouts redundant Default deleted (or justified+allowed)
  • cargo llvm-cov --all-features: named arms no longer dark; cargo test --all-features, clippy, fmt pass

References

  • docs/reviews/002-post-remediation-review.md (Part G' test-gaps; post-bulk re-analysis finding list)
  • src/adapters/forward.rs:1085-1090 (stream build-error arm), src/client/http_client.rs:484-545 (read-failure arms), src/websocket/byte_adapter.rs:789-798 (over-cap poll_write)
  • tests/client_tls.rs (the PEM harness: parse-failure tests at :226-448 are the pattern to mirror for read-failures)
  • tasks/infra/review-002-cov-deployment-knobs.md (the pre-bulk coverage task these extend)
  • tasks/infra/review-002-cov13-dead-code.md (the dead-code convention for the WsTimeouts Default)

Notes

Tests-only + one deletion. The streaming-build-error test's load-bearing assertion is the single envelope then end semantics — mirror oversized_upstream_sse_line_terminates_with_one_internal_envelope's assert structure but trigger pre-send instead (invalid input, no responder needed for the reject case — wire it against a live-responder anyway if the harness makes it cheap; the zero-upstream-contact assert is the point). The spawn_responder-family harnesses in forward.rs/from_jsonschema.rs cover the seam.