use std::sync::Arc;
use kernel::{MountSpec, Registry};
use xw_mgmt::audit_cmd::append_plugin_event;
use xwproviders::operation_audit;
use xwtui::plugin_watch::{self, PluginStateEvent};
fn drain(rx: &mut plugin_watch::PluginStatusRx) -> Vec<PluginStateEvent> {
let mut out = Vec::new();
while let Ok(ev) = rx.try_recv() {
out.push(ev);
}
out
}
fn fail(msg: &str) -> ! {
eprintln!("[probe] FAIL: {msg}");
std::process::exit(1);
}
fn main() {
let cwd =
std::env::args().nth(1).map(std::path::PathBuf::from).unwrap_or_else(std::env::temp_dir);
let reg = Arc::new(Registry::new());
let rt = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.expect("tokio current_thread rt");
println!("## S33a 增量流(订阅→mount→最小增量逐条; emit_status 与 Loader::mount_rows 同通路)");
let (tx1, mut rx1) = plugin_watch::plugin_status_channel();
let d1 = plugin_watch::attach(®, tx1);
let (uid1, uid2) = rt.block_on(async {
let u1 = reg
.clone()
.mount(MountSpec { plugin_name: "probe-p1".into(), ..Default::default() })
.await
.expect("mount probe-p1");
let u2 = reg
.clone()
.mount(MountSpec { plugin_name: "probe-p2".into(), ..Default::default() })
.await
.expect("mount probe-p2");
(u1, u2)
});
let evs_a = drain(&mut rx1);
if evs_a.is_empty() {
fail("S33a: 订阅在位但 mount 零增量——watch→通道链断裂");
}
for ev in &evs_a {
println!(
" Δ [{}] {} 载荷={{entryId: {}, phase: {}, at: {}}}",
ev.at,
ev.message(),
ev.entry_id,
ev.phase,
ev.at
);
}
for name in ["probe-p1", "probe-p2"] {
if !evs_a.iter().any(|e| e.entry_id == name && e.phase == "Active") {
fail(&format!("S33a: {name} 未达 Active 终相(NoopPlugin apply 应即时激活)"));
}
}
println!(
" 判读: {} 条增量逐条留痕, p1/p2 终相 Active ✓(载荷三字段结构体级, from/error/drain_timeout 不携带=R4)",
evs_a.len()
);
println!("## S33b 断线(run_disposer→后续 mount 零增量; R4 即时性降级非失真)");
plugin_watch::run_disposer(d1);
let uid3 = rt.block_on(async {
reg.clone()
.mount(MountSpec { plugin_name: "probe-p3".into(), ..Default::default() })
.await
.expect("mount probe-p3")
});
let evs_b = drain(&mut rx1);
if !evs_b.is_empty() {
fail(&format!("S33b: dispose 后仍收到 {} 条增量——断线语义失守", evs_b.len()));
}
println!(" 判读: dispose 后 mount probe-p3(uid={uid3})增量=0 条 ✓(断线=即时性降级, 状态真相无损)");
println!(
"## S33c 重连全量对齐(re-attach→增量恢复→全量对齐块, App::align_plugin_state 同构载荷)"
);
let (tx2, mut rx2) = plugin_watch::plugin_status_channel();
let d2 = plugin_watch::attach(®, tx2);
let uid4 = rt.block_on(async {
reg.clone()
.mount(MountSpec { plugin_name: "probe-p4".into(), ..Default::default() })
.await
.expect("mount probe-p4")
});
let evs_c = drain(&mut rx2);
if evs_c.is_empty() {
fail("S33c: re-attach 后增量未恢复——重连链断裂");
}
println!(
" 重连后增量 {} 条恢复 ✓({})",
evs_c.len(),
evs_c.iter().map(|e| e.message()).collect::<Vec<_>>().join("; ")
);
let mounted: [(&str, u64); 4] =
[("probe-p1", uid1), ("probe-p2", uid2), ("probe-p3", uid3), ("probe-p4", uid4)];
let rows: Vec<PluginStateEvent> = mounted
.iter()
.map(|(name, uid)| PluginStateEvent {
entry_id: (*name).into(),
phase: reg
.phase_of(*uid)
.map(|p| format!("{p:?}"))
.unwrap_or_else(|| "<无 fiber>".into()),
at: plugin_watch_iso_now(),
})
.collect();
println!(" plugin state 全量对齐({} 行, Loader 唯一权威)", rows.len());
for r in &rows {
println!(" [{}] {}", r.at, r.message());
}
if rows.iter().any(|r| r.phase != "Active") {
fail("S33c: 全量对齐快照存在非 Active 行——phase_of 与 mount 终相不一致");
}
println!(" 判读: 对齐块 4 行全 Active ✓(不覆盖不静默, 权威重同步语义)");
plugin_watch::run_disposer(d2);
println!("## S33d M-e 联立(在线装载留痕随审计时间线; 六字段域, source=tui 运行态面)");
for (i, (name, uid)) in mounted.iter().enumerate() {
append_plugin_event(
&cwd,
"load",
name,
i as u64,
"tui",
serde_json::json!({ "phase": "Active", "fiber_uid": uid }),
);
}
let path = operation_audit::default_path(&cwd);
let events = operation_audit::read_events(&path)
.unwrap_or_else(|e| fail(&format!("S33d: 审计回读失败: {e}")));
let plugin_domain = events
.iter()
.filter(|e| e.payload.get("domain").and_then(|d| d.as_str()) == Some("plugin"))
.count();
if plugin_domain != mounted.len() {
fail(&format!(
"S33d: 审计 plugin 域 {} 条 ≠ 装载 {} 条——在线留痕缺口",
plugin_domain,
mounted.len()
));
}
println!(
" 判读: {} 条 load 事件落审计时间线(domain=plugin 六字段域, revision 单调 0..{})✓",
plugin_domain,
mounted.len() - 1
);
println!(" 时间线回读(operation_audit::print_timeline):");
operation_audit::print_timeline(&path, None);
println!("[probe] S33a-d 全绿——SW.3.3 订阅链活体+载荷纪律+断线/重连/对齐+M-e 联立实证");
}
fn plugin_watch_iso_now() -> String {
let d = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap_or_default();
format!("{}s UTC", d.as_secs())
}