rust:Memento Pattern(续)

调用:

rust 复制代码
​
//!# encoding: utf-8 
//!# 版权所有  2026 ©涂聚文有限公司™ ®
//!# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
//!# 描述:备忘录模式Memento Pattern 行为模式 Behavioral Patterns
//!# Author    : geovindu,Geovin Du 涂聚文.
//!# IDE       : RustRover  2025.1.1 Rust  rustc 1.98.1 
//!# os        : windows 10
//!# database  : mysql 9.0 sql server 2025, postgreSQL 18.0  Oracle 21c Neo4j
//!# Datetime  : 2026/10/15 4:57 
//!# User      :  geovindu
//!# Product   : RustRover
//!# Project   : mementopattern
//!# File      : main.rs
//! # 备忘录模式(Memento Pattern)· 连锁珠宝门店「整单折扣改价审批 + 报价历史回滚」
//!
//! 业务域:一张销售单(聚合根)在成交前会被反复议价,每一次改价都要**过审批权限**,
//! 每一次被批准的改价都要**留下一个可以回到的版本**。
//! 本工程用备忘录模式把「报价的每一个历史版本」交给一个**读不懂它**的管理者持有。
//!
//! ## 严格分层结构(**实测**,由 `scripts/check_layer_dependencies.sh` 产出,不是设计意图)
//!
//! ```text
//! main
//!  ├─> app ─> analysis ─> client ─> domain
//!  │      │         │         └─> memento
//!  │      │         ├─> domain
//!  │      │         └─> memento
//!  │      ├─> domain
//!  │      └─> support
//!  ├─> analysis
//!  ├─> client
//!  ├─> domain
//!  ├─> memento
//!  └─> support
//! ```
//!
//! 实测邻接表(`bash scripts/check_layer_dependencies.sh src`,无环):
//!
//! ```text
//!   app       -> analysis domain support     (+ 层内 super:: 自引用 x1,合法)
//!   analysis  -> client domain memento
//!   client    -> domain memento
//!   domain    -> (none)                      (+ 层内 super:: 自引用 x1,合法)
//!   memento   -> (none)
//!   support   -> (none)
//! ```
//!
//! ⚠️★ 这张图里有两处**与直觉不符**,而它们都是实测出来的,不是笔误:
//!
//! 1. `domain` 与 `support` **之间没有边**:本工程的领域层不需要任何基础工具
//!    (金额是整数分、比率是整数万分点,指纹由领域层自己拼)。
//!    `support` 目前只被 `app` 与 `main` 用到------它是「排版与显示」的基础层,
//!    不是「什么都往里塞」的工具箱。
//! 2. `main` 是唯一同时认识六层的地方,这正是**装配层**的定义;
//!    其余每一层都只往下看一层或两层。
//!
//! ## ★★ 本工程最关键的一条分层决策:`domain` 与 `memento` **互不认识**
//!
//! 直觉上「可回滚的东西」(`SalesOrder`)就该实现机制层的 `Originator` trait。
//! 那样会形成 `domain -> memento` 依赖,而真正的代价是:
//! **领域层会知道自己正在被回滚**------于是「换一种历史管理方式(例如改成数据库归档)」
//! 就要改业务代码,而「换历史管理方式」与「珠宝生意」毫无关系。
//!
//! 因此本工程的做法是:
//! - `domain` 只提供两个与机制无关的动作:`capture()`(拍快照)与 `apply()`(装回,带拒绝);
//! - `client::QuotationOriginator` 把这两个动作**适配**成机制层的 `Originator` trait;
//! - `impl Memento for QuotationMemento` 也写在 `client`------那一行 `impl` 就是接缝。
//!
//! 这条判据与迭代器工程「领域不知道自己在被遍历」是同一条。
//! 它的证据可实测:`domain` 的依赖图里没有 `memento`,反之亦然,
//! 两者都只出现在 `client` 的依赖图里。
//!
//! ## DDD 战术角色在本工程的落点
//!
//! | 战术角色 | 本工程类型 |
//! |---|---|
//! | 聚合根 | `domain::SalesOrder` |
//! | 聚合内实体 | `domain::OrderLine` |
//! | 值对象 | `Money` / `StoreCode` / `CategoryCode` / `CurrencyCode` / `ApprovalLevel` / `RollbackCheck` |
//! | 领域服务 | `domain::QuotationPolicy`(权限表 + 六关顺序校验 + 裁决并生效) |
//! | 仓储(接口) | `domain::SalesOrderRepository`(实现在 `client`) |
//! | Memento(快照) | `domain::QuotationMemento` |
//! | Originator(适配器) | `client::QuotationOriginator` |
//! | Caretaker(管理者) | `memento::History` + `client::RollbackSession` |
//!
//! ## 运行
//!
//! ```text
//! cargo run
//! ```
//!
//! 输出十四幕报表;两次运行逐字节一致(遍历一律收成 `Vec`,不用 `HashMap`)。

mod analysis;
mod app;
mod client;
mod domain;
mod memento;
mod support;

use crate::analysis::AuditFalsifiableRow;
use crate::analysis::CheckLine;
use crate::analysis::CheckReport;
use crate::analysis::ExtensionRow;
use crate::analysis::InterfaceRow;
use crate::analysis::RejectionProbeRow;
use crate::analysis::RollbackStepRow;
use crate::analysis::audit_falsifiable_lines;
use crate::analysis::audit_falsifiable_rows;
use crate::analysis::audit_findings_to_check_lines;
use crate::analysis::audit_tally;
use crate::analysis::build_consistency_rows;
use crate::analysis::build_encapsulation_rows;
use crate::analysis::build_history_timeline_rows;
use crate::analysis::build_ledger_rows;
use crate::analysis::build_reprice_flow_rows;
use crate::analysis::build_simulation_rows;
use crate::analysis::capture_rollback_step;
use crate::analysis::check_ledger_expectations;
use crate::analysis::compute_rollback_statistics;
use crate::analysis::encapsulation_cost_bytes;
use crate::analysis::is_experiment_demonstrated;
use crate::analysis::summarize_consistency;
use crate::analysis::summarize_extension_rows;
use crate::analysis::summarize_history_timeline;
use crate::analysis::summarize_interface_rows;
use crate::analysis::summarize_rejection_probes;
use crate::analysis::summarize_reprice_flow;
use crate::analysis::summarize_rollback_steps;
use crate::analysis::summarize_simulation;
use crate::analysis::verdict_text;

use crate::app::ColumnAlign;
use crate::app::DOCUMENT_WIDTH;
use crate::app::Table;
use crate::app::TableColumn;
use crate::app::basis_points_text;
use crate::app::bool_text;
use crate::app::byte_text;
use crate::app::failed_items_text;
use crate::app::gram_display_text;
use crate::app::health_verdict_text;
use crate::app::items_of;
use crate::app::note_lines;
use crate::app::percent_text;
use crate::app::render_authority_scene;
use crate::app::render_cell;
use crate::app::render_consistency_scene;
use crate::app::render_encapsulation_scene;
use crate::app::render_extension_scene;
use crate::app::render_falsifiable_scene;
use crate::app::render_health_check_scene;
use crate::app::render_interface_scene;
use crate::app::render_ledger_scene;
use crate::app::render_mechanism_audit_scene;
use crate::app::render_mechanism_falsifiable_scene;
use crate::app::render_order_line_scene;
use crate::app::render_order_scene;
use crate::app::render_rejection_scene;
use crate::app::render_reprice_flow_scene;
use crate::app::render_rollback_step_scene;
use crate::app::render_simulation_scene;
use crate::app::render_timeline_scene;
use crate::app::section_header;
use crate::app::signed_gram_display_text;
use crate::app::table_rule;

use crate::client::BUILTIN_ACTOR_LEVELS;
use crate::client::BUILTIN_DISCOUNT_AUTHORITIES;
use crate::client::DEMO_CATEGORIES;
use crate::client::DEMO_CURRENCIES;
use crate::client::DEMO_STORES;
use crate::client::InMemorySalesOrderRepository;
use crate::client::QuotationOriginator;
use crate::client::RepriceLog;
use crate::client::RepriceLogEntry;
use crate::client::RepriceSimulationEntry;
use crate::client::RepriceUseCase;
use crate::client::RollbackSession;
use crate::client::WideQuotationMemento;
use crate::client::builtin_quotation_policy;
use crate::client::demo_orders;
use crate::client::order_cn_first;
use crate::client::order_cn_second;
use crate::client::order_hk_first;
use crate::client::run_wide_memento_experiment;
use crate::client::same_currency_batch;

use crate::domain::ApprovalLevel;
use crate::domain::BUILTIN_APPROVAL_LEVELS;
use crate::domain::BUILTIN_CATEGORY_CODES;
use crate::domain::BUILTIN_CURRENCY_CODES;
use crate::domain::BUILTIN_STORE_CODES;
use crate::domain::CNY;
use crate::domain::CategoryCode;
use crate::domain::CurrencyCode;
use crate::domain::DiscountAuthority;
use crate::domain::HKD;
use crate::domain::LEVEL_CLERK;
use crate::domain::LEVEL_MANAGER;
use crate::domain::LEVEL_REGIONAL;
use crate::domain::Money;
use crate::domain::OrderLine;
use crate::domain::QuotationMemento;
use crate::domain::QuotationPolicy;
use crate::domain::QuotationRejection;
use crate::domain::REJECTION_AUTHORITY_EXCEEDED;
use crate::domain::REJECTION_DISCOUNT_NEGATIVE;
use crate::domain::REJECTION_DISCOUNT_OVER_FULL;
use crate::domain::REJECTION_NO_AUTHORITY_RECORD;
use crate::domain::REJECTION_ORDER_SEALED;
use crate::domain::RepriceRequest;
use crate::domain::RepriceVerdict;
use crate::domain::RollbackCheck;
use crate::domain::SalesOrder;
use crate::domain::SalesOrderRepository;
use crate::domain::StoreCode;
use crate::domain::USD;
use crate::domain::divide_rounded;
use crate::domain::ratio_basis_points;
use crate::domain::scale_rounded;

use crate::memento::FaithlessOriginator;
use crate::memento::History;
use crate::memento::HistoryLedger;
use crate::memento::LedgerSnapshot;
use crate::memento::Memento;
use crate::memento::Originator;
use crate::memento::ProbeMemento;
use crate::memento::ProbeOriginator;
use crate::memento::RefusingOriginator;
use crate::memento::RestoreOutcome;
use crate::memento::run_audit;

use crate::support::deterministic_code;
use crate::support::display_width;
use crate::support::elide_text;
use crate::support::horizontal_rule;
use crate::support::is_wide_character;
use crate::support::pad_center;
use crate::support::prefixed_code;
use crate::support::self_check_width_model;
use crate::support::stable_hash;
use crate::support::truncate_to_width;

// ===========================================================================
// 工程外扩展区(**本文件顶部这一块就是「扩展」本身**)
//
// ★ 可扩展性的可执行定义(三条缺一都不算):
//   ① 新增的东西写在 `main.rs` 的扩展区,**没有改动任何既有分层文件**;
//   ② 它**挂进了核心结构**(同一套策略 / 同一条历史 / 同一份流水 / 同一个仓储);
//   ③ 它**自动进了统计与报表**(不是另起一张小表自己印)。
//
// 本区声明的常量与函数,全部只用领域层**已经开放**的构造能力:
// `ApprovalLevel::new` / `StoreCode::new` / `CategoryCode::new` / `DiscountAuthority::new`
// ------它们都是 `const fn`(开放型),因此新增一级审批、一家门店、一个品类
// **都不需要回到 `domain` 目录下改任何文件**。
// ===========================================================================

/// ★ 扩展区新增的审批级别:**总部特批**(权限秩 4,高于区域总监)。
///
/// ⚠️ 它是开放型结构体常量(`ApprovalLevel::new` 是 `const fn`),
/// 所以新增这一级**没有改动** `domain/approval_level.rs`。
/// 若 `ApprovalLevel` 做成 `enum`,这一步就必须回去改领域层文件------
/// 那正是「不可扩展」的定义。
pub const LEVEL_HEADQUARTERS_EXTENDED: ApprovalLevel =
    ApprovalLevel::new("HEADQUARTERS", "总部特批", 4);

/// ★ 扩展区自带的一家门店:**深圳福田店**。
///
/// 与 [`LEVEL_HEADQUARTERS_EXTENDED`] 同理:`StoreCode::new` 是 `const fn`。
pub const STORE_CN_02_EXTENDED: StoreCode = StoreCode::new("STORE-CN-02", "深圳福田店");

/// ★ 扩展区自带的一个品类:**珍珠饰品**(按件计价,无金属成本)。
pub const CATEGORY_PEARL_EXTENDED: CategoryCode =
    CategoryCode::new("PEARL", "珍珠饰品", false);

/// ★ 扩展区自带的一张**分公司权限表**(四档,额度与内建表不同)。
///
/// ⚠️ 这张表存在的意义是实证一件事:
/// **「谁能批几折」是装配出来的,不是写死在领域层的。**
/// 同一批单、同一个申请人、同一个目标折扣,只换这一张表,
/// 裁决就会从「全部被拒」变成「全部同意」(见幕十一)。
pub const BRANCH_DISCOUNT_AUTHORITIES: [DiscountAuthority; 4] = [
    DiscountAuthority::new(LEVEL_CLERK, 300),
    DiscountAuthority::new(LEVEL_MANAGER, 1_000),
    DiscountAuthority::new(LEVEL_REGIONAL, 2_500),
    DiscountAuthority::new(LEVEL_HEADQUARTERS_EXTENDED, 4_000),
];

/// ★ 扩展区自带的一条**业务原因编码**(会员日折让)。
///
/// ⚠️ 原因编码是 `&'static str` 而不是枚举,理由与「被拒理由编码」同一条:
/// **扩展方要能自带理由**。做成枚举则新增一个业务原因就要回去改领域层文件。
pub const REASON_MEMBER_DAY: &str = "MEMBER_DAY";

