From a2db07dffead0dc0428c0e0b2af6098e295c9627 Mon Sep 17 00:00:00 2001 From: soul Date: Tue, 10 Nov 2026 15:43:31 +0000 Subject: [PATCH] Fork card: replayed stale_fork returns the current card; identical body from another account; same body includes answered_at 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 --- .../cultnet/governance/fork-card-vectors.json | 1058 ++++++++++++++++- contracts/cultnet/governance/fork-card.md | 3 +- .../test/governance-vectors.test.ts | 4 +- scripts/gen-governance-vectors.py | 12 +- .../GovernanceVectorTests.cs | 4 +- 5 files changed, 1072 insertions(+), 9 deletions(-) diff --git a/contracts/cultnet/governance/fork-card-vectors.json b/contracts/cultnet/governance/fork-card-vectors.json index 2b72e188..783e17f7 100644 --- a/contracts/cultnet/governance/fork-card-vectors.json +++ b/contracts/cultnet/governance/fork-card-vectors.json @@ -1127,6 +1127,24 @@ }, "messagePackHex": "87AD736368656D6156657273696F6EBF67616D6563756C742E666F726B2E616E737765725F726571756573742E7630A7666F726B5F6964D92867616D6563756C742D636861743A7175657374696F6E3A736C6F742D6D61726B2D636F6E73656E74AC6F7074696F6E735F68617368D94037643935666338376435333234323036313166653431356331646566323761333434373631376262363832333566343665336166313330616561333631633438A6616E7377657282A663686F696365A26E6FA46E6F7465D9524B656570206974206C6F63616C3A206120736C6F74206D61726B2069732074686520617574686F7227732063616C6C2C20616E642073686172696E672069742069732061207365706172617465206163742EA9726574726163746564C2A87265747261637473C0AB616E7377657265645F6174B4323032362D31312D31325431393A30323A30305A" }, + { + "name": "request_id_uppercase", + "why": "request_id is lowercase", + "message": { + "schemaVersion": "gamecult.fork.answer_request.v0", + "fork_id": "gamecult-chat:question:slot-mark-consent", + "options_hash": "7d95fc87d532420611fe415c1def27a3447617bb68235f46e3af130aea361c48", + "answer": { + "choice": "no", + "note": "Keep it local: a slot mark is the author's call, and sharing it is a separate act." + }, + "retracted": false, + "retracts": null, + "answered_at": "2026-11-12T19:02:00Z", + "request_id": "0000000A-0000-4000-8000-00000000000B" + }, + "messagePackHex": "88AD736368656D6156657273696F6EBF67616D6563756C742E666F726B2E616E737765725F726571756573742E7630A7666F726B5F6964D92867616D6563756C742D636861743A7175657374696F6E3A736C6F742D6D61726B2D636F6E73656E74AC6F7074696F6E735F68617368D94037643935666338376435333234323036313166653431356331646566323761333434373631376262363832333566343665336166313330616561333631633438A6616E7377657282A663686F696365A26E6FA46E6F7465D9524B656570206974206C6F63616C3A206120736C6F74206D61726B2069732074686520617574686F7227732063616C6C2C20616E642073686172696E672069742069732061207365706172617465206163742EA9726574726163746564C2A87265747261637473C0AB616E7377657265645F6174B4323032362D31312D31325431393A30323A30305AAA726571756573745F6964D92430303030303030412D303030302D343030302D383030302D303030303030303030303042" + }, { "name": "request_id_not_a_uuid", "why": "request_id is a lowercase D-format UUID", @@ -6612,7 +6630,7 @@ "recordHex": "85AD736368656D6156657273696F6EB767616D6563756C742E666F726B2E7265636F72642E7630A7666F726B5F6964D92867616D6563756C742D636861743A7175657374696F6E3A736C6F742D6D61726B2D636F6E73656E74AC6F7074696F6E735F68617368D94037643935666338376435333234323036313166653431356331646566323761333434373631376262363832333566343665336166313330616561333631633438B1636F756E7465645F616E737765725F6964A26E31A7616E737765727391DE0010AD736368656D6156657273696F6EB767616D6563756C742E6465736B5F616E737765722E7630A9616E737765725F6964A26E31A7666F726B5F6964D92867616D6563756C742D636861743A7175657374696F6E3A736C6F742D6D61726B2D636F6E73656E74A76F7574636F6D65A7436F756E746564A26F66C0A87265747261637473C0A4636F6465C0AC6F7074696F6E735F68617368D94037643935666338376435333234323036313166653431356331646566323761333434373631376262363832333566343665336166313330616561333631633438A663686F696365A26E6FA46E6F7465D9524B656570206974206C6F63616C3A206120736C6F74206D61726B2069732074686520617574686F7227732063616C6C2C20616E642073686172696E672069742069732061207365706172617465206163742EAB616E7377657265645F6174B4323032362D31312D31325431393A30323A30305AAB72656365697665645F6174B4323032362D31312D31325431393A30323A30355AAF636C61696D5F696E5F667574757265C2A8616E737765726572D92465306431633262332D613439352D343638372D383837392D366135623463336432653166A9617574686F72697479A84F70657261746F72AA726571756573745F6964D92430303030303030312D303030302D343030302D383030302D303030303030303030303031" }, { - "name": "a_refused_answer_replays_its_refusal_with_the_card_it_carried", + "name": "Q1_a_replayed_stale_fork_returns_the_CURRENT_card_and_stores_nothing_new", "card": { "schemaVersion": "gamecult.fork.card.v0", "fork_id": "gamecult-chat:question:slot-mark-consent", @@ -6726,6 +6744,46 @@ } } }, + { + "kind": "card", + "body": null, + "server": null, + "response": null, + "card": { + "schemaVersion": "gamecult.fork.card.v0", + "fork_id": "gamecult-chat:question:slot-mark-consent", + "title": "Slot mark consent (revised)", + "context": "Should a slot mark be shared?", + "options": [ + { + "id": "yes", + "text": "Share it." + }, + { + "id": "no", + "text": "Keep it local." + } + ], + "recommendation": "no", + "depends": [ + "gamecult-chat:question:file-zone-audience" + ], + "leans": null, + "flag": null, + "raised_in": { + "kind": "CutSpec", + "id": "cultlib-gaps:cut_spec:cut-slot-tolerance.r4" + }, + "deciders": [ + "e0d1c2b3-a495-4687-8879-6a5b4c3d2e1f" + ], + "status": "open", + "ruling": null, + "ruled_from": [], + "order": 3, + "options_hash": "e7696ae1d487f78b5dc99fb8ccbd684d6e6f1ea7d7e190c21f3c6b4d8c42aaf7" + } + }, { "kind": "answer", "body": { @@ -6770,7 +6828,7 @@ "card": { "schemaVersion": "gamecult.fork.card.v0", "fork_id": "gamecult-chat:question:slot-mark-consent", - "title": "Slot mark consent", + "title": "Slot mark consent (revised)", "context": "Should a slot mark be shared?", "options": [ { @@ -6799,7 +6857,7 @@ "ruling": null, "ruled_from": [], "order": 3, - "options_hash": "7d95fc87d532420611fe415c1def27a3447617bb68235f46e3af130aea361c48" + "options_hash": "e7696ae1d487f78b5dc99fb8ccbd684d6e6f1ea7d7e190c21f3c6b4d8c42aaf7" } } } @@ -6807,7 +6865,7 @@ "record": { "schemaVersion": "gamecult.fork.record.v0", "fork_id": "gamecult-chat:question:slot-mark-consent", - "options_hash": "7d95fc87d532420611fe415c1def27a3447617bb68235f46e3af130aea361c48", + "options_hash": "e7696ae1d487f78b5dc99fb8ccbd684d6e6f1ea7d7e190c21f3c6b4d8c42aaf7", "counted_answer_id": null, "answers": [ { @@ -6830,7 +6888,997 @@ } ] }, - "recordHex": "85AD736368656D6156657273696F6EB767616D6563756C742E666F726B2E7265636F72642E7630A7666F726B5F6964D92867616D6563756C742D636861743A7175657374696F6E3A736C6F742D6D61726B2D636F6E73656E74AC6F7074696F6E735F68617368D94037643935666338376435333234323036313166653431356331646566323761333434373631376262363832333566343665336166313330616561333631633438B1636F756E7465645F616E737765725F6964C0A7616E737765727391DE0010AD736368656D6156657273696F6EB767616D6563756C742E6465736B5F616E737765722E7630A9616E737765725F6964A26E31A7666F726B5F6964D92867616D6563756C742D636861743A7175657374696F6E3A736C6F742D6D61726B2D636F6E73656E74A76F7574636F6D65A752656675736564A26F66C0A87265747261637473C0A4636F6465AA7374616C655F666F726BAC6F7074696F6E735F68617368D94031346238666662646236313130366462633036663639663366633865323037326166376132303564373636653463633034306538393733333031336435346463A663686F696365A26E6FA46E6F7465D9524B656570206974206C6F63616C3A206120736C6F74206D61726B2069732074686520617574686F7227732063616C6C2C20616E642073686172696E672069742069732061207365706172617465206163742EAB616E7377657265645F6174B4323032362D31312D31325431393A30323A30305AAB72656365697665645F6174B4323032362D31312D31325431393A30323A30355AAF636C61696D5F696E5F667574757265C2A8616E737765726572D92465306431633262332D613439352D343638372D383837392D366135623463336432653166A9617574686F72697479A84F70657261746F72AA726571756573745F6964D92430303030303030372D303030302D343030302D383030302D303030303030303030303037" + "recordHex": "85AD736368656D6156657273696F6EB767616D6563756C742E666F726B2E7265636F72642E7630A7666F726B5F6964D92867616D6563756C742D636861743A7175657374696F6E3A736C6F742D6D61726B2D636F6E73656E74AC6F7074696F6E735F68617368D94065373639366165316434383766373862356463393966623863636264363834643665366631656137643765313930633231663363366234643863343261616637B1636F756E7465645F616E737765725F6964C0A7616E737765727391DE0010AD736368656D6156657273696F6EB767616D6563756C742E6465736B5F616E737765722E7630A9616E737765725F6964A26E31A7666F726B5F6964D92867616D6563756C742D636861743A7175657374696F6E3A736C6F742D6D61726B2D636F6E73656E74A76F7574636F6D65A752656675736564A26F66C0A87265747261637473C0A4636F6465AA7374616C655F666F726BAC6F7074696F6E735F68617368D94031346238666662646236313130366462633036663639663366633865323037326166376132303564373636653463633034306538393733333031336435346463A663686F696365A26E6FA46E6F7465D9524B656570206974206C6F63616C3A206120736C6F74206D61726B2069732074686520617574686F7227732063616C6C2C20616E642073686172696E672069742069732061207365706172617465206163742EAB616E7377657265645F6174B4323032362D31312D31325431393A30323A30305AAB72656365697665645F6174B4323032362D31312D31325431393A30323A30355AAF636C61696D5F696E5F667574757265C2A8616E737765726572D92465306431633262332D613439352D343638372D383837392D366135623463336432653166A9617574686F72697479A84F70657261746F72AA726571756573745F6964D92430303030303030372D303030302D343030302D383030302D303030303030303030303037" + }, + { + "name": "V13_only_answered_at_changed_is_request_id_conflict", + "card": { + "schemaVersion": "gamecult.fork.card.v0", + "fork_id": "gamecult-chat:question:slot-mark-consent", + "title": "Slot mark consent", + "context": "Should a slot mark be shared?", + "options": [ + { + "id": "yes", + "text": "Share it." + }, + { + "id": "no", + "text": "Keep it local." + } + ], + "recommendation": "no", + "depends": [ + "gamecult-chat:question:file-zone-audience" + ], + "leans": null, + "flag": null, + "raised_in": { + "kind": "CutSpec", + "id": "cultlib-gaps:cut_spec:cut-slot-tolerance.r4" + }, + "deciders": [ + "e0d1c2b3-a495-4687-8879-6a5b4c3d2e1f" + ], + "status": "open", + "ruling": null, + "ruled_from": [], + "order": 3, + "options_hash": "7d95fc87d532420611fe415c1def27a3447617bb68235f46e3af130aea361c48" + }, + "optionsHash": "7d95fc87d532420611fe415c1def27a3447617bb68235f46e3af130aea361c48", + "steps": [ + { + "kind": "answer", + "body": { + "schemaVersion": "gamecult.fork.answer_request.v0", + "fork_id": "gamecult-chat:question:slot-mark-consent", + "options_hash": "7d95fc87d532420611fe415c1def27a3447617bb68235f46e3af130aea361c48", + "answer": { + "choice": "no", + "note": "Keep it local: a slot mark is the author's call, and sharing it is a separate act." + }, + "retracted": false, + "retracts": null, + "answered_at": "2026-11-12T19:02:00Z", + "request_id": "00000001-0000-4000-8000-000000000001" + }, + "server": { + "answer_id": "n1", + "answerer": "e0d1c2b3-a495-4687-8879-6a5b4c3d2e1f", + "authority": "Operator", + "received_at": "2026-11-12T19:02:05Z" + }, + "response": { + "schemaVersion": "gamecult.fork.answer_result.v0", + "answer": { + "schemaVersion": "gamecult.desk_answer.v0", + "answer_id": "n1", + "fork_id": "gamecult-chat:question:slot-mark-consent", + "outcome": "Counted", + "of": null, + "retracts": null, + "code": null, + "options_hash": "7d95fc87d532420611fe415c1def27a3447617bb68235f46e3af130aea361c48", + "choice": "no", + "note": "Keep it local: a slot mark is the author's call, and sharing it is a separate act.", + "answered_at": "2026-11-12T19:02:00Z", + "received_at": "2026-11-12T19:02:05Z", + "claim_in_future": false, + "answerer": "e0d1c2b3-a495-4687-8879-6a5b4c3d2e1f", + "authority": "Operator", + "request_id": "00000001-0000-4000-8000-000000000001" + }, + "card": null + } + }, + { + "kind": "answer", + "body": { + "schemaVersion": "gamecult.fork.answer_request.v0", + "fork_id": "gamecult-chat:question:slot-mark-consent", + "options_hash": "7d95fc87d532420611fe415c1def27a3447617bb68235f46e3af130aea361c48", + "answer": { + "choice": "no", + "note": "Keep it local: a slot mark is the author's call, and sharing it is a separate act." + }, + "retracted": false, + "retracts": null, + "answered_at": "2026-11-12T19:03:00Z", + "request_id": "00000001-0000-4000-8000-000000000001" + }, + "server": { + "answer_id": "n9", + "answerer": "e0d1c2b3-a495-4687-8879-6a5b4c3d2e1f", + "authority": "Operator", + "received_at": "2026-11-12T19:02:05Z" + }, + "response": { + "schemaVersion": "gamecult.fork.refusal.v0", + "code": "request_id_conflict", + "error": "request_id_conflict: this request_id was used for a different body" + } + } + ], + "record": { + "schemaVersion": "gamecult.fork.record.v0", + "fork_id": "gamecult-chat:question:slot-mark-consent", + "options_hash": "7d95fc87d532420611fe415c1def27a3447617bb68235f46e3af130aea361c48", + "counted_answer_id": "n1", + "answers": [ + { + "schemaVersion": "gamecult.desk_answer.v0", + "answer_id": "n1", + "fork_id": "gamecult-chat:question:slot-mark-consent", + "outcome": "Counted", + "of": null, + "retracts": null, + "code": null, + "options_hash": "7d95fc87d532420611fe415c1def27a3447617bb68235f46e3af130aea361c48", + "choice": "no", + "note": "Keep it local: a slot mark is the author's call, and sharing it is a separate act.", + "answered_at": "2026-11-12T19:02:00Z", + "received_at": "2026-11-12T19:02:05Z", + "claim_in_future": false, + "answerer": "e0d1c2b3-a495-4687-8879-6a5b4c3d2e1f", + "authority": "Operator", + "request_id": "00000001-0000-4000-8000-000000000001" + } + ] + }, + "recordHex": "85AD736368656D6156657273696F6EB767616D6563756C742E666F726B2E7265636F72642E7630A7666F726B5F6964D92867616D6563756C742D636861743A7175657374696F6E3A736C6F742D6D61726B2D636F6E73656E74AC6F7074696F6E735F68617368D94037643935666338376435333234323036313166653431356331646566323761333434373631376262363832333566343665336166313330616561333631633438B1636F756E7465645F616E737765725F6964A26E31A7616E737765727391DE0010AD736368656D6156657273696F6EB767616D6563756C742E6465736B5F616E737765722E7630A9616E737765725F6964A26E31A7666F726B5F6964D92867616D6563756C742D636861743A7175657374696F6E3A736C6F742D6D61726B2D636F6E73656E74A76F7574636F6D65A7436F756E746564A26F66C0A87265747261637473C0A4636F6465C0AC6F7074696F6E735F68617368D94037643935666338376435333234323036313166653431356331646566323761333434373631376262363832333566343665336166313330616561333631633438A663686F696365A26E6FA46E6F7465D9524B656570206974206C6F63616C3A206120736C6F74206D61726B2069732074686520617574686F7227732063616C6C2C20616E642073686172696E672069742069732061207365706172617465206163742EAB616E7377657265645F6174B4323032362D31312D31325431393A30323A30305AAB72656365697665645F6174B4323032362D31312D31325431393A30323A30355AAF636C61696D5F696E5F667574757265C2A8616E737765726572D92465306431633262332D613439352D343638372D383837392D366135623463336432653166A9617574686F72697479A84F70657261746F72AA726571756573745F6964D92430303030303030312D303030302D343030302D383030302D303030303030303030303031" + }, + { + "name": "V14_an_identical_body_from_another_account_gets_its_own_Counted_and_never_the_first_accounts_outcome", + "card": { + "schemaVersion": "gamecult.fork.card.v0", + "fork_id": "gamecult-chat:question:slot-mark-consent", + "title": "Slot mark consent", + "context": "Should a slot mark be shared?", + "options": [ + { + "id": "yes", + "text": "Share it." + }, + { + "id": "no", + "text": "Keep it local." + } + ], + "recommendation": "no", + "depends": [ + "gamecult-chat:question:file-zone-audience" + ], + "leans": null, + "flag": null, + "raised_in": { + "kind": "CutSpec", + "id": "cultlib-gaps:cut_spec:cut-slot-tolerance.r4" + }, + "deciders": [ + "e0d1c2b3-a495-4687-8879-6a5b4c3d2e1f", + "9f8e7d6c-5b4a-4392-8170-0f1e2d3c4b5a" + ], + "status": "open", + "ruling": null, + "ruled_from": [], + "order": 3, + "options_hash": "7d95fc87d532420611fe415c1def27a3447617bb68235f46e3af130aea361c48" + }, + "optionsHash": "7d95fc87d532420611fe415c1def27a3447617bb68235f46e3af130aea361c48", + "steps": [ + { + "kind": "answer", + "body": { + "schemaVersion": "gamecult.fork.answer_request.v0", + "fork_id": "gamecult-chat:question:slot-mark-consent", + "options_hash": "7d95fc87d532420611fe415c1def27a3447617bb68235f46e3af130aea361c48", + "answer": { + "choice": "no", + "note": "Keep it local: a slot mark is the author's call, and sharing it is a separate act." + }, + "retracted": false, + "retracts": null, + "answered_at": "2026-11-12T19:02:00Z", + "request_id": "00000001-0000-4000-8000-000000000001" + }, + "server": { + "answer_id": "n1", + "answerer": "11111111-2222-4333-8444-555555555555", + "authority": "Member", + "received_at": "2026-11-12T19:02:05Z" + }, + "response": { + "schemaVersion": "gamecult.fork.answer_result.v0", + "answer": { + "schemaVersion": "gamecult.desk_answer.v0", + "answer_id": "n1", + "fork_id": "gamecult-chat:question:slot-mark-consent", + "outcome": "Refused", + "of": null, + "retracts": null, + "code": "not_a_decider", + "options_hash": "7d95fc87d532420611fe415c1def27a3447617bb68235f46e3af130aea361c48", + "choice": "no", + "note": "Keep it local: a slot mark is the author's call, and sharing it is a separate act.", + "answered_at": "2026-11-12T19:02:00Z", + "received_at": "2026-11-12T19:02:05Z", + "claim_in_future": false, + "answerer": "11111111-2222-4333-8444-555555555555", + "authority": "Member", + "request_id": "00000001-0000-4000-8000-000000000001" + }, + "card": null + } + }, + { + "kind": "answer", + "body": { + "schemaVersion": "gamecult.fork.answer_request.v0", + "fork_id": "gamecult-chat:question:slot-mark-consent", + "options_hash": "7d95fc87d532420611fe415c1def27a3447617bb68235f46e3af130aea361c48", + "answer": { + "choice": "no", + "note": "Keep it local: a slot mark is the author's call, and sharing it is a separate act." + }, + "retracted": false, + "retracts": null, + "answered_at": "2026-11-12T19:02:00Z", + "request_id": "00000001-0000-4000-8000-000000000001" + }, + "server": { + "answer_id": "n2", + "answerer": "9f8e7d6c-5b4a-4392-8170-0f1e2d3c4b5a", + "authority": "Steward", + "received_at": "2026-11-12T19:03:05Z" + }, + "response": { + "schemaVersion": "gamecult.fork.answer_result.v0", + "answer": { + "schemaVersion": "gamecult.desk_answer.v0", + "answer_id": "n2", + "fork_id": "gamecult-chat:question:slot-mark-consent", + "outcome": "Counted", + "of": null, + "retracts": null, + "code": null, + "options_hash": "7d95fc87d532420611fe415c1def27a3447617bb68235f46e3af130aea361c48", + "choice": "no", + "note": "Keep it local: a slot mark is the author's call, and sharing it is a separate act.", + "answered_at": "2026-11-12T19:02:00Z", + "received_at": "2026-11-12T19:03:05Z", + "claim_in_future": false, + "answerer": "9f8e7d6c-5b4a-4392-8170-0f1e2d3c4b5a", + "authority": "Steward", + "request_id": "00000001-0000-4000-8000-000000000001" + }, + "card": null + } + }, + { + "kind": "answer", + "body": { + "schemaVersion": "gamecult.fork.answer_request.v0", + "fork_id": "gamecult-chat:question:slot-mark-consent", + "options_hash": "7d95fc87d532420611fe415c1def27a3447617bb68235f46e3af130aea361c48", + "answer": { + "choice": "no", + "note": "Keep it local: a slot mark is the author's call, and sharing it is a separate act." + }, + "retracted": false, + "retracts": null, + "answered_at": "2026-11-12T19:02:00Z", + "request_id": "00000001-0000-4000-8000-000000000001" + }, + "server": { + "answer_id": "n9", + "answerer": "11111111-2222-4333-8444-555555555555", + "authority": "Member", + "received_at": "2026-11-12T19:04:05Z" + }, + "response": { + "schemaVersion": "gamecult.fork.answer_result.v0", + "answer": { + "schemaVersion": "gamecult.desk_answer.v0", + "answer_id": "n1", + "fork_id": "gamecult-chat:question:slot-mark-consent", + "outcome": "Refused", + "of": null, + "retracts": null, + "code": "not_a_decider", + "options_hash": "7d95fc87d532420611fe415c1def27a3447617bb68235f46e3af130aea361c48", + "choice": "no", + "note": "Keep it local: a slot mark is the author's call, and sharing it is a separate act.", + "answered_at": "2026-11-12T19:02:00Z", + "received_at": "2026-11-12T19:02:05Z", + "claim_in_future": false, + "answerer": "11111111-2222-4333-8444-555555555555", + "authority": "Member", + "request_id": "00000001-0000-4000-8000-000000000001" + }, + "card": null + } + } + ], + "record": { + "schemaVersion": "gamecult.fork.record.v0", + "fork_id": "gamecult-chat:question:slot-mark-consent", + "options_hash": "7d95fc87d532420611fe415c1def27a3447617bb68235f46e3af130aea361c48", + "counted_answer_id": "n2", + "answers": [ + { + "schemaVersion": "gamecult.desk_answer.v0", + "answer_id": "n1", + "fork_id": "gamecult-chat:question:slot-mark-consent", + "outcome": "Refused", + "of": null, + "retracts": null, + "code": "not_a_decider", + "options_hash": "7d95fc87d532420611fe415c1def27a3447617bb68235f46e3af130aea361c48", + "choice": "no", + "note": "Keep it local: a slot mark is the author's call, and sharing it is a separate act.", + "answered_at": "2026-11-12T19:02:00Z", + "received_at": "2026-11-12T19:02:05Z", + "claim_in_future": false, + "answerer": "11111111-2222-4333-8444-555555555555", + "authority": "Member", + "request_id": "00000001-0000-4000-8000-000000000001" + }, + { + "schemaVersion": "gamecult.desk_answer.v0", + "answer_id": "n2", + "fork_id": "gamecult-chat:question:slot-mark-consent", + "outcome": "Counted", + "of": null, + "retracts": null, + "code": null, + "options_hash": "7d95fc87d532420611fe415c1def27a3447617bb68235f46e3af130aea361c48", + "choice": "no", + "note": "Keep it local: a slot mark is the author's call, and sharing it is a separate act.", + "answered_at": "2026-11-12T19:02:00Z", + "received_at": "2026-11-12T19:03:05Z", + "claim_in_future": false, + "answerer": "9f8e7d6c-5b4a-4392-8170-0f1e2d3c4b5a", + "authority": "Steward", + "request_id": "00000001-0000-4000-8000-000000000001" + } + ] + }, + "recordHex": "85AD736368656D6156657273696F6EB767616D6563756C742E666F726B2E7265636F72642E7630A7666F726B5F6964D92867616D6563756C742D636861743A7175657374696F6E3A736C6F742D6D61726B2D636F6E73656E74AC6F7074696F6E735F68617368D94037643935666338376435333234323036313166653431356331646566323761333434373631376262363832333566343665336166313330616561333631633438B1636F756E7465645F616E737765725F6964A26E32A7616E737765727392DE0010AD736368656D6156657273696F6EB767616D6563756C742E6465736B5F616E737765722E7630A9616E737765725F6964A26E31A7666F726B5F6964D92867616D6563756C742D636861743A7175657374696F6E3A736C6F742D6D61726B2D636F6E73656E74A76F7574636F6D65A752656675736564A26F66C0A87265747261637473C0A4636F6465AD6E6F745F615F64656369646572AC6F7074696F6E735F68617368D94037643935666338376435333234323036313166653431356331646566323761333434373631376262363832333566343665336166313330616561333631633438A663686F696365A26E6FA46E6F7465D9524B656570206974206C6F63616C3A206120736C6F74206D61726B2069732074686520617574686F7227732063616C6C2C20616E642073686172696E672069742069732061207365706172617465206163742EAB616E7377657265645F6174B4323032362D31312D31325431393A30323A30305AAB72656365697665645F6174B4323032362D31312D31325431393A30323A30355AAF636C61696D5F696E5F667574757265C2A8616E737765726572D92431313131313131312D323232322D343333332D383434342D353535353535353535353535A9617574686F72697479A64D656D626572AA726571756573745F6964D92430303030303030312D303030302D343030302D383030302D303030303030303030303031DE0010AD736368656D6156657273696F6EB767616D6563756C742E6465736B5F616E737765722E7630A9616E737765725F6964A26E32A7666F726B5F6964D92867616D6563756C742D636861743A7175657374696F6E3A736C6F742D6D61726B2D636F6E73656E74A76F7574636F6D65A7436F756E746564A26F66C0A87265747261637473C0A4636F6465C0AC6F7074696F6E735F68617368D94037643935666338376435333234323036313166653431356331646566323761333434373631376262363832333566343665336166313330616561333631633438A663686F696365A26E6FA46E6F7465D9524B656570206974206C6F63616C3A206120736C6F74206D61726B2069732074686520617574686F7227732063616C6C2C20616E642073686172696E672069742069732061207365706172617465206163742EAB616E7377657265645F6174B4323032362D31312D31325431393A30323A30305AAB72656365697665645F6174B4323032362D31312D31325431393A30333A30355AAF636C61696D5F696E5F667574757265C2A8616E737765726572D92439663865376436632D356234612D343339322D383137302D306631653264336334623561A9617574686F72697479A753746577617264AA726571756573745F6964D92430303030303030312D303030302D343030302D383030302D303030303030303030303031" + }, + { + "name": "V14_an_identical_body_from_another_decider_is_its_own_Revision_and_the_first_retry_still_returns_n1", + "card": { + "schemaVersion": "gamecult.fork.card.v0", + "fork_id": "gamecult-chat:question:slot-mark-consent", + "title": "Slot mark consent", + "context": "Should a slot mark be shared?", + "options": [ + { + "id": "yes", + "text": "Share it." + }, + { + "id": "no", + "text": "Keep it local." + } + ], + "recommendation": "no", + "depends": [ + "gamecult-chat:question:file-zone-audience" + ], + "leans": null, + "flag": null, + "raised_in": { + "kind": "CutSpec", + "id": "cultlib-gaps:cut_spec:cut-slot-tolerance.r4" + }, + "deciders": [ + "e0d1c2b3-a495-4687-8879-6a5b4c3d2e1f", + "9f8e7d6c-5b4a-4392-8170-0f1e2d3c4b5a" + ], + "status": "open", + "ruling": null, + "ruled_from": [], + "order": 3, + "options_hash": "7d95fc87d532420611fe415c1def27a3447617bb68235f46e3af130aea361c48" + }, + "optionsHash": "7d95fc87d532420611fe415c1def27a3447617bb68235f46e3af130aea361c48", + "steps": [ + { + "kind": "answer", + "body": { + "schemaVersion": "gamecult.fork.answer_request.v0", + "fork_id": "gamecult-chat:question:slot-mark-consent", + "options_hash": "7d95fc87d532420611fe415c1def27a3447617bb68235f46e3af130aea361c48", + "answer": { + "choice": "no", + "note": "Keep it local: a slot mark is the author's call, and sharing it is a separate act." + }, + "retracted": false, + "retracts": null, + "answered_at": "2026-11-12T19:02:00Z", + "request_id": "00000001-0000-4000-8000-000000000001" + }, + "server": { + "answer_id": "n1", + "answerer": "e0d1c2b3-a495-4687-8879-6a5b4c3d2e1f", + "authority": "Operator", + "received_at": "2026-11-12T19:02:05Z" + }, + "response": { + "schemaVersion": "gamecult.fork.answer_result.v0", + "answer": { + "schemaVersion": "gamecult.desk_answer.v0", + "answer_id": "n1", + "fork_id": "gamecult-chat:question:slot-mark-consent", + "outcome": "Counted", + "of": null, + "retracts": null, + "code": null, + "options_hash": "7d95fc87d532420611fe415c1def27a3447617bb68235f46e3af130aea361c48", + "choice": "no", + "note": "Keep it local: a slot mark is the author's call, and sharing it is a separate act.", + "answered_at": "2026-11-12T19:02:00Z", + "received_at": "2026-11-12T19:02:05Z", + "claim_in_future": false, + "answerer": "e0d1c2b3-a495-4687-8879-6a5b4c3d2e1f", + "authority": "Operator", + "request_id": "00000001-0000-4000-8000-000000000001" + }, + "card": null + } + }, + { + "kind": "answer", + "body": { + "schemaVersion": "gamecult.fork.answer_request.v0", + "fork_id": "gamecult-chat:question:slot-mark-consent", + "options_hash": "7d95fc87d532420611fe415c1def27a3447617bb68235f46e3af130aea361c48", + "answer": { + "choice": "no", + "note": "Keep it local: a slot mark is the author's call, and sharing it is a separate act." + }, + "retracted": false, + "retracts": null, + "answered_at": "2026-11-12T19:02:00Z", + "request_id": "00000001-0000-4000-8000-000000000001" + }, + "server": { + "answer_id": "n3", + "answerer": "9f8e7d6c-5b4a-4392-8170-0f1e2d3c4b5a", + "authority": "Steward", + "received_at": "2026-11-12T19:05:05Z" + }, + "response": { + "schemaVersion": "gamecult.fork.answer_result.v0", + "answer": { + "schemaVersion": "gamecult.desk_answer.v0", + "answer_id": "n3", + "fork_id": "gamecult-chat:question:slot-mark-consent", + "outcome": "Revision", + "of": "n1", + "retracts": null, + "code": null, + "options_hash": "7d95fc87d532420611fe415c1def27a3447617bb68235f46e3af130aea361c48", + "choice": "no", + "note": "Keep it local: a slot mark is the author's call, and sharing it is a separate act.", + "answered_at": "2026-11-12T19:02:00Z", + "received_at": "2026-11-12T19:05:05Z", + "claim_in_future": false, + "answerer": "9f8e7d6c-5b4a-4392-8170-0f1e2d3c4b5a", + "authority": "Steward", + "request_id": "00000001-0000-4000-8000-000000000001" + }, + "card": null + } + }, + { + "kind": "answer", + "body": { + "schemaVersion": "gamecult.fork.answer_request.v0", + "fork_id": "gamecult-chat:question:slot-mark-consent", + "options_hash": "7d95fc87d532420611fe415c1def27a3447617bb68235f46e3af130aea361c48", + "answer": { + "choice": "no", + "note": "Keep it local: a slot mark is the author's call, and sharing it is a separate act." + }, + "retracted": false, + "retracts": null, + "answered_at": "2026-11-12T19:02:00Z", + "request_id": "00000001-0000-4000-8000-000000000001" + }, + "server": { + "answer_id": "n9", + "answerer": "e0d1c2b3-a495-4687-8879-6a5b4c3d2e1f", + "authority": "Operator", + "received_at": "2026-11-12T19:02:05Z" + }, + "response": { + "schemaVersion": "gamecult.fork.answer_result.v0", + "answer": { + "schemaVersion": "gamecult.desk_answer.v0", + "answer_id": "n1", + "fork_id": "gamecult-chat:question:slot-mark-consent", + "outcome": "Counted", + "of": null, + "retracts": null, + "code": null, + "options_hash": "7d95fc87d532420611fe415c1def27a3447617bb68235f46e3af130aea361c48", + "choice": "no", + "note": "Keep it local: a slot mark is the author's call, and sharing it is a separate act.", + "answered_at": "2026-11-12T19:02:00Z", + "received_at": "2026-11-12T19:02:05Z", + "claim_in_future": false, + "answerer": "e0d1c2b3-a495-4687-8879-6a5b4c3d2e1f", + "authority": "Operator", + "request_id": "00000001-0000-4000-8000-000000000001" + }, + "card": null + } + } + ], + "record": { + "schemaVersion": "gamecult.fork.record.v0", + "fork_id": "gamecult-chat:question:slot-mark-consent", + "options_hash": "7d95fc87d532420611fe415c1def27a3447617bb68235f46e3af130aea361c48", + "counted_answer_id": "n1", + "answers": [ + { + "schemaVersion": "gamecult.desk_answer.v0", + "answer_id": "n1", + "fork_id": "gamecult-chat:question:slot-mark-consent", + "outcome": "Counted", + "of": null, + "retracts": null, + "code": null, + "options_hash": "7d95fc87d532420611fe415c1def27a3447617bb68235f46e3af130aea361c48", + "choice": "no", + "note": "Keep it local: a slot mark is the author's call, and sharing it is a separate act.", + "answered_at": "2026-11-12T19:02:00Z", + "received_at": "2026-11-12T19:02:05Z", + "claim_in_future": false, + "answerer": "e0d1c2b3-a495-4687-8879-6a5b4c3d2e1f", + "authority": "Operator", + "request_id": "00000001-0000-4000-8000-000000000001" + }, + { + "schemaVersion": "gamecult.desk_answer.v0", + "answer_id": "n3", + "fork_id": "gamecult-chat:question:slot-mark-consent", + "outcome": "Revision", + "of": "n1", + "retracts": null, + "code": null, + "options_hash": "7d95fc87d532420611fe415c1def27a3447617bb68235f46e3af130aea361c48", + "choice": "no", + "note": "Keep it local: a slot mark is the author's call, and sharing it is a separate act.", + "answered_at": "2026-11-12T19:02:00Z", + "received_at": "2026-11-12T19:05:05Z", + "claim_in_future": false, + "answerer": "9f8e7d6c-5b4a-4392-8170-0f1e2d3c4b5a", + "authority": "Steward", + "request_id": "00000001-0000-4000-8000-000000000001" + } + ] + }, + "recordHex": "85AD736368656D6156657273696F6EB767616D6563756C742E666F726B2E7265636F72642E7630A7666F726B5F6964D92867616D6563756C742D636861743A7175657374696F6E3A736C6F742D6D61726B2D636F6E73656E74AC6F7074696F6E735F68617368D94037643935666338376435333234323036313166653431356331646566323761333434373631376262363832333566343665336166313330616561333631633438B1636F756E7465645F616E737765725F6964A26E31A7616E737765727392DE0010AD736368656D6156657273696F6EB767616D6563756C742E6465736B5F616E737765722E7630A9616E737765725F6964A26E31A7666F726B5F6964D92867616D6563756C742D636861743A7175657374696F6E3A736C6F742D6D61726B2D636F6E73656E74A76F7574636F6D65A7436F756E746564A26F66C0A87265747261637473C0A4636F6465C0AC6F7074696F6E735F68617368D94037643935666338376435333234323036313166653431356331646566323761333434373631376262363832333566343665336166313330616561333631633438A663686F696365A26E6FA46E6F7465D9524B656570206974206C6F63616C3A206120736C6F74206D61726B2069732074686520617574686F7227732063616C6C2C20616E642073686172696E672069742069732061207365706172617465206163742EAB616E7377657265645F6174B4323032362D31312D31325431393A30323A30305AAB72656365697665645F6174B4323032362D31312D31325431393A30323A30355AAF636C61696D5F696E5F667574757265C2A8616E737765726572D92465306431633262332D613439352D343638372D383837392D366135623463336432653166A9617574686F72697479A84F70657261746F72AA726571756573745F6964D92430303030303030312D303030302D343030302D383030302D303030303030303030303031DE0010AD736368656D6156657273696F6EB767616D6563756C742E6465736B5F616E737765722E7630A9616E737765725F6964A26E33A7666F726B5F6964D92867616D6563756C742D636861743A7175657374696F6E3A736C6F742D6D61726B2D636F6E73656E74A76F7574636F6D65A85265766973696F6EA26F66A26E31A87265747261637473C0A4636F6465C0AC6F7074696F6E735F68617368D94037643935666338376435333234323036313166653431356331646566323761333434373631376262363832333566343665336166313330616561333631633438A663686F696365A26E6FA46E6F7465D9524B656570206974206C6F63616C3A206120736C6F74206D61726B2069732074686520617574686F7227732063616C6C2C20616E642073686172696E672069742069732061207365706172617465206163742EAB616E7377657265645F6174B4323032362D31312D31325431393A30323A30305AAB72656365697665645F6174B4323032362D31312D31325431393A30353A30355AAF636C61696D5F696E5F667574757265C2A8616E737765726572D92439663865376436632D356234612D343339322D383137302D306631653264336334623561A9617574686F72697479A753746577617264AA726571756573745F6964D92430303030303030312D303030302D343030302D383030302D303030303030303030303031" + }, + { + "name": "V16_Q5_a_forbidden_request_binds_no_request_id", + "card": { + "schemaVersion": "gamecult.fork.card.v0", + "fork_id": "gamecult-chat:question:slot-mark-consent", + "title": "Slot mark consent", + "context": "Should a slot mark be shared?", + "options": [ + { + "id": "yes", + "text": "Share it." + }, + { + "id": "no", + "text": "Keep it local." + } + ], + "recommendation": "no", + "depends": [ + "gamecult-chat:question:file-zone-audience" + ], + "leans": null, + "flag": null, + "raised_in": { + "kind": "CutSpec", + "id": "cultlib-gaps:cut_spec:cut-slot-tolerance.r4" + }, + "deciders": [ + "e0d1c2b3-a495-4687-8879-6a5b4c3d2e1f" + ], + "status": "open", + "ruling": null, + "ruled_from": [], + "order": 3, + "options_hash": "7d95fc87d532420611fe415c1def27a3447617bb68235f46e3af130aea361c48" + }, + "optionsHash": "7d95fc87d532420611fe415c1def27a3447617bb68235f46e3af130aea361c48", + "steps": [ + { + "kind": "answer", + "body": { + "schemaVersion": "gamecult.fork.answer_request.v0", + "fork_id": "gamecult-chat:question:slot-mark-consent", + "options_hash": "7d95fc87d532420611fe415c1def27a3447617bb68235f46e3af130aea361c48", + "answer": { + "choice": "no", + "note": "Keep it local: a slot mark is the author's call, and sharing it is a separate act." + }, + "retracted": false, + "retracts": null, + "answered_at": "2026-11-12T19:02:00Z", + "request_id": "00000001-0000-4000-8000-000000000001" + }, + "server": { + "answer_id": "n9", + "answerer": "e0d1c2b3-a495-4687-8879-6a5b4c3d2e1f", + "authority": "Operator", + "received_at": "2026-11-12T19:02:05Z", + "active": false + }, + "response": { + "schemaVersion": "gamecult.fork.refusal.v0", + "code": "forbidden", + "error": "forbidden: only Active members may use the desk" + } + }, + { + "kind": "answer", + "body": { + "schemaVersion": "gamecult.fork.answer_request.v0", + "fork_id": "gamecult-chat:question:slot-mark-consent", + "options_hash": "7d95fc87d532420611fe415c1def27a3447617bb68235f46e3af130aea361c48", + "answer": { + "choice": "no", + "note": "Keep it local: a slot mark is the author's call, and sharing it is a separate act." + }, + "retracted": false, + "retracts": null, + "answered_at": "2026-11-12T19:02:00Z", + "request_id": "00000001-0000-4000-8000-000000000001" + }, + "server": { + "answer_id": "n1", + "answerer": "e0d1c2b3-a495-4687-8879-6a5b4c3d2e1f", + "authority": "Operator", + "received_at": "2026-11-12T19:02:05Z" + }, + "response": { + "schemaVersion": "gamecult.fork.answer_result.v0", + "answer": { + "schemaVersion": "gamecult.desk_answer.v0", + "answer_id": "n1", + "fork_id": "gamecult-chat:question:slot-mark-consent", + "outcome": "Counted", + "of": null, + "retracts": null, + "code": null, + "options_hash": "7d95fc87d532420611fe415c1def27a3447617bb68235f46e3af130aea361c48", + "choice": "no", + "note": "Keep it local: a slot mark is the author's call, and sharing it is a separate act.", + "answered_at": "2026-11-12T19:02:00Z", + "received_at": "2026-11-12T19:02:05Z", + "claim_in_future": false, + "answerer": "e0d1c2b3-a495-4687-8879-6a5b4c3d2e1f", + "authority": "Operator", + "request_id": "00000001-0000-4000-8000-000000000001" + }, + "card": null + } + } + ], + "record": { + "schemaVersion": "gamecult.fork.record.v0", + "fork_id": "gamecult-chat:question:slot-mark-consent", + "options_hash": "7d95fc87d532420611fe415c1def27a3447617bb68235f46e3af130aea361c48", + "counted_answer_id": "n1", + "answers": [ + { + "schemaVersion": "gamecult.desk_answer.v0", + "answer_id": "n1", + "fork_id": "gamecult-chat:question:slot-mark-consent", + "outcome": "Counted", + "of": null, + "retracts": null, + "code": null, + "options_hash": "7d95fc87d532420611fe415c1def27a3447617bb68235f46e3af130aea361c48", + "choice": "no", + "note": "Keep it local: a slot mark is the author's call, and sharing it is a separate act.", + "answered_at": "2026-11-12T19:02:00Z", + "received_at": "2026-11-12T19:02:05Z", + "claim_in_future": false, + "answerer": "e0d1c2b3-a495-4687-8879-6a5b4c3d2e1f", + "authority": "Operator", + "request_id": "00000001-0000-4000-8000-000000000001" + } + ] + }, + "recordHex": "85AD736368656D6156657273696F6EB767616D6563756C742E666F726B2E7265636F72642E7630A7666F726B5F6964D92867616D6563756C742D636861743A7175657374696F6E3A736C6F742D6D61726B2D636F6E73656E74AC6F7074696F6E735F68617368D94037643935666338376435333234323036313166653431356331646566323761333434373631376262363832333566343665336166313330616561333631633438B1636F756E7465645F616E737765725F6964A26E31A7616E737765727391DE0010AD736368656D6156657273696F6EB767616D6563756C742E6465736B5F616E737765722E7630A9616E737765725F6964A26E31A7666F726B5F6964D92867616D6563756C742D636861743A7175657374696F6E3A736C6F742D6D61726B2D636F6E73656E74A76F7574636F6D65A7436F756E746564A26F66C0A87265747261637473C0A4636F6465C0AC6F7074696F6E735F68617368D94037643935666338376435333234323036313166653431356331646566323761333434373631376262363832333566343665336166313330616561333631633438A663686F696365A26E6FA46E6F7465D9524B656570206974206C6F63616C3A206120736C6F74206D61726B2069732074686520617574686F7227732063616C6C2C20616E642073686172696E672069742069732061207365706172617465206163742EAB616E7377657265645F6174B4323032362D31312D31325431393A30323A30305AAB72656365697665645F6174B4323032362D31312D31325431393A30323A30355AAF636C61696D5F696E5F667574757265C2A8616E737765726572D92465306431633262332D613439352D343638372D383837392D366135623463336432653166A9617574686F72697479A84F70657261746F72AA726571756573745F6964D92430303030303030312D303030302D343030302D383030302D303030303030303030303031" + }, + { + "name": "V17_Q6_a_body_refused_at_the_door_binds_no_request_id", + "card": { + "schemaVersion": "gamecult.fork.card.v0", + "fork_id": "gamecult-chat:question:slot-mark-consent", + "title": "Slot mark consent", + "context": "Should a slot mark be shared?", + "options": [ + { + "id": "yes", + "text": "Share it." + }, + { + "id": "no", + "text": "Keep it local." + } + ], + "recommendation": "no", + "depends": [ + "gamecult-chat:question:file-zone-audience" + ], + "leans": null, + "flag": null, + "raised_in": { + "kind": "CutSpec", + "id": "cultlib-gaps:cut_spec:cut-slot-tolerance.r4" + }, + "deciders": [ + "e0d1c2b3-a495-4687-8879-6a5b4c3d2e1f" + ], + "status": "open", + "ruling": null, + "ruled_from": [], + "order": 3, + "options_hash": "7d95fc87d532420611fe415c1def27a3447617bb68235f46e3af130aea361c48" + }, + "optionsHash": "7d95fc87d532420611fe415c1def27a3447617bb68235f46e3af130aea361c48", + "steps": [ + { + "kind": "answer", + "body": { + "schemaVersion": "gamecult.fork.answer_request.v0", + "fork_id": "gamecult-chat:question:slot-mark-consent", + "options_hash": "7d95fc87d532420611fe415c1def27a3447617bb68235f46e3af130aea361c48", + "answer": { + "choice": "no", + "note": "Keep it local: a slot mark is the author's call, and sharing it is a separate act." + }, + "retracted": false, + "retracts": null, + "answered_at": "2026-11-12T19:02:00Z", + "request_id": "00000001-0000-4000-8000-000000000001", + "mood": "happy" + }, + "server": { + "answer_id": "n9", + "answerer": "e0d1c2b3-a495-4687-8879-6a5b4c3d2e1f", + "authority": "Operator", + "received_at": "2026-11-12T19:02:05Z" + }, + "response": { + "schemaVersion": "gamecult.fork.refusal.v0", + "code": "body_unknown_field", + "error": "body_unknown_field: the body is a closed shape" + } + }, + { + "kind": "answer", + "body": { + "schemaVersion": "gamecult.fork.answer_request.v0", + "fork_id": "gamecult-chat:question:slot-mark-consent", + "options_hash": "7d95fc87d532420611fe415c1def27a3447617bb68235f46e3af130aea361c48", + "answer": { + "choice": "no", + "note": "Keep it local: a slot mark is the author's call, and sharing it is a separate act." + }, + "retracted": false, + "retracts": null, + "answered_at": "2026-11-12T19:02:00Z", + "request_id": "00000001-0000-4000-8000-000000000001" + }, + "server": { + "answer_id": "n1", + "answerer": "e0d1c2b3-a495-4687-8879-6a5b4c3d2e1f", + "authority": "Operator", + "received_at": "2026-11-12T19:02:05Z" + }, + "response": { + "schemaVersion": "gamecult.fork.answer_result.v0", + "answer": { + "schemaVersion": "gamecult.desk_answer.v0", + "answer_id": "n1", + "fork_id": "gamecult-chat:question:slot-mark-consent", + "outcome": "Counted", + "of": null, + "retracts": null, + "code": null, + "options_hash": "7d95fc87d532420611fe415c1def27a3447617bb68235f46e3af130aea361c48", + "choice": "no", + "note": "Keep it local: a slot mark is the author's call, and sharing it is a separate act.", + "answered_at": "2026-11-12T19:02:00Z", + "received_at": "2026-11-12T19:02:05Z", + "claim_in_future": false, + "answerer": "e0d1c2b3-a495-4687-8879-6a5b4c3d2e1f", + "authority": "Operator", + "request_id": "00000001-0000-4000-8000-000000000001" + }, + "card": null + } + } + ], + "record": { + "schemaVersion": "gamecult.fork.record.v0", + "fork_id": "gamecult-chat:question:slot-mark-consent", + "options_hash": "7d95fc87d532420611fe415c1def27a3447617bb68235f46e3af130aea361c48", + "counted_answer_id": "n1", + "answers": [ + { + "schemaVersion": "gamecult.desk_answer.v0", + "answer_id": "n1", + "fork_id": "gamecult-chat:question:slot-mark-consent", + "outcome": "Counted", + "of": null, + "retracts": null, + "code": null, + "options_hash": "7d95fc87d532420611fe415c1def27a3447617bb68235f46e3af130aea361c48", + "choice": "no", + "note": "Keep it local: a slot mark is the author's call, and sharing it is a separate act.", + "answered_at": "2026-11-12T19:02:00Z", + "received_at": "2026-11-12T19:02:05Z", + "claim_in_future": false, + "answerer": "e0d1c2b3-a495-4687-8879-6a5b4c3d2e1f", + "authority": "Operator", + "request_id": "00000001-0000-4000-8000-000000000001" + } + ] + }, + "recordHex": "85AD736368656D6156657273696F6EB767616D6563756C742E666F726B2E7265636F72642E7630A7666F726B5F6964D92867616D6563756C742D636861743A7175657374696F6E3A736C6F742D6D61726B2D636F6E73656E74AC6F7074696F6E735F68617368D94037643935666338376435333234323036313166653431356331646566323761333434373631376262363832333566343665336166313330616561333631633438B1636F756E7465645F616E737765725F6964A26E31A7616E737765727391DE0010AD736368656D6156657273696F6EB767616D6563756C742E6465736B5F616E737765722E7630A9616E737765725F6964A26E31A7666F726B5F6964D92867616D6563756C742D636861743A7175657374696F6E3A736C6F742D6D61726B2D636F6E73656E74A76F7574636F6D65A7436F756E746564A26F66C0A87265747261637473C0A4636F6465C0AC6F7074696F6E735F68617368D94037643935666338376435333234323036313166653431356331646566323761333434373631376262363832333566343665336166313330616561333631633438A663686F696365A26E6FA46E6F7465D9524B656570206974206C6F63616C3A206120736C6F74206D61726B2069732074686520617574686F7227732063616C6C2C20616E642073686172696E672069742069732061207365706172617465206163742EAB616E7377657265645F6174B4323032362D31312D31325431393A30323A30305AAB72656365697665645F6174B4323032362D31312D31325431393A30323A30355AAF636C61696D5F696E5F667574757265C2A8616E737765726572D92465306431633262332D613439352D343638372D383837392D366135623463336432653166A9617574686F72697479A84F70657261746F72AA726571756573745F6964D92430303030303030312D303030302D343030302D383030302D303030303030303030303031" + }, + { + "name": "V17_Q6_an_unknown_fork_binds_no_request_id", + "card": { + "schemaVersion": "gamecult.fork.card.v0", + "fork_id": "gamecult-chat:question:slot-mark-consent", + "title": "Slot mark consent", + "context": "Should a slot mark be shared?", + "options": [ + { + "id": "yes", + "text": "Share it." + }, + { + "id": "no", + "text": "Keep it local." + } + ], + "recommendation": "no", + "depends": [ + "gamecult-chat:question:file-zone-audience" + ], + "leans": null, + "flag": null, + "raised_in": { + "kind": "CutSpec", + "id": "cultlib-gaps:cut_spec:cut-slot-tolerance.r4" + }, + "deciders": [ + "e0d1c2b3-a495-4687-8879-6a5b4c3d2e1f" + ], + "status": "open", + "ruling": null, + "ruled_from": [], + "order": 3, + "options_hash": "7d95fc87d532420611fe415c1def27a3447617bb68235f46e3af130aea361c48" + }, + "optionsHash": "7d95fc87d532420611fe415c1def27a3447617bb68235f46e3af130aea361c48", + "steps": [ + { + "kind": "answer", + "body": { + "schemaVersion": "gamecult.fork.answer_request.v0", + "fork_id": "gamecult-chat:question:nope", + "options_hash": "7d95fc87d532420611fe415c1def27a3447617bb68235f46e3af130aea361c48", + "answer": { + "choice": "no", + "note": "Keep it local: a slot mark is the author's call, and sharing it is a separate act." + }, + "retracted": false, + "retracts": null, + "answered_at": "2026-11-12T19:02:00Z", + "request_id": "00000001-0000-4000-8000-000000000001" + }, + "server": { + "answer_id": "n9", + "answerer": "e0d1c2b3-a495-4687-8879-6a5b4c3d2e1f", + "authority": "Operator", + "received_at": "2026-11-12T19:02:05Z" + }, + "response": { + "schemaVersion": "gamecult.fork.refusal.v0", + "code": "fork_unknown", + "error": "fork_unknown: no such fork" + } + }, + { + "kind": "answer", + "body": { + "schemaVersion": "gamecult.fork.answer_request.v0", + "fork_id": "gamecult-chat:question:slot-mark-consent", + "options_hash": "7d95fc87d532420611fe415c1def27a3447617bb68235f46e3af130aea361c48", + "answer": { + "choice": "no", + "note": "Keep it local: a slot mark is the author's call, and sharing it is a separate act." + }, + "retracted": false, + "retracts": null, + "answered_at": "2026-11-12T19:02:00Z", + "request_id": "00000001-0000-4000-8000-000000000001" + }, + "server": { + "answer_id": "n1", + "answerer": "e0d1c2b3-a495-4687-8879-6a5b4c3d2e1f", + "authority": "Operator", + "received_at": "2026-11-12T19:02:05Z" + }, + "response": { + "schemaVersion": "gamecult.fork.answer_result.v0", + "answer": { + "schemaVersion": "gamecult.desk_answer.v0", + "answer_id": "n1", + "fork_id": "gamecult-chat:question:slot-mark-consent", + "outcome": "Counted", + "of": null, + "retracts": null, + "code": null, + "options_hash": "7d95fc87d532420611fe415c1def27a3447617bb68235f46e3af130aea361c48", + "choice": "no", + "note": "Keep it local: a slot mark is the author's call, and sharing it is a separate act.", + "answered_at": "2026-11-12T19:02:00Z", + "received_at": "2026-11-12T19:02:05Z", + "claim_in_future": false, + "answerer": "e0d1c2b3-a495-4687-8879-6a5b4c3d2e1f", + "authority": "Operator", + "request_id": "00000001-0000-4000-8000-000000000001" + }, + "card": null + } + } + ], + "record": { + "schemaVersion": "gamecult.fork.record.v0", + "fork_id": "gamecult-chat:question:slot-mark-consent", + "options_hash": "7d95fc87d532420611fe415c1def27a3447617bb68235f46e3af130aea361c48", + "counted_answer_id": "n1", + "answers": [ + { + "schemaVersion": "gamecult.desk_answer.v0", + "answer_id": "n1", + "fork_id": "gamecult-chat:question:slot-mark-consent", + "outcome": "Counted", + "of": null, + "retracts": null, + "code": null, + "options_hash": "7d95fc87d532420611fe415c1def27a3447617bb68235f46e3af130aea361c48", + "choice": "no", + "note": "Keep it local: a slot mark is the author's call, and sharing it is a separate act.", + "answered_at": "2026-11-12T19:02:00Z", + "received_at": "2026-11-12T19:02:05Z", + "claim_in_future": false, + "answerer": "e0d1c2b3-a495-4687-8879-6a5b4c3d2e1f", + "authority": "Operator", + "request_id": "00000001-0000-4000-8000-000000000001" + } + ] + }, + "recordHex": "85AD736368656D6156657273696F6EB767616D6563756C742E666F726B2E7265636F72642E7630A7666F726B5F6964D92867616D6563756C742D636861743A7175657374696F6E3A736C6F742D6D61726B2D636F6E73656E74AC6F7074696F6E735F68617368D94037643935666338376435333234323036313166653431356331646566323761333434373631376262363832333566343665336166313330616561333631633438B1636F756E7465645F616E737765725F6964A26E31A7616E737765727391DE0010AD736368656D6156657273696F6EB767616D6563756C742E6465736B5F616E737765722E7630A9616E737765725F6964A26E31A7666F726B5F6964D92867616D6563756C742D636861743A7175657374696F6E3A736C6F742D6D61726B2D636F6E73656E74A76F7574636F6D65A7436F756E746564A26F66C0A87265747261637473C0A4636F6465C0AC6F7074696F6E735F68617368D94037643935666338376435333234323036313166653431356331646566323761333434373631376262363832333566343665336166313330616561333631633438A663686F696365A26E6FA46E6F7465D9524B656570206974206C6F63616C3A206120736C6F74206D61726B2069732074686520617574686F7227732063616C6C2C20616E642073686172696E672069742069732061207365706172617465206163742EAB616E7377657265645F6174B4323032362D31312D31325431393A30323A30305AAB72656365697665645F6174B4323032362D31312D31325431393A30323A30355AAF636C61696D5F696E5F667574757265C2A8616E737765726572D92465306431633262332D613439352D343638372D383837392D366135623463336432653166A9617574686F72697479A84F70657261746F72AA726571756573745F6964D92430303030303030312D303030302D343030302D383030302D303030303030303030303031" }, { "name": "the_same_request_id_with_another_body_is_request_id_conflict", diff --git a/contracts/cultnet/governance/fork-card.md b/contracts/cultnet/governance/fork-card.md index bb84508a..222785b7 100644 --- a/contracts/cultnet/governance/fork-card.md +++ b/contracts/cultnet/governance/fork-card.md @@ -50,7 +50,7 @@ Vectors `optionsHash`: the seven of the binding file (`heimdall_A..G`), computed ### answer_request -`{schemaVersion, fork_id, options_hash, answer, retracted, retracts, answered_at, request_id}`. **`request_id`** is set by the client, a lowercase D-format UUID, one per intended answer, kept across retries; the first stored answer that carries it binds it to the stamped `answerer`. A **retry with the same `request_id` and the same body returns the stored outcome unchanged** (a `Refused` one included, a `stale_fork` with the card it carried) and **never adds a Revision**; the same `request_id` with a different body is `request_id_conflict` (409, a refusal, nothing stored). The same id from another account is another request. A body refused at step 1 or 2 binds nothing, so its id is free to reuse. The lookup comes after steps 1 and 2 and before the fork is looked up, so a retry gets its stored outcome even if the card has since changed. `answer` is `{choice, note}` (at least one non-nil) or nil on a retraction. `choice` is an option id; `note` is the person's words, verbatim, 1 to 4000 **UTF-8 bytes**, not blank. A schema counts characters, not bytes, so its `maxLength: 4000` (code points) is only the looser bound and both suites enforce the byte limit as a rule: 4000 ASCII bytes pass; 1000 astral characters (4000 bytes) pass and 1001 (4004) fail; `e` plus a combining acute is 3 bytes, so 1333 of them and an `x` pass and 1334 fail; 1999 two-byte characters plus three ASCII (4001 bytes) fail. A note over the limit is `body_invalid`. `answered_at` is the client's claim. **A request never carries `answerer` or `authority`**: both are stamped by Huginn (`answerer` from the verified subject the receiver passes; `authority` from the door's configuration). A body that names either key at any depth is refused whole, never stripped (`body_forbidden_field`); any other unknown key is `body_unknown_field`. The request type Bifrost sends over the second door is this document; it has no field for either key, so a client cannot supply them by construction, and Bifrost's scan is the first line, not the only one. How Huginn receives the verified subject is the door's authenticated context, not a body field (open choice 3). In map-mode `retracted` is always written (the binding file's optional `retracted` becomes `false`). +`{schemaVersion, fork_id, options_hash, answer, retracted, retracts, answered_at, request_id}`. **`request_id`** is set by the client, a lowercase D-format UUID, one per intended answer, kept across retries; the first stored answer that carries it binds it to the stamped `answerer`. "Same body" means every field equal, `answered_at` included, so a client resends identical bytes. A **retry with the same `request_id` and the same body returns the stored outcome unchanged** (a `Refused` one included; a replayed `stale_fork` carries the **current** card, because a stored `desk_answer` has no card field and no storage is added for one) and **never adds a Revision**; the same `request_id` with a different body is `request_id_conflict` (409, a refusal, nothing stored). The same id from another account is another request, judged on its own: it neither conflicts with nor replays the first account's outcome, even when the bytes are identical (vectors V14: an off-list account's `Refused`, then a decider's identical body is its own `Counted`). A body refused at step 1 or 2 binds nothing, so its id is free to reuse. The lookup comes after steps 1 and 2 and before the fork is looked up, so a retry gets its stored outcome even if the card has since changed. `answer` is `{choice, note}` (at least one non-nil) or nil on a retraction. `choice` is an option id; `note` is the person's words, verbatim, 1 to 4000 **UTF-8 bytes**, not blank. A schema counts characters, not bytes, so its `maxLength: 4000` (code points) is only the looser bound and both suites enforce the byte limit as a rule: 4000 ASCII bytes pass; 1000 astral characters (4000 bytes) pass and 1001 (4004) fail; `e` plus a combining acute is 3 bytes, so 1333 of them and an `x` pass and 1334 fail; 1999 two-byte characters plus three ASCII (4001 bytes) fail. A note over the limit is `body_invalid`. `answered_at` is the client's claim. **A request never carries `answerer` or `authority`**: both are stamped by Huginn (`answerer` from the verified subject the receiver passes; `authority` from the door's configuration). A body that names either key at any depth is refused whole, never stripped (`body_forbidden_field`); any other unknown key is `body_unknown_field`. The request type Bifrost sends over the second door is this document; it has no field for either key, so a client cannot supply them by construction, and Bifrost's scan is the first line, not the only one. How Huginn receives the verified subject is the door's authenticated context, not a body field (open choice 3). In map-mode `retracted` is always written (the binding file's optional `retracted` becomes `false`). ### desk_answer (the stored kind) @@ -162,6 +162,7 @@ Option B, **Bifrost receives the answer and Huginn stores it** (the design in th - `Refused` stores every refusal from steps 4 to 7 and R1 and R2 (his section 1.3b); only steps 1 and 2 and `fork_unknown` are not stored. The binding file does not say whether `fork_unknown` is stored; it cannot be keyed without a question, so it is not (open choice 4). - The binding file's `choice_valid` has no named refusal code; this page names it `choice_invalid`. `fork_known` is `fork_unknown`. A type-invalid body is `body_invalid`. - `ruled` (his R3 and V10) is dropped: a ruling that answers a fork closes it, so the case is `fork_closed` (V4, V10a). His file drops it too. +- Heimdall's section 1.3e (Q1 to Q6, V12 to V18) is the source for `request_id`; this page matches it, with two notes. Q1's open item is settled by his ruling: a replayed `stale_fork` returns the current card. In V14 a decider's identical body is a `Revision` whose `of` necessarily names the first account's counted answer id (the record shows it to every decider), so "never contains X's answer_id" holds for the replayed outcome, not for `of`; the vector with an off-list first account pins the replay case with a `Counted`. - `request_id` (on the request and the stored `desk_answer`) and `request_id_conflict` are this page's: his file has no idempotency key, and a retry after `unavailable` needs one. Eureka's `desk_answer` kind and Huginn's request type must carry it. - Transport (routes, scopes, list, read, `unavailable`) is this page's; his file has none yet. The note limit is 4000 UTF-8 bytes here, as his 1.1 leaves the unit unsaid. - The recommendation is never nil. The binding file's earlier vectors D and E used a nil recommendation; its updated D and E use `"a"`, as here. diff --git a/packages/cultnet-ts/test/governance-vectors.test.ts b/packages/cultnet-ts/test/governance-vectors.test.ts index a982753c..1c7bc07d 100644 --- a/packages/cultnet-ts/test/governance-vectors.test.ts +++ b/packages/cultnet-ts/test/governance-vectors.test.ts @@ -242,6 +242,8 @@ function judge(start: Card, steps: { kind: string; body: Record | n const refuse = (code: string) => store("Refused", null, code); const down = s.door_down === true, reached = s.stored === true; // the second door failed to answer; "stored" says whether Huginn had the request by then const unavailable = () => ({ schemaVersion: "gamecult.fork.unavailable.v0", code: "unavailable", error: "unavailable: the outcome is not confirmed, try again with the same request_id", retryAfterSeconds: s.retry_after_seconds }); + // a stored desk_answer has no card, so a replayed stale_fork carries the CURRENT card (fork-card.md, request_id) + const replay = (stored: any) => { const copy = structuredClone(stored); if (copy.answer.code === "stale_fork") copy.card = structuredClone(card); return copy; }; let response: unknown; if (s.answerer === null) response = door("unauthenticated"); else if (s.active === false) response = door("forbidden"); @@ -249,7 +251,7 @@ function judge(start: Card, steps: { kind: string; body: Record | n else if (Object.keys(b).some((k) => !REQUEST_KEYS.includes(k)) || (b.answer && Object.keys(b.answer).some((k) => k !== "choice" && k !== "note"))) response = door("body_unknown_field"); else if (!check(forkSchema, "answerRequest", b) || noteRuleErrors("answerRequest", b).length > 0 || (!b.retracted && b.answer === null)) response = door("body_invalid"); else if (down && !reached) response = unavailable(); - else if (seen.has(`${s.answerer}|${b.request_id}`)) { const prior = seen.get(`${s.answerer}|${b.request_id}`)!; response = isDeepStrictEqual(prior.body, b) ? structuredClone(prior.response) : door("request_id_conflict"); } + else if (seen.has(`${s.answerer}|${b.request_id}`)) { const prior = seen.get(`${s.answerer}|${b.request_id}`)!; response = isDeepStrictEqual(prior.body, b) ? replay(prior.response) : door("request_id_conflict"); } else if (b.fork_id !== card.fork_id) response = door("fork_unknown"); else if (b.options_hash !== optionsHash(card)) response = refuse("stale_fork"); else if (!card.deciders.includes(s.answerer)) response = refuse("not_a_decider"); diff --git a/scripts/gen-governance-vectors.py b/scripts/gen-governance-vectors.py index 1604ce56..7b5280bb 100644 --- a/scripts/gen-governance-vectors.py +++ b/scripts/gen-governance-vectors.py @@ -269,6 +269,8 @@ X1 = ok(x1, sx1, "Counted", None) REPLAY1 = (step("answer", x1, dict(sx1, answer_id="n9"), X1[0]["response"]), None) LOST = [(step("answer", x1, dict(sx1, door_down=True, stored=True, retry_after_seconds=30), unavailable_doc(30)), X1[1])] STALE_BODY = stale_body(); STALE_RF = rf(STALE_BODY, sx1, "stale_fork", c=CARD) +OFFLIST = rf(x1, srv("n1", ST, T(2), "Member"), "not_a_decider") +OFFLIST_REPLAY = (step("answer", x1, srv("n9", ST, T(4), "Member"), OFFLIST[0]["response"]), None) scen = [ sc("operator_answers_and_is_counted", CARD, [X1], "n1"), sc("choice_alone_is_counted", CARD, [ok(pick, sx1, "Counted", None)], "n1"), @@ -282,7 +284,14 @@ scen = [ sc("unavailable_before_huginn_stored_nothing_is_retried_into_a_Counted_answer", CARD, [step("answer", x1, dict(sx1, answer_id="n9", door_down=True, retry_after_seconds=30), unavailable_doc(30)), ok(x1, sx1, "Counted", None)], "n1"), sc("unavailable_after_huginn_stored_the_retry_with_the_same_request_id_returns_the_stored_outcome", CARD, LOST + [REPLAY1], "n1"), sc("a_retry_never_adds_a_Revision", CARD, [X1, REPLAY1], "n1"), - sc("a_refused_answer_replays_its_refusal_with_the_card_it_carried", CARD, [STALE_RF, (step("answer", STALE_BODY, dict(sx1, answer_id="n9"), STALE_RF[0]["response"]), None)], None), + sc("Q1_a_replayed_stale_fork_returns_the_CURRENT_card_and_stores_nothing_new", CARD, [STALE_RF, step("card", None, None, None, card=fork_edit), + (step("answer", STALE_BODY, dict(sx1, answer_id="n9"), result(STALE_RF[1], fork_edit)), None)], None, H2), + sc("V13_only_answered_at_changed_is_request_id_conflict", CARD, [X1, door(dict(x1, answered_at="2026-11-12T19:03:00Z"), dict(sx1, answer_id="n9"), "request_id_conflict")], "n1"), + sc("V14_an_identical_body_from_another_account_gets_its_own_Counted_and_never_the_first_accounts_outcome", Y_CARD, [OFFLIST, ok(x1, srv("n2", HM, T(3), "Steward"), "Counted", None), OFFLIST_REPLAY], "n2"), + sc("V14_an_identical_body_from_another_decider_is_its_own_Revision_and_the_first_retry_still_returns_n1", Y_CARD, [X1, ok(x1, sy1, "Revision", "n1"), (step("answer", x1, dict(sx1, answer_id="n9"), X1[0]["response"]), None)], "n1"), + sc("V16_Q5_a_forbidden_request_binds_no_request_id", CARD, [door(x1, dict(sx1, answer_id="n9", active=False), "forbidden"), ok(x1, sx1, "Counted", None)], "n1"), + sc("V17_Q6_a_body_refused_at_the_door_binds_no_request_id", CARD, [door(dict(x1, mood="happy"), dict(sx1, answer_id="n9"), "body_unknown_field"), ok(x1, sx1, "Counted", None)], "n1"), + sc("V17_Q6_an_unknown_fork_binds_no_request_id", CARD, [door(dict(x1, fork_id="gamecult-chat:question:nope"), dict(sx1, answer_id="n9"), "fork_unknown"), ok(x1, sx1, "Counted", None)], "n1"), sc("the_same_request_id_with_another_body_is_request_id_conflict", CARD, [X1, door(dict(x1, answer={"choice": "yes", "note": None}), dict(sx1, answer_id="n9"), "request_id_conflict")], "n1"), sc("the_same_request_id_from_another_account_is_another_request", Y_CARD, [X1, ok(dict(y1, request_id=x1["request_id"]), sy1, "Revision", "n1")], "n1"), sc("a_non_active_member_is_forbidden_before_the_body_is_read", CARD, [door(dict(x1, answerer="x"), dict(sx1, active=False), "forbidden"), door(x1, dict(sx1, active=False), "forbidden"), @@ -425,6 +434,7 @@ fork = { ("answer_with_neither", "an answer object holds a choice, a note, or both", body(answer={"choice": None, "note": None})), ("blank_note", "a blank note is no answer", body(None, " \u00a0 ")), ("request_id_missing", "map-mode writes every key; a retry needs the id", {k: v for k, v in x1.items() if k != "request_id"}), + ("request_id_uppercase", "request_id is lowercase", dict(x1, request_id="0000000A-0000-4000-8000-00000000000B")), ("request_id_not_a_uuid", "request_id is a lowercase D-format UUID", dict(x1, request_id="retry-1")), ("note_over_4000", "notes are at most 4000 UTF-8 bytes", body(None, "x" * 4001)), ("note_multibyte_4001_bytes", "a note is counted in UTF-8 bytes: 1999 e-acute is 3998 bytes, plus three ASCII is 4001 (rule: not expressible in the schema, 2002 characters)", body(None, "\u00e9" * 1999 + "abc")), diff --git a/tests/GameCult.Networking.Tests/GovernanceVectorTests.cs b/tests/GameCult.Networking.Tests/GovernanceVectorTests.cs index 9579e427..e3af0a76 100644 --- a/tests/GameCult.Networking.Tests/GovernanceVectorTests.cs +++ b/tests/GameCult.Networking.Tests/GovernanceVectorTests.cs @@ -357,6 +357,8 @@ namespace GameCult.Networking.Tests var down = s["door_down"] is not null; // the second door failed to answer; "stored" says whether Huginn had the request by then var reached = s["stored"] is not null; JsonNode Unavailable() => new JsonObject { ["schemaVersion"] = "gamecult.fork.unavailable.v0", ["code"] = "unavailable", ["error"] = "unavailable: the outcome is not confirmed, try again with the same request_id", ["retryAfterSeconds"] = Clone(s["retry_after_seconds"]) }; + // a stored desk_answer has no card, so a replayed stale_fork carries the CURRENT card (fork-card.md, request_id) + JsonNode Replay(JsonNode stored) { var copy = Clone(stored)!; if (S(copy["answer"]!["code"] ?? "") == "stale_fork") copy["card"] = Clone(card); return copy; } JsonNode response; if (s["answerer"] is null) response = Door("unauthenticated"); else if (s["active"] is JsonValue activeValue && !activeValue.GetValue()) response = Door("forbidden"); @@ -364,7 +366,7 @@ namespace GameCult.Networking.Tests else if (b.Any(kv => !RequestKeys.Contains(kv.Key)) || (b["answer"] is JsonObject ao && ao.Any(kv => kv.Key is not ("choice" or "note")))) response = Door("body_unknown_field"); else if (Errors(ForkSchema, "answerRequest", b).Count > 0 || NoteRuleErrors("answerRequest", b).Any() || (!retracted && b["answer"] is null)) response = Door("body_invalid"); else if (down && !reached) response = Unavailable(); - else if (seen.TryGetValue(S(s["answerer"]) + "|" + S(b["request_id"]), out var prior)) response = JsonNode.DeepEquals(prior.Body, b) ? Clone(prior.Response)! : Door("request_id_conflict"); + else if (seen.TryGetValue(S(s["answerer"]) + "|" + S(b["request_id"]), out var prior)) response = JsonNode.DeepEquals(prior.Body, b) ? Replay(prior.Response) : Door("request_id_conflict"); else if (S(b["fork_id"]) != S(card["fork_id"])) response = Door("fork_unknown"); else if (S(b["options_hash"]) != HashOf(card)) response = Refuse("stale_fork"); else if (!deciders.Contains(S(s["answerer"]))) response = Refuse("not_a_decider");