The ~/bin/quak that make install builds runs under bun. Bun's fetch rejects with a plain Error that has no cause and a code of bun's own, so isRetryable found neither Node's TypeError nor a known errno. Running the built binary against listeners on 127.0.0.1 and a name under .invalid gave:
refused connection, or failed TLS handshake: ConnectionRefused
name that does not resolve: ConnectionRefused or FailedToOpenSocket
reset, or closed before the response ended: ECONNRESET
deadline: TimeoutError
The two new codes join TRANSPORT_CODES in src/retry.ts, so they are retried, and classify in src/backup.ts calls them transient. They are not in CONNECT_CODES, so a POST or PUT is not replayed on them. When a connection bun kept open from an earlier request closes before any answer, bun sends the request again on a new connection, and if that one fails it gives one of these codes although the server may already have the request.
classify also records an error named TimeoutError as transient, as isRetryable retries it. quak's download deadline aborts with one whose message says only that the download stalled, so a stalled download was recorded as unknown.
Not visible in the diff: the API origin is fixed, so the binary reached the local listeners only through HTTPS_PROXY.
Unverified: that bun gives FailedToOpenSocket when it resends a request comes from reading bun's behaviour, not from a run.
Not changed: a certificate bun rejects (DEPTH_ZERO_SELF_SIGNED_CERT) is not retried, and the README says so.
Model: opus-5-5
For https://git.eeqj.de/sneak/quak/issues/206.
The `~/bin/quak` that `make install` builds runs under bun. Bun's `fetch` rejects with a plain `Error` that has no `cause` and a code of bun's own, so `isRetryable` found neither Node's `TypeError` nor a known errno. Running the built binary against listeners on 127.0.0.1 and a name under `.invalid` gave:
- refused connection, or failed TLS handshake: `ConnectionRefused`
- name that does not resolve: `ConnectionRefused` or `FailedToOpenSocket`
- reset, or closed before the response ended: `ECONNRESET`
- deadline: `TimeoutError`
The two new codes join `TRANSPORT_CODES` in `src/retry.ts`, so they are retried, and `classify` in `src/backup.ts` calls them transient. They are not in `CONNECT_CODES`, so a `POST` or `PUT` is not replayed on them. When a connection bun kept open from an earlier request closes before any answer, bun sends the request again on a new connection, and if that one fails it gives one of these codes although the server may already have the request.
`classify` also records an error named `TimeoutError` as transient, as `isRetryable` retries it. quak's download deadline aborts with one whose message says only that the download stalled, so a stalled download was recorded as `unknown`.
Not visible in the diff: the API origin is fixed, so the binary reached the local listeners only through `HTTPS_PROXY`.
Unverified: that bun gives `FailedToOpenSocket` when it resends a request comes from reading bun's behaviour, not from a run.
Not changed: a certificate bun rejects (`DEPTH_ZERO_SELF_SIGNED_CERT`) is not retried, and the README says so.
Model: opus-5-5
Bun gives ConnectionRefused after the server already has the request, so this PR lets a POST or PUT be sent twice (CONNECT_CODES and isSafeToReplay in src/retry.ts). Bun may send a request on a connection it kept open from an earlier request. If that connection closes before any answer, bun sends the request again on a new connection, and when that new connection is refused, fetch rejects with ConnectionRefused. Under bun 1.3.13, quak's own postJSON sent /users/two-factor/verify to a local server twice this way: once on the reused connection, and once more when it was replayed. Bun reports FailedToOpenSocket from that same new connection, so it carries the same doubt. That one I read in bun's behaviour and did not reproduce. Acceptable: neither bun code is in CONNECT_CODES. Both stay in TRANSPORT_CODES, so they are still retried for idempotent calls and recorded as transient. The tests in test/retry/retry.test.ts expect isSafeToReplay to be false for both. The comments on CONNECT_CODES and isSafeToReplay, the README paragraph on replaying requests and the TODO.md entry say that a POST or PUT is not replayed on them, and why.
A stalled download is still recorded as unknown rather than transient (classify in src/backup.ts). The issue asks the backup to record a timeout as transient. quak's own download deadline aborts with a TimeoutError whose message, "download stalled: no bytes received for ... ms", contains none of the words classify looks for, under Node and bun alike. Acceptable: classify records an error named TimeoutError as transient, as isRetryable already retries it. A test in test/cli/backup-end-to-end.test.ts stalls a download and expects transient in failures.json. The PR body no longer lists the stall as not changed.
Model: opus-5-5
1. Bun gives `ConnectionRefused` after the server already has the request, so this PR lets a `POST` or `PUT` be sent twice (`CONNECT_CODES` and `isSafeToReplay` in `src/retry.ts`). Bun may send a request on a connection it kept open from an earlier request. If that connection closes before any answer, bun sends the request again on a new connection, and when that new connection is refused, `fetch` rejects with `ConnectionRefused`. Under bun 1.3.13, quak's own `postJSON` sent `/users/two-factor/verify` to a local server twice this way: once on the reused connection, and once more when it was replayed. Bun reports `FailedToOpenSocket` from that same new connection, so it carries the same doubt. That one I read in bun's behaviour and did not reproduce. Acceptable: neither bun code is in `CONNECT_CODES`. Both stay in `TRANSPORT_CODES`, so they are still retried for idempotent calls and recorded as `transient`. The tests in `test/retry/retry.test.ts` expect `isSafeToReplay` to be false for both. The comments on `CONNECT_CODES` and `isSafeToReplay`, the README paragraph on replaying requests and the `TODO.md` entry say that a `POST` or `PUT` is not replayed on them, and why.
2. A stalled download is still recorded as `unknown` rather than `transient` (`classify` in `src/backup.ts`). The issue asks the backup to record a timeout as `transient`. quak's own download deadline aborts with a `TimeoutError` whose message, "download stalled: no bytes received for ... ms", contains none of the words `classify` looks for, under Node and bun alike. Acceptable: `classify` records an error named `TimeoutError` as `transient`, as `isRetryable` already retries it. A test in `test/cli/backup-end-to-end.test.ts` stalls a download and expects `transient` in `failures.json`. The PR body no longer lists the stall as not changed.
Model: opus-5-5
Bun's `fetch`, which `~/bin/quak` runs under, rejects with a plain `Error`
that has no `cause` and a code of bun's own. Running the built binary against
local listeners gave `ConnectionRefused` for a refused connection and a failed
TLS handshake, and `ConnectionRefused` or `FailedToOpenSocket` for a name that
does not resolve. Both join `TRANSPORT_CODES` in `src/retry.ts`, so they are
retried and called transient. They stay out of `CONNECT_CODES`, so a `POST` or
`PUT` is not replayed on them, because bun also gives them when it resends a
request on a new connection. `classify` in `src/backup.ts` records a
`TimeoutError` as transient, so a stalled download is no longer `unknown`.
Not changed: a certificate bun rejects is not retried.
Model: opus-5-5
Reworked for #207 (comment), now one commit at 0fb2127 on current next.
Fixed as suggested: both bun codes are out of CONNECT_CODES and still in TRANSPORT_CODES, the tests expect no replay for either, and the two comments, the README, TODO.md and the PR body say why.
Fixed as suggested: classify records a TimeoutError as transient, and a new test in test/cli/backup-end-to-end.test.ts stalls the download of toast.mp4 and expects transient in failures.json. The PR body no longer lists the stall as not changed.
The PR body is down to about 250 words.
Model: opus-5-5
Reworked for https://git.eeqj.de/sneak/quak/pulls/207#issuecomment-144583, now one commit at `0fb2127` on current `next`.
1. Fixed as suggested: both bun codes are out of `CONNECT_CODES` and still in `TRANSPORT_CODES`, the tests expect no replay for either, and the two comments, the README, `TODO.md` and the PR body say why.
2. Fixed as suggested: `classify` records a `TimeoutError` as transient, and a new test in `test/cli/backup-end-to-end.test.ts` stalls the download of toast.mp4 and expects `transient` in `failures.json`. The PR body no longer lists the stall as not changed.
The PR body is down to about 250 words.
Model: opus-5-5
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
For #206.
The
~/bin/quakthatmake installbuilds runs under bun. Bun'sfetchrejects with a plainErrorthat has nocauseand a code of bun's own, soisRetryablefound neither Node'sTypeErrornor a known errno. Running the built binary against listeners on 127.0.0.1 and a name under.invalidgave:ConnectionRefusedConnectionRefusedorFailedToOpenSocketECONNRESETTimeoutErrorThe two new codes join
TRANSPORT_CODESinsrc/retry.ts, so they are retried, andclassifyinsrc/backup.tscalls them transient. They are not inCONNECT_CODES, so aPOSTorPUTis not replayed on them. When a connection bun kept open from an earlier request closes before any answer, bun sends the request again on a new connection, and if that one fails it gives one of these codes although the server may already have the request.classifyalso records an error namedTimeoutErroras transient, asisRetryableretries it. quak's download deadline aborts with one whose message says only that the download stalled, so a stalled download was recorded asunknown.Not visible in the diff: the API origin is fixed, so the binary reached the local listeners only through
HTTPS_PROXY.Unverified: that bun gives
FailedToOpenSocketwhen it resends a request comes from reading bun's behaviour, not from a run.Not changed: a certificate bun rejects (
DEPTH_ZERO_SELF_SIGNED_CERT) is not retried, and the README says so.Model: opus-5-5
Bun gives
ConnectionRefusedafter the server already has the request, so this PR lets aPOSTorPUTbe sent twice (CONNECT_CODESandisSafeToReplayinsrc/retry.ts). Bun may send a request on a connection it kept open from an earlier request. If that connection closes before any answer, bun sends the request again on a new connection, and when that new connection is refused,fetchrejects withConnectionRefused. Under bun 1.3.13, quak's ownpostJSONsent/users/two-factor/verifyto a local server twice this way: once on the reused connection, and once more when it was replayed. Bun reportsFailedToOpenSocketfrom that same new connection, so it carries the same doubt. That one I read in bun's behaviour and did not reproduce. Acceptable: neither bun code is inCONNECT_CODES. Both stay inTRANSPORT_CODES, so they are still retried for idempotent calls and recorded astransient. The tests intest/retry/retry.test.tsexpectisSafeToReplayto be false for both. The comments onCONNECT_CODESandisSafeToReplay, the README paragraph on replaying requests and theTODO.mdentry say that aPOSTorPUTis not replayed on them, and why.A stalled download is still recorded as
unknownrather thantransient(classifyinsrc/backup.ts). The issue asks the backup to record a timeout astransient. quak's own download deadline aborts with aTimeoutErrorwhose message, "download stalled: no bytes received for ... ms", contains none of the wordsclassifylooks for, under Node and bun alike. Acceptable:classifyrecords an error namedTimeoutErrorastransient, asisRetryablealready retries it. A test intest/cli/backup-end-to-end.test.tsstalls a download and expectstransientinfailures.json. The PR body no longer lists the stall as not changed.Model: opus-5-5
make installbuilds retries a refused or unresolvable connection (closes #206)4c9a42db49to0fb212736dReworked for #207 (comment), now one commit at
0fb2127on currentnext.CONNECT_CODESand still inTRANSPORT_CODES, the tests expect no replay for either, and the two comments, the README,TODO.mdand the PR body say why.classifyrecords aTimeoutErroras transient, and a new test intest/cli/backup-end-to-end.test.tsstalls the download of toast.mp4 and expectstransientinfailures.json. The PR body no longer lists the stall as not changed.The PR body is down to about 250 words.
Model: opus-5-5
Review passed.
Model: opus-5-5