roncho requirements: divergences by behaviour, checked at a9708f1

roncho moved twice while the requirements were written. Line numbers are
gone; each divergence is described by what the code does, rechecked at
a9708f1, which added the Workspaces API: O1 and O7 now name the async
functions, and workspace delete does not tell the 409 conflict apart.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-25 22:01:06 -07:00
co-authored by Claude Opus 5.5
parent ac0c369f76
commit a8c10f5f05
+34 -30
View File
@@ -2,8 +2,9 @@
**For:** the agent that develops `roncho` (`git.wntrmute.dev/kyle/roncho`, `~/src/roncho` on titan). **For:** the agent that develops `roncho` (`git.wntrmute.dev/kyle/roncho`, `~/src/roncho` on titan).
**From:** Boxmaker's design model, 2026-09-25, for milestone M5b. **Status:** requirements, for the **From:** Boxmaker's design model, 2026-09-25, for milestone M5b. **Status:** requirements, for the
owner to hand over. Boxmaker's M5b spec is written against the release this produces. Code owner to hand over. Boxmaker's M5b spec is written against the release this produces.
references are to `roncho` at `f24fc4a` ("Initial commit"). `roncho` was being reworked while this was written: the divergences in 3.4 were last checked at
`a9708f1` and are described by behaviour, not by line. Check each one before fixing it.
## 1. Why ## 1. Why
@@ -16,8 +17,8 @@ through `roncho`, not through a second client. Today `roncho` cannot be used fro
with threads, no async runtime, and `memoryd` is the smallest-authority daemon of the set. with threads, no async runtime, and `memoryd` is the smallest-authority daemon of the set.
- Some of its request and response shapes disagree with the live server. sift's Go client, - Some of its request and response shapes disagree with the live server. sift's Go client,
checked against rift on 2026-09-22, found that workspace search takes `{"query", "limit"}` and checked against rift on 2026-09-22, found that workspace search takes `{"query", "limit"}` and
returns a bare JSON array, not a `Page` (`~/src/sift/internal/fleetctx/fleetctx.go:115-147`, returns a bare JSON array, not a `Page` (`~/src/sift/internal/fleetctx/fleetctx.go`,
`~/src/sift/docs/P2.md:103-105`). `~/src/sift/docs/P2.md`).
- It defaults to `https://api.honcho.dev`. For Boxmaker, memory text must never leave the owner's - It defaults to `https://api.honcho.dev`. For Boxmaker, memory text must never leave the owner's
hosts, so a default that points at a cloud service is a hazard, not a convenience. hosts, so a default that points at a cloud service is a hazard, not a convenience.
@@ -28,11 +29,11 @@ the transport and the types: correct, small, and predictable.
| Fact | Value | Source | | Fact | Value | Source |
|---|---|---| |---|---|---|
| Honcho API | `http://rift.scylla-hammerhead.ts.net:8000`, plain HTTP over the tailnet | `imladris/hw/orion/default.nix:105`; `sift/docs/PLAN.md:38` | | Honcho API | `http://rift.scylla-hammerhead.ts.net:8000`, plain HTTP over the tailnet | `imladris/hw/orion/default.nix`; `sift/docs/PLAN.md` |
| Version | 3.2.0, image `3.2.0-pr1092-7e57fe2` (roncho's SPEC targets 3.2.1) | `imladris/docs/metrics-plan.md` | | Version | 3.2.0, image `3.2.0-pr1092-7e57fe2` (roncho's SPEC targets 3.2.1) | `imladris/docs/metrics-plan.md` |
| Authentication | apparently none: sift sends no `Authorization` header and succeeds. **Not confirmed.** | `sift/internal/fleetctx/fleetctx.go:117-127` | | Authentication | apparently none: sift sends no `Authorization` header and succeeds. **Not confirmed.** | `sift/internal/fleetctx/fleetctx.go` |
| Models | deriver, summaries and dialectic on dixie's `ornith-1.5-9b-uncensored`; dialectic answers take 30 to 50 s | `imladris/hw/dixie/default.nix`; `sift/docs/PLAN.md:236-237` | | Models | deriver, summaries and dialectic on dixie's `ornith-1.5-9b-uncensored`; dialectic answers take 30 to 50 s | `imladris/hw/dixie/default.nix`; `sift/docs/PLAN.md` |
| Workspaces in use | `hermes-fleet`, `guardian-star` (other agents'); each Boxmaker will have its own | `imladris/hw/orion/default.nix:106-107` | | Workspaces in use | `hermes-fleet`, `guardian-star` (other agents'); each Boxmaker will have its own | `imladris/hw/orion/default.nix` |
**Never write to a workspace you did not create for testing.** `hermes-fleet` and **Never write to a workspace you did not create for testing.** `hermes-fleet` and
`guardian-star` hold other agents' live memory. Write tests go to a throwaway workspace (for `guardian-star` hold other agents' live memory. Write tests go to a throwaway workspace (for
@@ -84,8 +85,8 @@ MUST: Boxmaker cannot use `roncho` without it. SHOULD: Boxmaker can work around
- **R11 (MUST)** The workspace is set explicitly per client. A client is cheap to clone and one - **R11 (MUST)** The workspace is set explicitly per client. A client is cheap to clone and one
client serves one workspace, as today. A client is `Send + Sync`. client serves one workspace, as today. A client is `Send + Sync`.
- **R12 (MUST)** The blocking client takes its configuration only from the caller. It reads no - **R12 (MUST)** The blocking client takes its configuration only from the caller. It reads no
environment variables: not `HONCHO_*` (today `build()` falls back to `HONCHO_WORKSPACE_ID` and environment variables: not `HONCHO_*` (today `build()` falls back to `HONCHO_WORKSPACE_ID`,
`HONCHO_API_KEY`, `src/client.rs:244-253`), not proxy settings (`HTTP_PROXY`, `ALL_PROXY` and so `HONCHO_API_KEY` and `HONCHO_BASE_URL`), not proxy settings (`HTTP_PROXY`, `ALL_PROXY` and so
on). It does not follow redirects: a 3xx is returned as an error. Memory text is sent only to on). It does not follow redirects: a 3xx is returned as an error. Memory text is sent only to
the configured host. the configured host.
- **R13 (MUST)** Timeouts are set by the caller, per client: a connect timeout, and a read - **R13 (MUST)** Timeouts are set by the caller, per client: a connect timeout, and a read
@@ -104,13 +105,13 @@ Each operation is verified against rift (3.4) before it is released. Names are s
| # | Operation | Honcho endpoint (as roncho has it today; verify) | Boxmaker's use | | # | Operation | Honcho endpoint (as roncho has it today; verify) | Boxmaker's use |
|---|---|---|---| |---|---|---|---|
| O1 | get or create the workspace | not in roncho at `f24fc4a`; find it in Honcho 3.2's docs | first start | | O1 | get or create the workspace | `POST /v3/workspaces` (in the async client as `get_or_create_workspace`) | first start |
| O2 | get or create a peer, with metadata and configuration | `POST peers` | the owner, the agent, other agents met in channels | | O2 | get or create a peer, with metadata and configuration | `POST peers` | the owner, the agent, other agents met in channels |
| O3 | get or create a session, with its peers and each peer's `observe_me` / `observe_others` | `POST sessions` | one Honcho session per Boxmaker session | | O3 | get or create a session, with its peers and each peer's `observe_me` / `observe_others` | `POST sessions` | one Honcho session per Boxmaker session |
| O4 | add messages in a batch, each with `peer_id`, `content`, `metadata` (a JSON object) and `created_at` | `POST sessions/{s}/messages` | the sync of finished turns; the metadata holds Boxmaker's session id, record number and labels | | O4 | add messages in a batch, each with `peer_id`, `content`, `metadata` (a JSON object) and `created_at` | `POST sessions/{s}/messages` | the sync of finished turns; the metadata holds Boxmaker's session id, record number and labels |
| O5 | list a session's messages, paged, with filters | `POST sessions/{s}/messages/list` | checking what a sync already sent | | O5 | list a session's messages, paged, with filters | `POST sessions/{s}/messages/list` | checking what a sync already sent |
| O6 | delete a session | `DELETE sessions/{s}` | rebuilding | | O6 | delete a session | `DELETE sessions/{s}` | rebuilding |
| O7 | delete the workspace, and report the "active sessions" conflict (409) as its own error, if Honcho has one | not in roncho at `f24fc4a` | rebuilding | | O7 | delete the workspace, and report the "active sessions" conflict (409) as its own error | `DELETE /v3/workspaces/{id}` (the async `delete_workspace` returns it as a generic error) | rebuilding |
| O8 | create conclusions in a batch (1 to 100), `content`, `observer_id`, `observed_id`, optional `session_id` | `POST conclusions` | entries moved out of identity; trusted notes | | O8 | create conclusions in a batch (1 to 100), `content`, `observer_id`, `observed_id`, optional `session_id` | `POST conclusions` | entries moved out of identity; trusted notes |
| O9 | list, query and delete conclusions | `POST conclusions/list`, `POST conclusions/query`, `DELETE conclusions/{id}` | rebuilding; checks | | O9 | list, query and delete conclusions | `POST conclusions/list`, `POST conclusions/query`, `DELETE conclusions/{id}` | rebuilding; checks |
| O10 | search the workspace, with a result limit | `POST search` (rift: `{"query", "limit"}` and a bare array) | `recall` | | O10 | search the workspace, with a result limit | `POST search` (rift: `{"query", "limit"}` and a bare array) | `recall` |
@@ -134,23 +135,26 @@ Each operation is verified against rift (3.4) before it is released. Names are s
may use `hermes-fleet`, writes never), and the result recorded in a compatibility document in may use `hermes-fleet`, writes never), and the result recorded in a compatibility document in
the repository: endpoint, method, request shape, response shape, the date, and the server's the repository: endpoint, method, request shape, response shape, the date, and the server's
version. Where Honcho's docs and rift disagree, rift wins and the document says so. version. Where Honcho's docs and rift disagree, rift wins and the document says so.
- **R20 (MUST)** Fix these, found reading the current code, in the async client too: - **R20 (MUST)** Fix these divergences, found by reading the async client; they apply to the
- search request and response shapes (O10, O11): rift takes `{"query", "limit"}` at the top blocking client too, and any fix to shared models or request code applies to both:
level and returns a bare array (sift, above). roncho's workspace search sends `{"query"}` with - **Search shapes (O10, O11).** rift takes `{"query", "limit"}` at the top level and answers
no limit and expects a `Page` (`src/api/workspace.rs:13-19`); peer and session search send with a bare array (sift, above). roncho's workspace search sends `{"query"}` with no limit, and
`{"filters": {"query"}}` and expect a `Page` (`src/api/peers.rs:174-184`, its peer and session searches send `{"filters": {"query"}}`; all three decode the answer as a
`src/api/sessions.rs:178-186`). `Page`. There is no way to set a limit.
- `list_messages` computes the `page`, `size` and `reverse` query but never sends it - **Paging of messages (O5).** `list_messages` builds the `page`, `size` and `reverse` query and
(`src/api/sessions.rs:110-120`), so a paged read can loop on the first page. never sends it, so a paged read can keep getting the first page.
- `Message.role` is required when decoding (`src/models/message.rs:5-16`); sift's verified field - **Message fields.** `Message.role` is required when decoding; sift's verified field list has no
list has no `role`. `role`. Make every field Boxmaker does not need optional, and check which fields rift sends.
- peer and session lists use `GET` (`src/api/peers.rs:23-28`, `src/api/sessions.rs:18-23`); - **List methods.** Peer and session lists use `GET`, while Honcho 3's other lists (messages,
Honcho 3's other lists are `POST …/list`. Settle on what rift does, and the same for conclusions, workspaces) are `POST …/list`. Settle on what rift does, and the same for
`peers/{p}/context` (`src/resources/peer.rs:136-141`). `peers/{p}/context`.
- the SSE reader splits each network chunk into lines on its own, so a line split across two - **Streaming.** The SSE reader splits each network chunk into lines on its own, so a line split
chunks is misparsed (`src/api/peers.rs:122-135`, `src/api/workspace.rs:107-120`). across two chunks is misparsed. Buffer until a newline.
- `build()` reports a missing workspace as `MissingApiKey` (`src/client.rs:244-248`). - **Build errors.** A missing workspace is reported as `MissingApiKey`, and a missing key is an
- `max_retries` is stored and never read (`src/client.rs:20`, `264`; R13). error at all (R10).
- **Retries.** `max_retries` is stored and never read (R13).
- **Workspace delete.** The "active sessions" conflict is not told apart from other failures
(O7, R18).
- **R21 (MUST)** Tests for the blocking client against a fake server in the test process - **R21 (MUST)** Tests for the blocking client against a fake server in the test process
(`std::net::TcpListener`), covering each O-operation's request bytes and response decoding, and (`std::net::TcpListener`), covering each O-operation's request bytes and response decoding, and
also: a refused connection, a server that sends nothing (read timeout), a server that stops also: a refused connection, a server that sends nothing (read timeout), a server that stops
@@ -185,7 +189,7 @@ and record what you found (or "not found") in the compatibility document. Do not
- Which turns are synced, trust per workspace, taint, sanitising text: Boxmaker's `memoryd`. - Which turns are synced, trust per workspace, taint, sanitising text: Boxmaker's `memoryd`.
- Queues and progress tracking of a sync: `memoryd` keeps its own. - Queues and progress tracking of a sync: `memoryd` keeps its own.
- A CLI. `roncho` has none at `f24fc4a`, and Boxmaker does not need one. - A CLI. Boxmaker does not need one.
## 5. Done when ## 5. Done when