http: HTTP/2 connection core, streams, flow control and the SETTINGS handshake (step 3 of #72) #699

Open
opened 2026-10-30 15:40:28 +00:00 by orion · 5 comments
Collaborator

Goal

Step 3 of #72 (HTTP/2): the connection core of RFC 9113, as a state machine of its own in std/http that is fed octets, answers events and queues octets to send, with no socket, no task and no channel (they are step 3b, below) and no change to what a Client or a Server does. It reads and writes frames through the codec of step 2 (#685) and header blocks through HPACK (step 1, #563). Steps 4 and 5 (server, client) and 3b drive it.

Rules

A new module std/http/src/h2.trb (internal to the package, imported by relative path like h2frame.trb, not exported from lib.trb), in the form of HpackDecoder (a type with var fn methods; the implementer follows hpack.trb):

  • H2Connection with client(limits) and server(limits). feed(var buffer: Bytes): Result<List<H2Event>, H2Error> takes what has arrived (the server first strips the 24-octet preface with isPreface; anything else is a connection error PROTOCOL_ERROR, and a partial preface waits), decodes every complete frame and answers the events. drain(): Bytes takes the octets queued to send (a client's start is the preface plus its SETTINGS; a server's is its SETTINGS). Both ends must open with SETTINGS (section 3.4): any other first frame is PROTOCOL_ERROR.
  • Events (H2Event, one variant): Headers(streamId, fields, endStream, trailers) (the block is joined from HEADERS and CONTINUATION and decoded by the connection's one HPACK decoder, so the table stays in step even for a stream that is refused), Data(streamId, data, endStream), Reset(streamId, code), WindowOpened(streamId) (0 for the connection; a blocked sender may resume), SettingsApplied, Pong(opaque), GoAway(lastStreamId, code, debug), StreamRefused(streamId) (a stream above the peer's GOAWAY lastStreamId: nothing of it was processed, so it can be retried). Unknown frame types are ignored.
  • Stream states (section 5.1): idle, open, half-closed (local), half-closed (remote), closed, kept per stream id in a map and dropped when closed and released. A stream identifier at or below the highest one seen and not in the map is closed. Rules: identifiers a peer opens must rise (otherwise PROTOCOL_ERROR) and have the right parity (client odd, server even; a server never opens one because push is off); DATA or HEADERS on a half-closed (remote) stream is a stream error STREAM_CLOSED, on a closed stream a stream error STREAM_CLOSED too, except for a stream this end reset, whose frames are dropped (their DATA still counts against the connection window); DATA on an idle stream, RST_STREAM on an idle stream, WINDOW_UPDATE on an idle stream are PROTOCOL_ERROR of the connection; PRIORITY is accepted in every state and ignored; a second HEADERS on an open stream is the trailers and needs END_STREAM (otherwise a stream error PROTOCOL_ERROR).
  • Header-block sequence (sections 4.3, 6.10): after a HEADERS or PUSH_PROMISE without END_HEADERS only a CONTINUATION of the same stream may follow, any other frame is PROTOCOL_ERROR; a CONTINUATION without an open block is too. The octets buffered for a block are limited to maxHeaderListSize (a valid block never exceeds the weight of its list, whose every field counts name + value + 32); more is ENHANCE_YOUR_CALM of the connection. A block that HPACK refuses (a compression error, which includes a list over maxHeaderListSize) is a connection error COMPRESSION_ERROR, because the two tables can no longer be kept in step; a stream-level 431 for an oversized list is a later refinement. A PUSH_PROMISE is a connection error PROTOCOL_ERROR, as this end sent ENABLE_PUSH 0 (section 8.4).
  • SETTINGS handshake (sections 6.5, 6.5.3): the peer's SETTINGS is applied on receipt and acknowledged by an empty SETTINGS with ACK queued at once; our SETTINGS count as applied when the ACK arrives (SettingsApplied), and only then does the decoder's maxFrameSize change. An ACK that was not asked for is PROTOCOL_ERROR. Applied from the peer: HEADER_TABLE_SIZE to the HPACK encoder, MAX_FRAME_SIZE to the size of the frames this end writes, MAX_CONCURRENT_STREAMS to openStream, INITIAL_WINDOW_SIZE to the send window of every open stream by the difference (may go negative, section 6.9.2; above 2^31-1 is FLOW_CONTROL_ERROR of the connection). An unknown identifier is ignored.
  • Flow control (sections 5.2, 6.9): two send windows (connection, per stream) and two receive windows, DATA only, padding counted. sendData(streamId, data, endStream) writes DATA frames up to the smaller of the two send windows and the peer's frame size, and answers how many octets it took (the caller keeps the rest and retries on WindowOpened); END_STREAM goes on the frame that carries the last octet, an empty final DATA is allowed at a zero window. A DATA frame that overruns the receive window is FLOW_CONTROL_ERROR (connection for the connection window, stream error for a stream window). The receive side hands credit back only when the application says it consumed the data: consumed(streamId, count) queues a WINDOW_UPDATE once the unreturned credit reaches half of the window (and at once for the connection window's share, so no stream's slow reader stalls the others). A WINDOW_UPDATE that takes a send window above 2^31-1 is FLOW_CONTROL_ERROR (stream error on a stream, connection error on stream 0).
  • Opening and ending (client side openStream(fields, endStream): Result<Int, H2Error> encodes the HEADERS through splitHeaderBlock; a server answers with sendHeaders(streamId, fields, endStream)): refused with an H2Error that is not a protocol error when the peer's MAX_CONCURRENT_STREAMS is reached or a GOAWAY has been received (the waiting is 3b's). reset(streamId, code) sends RST_STREAM and closes the stream; release(streamId) is the application saying it has finished with the stream.
  • Peer limits (decided below): at most maxConcurrentStreams streams the peer opened and the application has not released; a HEADERS beyond is a stream error REFUSED_STREAM. At most 10000 queued control frames (SETTINGS ACK, PING ACK, RST_STREAM) the caller has not drained; more is ENHANCE_YOUR_CALM.
  • PING and GOAWAY: a PING gets an ACK with the same 8 octets, an ACK is the Pong event; ping(opaque) sends one. goAway(code, debug) queues GOAWAY with the highest peer stream identifier processed and from then on refuses new streams of the peer (silently ignored above that identifier); a received GOAWAY ends openStream and reports GoAway. A connection error found by feed queues the GOAWAY with its code itself and returns H2Error; the connection then accepts no further input.
  • Not here: header-field rules of section 8 (pseudo-headers, content-length, connection-specific fields) are the translation to Request and Response of steps 4 and 5; the socket, the task, the channels and the timeouts (SETTINGS ACK, PING) are step 3b; graceful two-phase shutdown is step 4.

