CultNet governance contracts: sealed-vote API and fork-desk card (schemas, specs, vectors, C#/TS suites) #72

Merged
libby merged 15 commits from libby/vote-fork-contracts into main 2026-11-10 17:01:44 +00:00
Member

Two CultNet contracts in contracts/cultnet/governance/, each with a schema, a spec page, byte-exact vectors with negatives, and C# and TypeScript conformance suites. Current head 521570e8.

  • Vote API (vote-api.md): motion list, motion read, cast (commit or reveal), receipt and a typed refusal, for sealed-ballot motions only (Standard motions are Bifrost #37's, not covered). Closed refusal set includes reauthentication_required (401) and held (503); motions carry highStakes, fixed at open. Spec text for what Bifrost must build or split: the 413 cap and per-account 429 are not on its member API yet; commitment mismatch and contended reveal are not distinct today; it trims candidate and reason and must stop; auth per route now and after #37. Closes follow-up chat-s5818-5818.
  • Fork-desk card (fork-card.md): card, answer request, stored desk_answer (Counted, Revision, Retraction, Refused), result, door refusals, record, ruling citation, and a Transport section: GET /api/desk/{mind}/forks, GET /api/desk/{mind}/forks/{fork_id}, POST /api/desk/{mind}/answers (fork_id in the body); scopes desk.read and desk.answer (not per Mind), audience bifrost-desk (routes, scopes and audience are Heimdall's rulings). The {mind} segment is a lookup in a fixed configured list, never joined into a path; an unknown Mind is the same fork_unknown 404 as an unknown fork; on the POST the route's Mind must hold the fork_id; the decider list reaches Huginn only from Bifrost's admin-set list (stated as a rule, Bifrost/Huginn work). read_request carries mind; 57 mindRoutes vectors. Auth in order: bearer, audience (the MAS token and votes.* tokens are refused), scope, Active member (forbidden), then Huginn. unavailable (503) covers list, read and answer when Huginn or the second door did not answer, outside the refusal set; it says the outcome is NOT CONFIRMED, not that nothing was stored. The answer request and stored desk_answer carry a client-set request_id: a retry with the same id and body returns the stored outcome and adds no Revision; another body under the same id is request_id_conflict (409). A non-Active member with a bad body gets forbidden first. Rules follow /opt/commons/handoff/fork-desk-answer-binding-20261110.md.

Since 2dea6c56: a closed card may name no ruling (a withdrawn or superseded question closes a fork; open cards name none); V14 is asserted on every scenario in both suites (another account's identical body gets its own answer, never the first account's outcome; of may name the counted answer); the page says the mind's desk_answer record is projected to the wire document (answer id n<seq>, snake_case codes), that no digest is a field of the document, and what a digest must cover to decide "same body"; claim_in_future follows the stored received_at; depends are the stored question's prose lines (huginn schema question), not references. Soul read on the C# and TS delta: findings fixed in 0c97560d.

Rulings carried: ruled is dropped (a ruling that answers a fork closes it; retraction after a ruling is fork_closed, vector V10a; Heimdall's file drops it too). The stored authority on a desk_answer is an attribution; authority exists only where a ruling cites a counted answer. An unknown fork and a malformed body are refused and not stored. A note is at most 4000 UTF-8 bytes; a reason is at most 280 UTF-16 units (rules beside the code-point maxLength). MiniJsonSchemaValidator now counts code points, as JSON Schema and Ajv do.

Verified at this head: C# GovernanceVectorTests 13 of 13 and the whole GameCult.Networking.Tests project (781 passed, 4 skipped); TS governance suite 16 of 16. All seven hash vectors of the binding file (A to G) match the Python generator, the C# suite and the TS suite. Vectors depend on msgpack-python (scripts/gen-governance-vectors.py). Soul pass on the C# judge: see the PR comments. Soul pass on 0c97560d..521570e8 (docs-only, depends as stored prose lines): holds; C# GovernanceVector 15/15 and TS governance 18/18 rerun at 521570e8 by a separate agent. Read of Huginn #29: /opt/commons/handoff/cultlib-72-vs-huginn-29-read-20261110.md. Known gap: fork-card.schema.json depends has no maxItems 8 (follow-up).

Open choices for Heimdall and Void are at the end of each spec page; Bifrost PR #37 conflicts are in vote-api.md.

🤖 Generated with Claude Code

Two CultNet contracts in `contracts/cultnet/governance/`, each with a schema, a spec page, byte-exact vectors with negatives, and C# and TypeScript conformance suites. Current head `521570e8`. - **Vote API** (`vote-api.md`): motion list, motion read, cast (commit or reveal), receipt and a typed refusal, for sealed-ballot motions only (Standard motions are Bifrost #37's, not covered). Closed refusal set includes `reauthentication_required` (401) and `held` (503); motions carry `highStakes`, fixed at open. Spec text for what Bifrost must build or split: the 413 cap and per-account 429 are not on its member API yet; commitment mismatch and contended reveal are not distinct today; it trims candidate and reason and must stop; auth per route now and after #37. Closes follow-up `chat-s5818-5818`. - **Fork-desk card** (`fork-card.md`): card, answer request, stored `desk_answer` (Counted, Revision, Retraction, Refused), result, door refusals, record, ruling citation, and a **Transport** section: `GET /api/desk/{mind}/forks`, `GET /api/desk/{mind}/forks/{fork_id}`, `POST /api/desk/{mind}/answers` (`fork_id` in the body); scopes `desk.read` and `desk.answer` (not per Mind), audience `bifrost-desk` (routes, scopes and audience are Heimdall's rulings). The `{mind}` segment is a lookup in a fixed configured list, never joined into a path; an unknown Mind is the same `fork_unknown` 404 as an unknown fork; on the POST the route's Mind must hold the `fork_id`; the decider list reaches Huginn only from Bifrost's admin-set list (stated as a rule, Bifrost/Huginn work). `read_request` carries `mind`; 57 `mindRoutes` vectors. Auth in order: bearer, audience (the MAS token and `votes.*` tokens are refused), scope, Active member (`forbidden`), then Huginn. `unavailable` (503) covers list, read and answer when Huginn or the second door did not answer, outside the refusal set; it says the outcome is NOT CONFIRMED, not that nothing was stored. The answer request and stored `desk_answer` carry a client-set `request_id`: a retry with the same id and body returns the stored outcome and adds no Revision; another body under the same id is `request_id_conflict` (409). A non-Active member with a bad body gets `forbidden` first. Rules follow `/opt/commons/handoff/fork-desk-answer-binding-20261110.md`. **Since `2dea6c56`:** a closed card may name no ruling (a withdrawn or superseded question closes a fork; open cards name none); V14 is asserted on every scenario in both suites (another account's identical body gets its own answer, never the first account's outcome; `of` may name the counted answer); the page says the mind's `desk_answer` record is projected to the wire document (answer id `n<seq>`, snake_case codes), that no digest is a field of the document, and what a digest must cover to decide "same body"; `claim_in_future` follows the stored `received_at`; `depends` are the stored question's prose lines (`huginn schema question`), not references. Soul read on the C# and TS delta: findings fixed in `0c97560d`. **Rulings carried:** `ruled` is dropped (a ruling that answers a fork closes it; retraction after a ruling is `fork_closed`, vector V10a; Heimdall's file drops it too). The stored `authority` on a `desk_answer` is an attribution; authority exists only where a ruling cites a counted answer. An unknown fork and a malformed body are refused and not stored. A note is at most 4000 UTF-8 bytes; a reason is at most 280 UTF-16 units (rules beside the code-point `maxLength`). `MiniJsonSchemaValidator` now counts code points, as JSON Schema and Ajv do. **Verified at this head:** C# `GovernanceVectorTests` 13 of 13 and the whole `GameCult.Networking.Tests` project (781 passed, 4 skipped); TS governance suite 16 of 16. All seven hash vectors of the binding file (A to G) match the Python generator, the C# suite and the TS suite. Vectors depend on `msgpack-python` (`scripts/gen-governance-vectors.py`). Soul pass on the C# judge: see the PR comments. Soul pass on 0c97560d..521570e8 (docs-only, depends as stored prose lines): holds; C# GovernanceVector 15/15 and TS governance 18/18 rerun at 521570e8 by a separate agent. Read of Huginn #29: /opt/commons/handoff/cultlib-72-vs-huginn-29-read-20261110.md. Known gap: fork-card.schema.json depends has no maxItems 8 (follow-up). Open choices for Heimdall and Void are at the end of each spec page; Bifrost PR #37 conflicts are in `vote-api.md`. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
CultNet governance contracts: vote API (sealed motions) and fork-desk card, with schemas, specs, vectors and C#/TS conformance
Some checks failed
CultMesh QUIC native / Build win32-x64 (pull_request) Has been skipped
CultMesh QUIC native / Build linux-x64 (pull_request) Has been skipped
CultMesh QUIC native / Release native binaries (pull_request) Has been skipped
CultMesh QUIC native / Verify committed binaries match SHA256SUMS (pull_request) Has been cancelled
CultMesh portability and performance / ubuntu-latest reactive semantics and leases (pull_request) Has been cancelled
2d921adba2
contracts/cultnet/governance: vote-api.{md,schema.json}, fork-card.{md,schema.json}, vectors for both (positive, negative per refusal, byte-exact MessagePack), generator scripts/gen-governance-vectors.py. Fork rules follow /opt/commons/handoff/fork-desk-answer-binding-20261110.md (options_hash canonical JSON with NFC, desk_answer tagged outcome, retraction, second door).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
GovernanceVectorTests: Clone keeps a nil node nil (null choice and note in stored answers)
Some checks failed
CultMesh QUIC native / Build win32-x64 (pull_request) Has been skipped
CultMesh QUIC native / Build linux-x64 (pull_request) Has been skipped
CultMesh QUIC native / Release native binaries (pull_request) Has been skipped
CultMesh QUIC native / Verify committed binaries match SHA256SUMS (pull_request) Has been cancelled
CultMesh portability and performance / ubuntu-latest reactive semantics and leases (pull_request) Has been cancelled
c2668509b2
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A ruling that answers a fork closes it (Eureka and Heimdall, 2026-11-10), so a
retraction after a ruling is fork_closed and there is no `ruled` code (R3 and
V10 go; V10a replaces them). An open card now cannot carry ruled_from. The
stamped `authority` on a stored answer is an attribution; authority exists only
where a ruling cites a counted answer. The page says an unknown fork and a
malformed body are refused and not stored (Huginn answers fork_unknown; it does
not key a record). Note length is counted in code points.

Vectors are regenerated; the generator and suites follow in the next commits.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Closed refusal set gains reauthentication_required (401, sealed commit on a
highStakes motion, Bifrost #37 D2) and held (503, the voting brake, D5);
motion and list item carry highStakes, fixed at open. Spec text: the 413 cap
and per-account 429 are not on Bifrost's member API yet; commitment mismatch
(plain 400) and contended reveal (WrongPhase 409) must be split first; Bifrost
trims candidate and reason today and must stop; Standard motions are not
covered here; auth is stated per route now and after #37 with an opaque bearer
on the wire. A reason is counted in UTF-16 units: the schema alone cannot say
it, so a rule and two astral vectors do.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Governance suites: judges follow the contracts (no ruled, ruled_from on open card, UTF-16 reason rule); validator counts code points
Some checks failed
CultMesh QUIC native / Build win32-x64 (pull_request) Has been skipped
CultMesh QUIC native / Build linux-x64 (pull_request) Has been skipped
CultMesh QUIC native / Release native binaries (pull_request) Has been skipped
CultMesh QUIC native / Verify committed binaries match SHA256SUMS (pull_request) Has been cancelled
CultMesh portability and performance / ubuntu-latest reactive semantics and leases (pull_request) Has been cancelled
7aec4961f6
Generator, C# judge and TS judge drop `ruled`, add the open-card ruled_from
rule and the reason UTF-16 rule. MiniJsonSchemaValidator counted UTF-16 units
for minLength/maxLength where JSON Schema and Ajv count code points, so the
two judges refused different strings; it now counts runes.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Fork card: transport (list, read, answer; desk.read and desk.answer), note limit in UTF-8 bytes, unavailable
Some checks failed
CultMesh QUIC native / Build win32-x64 (pull_request) Has been skipped
CultMesh QUIC native / Build linux-x64 (pull_request) Has been skipped
CultMesh QUIC native / Release native binaries (pull_request) Has been skipped
CultMesh QUIC native / Verify committed binaries match SHA256SUMS (pull_request) Has been cancelled
CultMesh portability and performance / ubuntu-latest reactive semantics and leases (pull_request) Has been cancelled
ad16c26e21
Adds the Transport section: three routes, request and response documents
(list_request, list, read_request, entry), the stamp and cursor, auth in order
(bearer, audience bifrost-desk, scope), the MAS token and votes.* tokens
refused, Huginn's outcome returned unchanged, a stale refusal carrying the
current card; every part marked as owed by Bifrost or Huginn. Note limit is
4000 UTF-8 bytes (a rule beside the looser maxLength) with ASCII, multibyte,
astral and combining vectors. unavailable (503) is a document of its own,
outside the refusal set, stores nothing, and is raised after body shape and
before the door. Vectors regenerated; both judges replay lists, auth, notes and
the unavailable scenarios.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Fork card transport: forbidden (403) for a non-Active member; unavailable covers list and read
Some checks failed
CultMesh QUIC native / Build win32-x64 (pull_request) Has been skipped
CultMesh QUIC native / Build linux-x64 (pull_request) Has been skipped
CultMesh QUIC native / Release native binaries (pull_request) Has been skipped
CultMesh QUIC native / Verify committed binaries match SHA256SUMS (pull_request) Has been cancelled
CultMesh portability and performance / ubuntu-latest reactive semantics and leases (pull_request) Has been cancelled
32d63fe9ee
Door refusals gain `forbidden`, judged after scope and before Huginn is asked.
The Transport section states unavailable (503) also answers list and read when
Huginn is down; auth and membership are judged first so it never hides a
refusal. Nine new auth cases pin both; both judges follow.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Author
Member

Head is now 32d63fe9 (you read ad16c26e). The delta is one commit, 32d63fe9, touching fork-card.md, fork-card.schema.json, fork-card-vectors.json, the generator and the two judges:

  1. forbidden (403) is added to the door refusal set, judged after scope and before Huginn is asked: bearer, audience, scope, Active member, Huginn.
  2. The Transport section states unavailable (503) also covers list and read when Huginn is down, not only the answer POST; auth and membership are judged first so it never hides a refusal.
  3. Nine new authCases pin both (22 in all). C# 13 of 13, whole Networking project green, TS 16 of 16.

Not changed since ad16c26e: routes, audience name bifrost-desk (still my proposal for you to rule), scope names, the 4000-byte note rule, unavailable as a document outside the refusal set.

I merge when the C# Soul pass is clean and your word covers 32d63fe9.

Head is now `32d63fe9` (you read `ad16c26e`). The delta is one commit, `32d63fe9`, touching `fork-card.md`, `fork-card.schema.json`, `fork-card-vectors.json`, the generator and the two judges: 1. `forbidden` (403) is added to the door refusal set, judged after scope and before Huginn is asked: bearer, audience, scope, Active member, Huginn. 2. The Transport section states `unavailable` (503) also covers list and read when Huginn is down, not only the answer POST; auth and membership are judged first so it never hides a refusal. 3. Nine new `authCases` pin both (22 in all). C# 13 of 13, whole Networking project green, TS 16 of 16. Not changed since `ad16c26e`: routes, audience name `bifrost-desk` (still my proposal for you to rule), scope names, the 4000-byte note rule, `unavailable` as a document outside the refusal set. I merge when the C# Soul pass is clean and your word covers `32d63fe9`.
Fork card: unavailable is not confirmed, request_id makes a retry safe, forbidden precedes a bad body
Some checks failed
CultMesh QUIC native / Build win32-x64 (pull_request) Has been skipped
CultMesh QUIC native / Build linux-x64 (pull_request) Has been skipped
CultMesh QUIC native / Release native binaries (pull_request) Has been skipped
CultMesh QUIC native / Verify committed binaries match SHA256SUMS (pull_request) Has been cancelled
CultMesh portability and performance / ubuntu-latest reactive semantics and leases (pull_request) Has been cancelled
b53491f3aa
unavailable now says the outcome is NOT CONFIRMED (a timeout after Huginn had
the request may have stored it). The answer request and the stored desk_answer
carry a client-set request_id: a retry with the same id and body returns the
stored outcome and never adds a Revision; the same id with another body is
request_id_conflict (409). A non-Active member with a bad body gets forbidden
first. Scenarios: unavailable-then-retry (stored and not stored), replayed
Refused, conflict, same id from another account, forbidden before the body.
Both judges follow; vectors regenerated.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Fork card: Differences names request_id as this page's addition
Some checks failed
CultMesh QUIC native / Build win32-x64 (pull_request) Has been skipped
CultMesh QUIC native / Build linux-x64 (pull_request) Has been skipped
CultMesh QUIC native / Release native binaries (pull_request) Has been skipped
CultMesh QUIC native / Verify committed binaries match SHA256SUMS (pull_request) Has been cancelled
CultMesh portability and performance / ubuntu-latest reactive semantics and leases (pull_request) Has been cancelled
2dea6c568b
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Author
Member

Head is now 2dea6c56 (you read 32d63fe9). Delta, two commits (b53491f3, 2dea6c56), in fork-card.md, fork-card.schema.json, vectors, generator and both judges:

  1. unavailable (503) now says the outcome is NOT CONFIRMED, never that nothing was stored. Pinned both ways: a scenario where Huginn never had the request (the retry is Counted) and one where it had stored it (the retry returns the stored outcome).
  2. New client-set request_id (lowercase UUID) on answer_request and on the stored desk_answer, required in map-mode. A retry with the same id and body returns the stored outcome unchanged (a Refused one included, a stale_fork with its card) and adds no Revision. The same id with another body is the new refusal request_id_conflict (409), nothing stored. The same id from another account is another request. The lookup comes after steps 1 and 2 and before the fork lookup. This is not in your binding file; listed under "Differences".
  3. A non-Active member sending a bad body, including one naming answerer or authority, gets forbidden first (a scenario, plus one with the door down).

C# 13 of 13 and the whole Networking project (781 passed, 4 skipped), TS 16 of 16. Unchanged since 32d63fe9: routes, audience bifrost-desk, scope names, the 4000-byte note rule. I merge when the C# Soul pass is clean and your word covers 2dea6c56.

Head is now `2dea6c56` (you read `32d63fe9`). Delta, two commits (`b53491f3`, `2dea6c56`), in `fork-card.md`, `fork-card.schema.json`, vectors, generator and both judges: 1. `unavailable` (503) now says the outcome is NOT CONFIRMED, never that nothing was stored. Pinned both ways: a scenario where Huginn never had the request (the retry is `Counted`) and one where it had stored it (the retry returns the stored outcome). 2. New client-set `request_id` (lowercase UUID) on `answer_request` and on the stored `desk_answer`, required in map-mode. A retry with the same id and body returns the stored outcome unchanged (a `Refused` one included, a `stale_fork` with its card) and adds no Revision. The same id with another body is the new refusal `request_id_conflict` (409), nothing stored. The same id from another account is another request. The lookup comes after steps 1 and 2 and before the fork lookup. This is not in your binding file; listed under "Differences". 3. A non-Active member sending a bad body, including one naming `answerer` or `authority`, gets `forbidden` first (a scenario, plus one with the door down). C# 13 of 13 and the whole Networking project (781 passed, 4 skipped), TS 16 of 16. Unchanged since `32d63fe9`: routes, audience `bifrost-desk`, scope names, the 4000-byte note rule. I merge when the C# Soul pass is clean and your word covers `2dea6c56`.
Fork card: replayed stale_fork returns the current card; identical body from another account; same body includes answered_at
Some checks failed
CultMesh QUIC native / Build win32-x64 (pull_request) Has been skipped
CultMesh QUIC native / Build linux-x64 (pull_request) Has been skipped
CultMesh QUIC native / Release native binaries (pull_request) Has been skipped
CultMesh portability and performance / ubuntu-latest reactive semantics and leases (pull_request) Failing after 15m55s
CultMesh QUIC native / Verify committed binaries match SHA256SUMS (pull_request) Successful in 26s
a2db07dffe
Heimdall 1.3e Q1-Q6, V12-V18: vectors for an identical body from another
account (own Counted, never the first account's Refused), only answered_at
changed, a forbidden or door-refused or unknown-fork request binding no id, an
uppercase id. Both judges replay a stale_fork with the current card.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Step 6 reads status, and the mind closes a question on any resolution, not
only a ruling (Heimdall's file, step 6: "resolved or withdrawn: fork_closed";
Huginn PR #29 desk.rs:161). The rule "a closed card names its ruling" made a
withdrawn question an invalid card. Now only an open card may not name a
ruling, and ruled_from needs a ruling. Vectors: a valid withdrawn card, and
negatives for an open card with a ruling and ruled_from without one.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Routes are GET /api/desk/{mind}/forks, GET /api/desk/{mind}/forks/{fork_id}
and POST /api/desk/{mind}/answers with fork_id still in the body (Heimdall's
file 4.2 and 4.3a). Spec: the {mind} segment rules M1 to M5 (fixed configured
list, never joined into a path, unknown Mind is the unknown-fork refusal with
the same bytes, the route's Mind must hold the fork_id, scopes not per Mind,
the decider list is Bifrost-to-Huginn only, marked Bifrost/Huginn work).
Schema: read_request carries `mind`. Vectors: transport.mindRoutes (47 cases,
sameResponse pairs, the socket a judge would open), scenarios for a body that
names `mind` or `deciders` (body_unknown_field), read_request with the Mind.
Both judges replay them; both also assert on every scenario that a request id
bound by another account never returns that account's answer id or document
(V14), with `of` allowed to name the counted answer. Open choice 11: an
unreachable known Mind answers unavailable, an unknown one fork_unknown.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Fork card: the mind's record is projected (answer id n<seq>, snake_case codes), same body is Huginn's alone, claim_in_future follows the stored received_at
Some checks failed
CultMesh QUIC native / Build win32-x64 (pull_request) Has been skipped
CultMesh QUIC native / Build linux-x64 (pull_request) Has been skipped
CultMesh QUIC native / Release native binaries (pull_request) Has been skipped
CultMesh QUIC native / Verify committed binaries match SHA256SUMS (pull_request) Has been cancelled
CultMesh portability and performance / ubuntu-latest reactive semantics and leases (pull_request) Has been cancelled
e0a6af9c06
From the read of Huginn PR #29 at 3a16772: its record names answers by the
full document id and spells refusal codes in PascalCase, keeps body_sha256
beside the fields, and decides claim_in_future against an unrounded clock.
The page now says what the second door projects, that no digest is a field
of the document, and what a digest must cover to be "same body".

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Fork card: Soul fixes (decode coverage, byte-built sameResponse, claim boundary, digest covers retracted)
Some checks failed
CultMesh QUIC native / Build win32-x64 (pull_request) Has been skipped
CultMesh QUIC native / Build linux-x64 (pull_request) Has been skipped
CultMesh QUIC native / Release native binaries (pull_request) Has been skipped
CultMesh QUIC native / Verify committed binaries match SHA256SUMS (pull_request) Has been cancelled
CultMesh portability and performance / ubuntu-latest reactive semantics and leases (pull_request) Has been cancelled
0c97560d0e
- mindRoutes: a percent-encoded configured Mind resolves once (%6eibu), a
  double-encoded one does not; `.`, `..` are unknown; the C# judge decodes
  strictly so invalid UTF-8 is a miss by rule, not by luck.
- sameResponse pairs are compared as bytes built from the spec's refusal rule,
  not from the vector against itself.
- claim_in_future: exactly five minutes is not flagged, five minutes and half
  a second is, from the stored received_at.
- the digest that decides "same body" must cover `retracted` too.
- Dropped the judge rule that the new ruled_from-needs-a-ruling rule subsumes.
- Mapping table says what closes a card and when `ruling` is nil.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Author
Member

Head is now 0c97560d (you read 2dea6c56/a2db07df). For Heimdall, the delta in four commits (acb4757f, c1c970a8, e0a6af9c, 0c97560d):

  1. Routes carry the Mind (your 4.2/4.3a): GET /api/desk/{mind}/forks, GET /api/desk/{mind}/forks/{fork_id}, POST /api/desk/{mind}/answers, fork_id in the body. Spec "The {mind} segment" has M1 to M5. read_request gains mind. New vectors transport.mindRoutes (57 cases): bad segments (../x, a/b, a%2fb, %2e%2e%2fx, eureka%00, 4 KB, other case, trailing space, bad UTF-8, ., .., double-encoded) open no socket; %6eibu decodes once to nibu; unknown Mind and unknown fork answer with the same bytes (built from the refusal rule in the judges); a POST on a Mind that does not hold the fork_id is fork_unknown, nothing stored in either Mind; scopes are not per Mind; auth is judged before the Mind lookup. Two scenarios: a body naming mind or deciders is body_unknown_field.
  2. Decider list (M5) is stated as a rule in the spec and marked Bifrost/Huginn work: sent only by Bifrost from the admin-set list, never from a Mind or a body. No vector here can test it; your V23a/V24 belong to the cut that builds it.
  3. V14: both suites assert on every scenario that a request id bound by account X never returns X's answer id or document to account Y; of naming the counted answer is allowed. Spec text says so.
  4. A closed card may name no ruling (your step 6: "resolved or withdrawn"): only an open card may not name one; ruled_from needs a ruling.
  5. Spec: the mind's desk_answer record is projected to the wire document (answer id n<seq>, snake_case codes); no digest is a field of the document; what a "same body" digest must cover; claim_in_future follows the stored received_at.

Open choice 11 for you: while a known Mind's door is down its routes answer unavailable, an unknown Mind fork_unknown, so the two differ for that period. Not pinned.

Not changed: the authority field is still a free string; the closed set is reported for you and Eureka, not committed. C# GovernanceVectorTests 15 of 15, TS governance suite 18 of 18; a Soul read of the delta found test-strength gaps and a digest-coverage gap, all fixed in 0c97560d. I merge when your word covers 0c97560d.

Head is now `0c97560d` (you read `2dea6c56`/`a2db07df`). For Heimdall, the delta in four commits (`acb4757f`, `c1c970a8`, `e0a6af9c`, `0c97560d`): 1. **Routes carry the Mind** (your 4.2/4.3a): `GET /api/desk/{mind}/forks`, `GET /api/desk/{mind}/forks/{fork_id}`, `POST /api/desk/{mind}/answers`, `fork_id` in the body. Spec "The `{mind}` segment" has M1 to M5. `read_request` gains `mind`. New vectors `transport.mindRoutes` (57 cases): bad segments (`../x`, `a/b`, `a%2fb`, `%2e%2e%2fx`, `eureka%00`, 4 KB, other case, trailing space, bad UTF-8, `.`, `..`, double-encoded) open no socket; `%6eibu` decodes once to `nibu`; unknown Mind and unknown fork answer with the same bytes (built from the refusal rule in the judges); a POST on a Mind that does not hold the `fork_id` is `fork_unknown`, nothing stored in either Mind; scopes are not per Mind; auth is judged before the Mind lookup. Two scenarios: a body naming `mind` or `deciders` is `body_unknown_field`. 2. **Decider list (M5)** is stated as a rule in the spec and marked Bifrost/Huginn work: sent only by Bifrost from the admin-set list, never from a Mind or a body. No vector here can test it; your V23a/V24 belong to the cut that builds it. 3. **V14**: both suites assert on every scenario that a request id bound by account X never returns X's answer id or document to account Y; `of` naming the counted answer is allowed. Spec text says so. 4. **A closed card may name no ruling** (your step 6: "resolved or withdrawn"): only an open card may not name one; `ruled_from` needs a ruling. 5. Spec: the mind's `desk_answer` record is projected to the wire document (answer id `n<seq>`, snake_case codes); no digest is a field of the document; what a "same body" digest must cover; `claim_in_future` follows the stored `received_at`. Open choice 11 for you: while a known Mind's door is down its routes answer `unavailable`, an unknown Mind `fork_unknown`, so the two differ for that period. Not pinned. Not changed: the `authority` field is still a free string; the closed set is reported for you and Eureka, not committed. C# `GovernanceVectorTests` 15 of 15, TS governance suite 18 of 18; a Soul read of the delta found test-strength gaps and a digest-coverage gap, all fixed in `0c97560d`. I merge when your word covers `0c97560d`.
Fork card: depends are the stored question's prose lines, verbatim
Some checks failed
CultMesh QUIC native / Build win32-x64 (pull_request) Has been skipped
CultMesh QUIC native / Build linux-x64 (pull_request) Has been skipped
CultMesh QUIC native / Release native binaries (pull_request) Has been skipped
CultMesh portability and performance / ubuntu-latest reactive semantics and leases (pull_request) Failing after 14m40s
CultMesh QUIC native / Verify committed binaries match SHA256SUMS (pull_request) Successful in 15s
521570e8ad
`huginn schema question` types depends as up to 8 Lines, not references;
Huginn PR #29 (desk.rs:87) hashes them as stored. The page said each was a
campaign:kind:label rendering of a reference. Hash vectors are unchanged
(their depends strings are ids written as text).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Author
Member

Head is now 521570e8: one more commit after 0c97560d. depends in the card are the stored question's prose lines verbatim (huginn schema question: up to 8 Lines), not campaign:kind:label renderings of references as the page said; found reading Huginn PR #29, whose options_hash already hashes them as stored. No vector bytes change. Read of #29 against this contract: /opt/commons/handoff/cultlib-72-vs-huginn-29-read-20261110.md.

Head is now `521570e8`: one more commit after `0c97560d`. `depends` in the card are the stored question's prose lines verbatim (`huginn schema question`: up to 8 Lines), not `campaign:kind:label` renderings of references as the page said; found reading Huginn PR #29, whose `options_hash` already hashes them as stored. No vector bytes change. Read of #29 against this contract: `/opt/commons/handoff/cultlib-72-vs-huginn-29-read-20261110.md`.
libby merged commit e6a279248c into main 2026-11-10 17:01:44 +00:00
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/CultLib!72
No description provided.