Delete every committed mutation suite

Better to have nothing than a harness that punishes refactoring
(operator ruling, 2026-09-22). Remove tools/eureka-cut8-mutations.psd1
(825 lines), eureka-cut9-mutations.psd1 (371), eureka-cut10-mutations.psd1
(994) and eureka-readside-mutations.psd1 (225). cut9, cut10 and readside
carried uncommitted edits that are now moot and are dropped with the
files. The harness that ran them, eureka-mutations.ps1, was already
deleted from the Eureka skill (37c80e4).

Code comments in crates/huginn-mind/src/mind.rs and
crates/huginn-daemon/src/serve.rs that cited entry ids from the
deleted suites (R5b, R5c, N1, N3, S2, S4, S3wide, Residue S1) are
reworded to drop the id or name the test that pins the rule instead;
each comment already sits beside that test. Comments citing F- and
other S/A-prefixed labels that do not match any entry in the deleted
files (F2-F6, S1, S5, A1, and the D3/D4/D5/D8 in query.rs, which name
a different rule than the D3/D4/D5/D8 entries in the deleted files)
are untouched.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Meta Vens 2026-09-22 18:45:53 +02:00
commit 7771c37c32
6 changed files with 16 additions and 2383 deletions

View file

@ -871,7 +871,7 @@ mod tests {
}
}
/// Residue S1: every fixture up to this one, including the pair above,
/// Every fixture up to this one, including the pair above,
/// moves `operation` and the runtime id together -- both short (`view`,
/// 4 bytes / `huginn-yggdrasil`, 16) or both long (`whoami`, 6 /
/// `huginn-thought-cage`, 19) -- so a formula that tracks only one of the

View file

