Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
43a101e
feat: add Status range predicates and delegate HttpExceptionFactory.i…
OmarAlJarrah Jul 4, 2026
6207a83
feat: add Response.isSuccessful and ResponseBody.string()/bytes()
OmarAlJarrah Jul 4, 2026
a51d5d1
feat: add Response.throwOnError(), HttpException.bodyAs(), and Respon…
OmarAlJarrah Jul 4, 2026
0ac3035
feat: add MediaType companion shortcuts and Serde-backed RequestBody …
OmarAlJarrah Jul 4, 2026
e1283ee
refactor!: overhaul Request.Builder with typed headers, URI url, defa…
OmarAlJarrah Jul 4, 2026
db870b5
fix: JacksonSerde.from(mapper) registers TristateModule by default
OmarAlJarrah Jul 4, 2026
c5b456d
feat: add jsonBody convenience to sdk-serde-jackson
OmarAlJarrah Jul 4, 2026
3a1482f
feat: builders for HttpRetryOptions/HttpInstrumentationOptions/HttpRe…
OmarAlJarrah Jul 4, 2026
275fc33
feat: HttpRetryOptions.fromConfiguration and default JDK connect timeout
OmarAlJarrah Jul 4, 2026
c54e8cf
fix: close body in HttpException.bodyAs, bound throwOnError buffering…
OmarAlJarrah Jul 5, 2026
7e66659
feat: ServiceLoader fallback resolves a single IoProvider without exp…
OmarAlJarrah Jul 5, 2026
8d54cee
feat: throwOnHttpError() step + async mirror on the stage pipeline
OmarAlJarrah Jul 5, 2026
c84cdc2
feat: appendStandardResilience() and HttpPipeline.standard(transport)…
OmarAlJarrah Jul 5, 2026
b9196cb
refactor!: adding a second pillar step fails fast instead of warn-and…
OmarAlJarrah Jul 5, 2026
c7a8cb5
refactor!: HttpPipeline/AsyncHttpPipeline implement the HttpClient SPIs
OmarAlJarrah Jul 5, 2026
f3830bf
feat: transports surface NetworkException for transport-level IO fail…
OmarAlJarrah Jul 5, 2026
eba18e1
feat: opt-in proxyFromEnvironment() on both transport builders
OmarAlJarrah Jul 5, 2026
e39ae69
feat: async CompletableFuture<Response>.handleWith(handler) terminal
OmarAlJarrah Jul 5, 2026
0b22857
fix: unify asAsync/toAsync cancellation on the interrupting path
OmarAlJarrah Jul 5, 2026
85f3307
refactor!: pagination strategies take SAM extractors, not Function1
OmarAlJarrah Jul 5, 2026
7db7482
feat: dep-free TypeRef<T> parametric decode + status-aware json handler
OmarAlJarrah Jul 5, 2026
fcbe657
refactor!: demote ETag/HttpRange to plain classes and add String cond…
OmarAlJarrah Jul 5, 2026
2f707ac
feat!: add RequestOptions carrier
OmarAlJarrah Jul 5, 2026
a3687e8
feat: transports honor per-call RequestOptions.timeout
OmarAlJarrah Jul 5, 2026
5f8e494
feat: pipeline threads RequestOptions; retry honors per-call maxRetries
OmarAlJarrah Jul 5, 2026
2d8df24
refactor!: rename the recovery pipeline stack to RecoveryChain/RetryR…
OmarAlJarrah Jul 5, 2026
d36b3dd
docs: installation section, ergonomic quick start, how-do-I snippets,…
OmarAlJarrah Jul 5, 2026
bc0b08d
chore: reconcile sdk-async-virtualthreads API snapshot for the async …
OmarAlJarrah Jul 5, 2026
3ef4028
fix: clamp negative per-call maxRetries to the configured default
OmarAlJarrah Jul 5, 2026
cfce016
refactor!: rename RecoveryChain pipeline properties to *Chain
OmarAlJarrah Jul 5, 2026
e752dbc
refactor!: remove redundant jsonBody in favor of RequestBody.create
OmarAlJarrah Jul 5, 2026
5d95eea
feat: add remaining Request verb factories and parametric Response.de…
OmarAlJarrah Jul 5, 2026
02bec41
fix: buffer the error body in jsonHandlerOrThrow to prevent use-after…
OmarAlJarrah Jul 5, 2026
08ae529
fix!: close correctness and plumbing gaps in the DX conveniences
OmarAlJarrah Jul 5, 2026
e0f1754
fix: harden response reading and request value types
OmarAlJarrah Jul 6, 2026
9f3852a
fix: correct Io provider ergonomics and redirect-options defensive copy
OmarAlJarrah Jul 6, 2026
8c018bf
fix: make generic decoding type-safe and error bodies replayable
OmarAlJarrah Jul 6, 2026
e07aa03
fix: correct retry classification and recovery re-evaluation
OmarAlJarrah Jul 6, 2026
6b30e5f
fix: make pipeline builders, close(), and auth replay safe
OmarAlJarrah Jul 6, 2026
129bc6b
fix: redact URL-valued headers and harden the async bridge SPI
OmarAlJarrah Jul 6, 2026
49dbe21
fix: unify pagination extractors, thread options, and plug page leaks
OmarAlJarrah Jul 6, 2026
731388e
fix: keep the Okio ServiceLoader shim under R8 and harden Jackson dec…
OmarAlJarrah Jul 6, 2026
0ceb9d8
docs: correct pagination snippets, stage diagram, and renamed-type re…
OmarAlJarrah Jul 6, 2026
c8f8c77
fix: transport cancellation, Content-Type parity, and adapter options
OmarAlJarrah Jul 6, 2026
cada299
chore: regenerate API snapshots and satisfy quality gates
OmarAlJarrah Jul 6, 2026
ada301b
test: lock in the review-fix behaviors with regression tests
OmarAlJarrah Jul 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions .superpowers/sdd/progress.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# DX Improvements — Progress Ledger