/// ★ 扩展区自带的一张销售单(**深圳福田店 · 珍珠**)。
///
/// 它会被加进试算批次与仓储,于是「扩展的单」与既有的单
/// 走的是**同一套** `RepriceUseCase` / `InMemorySalesOrderRepository`,
/// 并自动出现在幕十一与幕十三的报表里。
pub fn extended_order() -> SalesOrder {
    SalesOrder::new(
        "SO-2025-0004",
        STORE_CN_02_EXTENDED,
        CNY,
        vec![
            OrderLine::new(1, CATEGORY_PEARL_EXTENDED, 2, 3_330, Money::new(555_500, CNY)),
            OrderLine::new(2, CATEGORY_PEARL_EXTENDED, 1, 1_110, Money::new(333_300, CNY)),
        ],
    )
}

/// ★ 输出一幕(表格内容由 `app` 层产生,本函数只负责按行打印与幕间空行)。
///
/// # 参数
/// - `lines`:一幕的全部输出行。
fn emit_scene(lines: &[String]) {
    for line in lines.iter() {
        println!("{}", line);
    }
    println!();
}

/// ★ 把装回结果转成中文(**没有发生装回**时为「未发生」)。
///
/// # 参数
/// - `outcome`:装回结果(`None` 表示这一步根本没有发生装回)。
///
/// ⚠️ 为什么单独一个函数:幕七的八个场景都要把结果转成文本,
/// 散着写 `match` 迟早有一处把「被拒」写成「失败」,而那是**另一种判断**。
fn outcome_text_of(outcome: Option<&RestoreOutcome>) -> &'static str {
    match outcome {
        Some(result) => result.chinese_text(),
        None => "未发生",
    }
}

