Key file: nonblocking open, regular file only, 1024-byte bound, refuse
group/world-readable. --system-file capped at 64 KiB. Tests drive a forced
tools request through the real serve loop and the real claude backend.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Prompt on stdin, answer on stdout; no tools, cwd or endpoint options, key read
from a file, one-line stderr cause on every failure.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Readouts no longer take a lease's connection slot: the accept loop admits
max_connections + READOUT_CONNECTIONS, a lease holds one of max_connections
after it is read, a readout one of READOUT_CONNECTIONS, and a readout over its
limit is refused Busy rather than dropped. Socket tests hold the service lock
and a metered cell across readouts (no asking, no week wait, no lock), flood
the readout pool beside leases, and pin the refusal. The new public request
type is LeaseUsageReadoutRequest so it no longer shares a name with the kit's
EnvelopeKind::UsageReadoutRequest; wire bytes and fixtures are unchanged.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The timeout field was read only by a test (dead_code under -D warnings), so
ask() applies it to each request. The serve wrapper is reached by a
subprocess refusal test (no network); the serve test fails inside 30 s
instead of hanging; "Wednesday 21-Oct-26 ..." (no comma) is refused.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
serve_config is the public wrapper over a crate-private serve_config_with
that takes the usage client; the test runs it in-process against a fake and
asserts the fake received GET /api/oauth/usage with the bearer. The endpoint
is not a document field or env, so whoever writes the config cannot redirect
the token. The subprocess test that reached api.anthropic.com is deleted.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
UsageClient carries its timeout and url; UsageClient::production() is what
start() builds, and the test asserts that client's url and 10 s timeout as
spec r2 says, replacing a 1..=60 s bound no rule names.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
RFC 9110 10.2.3 makes a recipient accept IMF-fixdate, RFC 850 and asctime;
the last two read as absent and the poll asked again at the floor. The
two-digit RFC 850 year more than 50 years ahead is the latest past year.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Spawns the claude-connector binary on a ready document and reads the
usage poll state line from its stderr; the connector must also stay up.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
QuotaCell::observe_at is the one decision for both sensors: a reading older
than the held one is dropped, and a rejection stands against a reading that
only reports utilization (status polled) until its window resets or a reading
that carries its own verdict replaces it. The poll stamps its answer with the
moment it asked. Also: Retry-After in HTTP-date form is honoured; a refused
token is not sent again until it reads differently (the poll thread no longer
exits); the client's timeout is a parameter so a silent endpoint is tested;
tests pin redirects(0), the two-window mapping, the slow-server race, and the
late poll against a rejection.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
usage_poll asks the subscription's usage endpoint when the seven_day
reading is 15 min old or older, maps five_hour and seven_day onto
PlanQuota with status polled, and honours Retry-After; failures wait,
log once per change of state, and never touch the cell.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
LeaseTurn {SelfRun, PersonaTurn} on LeaseCaller and LeaseCallerConfig; the unit derives from the turn; Busy is keyed (caller, turn); a Persona invocation leases in sequence as lease:<invocation>:<n>, one open at a time. config add-lease-caller and init take --turn self|persona.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The reservation and the replay claim are one write in the connector's
replay store; a failed ledger write runs nothing. Amounts are integer
micro-USD with checked arithmetic, and the service derives every cost from
usage and the configured price. One function, ProviderCall::charge, decides
the charge: a result bound to its request and caller pays its true cost with
a truthful overrun, anything else pays the reservation (ruling
spend-bills-on-identity-not-validity). Each caller has a spend ceiling over
fixed epoch-aligned windows in its root-owned config
(connector-spend-caller-window-ceiling); the admission window is monotonic,
so a clock stepping back cannot reopen budget, and a clock-locked caller is
refused ClockBehindAdmissionWindow (spend-window-clock-ahead-fails-closed).
Refusals CostBound, SpendCeiling and ClockBehindAdmissionWindow are typed.
Spec eureka-body:cut_spec:cut-connector-spend.r1; reports h1-h5;
Soul s5 holds (verdict eureka-body:verdict:cut-connector-spend.s5).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A ReasoningState item carries each provider block as raw bytes. The service
decides what is foreign: foreign state after the last user text is refused,
earlier foreign state is dropped before the backend and counted on the
receipt. Backends receive a ProviderCall that holds only what they may see,
and the service fills and checks the receipt's provider tag and drop count;
a refused result reaches the caller as a typed Provider failure, releases
its slot and replays on retry. transcript_items turns a completed result
into transcript items from the receipt, so callers never branch on provider.
Spec eureka-body:cut_spec:cut-connector-reasoning-item.r1; reports h1-h2;
Soul s2 holds (verdict eureka-body:verdict:cut-connector-reasoning-item.s2).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each frame is a cultnet.operation_request.v0 / operation_response.v0
(service gamecult.model.connector, operation invoke) over loopback
TcpFramed, carrying the kit's sealed per-caller envelope: named
MessagePack only, unknown fields refused, binary ciphertext, JSON Schema
published from the types (ruling connector-v3-wire-cultnet-operation).
v2 is deleted with its fixtures (ruling connector-v3-only). The request is
provider-neutral, with max_output_tokens required; failure kinds, stop
reasons and usage are typed, and Policy is three typed refusals. Golden
v3 frames pin the carriage and envelope.
Spec eureka-body:cut_spec:cut-connector-contract-v3.r2; reports h1-h2;
Soul s2 holds (verdict eureka-body:verdict:cut-connector-contract-v3.s2).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The v2 contract, encrypted envelope and framing, client, caller admission
and replay, and the serve loop move into the model-connector crate behind
one ProviderBackend trait, relicensed AGPL-3.0-only by the sole copyright
holder (ruling connector-kit-relicense-agpl). Same schema ids and wire bytes
as v2, pinned by golden fixtures generated from fd7cec4. The Codex backend
is not ported (ruling codex-connector-park).
Serve owns the frame bounds: it measures the sealed envelope, refuses
configurations that cannot deliver their payload bound, answers over-bound
payloads and over-long ids with v2 refusals, and never records or replays
an undeliverable result.
Spec eureka-body:cut_spec:cut-connector-kit-lift.r1; reports h1-h5;
Soul s5 holds (verdict eureka-body:verdict:cut-connector-kit-lift.s5).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>