Branch: worktree-dx-improvements | Base: b015fd3
Plan: docs/superpowers/plans/2026-07-03-dx-improvements.md

## Work units (file-cohesive)
- [x] U1 Response family (T1 Status preds, T2 isSuccessful+string/bytes, T3 throwOnError+bodyAs, T9 deserialize)
- [x] U2 Request family + MediaType (T4, T5, T6, T7, T8-core)
- [x] U3 Jackson serde (T10 Tristate fix, T8 jsonBody)
- [x] U5 *Options builders + config + JDK timeout (T12, T13)
- [x] U6 ServiceLoader IoProvider (T15)
- [x] Pipeline steps (T16 throwOnHttpError, T17 standard, T22 pillar-fail, T25 HttpPipeline:HttpClient)
- [ ] U8 Async + transports (T14 NetworkException, T18 handleWith, T19 cancel, T23 proxyEnv)
- [x] U9 Serde TypeRef + pagination SAM (T20, T21)
- [x] U10 Value-class demotion (T24 ETag/HttpRange/RequestConditions)
- [x] U11 Per-request RequestOptions (T26)
- [x] U12 Recovery-stack rename (T27, T28)
- [x] U4 Docs (T11) — after ServiceLoader so samples are final
- [ ] FINAL apiDump + full gated build + final review + PR

## Completed
- U1: complete (commits 43a101e..a51d5d1, gates green: 2002 tests, detekt, apiCheck, ktlint)
- U2: complete (commits 0ac3035..e1283ee, 36 tests, gates green)
- U3: complete (commits db870b5..c5b456d, 38 tests, gates green)

## Wave-1 review findings (from wave1-review.md)
- FIX (Important) bodyAs: close body in finally (ResponseExtensions.kt ~60-68)
- FIX (Important) throwOnError: bound buffered body (cap ~1 MiB) + doc (ResponseExtensions.kt ~34-42)
- FIX (Important) T3 wording: "replayable" -> "buffered in memory, readable after throw"
- FIX (Minor) bodyAs: debug-log the swallowed exception (ref e)
- FIX (Minor) delete(): clear stale body for consistency with get()/head()
- DEFER to final: #6 jsonBody redundancy (plan-mandated, adjudicate), #8 create(value) nullability doc
- U5: complete (commits 3a1482f..275fc33, 11 tests, gates green)
- Wave-1 fixes: complete (commit c54e8cf; leak, OOM-cap, wording, log, delete-body — tests green)
- U6: complete (commit 7e66659, ServiceLoader fallback, full sdk-core suite green)
- U7a: complete (commits 8d54cee..c84cdc2; added Stage PRE_REDIRECT(50); NOTE: subagent briefly committed on MAIN then reverted it to b015fd3 — main verified clean, user kuri changes untouched)
- U7b: complete (commits b9196cb..c7a8cb5, pillar hard-fail + HttpPipeline:HttpClient; cwd guard held, main clean)
- U8a: complete (commits f3830bf..eba18e1, transports NetworkException + proxyFromEnvironment, 13 suites green)
- U8b: complete (commits e39ae69..0b22857, handleWith + unified cancel; 2nd main-slip reverted cleanly, main verified intact)
- U9: complete (commits 85f3307..7db7482, SAM extractors + TypeRef, gates green, path guard held)

## Final-review items (defer)
- jsonHandlerOrThrow leaves LIVE error body on throw; throwOnError BUFFERS — reconcile for consistency (buffer both, bounded 1 MiB)
- jsonBody(serde,value) redundancy vs RequestBody.create(value,serde) — decide keep/drop
- docs/pipelines.md stale "replace emits warning" line (U7b) — fix in U4 docs
- run aggregate koverVerify (80% floor) at finalization
- U10: complete (commit fcbe657, ETag/HttpRange demoted + String overloads, de-mangling proven)
- U11: complete (commits 2f707ac..5f8e494, RequestOptions timeout+maxRetries wired, full gate green)
- final-review: U11 negative per-call maxRetries used as-is (no clamp) — decide if OK; PipelineNext.options now public
- U12: complete (commit 2d8df24, recovery stack -> RecoveryChain/RetryRecovery/ThrowOnHttpErrorRecovery, grep-clean, gates green)
- U4: complete (commit d36b3dd, README+samples, sdk-example test+run green)
- ALL 13 UNITS COMPLETE — starting finalization