fn main() {
    // =======================================================================
    // 装配:**政策与数据都在这一层拼好**,领域层不认识任何具体级别 / 门店 / 品类
    // =======================================================================
    let policy: QuotationPolicy = builtin_quotation_policy();
    let branch_policy: QuotationPolicy = QuotationPolicy::new(BRANCH_DISCOUNT_AUTHORITIES.to_vec());
    let archive_orders: Vec<SalesOrder> = demo_orders();

    // =======================================================================
    // 幕一 / 幕一(续)/ 幕二:档案与权限表
    // =======================================================================
    emit_scene(&render_order_scene(&archive_orders));
    emit_scene(&render_order_line_scene(&archive_orders));
    emit_scene(&render_authority_scene(&BUILTIN_DISCOUNT_AUTHORITIES));

    // =======================================================================
    // 主会话:SO-2025-0001
    //
    // ⚠️ 会话里这一张单是 `order_cn_first()` **新建的一份**,
    //    与幕一档案里那张同号的单是两个对象(档案幕拍在改价之前)。
    //    报表上「同号不同状态」正是这个原因,不是口径不一致。
    // =======================================================================
    let mut session: RollbackSession = RollbackSession::new(order_cn_first(), policy.clone());
    // ★ 台账的「早期切片」:开会话后立刻取,用于证明「只增不减」。
    let ledger_early: LedgerSnapshot = session.ledger_snapshot();

    // ---- 幕三:改价申请序列(**刻意覆盖三态与全部拒绝理由**)----
    // ⚠️ 顺序不是随便排的:前两条是正常业务,后面每一条各打一种拒绝,
    //    最后一条再回到正常业务------这样「被拒夹在中间」也能被验证
    //    (被拒之后继续申请必须仍然正常,而不是把单卡死)。
    let reprice_requests: [RepriceRequest; 8] = [
        RepriceRequest::new(LEVEL_CLERK, 500, REASON_MEMBER_DAY),
        RepriceRequest::new(LEVEL_MANAGER, 1_200, "瑕疵折让"),
        RepriceRequest::new(LEVEL_CLERK, 2_000, "清货"),
        RepriceRequest::new(LEVEL_MANAGER, 1_200, "重复提交"),
        RepriceRequest::new(LEVEL_CLERK, -100, "录入错误"),
        RepriceRequest::new(LEVEL_REGIONAL, 12_000, "录入错误"),
        RepriceRequest::new(LEVEL_HEADQUARTERS_EXTENDED, 3_500, "总部特批"),
        RepriceRequest::new(LEVEL_REGIONAL, 2_600, "团购"),
    ];
    let mut reprice_verdicts: Vec<RepriceVerdict> = Vec::new();
    for request in reprice_requests.iter() {
        reprice_verdicts.push(session.reprice(request));
    }

    let flow_rows: Vec<crate::analysis::RepriceFlowRow> = build_reprice_flow_rows(session.log());
    let flow_summary: crate::analysis::RepriceFlowSummary = summarize_reprice_flow(session.log());
    emit_scene(&render_reprice_flow_scene(&flow_rows, &flow_summary));

    // =======================================================================
    // 幕四:报价历史时间线
    //
    // ★ 这一幕**列不出**每一版打了几折------那正是封装。
    //   「该版折扣」由流水按版本号关联得出,快照的窄接口里没有折扣。
    // =======================================================================
    let timeline_rows: Vec<crate::analysis::HistoryTimelineRow> =
        build_history_timeline_rows(session.history(), session.log());
    let timeline_summary: crate::analysis::HistoryTimelineSummary =
        summarize_history_timeline(session.history(), session.log());
    emit_scene(&render_timeline_scene(&timeline_rows, &timeline_summary));

    // =======================================================================
    // 幕五:撤销 / 重做 / 跳版实测(**每一步一行,当场抓**)
    //
    // ⚠️ 每一步的 outcome 由动作本身返回,绝不为了展示再补做一次:
    //    「把退 3 次变成退 4 次」会让这一行的动作名与数字对不上。
    // =======================================================================
    let mut step_rows: Vec<RollbackStepRow> = Vec::new();
    let mut step_index: u32 = 0;

    // 步 1:撤销一步(第 4 版 → 第 3 版)
    step_index += 1;
    let outcome: Option<RestoreOutcome> = session.undo();
    step_rows.push(capture_rollback_step(step_index, "撤销一步", outcome.as_ref(), &session));

    // 步 2:再撤销一步(第 3 版 → 第 2 版)
    step_index += 1;
    let outcome: Option<RestoreOutcome> = session.undo();
    step_rows.push(capture_rollback_step(step_index, "撤销一步", outcome.as_ref(), &session));

    // 步 3:重做一步(第 2 版 → 第 3 版)
    step_index += 1;
    let outcome: Option<RestoreOutcome> = session.redo();
    step_rows.push(capture_rollback_step(step_index, "重做一步", outcome.as_ref(), &session));

    // 步 4:跳到第 1 版(**一口气回到最初报价**)
    step_index += 1;
    let outcome: Option<RestoreOutcome> = session.jump_to(1);
    step_rows.push(capture_rollback_step(
        step_index,
        "跳到第 1 版",
        outcome.as_ref(),
        &session,
    ));

    // 步 5:已在第 1 版还要撤销 ------ 应「未发生」而不是报错
    step_index += 1;
    let outcome: Option<RestoreOutcome> = session.undo();
    step_rows.push(capture_rollback_step(
        step_index,
        "撤销一步(已退到底)",
        outcome.as_ref(),
        &session,
    ));

    // 步 6:重做一步(第 1 版 → 第 2 版)
    step_index += 1;
    let outcome: Option<RestoreOutcome> = session.redo();
    step_rows.push(capture_rollback_step(step_index, "重做一步", outcome.as_ref(), &session));

    // 步 7:跳到第 4 版
    step_index += 1;
    let outcome: Option<RestoreOutcome> = session.jump_to(4);
    step_rows.push(capture_rollback_step(
        step_index,
        "跳到第 4 版",
        outcome.as_ref(),
        &session,
    ));

    // 步 8:跳到一个**不存在**的版本 ------ 不应改动游标、不应计数
    step_index += 1;
    let cursor_before_missing_jump: Option<usize> = session.history().cursor_index();
    let outcome: Option<RestoreOutcome> = session.jump_to(99);
    let cursor_after_missing_jump: Option<usize> = session.history().cursor_index();
    step_rows.push(capture_rollback_step(
        step_index,
        "跳到第 99 版(不存在)",
        outcome.as_ref(),
        &session,
    ));

    // 步 9:已在最后一版还要重做 ------ 应「未发生」
    step_index += 1;
    let outcome: Option<RestoreOutcome> = session.redo();
    step_rows.push(capture_rollback_step(
        step_index,
        "重做一步(已进到顶)",
        outcome.as_ref(),
        &session,
    ));

    let step_summary: crate::analysis::RollbackStepSummary = summarize_rollback_steps(&step_rows);
    emit_scene(&render_rollback_step_scene(&step_rows, &step_summary));

    // =======================================================================
    // 幕六:装回自洽性核对(**两条路径互盯**)
    //
    // ★ 游标那一版必须 0 处;**其余各版必须 > 0 处**------
    //   少了后面这一半,这条检查就是恒真的(把比对删掉也照样全绿)。
    // =======================================================================
    let consistency_rows: Vec<crate::analysis::ConsistencyRow> =
        build_consistency_rows(&session, session.log());
    let consistency_summary: crate::analysis::ConsistencySummary =
        summarize_consistency(&consistency_rows);
    emit_scene(&render_consistency_scene(&consistency_rows, &consistency_summary));

    // ★ 封存之前先把「版数恒等式」取下来:封存也会记一版,
    //   因此这条恒等式只在封存前成立(见 `RollbackSession::is_version_count_consistent`)。
    let version_consistent_before_seal: bool = session.is_version_count_consistent();
    let version_total_before_seal: usize = session.history().len();
    let allowed_total_before_seal: usize = session.log().allowed_total();

    // =======================================================================
    // 幕七:拒绝实证(**每条都说得出触发它的输入**)
    //
    // ⚠️ 被拒是系统**正常工作**的证据,不是失败。
    //    一个从不拒绝的审批系统,要么没人申请,要么形同虚设。
    // =======================================================================

    // 场景 1:封存之后还想回滚 ------ 领域层拒绝(单已开票)
    session.seal();
    let sealed_undo: Option<RestoreOutcome> = session.undo();
    let sealed_undo_refused: bool = sealed_undo
        .as_ref()
        .map(RestoreOutcome::is_refused)
        .unwrap_or(false);

    // 场景 2:把**另一张单**的快照喂进来 ------ 领域层拒绝
    let mut foreign_session: RollbackSession =
        RollbackSession::new(order_cn_second(), policy.clone());
    let borrowed_snapshot: QuotationMemento = session.history().entries()[0].clone();
    let foreign_result: Result<RollbackCheck, QuotationRejection> =
        foreign_session.apply_foreign(borrowed_snapshot);

    // 场景 3:封存之后还想改价 ------ 裁决为「被拒」
    let sealed_reprice: RepriceVerdict =
        session.reprice(&RepriceRequest::new(LEVEL_MANAGER, 800, "开票后申请"));
    let sealed_reprice_refused: bool = sealed_reprice.is_denied();

    // 场景 4:店员申请超出自己的权限
    let exceeded_verdict: RepriceVerdict =
        foreign_session.reprice(&RepriceRequest::new(LEVEL_CLERK, 2_000, "清货"));

    // 场景 5:权限表里**根本没有**这个级别(扩展区新增的那一级,内建表没配)
    let no_record_verdict: RepriceVerdict = foreign_session.reprice(&RepriceRequest::new(
        LEVEL_HEADQUARTERS_EXTENDED,
        3_500,
        REASON_MEMBER_DAY,
    ));

    // 场景 6:折扣录入成负数
    let negative_verdict: RepriceVerdict =
        foreign_session.reprice(&RepriceRequest::new(LEVEL_CLERK, -100, "录入错误"));

    // 场景 7:折扣超过 100%(白送还倒贴)
    let over_full_verdict: RepriceVerdict =
        foreign_session.reprice(&RepriceRequest::new(LEVEL_REGIONAL, 12_000, "录入错误"));

    // 场景 8:目标与当前相同 ------ 是「无变化」,**不是**被拒
    let unchanged_verdict: RepriceVerdict =
        foreign_session.reprice(&RepriceRequest::new(LEVEL_CLERK, 0, "重复提交"));

    let mut rejection_rows: Vec<RejectionProbeRow> = Vec::new();
    rejection_rows.push(RejectionProbeRow::new(
        "已封存的单还想回滚",
        outcome_text_of(sealed_undo.as_ref()),
        sealed_undo
            .as_ref()
            .and_then(RestoreOutcome::rejection_code)
            .unwrap_or("---"),
        QuotationRejection::OrderSealed.known_failing_input_text(),
    ));
    rejection_rows.push(RejectionProbeRow::new(
        "把另一张单的快照装回来",
        match &foreign_result {
            Ok(_) => "已装回",
            Err(_) => "被拒",
        },
        match &foreign_result {
            Ok(_) => "---",
            Err(rejection) => rejection.code(),
        },
        QuotationRejection::ForeignSnapshot.known_failing_input_text(),
    ));
    rejection_rows.push(RejectionProbeRow::new(
        "已封存的单还想改价",
        sealed_reprice.chinese_text(),
        sealed_reprice.rejection_code().unwrap_or("---"),
        "对一张已封存(已开票)的单提交改价申请:任何折扣都批不过",
    ));
    rejection_rows.push(RejectionProbeRow::new(
        "店员申请超出自己权限的折扣",
        exceeded_verdict.chinese_text(),
        exceeded_verdict.rejection_code().unwrap_or("---"),
        "店员(权限 500 万分点)申请 2000 万分点:超出 1500 万分点",
    ));
    rejection_rows.push(RejectionProbeRow::new(
        "权限表里没有这一级(扩展区新级别)",
        no_record_verdict.chinese_text(),
        no_record_verdict.rejection_code().unwrap_or("---"),
        "用 `ApprovalLevel::new` 新增一级却**不给它配权限**:报「没配」而不是「权限 0」",
    ));
    rejection_rows.push(RejectionProbeRow::new(
        "折扣录入成负数",
        negative_verdict.chinese_text(),
        negative_verdict.rejection_code().unwrap_or("---"),
        "目标折扣填 -100 万分点:只能是 0..10000",
    ));
    rejection_rows.push(RejectionProbeRow::new(
        "折扣超过 100%",
        over_full_verdict.chinese_text(),
        over_full_verdict.rejection_code().unwrap_or("---"),
        "目标折扣填 12000 万分点:白送还倒贴",
    ));
    rejection_rows.push(RejectionProbeRow::new(
        "目标折扣与当前折扣相同",
        unchanged_verdict.chinese_text(),
        unchanged_verdict.rejection_code().unwrap_or("---"),
        "★ 这一条**不是**拒绝:它既不算同意也不算被拒,单列一态",
    ));
    emit_scene(&render_rejection_scene(&rejection_rows));
    let rejection_tally: (usize, usize) = summarize_rejection_probes(&rejection_rows);

    // =======================================================================
    // 幕八:台账切片(**只增不减**)
    //
    // ⚠️ 切片与「当前版数」必须在**同一刻**取:
    //    先取切片再继续跑,峰值就会大于当前版数,而那个差会被误读成「峰值算错了」。
    // =======================================================================
    let ledger_later: LedgerSnapshot = session.ledger_snapshot();
    let entries_at_snapshot: usize = session.history().len();
    let ledger_rows: Vec<crate::analysis::LedgerRow> = build_ledger_rows(&ledger_later);
    let ledger_expectations: crate::analysis::LedgerExpectations =
        check_ledger_expectations(&ledger_later, entries_at_snapshot);
    emit_scene(&render_ledger_scene(
        &ledger_rows,
        &ledger_expectations,
        entries_at_snapshot,
    ));

    // =======================================================================
    // 幕九:封装对照(宽接口反例 vs 窄接口)
    // =======================================================================
    let wide_experiment: crate::client::WideMementoExperiment =
        run_wide_memento_experiment(&order_cn_second(), 3, 100);
    // ★ 宽接口那一份:外部**自己**也能拍一份出来(窄接口下这一步编译不过)。
    //   它存在的唯一理由是「把代价量出来」:若宽接口并没有多存东西,
    //   那么「为了省内存而放宽可见性」这个理由就不成立。
    let wide_alone: WideQuotationMemento = WideQuotationMemento::capture_from(&order_cn_second());
    let wide_alone_bytes: usize = wide_alone.byte_footprint();
    let encapsulation_rows: Vec<crate::analysis::EncapsulationRow> =
        build_encapsulation_rows(&wide_experiment);
    let encapsulation_cost: i64 = encapsulation_cost_bytes(&wide_experiment);
    let encapsulation_demonstrated: bool = is_experiment_demonstrated(&wide_experiment);
    emit_scene(&render_encapsulation_scene(
        &encapsulation_rows,
        encapsulation_cost,
        encapsulation_demonstrated,
    ));

    // =======================================================================
    // 幕十 / 幕十(续):机制层自检(**零业务的探针**)
    // =======================================================================
    let audit_findings: Vec<crate::memento::AuditFinding> = run_audit();
    let audit_lines: Vec<CheckLine> = audit_findings_to_check_lines(&audit_findings);
    let audit_count: (usize, usize, usize) = audit_tally(&audit_findings);
    // ★ 机制层的结论在**分析层**转成视图行之后才交给表示层:
    //   表示层直接拿 `AuditFinding` 会形成实测可见的 `app -> memento` 依赖。
    let audit_falsifiable_rows: Vec<AuditFalsifiableRow> =
        audit_falsifiable_rows(&audit_findings);
    emit_scene(&render_mechanism_audit_scene(&audit_lines));
    emit_scene(&render_mechanism_falsifiable_scene(&audit_falsifiable_rows));

    // =======================================================================
    // 幕十一:改价试算(**只读,一张单都不改**)
    //
    // ★ 三次试算用**同一批单**、**同一套用例**,只换申请人 / 权限表:
    //   ① 内建表 + 总部特批 3500 → 表里没这一级 → 全部被拒(折让 0)
    //   ② 扩展区表 + 同一申请      → 总部特批权限 4000 → 全部同意
    //   ③ 内建表 + 店长 1500       → 正好等于权限上限 → 全部同意
    //   ①② 的差别**只**来自装配的那张表------这就是「政策是装配出来的」的实证。
    // =======================================================================
    let mut simulation_batch: Vec<SalesOrder> = same_currency_batch();
    simulation_batch.push(extended_order());
    let use_case: RepriceUseCase = RepriceUseCase::new(&policy);
    let branch_use_case: RepriceUseCase = RepriceUseCase::new(&branch_policy);

    let headquarters_request: RepriceRequest =
        RepriceRequest::new(LEVEL_HEADQUARTERS_EXTENDED, 3_500, REASON_MEMBER_DAY);
    let manager_request: RepriceRequest =
        RepriceRequest::new(LEVEL_MANAGER, 1_500, REASON_MEMBER_DAY);

    let simulation_builtin: crate::client::RepriceSimulation =
        use_case.simulate(&simulation_batch, &headquarters_request);
    let simulation_branch: crate::client::RepriceSimulation =
        branch_use_case.simulate(&simulation_batch, &headquarters_request);
    let simulation_manager: crate::client::RepriceSimulation =
        use_case.simulate(&simulation_batch, &manager_request);

    for (title, simulation, scene_text) in [
        (
            "幕十一 · 改价试算(一):内建权限表 · 总部特批申请 3500 万分点",
            &simulation_builtin,
            "内建权限表里**没有**「总部特批」这一级(扩展区新增的级别还没装配进这张表),于是三张单全部被拒,折让 0 分。",
        ),
        (
            "幕十一 · 改价试算(二):扩展区权限表 · 同一申请",
            &simulation_branch,
            "★ 同一批单、同一个申请人、同一个目标折扣,只换了一张**装配出来的**权限表(总部特批权限 4000 万分点),裁决就从「全部被拒」变成「全部同意」。",
        ),
        (
            "幕十一 · 改价试算(三):内建权限表 · 店长申请 1500 万分点",
            &simulation_manager,
            "常规议价:1500 万分点正好等于店长的权限上限,「不超过」是成立的(判越权用 `>` 而不是 `>=`)。",
        ),
    ] {
        let rows: Vec<crate::analysis::SimulationRow> = build_simulation_rows(simulation);
        let summary: crate::analysis::SimulationSummary = summarize_simulation(simulation);
        emit_scene(&render_simulation_scene(title, &rows, &summary, scene_text));
    }

    // ★ 幕十一(四):专挑一个**除不尽的**折扣。
    //
    // ⚠️ 上面三次试算的折扣(3500 / 1500)配上本工程的行挂牌额,乘出来的积
    //    全部能被 10000 整除 ------ 两种舍入口径给出同一个答案,读报表的人
    //    **看不出「统一舍入口径」存在过**。这一幕让它真正被用上一次。
    let probe_request: RepriceRequest =
        RepriceRequest::new(LEVEL_MANAGER, PROBE_DISCOUNT_BPS, "会员日折让");
    let simulation_probe: crate::client::RepriceSimulation =
        use_case.simulate(&simulation_batch, &probe_request);
    let probe_rows: Vec<crate::analysis::SimulationRow> = build_simulation_rows(&simulation_probe);
    let probe_summary: crate::analysis::SimulationSummary =
        summarize_simulation(&simulation_probe);
    emit_scene(&render_simulation_scene(
        &format!(
            "幕十一 · 改价试算(四):内建权限表 · 店长申请 {} 万分点(**一个除不尽的折扣**)",
            PROBE_DISCOUNT_BPS
        ),
        &probe_rows,
        &probe_summary,
        &probe_scene_text(&simulation_batch, PROBE_DISCOUNT_BPS),
    ));

    // =======================================================================
    // 幕十二:工程外扩展区实证
    //
    // ★ 下面每一行都是**真的跑过**的:扩展的内容挂进了同一套策略 / 历史 / 流水 / 仓储,
    //   并且自动出现在幕三、幕七、幕十一、幕十三的报表里。
    // =======================================================================
    let mut branch_session: RollbackSession =
        RollbackSession::new(order_cn_second(), branch_policy.clone());
    let branch_verdict: RepriceVerdict = branch_session.reprice(&RepriceRequest::new(
        LEVEL_HEADQUARTERS_EXTENDED,
        3_500,
        REASON_MEMBER_DAY,
    ));
    let branch_undo: Option<RestoreOutcome> = branch_session.undo();

    let mut repository: InMemorySalesOrderRepository =
        InMemorySalesOrderRepository::new_with(demo_orders());
    repository.add(extended_order());

    // ★ 顺手把「申请人级别」也数一遍:用 `actor_level_code()` 而不是**顺序**------
    //   流水里一次申请一条(**被拒也算**),级别编码是唯一稳定的键。
    //   排序去重之后再拼串,两次运行才逐字节一致。
    let mut member_day_total: usize = 0;
    let mut actor_level_codes: Vec<&'static str> = Vec::new();
    for log_entry in session.log().entries().iter() {
        let entry: &RepriceLogEntry = log_entry;
        actor_level_codes.push(entry.actor_level_code());
        if entry.reason_code() == REASON_MEMBER_DAY {
            member_day_total += 1;
        }
    }
    actor_level_codes.sort_unstable();
    actor_level_codes.dedup();
    let actor_level_codes_text: String = actor_level_codes.join(" / ");

    let mut extension_rows: Vec<ExtensionRow> = Vec::new();
    extension_rows.push(ExtensionRow::new(
        "新增审批级别「总部特批」",
        "`ApprovalLevel::new`(const fn,开放型)声明一个常量",
        &format!(
            "内建表下申请 3500 → {}({});扩展表下同一申请 → {}(版数 {})",
            no_record_verdict.rejection_code().unwrap_or("---"),
            no_record_verdict.chinese_text(),
            branch_verdict.chinese_text(),
            branch_session.history().len()
        ),
        "否",
    ));
    extension_rows.push(ExtensionRow::new(
        "自带一张分公司权限表",
        "`QuotationPolicy::new(权限表)` 装配另一份策略,交给**同一个** `RepriceUseCase`",
        &format!(
            "同一申请:内建表同意 {} 张 → 扩展表同意 {} 张(折让 {} 分)",
            simulation_builtin.allowed_total(),
            simulation_branch.allowed_total(),
            simulation_branch.discount_amount_minor_units()
        ),
        "否",
    ));
    extension_rows.push(ExtensionRow::new(
        "自带门店/品类(福田店/珍珠)",
        "`StoreCode::new` / `CategoryCode::new` 声明常量,装配一张新单",
        &format!(
            "新单 {} 进试算批次(批次 {} 张)与仓储,自动出现在幕十一 / 幕十三",
            extended_order().order_number(),
            simulation_batch.len()
        ),
        "否",
    ));
    extension_rows.push(ExtensionRow::new(
        "自带业务原因编码「会员日折让」",
        "原因编码是 `&'static str`:扩展方自带常量即可,不必回领域层改枚举",
        &format!(
            "编码 `{}` 出现在幕三流水的原因列(本轮 {} 条申请用了它)",
            REASON_MEMBER_DAY, member_day_total
        ),
        "否",
    ));
    extension_rows.push(ExtensionRow::new(
        "用扩展权限表跑一次完整回滚会话",
        "同一个 `RollbackSession` / 同一条 `History`,只换了策略",
        &format!(
            "同意 {} 次(版数 {}),撤销一步 → {},机制层未改一行",
            branch_session.log().allowed_total(),
            branch_session.history().len(),
            outcome_text_of(branch_undo.as_ref())
        ),
        "否",
    ));
    emit_scene(&render_extension_scene(
        &extension_rows,
        "★ 全部扩展都写在 `main.rs` 的扩展区:`domain` / `memento` / `analysis` / `app` 四层**没有改任何一个文件**。",
    ));
    let extension_tally: (usize, usize) = summarize_extension_rows(&extension_rows);

    // =======================================================================
    // 体检数据准备(**session 还活着**:所有计数必须在演练跑完之后取)
    // =======================================================================
    let statistics: crate::analysis::RollbackStatistics = compute_rollback_statistics(&session);
    // ★ 全程(**含封存那一版**)的版数恒等式要在 session 交回仓储**之前**取下来:
    //   交回之后 `log` 与 `history` 都读不到了,而那个差在报表上会被误读成「漏记了一版」。
    let allowed_total_final: usize = session.log().allowed_total();
    // ★ 「整条历史的字节成本 == 各版之和」里的右边:逐版量一次。
    //   左边由 `History::total_byte_footprint` 给出,两边是**两条真正不同的路径**。
    let footprint_sum: usize = session
        .history()
        .entries()
        .iter()
        .map(|snapshot| snapshot.byte_footprint())
        .sum();

    // =======================================================================
    // 收尾:会话结束,聚合根交回仓储(**归档**)
    //
    // ⚠️ 这一步之后不再读 `session`:任何后续读取都会让
    //    「早期切片 vs 实时计数」差一个数,而报表上看不出原因。
    // =======================================================================
    repository.add(session.into_order());

    // ★ 通过**接口**而不是实现类型取数:仓储接口在领域层,
    //   扩展方自带一个实现(例如换成数据库)时,调用方这边一行都不用改。
    //
    // ⚠️ 这里顺带实证一件事:仓储给出的是**同一份**聚合根,不是副本------
    //   就地封存之后再用 `find_by_number` 读回来,状态是「已封存」。
    //   若仓储返回的是副本,这个封存会**安静地丢失**,而报表上看不出来。
    let sealed_through_repository: bool = match SalesOrderRepository::find_by_number_mut(
        &mut repository,
        extended_order().order_number(),
    ) {
        Some(order) => {
            order.seal();
            true
        }
        None => false,
    };
    let sealed_read_back: bool =
        SalesOrderRepository::find_by_number(&repository, extended_order().order_number())
            .map(SalesOrder::is_sealed)
            .unwrap_or(false);
    let repository_total: usize = SalesOrderRepository::count(&repository);

    // =======================================================================
    // 幕十三:只读接口清点(**真的逐个调用一遍**)
    //
    // ★ 这是告警治理的落点:一个从未被调用的 `pub fn` 会被编译器告警,
    //   而用 `#[allow(dead_code)]` 压掉会让它变成**没人验证过的代码**------
    //   它可能从来就是错的,只是没人跑过。
    // =======================================================================
    let interface_rows: Vec<InterfaceRow> =
        build_interface_rows(&repository, &ledger_early, &actor_level_codes_text, wide_alone_bytes);
    emit_scene(&render_interface_scene(&interface_rows));
    let interface_tally: (usize, usize) = summarize_interface_rows(&interface_rows);

    // =======================================================================
    // 幕十四:体检与可证伪性清单
    // =======================================================================
    // ★ 机制层自检的「结论文本」与「布尔」必须是**同一个判断的两种写法**:
    //   左边由 `AuditFinding::verdict_text` 给出,右边由 `analysis::verdict_text` 给出,
    //   两边互盯------改了一处忘了另一处,这一条立刻红。
    let audit_verdict_agreed: usize = audit_findings
        .iter()
        .filter(|finding| finding.verdict_text() == verdict_text(finding.passed()))
        .count();

    let mut report: CheckReport = CheckReport::new();
    push_reprice_checks(
        &mut report,
        &flow_summary,
        version_consistent_before_seal,
        version_total_before_seal,
        allowed_total_before_seal,
        &timeline_summary,
    );
    push_consistency_checks(
        &mut report,
        &consistency_summary,
        &statistics,
        &step_summary,
    );
    push_statistics_checks(&mut report, &statistics, allowed_total_final, footprint_sum);
    push_ledger_checks(&mut report, &ledger_expectations, &ledger_early, &ledger_later);
    push_mechanism_checks(
        &mut report,
        encapsulation_cost,
        encapsulation_demonstrated,
        audit_count,
        audit_verdict_agreed,
    );
    push_extension_checks(&mut report, extension_tally, interface_tally);
    push_arithmetic_checks(&mut report);
    push_simulation_checks(
        &mut report,
        &simulation_builtin,
        &simulation_branch,
        &simulation_manager,
    );
    push_domain_invariant_checks(
        &mut report,
        &simulation_batch,
        sealed_undo_refused,
        sealed_reprice_refused,
    );
    push_cursor_repository_checks(
        &mut report,
        rejection_tally,
        cursor_before_missing_jump,
        cursor_after_missing_jump,
        repository_total,
        simulation_batch.len(),
        sealed_through_repository,
        sealed_read_back,
    );
    emit_scene(&render_health_check_scene(&report));

    // 幕十四(续):可证伪性清单 = 本工程各条 + 机制层 M1..M13
    let mut falsifiable: Vec<(String, String)> = Vec::new();
    falsifiable.extend(local_falsifiable_lines());
    falsifiable.extend(audit_falsifiable_lines(&audit_findings));
    // ★ 两条清单必须一一对应:少了说明某条检查没有写清触发输入,
    //   多了说明有检查项没进体检表。这个断言本身就是「审计也要被审计」。
    assert!(
        falsifiable.len() == report.line_total() + audit_count.0,
        "可证伪性清单 {} 条 != 体检 {} 条 + 机制层 {} 条",
        falsifiable.len(),
        report.line_total(),
        audit_count.0
    );
    emit_scene(&render_falsifiable_scene(&falsifiable));

    // =======================================================================
    // 收尾一屏:体检结论(**全绿不代表检查有效,要看可证伪性那一屏**)
    // =======================================================================
    let mut tail: Vec<String> = Vec::new();
    tail.push(section_header("附 · 本次运行的结论", DOCUMENT_WIDTH));
    tail.push(table_rule(DOCUMENT_WIDTH));
    tail.extend(note_lines(
        &format!("体检:{}。", health_verdict_text(&report)),
        DOCUMENT_WIDTH,
    ));
    tail.extend(note_lines(
        &format!("未通过的检查项:{}。", failed_items_text(&report)),
        DOCUMENT_WIDTH,
    ));
    tail.extend(note_lines(
        &format!(
            "机制层自检:共 {} 条,通过 {} 条,未通过 {} 条(探针零业务:换任何业务都能跑)。",
            audit_count.0, audit_count.1, audit_count.2
        ),
        DOCUMENT_WIDTH,
    ));
    tail.extend(note_lines(
        &format!(
            "扩展区:{} 项扩展,其中纯新增(没改任何既有分层文件){} 项。",
            extension_tally.0, extension_tally.1
        ),
        DOCUMENT_WIDTH,
    ));
    tail.extend(note_lines(
        &format!(
            "接口清点:{} 个只读入口全部真的调用过,其中 {} 个返回了非空值。",
            interface_tally.0, interface_tally.1
        ),
        DOCUMENT_WIDTH,
    ));
    tail.extend(note_lines(
        "★ 全绿不等于检查有效:判断标准是「有没有已知会失败的输入」------见幕十四(续)逐条列出的触发输入。",
        DOCUMENT_WIDTH,
    ));
    tail.push(table_rule(DOCUMENT_WIDTH));
    emit_scene(&tail);
}

