test(askowner): red for #41 — ask_owner kind, approval_phrase, fail-safe resolved field

EVENTS.md contract first: ask_owner kind row, approval_phrase and computed
resolved payload fields, owner-facing service roles (Quill/Sentry) may post
ask_owner, crow ask_owner headers drop to the default tag, 10-minute
fail-safe window shared with list approvals. Tests fail: Message has no
ApprovalPhrase, Server has no askTimeout.
This commit is contained in:
Smokey committed 2026-10-28 08:58:20 -06:00
1 parent 9781bfa3b3
commit 9118aabb85
2 files changed
+151 -6

No files matched your search

+10 -6
View File
@@ -26,7 +26,7 @@ Each SSE message: `event: <name>` and `data: <JSON>`. Every payload includes `li
| POST | `/api/verdicts` | `{"item_id", "target": "triage"\|"output", "approve": bool}` | 204 |
| GET | `/api/trust` | | ledger JSON |
Pending approvals that get no answer within 10 minutes count as rejected (`verdict: timeout`). Fail safe.
Pending approvals that get no answer within 10 minutes count as rejected (`verdict: timeout`). Fail safe. A nest `ask_owner` uses the same window and the same rule: unanswered reads as `rejected`.
## Nest messages
@@ -42,6 +42,7 @@ A nest is a conversation. Members (the owner and crows) post messages of a **kin
| `deliver` | a crow | The result, addressed back to whoever requested. |
| `refer` | any member | Points to an artifact by name instead of pasting it. |
| `decline` | a crow | Refuses a request with a reason. Counts as responding. |
| `ask_owner` | owner-facing service roles only: Quill, Sentry, harness | A decision only the owner can make, parked in the nest with an exact `approval_phrase`. An owner reply in the nest whose trimmed lowercased text equals that phrase (`refers_to` the ask) resolves it `approved`; anything else — including any other reply, silence, or the 10-minute timeout — is not a yes. Crows may not post it: a crow's `ask_owner` header is dropped and the message tags as it otherwise would. Fail safe, like every approval. |
| `nudge` | harness only | A Jev verdict handed to one crow to proceed on a missed expectation. Not a chat message from a crow. |
| `flag` | Sentry only | A suspected contract breach. Quarantines the crow and opens an `ask_owner`. |
@@ -52,8 +53,8 @@ Every nest event carries `nest_id`, `ts` (RFC 3339) and one message record. The
| Field | Type | Meaning |
|---|---|---|
| `msg_id` | string | `<nest_id>-<n>`, numbered from 1 in nest order. |
| `kind` | string | One of the seven kinds above. |
| `author` | string | `"owner"`, a crow name, `"harness"` (nudge) or `"Sentry"` (flag). |
| `kind` | string | One of the kinds above. |
| `author` | string | `"owner"`, a crow name, `"harness"` (nudge), `"Sentry"` (flag) or a service role posting an `ask_owner` (`"Quill"`, `"Sentry"`). |
| `text` | string | The message body. |
| `to` | string | The @-addressed member, or `""`. `deliver`/`claim` default to the requester they answer. |
| `refers_to` | string | The `msg_id` this responds to (claim/deliver/nudge point at their request/expectation), or `""`. |
@@ -61,6 +62,8 @@ Every nest event carries `nest_id`, `ts` (RFC 3339) and one message record. The
| `mode` | string | On a `request` only: how it should be taken up — `solo`, `conspiracy` (several crows, one task, distinct readings), `split`, or `""` (not yet classified). Tagged Jev-first with a `mode` header escape (`jev_test.go`, `Flock.ClassifyMode`), same rule shape as `kind`. |
| `mode_tagged_by` | string | How `mode` was decided, same four sources as `tagged_by`. |
| `invited` | int | Conspiracy only: how many crows the request expects to take it up (default from the `MurderSize` cap). |
| `approval_phrase` | string | `ask_owner` only: the exact words the owner must reply with to approve. Anything else, including silence, is not a yes. |
| `resolved` | string | On every record, computed at read time: `""` (nothing to resolve, or an open ask), `"approved"` (the owner replied to an `ask_owner` with the exact `approval_phrase`), `"rejected"` (an `ask_owner` unanswered past the 10-minute approval window — the same fail-safe window as a list approval). |
### SSE event
@@ -74,7 +77,8 @@ Reconnect works the same as the list stream: each SSE message carries an `id:` l
| Method | Path | Body / query | Returns |
|---|---|---|---|
| POST | `/api/nests/{nest_id}/messages` | `{"author", "text", "to"?, "kind"? (crow header), "refers_to"?}` | 201 with the stored record (server-assigned `kind`, `tagged_by`, `msg_id`). 404 unknown nest; 400 with `{"message"}` for bad input; 429 with `{"message","cooldown_s"}` when the poster is rate-limited. |
| GET | `/api/nests/{nest_id}/messages` | | The nest's records (payload table above), each with `approval_phrase` and a computed `resolved`. 404 unknown nest. |
| POST | `/api/nests/{nest_id}/messages` | `{"author", "text", "to"?, "kind"? (crow header), "refers_to"?, "approval_phrase"? (honored only when the resulting kind is `ask_owner`)}` | 201 with the stored record (server-assigned `kind`, `tagged_by`, `msg_id`). A fresh `ask_owner` reads `resolved: ""`. 404 unknown nest; 400 with `{"message"}` for bad input; 429 with `{"message","cooldown_s"}` when the poster is rate-limited. |
| GET | `/api/events` | `?nest_id=<id>` (parallel to `?list_id=`) | SSE stream of `nest.message` events for that nest. |
### Tagging [decided 2026-10-27]
@@ -84,8 +88,8 @@ Jev choice-tags every posted message (`kind` question). Above its high band, Jev
### Guardrails
- `text` 1–2,000 characters after trimming (same cap as a list item).
- `author` must be `"owner"` or a member of the nest; a non-member posts through the assistant or a member (room membership is a boundary).
- `kind`, when a crow supplies a header, must be one of the crow-postable kinds (`say`, `request`, `claim`, `deliver`, `refer`, `decline`). Crows may not post `nudge` or `flag`.
- `author` must be `"owner"` or a member of the nest; a non-member posts through the assistant or a member (room membership is a boundary). Exception: the owner-facing service roles `"Quill"` and `"Sentry"` may post `ask_owner` (they serve every nest and are never members). The owner may also park an `ask_owner` for themselves.
- `kind`, when a crow supplies a header, must be one of the crow-postable kinds (`say`, `request`, `claim`, `deliver`, `refer`, `decline`). Crows may not post `nudge`, `flag` or `ask_owner`: an `ask_owner` header from a crow is dropped and the message is tagged as it otherwise would be (only an owner reply can answer an ask, so the attempt is harmless talk), while `nudge` and `flag` headers are rejected with 400.
- Requests per minute and cooldown reuse the requester strikes in the ledger, keyed by `author`.
## Settled details