## Finalization
- apiDump reconciled (virtualthreads straggler committed)
- FULL GATED BUILD: BUILD SUCCESSFUL — all module tests, detekt, ktlint, allWarningsAsErrors, apiCheck, R8 shrink guard, kover 80% floor ALL GREEN
- Final whole-branch review: running
- TODO: triage final review + deferred items -> one fix wave -> PR
- Final review fix wave: complete (02bec41,5d95eea,e752dbc,cfce016,3ef4028) — all 5 findings fixed, gate green
- NOTE: intermediate commit cfce016 api-stale (same-file entanglement); branch HEAD green
- Running final full gated build before push

## DONE
- Final full gated build: BUILD SUCCESSFUL (kover+R8+all gates)
- Pushed worktree-dx-improvements -> origin/dx-improvements
- PR #208 opened (base main), clean (no styleguide/.superpowers/plan), CI build running
- 33 commits, +6277/-761 across 124 files
16 changes: 10 additions & 6 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,10 @@ modules), and concrete I/O plugs in via `IoProvider`.
Layered, from the bottom up:

1. **`io/` contracts** — `Source`/`Sink`, `BufferedSource`/`BufferedSink`, `Buffer`, `TeeSink`. All
interfaces; no concrete I/O in `sdk-core`. `Io.installProvider(provider)` wires the single `IoProvider`
seam once at startup; a missing provider throws `IllegalStateException` with the install instruction.
interfaces; no concrete I/O in `sdk-core`. `Io.provider` resolves the single `IoProvider` seam: an
explicit `Io.installProvider(provider)` always wins, otherwise it auto-discovers one on the classpath
via `ServiceLoader` (so the Okio adapter registers itself). Zero or multiple providers with no explicit
install throw `IllegalStateException` with an actionable message.
2. **HTTP models** — immutable `Request`/`Response`/`Headers`/`MediaType` etc., private constructor +
`Builder` + `newBuilder()`. `RequestBody.isReplayable()`/`toReplayable()`; `FileRequestBody` lets
transports dispatch `FileChannel.transferTo`.
Expand All @@ -86,8 +88,8 @@ Layered, from the bottom up:
- `http.pipeline` — stage-based runtime: `HttpPipelineBuilder` + `HttpStep` ordered by `Stage` with
pillar stages (exactly one REDIRECT / RETRY / AUTH / LOGGING / SERDE step per pipeline), plus the
async mirror (`AsyncHttpPipeline`, `AsyncHttpStep`) and sync→async bridges.
- `pipeline` — recovery-aware primitives: `RequestPipeline`, `ResponsePipeline`, `ExecutionPipeline`,
`ResponseOutcome`, with steps like `RetryStep` (backoff + `Retry-After`), `IdempotencyKeyStep`,
- `pipeline` — recovery-aware primitives: `RequestRecoveryChain`, `ResponseRecoveryChain`, `RecoveryChain`,
`ResponseOutcome`, with steps like `RetryRecovery` (backoff + `Retry-After`), `IdempotencyKeyStep`,
`ClientIdentityStep`.
See `docs/pipelines.md` before touching either.
6. **Transports** — `sdk-transport-okhttp` (Java 8) and `sdk-transport-jdkhttp` (Java 11). Both implement
Expand Down Expand Up @@ -134,8 +136,10 @@ Layered, from the bottom up:
- **Public API changes fail `apiCheck`.** Any visible signature change needs `./gradlew apiDump` and the
regenerated `api/*.api` files committed alongside the change. Never run `apiDump` to silence an
*unintentional* break.
- **`Io.installProvider(...)` must run before any code touches `Io.provider`.** Tests install
`OkioIoProvider` in `@BeforeTest`; production installs in the application startup path.
- **`Io.provider` resolves a provider via `ServiceLoader` when none was explicitly installed**, so a
single adapter on the classpath (e.g. `sdk-io-okio3`) needs no bootstrap call. An explicit
`Io.installProvider(...)` still overrides auto-discovery and always wins; tests install `OkioIoProvider`
in `@BeforeTest` to stay deterministic. Zero or multiple providers with no explicit install fail loudly.
- **Coverage floor is aggregate 80% line coverage.** The `minBound(80)` rule lives on the root-aggregate
`:koverVerify`, which the root `check` task depends on, so a plain `./gradlew build` enforces it. New
under-tested code can trip the gate even when its own module builds clean — check `koverHtmlReport` to see
Expand Down
Loading
Loading