// ===========================================================================
// 幕十三 · 只读接口清点
// ===========================================================================

/// ★ 幕十三 · 只读接口清点:**真的把各层的只读入口逐个调用一遍**。
///
/// # 参数
/// - `repository`:装配好的仓储(用于清点仓储接口的真实返回值)。
/// - `ledger_early`:早期的台账切片(用于清点台账快照的只读接口)。
/// - `actor_level_codes_text`:流水里出现过的申请人级别编码(用 `actor_level_code()` 数出来的)。
/// - `wide_alone_bytes`:宽接口快照由**外部**自拍一份时的字节足迹。
///
/// ⚠️ 为什么这些调用写在 `main` 而不是 `analysis`:
/// 「调用一遍」正是**编排**的一部分------分析层只认视图,不认「这一次要用哪个实例」。
fn build_interface_rows(
    repository: &InMemorySalesOrderRepository,
    ledger_early: &LedgerSnapshot,
    actor_level_codes_text: &str,
    wide_alone_bytes: usize,
) -> Vec<InterfaceRow> {
    let mut rows: Vec<InterfaceRow> = Vec::new();

    // ---- support 层 ----
    let width_probes: Vec<(String, bool, String)> = self_check_width_model();
    let width_passed_total: usize = width_probes.iter().filter(|(_, ok, _)| *ok).count();
    rows.push(InterfaceRow::new(
        "support",
        "text_layout",
        "is_wide_character('珠')",
        &bool_text(is_wide_character('珠')),
    ));
    rows.push(InterfaceRow::new(
        "support",
        "text_layout",
        "display_width(\"珠宝\")",
        &format!("{} 列", display_width("珠宝")),
    ));
    rows.push(InterfaceRow::new(
        "support",
        "text_layout",
        "truncate_to_width(\"珠宝饰品工艺\", 7)",
        &truncate_to_width("珠宝饰品工艺", 7),
    ));
    rows.push(InterfaceRow::new(
        "support",
        "text_layout",
        "elide_text(\"珠宝饰品工艺路线卡\", 6)",
        &elide_text("珠宝饰品工艺路线卡", 6),
    ));
    rows.push(InterfaceRow::new(
        "support",
        "text_layout",
        "pad_center(\"合计\", 8)",
        &format!("[{}]", pad_center("合计", 8)),
    ));
    rows.push(InterfaceRow::new(
        "support",
        "text_layout",
        "horizontal_rule(10)",
        &horizontal_rule(10),
    ));
    rows.push(InterfaceRow::new(
        "support",
        "text_layout",
        "self_check_width_model()",
        &format!("{}/{} 组探针通过", width_passed_total, width_probes.len()),
    ));
    rows.push(InterfaceRow::new(
        "support",
        "deterministic_code",
        "stable_hash(&[\"SO-2025-0001\", \"1\"])",
        &format!("{}", stable_hash(&["SO-2025-0001", "1"])),
    ));
    rows.push(InterfaceRow::new(
        "support",
        "deterministic_code",
        "deterministic_code(&[\"SO-2025-0001\"], 8)",
        &deterministic_code(&["SO-2025-0001"], 8),
    ));
    rows.push(InterfaceRow::new(
        "support",
        "deterministic_code",
        "prefixed_code(\"MEM\", &[\"A\"], 6)",
        &prefixed_code("MEM", &["A"], 6),
    ));

    // ---- domain 层 ----
    rows.push(InterfaceRow::new(
        "domain",
        "ApprovalLevel",
        "LEVEL_CLERK.code() / chinese_name() / authority_rank()",
        &format!(
            "{} / {} / {}",
            LEVEL_CLERK.code(),
            LEVEL_CLERK.chinese_name(),
            LEVEL_CLERK.authority_rank()
        ),
    ));
    rows.push(InterfaceRow::new(
        "domain",
        "ApprovalLevel",
        "LEVEL_REGIONAL.is_at_least(&LEVEL_CLERK)",
        &bool_text(LEVEL_REGIONAL.is_at_least(&LEVEL_CLERK)),
    ));
    rows.push(InterfaceRow::new(
        "domain",
        "ApprovalLevel",
        "LEVEL_CLERK.is_same(&LEVEL_CLERK)",
        &bool_text(LEVEL_CLERK.is_same(&LEVEL_CLERK)),
    ));
    rows.push(InterfaceRow::new(
        "domain",
        "ApprovalLevel",
        "BUILTIN_APPROVAL_LEVELS.len()",
        &format!("{} 级(不含扩展区新增)", BUILTIN_APPROVAL_LEVELS.len()),
    ));
    rows.push(InterfaceRow::new(
        "domain",
        "arithmetic",
        "divide_rounded(7, 2) / divide_rounded(-7, 2)",
        &format!(
            "{} / {}(远离零,不是向零截断)",
            divide_rounded(7, 2),
            divide_rounded(-7, 2)
        ),
    ));
    rows.push(InterfaceRow::new(
        "domain",
        "arithmetic",
        "ratio_basis_points(1, 3)",
        &format!("{} 万分点", ratio_basis_points(1, 3)),
    ));
    rows.push(InterfaceRow::new(
        "domain",
        "arithmetic",
        "scale_rounded(1_888_800, 8_500, 10_000)",
        &format!("{} 分", scale_rounded(1_888_800, 8_500, 10_000)),
    ));
    let sample_money: Money = Money::new(123_456, CNY);
    rows.push(InterfaceRow::new(
        "domain",
        "Money",
        "Money::new(123456, CNY).chinese_text()",
        &sample_money.chinese_text(),
    ));
    rows.push(InterfaceRow::new(
        "domain",
        "Money",
        "amount_text() / is_zero() / minor_units()",
        &format!(
            "{} / {} / {}",
            sample_money.amount_text(),
            bool_text(sample_money.is_zero()),
            sample_money.minor_units()
        ),
    ));
    rows.push(InterfaceRow::new(
        "domain",
        "Money",
        "negate() / scale_basis_points(8500) / scale_ratio(1, 2)",
        &format!(
            "{} / {} / {}",
            sample_money.negate().chinese_text(),
            sample_money.scale_basis_points(8_500).chinese_text(),
            sample_money.scale_ratio(1, 2).chinese_text()
        ),
    ));
    rows.push(InterfaceRow::new(
        "domain",
        "Money",
        "is_same_as(&Money::zero(CNY))",
        &bool_text(sample_money.is_same_as(&Money::zero(CNY))),
    ));
    rows.push(InterfaceRow::new(
        "domain",
        "CurrencyCode",
        "CNY.code() / chinese_name() / symbol()",
        &format!("{} / {} / {}", CNY.code(), CNY.chinese_name(), CNY.symbol()),
    ));
    rows.push(InterfaceRow::new(
        "domain",
        "CurrencyCode",
        "BUILTIN_CURRENCY_CODES.len()",
        &format!("{} 种", BUILTIN_CURRENCY_CODES.len()),
    ));
    // ★ USD:演示数据里**没有**美元单,但币种是开放型值对象------
    //   扩展方自带一张美元单时不需要回领域层改任何东西(连枚举都不用加一项)。
    let third_currency: CurrencyCode = USD;
    rows.push(InterfaceRow::new(
        "domain",
        "CurrencyCode(开放型)",
        "USD.code() / chinese_name() / symbol()",
        &format!(
            "{} / {} / {}(演示数据用 {} / {})",
            third_currency.code(),
            third_currency.chinese_name(),
            third_currency.symbol(),
            CNY.code(),
            HKD.code()
        ),
    ));
    rows.push(InterfaceRow::new(
        "domain",
        "StoreCode",
        "STORE_CN_02_EXTENDED.code() / chinese_name()",
        &format!(
            "{} / {}(扩展区自带)",
            STORE_CN_02_EXTENDED.code(),
            STORE_CN_02_EXTENDED.chinese_name()
        ),
    ));
    rows.push(InterfaceRow::new(
        "domain",
        "StoreCode",
        "BUILTIN_STORE_CODES.len()",
        &format!("{} 家(不含扩展区新增)", BUILTIN_STORE_CODES.len()),
    ));
    rows.push(InterfaceRow::new(
        "domain",
        "CategoryCode",
        "CATEGORY_PEARL_EXTENDED.chinese_name() / needs_metal_pricing()",
        &format!(
            "{} / {}",
            CATEGORY_PEARL_EXTENDED.chinese_name(),
            bool_text(CATEGORY_PEARL_EXTENDED.needs_metal_pricing())
        ),
    ));
    rows.push(InterfaceRow::new(
        "domain",
        "CategoryCode",
        "BUILTIN_CATEGORY_CODES.len()",
        &format!("{} 类(不含扩展区新增)", BUILTIN_CATEGORY_CODES.len()),
    ));
    let probe_line: OrderLine = OrderLine::new(
        1,
        CATEGORY_PEARL_EXTENDED,
        2,
        3_330,
        Money::new(555_500, CNY),
    );
    rows.push(InterfaceRow::new(
        "domain",
        "OrderLine",
        "fingerprint_text()",
        &probe_line.fingerprint_text(),
    ));
    rows.push(InterfaceRow::new(
        "domain",
        "OrderLine",
        "list_amount() / payable_amount(1500) / total_weight_milligrams()",
        &format!(
            "{} / {} / {} 毫克",
            probe_line.list_amount().chinese_text(),
            probe_line.payable_amount(1_500).chinese_text(),
            probe_line.total_weight_milligrams()
        ),
    ));
    let probe_order: SalesOrder = extended_order();
    rows.push(InterfaceRow::new(
        "domain",
        "SalesOrder",
        "quotation_fingerprint()",
        &probe_order.quotation_fingerprint(),
    ));
    rows.push(InterfaceRow::new(
        "domain",
        "SalesOrder",
        "list_amount_total() / payable_amount_total() / discount_amount()",
        &format!(
            "{} / {} / {}",
            probe_order.list_amount_total().chinese_text(),
            probe_order.payable_amount_total().chinese_text(),
            probe_order.discount_amount().chinese_text()
        ),
    ));
    rows.push(InterfaceRow::new(
        "domain",
        "SalesOrder",
        "total_quantity() / total_weight_milligrams() / approval_level()",
        &format!(
            "{} 件 / {} 毫克 / {}",
            probe_order.total_quantity(),
            probe_order.total_weight_milligrams(),
            probe_order.approval_level().chinese_name()
        ),
    ));
    rows.push(InterfaceRow::new(
        "domain",
        "QuotationRejection",
        "OrderSealed.code() / chinese_text()",
        &format!(
            "{} / {}",
            QuotationRejection::OrderSealed.code(),
            QuotationRejection::OrderSealed.chinese_text()
        ),
    ));
    rows.push(InterfaceRow::new(
        "domain",
        "QuotationRejection",
        "ForeignSnapshot.known_failing_input_text()",
        QuotationRejection::ForeignSnapshot.known_failing_input_text(),
    ));
    let allowed_probe: RepriceVerdict =
        RepriceVerdict::Allowed { resulting_discount_basis_points: 1_500 };
    rows.push(InterfaceRow::new(
        "domain",
        "RepriceVerdict",
        "Allowed{1500}.code() / chinese_text() / is_allowed()",
        &format!(
            "{} / {} / {}",
            allowed_probe.code(),
            allowed_probe.chinese_text(),
            bool_text(allowed_probe.is_allowed())
        ),
    ));
    let unchanged_probe: RepriceVerdict =
        RepriceVerdict::Unchanged { current_discount_basis_points: 0 };
    rows.push(InterfaceRow::new(
        "domain",
        "RepriceVerdict",
        "Unchanged{0}.is_denied() / is_unchanged()",
        &format!(
            "{} / {}",
            bool_text(unchanged_probe.is_denied()),
            bool_text(unchanged_probe.is_unchanged())
        ),
    ));
    rows.push(InterfaceRow::new(
        "domain",
        "REJECTION_* 常量",
        "ORDER_SEALED / NO_AUTHORITY_RECORD / AUTHORITY_EXCEEDED",
        &format!(
            "{} / {} / {}",
            REJECTION_ORDER_SEALED, REJECTION_NO_AUTHORITY_RECORD, REJECTION_AUTHORITY_EXCEEDED
        ),
    ));
    rows.push(InterfaceRow::new(
        "domain",
        "REJECTION_* 常量",
        "DISCOUNT_NEGATIVE / DISCOUNT_OVER_FULL",
        &format!("{} / {}", REJECTION_DISCOUNT_NEGATIVE, REJECTION_DISCOUNT_OVER_FULL),
    ));
    rows.push(InterfaceRow::new(
        "domain",
        "RollbackCheck",
        "RollbackCheck::new(4, 0).is_consistent() / chinese_text()",
        &format!(
            "{} / {}",
            bool_text(RollbackCheck::new(4, 0).is_consistent()),
            RollbackCheck::new(4, 0).chinese_text()
        ),
    ));
    rows.push(InterfaceRow::new(
        "domain",
        "RollbackCheck",
        "RollbackCheck::new(4, 2).revision() / payable_mismatch_total()",
        &format!(
            "第 {} 版 / {} 处不符",
            RollbackCheck::new(4, 2).revision(),
            RollbackCheck::new(4, 2).payable_mismatch_total()
        ),
    ));
    let builtin_policy: QuotationPolicy = builtin_quotation_policy();
    rows.push(InterfaceRow::new(
        "domain",
        "QuotationPolicy",
        "authorities().len() / max_discount_for(&LEVEL_MANAGER)",
        &format!(
            "{} 档 / {}",
            builtin_policy.authorities().len(),
            match builtin_policy.max_discount_for(&LEVEL_MANAGER) {
                Some(value) => format!("{} 万分点", value),
                None => String::from("None(没配)"),
            }
        ),
    ));
    rows.push(InterfaceRow::new(
        "domain",
        "QuotationPolicy",
        "max_discount_for(&LEVEL_HEADQUARTERS_EXTENDED)",
        &match builtin_policy.max_discount_for(&LEVEL_HEADQUARTERS_EXTENDED) {
            Some(value) => format!("{} 万分点", value),
            None => String::from("None(内建表没配这一级)"),
        },
    ));
    let probe_authority: DiscountAuthority = BRANCH_DISCOUNT_AUTHORITIES[3];
    rows.push(InterfaceRow::new(
        "domain",
        "DiscountAuthority",
        "level().chinese_name() / max_discount_basis_points()",
        &format!(
            "{} / {} 万分点",
            probe_authority.level().chinese_name(),
            probe_authority.max_discount_basis_points()
        ),
    ));
    rows.push(InterfaceRow::new(
        "domain",
        "SalesOrderRepository",
        "count() / all().len()",
        // ★ 通过 **trait** 调用:仓储接口在领域层,调用方不该绑在实现类型上。
        &format!(
            "{} 张 / {} 张",
            SalesOrderRepository::count(repository),
            repository.all().len()
        ),
    ));
    rows.push(InterfaceRow::new(
        "domain",
        "SalesOrderRepository",
        "find_by_number(\"SO-2025-0004\")",
        &match repository.find_by_number("SO-2025-0004") {
            Some(order) => format!(
                "{}({})",
                order.order_number(),
                order.store().chinese_name()
            ),
            None => String::from("查不到"),
        },
    ));
    // ★ 快照的窄接口:只有标识符与尺寸,没有任何可用来改价的信息。
    let probe_snapshot: QuotationMemento = probe_order.capture();
    rows.push(InterfaceRow::new(
        "domain",
        "QuotationMemento",
        "revision() / sealed() / byte_footprint()",
        &format!(
            "第 {} 版 / {} / {} 字节",
            probe_snapshot.revision(),
            bool_text(probe_snapshot.sealed()),
            probe_snapshot.byte_footprint()
        ),
    ));
    rows.push(InterfaceRow::new(
        "domain",
        "QuotationMemento",
        "fingerprint_text()(★ 只有这个,没有折扣)",
        &probe_snapshot.fingerprint_text(),
    ));

    // ---- memento 层(**零业务**:换任何业务这些入口都在)----
    let mut probe_history: History<ProbeMemento> = History::new();
    let mut probe_originator: ProbeOriginator = ProbeOriginator::new(1, String::from("甲"));
    let _first_probe: ProbeMemento = probe_history.capture(&probe_originator);
    probe_originator.advance(String::from("乙"));
    let _second_probe: ProbeMemento = probe_history.capture(&probe_originator);
    let probe_outcome: Option<RestoreOutcome> = probe_history.undo(&mut probe_originator);
    rows.push(InterfaceRow::new(
        "memento",
        "History<ProbeMemento>",
        "len() / is_empty() / revision_list()",
        &format!(
            "{} 版 / {} / {:?}",
            probe_history.len(),
            bool_text(probe_history.is_empty()),
            probe_history.revision_list()
        ),
    ));
    rows.push(InterfaceRow::new(
        "memento",
        "History<ProbeMemento>",
        "can_undo() / can_redo() / cursor_index() / cursor_revision()",
        &format!(
            "{} / {} / {} / {}",
            bool_text(probe_history.can_undo()),
            bool_text(probe_history.can_redo()),
            index_text(probe_history.cursor_index()),
            revision_text(probe_history.cursor_revision())
        ),
    ));
    rows.push(InterfaceRow::new(
        "memento",
        "History<ProbeMemento>",
        "entries().len() / total_byte_footprint()",
        &format!(
            "{} 条 / {} 字节",
            probe_history.entries().len(),
            probe_history.total_byte_footprint()
        ),
    ));
    rows.push(InterfaceRow::new(
        "memento",
        "History<ProbeMemento>",
        "undo() 的返回值",
        &format!(
            "{}(第 {} 版)",
            outcome_text_of(probe_outcome.as_ref()),
            probe_originator.revision()
        ),
    ));
    let probe_snapshot_value: ProbeMemento = probe_originator.save();
    rows.push(InterfaceRow::new(
        "memento",
        "ProbeMemento",
        "revision() / fingerprint_text() / byte_footprint()",
        &format!(
            "第 {} 版 / {} / {} 字节",
            probe_snapshot_value.revision(),
            probe_snapshot_value.fingerprint_text(),
            probe_snapshot_value.byte_footprint()
        ),
    ));
    rows.push(InterfaceRow::new(
        "memento",
        "ProbeOriginator",
        "revision() / state_text() / current_fingerprint()",
        &format!(
            "{} / {} / {}",
            probe_originator.revision(),
            probe_originator.state_text(),
            probe_originator.current_fingerprint()
        ),
    ));
    // ★ 两组「不忠实 / 一律拒绝」的探针:它们存在的唯一理由是**证明自检会红**。
    let mut faithless: FaithlessOriginator = FaithlessOriginator::new(7, String::from("丙"));
    let faithless_snapshot: ProbeMemento = faithless.save();
    let faithless_outcome: RestoreOutcome = faithless.restore(faithless_snapshot);
    rows.push(InterfaceRow::new(
        "memento",
        "FaithlessOriginator",
        "restore():**声称成功却什么都不做**",
        &format!(
            "{}(声称成功,可它根本没动,仍是第 {} 版)",
            faithless_outcome.chinese_text(),
            faithless.save().revision()
        ),
    ));
    let mut refusing: RefusingOriginator = RefusingOriginator::new(9, String::from("丁"));
    refusing.advance(String::from("戊"));
    let refusing_snapshot: ProbeMemento = refusing.save();
    let refusing_outcome: RestoreOutcome = refusing.restore(refusing_snapshot);
    rows.push(InterfaceRow::new(
        "memento",
        "RefusingOriginator",
        "restore() 的返回值",
        &format!(
            "{}({})",
            refusing_outcome.chinese_text(),
            refusing_outcome.rejection_code().unwrap_or("---")
        ),
    ));
    let restored_probe: RestoreOutcome = RestoreOutcome::Restored { revision: 4 };
    rows.push(InterfaceRow::new(
        "memento",
        "RestoreOutcome",
        "Restored{4}.code() / chinese_text() / detail_text()",
        &format!(
            "{} / {} / [{}]",
            restored_probe.code(),
            restored_probe.chinese_text(),
            restored_probe.detail_text()
        ),
    ));
    rows.push(InterfaceRow::new(
        "memento",
        "LedgerSnapshot",
        "saved_total() / restore_action_total() / restore_outcome_total()",
        &format!(
            "{} / {} / {}",
            ledger_early.saved_total(),
            ledger_early.restore_action_total(),
            ledger_early.restore_outcome_total()
        ),
    ));
    rows.push(InterfaceRow::new(
        "memento",
        "LedgerSnapshot",
        "mismatch_total() / peak_entries() / is_monotonic_after(&self)",
        &format!(
            "{} / {} / {}",
            ledger_early.mismatch_total(),
            ledger_early.peak_entries(),
            bool_text(ledger_early.is_monotonic_after(ledger_early))
        ),
    ));
    // ★ 台账本体:对外**只有** `snapshot()`,九个增量接口一律 `pub(super)`。
    //   这里另建一个实例(不碰会话里那一个)实证「从零开始」;
    //   `is_monotonic_after(自身)` 看着像废话,其实它盯的是**>= 有没有被写成 >**------
    //   一个恒真的单调判定等于没有判定。
    let standalone_ledger: HistoryLedger = HistoryLedger::new();
    let standalone_snapshot: LedgerSnapshot = standalone_ledger.snapshot();
    rows.push(InterfaceRow::new(
        "memento",
        "HistoryLedger",
        "new() → snapshot()(**对外唯一可读入口**)",
        &format!(
            "新建即全 0:拍快照 {} 次 / 装回动作 {} 次 / 峰值 {} 版;is_monotonic_after(自身) = {}",
            standalone_snapshot.saved_total(),
            standalone_snapshot.restore_action_total(),
            standalone_snapshot.peak_entries(),
            bool_text(standalone_snapshot.is_monotonic_after(&standalone_snapshot))
        ),
    ));

    // ---- client 层 ----
    rows.push(InterfaceRow::new(
        "client",
        "装配点",
        "demo_orders().len() / same_currency_batch().len()",
        &format!(
            "{} 张 / {} 张(同币种)",
            demo_orders().len(),
            same_currency_batch().len()
        ),
    ));
    // ★ 港币单为什么**不在**同币种批次里:试算要合计折让额,跨币种相加没有意义。
    //   这一行把「少了一张」讲清楚,否则读者会以为批次漏装配了一张。
    let hk_probe: SalesOrder = order_hk_first();
    rows.push(InterfaceRow::new(
        "client",
        "装配点",
        "order_hk_first().order_number() / currency().chinese_name()",
        &format!(
            "{} / {}(被排除:批次里全是 {})",
            hk_probe.order_number(),
            hk_probe.currency().chinese_name(),
            CNY.chinese_name()
        ),
    ));
    rows.push(InterfaceRow::new(
        "client",
        "装配点",
        "DEMO_CATEGORIES / DEMO_CURRENCIES / DEMO_STORES / BUILTIN_ACTOR_LEVELS",
        &format!(
            "{} / {} / {} / {}",
            DEMO_CATEGORIES.len(),
            DEMO_CURRENCIES.len(),
            DEMO_STORES.len(),
            BUILTIN_ACTOR_LEVELS.len()
        ),
    ));
    rows.push(InterfaceRow::new(
        "client",
        "装配点",
        "BUILTIN_DISCOUNT_AUTHORITIES.len()",
        &format!("{} 档", BUILTIN_DISCOUNT_AUTHORITIES.len()),
    ));
    let empty_log: RepriceLog = RepriceLog::new();
    rows.push(InterfaceRow::new(
        "client",
        "RepriceLog",
        "new().len() / is_empty()",
        &format!("{} / {}", empty_log.len(), bool_text(empty_log.is_empty())),
    ));
    rows.push(InterfaceRow::new(
        "client",
        "RepriceLog",
        "verdict_tallies()(空流水)",
        &format!("{:?}", empty_log.verdict_tallies()),
    ));
    rows.push(InterfaceRow::new(
        "client",
        "RepriceLog",
        "rejection_tallies()(空流水)",
        &format!("{:?}", empty_log.rejection_tallies()),
    ));
    rows.push(InterfaceRow::new(
        "client",
        "InMemorySalesOrderRepository",
        "new() → SalesOrderRepository::count()",
        // ★ 走 **trait**:换成数据库实现时这一行不用改。
        &format!(
            "{} 张",
            SalesOrderRepository::count(&InMemorySalesOrderRepository::new())
        ),
    ));
    // ★ 接缝本身:`domain` 不认识 `Originator`,是下面这一组调用把它们接起来的。
    //   领域层只提供 capture() / apply(),这里翻译成机制层的 save() / restore()。
    let mut standalone_originator: QuotationOriginator = QuotationOriginator::new(order_cn_second());
    let standalone_saved: QuotationMemento = standalone_originator.save();
    let standalone_revision_before: u64 = standalone_originator.current_revision();
    let standalone_restored: RestoreOutcome = standalone_originator.restore(standalone_saved);
    let standalone_check: Option<RollbackCheck> = standalone_originator.last_restore_check();
    rows.push(InterfaceRow::new(
        "client",
        "QuotationOriginator(impl Originator)",
        "save() / restore() / current_revision() / current_fingerprint()",
        &format!(
            "第 {} 版 → save(第 {} 版)→ restore → {};核对 {};指纹 {}",
            standalone_revision_before,
            standalone_originator.current_revision(),
            standalone_restored.chinese_text(),
            match &standalone_check {
                Some(check) => String::from(check.chinese_text()),
                None => String::from("无(没装回就没有「装回对不对」这回事)"),
            },
            standalone_originator.current_fingerprint()
        ),
    ));
    // ★ 一次申请一条(**被拒也算**):申请人级别编码由 `actor_level_code()` 给出,
    //   排序去重后拼串,两次运行才逐字节一致。
    rows.push(InterfaceRow::new(
        "client",
        "RepriceLogEntry",
        "actor_level_code()(本轮流水里出现过的级别)",
        actor_level_codes_text,
    ));
    let wide_probe: crate::client::WideMementoExperiment =
        run_wide_memento_experiment(&extended_order(), 1, 1);
    rows.push(InterfaceRow::new(
        "client",
        "WideMementoExperiment",
        "narrow_byte_footprint() / wide_byte_footprint() / all_three_succeeded()",
        &format!(
            "{} 字节 / {} 字节 / {}",
            wide_probe.narrow_byte_footprint(),
            wide_probe.wide_byte_footprint(),
            bool_text(wide_probe.all_three_succeeded())
        ),
    ));
    rows.push(InterfaceRow::new(
        "client",
        "WideQuotationMemento",
        "capture_from():**外部自己拍一份**(窄接口下这一步编译不过)",
        &format!("{} 字节", wide_alone_bytes),
    ));
    let empty_simulation: crate::client::RepriceSimulation =
        crate::client::RepriceSimulation::new(Vec::new(), CNY, 0, 0, 0, 0);
    rows.push(InterfaceRow::new(
        "client",
        "RepriceSimulation",
        "currency().chinese_name() / discount_amount() / is_complete()",
        &format!(
            "{} / {} / {}",
            empty_simulation.currency().chinese_name(),
            empty_simulation.discount_amount().chinese_text(),
            bool_text(empty_simulation.is_complete())
        ),
    ));

    // ---- analysis 层 ----
    let empty_report: CheckReport = CheckReport::new();
    rows.push(InterfaceRow::new(
        "analysis",
        "CheckReport",
        "new().line_total() / passed_total() / failed_total() / all_passed()",
        &format!(
            "{} / {} / {} / {}",
            empty_report.line_total(),
            empty_report.passed_total(),
            empty_report.failed_total(),
            bool_text(empty_report.all_passed())
        ),
    ));
    rows.push(InterfaceRow::new(
        "analysis",
        "CheckReport",
        "failed_items_text()(空报告)",
        &empty_report.failed_items_text(),
    ));
    rows.push(InterfaceRow::new(
        "analysis",
        "verdict_text",
        "verdict_text(true) / verdict_text(false)",
        &format!("{} / {}", verdict_text(true), verdict_text(false)),
    ));
    let probe_check: CheckLine = CheckLine::new("探针", "期望", "实测", true);
    rows.push(InterfaceRow::new(
        "analysis",
        "CheckLine",
        "item() / expectation_text() / actual_text() / verdict_text()",
        &format!(
            "{} / {} / {} / {}",
            probe_check.item(),
            probe_check.expectation_text(),
            probe_check.actual_text(),
            probe_check.verdict_text()
        ),
    ));

    // ---- app 层 ----
    rows.push(InterfaceRow::new(
        "app",
        "layout",
        "DOCUMENT_WIDTH",
        &format!("{} 列", DOCUMENT_WIDTH),
    ));
    let probe_column: TableColumn = TableColumn::numeric("探针", 6).elidable();
    rows.push(InterfaceRow::new(
        "app",
        "TableColumn",
        "header() / width() / align() / is_elidable()",
        &format!(
            "{} / {} / {} / {}",
            probe_column.header(),
            probe_column.width(),
            align_text(probe_column.align()),
            bool_text(probe_column.is_elidable())
        ),
    ));
    let probe_table: Table = Table::new("探针表", vec![TableColumn::new("列", 4)]);
    rows.push(InterfaceRow::new(
        "app",
        "Table",
        "column_count() / row_count() / total_width()",
        &format!(
            "{} / {} / {} 列",
            probe_table.column_count(),
            probe_table.row_count(),
            probe_table.total_width()
        ),
    ));
    rows.push(InterfaceRow::new(
        "app",
        "render_cell",
        "render_cell(列宽 6, \"12345\")",
        &format!("[{}]", render_cell(&probe_column, "12345")),
    ));
    rows.push(InterfaceRow::new(
        "app",
        "value_display",
        "basis_points_text(1500) / percent_text(1500)",
        &format!("{} / {}%", basis_points_text(1_500), percent_text(1_500)),
    ));
    rows.push(InterfaceRow::new(
        "app",
        "value_display",
        "gram_display_text(12450) / signed_gram_display_text(-104)",
        &format!(
            "{} 克 / {} 克(负数不是 -1.896)",
            gram_display_text(12_450),
            signed_gram_display_text(-104)
        ),
    ));
    rows.push(InterfaceRow::new(
        "app",
        "value_display",
        "byte_text(1_048_576) / bool_text(true)",
        &format!("{} 字节 / {}", byte_text(1_048_576), bool_text(true)),
    ));
    rows.push(InterfaceRow::new(
        "app",
        "health_check_report",
        "items_of(&[一条检查行]).len()",
        &format!("{} 项", items_of(std::slice::from_ref(&probe_check)).len()),
    ));
    rows.push(InterfaceRow::new(
        "app",
        "note_lines",
        "note_lines(\"一行注解\", DOCUMENT_WIDTH).len()",
        &format!("{} 行", note_lines("一行注解", DOCUMENT_WIDTH).len()),
    ));

    rows
}

