Commit graph

48 commits

Author SHA1 Message Date
Meta Vens
e80e522c10 claude-connector meter: each refresh of the weekly reading logs the reading
State::Read carries the week window's permille and reset; report writes every
Read, so a day's meter delta is last minus first in the journal. Idle, Failed
and Unread keep once-per-change logging.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-11 22:04:07 +01:00
9d0f4b400c Merge pull request 'claude-connector ask: no-tools completion CLI' (#2) from eureka-substrate/notool-ask-cli into main 2026-11-11 08:15:48 +00:00
2a65c4e7a2 ask: the binary reads --system-file through the capped reader
main.rs still called read_to_string, leaving read_system_file dead. Binary-level
tests cover a FIFO, /dev/zero, 64KiB+1 and exactly 64KiB.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-11 08:14:44 +00:00
42a157b049 ask: guard key and system file reads, name stdin/stdout/connection causes, widen tests
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>
2026-11-11 08:10:53 +00:00
c47597b421 claude-connector: add ask, a no-tools completion CLI over ConnectorClient
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>
2026-11-11 07:56:08 +00:00
61cc59d9a0 Merge pull request 'Lease socket answers a usage readout' (#1) from eureka-body/lease-usage-readout into main 2026-11-06 22:55:17 +00:00
Meta Vens
0282244114 lease tests: rustfmt the renamed imports (Soul s2 test-imports-unformatted)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 23:55:01 +01:00
Hands
51982b7f63 lease readouts: a pool of their own, a refusal over it, the arm's promises pinned, the request type named for the lease
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>
2026-11-06 23:31:24 +01:00
Meta Vens
254cf83d9d lease readout tests: drop the integration test that needs a crate-private meter hook (the unit test owns it)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-06 22:59:12 +01:00
Meta Vens
8331859537 lease_v2: pin the usage readout request and answer frames
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-06 22:58:15 +01:00
Meta Vens
6e87cf2e6c lease socket: a usage readout from the one QuotaCell, no lease, no caller check, no token, no meter wake
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-06 22:55:06 +01:00
Meta Vens
549962cb8a quota meter: the weekly reading comes from the CLI's own rate-limit event; while a lease is live and the reading is stale the connector makes the smallest real call. The usage poll and its HTTP client go: the setup token can never reach that endpoint (squash of eureka-body/quota-meter-stream 7d4c1bf..c298d9d; Soul s4-s5)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 13:12:31 +01:00
Meta Vens
7d4c1bf56e usage-meter-poll: gate fixes: the timeout is read per request, serve has a refusal test, the RFC 850 guard is pinned
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>
2026-11-01 03:30:55 +01:00
Meta Vens
8fb8b5a71d usage-meter-poll: the serve test asks a loopback fake, never the provider (finding serve-test-asks-real-provider)
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>
2026-11-01 03:17:08 +01:00
Meta Vens
f242290ca5 usage-meter-poll: pin what the production client is built with (finding new-client-timeout-unpinned)
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>
2026-11-01 03:17:08 +01:00
Meta Vens
481428a7ce usage-meter-poll: Retry-After reads all three HTTP-date forms (finding retry-after-obsolete-date-forms)
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>
2026-11-01 03:17:08 +01:00
Meta Vens
e17ef16d48 usage-meter-poll: a subprocess test that serve --config starts the poll
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>
2026-11-01 02:49:16 +01:00
Meta Vens
c1cc349b19 usage-meter-poll: the cell decides how a reading combines; a poll is as old as its question
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>
2026-11-01 02:49:16 +01:00
Meta Vens
6982cbca7e usage-meter-poll: pin the log lines and the thread loop
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 01:44:35 +01:00
Meta Vens
7f3a46313e usage-meter-poll: test helper no longer shadowed by its own binding
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 01:37:29 +01:00
Meta Vens
9143d2c5e2 usage-meter-poll: serve_config starts the poll beside the leases
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 01:35:51 +01:00
Meta Vens
79792eea85 usage-meter-poll: the usage poll, the QuotaCell's second sensor
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>
2026-11-01 01:35:50 +01:00
Meta Vens
c1802d85be lease v2: committed byte goldens, rustfmt
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 05:38:48 +01:00
Meta Vens
cfea6854ab lease tests: the fake unit record is global, keep it on invocation 1
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 05:30:41 +01:00
Meta Vens
9f10887169 lease v2: byte goldens, hold-loop and lease-helper tests
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 05:27:38 +01:00
Meta Vens
9db62027eb connector-usage-only: comment
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 05:08:19 +01:00
Meta Vens
7d9a6392a7 connector-usage-only: comments
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 04:59:02 +01:00
Meta Vens
a828602649 connector-usage-only: drop a stray doc comment
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 04:54:14 +01:00
Meta Vens
bb8909f2c2 connector-usage-only: regenerate v4 goldens and schemas, format, fix tests
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 04:51:05 +01:00
Meta Vens
28f2e5d2e7 connector-usage-only: test import
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 04:49:29 +01:00
Meta Vens
dcb5f109f7 connector-usage-only: store-failure tests, README front door
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 04:48:24 +01:00
Meta Vens
af5da3dfaa connector-usage-only: test fixes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 04:44:45 +01:00
Meta Vens
702e903fdd connector-usage-only: fix serve test splice
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 04:44:01 +01:00
Meta Vens
06a47bb13f connector-usage-only: delete the dollar authorities (WIP, does not yet build)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 04:43:18 +01:00
Meta Vens
d2b82a6c50 lease-persona-callers: the identity bound keeps room for the Persona sequence
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 01:59:39 +01:00
Meta Vens
47a4dcc6b4 lease-persona-callers: model-connector lease callers take the turn
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 01:58:12 +01:00
Meta Vens
1bf9fdb437 lease-persona-callers: rustfmt
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 01:57:21 +01:00
Meta Vens
13cbdaf23c lease-persona-callers: a lease caller names its turn kind; Persona and Self of one caller lease side by side
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>
2026-10-31 01:56:34 +01:00
Meta Vens
fdcfa063c7 connector-many-callers: one connector serves every Mind as its own caller; session handles are an HMAC under a connector secret over caller, session, instance, instructions, model and transcript prefix; config add-caller/add-lease-caller; one owner for distinct admissions (squash of eureka-body/connector-many-callers d1f25b5..a96b276; Soul s1-s2)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 00:11:53 +01:00
Meta Vens
d1f25b5ae6 claude-self-run-lease: Self runs borrow the one Claude token over a unix socket bound to the peer's uid, its pidfd and its unit's InvocationID; the connector sets the reservation, settle bills reported per-model usage uncapped, no report bills the reservation (squash of eureka-body/claude-self-run-lease 480cf94..b5f26ef; Soul s1-s3)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 21:54:03 +01:00
480cf941c8 claude-turn-schema-quota: schema-typed Persona replies via --json-schema, token on fd 3 never in the child env, per-window plan-quota capture, communal spend readout, not-logged-in bills zero (squash of eureka-body/claude-turn-schema-quota e867fad..429b344; Soul s1, s2)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 20:18:35 +01:00
e867fad379 B4b1 claude-connector-binary: connector daemon over one CultCache config document; token from a systemd credential, pin before every spawn, private prompt dir, 401/403/429 door set, shared readiness for check and serve (squash of eureka-body/claude-connector-binary 200933f..67c7849; Soul s1, s2)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 12:59:23 +01:00
200933f7cf B4a claude-code-backend: Claude backend driving the unmodified claude binary on the operator's subscription; tool-less turns, per-turn usage, process-group kill (squash of eureka-body/claude-code-backend e0c0832..341be82; Soul s1, s2)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 11:03:03 +01:00
Meta Vens
e0c0832ae0 connector-spend (B3c): reserve-then-settle spend in the replay ledger, one charge owner, a windowed per-caller ceiling (squash of eureka-body/connector-spend 1d51e71..45d0927)
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>
2026-10-28 18:47:06 +01:00
Meta Vens
1d51e71ebf connector-reasoning-item (B3b): one opaque reasoning item per provider block; the service owns foreign state (squash of eureka-body/connector-reasoning-item bf958fc..d915f67)
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>
2026-10-28 13:31:06 +01:00
Meta Vens
bf958fc327 connector-contract-v3 (B3a): the v3 contract as typed documents over CultNet operations (squash of eureka-body/connector-contract-v3 ec0519d..a0a6ccb)
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>
2026-10-28 12:26:34 +01:00
Meta Vens
ec0519d9ff connector-kit-lift: the provider-neutral connector kit, lifted from CodexConnector fd7cec4 (squash of eureka-body/connector-kit-lift 1cf879f..ba1f7eb)
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>
2026-10-28 07:12:42 +01:00
1cf879f1e0 Initial commit: LICENSE and README front door
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 03:49:49 +01:00