setup consent, connection details, transient-failure recovery, stream prelude retry, doctor/installer features - #9
Merged
Conversation
…r fixes
Consent (setup):
- one y/n question per detected harness ("Configure ZCode as a provider
with its supported models in <HARNESS>? [y/n]"); only y configures, n
skips and never deletes; without a terminal undecided harnesses are
skipped unless selected with --harness <list> or ZCODE_KIT_HARNESSES
(none skips all; unknown ids are errors)
- decisions stored per harness under generated/harness-choices/ through
the setup transaction (rollback removes them); update and doctor --fix
refresh only consented or kit-owned integrations; --reask asks again
- one prompter for all questions (typed-ahead answers stay in order),
Ctrl-C aborts with exit 130 and applies only the answers given
- a failing harness no longer takes the others down: its partial writes
are undone via transaction savepoints, setup exits 1, installers warn
and continue
- MCP bridge registration follows consent; doctor reports declined
harnesses as SKIP instead of FAIL
Connection details (manual client setup):
- setup, proxy start (also when already running) and proxy status print
the real base URLs, the local key and the model ids of the verified own
proxy; a stopped proxy is labelled as configuration only, a foreign
listener withholds the details
- the full key is shown only on an interactive terminal (stdin and
stdout TTY, not CI); logs, pipes, JSON and installer logs get a
redaction marker; status never creates or rotates the key
Proxy:
- account rotator: non-inference operations no longer move the sticky
account; the effective identity no longer depends on userId
- ordered transport: socket open is abortable; SNI only for hostnames
- upstream errors: no quota retry after bytes reached the client
- captcha verify header masked in debug logs
Docs: README (+ de/es/ja/zh-CN), harness guides (+ translations), proxy
README intros, CLI usage; tests for consent, connection details,
transaction savepoints and the proxy fixes.
…recisely Counter-check findings (documentation vs. code): the README sentence about unattended runs now names the refresh of an integration the kit created before it asked (no consent recorded, no MCP), the manual entry paragraph no longer calls the kit's own step "automatic configuration", setup.mjs no longer claims to wire every detected harness, and one pre-existing nuance in the Chinese proxy section (start lock is never taken over, not "kept") is corrected. Same wording in de/es/ja/zh-CN.
…h an error; setup: separate MCP consent, exit code 20 Trigger: errors that disappeared when the user sent a new "Continue" message. The proxy retried only four connect-level error codes; every other transient failure ended the harness turn although a fresh request would have succeeded, and a natively passed-through Anthropic stream that the gateway cut off simply stopped. Proxy: - pre-output transient ladder (shared by chat and /v1/responses): thrown connect failures and connection drops before a response (reset, pipe, timeout; never postWrite, TLS or abort) and HTTP 500/502/503/504/524/529 and 429 without a recognised gateway envelope are re-dispatched on the same account, initial + 3 retries with growing, abortable waits; a numeric Retry-After is honoured up to 15 s and surfaced above it. Gateway business envelopes, request/auth/model errors, streams and anything after output are never retried; the 1005/1113 schedule and the captcha layer keep their own single attempts. ZCODE_PROXY_TRANSIENT_RETRY_UNIT_MS sets the base delay (0 = no waits, off = connect-only as before) and is passed through by proxy start/restart. - ordered transport: an upstream close before response headers now carries postWrite (it was replayable by the quota failover); nested postWrite causes are recognised; the error listener stays attached on abort; IPv6 literals get a bare host and no SNI. - native Anthropic streams that end without message_stop, or whose read fails, get one terminal `event: error` frame (upstream_incomplete / upstream_stream_error); nothing is replayed, no message_stop invented. - captcha retry re-checks the client signal before solving and before the resend; account list marks the inference account as active even after a lookup served by another profile; one shared sensitive-header set for debug and dump output. Kit: - MCP bridge consent is recorded separately from provider consent: an explicit selection, or a y after the MCP note; integrate, a refresh or a stored decision without the flag never register the bridge. - setup exits 20 (not 1) when a harness failed and the others were configured; installers and update treat 20 as partial success and 130 (Ctrl-C) as "finish later", both still start the proxy / the shim. - setup withholds connection details when a foreign service holds the port; the details say when the model list came from configuration; [::1] listeners keep their URL. - transaction backups use a monotonic counter (no name reuse after restoreSince); undo and decision recording cannot abort the run; integrate warns when a decision cannot be recorded; install.sh proves /dev/tty can be opened and gives setup /dev/null without a terminal. Docs (en + de/es/ja/zh-CN): error modes, retry knob, stream termination, MCP consent, exit code 20. Tests: transient-retry, sse-terminal, ordered transport pre-header EOF, nested postWrite, captcha abort, rotator active marker, MCP consent paths, backup collision, connection-details markers.
…e stream end; setup: --no-mcp never records MCP consent Review findings on the second package (independent review and counter-check), each verified against the code before the change. Proxy - transient ladder: a gateway envelope now decides by its code. The codes the official client retries (500, 1120, 1230, 1234, 1302, 1303, 1305, 1312, 2007, 3002) are retried with any HTTP status, terminal verdicts (quota, balance, captcha, model, authorization, authentication, 1210) never, any other code follows the HTTP status. A captcha challenge header is handed to the captcha layer even on a transient status (no repeated sends of a spent token). A TLS code anywhere in the error chain blocks a retry. Content-type checks are case-insensitive. Retry-After accepts an HTTP-date. The account is re-checked before every retry, and a refused retry hands back the last response intact. - error mapping keeps a bounded numeric Retry-After on 503 and 529 as well as 429, so a delay the ladder surfaced reaches the client. - native Anthropic streams are forwarded frame by frame: an unfinished last frame (the usual shape of a cut connection) is dropped so the appended `event: error` frame stays parseable. The frame uses the standard `api_error` type and names the cause in its message. A gzip/deflate/br-encoded native stream is decoded before the monitor and forwarded identity-encoded, so the guarantee also holds for clients that accept compression. Kit - `setup --harness X --no-mcp` no longer stores MCP consent; a later plain setup never registers the declined bridge. - `integrate` keeps an MCP consent recorded earlier instead of clearing it. - connection details bracket every IPv6 literal, not only ::1. Docs (en + de/es/ja/zh-CN): retry policy wording (codes, budget vs the official client, Retry-After statuses, account re-check, ordered transport), stream termination (api_error, dropped partial frame), quota failover only when the rotator has another account. Checked and refuted: CRLF frames were already recognised (`$` with the m flag matches before CR in Node and Bun); tests now pin it.
…ate; kit: status --json, setup --select, doctor --forget/--upstream, rsync-free update Proxy - Stream prelude retry: a 200 event stream is read until its first content event. A transient error event (overloaded, api/rate-limit error, a retryable gateway code) or an end/read failure in that window is retried by the pre-output ladder on the same account, as the official client does; a content event hands on the held prelude and the untouched rest. Data-only frames are classified by their JSON type like the translators; bodies the transport already inflated are read as they are; a client abort cancels the upstream at once; bounds 15 s per attempt and 256 KiB held. Gateway codes shared in gateway-codes.ts. - Start-plan: a retry after a response, a post-write drop or a failed prelude takes a fresh pooled captcha token; a never-connected attempt keeps it; a mint failure keeps the previous one. - Ordered transport parity: a failure after the request was written and before any response is a drop, re-sent on the same account like a reset on the fetch path; the quota failover still never replays it on another account; a client abort is an AbortError and never retried. - Account metadata persistence: a failed write (store lock held by another process, transient I/O) stays unsaved and is rewritten in the background after 0.25/1/4/15 s instead of being dropped; each new change restarts the schedule, a busy 3-pass cap continues in the background, SIGINT/SIGTERM and the memory restart make one bounded final write; `accounts doctor` warns runtime_changes_unsaved. Kit - `proxy status --json` / `status --json`: one object (health, pid, base URLs, routes, model ids and their source, quota); never the key. - `setup --select`: one numbered list of detected harnesses (numbers, all, none); chosen = configured, the other detected = skipped; MCP only after the note and without --no-mcp; ignored next to an explicit selection or without a terminal. - doctor: unreadable decision files FAIL with the way out, decisions for undetected or unknown harnesses SKIP; `doctor --forget <harness>` removes one decision through a transaction (integration untouched). - `doctor --upstream` (opt-in): compares the kit's gateway with the provider configuration the ZCode client receives (remote release or legacy provider list; reference client 3.14.3 when the configured version gets no plan data); no credentials, no redirects, one 8 s budget. - install.sh: repeat installs no longer need rsync; a portable tar/find mirror copies first, then removes what the release dropped, never touching the key, user config, Bun path, node_modules, backups, logs or generated (at any depth). Tests: stream-prelude, persistence retry, prelude/captcha integration, abort during the prelude, status --json, --select (pty), --forget with rollback, doctor --upstream (both shapes, boundaries, drift against the proxy constants), repeat install (portable and default), and Windows CI tests for install.ps1 repeat install and setup exit 20/130/1. Docs (en + de/es/ja/zh-CN). Reviews before this commit: protocol review of the proxy part (double decompression in translation mode, data-only frames, shutdown write, schedule re-arm, byte bound — fixed) and a test-matrix review of the kit part (one time budget for both upstream requests — fixed).
… safety, prelude edge cases) CI (first run on Linux and Windows): - install.ps1 left $LASTEXITCODE at setup's 20/130 after reporting the installation as complete; callers checking it saw a failure. It is now reset to 0 once the installation succeeded. - Installer tests: the rsync fixture now has older installed files (rsync's size+mtime quick check skipped same-second, same-size files); the robocopy fixture ships proxy/ like a real release (/MIR purges a directory the release no longer ships, protected files inside included). Final review: - install.sh portable mirror: the archive goes through a file, so a failed or partial copy step stops before any delete (no pipefail in sh). - Memory restart: close() is bounded to 6 s so the 3 s metadata write still runs inside the 10 s exit cap. - Prelude gate: a body that cannot be decoded is handed on instead of retried; frames with mixed line endings split exactly like the frame-end scanner; the ladder stops at once when the client left during the prelude. - doctor --upstream: the response size cap applies while reading; the reference-version fallback runs only for covered plans; at most three requests (docs corrected in all languages). - doctor --forget: the setup lock is released even if the transaction cannot start; setup --select answers are trimmed. Documentation counter-check: --select needs a terminal and yields to an explicit selection; status --json carries quota only while the kit's own proxy runs (exit 0 only then) — README in all five languages, CLI usage.
ZepiGit
marked this pull request as ready for review
September 27, 2026 18:07
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.
Summary
Implements the approved product changes 7.1–7.4 (per-harness consent, copyable connection details, manual base-URL/API-key entry, docs), verified fixes in the bundled proxy found during the deep dive, a recovery package for transient upstream failures (the "sending Continue fixes it" report), and nine follow-up features, each reviewed before merge.
Per-harness consent in
zcode-kit setupyconfigures,nnever deletes; without a terminal nothing is configured silently. Unattended selection with--harness <list>/ZCODE_KIT_HARNESSES(none, unknown ids are errors).generated/harness-choices/through the setup transaction;update/doctor --fixrefresh only consented or kit-owned integrations;--reaskasks again.setup --selectshows one numbered list instead (1,3,all,none): chosen = configured, the other detected = skipped. Needs a terminal; ignored next to an explicit selection.yafter the note;--no-mcpis never stored as consent).$LASTEXITCODEafterwards).Connection details (7.1 / 7.3)
setup,proxy startandproxy statusprint base URLs, key and model ids of the verified own proxy; the full key only on an interactive terminal.proxy status --json/status --json: one object (health, pid, base URLs, routes, model ids and their source, quota while the own proxy runs); never the key.doctor
doctor --forget <harness>(transactional; integration untouched).doctor --upstream(opt-in, at most three unauthenticated GETs): compares the kit's gateway with the provider configuration the ZCode client receives (remote release or legacy provider list; reference client 3.14.3 as fallback). Live-verified: gateways match; start-plan upstream does not offer GLM-5.3 (informational).Proxy: transient-failure recovery
event: error(api_error) instead of a silent truncation.accounts doctorwarnsruntime_changes_unsaved.Installers
Docs
README, harness guides, proxy README (all in en/de/es/ja/zh-CN), Account Rotator docs (en/de), CLI usage.
Verification
npm test: 286 tests, 0 failures, 12 platform skips (locally; Linux and Windows in CI).startServer binds … ::1) is pre-existing and caused by the test container lacking IPv6.tsc --noEmitclean.