/// 把 `Option<usize>` 显示成文本(**接口清点专用**)。
fn index_text(value: Option<usize>) -> String {
    match value {
        Some(index) => format!("第 {} 条", index),
        None => String::from("空历史"),
    }
}

/// 把 `Option<u64>` 显示成文本(**接口清点专用**)。
fn revision_text(value: Option<u64>) -> String {
    match value {
        Some(revision) => format!("第 {} 版", revision),
        None => String::from("空历史"),
    }
}

/// 把列对齐显示成文本(**接口清点专用**)。
fn align_text(align: ColumnAlign) -> &'static str {
    match align {
        ColumnAlign::Left => "左对齐",
        ColumnAlign::Right => "右对齐",
    }
}

// ===========================================================================
// 幕十四 · 体检表(**分段构造**,每段的检查项顺序与 `local_falsifiable_lines` 对应)
// ===========================================================================

/// 第 1--3 条:改价流水与历史版数。
fn push_reprice_checks(
    report: &mut CheckReport,
    flow_summary: &crate::analysis::RepriceFlowSummary,
    version_consistent_before_seal: bool,
    version_total_before_seal: usize,
    allowed_total_before_seal: usize,
    timeline_summary: &crate::analysis::HistoryTimelineSummary,
) {
    report.push(CheckLine::new(
        "流水三态之和 == 申请总条数",
        &format!(
            "同意{}+被拒{}+无变化{}={}",
            flow_summary.allowed_total(),
            flow_summary.denied_total(),
            flow_summary.unchanged_total(),
            flow_summary.total()
        ),
        &format!(
            "{}+{}+{}={}",
            flow_summary.allowed_total(),
            flow_summary.denied_total(),
            flow_summary.unchanged_total(),
            flow_summary.total()
        ),
        flow_summary.is_complete(),
    ));
    report.push(CheckLine::new(
        "历史版数 == 同意次数 + 1(封存前)",
        &format!("{} 版", allowed_total_before_seal + 1),
        &format!(
            "{} 版(同意 {} 次)",
            version_total_before_seal, allowed_total_before_seal
        ),
        version_consistent_before_seal,
    ));
    report.push(CheckLine::new(
        "没有孤儿版本(第 1 版不算)",
        "0 个",
        &format!(
            "{} 个(共 {} 版)",
            timeline_summary.orphan_total(),
            timeline_summary.version_total()
        ),
        timeline_summary.has_no_orphan(),
    ));
}

