1@README.md
2
3## Notes for agents
4
5- **No hosting words in here.** Never name Cloudflare, celld, wrangler, Durable Objects, R2/buckets or
6  `fetch`/`Request`/`Response` types in this crate, in code or docs, except to say that an adapter is not
7  this crate. The port is Whiskers' own; the adapter adapts to it, not the other way round. If a port
8  seems to need a host's concept, the port is mis-shaped: change the port's language, not its dependencies.
9- **Must build for `wasm32-unknown-unknown`.** No `std::fs`, `std::net`, `std::thread`, `SystemTime` or
10  `Instant`. Check with `cargo check --target wasm32-unknown-unknown -p whiskers-ports` inside
11  `nix develop ~/whiskers`. Dependencies stay at `serde`, `serde_json`, `log` and `whiskers-core`.
12- **`serde_json` has `preserve_order` on purpose.** Stored journal lines keep a device's key order, and
13  every JSON reply of the service is laid out the same on every backend. Do not remove the feature.
14- **A capability is a trait here, its laws in `whiskers-conformance` and its routes in `whiskers-service`.** Adding one touches all
15  three (the README's "Capabilities" section lists the steps). Never write a stand-in port to satisfy a bound, never add a
16  runtime "not configured" branch to a route for a capability the adapter may lack, and never put a new capability only in
17  `Backend`'s supertraits without a `Has…` trait of its own: an adapter must be able to hold it alone.
18- **A contract is a law in `whiskers-conformance`.** Changing a contract means changing its law in the same
19  commit; adding a port means adding its laws and running them against the in-memory adapter and the native
20  one. A law no adapter can fail proves nothing: keep the "caught" tests in that crate.
21- **Make the wrong thing unrepresentable.** Anything that arrives from outside gets a validated newtype with
22  a private field (`DeviceName`, `SafePictureId`, `SpeechLine`...). Errors are enums that say why; a string
23  goes in a `Diagnostic` and is never branched on. Add a variant rather than parse a message.
24- **Rules live in `whiskers-core` or here, not in adapters.** The merge rules, the window arithmetic
25  (`ThinkingLedger`), the day arithmetic (`VoiceDay`) and the page rule (`Page::of`) are shared on purpose:
26  an adapter decides where state is kept and how access is serialised, and adds nothing to the arithmetic.
27- **Logging** follows `crates/CLAUDE.md`: levelled lines, never content.
28- `whiskers-core` also has a `ports` module (`Model`, `Guard`, `Log`...): those are what a *device's*
29  conversation pipeline runs through. These are the *backend's*. They are different layers.