()
| 425 | |
| 426 | #[test] |
| 427 | fn substance_hash_ignores_review_state() { |
| 428 | let base = intent_substance_hash(&node()); |
| 429 | |
| 430 | // Intent-level status is review state — hash holds. |
| 431 | let mut status = node(); |
| 432 | status.status = "done".to_string(); |
| 433 | assert_eq!( |
| 434 | intent_substance_hash(&status), |
| 435 | base, |
| 436 | "status must not move substance" |
| 437 | ); |
| 438 | |
| 439 | // Per-AC review state (acStatus / verifiedBy / evidence) — hash holds. |
| 440 | let mut reviewed = node(); |
| 441 | reviewed.has_acceptance_criterion[0].ac_status = "met".to_string(); |
| 442 | reviewed.has_acceptance_criterion[0].verified_by = Some("did:atomic:lee".to_string()); |
| 443 | reviewed.has_acceptance_criterion[0].evidence = Some("urn:atomic:change:01J8".to_string()); |
| 444 | assert_eq!( |
| 445 | intent_substance_hash(&reviewed), |
| 446 | base, |
| 447 | "AC review state must not move substance" |
| 448 | ); |
| 449 | |
| 450 | // Accumulating a verification record — hash holds. |
| 451 | let mut verified = node(); |
| 452 | verified.has_acceptance_criterion[0] |
| 453 | .verifications |
| 454 | .push(VerificationRecord { |
| 455 | type_: "VerificationRecord".to_string(), |
| 456 | kind: "manual".to_string(), |
| 457 | outcome: "fail".to_string(), |
| 458 | scope: "view".to_string(), |
| 459 | observed_at_merkle: "ABC".to_string(), |
| 460 | reference: None, |
| 461 | observation: None, |
| 462 | }); |
| 463 | assert_eq!( |
| 464 | intent_substance_hash(&verified), |
| 465 | base, |
| 466 | "verification records must not move substance" |
| 467 | ); |
| 468 | } |
| 469 | |
| 470 | #[test] |
| 471 | fn substance_hash_tracks_the_definition() { |
nothing calls this directly
no test coverage detected