Reviewer: GPT-6-Astra via Codex, on Paul's instruction.
VERDICT: CHANGES-REQUIRED — feat/k1-typed-errors-transport @ d9dac7226ade1f3743f4742ed7f4021cd0918ac3
Read the whole diff against origin/main 2a5d07b and the binding spec at 6049830. Only finding 1 blocks approval.
- P2 / blocking — Sources/RastrilloApple/NativeClientError.swift:87 (also Tests/RastrilloAppleTests/TypedErrorTests.swift:76): cancelled URLSession operations deliberately leak raw URLError(.cancelled). This violates the requested no-raw-URLError boundary and gives real HTTP a different cancellation shape from ScriptedTransport.hang. A scratch-only real NativeHTTP probe cancelled its calling task immediately before responseDetails; it failed both assertions with NSURLErrorDomain -999, rather than CancellationError. Returning the raw error is not necessary to preserve Task.isCancelled. Fix: normalize URLSession's .cancelled to CancellationError, leave existing CancellationError untouched, and replace the test that currently pins raw cancellation with real-operation coverage. Do not map cancellation to transient/offline or emit an offline outcome for it.
- P3 / nonblocking — Sources/RastrilloTestSupport/ScriptedTransport.swift:124: the fake's String.split(separator: "\n") is not faithful to NativeHTTP's byte-level line parser. Changing the new stream test's body to CRLF yields one entire event string instead of three lines; the real transport's existing CRLF test passes. The fake also emits an unterminated final line that the real parser drops. This can mislead future consumer stream tests. Fix: share/use equivalent line parsing, with CRLF, bare CR, and unterminated-line parity tests.
Rulings on the four declared departures:
- APPROVE the additional .transport(URLError.Code) with transient retry class: it represents TLS/non-offline failures without falsely reporting lost connectivity. REJECT the attached decision to keep raw cancellation; fix finding 1.
- APPROVE Equatable and nesting RetryClass: no semantic change or platform dependency, and useful exact assertions.
- APPROVE the generic rateLimited message: the case intentionally represents both 429 and 503; it preserves the unconfirmed-write warning without inventing a status.
- APPROVE the per-call responder: the Docs adopter demonstrates the need to route concurrent stream/save calls without FIFO ordering assumptions. It is Sendable, recording is locked, and a declined response fails explicitly. It does not require a new production abstraction.
Verification performed by this reviewer:
- make ci PASSED at d9dac72: 44 Swift tests, regenerated companion macOS and iOS simulator builds, server go test -race, 11 updater tool tests and the relocated bundle test.
- Mutation: mapping 401/303 to .server made HTTPTests.testStatusesAreTypedAndObserved and ScriptedTransportTests.testEndedSession fail with 6 assertions. Restored implementation: both passed.
- Mutated the new scripted stream fixture to CRLF: its line assertion went red for finding 2. Restored test: passed.
- Cancellation probe above failed on unchanged production code, then was removed.
- Docs K1's full native gate passed; Calendar K0's Swift tests and regenerated simulator build passed. All edits/probes were in detached /tmp worktrees and were reverted/removed; build outputs are being deleted as the review completes.
Hub CI at this exact head fails before compilation because Sparkle's archive cannot be validated: executable unzip is missing. Companion/server/bundle were skipped, not failed tests. This is an infrastructure failure, not evidence of a code failure. The author reports a Linux runner and no macOS runner; I could not independently audit runner inventory because amadan ci offer list was refused with "an agent cannot manage agents". I did not bypass that refusal. The local macOS gate is verified; the absence of any macOS runner is not independently verified.