From 14a914a6341df6b61ecc44b30d2b11cd212efcc3 Mon Sep 17 00:00:00 2001 From: Eureka Date: Tue, 10 Nov 2026 20:44:11 +0000 Subject: [PATCH] Desk wire envelope delta: decode refuses an empty decider list (minItems 1) Co-Authored-By: Claude Sonnet 5.5 --- crates/huginn-mind/src/desk_wire.rs | 8 ++++++-- schemas/cultnet/huginn.desk_request.v1.schema.json | 5 ++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/crates/huginn-mind/src/desk_wire.rs b/crates/huginn-mind/src/desk_wire.rs index 35382f4..028f424 100644 --- a/crates/huginn-mind/src/desk_wire.rs +++ b/crates/huginn-mind/src/desk_wire.rs @@ -207,7 +207,7 @@ pub const DESK_MAX_RESPONSE_BYTES: usize = 65536; /// Most deciders one call carries (CultLib `card.deciders` `maxItems`). pub const DESK_DECIDERS_MAX: usize = 64; -/// A decider list, read whole or not at all: at most `DESK_DECIDERS_MAX`, no subject twice. A +/// A decider list, read whole or not at all: one to `DESK_DECIDERS_MAX` subjects, none twice. A /// bad list is the decoder's refusal, which names the field and never quotes a subject. fn deciders<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result, D::Error> { struct List; @@ -227,6 +227,9 @@ fn deciders<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result schemars::Schem schemars::json_schema!({ "type": "array", "items": generator.subschema_for::(), + "minItems": 1, "maxItems": DESK_DECIDERS_MAX, "uniqueItems": true }) @@ -245,7 +249,7 @@ fn deciders_schema(generator: &mut schemars::SchemaGenerator) -> schemars::Schem /// Every request the desk door answers. The fields are the wire names: the `mind` addressed /// (the persona and pipeline requests say `instance`; the sets are separate), the verified /// `subject` and `authority` Bifrost vouches for (door context, never body fields), and the -/// `deciders` of this call, which the Mind never stores. Closed: a key outside the set refuses +/// `deciders` of this call (1 to 64, distinct; the Mind never stores them). Closed: a key outside the set refuses /// the whole payload. The reads answer in follow-up desk-wire-reads. #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[serde(deny_unknown_fields)] diff --git a/schemas/cultnet/huginn.desk_request.v1.schema.json b/schemas/cultnet/huginn.desk_request.v1.schema.json index 53f3598..caaa6a6 100644 --- a/schemas/cultnet/huginn.desk_request.v1.schema.json +++ b/schemas/cultnet/huginn.desk_request.v1.schema.json @@ -1,7 +1,7 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "DeskRequest", - "description": "Every request the desk door answers. The fields are the wire names: the `mind` addressed\n(the persona and pipeline requests say `instance`; the sets are separate), the verified\n`subject` and `authority` Bifrost vouches for (door context, never body fields), and the\n`deciders` of this call, which the Mind never stores. Closed: a key outside the set refuses\nthe whole payload. The reads answer in follow-up desk-wire-reads.", + "description": "Every request the desk door answers. The fields are the wire names: the `mind` addressed\n(the persona and pipeline requests say `instance`; the sets are separate), the verified\n`subject` and `authority` Bifrost vouches for (door context, never body fields), and the\n`deciders` of this call (1 to 64, distinct; the Mind never stores them). Closed: a key outside the set refuses\nthe whole payload. The reads answer in follow-up desk-wire-reads.", "oneOf": [ { "type": "object", @@ -18,6 +18,7 @@ "$ref": "#/$defs/Short" }, "maxItems": 64, + "minItems": 1, "uniqueItems": true }, "mind": { @@ -57,6 +58,7 @@ "$ref": "#/$defs/Short" }, "maxItems": 64, + "minItems": 1, "uniqueItems": true }, "mind": { @@ -91,6 +93,7 @@ "$ref": "#/$defs/Short" }, "maxItems": 64, + "minItems": 1, "uniqueItems": true }, "fork_id": {