diff --git a/igneum-pow/src/accept.rs b/igneum-pow/src/accept.rs index daa8186ca..51ef435f3 100644 --- a/igneum-pow/src/accept.rs +++ b/igneum-pow/src/accept.rs @@ -489,7 +489,9 @@ pub fn is_class_v4_shape(class: &LoadClass) -> bool { // class v5 (docs/design/class-v5-stored-state.md) is judged under the same rules: its state flag is set aside; // class v6 lane 1's index fold and re-weight table are set aside too (the address path and the op table are // not the shape) - && LoadClass { era: None, shadow: None, state: false, fold: false, rw: 0, ..*class } == LoadClass { shadow: None, ..V4_CLASS } + // the window and layer 8 off are set aside too (lane D's finding of 8 October 2026, 19:1x UK: a +nowin or +reg64c + // program was judged by the class v2 parts alone on the chain's path; the harness's own predicate hid it) + && LoadClass { era: None, shadow: None, state: false, fold: false, rw: 0, nowin: false, reg64: false, reg64_chain: false, ..*class } == LoadClass { shadow: None, ..V4_CLASS } } /// One pass of the dataflow freshness over the base program then the shadow block (the order of one iteration), diff --git a/igneum-pow/src/generator.rs b/igneum-pow/src/generator.rs index 6a822bbd9..8f30ee48b 100644 --- a/igneum-pow/src/generator.rs +++ b/igneum-pow/src/generator.rs @@ -1705,7 +1705,7 @@ pub fn candidate_from_words_class( // class v6 lane 1: the index fold and the re-weight table are set aside too (the address path and the table are not // the shape; a +fold or +rw program draws its sources under the same rule) let source_rule_v4 = matches!(class.shadow, Some(ShadowClass { instrs: V4_SHADOW_INSTRS, .. })) - && LoadClass { era: None, shadow: None, state: false, fold: false, rw: 0, nowin: false, ..class } == LoadClass { shadow: None, ..V4_CLASS }; + && LoadClass { era: None, shadow: None, state: false, fold: false, rw: 0, nowin: false, reg64: false, reg64_chain: false, ..class } == LoadClass { shadow: None, ..V4_CLASS }; // the op table and the roll's range: the plain table at 75 for every class without the re-weight flag let (weights, weights_sum) = class.nonload_weights(); let mut fresh = [false; 8]; diff --git a/igneum-pow/tests/v6fold.rs b/igneum-pow/tests/v6fold.rs index b3c62ff37..b67eb9756 100644 --- a/igneum-pow/tests/v6fold.rs +++ b/igneum-pow/tests/v6fold.rs @@ -247,6 +247,23 @@ fn v6_draw_connects_all_lanes_and_keeps_mad_bijective_by_construction() { assert_ne!(a.program_id(), b.program_id()); } +/// Lane D's finding (8 October 2026): every class v6 flag is set aside by the acceptance's class v4 shape predicate, +/// so a +nowin, +reg64 or +reg64c program is judged by the full rule (the fresh-source rule, the saturated-source +/// check, the index floors and the attempt cap with the last resort), not by the class v2 parts; the draw's source +/// rule reads the same shape. +#[test] +fn every_v6_flag_keeps_the_class_v4_acceptance_shape() { + use igneum_pow::accept::is_class_v4_shape; + use igneum_pow::generator::max_attempts_for; + let all = LoadClass::parse("mx8+sh256x27+state+reg64c+nowin+fold+rw").unwrap(); + for c in [V5_CLASS, V5_CLASS.with_nowin(), V5_CLASS.with_reg64(), V5_CLASS.with_reg64().with_reg64_chain(), V5_CLASS.with_fold(), all] { + assert!(is_class_v4_shape(&c), "{}", c.name()); + assert!(is_class_v4_shape(&LoadClass::era(c, &f8_bytes("era", 4), &V3_ALLOWED)), "{} under an era", c.name()); + assert_eq!(max_attempts_for(&c), max_attempts_for(&V5_CLASS), "{}: the same attempt cap and last resort", c.name()); + } + assert!(!is_class_v4_shape(&V3_CLASS) && !is_class_v4_shape(&LoadClass::V2)); +} + /// 2. The fold's form: `y = x * M; y ^= y >> 16; y = rotl(y, R)`, and nothing else moves. The plain era's stride is /// `rotl(x * M, R)` byte for byte. #[test]