Commit graph

378 commits

Author SHA1 Message Date
Heimdall
bafbf84e19 Desk tests: after #71, the production door registers by default and the card is opaque
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-12 10:21:01 +00:00
Heimdall
0a1563f3b4 Fixtures: pin line endings of the sha256-pinned vectors and READMEs (Soul)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-12 10:19:12 +00:00
Heimdall
5e5a8ed3f2 Desk tests: census of every vector section, replayed or not judged by Bifrost
Each top-level section and each subsection down to depth 3 of the vendored vectors is classified: replayed by a named
test (which must exist) or not judged, with the owner of the rule named (CultLib validators, Huginn's door). A re-pin that
adds or drops a section fails until classified. Also replays transport.listInvalid on the wire: the door refuses a
negative count and passes the rules it does not hold.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-12 10:19:12 +00:00
Heimdall
36f3a3df60 Desk door: close Huginn's Answered, Forks and Fork wrapper maps
DeskResponse declares Answered { answer, counted_answer_id, as_of: u64 }, Forks { list, as_of: u64 } and
Fork { entry, as_of: u64 } (desk_wire.rs at b299d6f7; the golden replies carry exactly those keys). The door now
requires as_of as an unsigned integer and refuses any other key, like every other contract map. First red: the six
wrapper tests (missing, nil, negative, text, bool, array, object as_of; extra keys).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-12 10:19:12 +00:00
Heimdall
755e03d827 Desk door: the wire walker's Closed is the only owner of required keys
JsonRequired on DeskAnswerDocument.Answerer and ForkRecord.AnswererCount was a second owner of what Closed already
decides at the boundary; nothing the typed vector replays needed is lost (they now go through the door). Every key of
the list, entry, record and answer documents, taken from a real CultLib entry, is removed and nulled: a missing key, or a
nil where the contract has none, is a door failure. First red: the test that the typed records declare no required keys.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-12 10:19:12 +00:00
Heimdall
9fb9318b48 Desk door tests: a binary or invalid UTF-8 anywhere in a reply is a door failure
Pins bin in note, answerer, next_cursor, a card position (value, nil position, key name) and a record id, and 0xff 0xfe
as text in the same places, through list, read and answer. The door already refuses both (Walk's default branch throws
on Binary; the strict UTF-8 decoder throws on bad bytes), so no source changes: the mutants (Binary written as null;
StrictUtf8 = new(false,false)) go red.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-12 10:19:12 +00:00
Heimdall
cc24c861dc Desk tests: replay the vectors' wire bytes through the real UnixSocketDeskDoor
List pages (listScenarios and listShortPages), valid entries, scenario records, valid cards, valid stored answers
(withheld Revision and Retraction included), the entry and deskAnswer negatives and the resultsInvalid vectors are
served from responseHex / messagePackHex on a socket double and compared with the vector message as JSON text (keys,
key order, integers). The list pages also go through the HTTP edge for a decider and a non-decider. The typed
Deserialize replays and the FakeDeskDoor list replays they supersede are removed. Recorded in comments: what the door
judges (closed typed maps) and what it does not (the contract's rules).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-12 10:19:12 +00:00
Heimdall
38f3559780 Desk: re-vendor Huginn desk fixtures at b299d6f7 (71 files, CultLib 3a51bbab subdirectory) and CultLib vectors at d3025d3c
Pins name the commits, the exact file list and each sha256; the verifier is proved to fail on a changed byte, an
extra file and a missing file, at both directory levels. The four golden request frames still reproduce. The
synthetic card-viewers and proposed non-decider fragments are gone: both reader views are now CultLib's own entry
bytes served through the door. Huginn's record-whole still has no answerer_count (its README says so), so the
fault test stays true and is re-pointed at it.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-12 10:19:12 +00:00
Heimdall
83378e8edc Desk door: strict reply decoding (control characters, closed typed maps, duplicate keys, strict base64, no floats or binary)
MessagePack is walked into JSON by the reader, so every control character is escaped and keys, order and
integers survive. Every contract map (list, entry, record, answer, refusal) is closed and typed; list.mind must
equal the call's Mind; a key written twice anywhere, a float, a binary, trailing bytes, or non-canonical base64
is a DeskDoorException, as is every malformed variant (null elements, non-map values).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-12 10:19:12 +00:00
Heimdall
b1b871ce02 Desk: re-pin CultLib card contract 3a51bbab and Huginn desk-feed fixtures 79d954c
Vectors re-vendored byte for byte (sha256 13afdcba...); ForkRecord gains
answerer_count, DeskAnswerDocument.Answerer is nullable, both required keys
(a missing one is a door fault, never an invented 0 or nil). The card stays opaque.
Huginn fixtures at 79d954c with UUID deciders, synthetic/proposed view fragments.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-12 10:19:12 +00:00
Heimdall
6dca0fa7d4 Desk: UnixSocketDeskDoor, the production IDeskDoor over Huginn's desk socket
One connection per call, one request frame, one reply frame, 1 s deadline,
65536-byte bound each way. Request frames reproduce Huginn's golden bytes;
replies are decoded by key and every failure is one DeskDoorException (503).
Adds the MessagePack package for the wire codec.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-12 10:19:12 +00:00
Heimdall
bf7dcfe235 Desk: the card is an opaque JsonElement, not a typed ForkCard
CultLib is still changing gamecult.fork.card.v0 (raised_at). Bifrost reads and
edits nothing in it, so it passes through with every key, number and key order.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-12 10:18:59 +00:00
Heimdall
558fd372cf Vendor Huginn desk-feed golden fixtures (9dde93e) with a sha256 pin test
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-12 10:18:59 +00:00
d26aa50041 Docs: desk feed visibility is Huginn's door policy; cite the written door spec (#69) 2026-11-12 10:17:33 +00:00
4cb83971f9 Desk: bearer credential (OpenIddict validation, desk.read/desk.answer, audience bifrost-desk) and answerer masking (#71) 2026-11-12 10:17:29 +00:00
d4365a8364 Mouth: fetch one named event's image for its Persona, store it, post an inert receipt (CHAT_FETCH, off by default) (#73)
A Persona's Mind shell holds no Matrix token, so the mouth now keeps one named image for her: it reads her live membership and the room's full state, takes content.url from the fetched event only, checks info.sha256 against the hash it computed, stores the bytes in her image store and posts the inert org.gamecult.file_received receipt as her own user. Behind CHAT_FETCH (exactly 1), off by default; an off mouth answers the kind as UnknownKind. Not deployed by this merge.

Shipper: Eureka. Reviewed by Heimdall against cut-mouth-fetch-attachment.r7 (bundle 3a6b45d, then delta d4bccd4: one log line per fetch with a fixed cause=, event-id percent-encoding pinned, doc-only change to docs/bridge.md).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-12 00:59:28 +00:00
0d820fdc00 Mouth: id shape on every delivery field, mentions bounded in bytes, round cap counts every target GET (#72) 2026-11-11 21:06:13 +00:00
7231cdb977 Mouth: reply_to lows after #64 (round cap defers, 60 s excerpt, wider scrub, id shape) (#68) 2026-11-11 20:05:46 +00:00
f6a826b6e7 Desk feed design: per-Mind open forks, read-only (decisions in PR #37 section 14) (#67) 2026-11-11 17:06:45 +00:00
6acb4980b8 docs: how a Ratatoskr voting module authenticates to Bifrost (design) (#37) 2026-11-11 17:06:31 +00:00
e8e8fcc178 Docs: no refresh token, MAS skips userinfo; withdrawal stops new tokens, open sessions run to expiry (#66) 2026-11-11 16:48:27 +00:00
1da912d5e9 Members: approve refuses no-membership/unknown accounts; neutral text for legacy suspensions (#65) 2026-11-11 16:39:48 +00:00
e12b8e2298 Mouth: v4 fixes after Soul pass (target cache, scrub, read cap) (#64) 2026-11-11 16:17:09 +00:00
dc35c4a254 Mouth: chat_pending.v4 reply_to (flag, default off) (#63) 2026-11-11 16:06:28 +00:00
ab89556101 Chat sign-in needs a live consent receipt; notice frozen as version 1 (#59) 2026-11-11 14:32:06 +00:00
e8df60630e Prefix lengths: host-level startup tests (tests only) (#62) 2026-11-11 14:12:55 +00:00
7813426e6d Drop HTMX (unpkg, no integrity); guard against third-party assets (#61) 2026-11-11 14:12:51 +00:00
70a2038435 Suspension gaps: bootstrap, demotion, members-page notices, admin-only reason (#60) 2026-11-11 14:12:47 +00:00
1571bf3e32 Consent: optional at registration, a consent page, CSRF-guarded accept/withdraw, notice v2 (#58) 2026-11-11 12:11:02 +00:00
028bc2fdf6 Registration: sign-up form with proof-of-work and a no-JS time-lock fallback (#56) 2026-11-11 11:17:25 +00:00
b2e0bb2514 Mouth: tail_gaps on chat_pending.v3, the rooms whose tail is incomplete (#57) 2026-11-11 11:07:35 +00:00
09addd83d8 Docs: proposed training notice v2 and consent-flow gaps (#55) 2026-11-11 10:32:18 +00:00
33be966b7d Registration gates: proof-of-work CAPTCHA and training-notice consent receipt (#54) 2026-11-11 10:15:46 +00:00
fc8242f655 Suspension survives sign-in; admin-only Suspend/Unsuspend with a receipt (#53) 2026-11-11 08:38:09 +00:00
e8722d0abf Mouth: room tail on chat_pending.v3 (#51) 2026-11-11 08:15:38 +00:00
24f3deb88e OIDC issuer: chat tier for accounts without Active membership (#52) 2026-11-11 08:13:09 +00:00
5201508bdc OIDC issuer: address budget, token-row cap, scheduled prune, marker brake (#50) 2026-11-11 08:12:48 +00:00
be44a09d52 OIDC: refuse reserved localparts at authorize; gap list in oidc-issuer.md (#49) 2026-11-11 06:39:35 +00:00
1d0548313c Mouth: addressing facts on deliveries (chat_pending.v3 basis and form) (#48) 2026-11-11 06:26:30 +00:00
4e86c33cd2 Resolve CultLib via VOIDBOT_CULTLIB_ROOT in tests; test formerly indexed stores (#47) 2026-11-11 05:01:33 +00:00
68dee25e3a Drop indexes: declarations from TS document types (#46) 2026-11-11 04:53:55 +00:00
781e6eabf6 Desk: pin vectors to CultLib de8a062a (#45) 2026-11-11 02:16:28 +00:00
05dcceb203 Desk: a stale answer on an oversize fork is 422 fork_too_large (#44) 2026-11-11 01:54:04 +00:00
815304568f Desk: pin vectors to CultLib f6c9bf5f (#43) 2026-11-11 01:49:37 +00:00
8385eca00f Desk: a read of an oversize fork is 422 fork_too_large (#42) 2026-11-11 01:35:07 +00:00
7e9ba5796b Desk: the fork desk's Bifrost half (#40) 2026-11-11 01:02:36 +00:00
12a153f66f Mill votes: ranked, paged read and not-yet-voted-by-this-network filter (#41) 2026-11-10 21:06:56 +00:00
73c6f50440 persona mouth: open a direct room for a Persona; answer unknown kinds loudly (#39) 2026-11-10 18:35:51 +00:00
752cd66686 deploy plan: restore reads a postgres-readable copy of the root-only dump (#38) 2026-11-10 18:28:31 +00:00
1a3fa02373 Merge pull request 'Reserve Matrix localparts and system names at identity creation' (#34) from heimdall/reserved-identities into main 2026-11-10 17:32:16 +00:00