@ -460,19 +460,19 @@ mod tests {
);
}
/// F3 (RS fix batch), R5b: a foreign store with no epoch record at all
/// still refuses `MissingIdentity`, the epoch-first order's own answer
/// (F5, read-side cut) -- not `ForeignStore`, which is what a mutant that
/// only reorders the gates when there *is* some epoch record present
/// would answer, by running the type gate first over a store that has
/// no epoch record to look at.
/// A foreign store with no epoch record at all still refuses
/// `MissingIdentity`, the epoch-first order's own answer -- not
/// `ForeignStore`, which is what a mutant that only reorders the gates
/// when there *is* some epoch record present would answer, by running
/// the type gate first over a store that has no epoch record to look at.
/// Pinned by this test.
#[test]
fn a_foreign_type_with_no_epoch_record_is_missing_identity_not_foreign_store() {
let store = planted(vec![foreign("epiphany.pipeline.campaign.v1")]);
assert_eq!(Mind::open_with(store, &slug(INSTANCE)).err(), Some(MindRefusal::MissingIdentity));
}
/// F3 (RS fix batch), R5c: an epoch record at the current key, but a
/// F3 (RS fix batch): an epoch record at the current key, but a
/// foreign value, beside a foreign type, still refuses `ForeignEpoch` --
/// the epoch gate reads the record's *value* before the type gate ever
/// runs, not only when the record's *key* is itself foreign. A mutant
@ -583,7 +583,7 @@ mod tests {
}
}
/// N3: one generated test in place of more fixture pairs. The base name
/// One generated test in place of more fixture pairs. The base name
/// carries all three separator bytes a `Slug` permits -- `_`, `.` and `-`
/// -- at three non-adjacent positions, so every combination of swapping
/// one separator for another at a fixed position is itself a grammatical,
@ -685,7 +685,7 @@ mod tests {
assert!(!inner.join("minds").exists(), "no store was created under the state root either");
}
/// S2: `open_with` is the door `open` shares with every store already in
/// `open_with` is the door `open` shares with every store already in
/// hand (planted directly, or opened by a test through `store_path_for`),
/// so it must run `require_grammatical_slug` too, not only `open`'s own
/// path-joining caller. A store need not hold anything for this to
@ -704,7 +704,7 @@ mod tests {
assert_eq!(store.pull_count(), 0, "refused before the store was ever pulled");
}
/// S2: `require_instance` is A1 for admission and the daemon's reads
/// `require_instance` is A1 for admission and the daemon's reads
/// alike, and it runs the same grammar door on the *declared* name before
/// comparing it to the mind's own. A declared name outside the grammar is
/// `InvalidFormat { field: "declared" }`, never folded into a comparison
@ -722,11 +722,13 @@ mod tests {
);
}
/// S4: a Unicode hyphen (U+2010) is not ASCII `-`, so a grammatical
/// A Unicode hyphen (U+2010) is not ASCII `-`, so a grammatical
/// `Slug` never contains one and a name carrying it is refused by the
/// leaf's own grammar as written -- nothing here may fold it to plain
/// `-` before asking `Slug::validate_slug`, the way `S3wide`'s fullwidth
/// mutant folds a fullwidth letter to its ASCII form.
/// `-` before asking `Slug::validate_slug`, the way a fullwidth mutant
/// pinned by
/// `daemon::tests::a_declared_instance_outside_the_grammar_is_refused_by_name_before_the_identity_check`
/// folds a fullwidth letter to its ASCII form.
#[test]
fn a_unicode_hyphen_is_not_folded_before_the_grammar_check() {
let declared = Slug(format!("ab{}cd", '\u{2010}'));

View file

@ -1,994 +0,0 @@
# Cut 10 mutations, D1-D22: the CultNet surface's rules. Each rule has a
# revert, `Dn`, which removes the rule, and a loosening, `DnL`, which weakens
# it rather than removing it, because a plain revert is the easy target. Every
# entry names the test that must fail while it is applied. Run through the
# Eureka skill's harness from this repo:
#
# $env:CARGO_TARGET_DIR = 'C:\Users\Meta\.cargo-target-codex'
# powershell -File C:\Users\Meta\.claude\skills\eureka\tools\eureka-mutations.ps1 -Repo F:\Projects\Huginn `
# -Entries tools/eureka-cut10-mutations.psd1 `
# -Target crates/huginn-mind/src/mind.rs,crates/huginn-mind/src/query.rs,crates/huginn-mind/src/wire.rs,crates/huginn-daemon/src/daemon.rs,crates/huginn-daemon/src/envelope.rs,crates/huginn-daemon/src/serve.rs,schemas/cultnet/huginn.mind_request.v1.schema.json,schemas/cultnet/huginn.mind_response.v1.schema.json `
# -Test 'cargo test -p huginn-daemon --lib'
#
# Entries whose test lives in `huginn-mind` carry their own `Command`. `D1` and
# `D1D` are one mutant run against two suites, which is the point of the rule:
# `Mind::require_instance` is the one instance check, and admission and the
# daemon's reads are its two callers. The same edit is `H1` in
# `eureka-cut8-mutations.psd1`.
#
# `M0` is the harness's own no-op control and is not listed here.
#
# Two rules have no loosening and say so rather than carrying a weak entry:
#
# - `D9`, the connection id the hub serves. It is one `u32` handed to
# `CultNetRudpServerHubOptions::new`; a hub serves that id or another one,
# and there is no shape of "serves more ids" to weaken it into.
# - `D12`'s order, weakened as far as it goes by `D12L`: a hub bound before the
# mind is opened and then dropped when the mind refuses. Any weaker form is
# the correct order again.
#
# `D17`-`D18` pin the dispatch's two read arms, `view` and `query`. RS-2
# deleted `open_items` and `history` along with `D19`, `D19L`, `D23` and
# `D23L`, the entries that pinned their arms; `D13` and `D13L` are re-anchored
# on the surviving `view`/`query` arms rather than deleted, since the rule
# they pin (one operation name per method) still holds over what remains.
@{
Mutations = @(
@{
Id = 'D1'
Rule = 'Ruling 14: the mind owns the instance check, and it is a comparison.'
Test = 'mind::tests::require_instance_is_the_one_check_admission_and_the_daemon_share'
Command = 'cargo test -p huginn-mind --lib'
File = 'crates/huginn-mind/src/mind.rs'
Old = @'
if declared != self.instance() {
return Err(MindRefusal::ForeignInstance {
declared: declared.0.clone(),
mind: self.instance().0.clone(),
});
}
Ok(())
'@
New = @'
let _ = declared;
Ok(())
'@
}
@{
Id = 'D1L'
Rule = 'The instance check compares the names, not their lengths.'
Test = 'mind::tests::require_instance_is_the_one_check_admission_and_the_daemon_share'
Command = 'cargo test -p huginn-mind --lib'
File = 'crates/huginn-mind/src/mind.rs'
Old = ' if declared != self.instance() {'
New = ' if declared.0.len() != self.instance().0.len() {'
}
@{
Id = 'D1L2'
Rule = 'It compares the names whole, not their first byte.'
Test = 'mind::tests::require_instance_is_the_one_check_admission_and_the_daemon_share'
Command = 'cargo test -p huginn-mind --lib'
File = 'crates/huginn-mind/src/mind.rs'
Old = ' if declared != self.instance() {'
New = ' if declared.0.as_bytes().first() != self.instance().0.as_bytes().first() {'
}
@{
Id = 'D1L3'
Rule = 'It runs on every declared name, not only on one long enough to look suspicious.'
Test = 'mind::tests::require_instance_is_the_one_check_admission_and_the_daemon_share'
Command = 'cargo test -p huginn-mind --lib'
File = 'crates/huginn-mind/src/mind.rs'
Old = ' if declared != self.instance() {'
New = ' if declared.0.len() > self.instance().0.len() && declared != self.instance() {'
}
@{
Id = 'D1L4'
Rule = 'It compares the names, not whether one begins with the other.'
Test = 'mind::tests::require_instance_is_the_one_check_admission_and_the_daemon_share'
Command = 'cargo test -p huginn-mind --lib'
File = 'crates/huginn-mind/src/mind.rs'
Old = ' if declared != self.instance() {'
New = ' if !declared.0.starts_with(&self.instance().0) {'
}
@{
Id = 'D1L5'
Rule = 'It compares the names as written: a slug may carry uppercase, so two names differing in case are two minds.'
Test = 'mind::tests::require_instance_is_the_one_check_admission_and_the_daemon_share'
Command = 'cargo test -p huginn-mind --lib'
File = 'crates/huginn-mind/src/mind.rs'
Old = ' if declared != self.instance() {'
New = ' if !declared.0.eq_ignore_ascii_case(&self.instance().0) {'
}
@{
Id = 'D1L6'
Rule = 'It compares the names as written: `_` and `-` are both legal inside a label, so folding one into the other answers a different mind''s name for this one.'
Test = 'mind::tests::require_instance_is_the_one_check_admission_and_the_daemon_share'
Command = 'cargo test -p huginn-mind --lib'
File = 'crates/huginn-mind/src/mind.rs'
Old = ' if declared != self.instance() {'
New = ' if declared.0.replace(''_'', "-") != self.instance().0.replace(''_'', "-") {'
}
@{
Id = 'D1L7'
Rule = 'It compares the names as written: `.` joins labels and `-` sits inside one, so folding the join into the separator answers a different mind''s name for this one.'
Test = 'mind::tests::require_instance_is_the_one_check_admission_and_the_daemon_share'
Command = 'cargo test -p huginn-mind --lib'
File = 'crates/huginn-mind/src/mind.rs'
Old = ' if declared != self.instance() {'
New = ' if declared.0.replace(''.'', "-") != self.instance().0.replace(''.'', "-") {'
}
@{
Id = 'D1N'
Rule = 'The refusal names which mind refused, so an agent can act on the field rather than guess.'
Test = 'mind::tests::require_instance_is_the_one_check_admission_and_the_daemon_share'
Command = 'cargo test -p huginn-mind --lib'
File = 'crates/huginn-mind/src/mind.rs'
Old = ' mind: self.instance().0.clone(),'
New = ' mind: declared.0.clone(),'
}
@{
Id = 'D1D'
Rule = 'One check, two callers: the daemon''s reads are refused by the same function admission asks.'
Test = 'daemon::tests::a_read_or_a_write_naming_another_instance_is_refused_by_the_mind_and_writes_nothing'
File = 'crates/huginn-mind/src/mind.rs'
Old = @'
if declared != self.instance() {
return Err(MindRefusal::ForeignInstance {
declared: declared.0.clone(),
mind: self.instance().0.clone(),
});
}
Ok(())
'@
New = @'
let _ = declared;
Ok(())
'@
}
@{
Id = 'D1DL'
Rule = 'The same comparison, reached the daemon''s way: a read naming a name of the mind''s own length is refused too.'
Test = 'daemon::tests::a_read_or_a_write_naming_another_instance_is_refused_by_the_mind_and_writes_nothing'
File = 'crates/huginn-mind/src/mind.rs'
Old = ' if declared != self.instance() {'
New = ' if declared.0.len() != self.instance().0.len() {'
}
@{
Id = 'D1DL2'
Rule = 'And case, the daemon''s way: the daemon''s own fixtures carry a name differing from the mind''s in case alone.'
Test = 'daemon::tests::a_read_or_a_write_naming_another_instance_is_refused_by_the_mind_and_writes_nothing'
File = 'crates/huginn-mind/src/mind.rs'
Old = ' if declared != self.instance() {'
New = ' if !declared.0.eq_ignore_ascii_case(&self.instance().0) {'
}
@{
Id = 'N3a'
Rule = 'N3: the comparison folds nothing; `_` and `.` stay distinct on both sides.'
Test = 'mind::tests::every_separator_variant_of_a_declared_name_is_foreign_not_the_mind'
Command = 'cargo test -p huginn-mind --lib'
File = 'crates/huginn-mind/src/mind.rs'
Old = ' if declared != self.instance() {'
New = ' if declared.0.replace(''_'', ".") != self.instance().0.replace(''_'', ".") {'
}
@{
Id = 'N3b'
Rule = 'N3: the comparison folds nothing on the mind''s own side alone; `_` and `-` stay distinct there too.'
Test = 'mind::tests::every_separator_variant_of_a_declared_name_is_foreign_not_the_mind'
Command = 'cargo test -p huginn-mind --lib'
File = 'crates/huginn-mind/src/mind.rs'
Old = ' if declared != self.instance() {'
New = ' if declared.0 != self.instance().0.replace(''_'', "-") {'
}
@{
Id = 'N3c'
Rule = 'N3: a leading or trailing `-` is part of the name, not padding `trim_matches` may strip before comparing.'
Test = 'mind::tests::every_separator_variant_of_a_declared_name_is_foreign_not_the_mind'
Command = 'cargo test -p huginn-mind --lib'
File = 'crates/huginn-mind/src/mind.rs'
Old = ' if declared != self.instance() {'
New = ' if declared.0.trim_matches(''-'') != self.instance().0.trim_matches(''-'') {'
}
@{
Id = 'N3d'
Rule = 'N3: a run of `--` is two hyphens, not one collapsed by the comparison before it runs.'
Test = 'mind::tests::every_separator_variant_of_a_declared_name_is_foreign_not_the_mind'
Command = 'cargo test -p huginn-mind --lib'
File = 'crates/huginn-mind/src/mind.rs'
Old = ' if declared != self.instance() {'
New = ' if declared.0.replace("--", "-") != self.instance().0.replace("--", "-") {'
}
@{
Id = 'S3wide'
Rule = 'The grammar check runs on the declared bytes as given: nothing folds a fullwidth character to its plain ASCII form before asking the leaf''s Slug::validate_slug whether the name is grammatical.'
Test = 'daemon::tests::a_declared_instance_outside_the_grammar_is_refused_by_name_before_the_identity_check'
Command = 'cargo test -p huginn-daemon --lib'
File = 'crates/huginn-mind/src/mind.rs'
Old = @'
fn require_grammatical_slug(field: &str, declared: &Slug) -> Result<(), MindRefusal> {
declared.validate_slug().map_err(|_| {
MindRefusal::Document(epiphany_pipeline::PipelineRefusal::InvalidFormat {
field: field.into(),
value: declared.0.clone(),
})
})
}
'@
New = @'
fn require_grammatical_slug(field: &str, declared: &Slug) -> Result<(), MindRefusal> {
let folded = Slug(
declared
.0
.chars()
.map(|c| match c as u32 {
0xFF01..=0xFF5E => char::from_u32(c as u32 - 0xFEE0).unwrap_or(c),
_ => c,
})
.collect(),
);
folded.validate_slug().map_err(|_| {
MindRefusal::Document(epiphany_pipeline::PipelineRefusal::InvalidFormat {
field: field.into(),
value: declared.0.clone(),
})
})
}
'@
}
# Residue S2: N1's door, `require_grammatical_slug`, had no mutation
# entry for two of its three callers. `open`'s deletion is covered by
# N1's own escape test; `open_with`'s survived all 81 tests before
# this batch added one that names it; `require_instance`'s is covered
# the same way, since neither caller's test constructs an ungrammatical
# name the other way.
@{
Id = 'N1open'
Rule = 'N1: `open` checks the declared name''s grammar before it ever joins a path from it.'
Test = 'mind::tests::a_slug_outside_the_grammar_cannot_escape_the_state_root'
Command = 'cargo test -p huginn-mind --lib'
File = 'crates/huginn-mind/src/mind.rs'
Old = @'
pub fn open(state_root: &Path, instance: &Slug) -> Result<Self, MindRefusal> {
require_grammatical_slug("instance", instance)?;
let path = Self::path_for(state_root, instance);
'@
New = @'
pub fn open(state_root: &Path, instance: &Slug) -> Result<Self, MindRefusal> {
let path = Self::path_for(state_root, instance);
'@
}
@{
Id = 'N1openwith'
Rule = 'N1: `open_with` checks the declared name''s grammar too, for every store already in hand and not only for one `open` derived a path for.'
Test = 'mind::tests::open_with_refuses_a_declared_instance_outside_the_grammar'
Command = 'cargo test -p huginn-mind --lib'
File = 'crates/huginn-mind/src/mind.rs'
Old = @'
pub fn open_with(store: S, instance: &Slug) -> Result<Self, MindRefusal> {
require_grammatical_slug("instance", instance)?;
let raw = store.pull_all().map_err(unavailable)?;
'@
New = @'
pub fn open_with(store: S, instance: &Slug) -> Result<Self, MindRefusal> {
let raw = store.pull_all().map_err(unavailable)?;
'@
}
@{
Id = 'N1requireinstance'
Rule = 'N1: `require_instance` checks the declared name''s grammar before comparing it to the mind''s own, so an ungrammatical name is refused by name rather than merely being foreign.'
Test = 'mind::tests::require_instance_refuses_a_declared_name_outside_the_grammar'
Command = 'cargo test -p huginn-mind --lib'
File = 'crates/huginn-mind/src/mind.rs'
Old = @'
pub fn require_instance(&self, declared: &Slug) -> Result<(), MindRefusal> {
require_grammatical_slug("declared", declared)?;
if declared != self.instance() {
'@
New = @'
pub fn require_instance(&self, declared: &Slug) -> Result<(), MindRefusal> {
if declared != self.instance() {
'@
}
@{
Id = 'S4fold'
Rule = 'Residue S4: the grammar check runs on the declared bytes as given: nothing folds a Unicode hyphen (U+2010) to plain ASCII `-` before asking Slug::validate_slug whether the name is grammatical.'
Test = 'mind::tests::a_unicode_hyphen_is_not_folded_before_the_grammar_check'
Command = 'cargo test -p huginn-mind --lib'
File = 'crates/huginn-mind/src/mind.rs'
Old = @'
fn require_grammatical_slug(field: &str, declared: &Slug) -> Result<(), MindRefusal> {
declared.validate_slug().map_err(|_| {
MindRefusal::Document(epiphany_pipeline::PipelineRefusal::InvalidFormat {
field: field.into(),
value: declared.0.clone(),
})
})
}
'@
New = @'
fn require_grammatical_slug(field: &str, declared: &Slug) -> Result<(), MindRefusal> {
let folded = Slug(declared.0.chars().map(|c| if c == '\u{2010}' { '-' } else { c }).collect());
folded.validate_slug().map_err(|_| {
MindRefusal::Document(epiphany_pipeline::PipelineRefusal::InvalidFormat {
field: field.into(),
value: declared.0.clone(),
})
})
}
'@
}
@{
Id = 'D2'
Rule = 'Rulings 14 and 18 on the wire: the daemon passes the declared instance to the mind as the client sent it.'
Test = 'daemon::tests::a_read_or_a_write_naming_another_instance_is_refused_by_the_mind_and_writes_nothing'
File = 'crates/huginn-daemon/src/daemon.rs'
Old = @'
HuginnMindRequest::Admit(batch) => {
let outcome = self.mind.admit(batch, now);
'@
New = @'
HuginnMindRequest::Admit(mut batch) => {
batch.instance = self.mind.instance().clone();
let outcome = self.mind.admit(batch, now);
'@
}
@{
Id = 'D2L'
Rule = 'Every read that names an instance is checked, not only the one that returns a page.'
Test = 'daemon::tests::a_read_or_a_write_naming_another_instance_is_refused_by_the_mind_and_writes_nothing'
File = 'crates/huginn-daemon/src/daemon.rs'
Old = ' && !matches!(request, HuginnMindRequest::Admit(_))'
New = ' && matches!(request, HuginnMindRequest::Query { .. })'
}
@{
Id = 'D3'
Rule = 'A refusal is data in the response, never a transport failure the client must parse out of a failure envelope.'
Test = 'serve::tests::a_malformed_envelope_is_answered_with_a_failure_and_touches_no_mind'
File = 'crates/huginn-daemon/src/serve.rs'
Old = ' let reply = encode_or_fail(&message_id, operation, &response, &runtime_id);'
New = @'
if let HuginnMindResponse::Refused(refusal) = &response {
return encode_failure(
&message_id,
operation,
&crate::envelope::OperationFailure {
code: "refused".into(),
message: format!("{refusal}"),
},
&runtime_id,
);
}
let reply = encode_or_fail(&message_id, operation, &response, &runtime_id);
'@
}
@{
Id = 'D3L'
Rule = 'The envelope''s status is derived from the response, so a refusal cannot go out as an acceptance.'
Test = 'wire::tests::the_wire_vocabulary_is_the_minds_methods_and_status_is_derived_from_the_response'
Command = 'cargo test -p huginn-mind --lib'
File = 'crates/huginn-mind/src/wire.rs'
Old = ' Self::Refused(_) | Self::Admit(PipelineAdmissionOutcome::Refused(_)) => "rejected",'
New = ' Self::Admit(PipelineAdmissionOutcome::Refused(_)) => "rejected",'
}
@{
Id = 'D4'
Rule = 'An envelope the daemon cannot decode touches no mind; it is answered with its own failure code.'
Test = 'serve::tests::a_malformed_envelope_is_answered_with_a_failure_and_touches_no_mind'
File = 'crates/huginn-daemon/src/envelope.rs'
Old = @'
let request: HuginnMindRequest = rmp_serde::from_slice(&bytes)
.map_err(|error| OperationFailure::new("payload-not-a-request", error.to_string()))?;
'@
New = @'
let request: HuginnMindRequest = rmp_serde::from_slice(&bytes).unwrap_or(HuginnMindRequest::Whoami);
'@
}
@{
Id = 'D4L'
Rule = 'The envelope is addressed to this service, and a request for another one is refused rather than served.'
Test = 'serve::tests::a_malformed_envelope_is_answered_with_a_failure_and_touches_no_mind'
File = 'crates/huginn-daemon/src/envelope.rs'
Old = @'
if service_id != MIND_SERVICE_ID {
return Err(OperationFailure::new("wrong-service", format!("{service_id} is not {MIND_SERVICE_ID}")));
}
'@
New = @'
let _ = service_id;
'@
}
@{
Id = 'D5'
Rule = 'The envelope''s operation string is checked against the decoded payload, never trusted.'
Test = 'serve::tests::a_malformed_envelope_is_answered_with_a_failure_and_touches_no_mind'
File = 'crates/huginn-daemon/src/envelope.rs'
Old = @'
if operation != request.operation() {
return Err(OperationFailure::new(
"operation-mismatch",
format!("the envelope says {operation} and the payload is {}", request.operation()),
));
}
'@
New = @'
let _ = operation;
'@
}
@{
Id = 'D5L'
Rule = 'The operation is checked as the name it is, not as a shape that happens to match.'
Test = 'serve::tests::a_malformed_envelope_is_answered_with_a_failure_and_touches_no_mind'
File = 'crates/huginn-daemon/src/envelope.rs'
Old = ' if operation != request.operation() {'
New = ' if operation.len() != request.operation().len() {'
}
@{
Id = 'D20'
Rule = 'An answer larger than one send can carry is refused by name, not handed to a send that fails silently.'
Test = 'serve::tests::an_answer_too_large_for_one_send_is_a_typed_refusal_that_reaches_the_client'
File = 'crates/huginn-daemon/src/serve.rs'
Old = ' if encoded <= MAX_RESPONSE_BYTES {'
New = ' if true {'
}
@{
Id = 'D20L'
Rule = 'It is measured against the window the hub was configured with, not against a number chosen to admit it.'
Test = 'serve::tests::an_answer_too_large_for_one_send_is_a_typed_refusal_that_reaches_the_client'
File = 'crates/huginn-daemon/src/serve.rs'
Old = ' if encoded <= MAX_RESPONSE_BYTES {'
New = ' if encoded <= MAX_RESPONSE_BYTES * 4 {'
}
@{
Id = 'D20L2'
Rule = 'The refusal carries the answer''s own encoded size, so a caller can tell how far it overshot.'
Test = 'serve::tests::an_answer_too_large_for_one_send_is_a_typed_refusal_that_reaches_the_client'
File = 'crates/huginn-daemon/src/serve.rs'
Old = ' bytes: encoded,'
New = ' bytes: MAX_RESPONSE_BYTES,'
}
@{
Id = 'D20L3'
Rule = 'And it carries the limit itself, not the size again, so the two are not one number twice.'
Test = 'serve::tests::an_answer_too_large_for_one_send_is_a_typed_refusal_that_reaches_the_client'
File = 'crates/huginn-daemon/src/serve.rs'
Old = ' limit: MAX_RESPONSE_BYTES,'
New = ' limit: encoded,'
}
@{
Id = 'D20L4'
Rule = 'The limit itself is deliverable: the comparison admits an answer of exactly the window''s size, as the transport does.'
Test = 'serve::tests::the_gates_boundary_is_the_transports_boundary_byte_for_byte'
File = 'crates/huginn-daemon/src/serve.rs'
Old = ' if encoded <= MAX_RESPONSE_BYTES {'
New = ' if encoded < MAX_RESPONSE_BYTES {'
}
@{
Id = 'D20L5'
Rule = 'What is measured is the encoded envelope the hub fragments, not the payload string inside it.'
Test = 'serve::tests::the_gates_boundary_is_the_transports_boundary_byte_for_byte'
File = 'crates/huginn-daemon/src/serve.rs'
Old = @'
let encoded = match encode_cultnet_message_to_vec(&reply, CultNetWireContract::CultNetSchemaV0) {
Ok(bytes) => bytes.len() as u64,
'@
New = @'
let encoded = match encode_cultnet_message_to_vec(&reply, CultNetWireContract::CultNetSchemaV0) {
Ok(bytes) => match &reply {
CultNetMessage::OperationResponse { payload, .. } => payload.len() as u64,
_ => bytes.len() as u64,
},
'@
}
@{
Id = 'D20L6'
Rule = 'What is measured holds for more than one envelope shape: a longer `message_id` changes the encoded envelope, so a formula that hard-codes one length''s overhead is wrong at another.'
Test = 'serve::tests::the_gates_boundary_holds_for_a_second_message_id_length'
File = 'crates/huginn-daemon/src/serve.rs'
Old = @'
let encoded = match encode_cultnet_message_to_vec(&reply, CultNetWireContract::CultNetSchemaV0) {
Ok(bytes) => bytes.len() as u64,
'@
New = @'
let encoded = match encode_cultnet_message_to_vec(&reply, CultNetWireContract::CultNetSchemaV0) {
Ok(bytes) => match &reply {
CultNetMessage::OperationResponse { payload, .. } => payload.len() as u64 + 231,
_ => bytes.len() as u64,
},
'@
}
@{
Id = 'N4a'
Rule = 'N4: what is measured holds for more than `message_id`''s length; `operation` and the runtime id are in the encoded envelope too, so a formula of `message_id.len()` alone -- even one shaped to survive a longer id, `+228+id.len()+(id.len()>31)` -- is wrong once the operation or runtime id it never looked at changes length.'
Test = 'serve::tests::the_gates_boundary_holds_across_operation_and_runtime_id'
Command = 'cargo test -p huginn-daemon --lib'
File = 'crates/huginn-daemon/src/serve.rs'
Old = @'
let encoded = match encode_cultnet_message_to_vec(&reply, CultNetWireContract::CultNetSchemaV0) {
Ok(bytes) => bytes.len() as u64,
'@
New = @'
let encoded = match encode_cultnet_message_to_vec(&reply, CultNetWireContract::CultNetSchemaV0) {
Ok(bytes) => match &reply {
CultNetMessage::OperationResponse { payload, .. } => {
payload.len() as u64 + 228 + message_id.len() as u64 + (message_id.len() > 31) as u64
}
_ => bytes.len() as u64,
},
'@
}
@{
Id = 'N4b'
Rule = 'N4: a coincidence caught the same way -- `228+id.len()*38/37` fits both of the suite''s `message_id` lengths (three and forty bytes) by the ratio between them, not by measuring the envelope, so it is wrong once the operation or the runtime id changes the envelope''s size at either length.'
Test = 'serve::tests::the_gates_boundary_holds_across_operation_and_runtime_id'
Command = 'cargo test -p huginn-daemon --lib'
File = 'crates/huginn-daemon/src/serve.rs'
Old = @'
let encoded = match encode_cultnet_message_to_vec(&reply, CultNetWireContract::CultNetSchemaV0) {
Ok(bytes) => bytes.len() as u64,
'@
New = @'
let encoded = match encode_cultnet_message_to_vec(&reply, CultNetWireContract::CultNetSchemaV0) {
Ok(bytes) => match &reply {
CultNetMessage::OperationResponse { payload, .. } => {
payload.len() as u64 + 228 + (message_id.len() as u64 * 38 / 37)
}
_ => bytes.len() as u64,
},
'@
}
@{
Id = 'N4c'
Rule = 'Residue S1: what is measured holds for the operation and the runtime id independently, not merely for the two moving together as N4a and N4b probed them; a formula that adds a term for the operation''s length but drops the runtime id -- `228+id+(id>31)+(op.len()-4)*3/2` -- is wrong once a fixture holds the operation long and the runtime id short.'
Test = 'serve::tests::the_gates_boundary_holds_when_operation_and_runtime_id_vary_independently'
Command = 'cargo test -p huginn-daemon --lib'
File = 'crates/huginn-daemon/src/serve.rs'
Old = @'
let encoded = match encode_cultnet_message_to_vec(&reply, CultNetWireContract::CultNetSchemaV0) {
Ok(bytes) => bytes.len() as u64,
'@
New = @'
let encoded = match encode_cultnet_message_to_vec(&reply, CultNetWireContract::CultNetSchemaV0) {
Ok(bytes) => match &reply {
CultNetMessage::OperationResponse { payload, .. } => {
payload.len() as u64
+ 228
+ message_id.len() as u64
+ (message_id.len() > 31) as u64
+ (operation.len() as u64).saturating_sub(4) * 3 / 2
}
_ => bytes.len() as u64,
},
'@
}
@{
Id = 'N4d'
Rule = 'Residue S1: the same, the other way round; a formula that adds a term for the runtime id but drops the operation -- `228+id+(id>31)+3*(rt.len()-16)` -- is wrong once a fixture holds the runtime id long and the operation short.'
Test = 'serve::tests::the_gates_boundary_holds_when_operation_and_runtime_id_vary_independently'
Command = 'cargo test -p huginn-daemon --lib'
File = 'crates/huginn-daemon/src/serve.rs'
Old = @'
let encoded = match encode_cultnet_message_to_vec(&reply, CultNetWireContract::CultNetSchemaV0) {
Ok(bytes) => bytes.len() as u64,
'@
New = @'
let encoded = match encode_cultnet_message_to_vec(&reply, CultNetWireContract::CultNetSchemaV0) {
Ok(bytes) => match &reply {
CultNetMessage::OperationResponse { payload, .. } => {
payload.len() as u64
+ 228
+ message_id.len() as u64
+ (message_id.len() > 31) as u64
+ 3 * (runtime_id.len() as u64).saturating_sub(16)
}
_ => bytes.len() as u64,
},
'@
}
@{
Id = 'D21'
Rule = 'The refusal rides the response schema like every other refusal, not a failure envelope the client must parse apart.'
Test = 'serve::tests::an_answer_too_large_for_one_send_is_a_typed_refusal_that_reaches_the_client'
File = 'crates/huginn-daemon/src/serve.rs'
Old = @'
let refusal = HuginnMindResponse::Refused(MindRefusal::ResponseTooLarge {
bytes: encoded,
limit: MAX_RESPONSE_BYTES,
});
encode_or_fail(message_id, operation, &refusal, runtime_id)
'@
New = @'
encode_failure(
message_id,
operation,
&crate::envelope::OperationFailure {
code: "response-too-large".into(),
message: format!("{encoded} bytes against a {MAX_RESPONSE_BYTES} limit"),
},
runtime_id,
)
'@
}
@{
Id = 'D21L'
Rule = 'It echoes the client''s own correlation key, so a refusal can be matched to the request that earned it.'
Test = 'serve::tests::an_answer_too_large_for_one_send_is_a_typed_refusal_that_reaches_the_client'
File = 'crates/huginn-daemon/src/serve.rs'
Old = ' encode_or_fail(message_id, operation, &refusal, runtime_id)'
New = ' encode_or_fail("response-too-large", operation, &refusal, runtime_id)'
}
@{
Id = 'D22'
Rule = 'The window the gate measures against is the window the hub carries: a smaller one sends nothing and says nothing.'
Test = 'serve::tests::an_answer_too_large_for_one_send_is_a_typed_refusal_that_reaches_the_client'
File = 'crates/huginn-daemon/src/serve.rs'
Old = ' options.max_pending_reliable_packets = Some(MAX_PENDING_RELIABLE_PACKETS);'
New = ' options.max_pending_reliable_packets = Some(MAX_PENDING_RELIABLE_PACKETS / 2);'
}
@{
Id = 'D22L'
Rule = 'Not merely close to it: a window short by a few dozen packets still drops an answer the gate admitted.'
Test = 'serve::tests::an_answer_too_large_for_one_send_is_a_typed_refusal_that_reaches_the_client'
File = 'crates/huginn-daemon/src/serve.rs'
Old = ' options.max_pending_reliable_packets = Some(MAX_PENDING_RELIABLE_PACKETS);'
New = ' options.max_pending_reliable_packets = Some(MAX_PENDING_RELIABLE_PACKETS - 64);'
}
@{
Id = 'D22L2'
Rule = 'The fragment size is the window''s other half: a smaller one carries fewer bytes in the same packet count.'
Test = 'serve::tests::an_answer_too_large_for_one_send_is_a_typed_refusal_that_reaches_the_client'
File = 'crates/huginn-daemon/src/serve.rs'
Old = ' options.max_fragment_bytes = Some(MAX_FRAGMENT_BYTES);'
New = ' options.max_fragment_bytes = Some(MAX_FRAGMENT_BYTES - 64);'
}
@{
Id = 'D17'
Rule = 'A refusal `view` raised crosses the dispatch as itself, not rewrapped as unavailable.'
Test = 'daemon::tests::a_refusal_a_read_raised_is_the_answer_the_dispatch_returns_whole'
File = 'crates/huginn-daemon/src/daemon.rs'
Old = @'
HuginnMindRequest::View { id, .. } => match self.mind.view(&id) {
Ok(view) => HuginnMindResponse::View(view),
Err(refusal) => HuginnMindResponse::Refused(refusal),
},
'@
New = @'
HuginnMindRequest::View { id, .. } => match self.mind.view(&id) {
Ok(view) => HuginnMindResponse::View(view),
Err(refusal) => HuginnMindResponse::Refused(huginn_mind::MindRefusal::Unavailable {
detail: format!("{refusal}"),
}),
},
'@
}
@{
Id = 'D17L'
Rule = 'It is not swallowed into an empty answer either: a malformed reference is not an absent document.'
Test = 'daemon::tests::a_refusal_a_read_raised_is_the_answer_the_dispatch_returns_whole'
File = 'crates/huginn-daemon/src/daemon.rs'
Old = @'
Err(refusal) => HuginnMindResponse::Refused(refusal),
},
HuginnMindRequest::Query { query, .. } => match self.mind.query(&query) {
'@
New = @'
Err(_) => HuginnMindResponse::View(None),
},
HuginnMindRequest::Query { query, .. } => match self.mind.query(&query) {
'@
}
@{
Id = 'D18'
Rule = 'A refusal `query` raised crosses the dispatch as itself, with the mind''s own detail.'
Test = 'daemon::tests::a_refusal_a_read_raised_is_the_answer_the_dispatch_returns_whole'
File = 'crates/huginn-daemon/src/daemon.rs'
Old = @'
HuginnMindRequest::Query { query, .. } => match self.mind.query(&query) {
Ok(page) => HuginnMindResponse::Query(page),
Err(refusal) => HuginnMindResponse::Refused(refusal),
},
'@
New = @'
HuginnMindRequest::Query { query, .. } => match self.mind.query(&query) {
Ok(page) => HuginnMindResponse::Query(page),
Err(refusal) => HuginnMindResponse::Refused(huginn_mind::MindRefusal::Unavailable {
detail: format!("a query was refused: {refusal}"),
}),
},
'@
}
@{
Id = 'D18L'
Rule = 'Nor is it flattened into an empty page, which would read as a mind holding nothing.'
Test = 'daemon::tests::a_refusal_a_read_raised_is_the_answer_the_dispatch_returns_whole'
File = 'crates/huginn-daemon/src/daemon.rs'
Old = @'
Ok(page) => HuginnMindResponse::Query(page),
Err(refusal) => HuginnMindResponse::Refused(refusal),
'@
New = @'
Ok(page) => HuginnMindResponse::Query(page),
Err(_) => HuginnMindResponse::Query(huginn_mind::PipelineQueryPage { items: vec![], matched: 0 }),
'@
}
@{
Id = 'D5L2'
Rule = 'The operation is compared as bytes: another casing of the name is another name.'
Test = 'serve::tests::a_malformed_envelope_is_answered_with_a_failure_and_touches_no_mind'
File = 'crates/huginn-daemon/src/envelope.rs'
Old = ' if operation != request.operation() {'
New = ' if !operation.eq_ignore_ascii_case(request.operation()) {'
}
@{
Id = 'D6'
Rule = 'The index never decides an outcome: a sink that fails does not refuse a batch the mind admitted.'
Test = 'daemon::tests::the_index_is_handed_every_landed_write_after_commit_and_never_decides_the_outcome'
File = 'crates/huginn-daemon/src/daemon.rs'
Old = @'
let refs = writes.iter().map(|write| write.id.0.clone()).collect::<Vec<_>>().join(", ");
eprintln!("huginn: the index refused the landed writes [{refs}]: {error:#}");
'@
New = @'
return HuginnMindResponse::Admit(PipelineAdmissionOutcome::Refused(
huginn_mind::MindRefusal::Unavailable { detail: format!("{error:#}") },
));
'@
}
@{
Id = 'D6L'
Rule = 'The index does not change the answer either: the outcome is the mind''s, whatever the sink did with it.'
Test = 'daemon::tests::the_index_is_handed_every_landed_write_after_commit_and_never_decides_the_outcome'
File = 'crates/huginn-daemon/src/daemon.rs'
Old = @'
let refs = writes.iter().map(|write| write.id.0.clone()).collect::<Vec<_>>().join(", ");
eprintln!("huginn: the index refused the landed writes [{refs}]: {error:#}");
'@
New = @'
return HuginnMindResponse::Admit(PipelineAdmissionOutcome::AlreadyAdmitted {
receipt_id: format!("index-unavailable: {error:#}"),
});
'@
}
@{
Id = 'D7'
Rule = 'The index is handed every landed write.'
Test = 'daemon::tests::the_index_is_handed_every_landed_write_after_commit_and_never_decides_the_outcome'
File = 'crates/huginn-daemon/src/daemon.rs'
Old = ' && let Err(error) = self.index.committed(&self.mind, writes)'
New = ' && let Err(error) = self.index.committed(&self.mind, &[])'
}
@{
Id = 'D7L'
Rule = 'Derived writes are landed writes: a ruling that answers a question hands the index two documents, not one.'
Test = 'daemon::tests::the_index_is_handed_every_landed_write_after_commit_and_never_decides_the_outcome'
File = 'crates/huginn-daemon/src/daemon.rs'
Old = ' && let Err(error) = self.index.committed(&self.mind, writes)'
New = ' && let Err(error) = self.index.committed(&self.mind, &writes[..1])'
}
@{
Id = 'D8'
Rule = 'Each reply goes to the session its request arrived on.'
Test = 'serve::tests::two_clients_get_their_own_replies_over_loopback'
File = 'crates/huginn-daemon/src/serve.rs'
Old = @'
let reply = answer(daemon, registry, message, Utc::now());
if let Err(error) = hub.send_schema_message(&session, &reply) {
'@
New = @'
let reply = answer(daemon, registry, message, Utc::now());
let session = hub.sessions().into_iter().next().unwrap_or(session);
if let Err(error) = hub.send_schema_message(&session, &reply) {
'@
}
@{
Id = 'D8L'
Rule = 'A reply goes to one session, not to everyone connected: another peer''s answer is not this peer''s to read.'
Test = 'serve::tests::two_clients_get_their_own_replies_over_loopback'
File = 'crates/huginn-daemon/src/serve.rs'
Old = @'
if let Err(error) = hub.send_schema_message(&session, &reply) {
eprintln!("huginn: {} did not receive its reply: {error:#}", session.remote_addr);
}
'@
New = @'
for session in hub.sessions() {
if let Err(error) = hub.send_schema_message(&session, &reply) {
eprintln!("huginn: {} did not receive its reply: {error:#}", session.remote_addr);
}
}
'@
}
@{
Id = 'D9'
Rule = 'The hub serves CultNet''s operation connection id and no other, so a peer speaking another protocol on the port never becomes a session.'
Test = 'serve::tests::two_clients_get_their_own_replies_over_loopback'
File = 'crates/huginn-daemon/src/serve.rs'
Old = ' let mut options = CultNetRudpServerHubOptions::new(runtime_id, socket, CULTNET_OPERATION_CONNECTION_ID);'
New = ' let mut options = CultNetRudpServerHubOptions::new(runtime_id, socket, 0x4355_4c55);'
}
@{
Id = 'D10'
Rule = '`whoami` is derived from the mind: `documents` counts pipeline documents, not every row the store holds.'
Test = 'daemon::tests::a_batch_round_trips_typed_through_handle_without_a_socket'
File = 'crates/huginn-mind/src/wire.rs'
Old = @'
} else if PipelineKind::ALL.iter().any(|kind| kind.type_id() == envelope.r#type) {
documents += 1;
}
'@
New = @'
} else {
documents += 1;
}
'@
}
@{
Id = 'D10L'
Rule = 'A mind says how many receipts it holds, so a reader can tell a mind that has admitted from one that has not.'
Test = 'daemon::tests::a_batch_round_trips_typed_through_handle_without_a_socket'
File = 'crates/huginn-mind/src/wire.rs'
Old = @'
if envelope.r#type == HuginnCommitReceipt::TYPE {
receipts += 1;
'@
New = @'
if envelope.r#type == HuginnCommitReceipt::TYPE {
receipts += 0;
'@
}
@{
Id = 'D11'
Rule = 'Ruling 15: a mind that will not open is refused, and no other mind is opened in its place.'
Test = 'daemon::tests::the_daemon_refuses_loudly_when_it_cannot_open_the_mind_and_binds_nothing'
File = 'crates/huginn-daemon/src/daemon.rs'
Old = ' Ok(Self { mind: Mind::open(state_root, instance)?, index: NoIndex })'
New = @'
let mind = match Mind::open(state_root, instance) {
Ok(mind) => mind,
Err(_) => Mind::open(&state_root.join("fallback"), instance)?,
};
Ok(Self { mind, index: NoIndex })
'@
}
@{
Id = 'D11L'
Rule = 'Every refusal of the opener is a refusal to serve, not only the held lock: a store naming another instance is not this daemon''s to open.'
Test = 'daemon::tests::the_daemon_refuses_loudly_when_it_cannot_open_the_mind_and_binds_nothing'
File = 'crates/huginn-daemon/src/daemon.rs'
Old = ' Ok(Self { mind: Mind::open(state_root, instance)?, index: NoIndex })'
New = @'
let mind = match Mind::open(state_root, instance) {
Ok(mind) => mind,
Err(held @ MindRefusal::MindAlreadyOwned { .. }) => return Err(held),
Err(_) => Mind::open(&state_root.join("fallback"), instance)?,
};
Ok(Self { mind, index: NoIndex })
'@
}
@{
Id = 'D12'
Rule = 'Ruling 15 as an order: the mind opens before anything binds, so a refused mind is reported as a refused mind and no socket is ever taken.'
Test = 'serve::tests::startup_opens_the_mind_before_it_binds_anything'
File = 'crates/huginn-daemon/src/serve.rs'
Old = @'
let daemon = Daemon::open(&options.state_root, &options.instance)?;
let hub = bind(options.bind, &daemon.runtime_id())?;
'@
New = @'
let hub = bind(options.bind, "huginn")?;
let daemon = Daemon::open(&options.state_root, &options.instance)?;
'@
}
@{
Id = 'D12L'
Rule = 'Tidying up afterwards is not the order: a socket taken before the mind opened was still taken, and the refusal still comes back as the port''s rather than the mind''s.'
Test = 'serve::tests::startup_opens_the_mind_before_it_binds_anything'
File = 'crates/huginn-daemon/src/serve.rs'
Old = @'
let daemon = Daemon::open(&options.state_root, &options.instance)?;
let hub = bind(options.bind, &daemon.runtime_id())?;
'@
New = @'
let hub = bind(options.bind, "huginn")?;
let daemon = match Daemon::open(&options.state_root, &options.instance) {
Ok(daemon) => daemon,
Err(refusal) => {
drop(hub);
return Err(refusal.into());
}
};
let hub = bind(options.bind, &daemon.runtime_id())?;
'@
}
@{
Id = 'D13'
Rule = 'The wire vocabulary is the mind''s methods: one operation name per method, and it is that method''s name. Re-anchored on `view` after RS-2 deleted `History`: `View`''s own name, duplicated onto `Query`''s spelling, breaks the one-name-per-method rule the same way.'
Test = 'wire::tests::the_wire_vocabulary_is_the_minds_methods_and_status_is_derived_from_the_response'
Command = 'cargo test -p huginn-mind --lib'
File = 'crates/huginn-mind/src/wire.rs'
Old = ' Self::View { .. } => "view",'
New = ' Self::View { .. } => "query",'
}
@{
Id = 'D13L'
Rule = 'The operation name is the method''s exact spelling, so a client reading `Mind`''s surface can address it without a translation table. Re-anchored on `query` after RS-2 deleted `OpenItems`: PowerShell''s default `-eq` is case-insensitive, so a pure-casing mutant (`"query"` -> `"Query"`) reads as no change to the harness''s own "replacement changes nothing" guard; this loosening instead adds a plausible near-miss spelling.'
Test = 'wire::tests::the_wire_vocabulary_is_the_minds_methods_and_status_is_derived_from_the_response'
Command = 'cargo test -p huginn-mind --lib'
File = 'crates/huginn-mind/src/wire.rs'
Old = ' Self::Query { .. } => "query",'
New = ' Self::Query { .. } => "queries",'
}
@{
Id = 'D14'
Rule = 'The published request schema equals its derivation, byte for byte.'
Test = 'wire::tests::published_wire_schemas_match_derivation'
Command = 'cargo test -p huginn-mind --lib'
File = 'schemas/cultnet/huginn.mind_request.v1.schema.json'
Old = ' "title": "HuginnMindRequest",'
New = ' "title": "HuginnMindRequest",'
}
@{
Id = 'D14L'
Rule = 'Both files are pinned, not one: the response schema is derived too, and a hand edit to it is the same drift.'
Test = 'wire::tests::published_wire_schemas_match_derivation'
Command = 'cargo test -p huginn-mind --lib'
File = 'schemas/cultnet/huginn.mind_response.v1.schema.json'
Old = ' "title": "HuginnMindResponse",'
New = ' "title": "HuginnMindResponse v1",'
}
@{
Id = 'D15'
Rule = 'A replay is an answer, not a rejection: `AlreadyAdmitted` tells a client its batch is in the mind already.'
Test = 'envelope::tests::a_refusal_is_a_typed_response_not_a_transport_failure'
File = 'crates/huginn-mind/src/wire.rs'
Old = ' Self::Refused(_) | Self::Admit(PipelineAdmissionOutcome::Refused(_)) => "rejected",'
New = @'
Self::Refused(_)
| Self::Admit(PipelineAdmissionOutcome::Refused(_))
| Self::Admit(PipelineAdmissionOutcome::AlreadyAdmitted { .. }) => "rejected",
'@
}
@{
Id = 'D15L'
Rule = 'A conflict is an answer too: it names the identities that collided, which a rejection would throw away.'
Test = 'envelope::tests::a_refusal_is_a_typed_response_not_a_transport_failure'
File = 'crates/huginn-mind/src/wire.rs'
Old = ' Self::Refused(_) | Self::Admit(PipelineAdmissionOutcome::Refused(_)) => "rejected",'
New = @'
Self::Refused(_)
| Self::Admit(PipelineAdmissionOutcome::Refused(_))
| Self::Admit(PipelineAdmissionOutcome::Conflict { .. }) => "rejected",
'@
}
@{
Id = 'D16'
Rule = 'A message of another family is answered, not dropped: CultNet refuses an empty error string, so a silent arm hangs the client.'
Test = 'serve::tests::a_malformed_envelope_is_answered_with_a_failure_and_touches_no_mind'
File = 'crates/huginn-daemon/src/serve.rs'
Old = @'
_ => CultNetMessage::Error {
error: format!(
"{MIND_SERVICE_ID} answers cultnet.operation_request.v0 and cultnet.schema_catalog_request.v0"
),
},
'@
New = @'
_ => CultNetMessage::Error { error: String::new() },
'@
}
@{
Id = 'D16L'
Rule = 'The answer names both messages the service accepts, so a client that guessed wrong learns what to send.'
Test = 'serve::tests::a_malformed_envelope_is_answered_with_a_failure_and_touches_no_mind'
File = 'crates/huginn-daemon/src/serve.rs'
Old = @'
_ => CultNetMessage::Error {
error: format!(
"{MIND_SERVICE_ID} answers cultnet.operation_request.v0 and cultnet.schema_catalog_request.v0"
),
},
'@
New = @'
_ => CultNetMessage::Error { error: format!("{MIND_SERVICE_ID} answers cultnet.operation_request.v0") },
'@
}
)
}

View file

@ -1,825 +0,0 @@
# Cut 8 mutations, H1-H51: each entry restores one permissiveness the cut
# closed and names the test that must fail while it is applied. H40-H46 are
# the Cut 6d follow-up's rules (the two sequences, the recursive in-force, the
# single in-force stewardship, the Q19 cap, and the sequences `derive` sets);
# H47-H51 close the gaps Soul found where the code was right and the suite
# blind. H52-H61 are the follow-up's own fixes and the gaps Soul's second pass
# left: the sequences a replay re-derives (H52-H54), the withdrawal that would
# re-raise an earlier record over a later one (H55-H56), the gap a sequence
# rule must refuse (H57-H58), and three rules the suite could not tell apart
# from weaker ones (H59-H61). H62-H67 are the second pass's own: the
# assignment a replayed hand-off withdraws, picked by content rather than key
# order (H62-H63), and four more rules the suite could not tell apart from
# weaker ones (H64-H67). Run through the Eureka skill's harness from this repo:
#
# Soul's Y7 -- `later_than`'s resolution arm returning `false` -- has no entry
# here and can have none: the arm is deleted. It was dead code behind the Q19
# cap, so no test could reach it and no mutation of it could fail.
#
# H32 is re-anchored to the same follow-up: its A4 half is unreachable now
# that a derived write takes the sequence after the batch's own records, so a
# derived identity can no longer collide with one the batch holds. What it
# still pins is that derived writes are validated, staged and resolved like
# any other, which the transfer test's strong read shows.
#
# $env:CARGO_TARGET_DIR = 'C:\Users\Meta\.cargo-target-codex'
# powershell -File C:\Users\Meta\.claude\skills\eureka\tools\eureka-mutations.ps1 -Repo F:\Projects\Huginn `
# -Entries tools/eureka-cut8-mutations.psd1 `
# -Target crates/huginn-mind/src/mind.rs,crates/huginn-mind/src/receipt.rs,crates/huginn-mind/src/admission.rs,crates/huginn-mind/src/docs.rs,crates/huginn-mind/src/store.rs `
# -Test 'cargo test -p huginn-mind --lib'
#
# `store.rs` is a target only for H5, whose mutant needs a `MindStore` impl
# for the transient redb store that the live crate deliberately lacks.
#
# Cut 9 moved `Docs`, its derivations and `later_than` into `docs.rs`, so the
# nine entries that anchor them name that file: H33, H41, H62, H63, H65, H66
# and H67 by file alone, and H47 and H60 re-anchored on the scope selectors
# `assignments_of` and `resolutions_of` the move extracted. Their rules are
# unchanged.
#
# Cut 10 moved A1's comparison into `Mind::require_instance`, which admission
# and the daemon's reads now share, so H1 anchors on `mind.rs`. One mutant,
# two suites, one owner: the same edit is `D1` in `eureka-cut10-mutations.psd1`.
@{
Mutations = @(
@{
Id = 'H1'
Rule = 'Ruling 14: admission refuses another instance''s identity (A1).'
Test = 'admission::tests::admission_refuses_a_foreign_instance_whatever_the_transport'
File = 'crates/huginn-mind/src/mind.rs'
Old = ' if declared != self.instance() {'
New = ' if false {'
}
@{
Id = 'H2'
Rule = 'Ruling 14: identity lives in the state; the opener compares the stored instance against the declared one.'
Test = 'mind::tests::the_instance_document_is_the_identity_not_the_path'
File = 'crates/huginn-mind/src/mind.rs'
Old = ' if stored.instance != *instance {'
New = ' if stored.instance != stored.instance {'
}
@{
Id = 'H3'
Rule = 'Ruling 14: a mind is never un-owned; an empty mind''s first batch must carry the instance (A6).'
Test = 'admission::tests::an_empty_store_opens_and_the_first_write_must_carry_the_instance'
File = 'crates/huginn-mind/src/admission.rs'
Old = @'
if self.is_empty() && !carries_instance {
return Err(MindRefusal::MissingIdentity);
}
'@
New = ''
}
@{
Id = 'H4'
Rule = 'Ruling 14: the epoch record is derived on the first write (A6).'
Test = 'admission::tests::an_empty_store_opens_and_the_first_write_must_carry_the_instance'
File = 'crates/huginn-mind/src/admission.rs'
Old = @'
if carries_instance {
writes.push(HuginnMindEpoch::envelope(self.cache())?);
}
'@
New = ''
}
@{
Id = 'H5'
Rule = 'Ruling 15: one writer; Mind::open chooses the owned store whose lock refuses a second owner.'
Test = 'mind::tests::a_mind_has_one_owner_at_a_time'
Edits = @(
@{
File = 'crates/huginn-mind/src/store.rs'
Old = 'impl MindStore for OwnedRedbMessagePackBackingStore {'
New = @'
impl MindStore for cultcache_rs::RedbMessagePackBackingStore {
fn compare_and_swap_batch(
&self,
expected: &[CultCacheEnvelope],
replacements: Vec<CultCacheEnvelope>,
) -> Result<bool> {
cultcache_rs::RedbMessagePackBackingStore::compare_and_swap_batch(self, expected, replacements)
}
}
impl MindStore for OwnedRedbMessagePackBackingStore {
'@
}
@{
File = 'crates/huginn-mind/src/mind.rs'
Old = 'use cultcache_rs::{CultCache, CultCacheEnvelope, DatabaseEntry, OwnedRedbMessagePackBackingStore};'
New = 'use cultcache_rs::{CultCache, CultCacheEnvelope, DatabaseEntry, OwnedRedbMessagePackBackingStore, RedbMessagePackBackingStore};'
}
@{
File = 'crates/huginn-mind/src/mind.rs'
Old = 'impl Mind<OwnedRedbMessagePackBackingStore> {'
New = 'impl Mind<RedbMessagePackBackingStore> {'
}
@{
File = 'crates/huginn-mind/src/mind.rs'
Old = ' let store = OwnedRedbMessagePackBackingStore::new(&path).map_err(|error| {'
New = ' let store = RedbMessagePackBackingStore::new(&path).map_err(|error| {'
}
)
}
@{
Id = 'H6'
Rule = 'Ruling 20: the opener attaches nothing until every gate passes. Re-anchored by RS-1, which swapped the epoch and type gates'' order; the rule -- every gate before attach -- is unchanged.'
Test = 'mind::tests::the_opener_refuses_foreign_epoch_missing_identity_and_foreign_type_before_attaching'
File = 'crates/huginn-mind/src/mind.rs'
Old = @'
refuse_foreign_epoch(&raw)?;
refuse_foreign_types(&raw)?;
refuse_foreign_identity(&raw, instance)?;
let (cache, image) = attach(store.clone())?;
'@
New = @'
let (cache, image) = attach(store.clone())?;
refuse_foreign_epoch(&raw)?;
refuse_foreign_types(&raw)?;
refuse_foreign_identity(&raw, instance)?;
'@
}
@{
Id = 'H7'
Rule = 'Ruling 20: validation before replay; A9 runs after the per-kind rules, never before them.'
Test = 'admission::tests::a_refused_batch_is_not_answered_from_a_stored_receipt'
File = 'crates/huginn-mind/src/admission.rs'
Old = @'
for staged in &docs.batch {
check(&docs, staged, &mind)?;
}
// A9
if let Some(existing) = receipt::replay(self, &candidate)? {
return Ok(PipelineAdmissionOutcome::AlreadyAdmitted { receipt_id: existing.receipt_id });
}
'@
New = @'
if let Some(existing) = receipt::replay(self, &candidate)? {
return Ok(PipelineAdmissionOutcome::AlreadyAdmitted { receipt_id: existing.receipt_id });
}
for staged in &docs.batch {
check(&docs, staged, &mind)?;
}
'@
}
@{
Id = 'H8'
Rule = 'Q2/epoch: a store written at another epoch is refused.'
Test = 'mind::tests::the_opener_refuses_foreign_epoch_missing_identity_and_foreign_type_before_attaching'
File = 'crates/huginn-mind/src/mind.rs'
Old = ' if record.schema_epoch != PIPELINE_SCHEMA_EPOCH {'
New = ' if false {'
}
@{
Id = 'H9'
Rule = 'Opener: a store holding a foreign type is refused before anything else.'
Test = 'mind::tests::the_opener_refuses_foreign_epoch_missing_identity_and_foreign_type_before_attaching'
File = 'crates/huginn-mind/src/mind.rs'
Old = @'
refuse_foreign_types(&raw)?;
'@
New = ''
}
@{
Id = 'H10'
Rule = 'Receipt: an exact replay answers with the stored receipt (A9).'
Test = 'admission::tests::exact_replay_returns_already_admitted_across_provenance'
File = 'crates/huginn-mind/src/admission.rs'
Old = ' if let Some(existing) = receipt::replay(self, &candidate)? {'
New = ' if let Some(existing) = receipt::replay(self, &candidate)?.filter(|_| false) {'
}
@{
Id = 'H11'
Rule = 'Receipt: the digest is content, not author; provenance is never digested.'
Test = 'admission::tests::a_receipt_names_the_exact_bytes_it_read_and_wrote'
File = 'crates/huginn-mind/src/receipt.rs'
Old = ' let bytes = rmp_serde::to_vec_named(&(&self.instance, &self.strong_reads, &self.writes))'
New = ' let bytes = rmp_serde::to_vec_named(&(&self.instance, &self.strong_reads, &self.writes, &self.provenance))'
}
@{
Id = 'H12'
Rule = 'Receipt: strong reads are the swap''s expectation, pinning the cited bytes (A11).'
Test = 'admission::tests::a_receipt_names_the_exact_bytes_it_read_and_wrote'
File = 'crates/huginn-mind/src/receipt.rs'
Old = ' let expected: &[CultCacheEnvelope] = &strong_reads;'
New = ' let expected: &[CultCacheEnvelope] = &[];'
}
@{
Id = 'H13'
Rule = 'All-or-nothing: a lost swap is a Conflict, never a Committed (A11).'
Test = 'admission::tests::batch_is_all_or_nothing'
File = 'crates/huginn-mind/src/receipt.rs'
Old = ' if !landed {'
New = ' if false {'
}
@{
Id = 'H14'
Rule = 'Supersession, not overwrite: a write colliding with the image is refused before the swap (A10).'
Test = 'admission::tests::a_document_is_written_once_and_superseded_by_resolution'
File = 'crates/huginn-mind/src/admission.rs'
Old = @'
refuse_collisions(&docs)?;
'@
New = ''
}
@{
Id = 'H15'
Rule = 'The resolution matrix is admission''s: every subject kind admits only its outcomes.'
Test = 'admission::tests::the_resolution_matrix_is_admissions'
File = 'crates/huginn-mind/src/admission.rs'
Old = @'
fits
}
'@
New = @'
true
}
'@
}
@{
Id = 'H16'
Rule = '6c: a supersession names at least one supersessor.'
Test = 'admission::tests::supersession_names_each_supersessor_and_none_is_empty'
File = 'crates/huginn-mind/src/admission.rs'
Old = @'
if let ResolutionOutcome::Superseded { by } = &resolution.outcome && by.is_empty() {
return Err(MindRefusal::EmptySupersession);
}
'@
New = ''
}
@{
Id = 'H17'
Rule = 'Q10 + 6c: every supersessor and outcome referent must exist (A7).'
Test = 'admission::tests::supersession_names_each_supersessor_and_none_is_empty'
File = 'crates/huginn-mind/src/admission.rs'
Old = @'
refs.extend(outcome_references(&resolution.outcome));
'@
New = ''
}
@{
Id = 'H18'
Rule = '6c: an operator quote requires operator authority.'
Test = 'admission::tests::an_operator_quote_requires_operator_authority'
File = 'crates/huginn-mind/src/admission.rs'
Old = @'
if ruling.operator_quote.is_some() && ruling.authority != RulingAuthority::Operator {
return Err(MindRefusal::QuoteWithoutOperator { ruling: key.into() });
}
'@
New = ''
}
@{
Id = 'H19'
Rule = 'Ruling A: every promise of the cited report is measured by exactly one claim.'
Test = 'admission::tests::verdict_vocabulary_binds_claims_to_findings_promises_and_mutations'
File = 'crates/huginn-mind/src/admission.rs'
Old = ' if count != 1 {'
New = ' if count == 0 {'
}
@{
Id = 'H20'
Rule = '6c: every mutation label a claim names exists in the report.'
Test = 'admission::tests::verdict_vocabulary_binds_claims_to_findings_promises_and_mutations'
File = 'crates/huginn-mind/src/admission.rs'
Old = @'
for label in &claim.mutations {
if !report.mutations.iter().any(|mutation| mutation.label == *label) {
return Err(MindRefusal::UnknownMutationLabel { label: label.0.clone() });
}
}
'@
New = ''
}
@{
Id = 'H21'
Rule = 'Opener step 3: the epoch record is the record under the epoch''s own key; any other key is not it.'
Test = 'mind::tests::the_opener_refuses_foreign_epoch_missing_identity_and_foreign_type_before_attaching'
File = 'crates/huginn-mind/src/mind.rs'
Old = @'
if record.key != PIPELINE_SCHEMA_EPOCH {
return Err(foreign(record.key.clone()));
}
'@
New = ''
}
@{
Id = 'H22'
Rule = 'Opener step 3: exactly one epoch record, counted before any value is read, so the store''s order cannot decide the outcome.'
Test = 'mind::tests::the_opener_refuses_foreign_epoch_missing_identity_and_foreign_type_before_attaching'
File = 'crates/huginn-mind/src/mind.rs'
Old = @'
let extra = records.count();
if extra > 0 {
return Err(foreign(format!("{} records", extra + 1)));
}
'@
New = ''
}
@{
Id = 'H23'
Rule = 'campaign: a campaign of no repos is refused, and by the organ''s own refusal (EmptyRepos), not a minted leaf bound.'
Test = 'admission::tests::a_campaign_names_only_repos_this_mind_stewards'
File = 'crates/huginn-mind/src/admission.rs'
Old = @'
if campaign.repos.is_empty() {
return Err(MindRefusal::EmptyRepos { campaign: key.into() });
}
'@
New = ''
}
@{
Id = 'H24'
Rule = 'A11: the receipt lands inside the batch''s own compare-and-swap, never in a second one after it.'
Test = 'receipt::tests::a_commit_is_one_swap_carrying_the_documents_and_the_receipt_together'
File = 'crates/huginn-mind/src/receipt.rs'
Old = @'
replacements.push(receipt_envelope);
let expected: &[CultCacheEnvelope] = &strong_reads;
let landed = MindStore::compare_and_swap_batch(mind.store(), expected, replacements).map_err(unavailable)?;
'@
New = @'
let expected: &[CultCacheEnvelope] = &strong_reads;
let landed = MindStore::compare_and_swap_batch(mind.store(), expected, replacements).map_err(unavailable)?;
let landed = landed && MindStore::compare_and_swap_batch(mind.store(), &[], vec![receipt_envelope]).map_err(unavailable)?;
'@
}
@{
Id = 'H25'
Rule = 'A7: every reference the image resolved is pinned as a strong read, not the first of them.'
Test = 'admission::tests::every_cited_image_document_is_a_strong_read'
File = 'crates/huginn-mind/src/admission.rs'
Old = @'
.filter_map(|(type_id, key)| self.raw_envelope(type_id, key).cloned())
.collect::<Vec<_>>();
'@
New = @'
.filter_map(|(type_id, key)| self.raw_envelope(type_id, key).cloned())
.take(1)
.collect::<Vec<_>>();
'@
}
@{
Id = 'H26'
Rule = 'campaign: stewardship is looked for in image and batch, not in the batch alone.'
Test = 'admission::tests::a_campaign_names_only_repos_this_mind_stewards'
File = 'crates/huginn-mind/src/admission.rs'
Old = ' if docs.stewardship_of(mind, repo, None).is_none() {'
New = ' if !docs.batch.iter().any(|staged| matches!(&staged.document, D::Stewardship(stewardship) if stewardship.repo == *repo)) {'
}
@{
Id = 'H27'
Rule = 'cut_report: the report''s repo must equal its spec''s, not only its branch.'
Test = 'admission::tests::a_cut_report_cites_an_in_force_spec_and_agrees_with_it'
File = 'crates/huginn-mind/src/admission.rs'
Old = @'
if report.repo != spec.repo {
return Err(MindRefusal::SpecMismatch { field: "repo".into() });
}
'@
New = ''
}
@{
Id = 'H28'
Rule = 'Ruling A: a promise is measured by the claim naming that label, not by any claim naming any promise.'
Test = 'admission::tests::verdict_vocabulary_binds_claims_to_findings_promises_and_mutations'
File = 'crates/huginn-mind/src/admission.rs'
Old = ' let count = verdict.claims.iter().filter(|claim| claim.promise.as_ref() == Some(&promise.label)).count();'
New = ' let count = verdict.claims.iter().filter(|claim| claim.promise.is_some()).count();'
}
@{
Id = 'H29'
Rule = 'finding: the invariant vocabulary is the in-force target''s, not any target the campaign ever had.'
Test = 'admission::tests::a_finding_names_evidence_locations_and_known_invariants'
File = 'crates/huginn-mind/src/admission.rs'
Old = ' D::Target(target) if target.campaign == finding.campaign && docs.in_force(K::Target, target_key) => Some(target),'
New = ' D::Target(target) if target.campaign == finding.campaign && (docs.in_force(K::Target, target_key) || true) => Some(target),'
}
@{
Id = 'H30'
Rule = 'The matrix is one row per kind: a question is answered or withdrawn, never superseded.'
Test = 'admission::tests::the_resolution_matrix_is_admissions'
File = 'crates/huginn-mind/src/admission.rs'
Old = @'
(K::Question, O::Withdrawn { .. }) => true,
'@
New = @'
(K::Question, O::Withdrawn { .. }) => true,
(K::Question, O::Superseded { by }) => all(by, K::Question),
'@
}
@{
Id = 'H31'
Rule = 'hand_off: the derived stewardship starts on the day the repo was handed over.'
Test = 'admission::tests::a_hand_off_derives_this_minds_side_only'
File = 'crates/huginn-mind/src/admission.rs'
Old = ' assigned_on: hand_off.handed_on.clone(),'
New = ' assigned_on: epiphany_pipeline::Date("2026-01-01".into()),'
}
@{
Id = 'H32'
Rule = 'Derived writes go through validation, A4 and A7 like any other: what a derived write cites in the image is pinned.'
Test = 'admission::tests::a_repo_is_stewarded_once_at_a_time_and_again_after_a_transfer'
File = 'crates/huginn-mind/src/admission.rs'
Old = @'
for document in derive(&docs, &mind) {
document.validate()?;
let envelope = document.prepare(self.cache()).map_err(unavailable)?;
docs.push(stage(envelope, &mind)?)?;
}
for staged in &docs.batch[originals..] {
resolve(&docs, staged, &mind, &mut strong)?;
}
'@
New = @'
for document in derive(&docs, &mind) {
let envelope = document.prepare(self.cache()).map_err(unavailable)?;
docs.batch.push(Staged { kind: document.kind(), key: envelope.key.clone(), document, envelope });
}
let _ = originals;
'@
}
@{
Id = 'H33'
Rule = 'A4: one identity, once, within a batch.'
Test = 'admission::tests::a_batch_is_one_to_sixty_four_documents_each_with_its_own_identity'
File = 'crates/huginn-mind/src/docs.rs'
Old = @'
if self.batch.iter().any(|other| other.kind == staged.kind && other.key == staged.key) {
return Err(MindRefusal::IdentityCollision { kind: staged.kind, id: staged.key });
}
'@
New = ''
}
@{
Id = 'H34'
Rule = 'A2: one to sixty-four envelopes, both ends checked.'
Test = 'admission::tests::a_batch_is_one_to_sixty_four_documents_each_with_its_own_identity'
File = 'crates/huginn-mind/src/admission.rs'
Old = ' if envelopes.is_empty() || envelopes.len() > BATCH_MAX {'
New = ' if false {'
}
@{
Id = 'H35'
Rule = 'question: a question offers a real choice, at least two options, one of them the recommendation.'
Test = 'admission::tests::a_question_offers_at_least_two_options_and_recommends_one_of_them'
File = 'crates/huginn-mind/src/admission.rs'
Old = @'
if question.options.len() < 2 || !question.options.iter().any(|option| option.label == question.recommended) {
return Err(MindRefusal::InvalidOptions { question: key.into() });
}
'@
New = ''
}
@{
Id = 'H36'
Rule = 'question: an option label names one option.'
Test = 'admission::tests::a_label_names_one_option_and_one_invariant'
File = 'crates/huginn-mind/src/admission.rs'
Old = ' unique_labels("question.options", question.options.iter().map(|option| option.label.0.as_str()))'
New = ' Ok(())'
}
@{
Id = 'H37'
Rule = 'target: an invariant label names one invariant.'
Test = 'admission::tests::a_label_names_one_option_and_one_invariant'
File = 'crates/huginn-mind/src/admission.rs'
Old = ' unique_labels("target.invariants", target.invariants.iter().map(|invariant| invariant.label.0.as_str()))'
New = ' Ok(())'
}
@{
Id = 'H38'
Rule = 'finding: a finding names where in the code it lives, not only that evidence exists.'
Test = 'admission::tests::a_finding_names_evidence_locations_and_known_invariants'
File = 'crates/huginn-mind/src/admission.rs'
Old = ' if finding.evidence.is_empty() || finding.locations.is_empty() {'
New = ' if finding.evidence.is_empty() {'
}
@{
Id = 'H39'
Rule = 'resolution: an Answered names the ruling that answers this subject, not some other question''s ruling.'
Test = 'admission::tests::a_ruling_answering_a_question_derives_the_answered_resolution_atomically'
File = 'crates/huginn-mind/src/admission.rs'
Old = @'
if ruling.answers.as_ref().map(|answers| answers.0.as_str()) != Some(subject_id) {
return Err(incompatible());
}
'@
New = ' let _ = (ruling, subject_id);'
}
@{
Id = 'H40'
Rule = 'resolution: the sequence is the previous plus one over image and batch (Q17 B).'
Test = 'admission::tests::a_subject_with_a_resolution_in_force_refuses_another'
File = 'crates/huginn-mind/src/admission.rs'
Old = ' if resolution.sequence != expected {'
New = ' if false {'
}
@{
Id = 'H41'
Rule = 'In force is recursive: a withdrawn resolution no longer closes its subject.'
Test = 'admission::tests::a_withdrawn_resolution_reopens_its_subject_and_stays_readable'
File = 'crates/huginn-mind/src/docs.rs'
Old = @'
&& !own(resolution)
&& self.in_force(PipelineKind::Resolution, key)
'@
New = @'
&& !own(resolution)
&& { let _ = key; true }
'@
}
@{
Id = 'H42'
Rule = 'stewardship: the sequence is the previous plus one, as a resolution''s is (Q18 A, Q20 A).'
Test = 'admission::tests::a_repo_is_stewarded_once_at_a_time_and_again_after_a_transfer'
File = 'crates/huginn-mind/src/admission.rs'
Old = ' if stewardship.sequence != expected {'
New = ' if false {'
}
@{
Id = 'H43'
Rule = 'stewardship: at most one assignment of a repo is in force on a mind.'
Test = 'admission::tests::a_repo_is_stewarded_once_at_a_time_and_again_after_a_transfer'
File = 'crates/huginn-mind/src/admission.rs'
Old = @'
if docs.stewardships_of(mind, &stewardship.repo, None).iter().any(|(other, _)| *other != key) {
return Err(MindRefusal::AlreadyStewarded { repo: stewardship.repo.0.clone() });
}
'@
New = ''
}
@{
Id = 'H44'
Rule = 'Q19 A: a withdrawal cannot be withdrawn; the chain stops at depth two.'
Test = 'admission::tests::a_withdrawn_resolution_reopens_its_subject_and_stays_readable'
File = 'crates/huginn-mind/src/admission.rs'
Old = @'
if subject_kind == K::Resolution
&& let Some(D::Resolution(subject)) = docs.find(K::Resolution, subject_id)
&& subject.subject.kind == K::Resolution
{
return Err(incompatible());
}
'@
New = ''
}
@{
Id = 'H45'
Rule = 'derive: a derived resolution takes the subject''s next sequence, not always the first.'
Test = 'admission::tests::a_withdrawn_resolution_reopens_its_subject_and_stays_readable'
File = 'crates/huginn-mind/src/admission.rs'
Old = @'
let sequence = docs.derived_resolution_sequence(&subject, |outcome| {
matches!(outcome, ResolutionOutcome::Answered { by } if by.kind == K::Ruling && by.id.0 == staged.key)
});
'@
New = @'
let sequence = 1;
'@
}
@{
Id = 'H46'
Rule = 'derive: H45''s other half, a derived stewardship takes the repo''s next sequence on this mind.'
Test = 'admission::tests::a_repo_is_stewarded_once_at_a_time_and_again_after_a_transfer'
File = 'crates/huginn-mind/src/admission.rs'
Old = ' sequence: docs.derived_stewardship_sequence(mind, &hand_off.repo, &staged.key),'
New = ' sequence: 1,'
}
@{
Id = 'H47'
Rule = 'stewardships_of: only an in-force assignment counts, so a handed-away repo is not stewarded.'
Test = 'admission::tests::a_repo_is_stewarded_once_at_a_time_and_again_after_a_transfer'
File = 'crates/huginn-mind/src/docs.rs'
Old = @'
self.assignments_of(mind, repo)
.filter(|(key, _)| {
self.in_force_unless(PipelineKind::Stewardship, key, |resolution| {
matches!(&resolution.outcome, ResolutionOutcome::Withdrawn { reason } if Some(reason.0.as_str()) == hand_off_key)
})
})
'@
New = @'
self.assignments_of(mind, repo)
.filter(|_| {
let _ = hand_off_key;
true
})
'@
}
@{
Id = 'H48'
Rule = 'A7: a document two batch documents cite is pinned once, not cancelled by the second citation.'
Test = 'admission::tests::every_cited_image_document_is_a_strong_read'
File = 'crates/huginn-mind/src/admission.rs'
Old = ' strong.insert((reference.kind.type_id().to_string(), reference.id));'
New = @'
let pin = (reference.kind.type_id().to_string(), reference.id);
if !strong.insert(pin.clone()) {
strong.remove(&pin);
}
'@
}
@{
Id = 'H49'
Rule = 'finding: the in-force target is looked for in image and batch, not the image alone.'
Test = 'admission::tests::a_finding_names_evidence_locations_and_known_invariants'
File = 'crates/huginn-mind/src/admission.rs'
Old = ' let target = docs.of_kind(K::Target).find_map(|(target_key, document)| match document {'
New = ' let target = docs.image.iter().map(|held| (held.key.as_str(), &held.document)).find_map(|(target_key, document)| match document {'
}
@{
Id = 'H50'
Rule = 'resolution: the Answered coherence check reads the ruling wherever it is, batch or image.'
Test = 'admission::tests::a_ruling_answering_a_question_derives_the_answered_resolution_atomically'
File = 'crates/huginn-mind/src/admission.rs'
Old = ' let Some(D::Ruling(ruling)) = docs.find(K::Ruling, &by.id.0) else { return Ok(()) };'
New = ' let Some(D::Ruling(ruling)) = docs.in_batch(K::Ruling, &by.id.0) else { return Ok(()) };'
}
@{
Id = 'H51'
Rule = 'cut_report: the branch is compared as written; git''s refs are case-sensitive.'
Test = 'admission::tests::a_cut_report_cites_an_in_force_spec_and_agrees_with_it'
File = 'crates/huginn-mind/src/admission.rs'
Old = ' if report.branch != spec.branch {'
New = ' if !report.branch.0.eq_ignore_ascii_case(&spec.branch.0) {'
}
@{
Id = 'H52'
Rule = 'derive: a ruling''s resolution takes the next sequence even when the image already holds the one this batch derived, so an exact replay never matches.'
Test = 'admission::tests::an_exact_replay_re_derives_the_rulings_resolution'
File = 'crates/huginn-mind/src/admission.rs'
Old = @'
let sequence = docs.derived_resolution_sequence(&subject, |outcome| {
matches!(outcome, ResolutionOutcome::Answered { by } if by.kind == K::Ruling && by.id.0 == staged.key)
});
'@
New = @'
let sequence = docs.latest_resolution(&subject, None) + 1;
'@
}
@{
Id = 'H53'
Rule = 'derive: the hand-off''s withdrawal takes the next sequence even when the image holds the one this hand-off derived.'
Test = 'admission::tests::an_exact_replay_re_derives_both_sides_of_a_hand_off'
File = 'crates/huginn-mind/src/admission.rs'
Old = @'
let sequence = docs.derived_resolution_sequence(&subject, |outcome| {
matches!(outcome, ResolutionOutcome::Withdrawn { reason } if reason.0 == staged.key)
});
'@
New = @'
let sequence = docs.latest_resolution(&subject, None) + 1;
'@
}
@{
Id = 'H54'
Rule = 'derive: the hand-off''s assignment takes the next sequence even when the image holds the one this hand-off derived.'
Test = 'admission::tests::an_exact_replay_re_derives_both_sides_of_a_hand_off'
File = 'crates/huginn-mind/src/admission.rs'
Old = ' sequence: docs.derived_stewardship_sequence(mind, &hand_off.repo, &staged.key),'
New = ' sequence: docs.latest_stewardship(mind, &hand_off.repo, None) + 1,'
}
@{
Id = 'H55'
Rule = 'Q19 A: a withdrawal may re-raise an earlier stewardship over a later one.'
Test = 'admission::tests::a_withdrawal_does_not_reinstate_a_stewardship_over_a_later_one'
File = 'crates/huginn-mind/src/admission.rs'
Old = ' if matches!(resolution.outcome, ResolutionOutcome::Withdrawn { .. })'
New = ' if false'
}
@{
Id = 'H56'
Rule = 'H55 against the revision case: an earlier revision re-raised over the one that superseded it.'
Test = 'admission::tests::a_withdrawal_does_not_reinstate_a_revision_over_a_later_one'
File = 'crates/huginn-mind/src/admission.rs'
Old = ' if matches!(resolution.outcome, ResolutionOutcome::Withdrawn { .. })'
New = ' if false'
}
@{
Id = 'H57'
Rule = 'resolution: the sequence rule accepts a gap (only a taken sequence refuses).'
Test = 'admission::tests::a_sequence_gap_refuses_on_both_sequenced_kinds'
File = 'crates/huginn-mind/src/admission.rs'
Old = ' if resolution.sequence != expected {'
New = ' if resolution.sequence < expected {'
}
@{
Id = 'H58'
Rule = 'stewardship: the sequence rule accepts a gap (only a taken sequence refuses).'
Test = 'admission::tests::a_sequence_gap_refuses_on_both_sequenced_kinds'
File = 'crates/huginn-mind/src/admission.rs'
Old = ' if stewardship.sequence != expected {'
New = ' if stewardship.sequence < expected {'
}
@{
Id = 'H59'
Rule = 'Q19 cap: the subject resolution is looked for in the image only, so a chain landing in one batch is not capped.'
Test = 'admission::tests::the_cap_reads_a_chain_landing_in_one_batch'
File = 'crates/huginn-mind/src/admission.rs'
Old = ' && let Some(D::Resolution(subject)) = docs.find(K::Resolution, subject_id)'
New = ' && let Some(D::Resolution(subject)) = docs.in_image(K::Resolution, subject_id)'
}
@{
Id = 'H60'
Rule = 'latest_resolution reads the image only, not the batch.'
Test = 'admission::tests::the_latest_resolution_counts_the_batch'
File = 'crates/huginn-mind/src/docs.rs'
Old = @'
self.resolutions_of(subject)
.filter(|(_, resolution)| own != Some(*resolution))
'@
New = @'
self.image.iter().filter(|held| held.kind == PipelineKind::Resolution).filter_map(|held| match &held.document { PipelineDocument::Resolution(resolution) => Some((held.key.as_str(), resolution)), _ => None })
.filter(|(_, resolution)| resolution.subject == *subject && own != Some(*resolution))
'@
}
@{
Id = 'H61'
Rule = 'derive: the hand-off''s withdrawal always takes sequence 1.'
Test = 'admission::tests::a_hand_offs_derived_withdrawal_takes_the_next_sequence'
File = 'crates/huginn-mind/src/admission.rs'
Old = @'
let sequence = docs.derived_resolution_sequence(&subject, |outcome| {
matches!(outcome, ResolutionOutcome::Withdrawn { reason } if reason.0 == staged.key)
});
'@
New = @'
let sequence = 1;
'@
}
@{
Id = 'H62'
Rule = 'stewardship_of: the assignment a hand-off withdraws is picked by key order, so a replay after ten transfers withdraws whichever sorts first.'
Test = 'admission::tests::a_source_side_replay_withdraws_the_assignment_it_withdrew'
File = 'crates/huginn-mind/src/docs.rs'
Old = @'
let candidates = self.stewardships_of(mind, repo, hand_off_key);
hand_off_key
.and_then(|hand_off| {
candidates.iter().find(|(key, _)| {
self.resolutions().any(|(_, resolution)| {
resolution.subject.kind == PipelineKind::Stewardship
&& resolution.subject.id.0 == *key
&& matches!(&resolution.outcome, ResolutionOutcome::Withdrawn { reason } if reason.0 == hand_off)
})
})
})
.or_else(|| candidates.first())
.copied()
'@
New = @'
self.stewardships_of(mind, repo, hand_off_key).first().copied()
'@
}
@{
Id = 'H63'
Rule = 'stewardship_of: H62''s weaker half, any withdrawal of a candidate identifies it, whatever hand-off gave the reason.'
Test = 'admission::tests::a_source_side_replay_withdraws_the_assignment_it_withdrew'
File = 'crates/huginn-mind/src/docs.rs'
Old = ' && matches!(&resolution.outcome, ResolutionOutcome::Withdrawn { reason } if reason.0 == hand_off)'
New = ' && { let _ = hand_off; matches!(&resolution.outcome, ResolutionOutcome::Withdrawn { .. }) }'
}
@{
Id = 'H64'
Rule = 'derive: the ruling''s resolution matches any answer of the question, whichever ruling answered it.'
Test = 'admission::tests::a_ruling_answering_a_reopened_question_takes_the_next_sequence'
File = 'crates/huginn-mind/src/admission.rs'
Old = ' matches!(outcome, ResolutionOutcome::Answered { by } if by.kind == K::Ruling && by.id.0 == staged.key)'
New = ' matches!(outcome, ResolutionOutcome::Answered { .. })'
}
@{
Id = 'H65'
Rule = 'later_than: a cut spec is sequenced within its campaign, not within its cut.'
Test = 'admission::tests::a_reinstatement_reads_the_revisions_of_its_own_cut'
File = 'crates/huginn-mind/src/docs.rs'
Old = ' other.campaign == base.campaign && other.cut == base.cut && other.revision > base.revision'
New = ' other.campaign == base.campaign && other.revision > base.revision'
}
@{
Id = 'H66'
Rule = 'later_in_force: a later record blocks a reinstatement whether or not it still stands.'
Test = 'admission::tests::a_withdrawn_later_assignment_does_not_block_a_reinstatement'
File = 'crates/huginn-mind/src/docs.rs'
Old = ' self.of_kind(kind).find(|(key, other)| later_than(base, other) && self.in_force(kind, key)).map(|(key, _)| key)'
New = ' self.of_kind(kind).find(|(key, other)| later_than(base, other)).map(|(key, _)| key)'
}
@{
Id = 'H67'
Rule = 'later_in_force: the image only, so a later record landing in the same batch does not block.'
Test = 'admission::tests::a_reinstatement_is_blocked_by_an_assignment_in_its_own_batch'
File = 'crates/huginn-mind/src/docs.rs'
Old = ' self.of_kind(kind).find(|(key, other)| later_than(base, other) && self.in_force(kind, key)).map(|(key, _)| key)'
New = ' self.image.iter().filter(|held| held.kind == kind).map(|held| (held.key.as_str(), &held.document)).find(|(key, other)| later_than(base, other) && self.in_force(kind, key)).map(|(key, _)| key)'
}
)
}

View file

@ -1,371 +0,0 @@
# Cut 9 mutations, V1-V24L: the read side's rules, each entry restoring one
# permissiveness the cut closed and naming the test that must fail while it is
# applied. A rule with two weakenings has two entries: `Vn` is the revert, the
# rule simply absent, and `VnL` is the loosening, the rule weakened rather than
# removed. Run through the Eureka skill's harness from this repo:
#
# $env:CARGO_TARGET_DIR = 'C:\Users\Meta\.cargo-target-codex'
# powershell -File C:\Users\Meta\.claude\skills\eureka\tools\eureka-mutations.ps1 -Repo F:\Projects\Huginn `
# -Entries tools/eureka-cut9-mutations.psd1 `
# -Target crates/huginn-mind/src/docs.rs,crates/huginn-mind/src/query.rs `
# -Test 'cargo test -p huginn-mind --lib'
#
# `docs.rs` is a target for V1 alone, which is the point of V1: in force has
# one owner, and the mutant that breaks it for the rules is the mutant that
# breaks it for the views. V1L is H41's own edit, listed here as well as in
# `eureka-cut8-mutations.psd1` -- one mutant, two suites, one owner.
#
# Two weakenings the spec names have no entry, not because they are
# unreachable but because nothing in this suite exercises the path that would
# reach them. `MindStore::compare_and_swap_batch` is `pub`, and `store.rs`'s
# own re-export of `CacheBackingStore` already lets code outside this crate
# push a row that skips A5 (and every other admission rule) entirely -- the
# door named at `store.rs:18-19`. Recorded as not yet reached, not as
# unreachable:
#
# - `assignments_of` comparing the repo and ignoring the instance. A5 refuses
# a stewardship naming another instance for every row admission writes, so
# every stewardship admission ever lands already names the mind that holds
# it, and every caller reachable through admission is a sequence this mind
# derives over its own scope. A row planted through the store port directly,
# naming another instance, is not yet reached by anything in this suite.
# - `resolutions_of` comparing a subject by `id` alone, which was `V10L` until
# the leaf opened `PipelineRef::validate_ref` and `view` and `history` began
# asking it. A ref that reaches the comparison through admission has a kind
# its id's kind segment agrees with, and every stored subject admission
# writes was held to the same grammar, so on both sides the kind is a
# function of the id and comparing the whole ref and comparing the id alone
# cannot differ for anything admission wrote. The rule is still the rule; it
# is the reachable weakening that went, and what defends it is `V24`/`V24L`
# at the doors instead. A row planted through the store port directly, with
# a subject whose kind disagrees with its id, is not yet reached either.
#
# The one listed beside them in the spec is failable and has an entry: the
# `semantic` check below `Reader::new` changes the answer for a store the
# reader refuses -- a doubled receipt, a row that does not decode -- from the
# semantic refusal to the integrity one, and `V8L` is that move.
@{
Mutations = @(
@{
Id = 'V1'
Rule = 'One owner for in force: the views derive status through the same closing_resolution the rules ask.'
Test = 'query::tests::status_is_the_derivation_admission_uses'
File = 'crates/huginn-mind/src/docs.rs'
Old = @'
self.resolutions().find(|&(key, resolution)| {
resolution.subject.kind == kind
&& resolution.subject.id.0 == id
&& !own(resolution)
&& self.in_force(PipelineKind::Resolution, key)
})
'@
New = @'
let _ = (kind, id, own);
None
'@
}
@{
Id = 'V1L'
Rule = 'In force is recursive for a reader as it is for a rule: a withdrawn resolution stops closing its subject. H41''s edit, run against the views.'
Test = 'query::tests::status_is_the_derivation_admission_uses'
File = 'crates/huginn-mind/src/docs.rs'
Old = @'
&& !own(resolution)
&& self.in_force(PipelineKind::Resolution, key)
'@
New = @'
&& !own(resolution)
&& { let _ = key; true }
'@
}
@{
Id = 'V2'
Rule = 'admitted_at is the receipt''s committed_at, never the store''s stored_at stamp (R-C).'
Test = 'query::tests::views_read_admitted_at_from_the_receipt_not_stored_at'
File = 'crates/huginn-mind/src/query.rs'
Old = ' admitted_at: receipt.committed_at.clone(),'
New = ' admitted_at: mind.raw_envelope(&write.document_type, &write.document_key).map_or_else(|| receipt.committed_at.clone(), |envelope| envelope.stored_at.clone()),'
}
@{
Id = 'V3'
Rule = 'The facts come from a receipt''s writes only, so a document a later batch cited keeps the receipt that wrote it.'
Test = 'query::tests::views_join_admission_facts_from_the_receipt_that_wrote_them'
File = 'crates/huginn-mind/src/query.rs'
Old = ' for write in receipt.writes.iter() {'
New = ' for write in receipt.writes.iter().chain(&receipt.strong_reads) {'
}
@{
Id = 'V4'
Rule = 'A row no receipt wrote refuses, from view and query alike, and is never skipped.'
Test = 'query::tests::views_join_admission_facts_from_the_receipt_that_wrote_them'
Edits = @(
@{
File = 'crates/huginn-mind/src/query.rs'
Old = ' let view = reader.view_of(held)?;'
New = ' let Ok(view) = reader.view_of(held) else { continue };'
}
@{
File = 'crates/huginn-mind/src/query.rs'
Old = ' reader.held(id.kind, &id.id.0).map(|held| reader.view_of(held)).transpose()'
New = ' Ok(reader.held(id.kind, &id.id.0).and_then(|held| reader.view_of(held).ok()))'
}
)
}
@{
Id = 'V4L'
Rule = 'Two receipts naming one write is an integrity fault, not a choice of which to believe.'
Test = 'query::tests::views_join_admission_facts_from_the_receipt_that_wrote_them'
File = 'crates/huginn-mind/src/query.rs'
Old = @'
if facts.insert(identity, landed).is_some() {
return Err(integrity(&write.document_type, &write.document_key, "is written by two receipts"));
}
'@
New = @'
facts.insert(identity, landed);
'@
}
@{
Id = 'V5'
Rule = 'The cap: a caller''s limit is clamped into 1..=QUERY_LIMIT_MAX.'
Test = 'query::tests::query_orders_by_admitted_at_then_id_and_caps_at_200_with_the_match_count'
File = 'crates/huginn-mind/src/query.rs'
Old = '.clamp(1, QUERY_LIMIT_MAX));'
New = '.max(1));'
}
@{
Id = 'V5L'
Rule = 'The cap is 200, and the test spells it out rather than reading the constant under test.'
Test = 'query::tests::query_orders_by_admitted_at_then_id_and_caps_at_200_with_the_match_count'
File = 'crates/huginn-mind/src/query.rs'
Old = 'pub const QUERY_LIMIT_MAX: usize = 200;'
New = 'pub const QUERY_LIMIT_MAX: usize = 201;'
}
@{
Id = 'V6'
Rule = 'The order is (admitted_at, id): the batch decides, and the key only breaks a tie inside one.'
Test = 'query::tests::query_orders_by_admitted_at_then_id_and_caps_at_200_with_the_match_count'
File = 'crates/huginn-mind/src/query.rs'
Old = @'
(&left.admission.admitted_at, &left.id.id.0).cmp(&(&right.admission.admitted_at, &right.id.id.0))
'@
New = @'
left.id.id.0.cmp(&right.id.id.0)
'@
}
@{
Id = 'V6L'
Rule = 'A tie inside one batch falls to the key, which is root-first and so is not the image''s (type, key) order.'
Test = 'query::tests::query_orders_by_admitted_at_then_id_and_caps_at_200_with_the_match_count'
File = 'crates/huginn-mind/src/query.rs'
Old = @'
(&left.admission.admitted_at, &left.id.id.0).cmp(&(&right.admission.admitted_at, &right.id.id.0))
'@
New = @'
left.admission.admitted_at.cmp(&right.admission.admitted_at)
'@
}
@{
Id = 'V7'
Rule = 'matched is the count before the cap, so a truncated page is visible as one.'
Test = 'query::tests::query_orders_by_admitted_at_then_id_and_caps_at_200_with_the_match_count'
File = 'crates/huginn-mind/src/query.rs'
Old = @'
let matched = items.len() as u32;
ordered(&mut items);
let limit = query.limit.map_or(QUERY_LIMIT_MAX, |limit| (limit as usize).clamp(1, QUERY_LIMIT_MAX));
items.truncate(limit);
'@
New = @'
ordered(&mut items);
let limit = query.limit.map_or(QUERY_LIMIT_MAX, |limit| (limit as usize).clamp(1, QUERY_LIMIT_MAX));
items.truncate(limit);
let matched = items.len() as u32;
'@
}
@{
Id = 'V8'
Rule = 'semantic is refused typed until Cut 11, never answered with an empty page.'
Test = 'query::tests::semantic_query_refuses_typed_until_wired'
File = 'crates/huginn-mind/src/query.rs'
Old = @'
return Err(MindRefusal::Unavailable {
detail: "semantic query: the index is not wired (Cut 11)".into(),
});
'@
New = @'
return Ok(PipelineQueryPage { items: vec![], matched: 0 });
'@
}
@{
Id = 'V8L'
Rule = 'The semantic refusal is decided before the image and the receipts are read, so a store the reader refuses still answers the question the caller asked.'
Test = 'query::tests::semantic_query_refuses_typed_until_wired'
File = 'crates/huginn-mind/src/query.rs'
Old = @'
if query.semantic.is_some() {
return Err(MindRefusal::Unavailable {
detail: "semantic query: the index is not wired (Cut 11)".into(),
});
}
let reader = Reader::new(self)?;
'@
New = @'
let reader = Reader::new(self)?;
if query.semantic.is_some() {
return Err(MindRefusal::Unavailable {
detail: "semantic query: the index is not wired (Cut 11)".into(),
});
}
'@
}
@{
Id = 'V16'
Rule = 'The cut filter is the label, not every cut.'
Test = 'query::tests::query_filters_each_select_by_one_field'
File = 'crates/huginn-mind/src/query.rs'
Old = ' && !root_and_local(&base.key).1.starts_with(&format!("cut-{}.", cut.0))'
New = ' && !root_and_local(&base.key).1.starts_with("cut-")'
}
@{
Id = 'V16L'
Rule = 'The cut prefix ends at the dot, so cut-1 does not match cut-10.'
Test = 'query::tests::query_filters_each_select_by_one_field'
File = 'crates/huginn-mind/src/query.rs'
Old = ' && !root_and_local(&base.key).1.starts_with(&format!("cut-{}.", cut.0))'
New = ' && !root_and_local(&base.key).1.starts_with(&format!("cut-{}", cut.0))'
}
@{
Id = 'V17'
Rule = 'A filter reaches a resolution through its base, the document it is a record of.'
Test = 'query::tests::query_filters_each_select_by_one_field'
File = 'crates/huginn-mind/src/query.rs'
Old = @'
let mut current = held;
while let PipelineDocument::Resolution(resolution) = &current.document {
let Some(subject) = self.held(resolution.subject.kind, &resolution.subject.id.0) else {
return current;
};
current = subject;
}
current
'@
New = @'
held
'@
}
@{
Id = 'V17L'
Rule = 'The base is walked to the first non-resolution, not one step: a withdrawal of a resolution is two steps from its document.'
Test = 'query::tests::query_filters_each_select_by_one_field'
File = 'crates/huginn-mind/src/query.rs'
Old = ' while let PipelineDocument::Resolution(resolution) = &current.document {'
New = ' if let PipelineDocument::Resolution(resolution) = &current.document {'
}
@{
Id = 'V18'
Rule = 'campaign is the key''s root segment.'
Test = 'query::tests::query_filters_each_select_by_one_field'
File = 'crates/huginn-mind/src/query.rs'
Old = @'
if let Some(campaign) = &query.campaign
&& root_and_local(&held.key).0 != campaign.0
{
return false;
}
'@
New = ''
}
@{
Id = 'V18L'
Rule = 'The root, not a campaign field: a stewardship under an instance root and a resolution under its subject''s root carry no campaign of their own.'
Test = 'query::tests::query_filters_each_select_by_one_field'
File = 'crates/huginn-mind/src/query.rs'
Old = ' && root_and_local(&held.key).0 != campaign.0'
New = ' && !matches!(&held.document, PipelineDocument::Campaign(value) if value.slug == *campaign)'
}
@{
Id = 'V19'
Rule = 'kinds selects by the document''s kind, and an empty list matches every kind.'
Test = 'query::tests::query_filters_each_select_by_one_field'
File = 'crates/huginn-mind/src/query.rs'
Old = @'
if !query.kinds.is_empty() && !query.kinds.contains(&held.kind) {
return false;
}
'@
New = ''
}
@{
Id = 'V20'
Rule = 'in_force selects by the derived status.'
Test = 'query::tests::query_filters_each_select_by_one_field'
File = 'crates/huginn-mind/src/query.rs'
Old = @'
if let Some(in_force) = query.in_force
&& in_force != (view.status == PipelineStatus::InForce)
{
return false;
}
'@
New = ''
}
@{
Id = 'V20L'
Rule = 'in_force selects the status the caller asked for, not its opposite.'
Test = 'query::tests::query_filters_each_select_by_one_field'
File = 'crates/huginn-mind/src/query.rs'
Old = ' && in_force != (view.status == PipelineStatus::InForce)'
New = ' && in_force == (view.status == PipelineStatus::InForce)'
}
@{
Id = 'V21'
Rule = 'faculty selects by the receipt''s provenance: attribution filters, and grants nothing (ruling 18).'
Test = 'query::tests::query_filters_each_select_by_one_field'
File = 'crates/huginn-mind/src/query.rs'
Old = @'
if let Some(faculty) = query.faculty
&& view.admission.provenance.faculty != faculty
{
return false;
}
'@
New = ''
}
@{
Id = 'V23'
Rule = 'repo selects by the repo the document names, read through the base.'
Test = 'query::tests::query_filters_each_select_by_one_field'
File = 'crates/huginn-mind/src/query.rs'
Old = @'
if let Some(repo) = &query.repo
&& !repo_matches(&base.document, repo)
{
return false;
}
'@
New = ''
}
@{
Id = 'V23L'
Rule = 'A campaign matches through the repos it lists, as the five single-repo kinds match through their field.'
Test = 'query::tests::query_filters_each_select_by_one_field'
File = 'crates/huginn-mind/src/query.rs'
Old = ' D::Campaign(campaign) => campaign.repos.contains(repo),'
New = ' D::Campaign(_) => false,'
}
@{
Id = 'V24'
Rule = 'The door that takes a ref asks the leaf''s grammar first: a ref whose kind and id disagree is refused, never answered over as an absent document. RS-2 deleted `history`, the rule''s other door; only `view`''s survives, so this is now a single edit rather than the two-door `Edits` array it was before.'
Test = 'query::tests::a_ref_whose_kind_and_id_disagree_is_refused_by_both_doors'
File = 'crates/huginn-mind/src/query.rs'
Old = @'
id.validate_ref()?;
let reader = Reader::new(self)?;
'@
New = @'
let reader = Reader::new(self)?;
'@
}
)
}

View file

@ -1,179 +0,0 @@
# RS-1 mutations, R1-R5: the receipt ordinal, receipt v2, and the epoch-first
# opener. Each rule has a revert, `Rn`, and (where a distinct weaker shape
# exists) a loosening, `RnL`. Every entry names the test that must fail while
# it is applied. Run through the Eureka skill's harness from this repo:
#
# $env:CARGO_TARGET_DIR = 'C:\Users\Meta\.cargo-target-codex'
# powershell -File C:\Users\Meta\.claude\skills\eureka\tools\eureka-mutations.ps1 -Repo F:\Projects\Huginn `
# -Entries tools/eureka-readside-mutations.psd1 `
# -Target crates/huginn-mind/src/receipt.rs,crates/huginn-mind/src/admission.rs,crates/huginn-mind/src/mind.rs `
# -Test 'cargo test -p huginn-mind --lib'
#
# `M0` is the harness's own no-op control and is not listed here.
#
# R2 has no loosening and says so rather than carrying a weak entry: "the
# ordinal is not digested" has one natural mutant, putting it back in the
# digest. There is no partial shape of "digested a little" to weaken it into.
#
# R5 has no loosening for the same reason D9 and D12 in cut10 give: the rule
# is an order between two calls, and the only two orders are the order and
# its reverse. Swapping the gates back is the revert and the whole space of
# wrong orders at once.
@{
Mutations = @(
@{
Id = 'R1'
Rule = 'The ordinal is head + 1 at admission, assigned nowhere else.'
Test = 'admission::tests::ordinals_are_admission_order_not_clock_or_id_order'
File = 'crates/huginn-mind/src/admission.rs'
Old = ' let candidate = receipt::candidate(&mind, provenance, &strong_reads, &writes, receipt::head(self)? + 1, now)?;'
New = ' let candidate = receipt::candidate(&mind, provenance, &strong_reads, &writes, 1, now)?;'
}
@{
Id = 'R1L'
Rule = 'The ordinal is admission order, not a function of the clock or the receipt id: a same-second batch of three must not fall back to ranking by (committed_at, receipt_id).'
Test = 'admission::tests::ordinals_are_admission_order_not_clock_or_id_order'
File = 'crates/huginn-mind/src/admission.rs'
Old = ' let candidate = receipt::candidate(&mind, provenance, &strong_reads, &writes, receipt::head(self)? + 1, now)?;'
New = @'
let provisional = receipt::candidate(&mind, provenance.clone(), &strong_reads, &writes, 0, now)?;
let mut order = self.receipts()?.into_iter().map(|r| (r.committed_at, r.receipt_id)).collect::<Vec<_>>();
order.push((provisional.committed_at.clone(), provisional.receipt_id.clone()));
order.sort();
let ordinal = (order
.iter()
.position(|entry| entry == &(provisional.committed_at.clone(), provisional.receipt_id.clone()))
.unwrap()
+ 1) as u64;
let candidate = receipt::candidate(&mind, provenance, &strong_reads, &writes, ordinal, now)?;
'@
}
@{
Id = 'R1L2'
Rule = 'head is exactly N, not N off by one.'
Test = 'admission::tests::ordinals_are_admission_order_not_clock_or_id_order'
File = 'crates/huginn-mind/src/receipt.rs'
Old = ' Ok(n)'
New = ' Ok(n.saturating_sub(1))'
}
@{
Id = 'R2'
Rule = 'The ordinal is not digested (A9): an exact replay keeps the ordinal its first admission assigned, whatever the head has moved to since.'
Test = 'admission::tests::an_exact_replay_keeps_its_ordinal'
File = 'crates/huginn-mind/src/receipt.rs'
Old = ' let bytes = rmp_serde::to_vec_named(&(&self.instance, &self.strong_reads, &self.writes))'
New = ' let bytes = rmp_serde::to_vec_named(&(&self.instance, &self.strong_reads, &self.writes, self.ordinal))'
}
@{
Id = 'R3'
Rule = 'head requires the ordinals to be exactly {1..=N}; a chain that is not dense refuses rather than answering a number.'
Test = 'receipt::tests::a_chain_that_is_not_dense_refuses_admission_and_reads_alike'
File = 'crates/huginn-mind/src/receipt.rs'
Old = @'
let mut ordinals = mind.receipts()?.into_iter().map(|receipt| receipt.ordinal).collect::<Vec<_>>();
ordinals.sort_unstable();
let n = ordinals.len() as u64;
if ordinals.into_iter().eq(1..=n) {
Ok(n)
} else {
Err(MindRefusal::Unavailable { detail: "receipt ordinals are not 1..=N: found a duplicate or a gap".into() })
}
'@
New = @'
Ok(mind.receipts()?.len() as u64)
'@
}
@{
Id = 'R3L'
Rule = 'Density is validated wherever the ordinal is read, in the one shared head, not only along the one path a caller happens to exercise it from.'
Test = 'receipt::tests::a_chain_that_is_not_dense_refuses_admission_and_reads_alike'
Edits = @(
@{
File = 'crates/huginn-mind/src/receipt.rs'
Old = @'
let mut ordinals = mind.receipts()?.into_iter().map(|receipt| receipt.ordinal).collect::<Vec<_>>();
ordinals.sort_unstable();
let n = ordinals.len() as u64;
if ordinals.into_iter().eq(1..=n) {
Ok(n)
} else {
Err(MindRefusal::Unavailable { detail: "receipt ordinals are not 1..=N: found a duplicate or a gap".into() })
}
'@
New = @'
Ok(mind.receipts()?.len() as u64)
'@
}
@{
File = 'crates/huginn-mind/src/admission.rs'
Old = ' let candidate = receipt::candidate(&mind, provenance, &strong_reads, &writes, receipt::head(self)? + 1, now)?;'
New = @'
{
let mut ordinals = self.receipts()?.into_iter().map(|r| r.ordinal).collect::<Vec<_>>();
ordinals.sort_unstable();
let n = ordinals.len() as u64;
if !ordinals.into_iter().eq(1..=n) {
return Err(MindRefusal::Unavailable {
detail: "receipt ordinals are not 1..=N: found a duplicate or a gap".into(),
});
}
}
let candidate = receipt::candidate(&mind, provenance, &strong_reads, &writes, receipt::head(self)? + 1, now)?;
'@
}
)
}
@{
Id = 'R4'
Rule = 'Receipt v2 is a new type id, not the old id with an added field: a store carrying a v1-shaped receipt is refused at the type gate.'
Test = 'mind::tests::a_v1_receipt_store_is_refused_at_open'
Edits = @(
@{
File = 'crates/huginn-mind/src/receipt.rs'
Old = 'pub const RECEIPT_SCHEMA_VERSION: &str = "huginn.mind_commit_receipt.v2";'
New = 'pub const RECEIPT_SCHEMA_VERSION: &str = "huginn.mind_commit_receipt.v1";'
}
@{
File = 'crates/huginn-mind/src/receipt.rs'
Old = '#[cultcache(type = "huginn.mind_commit_receipt.v2", schema = "HuginnCommitReceipt")]'
New = '#[cultcache(type = "huginn.mind_commit_receipt.v1", schema = "HuginnCommitReceipt")]'
}
)
}
@{
Id = 'R4L'
Rule = 'The type gate knows only the current id, not the old one kept beside it for compatibility: a widened opener that still recognises huginn.mind_commit_receipt.v1 as known is the shape F3 warns against (a silent misread of every old receipt''s ordinal as 0), one step short of a full revert.'
Test = 'mind::tests::a_v1_receipt_store_is_refused_at_open'
File = 'crates/huginn-mind/src/mind.rs'
Old = @'
fn is_known_type(type_id: &str) -> bool {
type_id == HuginnMindEpoch::TYPE
|| type_id == HuginnCommitReceipt::TYPE
|| PipelineKind::ALL.iter().any(|kind| kind.type_id() == type_id)
}
'@
New = @'
fn is_known_type(type_id: &str) -> bool {
type_id == HuginnMindEpoch::TYPE
|| type_id == HuginnCommitReceipt::TYPE
|| type_id == "huginn.mind_commit_receipt.v1"
|| PipelineKind::ALL.iter().any(|kind| kind.type_id() == type_id)
}
'@
}
@{
Id = 'R5'
Rule = 'The epoch gate runs before the type gate, so a store written at a foreign epoch is refused as ForeignEpoch and not ForeignStore: a real epoch bump always moves every type id, so the type gate would otherwise fire first and the epoch gate would never be reached for the one case it exists for.'
Test = 'mind::tests::a_store_written_at_the_previous_epoch_is_refused_by_the_epoch_gate'
File = 'crates/huginn-mind/src/mind.rs'
Old = @'
refuse_foreign_epoch(&raw)?;
refuse_foreign_types(&raw)?;
'@
New = @'
refuse_foreign_types(&raw)?;
refuse_foreign_epoch(&raw)?;
'@
}
)
}