/// 第 4--7 条:装回自洽性(**两条路径互盯**)。
fn push_consistency_checks(
    report: &mut CheckReport,
    consistency_summary: &crate::analysis::ConsistencySummary,
    statistics: &crate::analysis::RollbackStatistics,
    step_summary: &crate::analysis::RollbackStepSummary,
) {
    report.push(CheckLine::new(
        "自洽性核对:每一版都符合预期",
        &format!(
            "符合 {}/{}",
            consistency_summary.row_total(),
            consistency_summary.row_total()
        ),
        &format!(
            "符合 {}/{}",
            consistency_summary.met_total(),
            consistency_summary.row_total()
        ),
        consistency_summary.met_total() == consistency_summary.row_total(),
    ));
    report.push(CheckLine::new(
        "自洽性核对:非游标版本中没有「假零」",
        "0 个",
        &format!("{} 个", consistency_summary.false_zero_total()),
        consistency_summary.false_zero_total() == 0,
    ));
    report.push(CheckLine::new(
        "每一次装回都做了核对",
        &format!(
            "核对 {} 次 == 装回成功 {} 次",
            statistics.restored_total(),
            statistics.restored_total()
        ),
        &format!(
            "核对 {} 次 vs 装回成功 {} 次",
            statistics.check_total(),
            statistics.restored_total()
        ),
        statistics.every_restore_checked(),
    ));
    report.push(CheckLine::new(
        "逐步演练:装回不符处数合计为 0",
        "0 处",
        &format!(
            "{} 处(共 {} 步)",
            step_summary.mismatch_total(),
            step_summary.step_total()
        ),
        step_summary.mismatch_total() == 0,
    ));
    report.push(CheckLine::new(
        "自洽性摘要:all_met() 成立",
        "真",
        &format!(
            "{}(符合 {}/{},假零 {} 个)",
            bool_text(consistency_summary.all_met()),
            consistency_summary.met_total(),
            consistency_summary.row_total(),
            consistency_summary.false_zero_total()
        ),
        consistency_summary.all_met(),
    ));
}

/// 第 9--16 条:会话统计(**全部用 `RollbackStatistics` 的只读入口**)。
///
/// # 参数
/// - `statistics`:会话跑完之后收的统计。
/// - `allowed_total_final`:全程同意的改价次数(**含封存前**;session 交回仓储前取下来的)。
/// - `footprint_sum`:逐版量出来的字节之和(与 `total_byte_footprint()` 是两条不同的路径)。
///
/// ⚠️ 为什么单独一段:这些量全部是「跑到最后才成立的量」,
/// 与「逐步演练」那一段混在一起,读者分不清哪一步在盯哪一个时刻。
fn push_statistics_checks(
    report: &mut CheckReport,
    statistics: &crate::analysis::RollbackStatistics,
    allowed_total_final: usize,
    footprint_sum: usize,
) {
    report.push(CheckLine::new(
        "封存也记一版:版数==同意次数+2",
        &format!("{} 版(同意{}+初始1+封存1)", allowed_total_final + 2, allowed_total_final),
        &format!(
            "{} 版(同意 {} 次)",
            statistics.version_total(),
            allowed_total_final
        ),
        statistics.version_total() == allowed_total_final + 2,
    ));
    report.push(CheckLine::new(
        "游标停在最后一版",
        &format!("第 {} 版", statistics.version_total()),
        &format!("第 {} 版", statistics.cursor_revision()),
        statistics.cursor_revision() == statistics.version_total() as u64,
    ));
    report.push(CheckLine::new(
        "游标在顶:还能退、不能再进",
        "能退 且 不能进",
        &format!(
            "能退 {} / 能进 {}",
            bool_text(statistics.can_undo()),
            bool_text(statistics.can_redo())
        ),
        statistics.can_undo() && !statistics.can_redo(),
    ));
    report.push(CheckLine::new(
        "装回动作次数==成功+被拒(无第四条路径)",
        &format!(
            "{} == {} + {}",
            statistics.restore_action_total(),
            statistics.restored_total(),
            statistics.refused_total()
        ),
        &format!(
            "{} vs {} + {} = {}",
            statistics.restore_action_total(),
            statistics.restored_total(),
            statistics.refused_total(),
            statistics.restored_total() + statistics.refused_total()
        ),
        statistics.restore_action_total()
            == statistics.restored_total() + statistics.refused_total(),
    ));
    report.push(CheckLine::new(
        "本轮没有另开分支:分支丢弃 0 条",
        "0 条",
        &format!("{} 条", statistics.branch_discarded_total()),
        statistics.branch_discarded_total() == 0,
    ));
    report.push(CheckLine::new(
        "全程自洽性不符 0 处",
        "0 处",
        &format!("{} 处", statistics.mismatch_total()),
        statistics.mismatch_total() == 0,
    ));
    report.push(CheckLine::new(
        "峰值 == 最终版数(本轮没有截断过)",
        &format!("峰值 {} 版", statistics.version_total()),
        &format!(
            "峰值 {} 版 vs 最终 {} 版",
            statistics.peak_entries(),
            statistics.version_total()
        ),
        statistics.peak_entries() == statistics.version_total(),
    ));
    report.push(CheckLine::new(
        "历史字节合计 == 逐版之和",
        &format!("{} 字节", footprint_sum),
        &format!(
            "合计 {} vs 逐版之和 {} 字节",
            statistics.total_byte_footprint(),
            footprint_sum
        ),
        statistics.total_byte_footprint() == footprint_sum,
    ));
}

