release/v0.0.201 — http send-failed poison (#177) + ultracode codeword sticky (#178) - #180
Merged
Merged
Conversation
…orm the session (#177) post() was built on client.fetch, which never exposes the Request: a request whose body SEND failed left reader.state == .ready, Request.deinit read that as "connection still clean", and the DEAD connection went back into the shared keep-alive pool. findConnection hands the free list out LIFO, so every retry — and every later same-host request — pulled the same corpse: the observed storm where a ~230k-token compaction request failed 6/6 and then, after /clear, a tiny [title] request failed 6/6 in the same process while live WS/SSE turns kept working (they bypass the pool). The streaming path has poisoned exactly this failure for a while (agent_stream.zig's errdefer conn.closing = true, "WriteFailed forever after (observed in the wild)"), and RetryPlan's doc comment even claimed postWatched had the same protection — it never did. - post(): client.request + sendHeadTask (same wire behavior as fetch for our POSTs) with the errdefer poison on every error path, plus an explicit poison on the 429/5xx early-returns that leave body bytes unread on the connection. - RetryPlan doc: describe the protection that now actually exists. - Regression test on a real loopback listener: conn 1 is closed unread so an 8MB send fails mid-write; the follow-up tiny POST must dial fresh and reach conn 2's 200 (it re-failed on the pooled corpse before the fix). Red-checked: 165/166 with the poison disabled, 166/166 with it. Fixes #177 Co-Authored-By: blackfloofie <265516171+blackfloofie@users.noreply.github.com>
…ets goal/ultracode steering (#178) The explicit "ultracode" scan ran over the fully ASSEMBLED turn message — base prompt plus the goal/todos/eval harness notes — so any standing goal containing the word kept re-triggering the explicit banner and workflow steering on every turn. And /clear kept root.goal and root.ultracode_mode (only /new reset them — an artifact of /new landing later, not a design choice), so even "context cleared — fresh conversation" didn't stop it: the observed session bannered ULTRACODE on a plain prompt right after /clear, every time. - applyUltracodeSteering takes the raw typed text alongside the assembled msg and scans ONLY the raw text for the codeword; the note still lands on the assembled msg. The oneshot path (session_run) already scanned the raw prompt; the REPL mainloop now matches it. - /clear resets the same conversation steering as /new (goal + ultracode_mode) via a shared helper, and says so when a standing goal is dropped. - Regression tests: codeword arriving via an appended harness note is not explicit; typed codeword still is (case-insensitive); persistent mode still notes without bannering; the /clear//new reset helper. Fixes #178 Co-Authored-By: blackfloofie <265516171+blackfloofie@users.noreply.github.com>
http: poison send-failed connections so one WriteFailed can't storm the session (#177)
ultracode: scan the codeword on the raw prompt only + /clear resets goal/ultracode steering (#178)
…t can't hang the binary The regression test's first assertion (expectError WriteFailed) had no safety net: if the 8MB send ever failed with something other than WriteFailed, the test returned before the second post() ran, leaving the server task parked in its second accept() and hanging the deferred fut.await. The trigger is unreachable today (Io.Writer collapses every send error to WriteFailed; the loopback RST lands on the first bytes), but the guard mirrors the second post()'s existing throwaway-dial release so the test can never hang regardless. Surfaced by the pre-PR adversarial review; test-only, no production change. Co-Authored-By: blackfloofie <265516171+blackfloofie@users.noreply.github.com>
Adds a loopback test for post()'s 429/5xx branch — previously the whole branch was uncovered; only the send-failed path had a test. conn 1 answers a keep-alive 500 with an oversized (>600B capture buffer) body; post() must partial-drain it, return error.ServerError, and the session must recover on the next request (fresh dial to conn 2's 200). Honest scope note (verified by disabling the poison): unlike the send-failed case, std does NOT re-pool a partially-read response connection on its own, so post()'s explicit 5xx poison is defensive/redundant — this test exercises the 5xx path end-to-end, it does not isolate that poison. The load-bearing #177 regression (a failed SEND leaves the reader deceptively .ready, so std DOES re-pool the corpse) remains covered by the send-failed test, which provably goes red when the poison is removed. Surfaced by the pre-PR adversarial review. Co-Authored-By: blackfloofie <265516171+blackfloofie@users.noreply.github.com>
The graff login codex PKCE callback (localhost:1455) served a single bare line of HTML. Replace it with a branded, dark-mode-aware confirmation card (centered, system font, prefers-color-scheme, charset=utf-8 so the ✓/◆ render) and bump the write buffer to fit it. Same close-tab-and-return semantics — correct for a CLI login. Folded into v0.0.201. Co-Authored-By: blackfloofie <265516171+blackfloofie@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Consolidated release. Two committed fixes plus test hardening and a login-page polish, adversarially reviewed before this PR (6 review lanes + refute pass; 0 confirmed defects).
Fixes
post()is rebuilt onclient.request(notclient.fetch) so a failed body send poisons the connection instead of returning a corpse to the keep-alive pool — oneWriteFailedcould otherwise storm every later non-streaming request (compaction,[title], subagents).ultracodecodeword is scanned on the raw typed prompt only, not the assembled turn message (goal/todo notes appended). And/clearnow resets the standing goal + ultracode mode (previously only/newdid), so the banner stops firing on plain prompts after a clear.Tests
WriteFailedresult can never hang the test binary.stdwon't re-pool a partially-read connection on its own, so this exercises the path rather than isolating the (defensive) 5xx poison; the load-bearing regression stays covered by the send-failed test (verified red without the poison).Polish
graff login codexcallback now lands on a branded, dark-mode-aware confirmation card instead of a bare line of text.Changelog bumped to 0.0.201. Merging this closes #177 and #178; tag
v0.0.201on the merge commit triggersrelease.yml.