Mouth: fetch one named event's image for its Persona, store it, post an inert receipt (CHAT_FETCH, off by default) #73

Merged
heimdall merged 4 commits from eureka/mouth-fetch-attachment into main 2026-11-12 00:59:28 +00:00
Owner

What

The mouth fetches one named event's image for its Persona, verifies it, stores it, and posts an inert org.gamecult.file_received receipt as her, behind CHAT_FETCH=1 (off by default; off, the kind is answered as any unknown kind). Spec: eureka-body:cut_spec:cut-mouth-fetch-attachment.r7, with the sibling Huginn side cut-persona-save-attachment.r7 (not in this PR). Adds tests/fixtures/persona-chat-v7/, which Huginn copies as persona-chat-v9.

Review state

  • Heimdall read the cut 2026-11-12: right, with Lows; the Lows are folded in (store-failure log folded into the single fetch line with cause=, cause= and the isFetchId v3-room note documented, percent-encoding pinned by a mutant-checked test).
  • Soul: eureka-body:verdict:cut-mouth-fetch-attachment.s1, .s2, .s3 (reports h2, h3, h4).
  • Tests: full tests/ with a built CultLib: 343 tests, 336 pass, 7 fail; the same 7 fail at base 0d820fd (3 in cultmesh-bridge-commands, 4 in feedback-idunn-health), none in the mouth.
  • Open Lows, not fixed here: room-id and next_batch cursor encoding are unpinned by tests (guarded today by shape checks and the live joined_rooms match); isFetchId vs bare isMatrixId is Heimdall's call (kept; refuses v3-room event ids containing /, fail closed); the album root is the sender's claim (spec-sanctioned).

Ship (no deploy in this PR)

  • Flag off by default. Ships after M4 of root-list-mouth-runtime-20261111.md (Bifrost 0d820fd) as its own later mouth update, never rolled back below M4 while Huginn 6d6aea7 is installed.
  • Shipper: Eureka. Why: attachment fetch for Minds' sandboxes (Kiko 2026-11-11), specs r7, Heimdall's read 2026-11-12.
  • Order: deploy the mouth with CHAT_FETCH unset, then CHAT_FETCH=1, then Huginn's flag.
  • Readback: flag off, the unknown-kind answer; flag on, one fetch of a hash-bearing file in an album thread in a test room: one log line outcome=Stored receipt=posted and one org.gamecult.file_received thread reply from her user; in no thread, one plain event with m.reference = content.event_id.
  • Rollback: unset CHAT_FETCH, restart the mouth (the kind is unknown again); to the previous release 0d820fd if needed; no migration; receipts already in rooms stay (inert).

🤖 Generated with Claude Code

## What The mouth fetches one named event's image for its Persona, verifies it, stores it, and posts an inert `org.gamecult.file_received` receipt as her, behind `CHAT_FETCH=1` (off by default; off, the kind is answered as any unknown kind). Spec: `eureka-body:cut_spec:cut-mouth-fetch-attachment.r7`, with the sibling Huginn side `cut-persona-save-attachment.r7` (not in this PR). Adds `tests/fixtures/persona-chat-v7/`, which Huginn copies as persona-chat-v9. ## Review state - Heimdall read the cut 2026-11-12: right, with Lows; the Lows are folded in (store-failure log folded into the single fetch line with `cause=`, `cause=` and the isFetchId v3-room note documented, percent-encoding pinned by a mutant-checked test). - Soul: `eureka-body:verdict:cut-mouth-fetch-attachment.s1`, `.s2`, `.s3` (reports h2, h3, h4). - Tests: full `tests/` with a built CultLib: 343 tests, 336 pass, 7 fail; the same 7 fail at base 0d820fd (3 in cultmesh-bridge-commands, 4 in feedback-idunn-health), none in the mouth. - Open Lows, not fixed here: room-id and `next_batch` cursor encoding are unpinned by tests (guarded today by shape checks and the live joined_rooms match); `isFetchId` vs bare `isMatrixId` is Heimdall's call (kept; refuses v3-room event ids containing `/`, fail closed); the album root is the sender's claim (spec-sanctioned). ## Ship (no deploy in this PR) - Flag off by default. Ships after M4 of `root-list-mouth-runtime-20261111.md` (Bifrost 0d820fd) as its own later mouth update, never rolled back below M4 while Huginn 6d6aea7 is installed. - Shipper: Eureka. Why: attachment fetch for Minds' sandboxes (Kiko 2026-11-11), specs r7, Heimdall's read 2026-11-12. - Order: deploy the mouth with CHAT_FETCH unset, then `CHAT_FETCH=1`, then Huginn's flag. - Readback: flag off, the unknown-kind answer; flag on, one fetch of a hash-bearing file in an album thread in a test room: one log line `outcome=Stored receipt=posted` and one `org.gamecult.file_received` thread reply from her user; in no thread, one plain event with m.reference = content.event_id. - Rollback: unset `CHAT_FETCH`, restart the mouth (the kind is unknown again); to the previous release 0d820fd if needed; no migration; receipts already in rooms stay (inert). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
chat_fetch_request.v1 [request_id, persona, room, event_id] and chat_fetch_receipt.v1
[request_id, outcome, room_id, image, receipt] with a closed 14-word outcome enum. The mouth
reads live membership, the full room state, and the event itself; takes content.url from the
event; fetches through fetchImage (one optional deadline signal added); decides info.sha256
against the computed hash before images.put; posts the contract's org.gamecult.file_received
as her own user (thread reply, else plain m.reference), idempotence read from Matrix.
One 15 s deadline owns the fetch; throwIfAborted and released() are the first step inside the
gate, as send does. Event id, room, and the sender-controlled album root must be path-safe
Matrix ids or nothing is built from them. Golden fixtures persona-chat-v7.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The fetch-error and file-receipt-not-proven lines are gone: a failure folds into the one fetch line as cause=Class/status, never a message.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
GameCult/Bifrost!73
No description provided.