jevcrates.git / jev-http / CLAUDE.md
1@README.md
2
3- **Never print, log or format the key.** To check that it arrived, print its
4  length. `Jev` holds it and only ever puts it in an `Authorization` header.
5- This crate is host-only, by design and by documentation, not by accident. A
6  wasm target must not depend on it; add the relay client beside it instead.
7- **`tokio::time::sleep` is in here, so nothing behind a hot-patch point may
8  call into this crate.** A subsecond patch gets its own copy of the process's
9  thread-locals, so patched code that touches a tokio runtime context finds
10  none (jevsnes `apps/native/CLAUDE.md`). Network I/O stays on the worker
11  thread; the decision logic that IS patchable touches none of it.
12- The retry policy is `jev-client`'s, over `jev-protocol::retry`. This crate
13  supplies only the ports (`HttpsTransport`, `TokioRuntime`); never add a
14  retry loop here, which would be a second policy beside that one.
15- **Never add a way to build a `Jev` without a `Ledger`.** `new`/`from_env`
16  are the only constructors and both require one, on purpose - see the
17  crate's own doc comment. A convenience constructor that skips it would be
18  a client that can spend without anything checking the rate guards or
19  seeing the vendor's out-of-credit answer.
20- **There is no lifetime cap, and none should be reintroduced.** Removed
21  2026-09-22 (the user's own ruling on an earlier, self-imposed `$4.00`/
22  `$4.50`: "not this random $4 number"). The only hard stop on
23  total spend is the vendor's own out-of-credit response
24  (`Refusal::OutOfCredit`); the per-minute and per-hour guards stay, but they
25  are RATE limits, not a budget - see the README's "There is no lifetime cap".
26- **`Ledger::window` re-reads and re-sums the whole file on every call, on
27  purpose.** A cached running total is a second piece of state that has to
28  agree with the log, and a cache that drifts toward "we have spent less
29  than we have" is exactly the failure this exists to prevent - see
30  `ledger.rs`'s own doc comment. Do not add a cache to make this faster
31  without re-reading that reasoning first.
32- **The ledger's own tests use `Ledger::at`, not `Ledger::open`.** `open`
33  reads `$XDG_STATE_HOME`, which every test in the process shares - a test
34  that used it would pollute the real ledger (and, worse, could seed the
35  opening estimate, `OPENING_ESTIMATE_USD`) the first time it ran on a
36  developer's machine.
37- **`ApiErrorKind::OutOfCredit`'s classification is a guess, not a
38  documented fact**, and this crate's out-of-credit flag rests on it. The
39  rule for correcting it is in `../jev-protocol/CLAUDE.md`.
40- **A hold is released only when nothing can have been billed** (`ask`'s
41  `nothing_billed`). After an interrupted or timed-out attempt the cost is
42  unknown, and the hold goes on counting its worst case.
43- **No guard may write a flag a human has to clear, except out-of-credit.**
44  The question bucket and the hour breaker are computed from the ledger's
45  own lines and heal as the window slides (see README, "Why the rate guards
46  heal themselves"). Do not reintroduce a pause file for them; a legacy
47  `paused.json` is not read by anything. `out-of-credit.json` is the one
48  flag, because waiting does not change it.
49- **Admission is check-and-hold under one `flock`** (`Ledger::admit`). A
50  check that reads the ledger and a write that happens later, outside the
51  lock, is the race that let two processes both see "29" and both ask.
52- **Guard logic takes `now` as an argument** (`Window::verdict`,
53  `Ledger::admit`, `Ledger::status`); the tests use a fake clock by passing
54  one. Keep `ledger::now()` calls at the edges (`Jev::ask`, `Jev::status`).