Decided by the loop

  • Sans-IO, bytes in and bytes out. The core is a value that takes octets and returns events, so it is tested without a network, in the VM and --native, with both ends in one program wired by drain into feed, and so the task of 3b (one per connection) owns it without a lock. The alternative, a task with channels at once, is the shape of 3b; splitting it off keeps the PR at the size of step 2 (the state rules and the windows are the part with the many tests).
  • Own the HPACK codec in the core. Header blocks must be decoded in the order they arrive, also for refused streams, or the tables of the two ends diverge; so decoding happens in feed, and events carry fields, not blocks. (Applies to the encoder the same way: openStream and sendHeaders encode under one encoder, in call order.)
  • Defaults (H2Limits, following Go's net/http2, epic "Limits"): maxConcurrentStreams 100, per-stream initial window 65535 (not announced, it is the default), connection receive window raised to 1 MiB by a WINDOW_UPDATE right after SETTINGS, maxFrameSize 16384, maxHeaderListSize 65536, headerTableSize 4096, ENABLE_PUSH 0 announced by a client; a server announces nothing it does not change from the default except MAX_CONCURRENT_STREAMS and MAX_HEADER_LIST_SIZE. A program cannot change them yet; H2Limits is a record so a later issue can expose them.
  • Rapid reset (CVE-2023-44487): a stream's slot in the peer's concurrency limit is held until the application calls release, not until RST_STREAM arrives, as Go and nghttp2 did after the attack. A peer that opens and cancels streams quickly therefore runs into REFUSED_STREAM instead of creating unbounded work.
  • Closed streams carry no history, only the highest identifier seen plus a set of the streams this end reset that is capped at 1000 (the oldest forgotten): enough for the frames that were in flight when the reset was sent, and bounded.
  • Trailers are reported, not dropped, by the core (trailers: true); dropping them is the layer above, as the epic decided.
  • Window credit is explicit (consumed), not automatic on receipt, because a stream's Body is pulled (NETWORK.md section 1): credit follows the reader, which is the backpressure HTTP/2 exists to give.

Acceptance criteria

std/http/tests/h2.test.trb (VM and --native, as the other std/http/tests), all with a client and a server H2Connection in one program, their output fed into each other:

  1. The handshake: both ends' first octets are the preface plus SETTINGS and SETTINGS, each SETTINGS is acknowledged, SettingsApplied arrives on both, and a server that gets a first frame that is not SETTINGS, or a partial preface, answers as above (PROTOCOL_ERROR with GOAWAY, and need-more).
  2. A request and a response: HEADERS (with a header block split into HEADERS + CONTINUATION by a small MAX_FRAME_SIZE), DATA both ways, trailers, END_STREAM on each side; the stream walks idle, open, half-closed, closed and the events arrive in order with the right fields; the HPACK tables stay in step over ten requests with repeated fields.
  3. Flow control: a body of 200000 octets goes over the 65535-octet windows only as the receiver calls consumed; sendData answers the short count and WindowOpened resumes it; a DATA frame beyond the receive window, a WINDOW_UPDATE past 2^31-1, and an INITIAL_WINDOW_SIZE change that takes an open stream's window negative and back are each a test, with the level (stream or connection) and the code named.
  4. Each refusal of the stream-state, header-block, SETTINGS and peer-limit rules above is its own test and names the expected error code and level: DATA on idle, a second stream id below the first, wrong parity, a frame between HEADERS and CONTINUATION, a CONTINUATION alone, a PUSH_PROMISE, an unsolicited SETTINGS ACK, DATA after END_STREAM, a header block over the buffered limit, the 101st concurrent stream, a flood of PING without drain.
  5. reset and the peer's RST_STREAM: the event, the closed state, the frames dropped for a stream this end reset (their DATA still debits the connection window), and the slot held until release (a loop of 1000 open-and-reset requests from the client gets REFUSED_STREAM once 100 are unreleased).
  6. PING round trip, goAway and a received GOAWAY (new openStream refused, StreamRefused for a stream above lastStreamId), and a connection error that queues its own GOAWAY and rejects later input.
  7. A fixed-seed run of at least 200 generated requests with random header sets and bodies over one connection pair, all completing with equal bytes.

tools/gates.sh a and b green in forge CI. NETWORK.md section 12 gets "As built, step 3: the connection core" and slice 12's row and FIRST-PARTY.md gap 25 get the note (the gap stays open); skills/ regenerated if the docs change reaches them.

Design record / seed

Implements NETWORK.md slice 12 (HTTP/2), RFC 9113 sections 3.4, 5, 6.5, 6.9 and 6.10. Seed: no (std only, no syntax, no native, no string lookup by the compiler).

Size

One PR, two Conventional Commits: feat(http): HTTP/2 connection core, streams and handshake, then feat(http): HTTP/2 flow control, limits and the rapid-reset guard (with the docs).

Dependencies

#685 (frames, landed) and #563 (HPACK, landed). Part of #72. Step 3b (the connection task over a Transport with a channel per stream, the SETTINGS and PING timeouts, tested over loopback with --native) is filed when this one has landed; steps 4 to 6 follow after it.

## Goal Step 3 of #72 (HTTP/2): the **connection core** of RFC 9113, as a state machine of its own in `std/http` that is fed octets, answers events and queues octets to send, with **no socket, no task and no channel** (they are step 3b, below) and no change to what a `Client` or a `Server` does. It reads and writes frames through the codec of step 2 (#685) and header blocks through HPACK (step 1, #563). Steps 4 and 5 (server, client) and 3b drive it. ## Rules A new module `std/http/src/h2.trb` (internal to the package, imported by relative path like `h2frame.trb`, not exported from `lib.trb`), in the form of `HpackDecoder` (a type with `var fn` methods; the implementer follows `hpack.trb`): - **`H2Connection`** with `client(limits)` and `server(limits)`. `feed(var buffer: Bytes): Result<List<H2Event>, H2Error>` takes what has arrived (the server first strips the 24-octet preface with `isPreface`; anything else is a connection error `PROTOCOL_ERROR`, and a partial preface waits), decodes every complete frame and answers the events. `drain(): Bytes` takes the octets queued to send (a client's start is the preface plus its SETTINGS; a server's is its SETTINGS). Both ends must open with SETTINGS (section 3.4): any other first frame is `PROTOCOL_ERROR`. - **Events** (`H2Event`, one variant): `Headers(streamId, fields, endStream, trailers)` (the block is joined from HEADERS and CONTINUATION and decoded by the connection's one HPACK decoder, so the table stays in step even for a stream that is refused), `Data(streamId, data, endStream)`, `Reset(streamId, code)`, `WindowOpened(streamId)` (0 for the connection; a blocked sender may resume), `SettingsApplied`, `Pong(opaque)`, `GoAway(lastStreamId, code, debug)`, `StreamRefused(streamId)` (a stream above the peer's GOAWAY `lastStreamId`: nothing of it was processed, so it can be retried). Unknown frame types are ignored. - **Stream states** (section 5.1): idle, open, half-closed (local), half-closed (remote), closed, kept per stream id in a map and dropped when closed *and* released. A stream identifier at or below the highest one seen and not in the map is closed. Rules: identifiers a peer opens must rise (otherwise `PROTOCOL_ERROR`) and have the right parity (client odd, server even; a server never opens one because push is off); DATA or HEADERS on a half-closed (remote) stream is a stream error `STREAM_CLOSED`, on a closed stream a stream error `STREAM_CLOSED` too, except for a stream this end reset, whose frames are dropped (their DATA still counts against the connection window); DATA on an idle stream, RST_STREAM on an idle stream, WINDOW_UPDATE on an idle stream are `PROTOCOL_ERROR` of the connection; PRIORITY is accepted in every state and ignored; a second HEADERS on an open stream is the trailers and needs `END_STREAM` (otherwise a stream error `PROTOCOL_ERROR`). - **Header-block sequence** (sections 4.3, 6.10): after a HEADERS or PUSH_PROMISE without `END_HEADERS` only a CONTINUATION of the same stream may follow, any other frame is `PROTOCOL_ERROR`; a CONTINUATION without an open block is too. The octets buffered for a block are limited to `maxHeaderListSize` (a valid block never exceeds the weight of its list, whose every field counts `name + value + 32`); more is `ENHANCE_YOUR_CALM` of the connection. A block that HPACK refuses (a compression error, which includes a list over `maxHeaderListSize`) is a connection error `COMPRESSION_ERROR`, because the two tables can no longer be kept in step; a stream-level `431` for an oversized list is a later refinement. A `PUSH_PROMISE` is a connection error `PROTOCOL_ERROR`, as this end sent `ENABLE_PUSH` 0 (section 8.4). - **SETTINGS handshake** (sections 6.5, 6.5.3): the peer's SETTINGS is applied on receipt and acknowledged by an empty SETTINGS with ACK queued at once; our SETTINGS count as applied when the ACK arrives (`SettingsApplied`), and only then does the decoder's `maxFrameSize` change. An ACK that was not asked for is `PROTOCOL_ERROR`. Applied from the peer: `HEADER_TABLE_SIZE` to the HPACK encoder, `MAX_FRAME_SIZE` to the size of the frames this end writes, `MAX_CONCURRENT_STREAMS` to `openStream`, `INITIAL_WINDOW_SIZE` to the send window of every open stream by the difference (may go negative, section 6.9.2; above 2^31-1 is `FLOW_CONTROL_ERROR` of the connection). An unknown identifier is ignored. - **Flow control** (sections 5.2, 6.9): two send windows (connection, per stream) and two receive windows, DATA only, padding counted. `sendData(streamId, data, endStream)` writes DATA frames up to the smaller of the two send windows and the peer's frame size, and answers how many octets it took (the caller keeps the rest and retries on `WindowOpened`); `END_STREAM` goes on the frame that carries the last octet, an empty final DATA is allowed at a zero window. A DATA frame that overruns the receive window is `FLOW_CONTROL_ERROR` (connection for the connection window, stream error for a stream window). The receive side hands credit back only when the application says it consumed the data: `consumed(streamId, count)` queues a WINDOW_UPDATE once the unreturned credit reaches half of the window (and at once for the connection window's share, so no stream's slow reader stalls the others). A WINDOW_UPDATE that takes a send window above 2^31-1 is `FLOW_CONTROL_ERROR` (stream error on a stream, connection error on stream 0). - **Opening and ending** (client side `openStream(fields, endStream): Result<Int, H2Error>` encodes the HEADERS through `splitHeaderBlock`; a server answers with `sendHeaders(streamId, fields, endStream)`): refused with an `H2Error` that is not a protocol error when the peer's `MAX_CONCURRENT_STREAMS` is reached or a GOAWAY has been received (the waiting is 3b's). `reset(streamId, code)` sends RST_STREAM and closes the stream; `release(streamId)` is the application saying it has finished with the stream. - **Peer limits** (decided below): at most `maxConcurrentStreams` streams the peer opened and the application has not released; a HEADERS beyond is a stream error `REFUSED_STREAM`. At most 10000 queued control frames (SETTINGS ACK, PING ACK, RST_STREAM) the caller has not drained; more is `ENHANCE_YOUR_CALM`. - **PING and GOAWAY**: a PING gets an ACK with the same 8 octets, an ACK is the `Pong` event; `ping(opaque)` sends one. `goAway(code, debug)` queues GOAWAY with the highest peer stream identifier processed and from then on refuses new streams of the peer (silently ignored above that identifier); a received GOAWAY ends `openStream` and reports `GoAway`. A connection error found by `feed` queues the GOAWAY with its code itself and returns `H2Error`; the connection then accepts no further input. - **Not here**: header-field rules of section 8 (pseudo-headers, `content-length`, connection-specific fields) are the translation to `Request` and `Response` of steps 4 and 5; the socket, the task, the channels and the timeouts (SETTINGS ACK, PING) are step 3b; graceful two-phase shutdown is step 4. ### Decided by the loop - **Sans-IO, bytes in and bytes out.** The core is a value that takes octets and returns events, so it is tested without a network, in the VM and `--native`, with both ends in one program wired by `drain` into `feed`, and so the task of 3b (one per connection) owns it without a lock. The alternative, a task with channels at once, is the shape of 3b; splitting it off keeps the PR at the size of step 2 (the state rules and the windows are the part with the many tests). - **Own the HPACK codec in the core.** Header blocks must be decoded in the order they arrive, also for refused streams, or the tables of the two ends diverge; so decoding happens in `feed`, and events carry fields, not blocks. (Applies to the encoder the same way: `openStream` and `sendHeaders` encode under one encoder, in call order.) - **Defaults** (`H2Limits`, following Go's `net/http2`, epic "Limits"): `maxConcurrentStreams` 100, per-stream initial window 65535 (not announced, it is the default), connection receive window raised to 1 MiB by a WINDOW_UPDATE right after SETTINGS, `maxFrameSize` 16384, `maxHeaderListSize` 65536, `headerTableSize` 4096, `ENABLE_PUSH` 0 announced by a client; a server announces nothing it does not change from the default except `MAX_CONCURRENT_STREAMS` and `MAX_HEADER_LIST_SIZE`. A program cannot change them yet; `H2Limits` is a record so a later issue can expose them. - **Rapid reset** (CVE-2023-44487): a stream's slot in the peer's concurrency limit is held until the application calls `release`, not until RST_STREAM arrives, as Go and nghttp2 did after the attack. A peer that opens and cancels streams quickly therefore runs into `REFUSED_STREAM` instead of creating unbounded work. - **Closed streams carry no history**, only the highest identifier seen plus a set of the streams this end reset that is capped at 1000 (the oldest forgotten): enough for the frames that were in flight when the reset was sent, and bounded. - **Trailers are reported, not dropped**, by the core (`trailers: true`); dropping them is the layer above, as the epic decided. - **Window credit is explicit** (`consumed`), not automatic on receipt, because a stream's `Body` is pulled (NETWORK.md section 1): credit follows the reader, which is the backpressure HTTP/2 exists to give. ## Acceptance criteria `std/http/tests/h2.test.trb` (VM and `--native`, as the other `std/http/tests`), all with a client and a server `H2Connection` in one program, their output fed into each other: 1. The handshake: both ends' first octets are the preface plus SETTINGS and SETTINGS, each SETTINGS is acknowledged, `SettingsApplied` arrives on both, and a server that gets a first frame that is not SETTINGS, or a partial preface, answers as above (`PROTOCOL_ERROR` with GOAWAY, and need-more). 2. A request and a response: HEADERS (with a header block split into HEADERS + CONTINUATION by a small `MAX_FRAME_SIZE`), DATA both ways, trailers, `END_STREAM` on each side; the stream walks idle, open, half-closed, closed and the events arrive in order with the right fields; the HPACK tables stay in step over ten requests with repeated fields. 3. Flow control: a body of 200000 octets goes over the 65535-octet windows only as the receiver calls `consumed`; `sendData` answers the short count and `WindowOpened` resumes it; a DATA frame beyond the receive window, a WINDOW_UPDATE past 2^31-1, and an `INITIAL_WINDOW_SIZE` change that takes an open stream's window negative and back are each a test, with the level (stream or connection) and the code named. 4. Each refusal of the stream-state, header-block, SETTINGS and peer-limit rules above is its own test and names the expected error code and level: DATA on idle, a second stream id below the first, wrong parity, a frame between HEADERS and CONTINUATION, a CONTINUATION alone, a PUSH_PROMISE, an unsolicited SETTINGS ACK, DATA after END_STREAM, a header block over the buffered limit, the 101st concurrent stream, a flood of PING without `drain`. 5. `reset` and the peer's RST_STREAM: the event, the closed state, the frames dropped for a stream this end reset (their DATA still debits the connection window), and the slot held until `release` (a loop of 1000 open-and-reset requests from the client gets `REFUSED_STREAM` once 100 are unreleased). 6. PING round trip, `goAway` and a received GOAWAY (new `openStream` refused, `StreamRefused` for a stream above `lastStreamId`), and a connection error that queues its own GOAWAY and rejects later input. 7. A fixed-seed run of at least 200 generated requests with random header sets and bodies over one connection pair, all completing with equal bytes. `tools/gates.sh a` and `b` green in forge CI. NETWORK.md section 12 gets "As built, step 3: the connection core" and slice 12's row and FIRST-PARTY.md gap 25 get the note (the gap stays open); `skills/` regenerated if the docs change reaches them. ## Design record / seed Implements NETWORK.md slice 12 (HTTP/2), RFC 9113 sections 3.4, 5, 6.5, 6.9 and 6.10. Seed: no (std only, no syntax, no native, no string lookup by the compiler). ## Size One PR, two Conventional Commits: `feat(http): HTTP/2 connection core, streams and handshake`, then `feat(http): HTTP/2 flow control, limits and the rapid-reset guard` (with the docs). ## Dependencies #685 (frames, landed) and #563 (HPACK, landed). Part of #72. **Step 3b** (the connection task over a `Transport` with a channel per stream, the SETTINGS and PING timeouts, tested over loopback with `--native`) is filed when this one has landed; steps 4 to 6 follow after it.
Author
Collaborator

[loop:torbscript] decided by the loop: step 3 is the connection core as a sans-IO state machine (octets in, events and octets out), not the task with channels at once. Why: the stream-state rules, the flow-control windows and the limits are the part with the many tests, and a state machine needs no network to test (both ends in one program, VM and --native); the Transport task and the channel per stream become step 3b, filed when this lands. It keeps the PR at the size of step 2 (two commits). HPACK is owned by the core because header blocks must be decoded in arrival order, also for refused streams. Window credit is explicit (consumed) so a pulled Body gives the backpressure. A peer's stream slot is held until the application releases it, which is the guard against rapid reset (CVE-2023-44487). Defaults follow Go's net/http2 as the epic says. Seed impact: none (std only).
next: ready

[loop:torbscript] decided by the loop: step 3 is the connection core as a sans-IO state machine (octets in, events and octets out), not the task with channels at once. Why: the stream-state rules, the flow-control windows and the limits are the part with the many tests, and a state machine needs no network to test (both ends in one program, VM and `--native`); the Transport task and the channel per stream become step 3b, filed when this lands. It keeps the PR at the size of step 2 (two commits). HPACK is owned by the core because header blocks must be decoded in arrival order, also for refused streams. Window credit is explicit (`consumed`) so a pulled `Body` gives the backpressure. A peer's stream slot is held until the application releases it, which is the guard against rapid reset (CVE-2023-44487). Defaults follow Go's `net/http2` as the epic says. Seed impact: none (std only). next: ready
Author
Collaborator

[loop:torbscript] claim implementation by session:loop-torbscript-20261030 @anthropic:tkoehn until 2026-10-31T01:31Z

[loop:torbscript] claim implementation by session:loop-torbscript-20261030 @anthropic:tkoehn until 2026-10-31T01:31Z
Author
Collaborator

[loop:torbscript] release implementation by session:loop-torbscript-20261030 @anthropic:tkoehn: the worker run ended without a result (the worker runtime refused its oversized output log); no branch, commit or PR was pushed, so nothing is left to pick up. The item is still ready; the next worker starts from main and keeps its command output small.
next: implementation

[loop:torbscript] release implementation by session:loop-torbscript-20261030 @anthropic:tkoehn: the worker run ended without a result (the worker runtime refused its oversized output log); no branch, commit or PR was pushed, so nothing is left to pick up. The item is still `ready`; the next worker starts from main and keeps its command output small. next: implementation
Author
Collaborator

[loop:torbscript] claim implementation by session:loop-torbscript-20261030 @anthropic:tkoehn until 2026-10-31T04:27Z

[loop:torbscript] claim implementation by session:loop-torbscript-20261030 @anthropic:tkoehn until 2026-10-31T04:27Z
Author
Collaborator

[loop:torbscript] release implementation by session:loop-torbscript-20261030 @anthropic:tkoehn: the worker run was cancelled without a result; no branch, no PR. Release of the claim.
next: implementation

[loop:torbscript] release implementation by session:loop-torbscript-20261030 @anthropic:tkoehn: the worker run was cancelled without a result; no branch, no PR. Release of the claim. next: implementation
Sign in to join this conversation.
No labels
loop
ready
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
torbscript/language#699
No description provided.