复审 r2 P2-1:界面无条件断言「已停手并回滚:没有留下半包,也没有覆盖已有文件」,而两条路径下
这句话是假的——①取消来得太晚(落在最后一个检查点之后)时管线已经跑完,用户的同名文件被覆盖、
实例已登记;②回滚本身没做完(`rolled_back=false`)。core 一直是诚实的,是 presenter 把报告丢了:
`cancel.load()` 早退 + `cancel_pack` bump 代次后 `handle` 按代次丢弃。
按"接通真相"做(不是改软话):
- **终态一定发出**:`import::run` 去掉 `cancel` 的无条件早退,收尾抽成 `finish`(清自建空目录 +
无条件 `send(PackEvent::Report)`);取消标记在管线返回后**再读一次**,作为"太晚"的唯一证据。
- **终态穿透代次**:`HostPackState::terminal_epochs` 记下 `cancel_pack` 作废的那个代次,
`handle` 对它**只放行一条 `PackEvent::Report`**(进度事件照旧按代次丢,`fresh_cancel` 起新
一轮时清空)。这是路径 A 的成因与修法。
- **DTO 三档**(tower 批准扩 scope):`ImportStatusView` 加 `Cancelled`;新增
`ImportCancelView { NotRequested, RolledBack, RollbackIncomplete, TooLate }` 挂在
`ImportReportView::cancel` 上——已回滚 / 回滚没做完 / 取消太晚,三档各自可判。
`PackEvent::Report` 到达时清掉 `ImportState.cancelled`(它现在只是"取消后还没有结果"的占位)。
- **界面按结局分支**:标题 `PackStatusCancelled`(已取消 — 已回滚)/ `PackCancelIncomplete`
(已取消 — 回滚没做完)/ 取消太晚时保留真实状态标题并另起一句 `PackCancelTooLate`
(实例会保留、同名文件可能已被覆盖);占位的 `PackCancelled` 改成"正在停手,真实结果随后给出"。
图标:`Close`(描边,页面对填充字形有守门)/ 回滚不完整用 `Warn`,一档都不用 `Role::Error`。
守门与变异:
- 新增路径 A 用例 `a_late_cancel_still_delivers_the_real_outcome_to_the_ui`:真管线把取消置在
**最后一条 Commit 进度**上(之后没有检查点)⇒ core 报 `Success`/未回滚、用户的 `mods/a.jar`
确实被覆盖;再 `cancel_pack`(代次 +1 并记终态)→ `finish` → `handle`,断言界面收到
`status == Success` + `rolled_back == false` + `cancel == TooLate`,且同代次的进度事件仍被丢。
- 变异①:`handle` 恢复"代次不符一律丢" ⇒ 该用例红("取消太晚时,真实结果必须到达界面")。
- 变异②:`finish` 恢复"取消就早退" ⇒ 该用例红(另带 P2-2 那条也红)。
- app-iced 新增 `model/tests/cancel.rs`:三档标题互不相同 + 「太晚」必须有那句补充说明 +
已回滚不许显示成「部分成功」。
验证(CARGO_TARGET_DIR=C:/Temp/ull-target/wt-194):
`cargo test -p unlucky-core -p unlucky-presenter -p unlucky-app-iced` = 2185 passed / 0 failed;
`-p unlucky-i18n` = 31 / 0;clippy 四 crate = 0 warning / 0 error。
76 lines
3.7 KiB
Rust
76 lines
3.7 KiB
Rust
//! presenter ↔ core/agent 的 IPC 边界(01c §5 纪律)。
|
||
//!
|
||
//! 这里只允许出现「扁平 DTO / 事件 / 指令」:本 crate 的 DTO 里不得出现 `unlucky_core::*`
|
||
//! 或 `use unlucky_agent::*` 的内部类型。core/agent 侧的 host 层负责把自身类型翻译成本模块的类型,
|
||
//! 反向的 [`AppCommand`] 也一样。P0 阶段由 [`crate::mock`] 的假后端实现 [`Backend`] 驱动骨架,
|
||
//! P3 起由 [`crate::host`] 的真实后端驱动全部页面。
|
||
//!
|
||
//! 结构:**按领域拆子模块**(instances / versions / logs / agent / accounts / java /
|
||
//! settings / install / notices / content / events),全量 `pub use` 出去,调用方依旧写
|
||
//! `crate::dto::InstanceSummary` 这类路径。
|
||
//! 契约说明(字段口径、事件顺序、错误语义)见 `DevDocs/SubAgentsTalk/app-DTO通道约定.md`;
|
||
//! UI 侧的唯一入口与 iced 接线用法见 crate 文档(`src/lib.rs`)。
|
||
//!
|
||
//! 全部跨界类型 `Serialize + Deserialize`(AGENTS §6):事件与快照是 IPC 契约,
|
||
//! 序列化能力由 derive 钉住,`dto` 的单测做 round-trip 断言。
|
||
|
||
mod accounts;
|
||
mod agent;
|
||
mod content;
|
||
mod events;
|
||
mod install;
|
||
mod instances;
|
||
mod java;
|
||
// M157: 实例启动参数(启动参数区的读取视图 + 写回补丁)
|
||
mod launch_args;
|
||
mod launch_failure;
|
||
mod logs;
|
||
mod notices;
|
||
// M113: import/export —— 整合包导入/导出的 DTO(M111/M112 管线的 IPC 面)
|
||
mod pack;
|
||
mod settings;
|
||
// M159: 自更新(检查结论 / 候选 / 就位状态)
|
||
mod update;
|
||
mod versions;
|
||
|
||
pub use accounts::{
|
||
looks_like_jwt, redact, valid_offline_name, AccountKind, AccountNotice, AccountNoticeCode,
|
||
AccountView, AuthlibLoginView, AuthlibRequest, BrowserLoginNote, DeviceLoginPhase,
|
||
DeviceLoginView, LoginFailure, SkinImage, REDACTED,
|
||
};
|
||
pub use agent::{AgentEvent, ChatMessage, ChatRole, ConfirmRequest, Sensitivity, ToolCallView};
|
||
pub use content::{
|
||
loader_facet, ContentDetail, ContentDetailRequest, ContentFailure, ContentFailureKind,
|
||
ContentHit, ContentInstallRequest, ContentKind, ContentQuery, ContentResults, ContentSort,
|
||
ContentSource, ContentState, ContentVersionView,
|
||
};
|
||
pub use events::{AppCommand, AppEvent, Backend, CoreEvent, LaunchFinished, LiveLogBatch};
|
||
pub use install::{
|
||
derive_speed, human_bytes, InstallFailureKind, InstallFailureView, InstallProgressView,
|
||
InstallStage,
|
||
};
|
||
pub use instances::{
|
||
CreateRequest, InstanceId, InstanceRuntime, InstanceSummary, LaunchFailureCause,
|
||
LaunchFailureStage, LaunchFailureView, LaunchStage, LoaderInfo, LoaderKind, Progress,
|
||
};
|
||
pub use java::{JavaChainOutcome, JavaChainStep, JavaPageView, JavaRuntimeView, JavaVendorView};
|
||
pub use launch_args::{LaunchArgsPatch, LaunchArgsView};
|
||
pub use logs::{Diagnosis, DiagnosisReport, LogLevel, LogLine, LogOutcome, LogSession, SessionId};
|
||
pub use notices::{NoticeLevel, NoticeView};
|
||
// M113: import/export
|
||
pub use pack::{
|
||
ConflictChoiceView, ConflictDecisionView, ConflictDecisionsView, ConflictFileView,
|
||
ConflictReasonView, ConflictSourceView, ExportClassView, ExportDoneView, ExportFileView,
|
||
ExportPreviewView, ExportReasonView, ExportRequestView, ExportState, FileActionView,
|
||
ImportCancelView, ImportConflictView, ImportErrorView, ImportFailureStageView,
|
||
ImportProgressView, ImportReportView, ImportRequestView, ImportScanView, ImportStageView,
|
||
ImportState, ImportStatusView, ImportedFileView, MissingFileView, MissingReasonView,
|
||
PackCommand, PackEvent, PackFormatView, PackState, ProbeView,
|
||
};
|
||
pub use settings::{SettingControl, SettingGroupView, SettingRowView};
|
||
// M159: 自更新
|
||
pub use update::{
|
||
ReadyUpdate, UpdateBanner, UpdateCandidateView, UpdateFailureView, UpdateOutcome, UpdateView,
|
||
};
|
||
pub use versions::{AncientKind, VersionCategory, VersionKind, VersionSummary};
|