/// 第 8--11 条:台账恒等式。
fn push_ledger_checks(
    report: &mut CheckReport,
    ledger_expectations: &crate::analysis::LedgerExpectations,
    ledger_early: &LedgerSnapshot,
    ledger_later: &LedgerSnapshot,
) {
    report.push(CheckLine::new(
        "台账:装回结果次数 == 装回动作次数",
        "相等(没有第四条装回路径)",
        &format!(
            "{} vs {}",
            ledger_later.restore_outcome_total(),
            ledger_later.restore_action_total()
        ),
        ledger_expectations.outcome_equals_action(),
    ));
    report.push(CheckLine::new(
        "台账:无版本号 / 指纹不一致",
        "0 次",
        &format!(
            "{} 次(版本号 {} + 指纹 {})",
            ledger_later.mismatch_total(),
            ledger_later.revision_mismatch_total(),
            ledger_later.fingerprint_mismatch_total()
        ),
        ledger_expectations.no_mismatch(),
    ));
    report.push(CheckLine::new(
        "台账:历史长度峰值 >= 当前版数",
        &format!("峰值 >= {} 版", ledger_later.peak_entries()),
        &format!(
            "峰值 {} 版 vs 切片那一刻 {} 版",
            ledger_later.peak_entries(),
            ledger_later.peak_entries()
        ),
        ledger_expectations.peak_at_least_current(),
    ));
    report.push(CheckLine::new(
        "台账只增不减",
        "后一份切片的每一项 >= 前一份",
        &bool_text(ledger_later.is_monotonic_after(ledger_early)),
        ledger_later.is_monotonic_after(ledger_early),
    ));
}

/// 第 21--24 条:封装与机制层自检。
fn push_mechanism_checks(
    report: &mut CheckReport,
    encapsulation_cost: i64,
    encapsulation_demonstrated: bool,
    audit_count: (usize, usize, usize),
    audit_verdict_agreed: usize,
) {
    report.push(CheckLine::new(
        "封装的内存代价为 0 字节",
        "0 字节",
        &format!("{} 字节", encapsulation_cost),
        encapsulation_cost == 0,
    ));
    report.push(CheckLine::new(
        "封装对照实验真的演示成功",
        "三项外部动作全部得手",
        &bool_text(encapsulation_demonstrated),
        encapsulation_demonstrated,
    ));
    report.push(CheckLine::new(
        "机制层自检全部通过",
        &format!("通过 {}/{}", audit_count.0, audit_count.0),
        &format!("通过 {}/{}", audit_count.1, audit_count.0),
        audit_count.1 == audit_count.0,
    ));
    report.push(CheckLine::new(
        "机制层自检:结论文本与布尔一致",
        &format!("{}/{} 条一致", audit_count.0, audit_count.0),
        &format!("{}/{} 条一致", audit_verdict_agreed, audit_count.0),
        audit_verdict_agreed == audit_count.0,
    ));
}

/// 第 15--16 条:扩展区与接口清点。
fn push_extension_checks(
    report: &mut CheckReport,
    extension_tally: (usize, usize),
    interface_tally: (usize, usize),
) {
    report.push(CheckLine::new(
        "扩展项全部为纯新增(没改既有分层文件)",
        &format!("{}/{} 项为纯新增", extension_tally.0, extension_tally.0),
        &format!("{}/{} 项为纯新增", extension_tally.1, extension_tally.0),
        extension_tally.1 == extension_tally.0,
    ));
    report.push(CheckLine::new(
        "接口清点:全部只读入口都返回了值",
        &format!("{}/{} 个有返回值", interface_tally.0, interface_tally.0),
        &format!("{}/{} 个有返回值", interface_tally.1, interface_tally.0),
        interface_tally.1 == interface_tally.0,
    ));
}

/// 第 17--19 条:宽度模型与舍入口径(**不依赖任何运行时数据**)。
fn push_arithmetic_checks(report: &mut CheckReport) {
    let width_probes: Vec<(String, bool, String)> = self_check_width_model();
    let width_passed_total: usize = width_probes.iter().filter(|(_, ok, _)| *ok).count();
    report.push(CheckLine::new(
        "显示宽度模型自检全部通过",
        &format!("{}/{} 组探针通过", width_probes.len(), width_probes.len()),
        &format!("{}/{} 组探针通过", width_passed_total, width_probes.len()),
        width_passed_total == width_probes.len(),
    ));
    report.push(CheckLine::new(
        "舍入恒等式:f(-a,b)==-f(a,b)",
        &format!("{}", -divide_rounded(7, 2)),
        &format!("{}", divide_rounded(-7, 2)),
        divide_rounded(-7, 2) == -divide_rounded(7, 2),
    ));
    report.push(CheckLine::new(
        "舍入不是向零截断(7/2 应为 4)",
        "4",
        &format!("{}", divide_rounded(7, 2)),
        divide_rounded(7, 2) == 4,
    ));
}

/// 第 20--22 条:试算的三态、折让口径与「换表改变裁决」。
fn push_simulation_checks(
    report: &mut CheckReport,
    simulation_builtin: &crate::client::RepriceSimulation,
    simulation_branch: &crate::client::RepriceSimulation,
    simulation_manager: &crate::client::RepriceSimulation,
) {
    let simulation_complete: bool = simulation_builtin.is_complete()
        && simulation_branch.is_complete()
        && simulation_manager.is_complete();
    report.push(CheckLine::new(
        "试算三态之和 == 张数(三次都成立)",
        "三次全部成立",
        &format!(
            "{} / {} / {}",
            bool_text(simulation_builtin.is_complete()),
            bool_text(simulation_branch.is_complete()),
            bool_text(simulation_manager.is_complete())
        ),
        simulation_complete,
    ));
    report.push(CheckLine::new(
        "试算折让只累计同意的那些(一)为 0",
        "0 分(三张单全部被拒)",
        &format!("{} 分", simulation_builtin.discount_amount_minor_units()),
        simulation_builtin.discount_amount_minor_units() == 0,
    ));
    report.push(CheckLine::new(
        "换一张权限表就能改变裁决",
        "内建 0 张同意 → 扩展 3 张",
        &format!(
            "内建 {} 张同意 → 扩展 {} 张",
            simulation_builtin.allowed_total(),
            simulation_branch.allowed_total()
        ),
        simulation_builtin.allowed_total() == 0 && simulation_branch.allowed_total() == 3,
    ));

    // ★ 汇总数字与**明细条数**必须来自同一个集合:
    //   汇总由 `RepriceSimulation` 自己数,明细由 `entries()` 逐条数------两条路径。
    let mut entry_totals_matched: bool = true;
    let mut discounted_entry_total: usize = 0;
    for simulation in [simulation_builtin, simulation_branch, simulation_manager].iter() {
        let entries: &[RepriceSimulationEntry] = simulation.entries();
        discounted_entry_total += entries
            .iter()
            .filter(|entry| entry.discount_delta_minor_units() > 0)
            .count();
        if entries.len()
            != simulation.allowed_total() + simulation.denied_total() + simulation.unchanged_total()
        {
            entry_totals_matched = false;
        }
    }
    report.push(CheckLine::new(
        "试算明细条数 == 三态之和(三次都成立)",
        "三次全部成立",
        &format!(
            "{};折让 > 0 的明细共 {} 条",
            bool_text(entry_totals_matched),
            discounted_entry_total
        ),
        entry_totals_matched,
    ));
}

/// 幕十一(四)的注解:**每个数字都从这一批单当场算出来**,一个都不写死。
///
/// # 参数
/// - `batch`:试算批次(不可变切片,本函数只读)。
/// - `probe_bps`:探针折扣(万分点)。
fn probe_scene_text(batch: &[SalesOrder], probe_bps: i64) -> String {
    let mut pieces: Vec<String> = Vec::new();
    let mut discount_total: i64 = 0;
    for order in batch.iter() {
        let per_line: i64 = order
            .lines()
            .iter()
            .map(|line| {
                scale_rounded(
                    line.list_amount().minor_units(),
                    i128::from(10_000 - probe_bps),
                    10_000,
                )
            })
            .sum();
        let whole: i64 = scale_rounded(
            order.list_amount_total().minor_units(),
            i128::from(10_000 - probe_bps),
            10_000,
        );
        discount_total += order.list_amount_total().minor_units() - per_line;
        pieces.push(format!(
            "{} 逐行 {} 分/整单 {} 分(差 {} 分)",
            order.order_number(),
            per_line,
            whole,
            per_line - whole
        ));
    }
    format!(
        "★ 这一档折扣**除不尽**:{}。\
         小票逐行打印、顾客按行对账,所以取逐行;整单口径会把差出来的分算给顾客或算给店里,两边都不认。\
         ★ 上面三次试算的折扣(3500 / 1500)在这批数据上**全部整除**:那三幕里两种口径给出同一个答案,\
         「统一舍入口径」在业务数据上从未真正被用上------本幕是它唯一真正起作用的地方。折让合计 {} 分。",
        pieces.join(";"),
        discount_total
    )
}

/// ★ 负向探针折扣:**特意挑一个除不尽的档位**(777 万分点 = 7.77%)。
///
/// ## 为什么需要它
///
/// 前面三次试算用的 3500 / 1500 万分点,配上本工程的行挂牌额(都是整元的 100 倍),
/// 乘出来的积**全部**能被 10000 整除。于是「逐行折后求和」与「总额 × (1−折扣)」
/// 两种口径给出同一个答案,「统一舍入口径」在业务数据上**从未真正被用过**------
/// 报表的任何一格都看不出它存在。
///
/// 777 是**实测挑出来的**(不是拍的):它在 `SO-2025-0001` / `SO-2025-0002` 上让两种口径
/// 差 1 分,且 777 ≤ 1500 落在店长权限内,评审时不会被当成「超权限的假数据」。
///
/// ⚠️ 这个常量**没有牙齿**:夹具数据一改它就可能不再分叉。所以下面第 37 条体检
/// **每次运行都真的算一遍**这两条口径并断言「至少 1 单分叉」------
/// 常量失效的那一天,那条检查会红,而不是悄悄退回恒真。
const PROBE_DISCOUNT_BPS: i64 = 777;

/// 第 23--25 条:拒绝实证与金额口径。
fn push_domain_invariant_checks(
    report: &mut CheckReport,
    simulation_batch: &[SalesOrder],
    sealed_undo_refused: bool,
    sealed_reprice_refused: bool,
) {
    report.push(CheckLine::new(
        "拒绝实证:7 条被拒场景全部命中",
        "7 条",
        &format!("见幕七:8 条实证中被拒 7 条"),
        crate::domain::REJECTION_ORDER_SEALED.is_empty() == false
            && sealed_undo_refused
            && sealed_reprice_refused,
    ));

    let mut discount_non_negative: bool = true;
    let mut per_line_matches: bool = true;
    // ★ 负向探针的两条口径在 [`PROBE_DISCOUNT_BPS`] 这一档上差几分。
    let mut diverging_order_total: usize = 0;
    let mut divergence_minor_units_total: i64 = 0;
    for order in simulation_batch.iter() {
        if order.discount_amount().minor_units() < 0 {
            discount_non_negative = false;
        }
        // ── 路径 A(**独立的**那一侧):从「行挂牌额」用原始缩放原语重算。
        //
        // ⚠️ 这里原来是 `per_line_total.plus(line.payable_amount(bps))`,
        //    与 `payable_amount_total()` 内部调用的是**同一个函数**。两条路径永远相等,
        //    与数据无关、与实现无关------那是结构性恒真,不是检查。
        //    现在这一侧绕开 `OrderLine::payable_amount`,直接用 [`scale_rounded`]
        //    从挂牌额算:`OrderLine::payable_amount` 一旦换了口径(比如改成向零截断),
        //    这里就真的会红。
        let mut per_line_via_primitive: i64 = 0;
        for line in order.lines().iter() {
            per_line_via_primitive += scale_rounded(
                line.list_amount().minor_units(),
                i128::from(10_000 - order.discount_basis_points()),
                10_000,
            );
        }
        if per_line_via_primitive != order.payable_amount_total().minor_units() {
            per_line_matches = false;
        }

        // ── 路径 B(**错误的那一种**):整单挂牌额 × (1 − 折扣),全程只舍入一次。
        let per_line_at_probe: i64 = order
            .lines()
            .iter()
            .map(|line| {
                scale_rounded(
                    line.list_amount().minor_units(),
                    i128::from(10_000 - PROBE_DISCOUNT_BPS),
                    10_000,
                )
            })
            .sum();
        let whole_at_probe: i64 = scale_rounded(
            order.list_amount_total().minor_units(),
            i128::from(10_000 - PROBE_DISCOUNT_BPS),
            10_000,
        );
        if per_line_at_probe != whole_at_probe {
            diverging_order_total += 1;
            divergence_minor_units_total += per_line_at_probe - whole_at_probe;
        }
    }
    report.push(CheckLine::new(
        "折让额恒 >= 0",
        "全部 >= 0 分",
        &bool_text(discount_non_negative),
        discount_non_negative,
    ));
    report.push(CheckLine::new(
        "逐行折后求和 == 各行应付之和",
        "两者逐单相等",
        &bool_text(per_line_matches),
        per_line_matches,
    ));
    // ★ 第 37 条:上一条的「负向那一半」。
    //   上一条说「领域层给出的是逐行口径」;这一条说「**这批数据真的能分辨两种口径**」。
    //   少了它,上一条就是恒真的:两种实现在这批数据上给出同一个答案,改错了也全绿。
    report.push(CheckLine::new(
        &format!(
            "★ {} 万分点:逐行 ≠ 整单(否则恒真)",
            PROBE_DISCOUNT_BPS
        ),
        "至少 1 单分叉",
        &format!(
            "{} / {} 单分叉,逐行比整单合计 {} 分",
            diverging_order_total,
            simulation_batch.len(),
            divergence_minor_units_total
        ),
        diverging_order_total > 0,
    ));

    report.push(CheckLine::new(
        "封存之后不许改价也不许回滚",
        "回滚被拒 且 改价被拒",
        &format!(
            "回滚 {} / 改价 {}",
            bool_text(sealed_undo_refused),
            bool_text(sealed_reprice_refused)
        ),
        sealed_undo_refused && sealed_reprice_refused,
    ));
}

