Skip to content

feat(net): hyper backend transport (hyper_leaf + build + TokioTimer)#90

Merged
NotAProfDev merged 12 commits into
mainfrom
feat/net-http-hyper
Jul 5, 2026
Merged

feat(net): hyper backend transport (hyper_leaf + build + TokioTimer)#90
NotAProfDev merged 12 commits into
mainfrom
feat/net-http-hyper

Conversation

@NotAProfDev

@NotAProfDev NotAProfDev commented Jul 5, 2026

Copy link
Copy Markdown
Owner

Closes #89

PR A (transport) of the net-http hyper-backend slice — the runtime/TLS half deferred by the stack() assembly (#88). Design: docs/superpowers/specs/2026-07-05-net-http-hyper-backend-design.md; plan: docs/superpowers/plans/2026-07-05-net-http-hyper-backend-pr-a.md.

New crate oath-adapter-net-http-hyper — the first (and only) crate to own hyper/tokio/rustls (ADR-0030 §7's containment boundary). Behind the HttpClient seam, so a future net-http-reqwest is zero churn to the stack.

  • TokioTimer — the tokio-backed Timer (sleep + now both on tokio's clock, so it stays coherent under start_paused).
  • HyperLeaf / hyper_leaf(conn) / ConnConfig — a pooled hyper_util legacy::Client on a rustls HTTPS connector (aws-lc-rs provider, webpki-roots, ALPN h2+http/1.1, TCP_NODELAY). ConnConfig = { pool_max_idle_per_host, pool_idle_timeout, connect_timeout }; connect_timeout is a distinct, tighter bound than the per-attempt Timeout layer. The blanket impl (ADR-0030 §6) makes HyperLeaf: HttpClient once its body error is normalized.
  • HyperBody = MapErr<Incoming, fn(hyper::Error) -> HttpError> + the map_legacy_err/map_hyper_err anti-corruption mappers: connect-phase (DNS/TCP/TLS/handshake, incl. connect-timeout) → HttpError::Connection; everything else + mid-stream body errors → HttpError::Other. No Timeout mapping (that's the layer's job).
  • build<T, A, K>(…) = stack(hyper_leaf(conn), …) — a one-line delegation to the feat(net): stack() assembly + HttpConfig (Slice 2) #88 assembly, so the ordering invariants stay tested there. Return impl HttpClient + Clone + Send + Sync + 'static.

Response bodies stream (ResponseBody::streaming); leaf-side buffering (BufferMode) follows in PR B. Guarded (the concurrency permit) is attached by the RateLimit layer, not the leaf.

Tests (deterministic, no external network): plain-HTTP loopback round-trip; a real self-signed TLS handshake (rcgen cert + a client trusting exactly that cert — exercises aws-lc-rs/webpki in CI); connect-timeout → Connection; aborted connection → Other; deterministic paused-time TokioTimer test; and a build() smoke that round-trips through the full stack plus a missing-coverage → BuildError::UndeclaredKey boot-check.

just ci + just msrv green. One narrow, documented deny.toml license exception (webpki-roots → CDLA-Permissive-2.0, Mozilla's CA-bundle data license — first surfaced now that cargo-deny walks the hyper/rustls tree).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added a new Hyper-based HTTP transport backend with pooled connections, rustls/TLS (including ALPN), configurable connect timeout, and streaming response bodies.
    • Introduced a Tokio-backed timer and a new entry point to assemble the HTTP client stack.
  • Bug Fixes

    • Improved error normalization so failures are reported consistently, including during response streaming.
    • Added fail-closed behavior when rate-limit pacing coverage is incomplete.
  • Tests

    • Added end-to-end coverage for HTTP, TLS, timeout, and truncated-body error scenarios.
  • Documentation

    • Updated the changelog, design/ADR text, and added a delivery plan.
    • Updated license allowlist for a TLS roots dependency.

NotAProfDev and others added 11 commits July 5, 2026 10:15
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add tokio-rustls as a dev-dependency and drive a real aws-lc-rs/webpki
handshake in-crate: an rcgen self-signed cert served over a rustls
loopback listener, and a HyperLeaf whose connector trusts exactly that
cert (a custom RootCertStore, not webpki-roots).

Also records a narrowly-scoped deny.toml license exception for
webpki-roots' CDLA-Permissive-2.0 data license — the first time
cargo-deny fully exercised the hyper/rustls/aws-lc dependency tree.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 5, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: a91cec27-68aa-4567-8826-96b1321ea468

📥 Commits

Reviewing files that changed from the base of the PR and between a11fc05 and 7f9dc10.

📒 Files selected for processing (1)
  • crates/adapter/net/http/hyper/src/leaf.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/adapter/net/http/hyper/src/leaf.rs

📝 Walkthrough

Walkthrough

Adds a new oath-adapter-net-http-hyper crate implementing a Hyper-based HTTP transport backend: TokioTimer, ConnConfig/HyperLeaf/hyper_leaf pooled TLS connector, hyper-to-HttpError error mapping, and build() delegating to stack(). Includes workspace wiring, license exception, changelog, ADR amendment, and design/plan documentation.

Changes

Hyper backend transport crate

Layer / File(s) Summary
Workspace and crate manifest wiring
Cargo.toml, crates/adapter/net/http/hyper/Cargo.toml, deny.toml
Adds the new crate to the workspace, registers workspace dependencies for Hyper/TLS support, populates the crate manifest, and adds a webpki-roots license exception.
Crate surface and timer
crates/adapter/net/http/hyper/src/lib.rs, crates/adapter/net/http/hyper/src/timer.rs
Wires the crate modules and re-exports, and adds TokioTimer with a paused-time test.
Error mapping and HyperLeaf
crates/adapter/net/http/hyper/src/error.rs, crates/adapter/net/http/hyper/src/leaf.rs
Defines the error normalization helpers plus the pooled rustls-backed HyperLeaf, its request/response handling, and the transport tests.
build() construction surface
crates/adapter/net/http/hyper/src/build.rs
Adds build() over stack(hyper_leaf(conn), ...) and tests the happy path plus fail-closed rate-limit coverage.
Changelog, ADR, and design docs
CHANGELOG.md, docs/adr/..., docs/superpowers/plans/..., docs/superpowers/specs/...
Documents the new backend, records the TLS/connector configuration, and adds planning/design material for the slice.

Estimated code review effort: 3 (Moderate) | ~30 minutes

Possibly related PRs

  • NotAProfDev/oath#58: This PR builds on the shared Timer and HTTP service/stack abstractions used by the new Hyper backend.
  • NotAProfDev/oath#60: The new backend maps Hyper errors into the shared HttpError and returns responses through the existing HTTP contract.
  • NotAProfDev/oath#76: The build() tests exercise rate-scope pacing and fail-closed coverage behavior through the shared rate-limit stack.

Suggested labels: enhancement

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is Conventional Commits-formatted and clearly matches the hyper backend transport changes.
Linked Issues check ✅ Passed The crate, timer, pooled TLS leaf, error mapping, build delegation, and streaming-body behavior match #89.
Out of Scope Changes check ✅ Passed The docs, changelog, workspace wiring, and license exception support the hyper backend slice and do not appear unrelated.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ 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 feat/net-http-hyper

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
crates/adapter/net/http/hyper/src/error.rs (1)

24-30: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

No test coverage for map_hyper_err (mid-stream body errors).

The connect-timeout and aborted-connection tests in leaf.rs only exercise map_legacy_err (the initial-request path). The mid-stream body-error path handled by map_hyper_err — the other half of this file's contract — isn't exercised by any provided test.

Consider adding a test that has the server send a partial/chunked response then abruptly close the connection mid-body, verifying the streamed body yields HttpError::Other.

🤖 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 `@crates/adapter/net/http/hyper/src/error.rs` around lines 24 - 30, Add test
coverage for the mid-stream body-error path handled by map_hyper_err in
error.rs, since only map_legacy_err is currently exercised by the existing
leaf.rs tests. Extend the relevant HTTP client/server test setup in leaf.rs to
return a partial/chunked response and then abruptly close the connection while
the body is still streaming, and assert that reading the streamed body produces
HttpError::Other. Use the existing map_hyper_err and HttpError::other contract
as the target behavior.
🤖 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 `@crates/adapter/net/http/hyper/src/error.rs`:
- Around line 24-30: Add test coverage for the mid-stream body-error path
handled by map_hyper_err in error.rs, since only map_legacy_err is currently
exercised by the existing leaf.rs tests. Extend the relevant HTTP client/server
test setup in leaf.rs to return a partial/chunked response and then abruptly
close the connection while the body is still streaming, and assert that reading
the streamed body produces HttpError::Other. Use the existing map_hyper_err and
HttpError::other contract as the target behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 57456814-ab6c-4a0a-8d35-574c3e0fe75e

📥 Commits

Reviewing files that changed from the base of the PR and between d3911a6 and a11fc05.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock, !**/*.lock
📒 Files selected for processing (12)
  • CHANGELOG.md
  • Cargo.toml
  • crates/adapter/net/http/hyper/Cargo.toml
  • crates/adapter/net/http/hyper/src/build.rs
  • crates/adapter/net/http/hyper/src/error.rs
  • crates/adapter/net/http/hyper/src/leaf.rs
  • crates/adapter/net/http/hyper/src/lib.rs
  • crates/adapter/net/http/hyper/src/timer.rs
  • deny.toml
  • docs/adr/0030-http-transport-contract-wire-bytes-streaming-composition.md
  • docs/superpowers/plans/2026-07-05-net-http-hyper-backend-pr-a.md
  • docs/superpowers/specs/2026-07-05-net-http-hyper-backend-design.md

Addresses a CodeRabbit review nitpick on #90: the streaming body-error
mapper had no test; only the send-phase mapper (map_legacy_err) did.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@NotAProfDev NotAProfDev merged commit d789c07 into main Jul 5, 2026
5 checks passed
@NotAProfDev NotAProfDev deleted the feat/net-http-hyper branch July 5, 2026 16:32
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.

feat(net): hyper backend transport — hyper_leaf + build() + TokioTimer (hyper-backend slice, PR A)

1 participant