RulingAuthority gains Mind: a ruling the Mind's Self makes is its own word

Additive unit-enum variant; schemas regenerated by derivation. The query
alias domain now derives from the enum (unit_enums! exposes NAMES), so the
second authority list in huginn-mind rows.rs is gone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Meta Vens 2026-10-09 15:35:22 +02:00
commit 775148f28b
7 changed files with 74 additions and 7 deletions

View file

@ -439,6 +439,11 @@ macro_rules! unit_enums {
($($name:ident { $($variant:ident),* $(,)? })*) => {$(
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, JsonSchema)]
pub enum $name { $($variant),* }
impl $name {
/// The variants' spellings, in declaration order: the names the wire and
/// `Debug` use.
pub const NAMES: &'static [&'static str] = &[$(stringify!($variant)),*];
}
impl Bounded for $name {
fn validate(&self, _field: &str) -> Result<(), PipelineRefusal> {
Ok(())
@ -472,7 +477,7 @@ unit_enums! {
ClaimOutcome { Holds, Falsified, Unproven }
FindingConfidence { Confirmed, Plausible }
FindingSeverity { Blocker, High, Medium, Low }
RulingAuthority { Operator, Standing, Defaulted }
RulingAuthority { Operator, Standing, Defaulted, Mind }
FindingOrigin { Introduced, PreExisting }
}
@ -1269,6 +1274,39 @@ mod tests {
ruling
}
/// A ruling the Mind's own Self made: authority Mind, no operator quote,
/// no question answered. Built from the ruling sample, not inserted into
/// `samples()`, whose tests pick kinds by index.
fn mind_ruling() -> PipelineRuling {
let mut ruling = ruling_sample();
(ruling.authority, ruling.operator_quote, ruling.answers, ruling.choice) = (RulingAuthority::Mind, None, None, None);
ruling
}
#[test]
fn a_ruling_with_authority_mind_keys_encodes_and_round_trips_like_any_ruling() -> Result<()> {
let cache = schema_cache()?;
let document = PipelineDocument::Ruling(mind_ruling());
document.validate()?;
let envelope = document.prepare(&cache)?;
assert!(envelope.key.starts_with("eureka-state:ruling:"), "{}", envelope.key);
assert_eq!(PipelineDocument::decode(&envelope)?, document);
let json = serde_json::to_value(&document)?;
assert_eq!(json["value"]["authority"], "Mind");
assert_eq!(serde_json::from_value::<PipelineDocument>(json)?, document);
let packed = rmp_serde::to_vec_named(&document)?;
assert_eq!(rmp_serde::from_slice::<PipelineDocument>(&packed)?, document);
let standing = PipelineDocument::Ruling(ruling_sample());
assert_ne!(standing.prepare(&cache)?.payload, envelope.payload, "Mind is not a spelling of another authority");
Ok(())
}
#[test]
fn unit_enum_names_are_the_variants_in_declaration_order() {
assert_eq!(RulingAuthority::NAMES, ["Operator", "Standing", "Defaulted", "Mind"]);
assert_eq!(FindingOrigin::NAMES, ["Introduced", "PreExisting"]);
}
fn report_sample() -> PipelineCutReport {
let PipelineDocument::CutReport(report) = samples().remove(5).0 else { unreachable!() };
report
@ -1340,6 +1378,7 @@ mod tests {
f.severity = severity;
out.push((format!("finding.severity-{name}"), D::Finding(f)));
}
out.push(("ruling.authority-mind".into(), D::Ruling(mind_ruling())));
out
}

View file

@ -1859,10 +1859,21 @@ mod tests {
let mut quoted = ruling("R1");
quoted.operator_quote = Some("all recommendations, go ahead".into());
assert_eq!(refusal(admit(&mut mind, vec![D::Ruling(quoted.clone())])), MindRefusal::QuoteWithoutOperator { ruling: id("ruling", "R1") });
quoted.authority = RulingAuthority::Mind;
assert_eq!(refusal(admit(&mut mind, vec![D::Ruling(quoted.clone())])), MindRefusal::QuoteWithoutOperator { ruling: id("ruling", "R1") });
assert!(mind.get(K::Ruling, &id("ruling", "R1")).unwrap().is_none(), "a refused batch leaves the store unchanged");
quoted.authority = RulingAuthority::Operator;
committed(admit(&mut mind, vec![D::Ruling(quoted)]));
}
#[test]
fn a_mind_ruling_without_a_quote_is_admitted() {
let mut mind = seeded();
let mut own = ruling("R1");
own.authority = RulingAuthority::Mind;
committed(admit(&mut mind, vec![D::Ruling(own)]));
}
#[test]
fn a_revision_requires_its_predecessors_supersession_in_the_batch() {
let mut mind = seeded();

View file

@ -1219,6 +1219,21 @@ mod tests {
}
}
/// The alias domain and the enum agree: a Mind-authority ruling is
/// selectable by its own word, and only by it.
#[test]
fn a_query_for_mind_authority_is_answered() {
let mut mind = seeded();
let mut own = ruling("R1");
own.authority = RulingAuthority::Mind;
committed(admit(&mut mind, vec![D::Ruling(own), D::Ruling(ruling("R2"))]));
let by = |word: &str| mind.query(&with(of_kinds(&[K::Ruling]), any_of("authority", &[word]))).unwrap();
assert_eq!(by("Mind").matched, 1);
assert_eq!(by("Standing").matched, 1);
let misspelt = with(of_kinds(&[K::Ruling]), any_of("authority", &["Minds"]));
assert!(matches!(refused(&mind, &misspelt), MindRefusal::SelectionInvalid { value: Some(v), .. } if v == "Minds"));
}
#[test]
fn an_unknown_schema_or_malformed_key_is_refused() {
let mind = worked();

View file

@ -12,7 +12,7 @@
use std::collections::BTreeMap;
use cultnet_rs::{Row, RowSet, Selection};
use eureka_pipeline::{OrgRepo, Label, PipelineDocument, PipelineKind, PipelineRef, ResolutionOutcome, Slug};
use eureka_pipeline::{OrgRepo, Label, PipelineDocument, PipelineKind, PipelineRef, ResolutionOutcome, RulingAuthority, Slug};
use crate::docs::{CitationRole, Held, kind_of_id, kind_of_type};
use crate::query::PipelineDocumentView;
@ -43,7 +43,6 @@ const FACULTIES: [&str; 7] = ["SelfFaculty", "Imagination", "Hands", "Soul", "Li
const SEVERITIES: [&str; 4] = ["Blocker", "High", "Medium", "Low"];
const CONFIDENCES: [&str; 2] = ["Confirmed", "Plausible"];
const ORIGINS: [&str; 2] = ["Introduced", "PreExisting"];
const AUTHORITIES: [&str; 3] = ["Operator", "Standing", "Defaulted"];
const CLAIM_OUTCOMES: [&str; 3] = ["Holds", "Falsified", "Unproven"];
const OUTCOMES: [&str; 6] = ["Superseded", "Answered", "Fixed", "Deferred", "Recorded", "Withdrawn"];
const BOOLEANS: [&str; 2] = ["true", "false"];
@ -106,7 +105,7 @@ impl Alias {
Self::Severity => Some(&SEVERITIES),
Self::Confidence => Some(&CONFIDENCES),
Self::Origin => Some(&ORIGINS),
Self::Authority => Some(&AUTHORITIES),
Self::Authority => Some(RulingAuthority::NAMES),
Self::ClaimOutcome => Some(&CLAIM_OUTCOMES),
Self::Outcome => Some(&OUTCOMES),
Self::Root | Self::Repo | Self::Cut => None,

View file

@ -75,7 +75,8 @@
"enum": [
"Operator",
"Standing",
"Defaulted"
"Defaulted",
"Mind"
],
"type": "string"
},

View file

@ -1674,7 +1674,8 @@
"enum": [
"Operator",
"Standing",
"Defaulted"
"Defaulted",
"Mind"
]
},
"SemanticQuery": {

View file

@ -3702,7 +3702,8 @@
"enum": [
"Operator",
"Standing",
"Defaulted"
"Defaulted",
"Mind"
]
},
"Sha": {