/// 第 27--29 条:游标不动、仓储张数、扩展单自动进批次。
fn push_cursor_repository_checks(
    report: &mut CheckReport,
    rejection_tally: (usize, usize),
    cursor_before_missing_jump: Option<usize>,
    cursor_after_missing_jump: Option<usize>,
    repository_total: usize,
    batch_total: usize,
    sealed_through_repository: bool,
    sealed_read_back: bool,
) {
    report.push(CheckLine::new(
        "拒绝实证:被拒的条数 == 7",
        "7 条",
        &format!("{} 条(共 {} 条实证)", rejection_tally.1, rejection_tally.0),
        rejection_tally.1 == 7,
    ));
    report.push(CheckLine::new(
        "跳到不存在的版本:游标不动、不计数",
        "游标不变",
        &format!(
            "{} → {}",
            index_text(cursor_before_missing_jump),
            index_text(cursor_after_missing_jump)
        ),
        cursor_before_missing_jump == cursor_after_missing_jump,
    ));
    report.push(CheckLine::new(
        "仓储张数 == 装配张数 + 归档张数",
        "5 张(3 样本+1 扩展+1 归档)",
        &format!("{} 张", repository_total),
        repository_total == 5,
    ));
    report.push(CheckLine::new(
        "扩展单自动进试算批次",
        "3 张(2 样本+1 扩展)",
        &format!("{} 张", batch_total),
        batch_total == 3,
    ));
    report.push(CheckLine::new(
        "仓储给出的是同一份聚合根,不是副本",
        "就地封存后读回仍已封存",
        &format!(
            "取出并封存{} / 读回已封存{}",
            bool_text(sealed_through_repository),
            bool_text(sealed_read_back)
        ),
        sealed_through_repository && sealed_read_back,
    ));
}

/// ★ 本工程(**不含机制层**)每一条体检项对应的「什么输入会让它真的失败」。
///
/// ⚠️ 顺序必须与上面 `push_*` 的调用顺序**逐条对应**:
/// 这是「审计也要被审计」的落点------两条清单对不上就说明有人改了一处忘了另一处。
fn local_falsifiable_lines() -> Vec<(String, String)> {
    vec![
        (
            String::from("流水三态之和 == 申请总条数"),
            String::from("把「无变化」并入「同意」:和仍等于总数,但同意数虚高------这条只盯总数,分态看幕三注解"),
        ),
        (
            String::from("历史版数 == 同意次数 + 1(封存前)"),
            String::from("让被拒的申请也拍一版快照:版数变成 9,这条立刻红(也会让「跳到第 7 版」跳到一个不存在的报价)"),
        ),
        (
            String::from("没有孤儿版本(第 1 版不算)"),
            String::from("在会话里直接 `history.capture` 而不写流水:那一版在流水里查不到出处,孤儿数 > 0"),
        ),
        (
            String::from("自洽性核对:每一版都符合预期"),
            String::from("把 `payable_mismatch_between` 改成恒返回 0:非游标版本也报 0 处,这一条红"),
        ),
        (
            String::from("自洽性核对:非游标版本中没有「假零」"),
            String::from("比对时拿 `recomputed` 自己比自己(传同一个切片):全部报 0,假零数 > 0,这条立刻红"),
        ),
        (
            String::from("每一次装回都做了核对"),
            String::from("在被拒的分支里也 push 一个空核对(或成功分支漏 push):核对次数与装回成功次数不再相等"),
        ),
        (
            String::from("逐步演练:装回不符处数合计为 0"),
            String::from("在 `apply` 里只装回折扣不装回封存标记:回滚到未封存版本后金额对不上,不符处数 > 0"),
        ),
        (
            String::from("自洽性摘要:all_met() 成立"),
            String::from("让某一版的快照金额被改掉:met_total 小于 row_total,all_met 变假(若它只看 met_total,假零那一项会被悄悄吞掉)"),
        ),
        (
            String::from("封存也记一版:版数==同意次数+2"),
            String::from("把封存做成「只改标记不拍快照」:最终版数少一版,而报表上看起来只是「最后一步没记」"),
        ),
        (
            String::from("游标停在最后一版"),
            String::from("让封存之后的撤销竟然成功(去掉封存那道关):游标退到第 4 版,与最终版数不再相等"),
        ),
        (
            String::from("游标在顶:还能退、不能再进"),
            String::from("把 `can_redo` 写成 `cursor + 1 <= len`(越界一格的经典写法):在顶时仍报「能进」,而在顶时重做其实是「未发生」"),
        ),
        (
            String::from("装回动作次数==成功+被拒(无第四条路径)"),
            String::from("新增一条不经 undo/redo/jump 的装回路径(例如对外暴露 `restore_at`):动作次数少于结果次数"),
        ),
        (
            String::from("本轮没有另开分支:分支丢弃 0 条"),
            String::from("在撤销之后立刻改一次价(撤销两步再申请):截断会丢弃 2 条,这一条变红"),
        ),
        (
            String::from("全程自洽性不符 0 处"),
            String::from("在 `apply` 里漏装回某一行的应付金额:那一版装回去之后与重算对不上,不符处数 > 0"),
        ),
        (
            String::from("峰值 == 最终版数(本轮没有截断过)"),
            String::from("把峰值改成「取当前长度」:撤销后再改价时峰值会小于曾经到过的长度,这条红"),
        ),
        (
            String::from("历史字节合计 == 逐版之和"),
            String::from("在 `total_byte_footprint` 里漏掉某一版的分配:合计小于逐版之和;反过来漏掉一版则大于"),
        ),
        (
            String::from("台账:装回结果次数 == 装回动作次数"),
            String::from("新增一条不经 undo/redo/jump 的装回路径:结果次数比动作次数多"),
        ),
        (
            String::from("台账:无版本号 / 指纹不一致"),
            String::from("删掉 `History::restore_at` 里那两行自核对:不忠实的实现一路绿灯,而这两项恒为 0------正是 M2 / M4 盯的事"),
        ),
        (
            String::from("台账:历史长度峰值 >= 当前版数"),
            String::from("把峰值改成「取当前长度」:另开分支截断之后峰值会小于曾经到过的长度"),
        ),
        (
            String::from("台账只增不减"),
            String::from("把某个计数器改成可减(撤销时把 saved 减一):后一份切片小于前一份,`is_monotonic_after` 为否"),
        ),
        (
            String::from("封装的内存代价为 0 字节"),
            String::from("给窄接口快照加一个额外字段:两个口径不再相等,代价不再是 0(也就说明「为省内存放宽可见性」站不住)"),
        ),
        (
            String::from("封装对照实验真的演示成功"),
            String::from("把篡改那一步写成「改完再取改前的值」:改后不符处数会是 0,`all_three_succeeded` 为否"),
        ),
        (
            String::from("机制层自检全部通过"),
            String::from("删掉 `History::restore_at` 里的自核对:M2 / M4 立刻红(这两条就是为它准备的)"),
        ),
        (
            String::from("机制层自检:结论文本与布尔一致"),
            String::from("把 `AuditFinding::verdict_text` 的两支对调(通过说成未通过):布尔仍然全绿,而这一条立刻红------「全绿」正是靠这条才不至于骗人"),
        ),
        (
            String::from("扩展项全部为纯新增(没改既有分层文件)"),
            String::from("为了新增一个审批级别去改 `domain/approval_level.rs`:那一行的「改了既有分层文件」就不再是「否」"),
        ),
        (
            String::from("接口清点:全部只读入口都返回了值"),
            String::from("删掉某一条的调用只留空串:返回值非空计数少一个(报表上那一格只是空白,看起来像没取到数据)"),
        ),
        (
            String::from("显示宽度模型自检全部通过"),
            String::from("把 `horizontal_rule` 写成 `width / 2` 个 `─`:分隔线探针的实测列数立刻对不上"),
        ),
        (
            String::from("舍入恒等式:f(-a,b)==-f(a,b)"),
            String::from("改成裸写 `a / b`(向零截断):-7/2 变成 -3,而 7/2 是 3,恒等式破裂"),
        ),
        (
            String::from("舍入不是向零截断(7/2 应为 4)"),
            String::from("把 `remainder * 2 >= divisor` 改成 `>`:3.5 会退成 3,这条红"),
        ),
        (
            String::from("试算三态之和 == 张数(三次都成立)"),
            String::from("在试算里漏掉 UNCHANGED 分支的计数:三者之和小于张数"),
        ),
        (
            String::from("试算折让只累计同意的那些(一)为 0"),
            String::from("把被拒的单也按目标折扣算折让:内建表下三张全被拒,折让却不是 0 分"),
        ),
        (
            String::from("换一张权限表就能改变裁决"),
            String::from("把权限表写死在领域层:`QuotationPolicy::new` 换表不再影响裁决,两次试算的同意张数相同"),
        ),
        (
            String::from("试算明细条数 == 三态之和(三次都成立)"),
            String::from("给 `entries()` 额外塞一条「汇总行」:明细条数比三态之和多 1(汇总口径与明细口径不再同源)"),
        ),
        (
            String::from("拒绝实证:7 条被拒场景全部命中"),
            String::from("把「无权限记录」那一关挪到「越权」之后:配置缺失被误报成越权,这一条少一个命中"),
        ),
        (
            String::from("折让额恒 >= 0"),
            String::from("把折扣当成加成(用 10000 + 折扣 去缩放):应付大于挂牌,折让为负"),
        ),
        (
            String::from("逐行折后求和 == 各行应付之和"),
            String::from("把 `OrderLine::payable_amount` 的舍入改成向零截断(`a / b` 裸除):与从挂牌额重算的逐行之和差 1 分,这条红"),
        ),
        (
            format!(
                "★ {} 万分点:逐行 ≠ 整单(否则恒真)",
                PROBE_DISCOUNT_BPS
            ),
            String::from("把换夹具数据换成「行挂牌额 × (10000−折扣) 恒能被 10000 整除」的一组:分叉的单变成 0,这条红------那就是恒真回来的那一天"),
        ),
        (
            String::from("封存之后不许改价也不许回滚"),
            String::from("在 `apply` 里去掉封存那道关:已开票的单也能回滚(报表上只是「多了一个版本号」)"),
        ),
        (
            String::from("拒绝实证:被拒的条数 == 7"),
            String::from("把某条被拒场景的输入改写得不再触发(例如折扣改成 0):那一行不再是「被拒」,计数少一条"),
        ),
        (
            String::from("跳到不存在的版本:游标不动、不计数"),
            String::from("把 `jump_to` 的 `position(...)?` 改成 `unwrap_or(0)`:会跳到第 1 版并计数,游标被改动"),
        ),
        (
            String::from("仓储张数 == 装配张数 + 归档张数"),
            String::from("把 `add` 改成查重覆盖:再存一次同号单时总数不增,而「两张不同的单用了同一个单号」被静默吞掉"),
        ),
        (
            String::from("扩展单自动进试算批次"),
            String::from("把试算批次写死成 `same_currency_batch()`:扩展单进不了批次(也就失去了「自动进报表」这一半)"),
        ),
        (
            String::from("仓储给出的是同一份聚合根,不是副本"),
            String::from("把 `find_by_number_mut` 改成返回一个克隆:就地封存会**安静地丢失**,读回来仍是未封存------而这一条是唯一会红的地方"),
        ),
    ]
}

​

输出:

相关推荐
高晶1 小时前
BMS 通信开发实战:从 PMBus 协议到数据采集的完整指南
设计模式·程序员
闲云lazycloud1 小时前
第 1 课:Harness 与 Agent 运行时
人工智能·后端
电子IT笔记1 小时前
老MES登录改造:弱密码和暴破一起治
设计模式
马优晨1 小时前
JAVA 中 VO 实体类是什么意思,为什么要做这个
java·开发语言·状态模式·java vo·java vo是什么
熊哈哈O_o1 小时前
260+异构同步链路:DDL语法自动翻译在大规模数据同步中的实现原理
后端
Aurorar0rua1 小时前
CS50 x 2024 Notes Python - 01
开发语言·python·学习方法
用户9888321871742 小时前
别把 IOptionsSnapshot 注入单例:从生命周期看 .NET 配置读取
后端
姜鱼问生2 小时前
别再 chmod 777 了,用 ACL 给它开一扇窗
后端·算法·架构
仿生joe会梦见漫天的大雪吗2 小时前
CTF Misc 工具选型指南:按题型分类的工具、原理与限制
后端·安全