whiskers.git / crates / whiskers-ports / src / capability.rs

Capabilities: what a place Whiskers runs can offer, one small trait each.

An adapter is a type that holds some ports and says which it holds by implementing the Has… trait of each. Nothing obliges it to hold them all: the native binary holds every one, a Worker that serves only the hubs holds three. What is served is then a question the compiler answers. whiskers-service builds a route only on the capabilities it needs (Service::check requires HasJudge + HasClock, and an adapter without them cannot call it), and whiskers-conformance selects the laws of a capability only for an adapter that has it. There is no stand-in port and no "not configured" answer for a capability the adapter does not have: the route is not there.

Each trait names the port's type and hands out a reference to it. The ports are not boxed: an adapter is a build-time choice, and a Worker's futures cannot be Send, which a dyn with a Send bound would demand.

One household, one writer. Every stateful capability of one adapter must behave as if exactly one thing at a time writes a household's state. How is the adapter's business: natively, locks in one process; on Cloudflare, one Durable Object per household (single-threaded, so each merge is atomic by construction); under celld, the same object, owned by exactly one node at a time. An adapter whose stateful capabilities are not serialised together (the hubs on one writer, the allowance on another) is not an adapter: the conformance suite's concurrency checks exist to catch it.

[Backend] is the name for "every capability", for the adapter that is complete (the native binary).

23use crate::allowance::Allowance;
24use crate::embed::Embedder;
25use crate::hub::{ChatHub, HouseholdHub, MemoryHub};
26use crate::journal::Journal;
27use crate::judge::Judge;
28use crate::pictures::PictureShelf;
29use crate::think::Thinker;
30use crate::time::Clock;
31use crate::voice::Voice;

What Whiskers remembers.

34pub trait HasMemory {
35    type Memory: MemoryHub;
36    fn memory(&self) -> &Self::Memory;
37}

The grown-ups' choices and the day's time. Besides its own sync route, the routes that apply a policy (the thinking window, the voice cap, the usage screen) read the household's choices from it.

41pub trait HasHousehold {
42    type Household: HouseholdHub;
43    fn household(&self) -> &Self::Household;
44}

The one running session.

47pub trait HasChat {
48    type Chat: ChatHub;
49    fn chat(&self) -> &Self::Chat;
50}

The one append-only log of everything said.

53pub trait HasJournal {
54    type Journal: Journal;
55    fn journal(&self) -> &Self::Journal;
56}

The pictures that go with memories.

59pub trait HasPictures {
60    type Pictures: PictureShelf;
61    fn pictures(&self) -> &Self::Pictures;
62}

What may be spent: the thinking window and the day's voice characters.

65pub trait HasAllowance {
66    type Allowance: Allowance;
67    fn allowance(&self) -> &Self::Allowance;
68}

Jev's decisions.

71pub trait HasJudge {
72    type Judge: Judge;
73    fn judge(&self) -> &Self::Judge;
74}

Text to vectors.

77pub trait HasEmbedder {
78    type Embedder: Embedder;
79    fn embedder(&self) -> &Self::Embedder;
80}

The natural voice.

83pub trait HasVoice {
84    type Voice: Voice;
85    fn voice(&self) -> &Self::Voice;
86}

The language model.

89pub trait HasThinker {
90    type Thinker: Thinker;
91    fn thinker(&self) -> &Self::Thinker;
92}

The time.

95pub trait HasClock {
96    type Clock: Clock;
97    fn clock(&self) -> &Self::Clock;
98}

Every capability. There is nothing to implement: a type is a Backend exactly when it implements all the Has… traits, so a capability added to this list is a compile error in every adapter that claims to be complete, until it has it.

103pub trait Backend:
104    HasMemory
105    + HasHousehold
106    + HasChat
107    + HasJournal
108    + HasPictures
109    + HasAllowance
110    + HasJudge
111    + HasEmbedder
112    + HasVoice
113    + HasThinker
114    + HasClock
115{
116}
118impl<T> Backend for T where
119    T: HasMemory
120        + HasHousehold
121        + HasChat
122        + HasJournal
123        + HasPictures
124        + HasAllowance
125        + HasJudge
126        + HasEmbedder
127        + HasVoice
128        + HasThinker
129        + HasClock
130{
131}