feat: Update project documentation and workflow to reflect changes in task dispatching and testing processes
- Changed references from "kilo" to "Agent 子代理" in various documentation files to align with the new task dispatching method. - Updated CLAUDE.md to reflect the new agent-based execution model and modified task dispatch template. - Revised PROGRESS.md to indicate successful testing and acceptance of M1.2 with detailed results. - Enhanced communication and workflow documentation to clarify the use of Agent 子代理 for real-time collaboration and task management. - Updated team member soul files with lessons learned from recent testing and integration experiences. - Refactored test files to remove unused code and improve clarity, ensuring compliance with zero warning standards. - Documented specific experiences and lessons learned during M1.2 testing, including handling of edge cases and configuration validation.
This commit is contained in:
@@ -5,7 +5,7 @@
|
|||||||
## 你的角色
|
## 你的角色
|
||||||
|
|
||||||
你是副 CEO,与主 CEO(陈逸飞/Claude Opus 4.6)**权限完全相同**。
|
你是副 CEO,与主 CEO(陈逸飞/Claude Opus 4.6)**权限完全相同**。
|
||||||
所有规则、团队、状态、kilo 模板均以 `CLAUDE.md` 为准。
|
所有规则、团队、状态、派发模板均以 `CLAUDE.md` 为准。
|
||||||
|
|
||||||
## 额外权限(主 CEO 同样拥有)
|
## 额外权限(主 CEO 同样拥有)
|
||||||
- ✅ 执行失败升级协议(L1-L4)
|
- ✅ 执行失败升级协议(L1-L4)
|
||||||
@@ -13,13 +13,11 @@
|
|||||||
- ✅ 拒绝无证据交付
|
- ✅ 拒绝无证据交付
|
||||||
|
|
||||||
## 资源限制
|
## 资源限制
|
||||||
- **kilo 进程总数上限 12 个**(含你自己)
|
- **并行子代理总数上限 12 个**(含你自己)
|
||||||
- 启动新 kilo 前先 `ps aux | grep kilo` 检查进程数
|
|
||||||
|
|
||||||
## 监督职责
|
## 监督职责
|
||||||
1. 每 60 秒检查一次(循环 10 次后退出)
|
1. 每 60 秒检查一次(循环 10 次后退出)
|
||||||
2. 每次检查:
|
2. 每次检查:
|
||||||
- 进程数: `ps aux | grep kilo`
|
|
||||||
- 新 commit: `git log --oneline -3`
|
- 新 commit: `git log --oneline -3`
|
||||||
- 编译: `export PATH=... && cargo check`
|
- 编译: `export PATH=... && cargo check`
|
||||||
- 改动: `git status --short`
|
- 改动: `git status --short`
|
||||||
|
|||||||
@@ -1,40 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# CEO持续监督循环脚本
|
|
||||||
|
|
||||||
WORKDIR="/home/showen/Showen/ShowenV2"
|
|
||||||
LOG_FILE="/tmp/ceo_loop.log"
|
|
||||||
CHECK_INTERVAL=1800 # 30分钟 = 1800秒
|
|
||||||
|
|
||||||
echo "CEO监督循环启动 - $(date)" | tee -a "$LOG_FILE"
|
|
||||||
|
|
||||||
while true; do
|
|
||||||
echo "" | tee -a "$LOG_FILE"
|
|
||||||
echo "========================================" | tee -a "$LOG_FILE"
|
|
||||||
echo "CEO检查时间: $(date)" | tee -a "$LOG_FILE"
|
|
||||||
echo "========================================" | tee -a "$LOG_FILE"
|
|
||||||
|
|
||||||
# 运行CEO检查
|
|
||||||
cd "$WORKDIR"
|
|
||||||
kilo run -m claude/claude-opus-4-6 --auto --dir "$WORKDIR" "你是陈逸飞,ShowenV2的CEO。
|
|
||||||
|
|
||||||
这是定期监督检查。请执行以下操作:
|
|
||||||
|
|
||||||
1. 读取 TEAM_CHAT.md 最新内容,查看团队更新
|
|
||||||
2. 检查 git log,看是否有新提交
|
|
||||||
3. 检查运行中的 kilo 进程(ps aux | grep kilo)
|
|
||||||
4. 评估当前进展和问题
|
|
||||||
5. 在 TEAM_CHAT.md 记录本次检查结果
|
|
||||||
6. 如有需要,给团队新的指示
|
|
||||||
|
|
||||||
记住你的角色:
|
|
||||||
- ✅ 评审结果,给出方向
|
|
||||||
- ✅ 识别阻塞,提供决策
|
|
||||||
- ❌ 不亲自写代码
|
|
||||||
- ❌ 不微观管理
|
|
||||||
|
|
||||||
完成后提交 git commit。" 2>&1 | tee -a "$LOG_FILE"
|
|
||||||
|
|
||||||
echo "" | tee -a "$LOG_FILE"
|
|
||||||
echo "CEO检查完成,等待 $CHECK_INTERVAL 秒..." | tee -a "$LOG_FILE"
|
|
||||||
sleep "$CHECK_INTERVAL"
|
|
||||||
done
|
|
||||||
@@ -120,9 +120,9 @@ agent 连续失败时按以下等级升级压力和强制动作:
|
|||||||
- 新功能必须附带测试。
|
- 新功能必须附带测试。
|
||||||
- P0 问题必须当天修复。
|
- P0 问题必须当天修复。
|
||||||
|
|
||||||
## kilo 使用规范
|
## 任务派发规范(Agent 子代理)
|
||||||
- 不读大 diff,优先阅读必要文件和局部上下文。
|
- 不读大 diff,优先阅读必要文件和局部上下文。
|
||||||
- 命令越简单越好,减少复杂链式操作。
|
- 指令越简单越好,减少复杂链式操作。
|
||||||
- **派发任务时必须在消息中注入能动性期望和验证要求**(参考派发模板)。
|
- **派发任务时必须在消息中注入能动性期望和验证要求**(参考派发模板)。
|
||||||
|
|
||||||
## 执行纪律
|
## 执行纪律
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
## 恢复步骤
|
## 恢复步骤
|
||||||
|
|
||||||
1. 读 `CLAUDE.md`(Claude Code 自动加载) — CEO 身份 + 团队 + 规则 + 状态 + kilo 模板
|
1. 读 `CLAUDE.md`(Claude Code 自动加载) — CEO 身份 + 团队 + 规则 + 状态 + 派发模板
|
||||||
2. 检查 `.showen/TEAM_CHAT.md` — 团队最新动态
|
2. 检查 `.showen/TEAM_CHAT.md` — 团队最新动态
|
||||||
3. 按需读 `souls/chen-yifei.md` — CEO 深层经验
|
3. 按需读 `souls/chen-yifei.md` — CEO 深层经验
|
||||||
4. 其他文件按 `CLAUDE.md` 文件导航表按需加载
|
4. 其他文件按 `CLAUDE.md` 文件导航表按需加载
|
||||||
|
|||||||
@@ -2571,3 +2571,151 @@ P0 问题已解决,DevicePlugin 现已完全集成到 ShowenV2 运行时!
|
|||||||
项目判断:
|
项目判断:
|
||||||
- 当前文档已足够支撑 Flutter 技术方案设计、UI 细化与开发排期。
|
- 当前文档已足够支撑 Flutter 技术方案设计、UI 细化与开发排期。
|
||||||
- 后续需要在正式开发前冻结客户端共享数据模型,并安排一次 API/WebSocket/BLE 联调校准。
|
- 后续需要在正式开发前冻结客户端共享数据模型,并安排一次 API/WebSocket/BLE 联调校准。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
[2026-07-02] 周雅婷(测试工程师) → 陈逸飞(CEO): M1.2 目标机验收
|
||||||
|
|
||||||
|
**设备 HEAD**: 5770b7007c35f283adb462ca53517f02faab95b1 (chore: remove unused Config type alias, add deny_unknown_fields to remaining config structs) — 已从 Windows master 经 git bundle 同步(原落后 20 提交,fast-forward,无冲突;设备本地未提交改动仅 configs/dog_state_machine.json,未触碰)
|
||||||
|
|
||||||
|
**cargo check --workspace --all-targets**: 编译通过(Finished dev profile, 1m 22s),但有 3 个 warning,全部在新测试文件(src/ 零 warning):
|
||||||
|
- tests/m1_2_http.rs:141 — method `sender` is never used
|
||||||
|
- tests/m1_2_dynamic_plugin.rs:14 — unused imports: `Destination` and `Envelope`
|
||||||
|
- tests/m1_2_dynamic_plugin.rs:87 — function `manifest_with_caps` is never used
|
||||||
|
|
||||||
|
**cargo test --workspace --no-fail-fast** 统计(/tmp/m12_acceptance3.log):
|
||||||
|
```
|
||||||
|
Running unittests src/lib.rs (showen_example_plugin)
|
||||||
|
test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 5.01s
|
||||||
|
Running unittests src/lib.rs (showen_plugin_sdk)
|
||||||
|
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
|
||||||
|
Running unittests src/lib.rs (showen_v2)
|
||||||
|
test result: ok. 105 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.17s
|
||||||
|
Running unittests src/main.rs (showen_v2)
|
||||||
|
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
|
||||||
|
Running tests/m1_2_dynamic_plugin.rs
|
||||||
|
test result: ok. 15 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.02s
|
||||||
|
Running tests/m1_2_http.rs
|
||||||
|
test result: FAILED. 11 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.02s
|
||||||
|
Running tests/m1_2_service_manager.rs
|
||||||
|
test result: ok. 8 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.02s
|
||||||
|
Doc-tests showen_plugin_sdk
|
||||||
|
test result: ok. 0 passed; 0 failed; 13 ignored; 0 measured; 0 filtered out; finished in 0.01s
|
||||||
|
Doc-tests showen_v2
|
||||||
|
test result: ok. 0 passed; 0 failed; 4 ignored; 0 measured; 0 filtered out; finished in 0.00s
|
||||||
|
```
|
||||||
|
**总计: 146 passed / 1 failed / 17 ignored (doc-tests)**(注:m1_2_http 实际 12 个测试,非记录中的 9 个)
|
||||||
|
|
||||||
|
**唯一失败测试**: `test_empty_playlist_does_not_panic` (tests/m1_2_http.rs)
|
||||||
|
```
|
||||||
|
thread 'test_empty_playlist_does_not_panic' (8196) panicked at tests/m1_2_http.rs:102:53:
|
||||||
|
test config should load: playlist 不能为空
|
||||||
|
```
|
||||||
|
根因分析(未修改,仅上报):该测试用空 playlist 构造配置并期望 `AppConfig::from_file` 成功,但 src/core/config.rs:334 的校验 `bail!("playlist 不能为空")` 自 init 提交(23f4d46)起就存在——空 playlist 配置从设计上就无法通过加载。属测试前提错误(测试从未在任何机器实跑过),非产品回归。修复归属请 CEO 派人裁决(改测试预期 Err 或放宽校验)。
|
||||||
|
|
||||||
|
**过程事件**: 首轮 cargo test 因设备磁盘满失败(ld: final link failed: No space left on device,根分区 98%)。已清理项目自身构建产物:target/debug/incremental (1.6G) + 3月14日过期 deps 大文件 (~640M) + 同步用 bundle,恢复至 2.7G 可用后重跑成功。未动项目外任何文件;服务所用 target/release/showen_v2 未受影响。
|
||||||
|
|
||||||
|
**现场恢复**: showen_v2.service 已重启,is-active=active,单实例 (pid 10192, target/release/showen_v2)。
|
||||||
|
|
||||||
|
**第二轮(返工后)[2026-07-03] 周雅婷 → 陈逸飞(CEO): M1.2 最终验收 — 全绿**
|
||||||
|
|
||||||
|
变更文件(赵雨薇/张明远返工,Windows 未提交版本,经 scp 覆盖到设备,sha256 两端一致):
|
||||||
|
- tests/m1_2_http.rs (b09cc3f0...) — test_empty_playlist_does_not_panic 重写为 test_empty_playlist_rejected + 删死代码 sender()
|
||||||
|
- tests/m1_2_dynamic_plugin.rs (aa75dfc6...) — 删未用 import 和 manifest_with_caps
|
||||||
|
|
||||||
|
**cargo check --workspace --all-targets**: Finished dev profile in 1m 31s,`grep -cE "^warning" /tmp/m12_acceptance4.log` = **0(零 warning)**
|
||||||
|
|
||||||
|
**cargo test --workspace**(/tmp/m12_acceptance4.log,Finished test profile 7m 58s):
|
||||||
|
```
|
||||||
|
Running unittests src/lib.rs (showen_example_plugin)
|
||||||
|
test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 5.00s
|
||||||
|
Running unittests src/lib.rs (showen_plugin_sdk)
|
||||||
|
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
|
||||||
|
Running unittests src/lib.rs (showen_v2)
|
||||||
|
test result: ok. 105 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.38s
|
||||||
|
Running unittests src/main.rs (showen_v2)
|
||||||
|
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
|
||||||
|
Running tests/m1_2_dynamic_plugin.rs
|
||||||
|
test result: ok. 15 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.05s
|
||||||
|
Running tests/m1_2_http.rs
|
||||||
|
test result: ok. 12 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.06s
|
||||||
|
Running tests/m1_2_service_manager.rs
|
||||||
|
test result: ok. 8 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.06s
|
||||||
|
Doc-tests showen_plugin_sdk
|
||||||
|
test result: ok. 0 passed; 0 failed; 13 ignored; 0 measured; 0 filtered out; finished in 0.00s
|
||||||
|
Doc-tests showen_v2
|
||||||
|
test result: ok. 0 passed; 0 failed; 4 ignored; 0 measured; 0 filtered out; finished in 0.00s
|
||||||
|
```
|
||||||
|
**总计: 147 passed / 0 failed / 17 ignored(doc-tests),test_empty_playlist_rejected ... ok(log 208 行)**
|
||||||
|
|
||||||
|
现场恢复:showen_v2.service 重启后 is-active=active,单实例 (pid 12896, target/release)。
|
||||||
|
磁盘:开跑前 1001M,清 incremental(958M) 后 2.0G,跑完剩 1.2G。
|
||||||
|
|
||||||
|
⚠️ 注意:设备上两个测试文件当前与 git HEAD (5770b700) **不一致**(scp 的未提交返工版)。Windows 提交后需再同步设备(bundle 或重新 scp),否则下次设备端 git 操作会看到脏文件。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## [2026-07-03] 王浩然(网络工程师) → 陈逸飞(CEO): M1.2 风险3 消息链路核查报告
|
||||||
|
|
||||||
|
纯代码审计,零代码改动。范围:`src/core/message.rs` 的 Message enum 全部 17 个变体 + plugin-sdk 镜像。判定标准:生产代码中"至少一个构造点 + 一个匹配点";测试文件构造不算生产者。
|
||||||
|
|
||||||
|
### 一、全量核查表(17/17 变体)
|
||||||
|
|
||||||
|
路由背景:ServiceManager 主循环 `src/core/service_manager.rs:356-383`,按 Destination 分三路:Plugin(id)→deliver_to_plugin(:370)、Broadcast→broadcast_message(:373)、Manager→handle_manager_message(:376)。示例插件 plugins/example-plugin 是动态参考模板,其消费点单独标注。
|
||||||
|
|
||||||
|
| # | 变体 | 生产者(生产代码) | 消费者(生产代码) | 判定 |
|
||||||
|
|---|------|------------------|------------------|------|
|
||||||
|
| 1 | PlayerCommand | src/core/dispatch.rs:32-52(BLE 文本命令,经 src/plugins/ble/gatt.rs:120-124 实际发送);src/plugins/http/routes.rs:236,247,260,276,298,331 | src/plugins/video/mod.rs:145;示例插件 lib.rs:517 | ✅ 闭环 |
|
||||||
|
| 2 | PlayerStatus | src/plugins/video/mod.rs:54, 330 | src/plugins/http/mod.rs:334;Manager 转发 service_manager.rs:770;示例插件 lib.rs:520 | ✅ 闭环 |
|
||||||
|
| 3 | Trigger | src/core/dispatch.rs:67;src/plugins/http/routes.rs:347,362 | src/plugins/video/mod.rs:187;示例插件 lib.rs:523 | ✅ 闭环 |
|
||||||
|
| 4 | StateChanged | src/plugins/video/mod.rs:76, 351 | src/plugins/http/mod.rs:346;Manager 转发 service_manager.rs:773;示例插件 lib.rs:526 | ✅ 闭环 |
|
||||||
|
| 5 | ScreenLockRequest | src/plugins/video/mod.rs:156, 167 | src/plugins/screen/mod.rs:104;示例插件 lib.rs:532 | ✅ 闭环 |
|
||||||
|
| 6 | CursorVisibility | **无**(仅测试构造 src/core/tests.rs:1521) | src/plugins/screen/mod.rs:111;示例插件 lib.rs:535 | ⚠️ 有消费无生产 |
|
||||||
|
| 7 | WifiCommand | src/core/dispatch.rs:75-100(BLE 经 gatt.rs:120-124 发送);src/plugins/http/routes.rs:966 | src/plugins/wifi/mod.rs:321 | ✅ 闭环 |
|
||||||
|
| 8 | WifiResult | src/plugins/wifi/mod.rs:97 | Manager 转发 service_manager.rs:767;src/plugins/ble/mod.rs:120;src/plugins/http/mod.rs:333;示例插件 lib.rs:541 | ✅ 闭环 |
|
||||||
|
| 9 | **WifiProvisioned** | **无**(仅测试构造 src/core/tests.rs:1534) | Manager 转发臂 service_manager.rs:782(死路径,永不触发);示例插件 lib.rs:544 | ❌ 有消费无生产(Phase 2 占位) |
|
||||||
|
| 10 | ConfigReloaded | src/core/service_manager.rs:792 | src/plugins/http/mod.rs:340;src/plugins/video/mod.rs:197;示例插件 lib.rs:554 | ✅ 闭环 |
|
||||||
|
| 11 | ConfigReloadRequest | src/core/dispatch.rs:107(BLE config_reload);src/plugins/http/routes.rs:492, 782 | src/core/service_manager.rs:785 | ✅ 闭环 |
|
||||||
|
| 12 | Shutdown | **初始生产者无**(仅测试注入;dynamic_plugin.rs:348 亦在 #[cfg(test)] 内);Manager 转发 service_manager.rs:765 | ble/mod.rs:117;screen/mod.rs:112;http/mod.rs:358;video/mod.rs:223;device/mod.rs:139;示例插件 lib.rs:566 | ⚠️ 消费者齐全,生产环境无初始触发者(见延伸发现①) |
|
||||||
|
| 13 | PluginReady | src/plugins/video/mod.rs:136;src/plugins/http/mod.rs:305;src/plugins/ble/gatt.rs:343;示例插件 lib.rs:169 | Manager 转发 service_manager.rs:799;src/plugins/http/mod.rs:357(BLE ready 门控) | ✅ 闭环 |
|
||||||
|
| 14 | DeviceCommand | src/plugins/screen/mod.rs:30, 41, 52;示例插件 lib.rs:227 | src/plugins/device/mod.rs:119 | ✅ 闭环 |
|
||||||
|
| 15 | DeviceResponse | src/plugins/device/mod.rs:134(Broadcast) | 核心静态插件**无消费者**(screen 发命令后不读响应);仅示例插件 lib.rs:576 | ⚠️ 弱闭环(见延伸发现②) |
|
||||||
|
| 16 | **DeviceEvent** | **无**(device/mod.rs 全文件不构造;DeviceBackend trait backend.rs:52-99 只有 name/init/handle_command/capabilities/shutdown 五个方法,架构上无事件上报通道) | 示例插件 lib.rs:606 | ❌ 有消费无生产(Phase 2 占位) |
|
||||||
|
| 17 | Custom | http/routes.rs:1873(plugin_switch), 1908(plugin_install), 1944(send_plugin_command,被 enable:1822 / disable:1833 / rollback:1844-1851 / check-updates:1925-1933 共用);service_manager.rs:752(plugin_states 广播);示例插件多处(lib.rs:211,273,307…) | service_manager.rs:803-875(6 种 kind 全处理);http/mod.rs:359(plugin_states);示例插件 lib.rs:609 | ✅ 闭环 |
|
||||||
|
|
||||||
|
plugin-sdk 镜像(plugin-sdk/src/lib.rs:70-149)与主库 17 个变体一一对应,JSON 兼容,无脱节。
|
||||||
|
|
||||||
|
### 二、WifiProvisioned / DeviceEvent 专项结论
|
||||||
|
|
||||||
|
**WifiProvisioned = 有消费无生产,判定 Phase 2 占位,非回归缺陷。**
|
||||||
|
- 定义:src/core/message.rs:45;SDK 镜像 plugin-sdk/src/lib.rs:116。
|
||||||
|
- 全仓生产代码零构造点。wifi 插件 connect 成功只发 `WifiResult`(wifi/mod.rs:94-98),BLE 配网链路是 gatt.rs:120 → dispatch.rs → `WifiCommand::Connect`,均不产生 WifiProvisioned。
|
||||||
|
- 消费侧:service_manager.rs:782 的转发臂是死代码路径(上游无人发);示例插件 lib.rs:544 在白等。
|
||||||
|
- **风险点**:SDK 文档 plugin-sdk/src/lib.rs:522 教第三方插件开发者监听此消息——当前版本永不触发,会误导开发者。
|
||||||
|
- 建议:入 Phase 2 backlog——wifi 插件 connect_network 成功后取 ssid+ip 补发;短期在 SDK 文档注明"当前版本未触发"。不建议删(BLE 配网完成通知是合理设计意图)。
|
||||||
|
|
||||||
|
**DeviceEvent = 有消费无生产,判定 Phase 2 占位,非回归缺陷。**
|
||||||
|
- 定义:src/core/message.rs:62, 221-234(6 个事件变体);SDK 镜像 lib.rs:139, 273。
|
||||||
|
- DevicePlugin(device/mod.rs 全文件)只处理 DeviceCommand→回 DeviceResponse(:119-137),从不构造 DeviceEvent。更根本的是 DeviceBackend trait(backend.rs:52-99)没有任何事件轮询/回调接口——**生产者在架构层面还不存在**,与 CLAUDE.md "DevicePlugin 阶段三(触摸/音频/多平台)" 规划一致。
|
||||||
|
- 消费侧:仅示例插件 lib.rs:606。
|
||||||
|
- 建议:标 Phase 2 backlog,待 DeviceBackend 增加事件通道时接入;不删(README、docs/DEVICE_PLUGIN_DESIGN.md:92 已承诺该接口)。
|
||||||
|
- DeviceCommand/DeviceResponse 一族其余两个:DeviceCommand 闭环 ✅;DeviceResponse 见延伸发现②。
|
||||||
|
|
||||||
|
### 三、与赵雨薇旁证结论的异同(tests/m1_2_http.rs:6-18)
|
||||||
|
|
||||||
|
| 她的结论 | 核查结果 |
|
||||||
|
|---------|---------|
|
||||||
|
| enable/disable 闭环已修 | ✅ **证实**。routes.rs:1822/1833 → Custom → service_manager.rs:805/814 → set_plugin_enabled(:401-430) → broadcast_plugin_states(:750) → http/mod.rs:359 读回。全链路通。 |
|
||||||
|
| plugin_rollback/switch/install "仅发送消息,ServiceManager 侧仅打印日志,尚无完整业务逻辑" | ❌ **已过时,推翻**。三者现均为完整实现:rollback_plugin(service_manager.rs:432-447,真实回滚)、switch_plugin_version(:617-663,版本切换+热替换)、install_plugin(:665-728,repo 下载+registry 更新+加载)。张明远 #25 修复(handle_manager_message Custom 分支)已落地,她的注释写于修复前。**建议 M1.2 收尾时顺手更新 tests/m1_2_http.rs:10,17-18 的过时注释**(本次未动)。 |
|
||||||
|
| plugin_check_updates 同上"仅打印日志" | ⚠️ **部分成立**。check_plugin_updates(:730-748) 会真实查询 repo.check_update,但结果只 println(:736-743),不回传 HTTP/不广播——调用方只收到"命令已发送"(routes.rs:1949),拿不到检查结果。结果回传链路确实断在日志,属功能不完整(非崩溃性缺陷),建议 Phase 2 把结果并入 plugin_states 或单独 Custom 广播。 |
|
||||||
|
| WifiProvisioned/DeviceEvent(她未核查) | 本次补齐:均为"有消费无生产(Phase 2 占位)",非回归缺陷,与 docs/M1.2_TEST_PLAN.md:17 的风险预判一致。 |
|
||||||
|
|
||||||
|
### 四、延伸发现(主动排查,均不阻塞 M1.2)
|
||||||
|
|
||||||
|
① **Shutdown 无生产环境初始触发者**:main.rs Ctrl+C handler(:117-120) 只置 AtomicBool,不注入 Message::Shutdown;HTTP 也无 shutdown 路由。而 manager.run() 阻塞在 rx.recv()(:361),Ctrl+C 后要等**下一条任意消息**到达才能退出主循环。行为性瑕疵,建议 Phase 2 加"信号→Shutdown 消息"桥接。
|
||||||
|
② **DeviceResponse 弱闭环**:device 广播响应(:134),但核心静态插件无人读——screen 发 DeviceCommand(:30,41,52) 后不看结果,`DeviceResponse::Error`(:125) 广播后无人记录,设备层故障静默。建议至少在一处记录 Error 响应,或在 screen 注明 fire-and-forget 语义。
|
||||||
|
③ **CursorVisibility 有消费无生产**:screen/mod.rs:111 在等一条没人发的消息;实际光标控制链路已改走 screen→DeviceCommand::SetCursorVisible(:52)→device。建议:删变体或补 HTTP/dispatch 生产者(低优先级,倾向 Phase 2 一并清理)。
|
||||||
|
|
||||||
|
### 五、总判定
|
||||||
|
|
||||||
|
17 个变体中:**11 个闭环 ✅;WifiProvisioned/DeviceEvent 为 Phase 2 占位 ❌(非回归缺陷);Shutdown/DeviceResponse/CursorVisibility 弱链 ⚠️(行为性瑕疵,已给建议);Custom 六种 plugin_* kind 全部闭环(修正赵雨薇过时结论)**。风险3 可关闭:无"消息发出去没人处理"的黑洞(除示例性 Custom heartbeat 外),断链项全部是已规划的 Phase 2 占位,且每条均有 file:line 可复核。
|
||||||
|
|||||||
49
CLAUDE.md
49
CLAUDE.md
@@ -6,7 +6,7 @@
|
|||||||
## 你的身份
|
## 你的身份
|
||||||
|
|
||||||
你是**陈逸飞**,ShowenV2 的 CEO 兼技术总监(Claude Opus 4.6)。
|
你是**陈逸飞**,ShowenV2 的 CEO 兼技术总监(Claude Opus 4.6)。
|
||||||
你**不写代码、不跑测试、不改配置**。所有执行通过 kilo 派发团队完成。
|
你**不写代码、不跑测试、不改配置**。所有执行通过 Agent 子代理派发团队完成。
|
||||||
|
|
||||||
## 项目概要
|
## 项目概要
|
||||||
|
|
||||||
@@ -77,12 +77,12 @@ export PATH="/home/showen/.rustup/toolchains/stable-aarch64-unknown-linux-gnu/bi
|
|||||||
| 成员 | 失败计数 | 等级 | 更新时间 |
|
| 成员 | 失败计数 | 等级 | 更新时间 |
|
||||||
|------|---------|------|---------|
|
|------|---------|------|---------|
|
||||||
| 刘建国(PM) | 0 | — | 2026-03-19 |
|
| 刘建国(PM) | 0 | — | 2026-03-19 |
|
||||||
| 张明远 | 0 | — | 2026-03-19 |
|
| 张明远 | 1 | — | 2026-07-03 |
|
||||||
| 李思琪 | 0 | — | 2026-03-19 |
|
| 李思琪 | 0 | — | 2026-03-19 |
|
||||||
| 王浩然 | 0 | — | 2026-03-19 |
|
| 王浩然 | 0 | — | 2026-03-19 |
|
||||||
| 赵雨薇 | 0 | — | 2026-03-19 |
|
| 赵雨薇 | 1 | — | 2026-07-03 |
|
||||||
| 林晓峰(QA) | 0 | — | 2026-03-19 |
|
| 林晓峰(QA) | 0 | — | 2026-03-19 |
|
||||||
| 周雅婷 | 0 | — | 2026-03-19 |
|
| 周雅婷 | 0 | — | 2026-07-03(两轮验收执行出色) |
|
||||||
|
|
||||||
> 计数累加:审核不合格+1 / 返工+1 / 违反铁律+1。重置:连续2次成功→0 / Phase切换→全员0。
|
> 计数累加:审核不合格+1 / 返工+1 / 违反铁律+1。重置:连续2次成功→0 / Phase切换→全员0。
|
||||||
|
|
||||||
@@ -90,14 +90,14 @@ export PATH="/home/showen/.rustup/toolchains/stable-aarch64-unknown-linux-gnu/bi
|
|||||||
|
|
||||||
## 当前状态
|
## 当前状态
|
||||||
|
|
||||||
- **质量**: 115/115 已在 Linux ARM64 验证(107 核心 + 8 集成);+ 24 M1.2 集成测试已写入本地,**待目标机 `cargo test` 验收后方可计入**;Flutter 15/15;零 warning
|
- **质量**: **147/147 已在 Linux ARM64 目标机验证**(2026-07-03 实跑:lib 105 + example 7 + m1_2_dynamic 15 + m1_2_http 12 + m1_2_service_manager 8);Flutter 15/15;零 warning
|
||||||
- **里程碑**: M1.1 完成,M1.2 进行中(集成测试全部编写完毕,待 Linux 验收后收尾)
|
- **里程碑**: M1.1 完成,**M1.2 测试验收已通过**(两轮:第一轮 1 失败 3 warning → 返工 → 第二轮全绿),收尾差 commit+tag(待老板批准)+ 风险3 核查
|
||||||
- **DevicePlugin 能力**: Display + SleepInhibit + Backlight + Cursor (Linux ARM64)
|
- **DevicePlugin 能力**: Display + SleepInhibit + Backlight + Cursor (Linux ARM64)
|
||||||
- **ScreenPlugin**: 已重构为 thin wrapper
|
- **ScreenPlugin**: 已重构为 thin wrapper
|
||||||
- **Flutter App**: 完成度 ~98%, APK v0.3 (52.6MB) 已编译, cupertino_icons 已修复
|
- **Flutter App**: 完成度 ~98%, APK v0.3 (52.6MB) 已编译, cupertino_icons 已修复
|
||||||
- **API 文档**: 已校准(以 routes.rs 为唯一权威重写)
|
- **API 文档**: 已校准(以 routes.rs 为唯一权威重写)
|
||||||
- **示例插件**: 已完善为开发者参考模板 (manifest.json + 请求/响应示范 + 7 个测试)
|
- **示例插件**: 已完善为开发者参考模板 (manifest.json + 请求/响应示范 + 7 个测试)
|
||||||
- **M1.2 进展**: 5 项完成 — 插件管理API闭环 + ServiceManager集成测试(8) + HTTP路由测试(9) + 动态插件测试(15) + 风险3消息链路确认;**最终验收缺 Linux cargo test 证据 + git commit**
|
- **M1.2 进展**: 目标机两轮验收完成(2026-07-03,147/147 零 warning,证据见 TEAM_CHAT.md);HTTP 路由测试实为 12 个(旧记录 9 有误)、lib 单测实为 105(旧记录 107 有误);剩余 commit+tag、风险3 补派核查
|
||||||
|
|
||||||
### 已修复(本轮)
|
### 已修复(本轮)
|
||||||
|
|
||||||
@@ -130,25 +130,32 @@ export PATH="/home/showen/.rustup/toolchains/stable-aarch64-unknown-linux-gnu/bi
|
|||||||
|
|
||||||
25. ~~**P0**: 插件管理 API 闭环~~ ✅ 张明远修复 (handle_manager_message Custom 分支 + broadcast_plugin_states + 7 个新测试)
|
25. ~~**P0**: 插件管理 API 闭环~~ ✅ 张明远修复 (handle_manager_message Custom 分支 + broadcast_plugin_states + 7 个新测试)
|
||||||
26. ~~**M1.2**: ServiceManager 集成测试~~ ✅ 周雅婷完成 (tests/m1_2_service_manager.rs, 8 个测试全通过)
|
26. ~~**M1.2**: ServiceManager 集成测试~~ ✅ 周雅婷完成 (tests/m1_2_service_manager.rs, 8 个测试全通过)
|
||||||
27. ⏳ **M1.2**: HTTP API 路由集成测试 — 赵雨薇编写完成 (tests/m1_2_http.rs, 9 个测试:播放控制/配置重载/播放列表快照/插件管理闭环/路径穿越防护),**待 Linux ARM64 cargo test 验证 + git commit**
|
27. ~~**M1.2**: HTTP API 路由集成测试~~ ✅ 赵雨薇完成 (tests/m1_2_http.rs, 实为 12 个测试;2026-07-03 目标机验证通过,含一次返工:空 playlist 测试前提错误重写为 test_empty_playlist_rejected + 删死代码 sender)
|
||||||
28. ⏳ **M1.2**: 动态插件集成测试 — 张明远编写完成 (tests/m1_2_dynamic_plugin.rs, 15 个测试:manifest校验/生命周期/热替换回滚/版本GC/路径穿越),**待 Linux ARM64 cargo test 验证 + git commit**
|
28. ~~**M1.2**: 动态插件集成测试~~ ✅ 张明远完成 (tests/m1_2_dynamic_plugin.rs, 15 个测试;2026-07-03 目标机验证通过,含一次返工:删 2 处死代码 warning)
|
||||||
29. ⏳ **M1.2 风险3**: 消息链路分析 — 赵雨薇在 m1_2_http.rs 注释中给出旁证结论:enable/disable 闭环已修;plugin_rollback/switch/install/check_updates 为待实现项(非回归缺陷)。**WifiProvisioned/DeviceEvent 生产者确认尚未系统性核查(王浩然原任务 agent 失败,需补派)**
|
29. ~~**M1.2 风险3**: 消息链路核查~~ ✅ 王浩然完成 (2026-07-03 全量核查 17 个 Message 变体:11 闭环 / WifiProvisioned、DeviceEvent 为 Phase 2 占位(有消费无生产,非回归) / 3 弱链;Custom 六种 plugin_* 全闭环。修正赵雨薇旁证:rollback/switch/install 在 #25 修复后已是完整实现。报告见 TEAM_CHAT.md,**风险3 关闭**)
|
||||||
|
30. ~~**P0**: 设备端开机自启出现 3 个实例~~ ✅ 赵雨薇修复 (2026-07-02, 根因:3 个自启动入口叠加;仅保留用户级 showen_v2.service,其余移入 ~/autostart_backup_20260702/,重启验证进程==1)
|
||||||
|
31. ~~**P0**: 设备端窗口非全屏~~ ✅ 赵雨薇修复 (2026-07-02, 根因:应用先于 kwin 启动,OpenCV 全屏调用空操作;ExecStartPre 等待 kwin + kwinrulesrc 强制全屏规则,重启验证 800x800 无边框)
|
||||||
|
|
||||||
### 待处理
|
### 待处理
|
||||||
|
|
||||||
1. **[M1.2 验收 — 阻塞]** 在 Linux ARM64 执行 `cargo test --workspace`,确认 24 个新集成测试全通过,输出贴到 TEAM_CHAT.md → 再 git commit 三个测试文件
|
1. **[M1.2 收尾 — 待老板批准]** git commit 返工后的两个测试文件 + 本轮文档改动,打 M1.2 tag;**commit 后必须重新同步设备**(设备 tests/ 下是 scp 的未提交版本,HEAD 仍 5770b700)
|
||||||
2. **[M1.2 收尾]** 风险3 WifiProvisioned/DeviceEvent 生产者代码核查(补派王浩然)
|
2. ~~**[M1.2 收尾]** tests/m1_2_http.rs 过时注释更新~~ ✅ 赵雨薇完成(2026-07-03,纯注释改动,核实点位后订正为"六种 plugin_* 闭环,唯 check_updates 结果回传属 Phase 2");注意此改动在第二轮验收之后,commit 前设备端补一次 cargo check 即可
|
||||||
3. **[M1.2 收尾]** 全部测试通过后更新 PROGRESS.md M1.2 章节 + 打 tag
|
3. **[M1.2 收尾]** sanitize_filename 集成测试测的是逻辑复制而非产品函数,转正需产品侧小改动(改 pub 或 routes.rs 内加单测)— 赵雨薇上报
|
||||||
4. DevicePlugin 阶段三(framebuffer迁移/触摸/音频/多平台)— Phase 2 规划
|
4. DevicePlugin 阶段三(framebuffer迁移/触摸/音频/多平台)— Phase 2 规划
|
||||||
|
5. **[设备遗留-代码]** 单实例保护(锁文件/socket 互斥)+ unclutter 僵尸子进程 reap — 派内核/视频工程师
|
||||||
|
6. **[设备遗留-系统]** 设备时钟慢约一年(NTP 失效,apt HTTPS 证书报 not yet valid)+ 磁盘长期 9x% 满(两轮验收均被迫清 target/debug/incremental)— 需排查
|
||||||
|
7. **[环境]** 设备 SSH 已打通:`ssh -p 2222 showen@192.168.31.105` 免密(2026-07-02 配置),目标机验收可远程执行
|
||||||
|
8. **[代码质量-P2]** Shutdown 消息无生产触发者:main.rs:117-120 Ctrl+C 只置 AtomicBool,主循环阻塞在 rx.recv(),需等下一条任意消息才真正退出(王浩然发现)
|
||||||
|
9. **[Phase 2 清理]** SDK 文档教开发者监听永不触发的 WifiProvisioned (plugin-sdk/src/lib.rs:522);CursorVisibility 有消费无生产(实际链路已走 DeviceCommand);check_updates 结果仅 println 不回传;DeviceResponse 广播后核心无人读、Error 静默
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## kilo 派发模板(唯一权威版本)
|
## 任务派发模板(唯一权威版本)
|
||||||
|
|
||||||
```bash
|
通过 Claude Code 的 **Agent 工具(子代理)** 派发,子代理提示词:
|
||||||
kilo run -m openai/gpt-5.4 --auto \
|
|
||||||
--dir /home/showen/Showen/ShowenV2 \
|
```text
|
||||||
"你是<角色名>。
|
你是<角色名>。
|
||||||
|
|
||||||
开工前必读:
|
开工前必读:
|
||||||
1. souls/<name>.md(你的灵魂文件)
|
1. souls/<name>.md(你的灵魂文件)
|
||||||
@@ -158,15 +165,15 @@ kilo run -m openai/gpt-5.4 --auto \
|
|||||||
任务:<具体说明>
|
任务:<具体说明>
|
||||||
|
|
||||||
交付要求:
|
交付要求:
|
||||||
- 完成后执行 export PATH=\"/home/showen/.rustup/toolchains/stable-aarch64-unknown-linux-gnu/bin:\$PATH\" && cargo check --workspace --all-targets && cargo test --workspace
|
- 完成后执行 cargo check --workspace --all-targets && cargo test --workspace
|
||||||
- 两项都绿灯后把输出贴在交付中
|
- 两项都绿灯后把输出贴在交付中
|
||||||
- 修完检查同文件是否有类似问题
|
- 修完检查同文件是否有类似问题
|
||||||
- 更新你的 soul 文件
|
- 更新你的 soul 文件
|
||||||
|
|
||||||
验收标准:<具体标准>"
|
验收标准:<具体标准>
|
||||||
```
|
```
|
||||||
|
|
||||||
**kilo 使用规则**: 不读大 diff / 命令越简单越好 / 进程上限 12 个 / `--auto` 自动批准
|
**派发规则**: 不读大 diff / 指令越简单越好 / 并行子代理上限 12 个,注意文件重叠冲突
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -5,9 +5,10 @@
|
|||||||
|
|
||||||
## 当前里程碑
|
## 当前里程碑
|
||||||
|
|
||||||
**M1.2 — 进行中** 🔄
|
**M1.2 — 测试验收已通过,收尾中** 🔄
|
||||||
- 集成测试全部编写完毕(ServiceManager 8 + HTTP路由 9 + 动态插件 15 = 32 个)
|
- 集成测试全部编写完毕(ServiceManager 8 + HTTP路由 12 + 动态插件 15 = 35 个)
|
||||||
- **阻塞项**:待 Linux ARM64 运行 `cargo test --workspace` 验收 + git commit
|
- 2026-07-03 目标机(Linux ARM64, 192.168.31.105)两轮验收:**147/147 全过、零 warning**(第一轮暴露 1 个测试前提错误 + 3 个 warning,返工后第二轮全绿,证据见 TEAM_CHAT.md)
|
||||||
|
- 剩余:commit 返工测试文件 + 打 tag(待批准)+ 风险3 生产者核查(王浩然)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -92,7 +92,7 @@
|
|||||||
### 2. 实时沟通(可选)
|
### 2. 实时沟通(可选)
|
||||||
|
|
||||||
#### 工具
|
#### 工具
|
||||||
- **kilo 命令** - 启动子任务进行实时协作
|
- **Agent 子代理** - 启动子任务进行实时协作
|
||||||
- **语音/视频会议** - 复杂问题讨论
|
- **语音/视频会议** - 复杂问题讨论
|
||||||
- **屏幕共享** - 代码调试和演示
|
- **屏幕共享** - 代码调试和演示
|
||||||
|
|
||||||
|
|||||||
@@ -285,7 +285,7 @@ CEO 决策(如涉及重大变更)
|
|||||||
- **要求**: 必须记录在 TEAM_CHAT.md
|
- **要求**: 必须记录在 TEAM_CHAT.md
|
||||||
|
|
||||||
#### 2. 实时沟通(可选)
|
#### 2. 实时沟通(可选)
|
||||||
- **工具**: kilo 命令、语音、视频会议
|
- **工具**: Agent 子代理、语音、视频会议
|
||||||
- **适用**: 紧急问题、复杂讨论、头脑风暴
|
- **适用**: 紧急问题、复杂讨论、头脑风暴
|
||||||
- **要求**:
|
- **要求**:
|
||||||
- 沟通后必须在 TEAM_CHAT.md 记录要点
|
- 沟通后必须在 TEAM_CHAT.md 记录要点
|
||||||
@@ -381,8 +381,8 @@ CEO 决策(如涉及重大变更)
|
|||||||
**解锁条件**: 首次任务评分 ≥ 7/10 即可解锁灵魂文件写入权限
|
**解锁条件**: 首次任务评分 ≥ 7/10 即可解锁灵魂文件写入权限
|
||||||
|
|
||||||
### 通信机制
|
### 通信机制
|
||||||
- **任务下发**: CEO → `kilo run -m openai/gpt-5.4 --auto --dir <dir>` (带详细上下文)
|
- **任务下发**: CEO → Agent 子代理(提示词带详细上下文)
|
||||||
- **产出回收**: kilo 输出 → CEO 读取文件 → 审核 → git commit
|
- **产出回收**: 子代理交付 → CEO 读取文件 → 审核 → git commit
|
||||||
- **团队会议**: 重大决策记录到 PROGRESS.md
|
- **团队会议**: 重大决策记录到 PROGRESS.md
|
||||||
- **灵魂文件**: `souls/<name>.md` 持久化成员状态
|
- **灵魂文件**: `souls/<name>.md` 持久化成员状态
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
- git commit 方案文档
|
- git commit 方案文档
|
||||||
|
|
||||||
### 2. 派发阶段
|
### 2. 派发阶段
|
||||||
- CEO 或 PM 通过 `kilo run -m openai/gpt-5.4 --auto --dir <dir>` 派发
|
- CEO 或 PM 通过 Agent 子代理派发
|
||||||
- **任务消息必须包含**:
|
- **任务消息必须包含**:
|
||||||
- 角色身份
|
- 角色身份
|
||||||
- **开工前必读文件**:souls/<name>.md + .showen/COMPANY_RULES.md + .showen/TEAM_CHAT.md
|
- **开工前必读文件**:souls/<name>.md + .showen/COMPANY_RULES.md + .showen/TEAM_CHAT.md
|
||||||
@@ -63,7 +63,7 @@
|
|||||||
|
|
||||||
| 文件 | 用途 |
|
| 文件 | 用途 |
|
||||||
|------|------|
|
|------|------|
|
||||||
| CLAUDE.md | **CEO 唯一必读**:身份/规则/团队/状态/kilo模板 |
|
| CLAUDE.md | **CEO 唯一必读**:身份/规则/团队/状态/派发模板 |
|
||||||
| PROGRESS.md | 里程碑摘要、最近变更 |
|
| PROGRESS.md | 里程碑摘要、最近变更 |
|
||||||
| TEAM.md | 团队成员档案、制度、绩效详情 |
|
| TEAM.md | 团队成员档案、制度、绩效详情 |
|
||||||
| TEAM_CHAT.md | 团队异步沟通、任务讨论 |
|
| TEAM_CHAT.md | 团队异步沟通、任务讨论 |
|
||||||
@@ -76,14 +76,12 @@
|
|||||||
|
|
||||||
### 派发任务
|
### 派发任务
|
||||||
|
|
||||||
> kilo 派发模板的权威版本见 `CLAUDE.md`。以下为快速参考:
|
> 派发模板的权威版本见 `CLAUDE.md`。以下为快速参考(Agent 子代理提示词):
|
||||||
|
|
||||||
```bash
|
```text
|
||||||
kilo run -m openai/gpt-5.4 --auto \
|
你是<角色名>。开工前必读:souls/<name>.md + .showen/COMPANY_RULES.md + .showen/TEAM_CHAT.md。
|
||||||
--dir /home/showen/Showen/ShowenV2 \
|
|
||||||
"你是<角色名>。开工前必读:souls/<name>.md + .showen/COMPANY_RULES.md + .showen/TEAM_CHAT.md。
|
|
||||||
任务:<具体说明>。交付要求:贴 cargo check/test 输出 + 检查同类问题 + 更新 soul 文件。
|
任务:<具体说明>。交付要求:贴 cargo check/test 输出 + 检查同类问题 + 更新 soul 文件。
|
||||||
验收标准:<具体标准>"
|
验收标准:<具体标准>
|
||||||
```
|
```
|
||||||
|
|
||||||
### 审核提交
|
### 审核提交
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
|
|
||||||
CEO (陈逸飞) → PM (刘建国) → 开发团队
|
CEO (陈逸飞) → PM (刘建国) → 开发团队
|
||||||
|
|
||||||
任务通过 `kilo run` 派发给各成员,成员首次任务评分 ≥ 7 分解锁灵魂文件,末尾淘汰制。
|
任务通过 Agent 子代理派发给各成员,成员首次任务评分 ≥ 7 分解锁灵魂文件,末尾淘汰制。
|
||||||
|
|
||||||
## 子目录
|
## 子目录
|
||||||
|
|
||||||
|
|||||||
@@ -42,9 +42,9 @@
|
|||||||
|
|
||||||
## CEO 个人经验
|
## CEO 个人经验
|
||||||
|
|
||||||
### kilo 派发经验
|
### 子代理派发经验(kilo 机制已于 2026-07-02 废除,教训保留,现用 Agent 子代理)
|
||||||
- PM 刘建国 git commit 连续两次失败(agent 无视"不要读 diff"),QA 林晓峰一次搞定
|
- PM 刘建国 git commit 连续两次失败(agent 无视"不要读 diff"),QA 林晓峰一次搞定
|
||||||
- kilo agent 倾向于自作主张读 diff/分析代码 → 只给命令,不给"任务描述"
|
- 执行 agent 倾向于自作主张读 diff/分析代码 → 只给命令,不给"任务描述"
|
||||||
- 指令越简单越好,不要让 agent 读大文件/大 diff
|
- 指令越简单越好,不要让 agent 读大文件/大 diff
|
||||||
- 代码提交任务直接给命令序列,不需要 agent 自行分析
|
- 代码提交任务直接给命令序列,不需要 agent 自行分析
|
||||||
- GPT-5.4 执行力 > 策略力 → 给具体命令比给目标可靠
|
- GPT-5.4 执行力 > 策略力 → 给具体命令比给目标可靠
|
||||||
@@ -54,7 +54,7 @@
|
|||||||
- 关键路径任务(git push)派给最可靠的人,不按头衔
|
- 关键路径任务(git push)派给最可靠的人,不按头衔
|
||||||
- PM 不可靠时可跳过 PM 直接派开发者,记录原因
|
- PM 不可靠时可跳过 PM 直接派开发者,记录原因
|
||||||
- QA 比 PM 更适合执行类任务(提交、验证),PM 适合分析和规划
|
- QA 比 PM 更适合执行类任务(提交、验证),PM 适合分析和规划
|
||||||
- 员工用 kilo 完成后必须自行更新 soul 文件,否则经验丢失
|
- 员工完成任务后必须自行更新 soul 文件,否则经验丢失
|
||||||
|
|
||||||
### 角色边界
|
### 角色边界
|
||||||
- **CEO 绝不直接写代码/改代码/跑测试** — 即使小修复也派回原作者
|
- **CEO 绝不直接写代码/改代码/跑测试** — 即使小修复也派回原作者
|
||||||
|
|||||||
@@ -72,8 +72,8 @@
|
|||||||
## 工作方法
|
## 工作方法
|
||||||
1. 收到 CEO 目标后,立即拆解为具体任务
|
1. 收到 CEO 目标后,立即拆解为具体任务
|
||||||
2. 评估任务依赖关系,确定并行方案
|
2. 评估任务依赖关系,确定并行方案
|
||||||
3. 通过 kilo 派发任务,消息中包含:角色、上下文文件、具体要求、验收标准
|
3. 通过 Agent 子代理派发任务,提示词中包含:角色、上下文文件、具体要求、验收标准
|
||||||
4. **多线程思考**: 可以并行启动多个 kilo 进程探索方案或分析代码
|
4. **多线程思考**: 可以并行启动多个子代理探索方案或分析代码
|
||||||
5. 任务完成后运行 cargo check 验证
|
5. 任务完成后运行 cargo check 验证
|
||||||
6. 初审通过后更新 PROGRESS.md,向 CEO 汇报
|
6. 初审通过后更新 PROGRESS.md,向 CEO 汇报
|
||||||
7. 遇到技术难题或架构问题,立即上报 CEO
|
7. 遇到技术难题或架构问题,立即上报 CEO
|
||||||
@@ -129,14 +129,12 @@
|
|||||||
建议下一步: <PM 的建议>
|
建议下一步: <PM 的建议>
|
||||||
```
|
```
|
||||||
|
|
||||||
### kilo 派发模板(含能动性要求)
|
### 任务派发模板(含能动性要求)
|
||||||
|
|
||||||
> 权威版本见 `CLAUDE.md`。此处保留副本供 PM 独立 session 使用。
|
> 权威版本见 `CLAUDE.md`。此处保留副本供 PM 独立 session 使用(Agent 子代理提示词)。
|
||||||
|
|
||||||
```bash
|
```text
|
||||||
kilo run -m openai/gpt-5.4 --auto \
|
你是<角色名>。
|
||||||
--dir /home/showen/Showen/ShowenV2 \
|
|
||||||
"你是<角色名>。
|
|
||||||
|
|
||||||
开工前必读:
|
开工前必读:
|
||||||
1. souls/<name>.md(你的灵魂文件)
|
1. souls/<name>.md(你的灵魂文件)
|
||||||
@@ -146,13 +144,13 @@ kilo run -m openai/gpt-5.4 --auto \
|
|||||||
任务:<具体说明>
|
任务:<具体说明>
|
||||||
|
|
||||||
交付要求:
|
交付要求:
|
||||||
- 完成后执行 export PATH=\"/home/showen/.rustup/toolchains/stable-aarch64-unknown-linux-gnu/bin:\$PATH\" && cargo check --workspace --all-targets
|
- 完成后执行 cargo check --workspace --all-targets
|
||||||
- 再执行 cargo test --workspace
|
- 再执行 cargo test --workspace
|
||||||
- 两项都绿灯后,把输出贴在交付汇报中
|
- 两项都绿灯后,把输出贴在交付汇报中
|
||||||
- 修完 bug 检查同文件是否有类似问题
|
- 修完 bug 检查同文件是否有类似问题
|
||||||
- 更新你的 soul 文件
|
- 更新你的 soul 文件
|
||||||
|
|
||||||
验收标准:<具体标准>"
|
验收标准:<具体标准>
|
||||||
```
|
```
|
||||||
|
|
||||||
## 沟通协议
|
## 沟通协议
|
||||||
@@ -163,10 +161,9 @@ kilo run -m openai/gpt-5.4 --auto \
|
|||||||
- 涉及状态变化、流程更新或复盘结论时,确保同步到规则文件或 soul 文件,避免信息只停留在聊天记录中。
|
- 涉及状态变化、流程更新或复盘结论时,确保同步到规则文件或 soul 文件,避免信息只停留在聊天记录中。
|
||||||
|
|
||||||
## 记忆
|
## 记忆
|
||||||
- kilo 调用方式:`kilo run -m openai/gpt-5.4 --auto --dir /home/showen/Showen/ShowenV2 "消息"`
|
- 派发方式:Agent 子代理(Claude Code Agent 工具),在提示词中指示读取文件
|
||||||
- 不使用 `-f` 参数,在消息中指示读取文件
|
|
||||||
- 每个任务必须 cargo check 通过
|
- 每个任务必须 cargo check 通过
|
||||||
- 编译环境:`export PATH="/home/showen/.rustup/toolchains/stable-aarch64-unknown-linux-gnu/bin:$PATH"`
|
- Linux ARM64 目标机编译环境:`export PATH="/home/showen/.rustup/toolchains/stable-aarch64-unknown-linux-gnu/bin:$PATH"`
|
||||||
|
|
||||||
## 复盘记录
|
## 复盘记录
|
||||||
|
|
||||||
|
|||||||
@@ -58,3 +58,9 @@
|
|||||||
- BLE 注册不能靠固定 sleep,需等待 `RegisterApplication` / `RegisterAdvertisement` 的真实 D-Bus reply
|
- BLE 注册不能靠固定 sleep,需等待 `RegisterApplication` / `RegisterAdvertisement` 的真实 D-Bus reply
|
||||||
- 为跑通全量验证,顺手补了 `DynamicPlugin` 的 `Debug` 实现,并修正 plugin_repo 测试构造方式
|
- 为跑通全量验证,顺手补了 `DynamicPlugin` 的 `Debug` 实现,并修正 plugin_repo 测试构造方式
|
||||||
- API 文档校准必须以 `src/plugins/http/routes.rs` 为唯一权威;WebSocket 命令返回仍是 `{ok: ...}`,HTTP 写接口才统一 `{status, message}`
|
- API 文档校准必须以 `src/plugins/http/routes.rs` 为唯一权威;WebSocket 命令返回仍是 `{ok: ...}`,HTTP 写接口才统一 `{status, message}`
|
||||||
|
|
||||||
|
## 个人经验 (2026-07-03) — M1.2 风险3 消息链路审计
|
||||||
|
- 消息链路审计方法:以 Message enum 定义为基准,逐变体 grep 构造点/匹配点,再按 ServiceManager 三路路由(Plugin/Broadcast/Manager, service_manager.rs:369-377)验证链路;测试文件构造一律不算生产者
|
||||||
|
- 审计陷阱:构造点可能藏在 #[cfg(test)] 内(如 ble/gatt.rs:772、dynamic_plugin.rs:348),必须回看 mod tests 边界再下判定
|
||||||
|
- BLE 命令的真实生产者是 core/dispatch.rs::parse_command(gatt.rs:120 调用),不在 gatt.rs 里直接构造消息
|
||||||
|
- 结论:WifiProvisioned/DeviceEvent 均为"有消费无生产"的 Phase 2 占位(DeviceBackend trait 连事件通道都没有);plugin_rollback/switch/install 已是完整实现,队友旧注释会过时——审计要以当前代码为准,不能沿用他人历史结论
|
||||||
|
|||||||
@@ -125,3 +125,8 @@
|
|||||||
- 为版本切换、安装、更新检查补了 Manager 侧 helper,统一复用 `VersionManager` / `PluginRepository` / 热替换生命周期
|
- 为版本切换、安装、更新检查补了 Manager 侧 helper,统一复用 `VersionManager` / `PluginRepository` / 热替换生命周期
|
||||||
- 在 `src/core/tests.rs` 增加 7 个回归测试,覆盖初始状态广播和 6 个自定义管理命令;保留旧生命周期测试并过滤新增状态广播事件
|
- 在 `src/core/tests.rs` 增加 7 个回归测试,覆盖初始状态广播和 6 个自定义管理命令;保留旧生命周期测试并过滤新增状态广播事件
|
||||||
- `cargo check --workspace --all-targets` 零 warning,`cargo test --workspace` 107/107 + 集成测试全绿
|
- `cargo check --workspace --all-targets` 零 warning,`cargo test --workspace` 107/107 + 集成测试全绿
|
||||||
|
|
||||||
|
## 个人经验 (2026-07-03 - M1.2 集成测试返工教训)
|
||||||
|
- `tests/m1_2_dynamic_plugin.rs` 目标机实跑暴露 2 个 warning(unused imports `Destination`/`Envelope` + 死函数 `manifest_with_caps`)——是我预写辅助函数/import 后测试改走 `register_dynamic_with_manifest` 路线留下的残留
|
||||||
|
- 教训:**交付前必须对测试文件本身做死代码自查**(本机编译不了 aarch64 也要人工逐符号核对 import 和 helper 的使用点),不能只保证测试逻辑正确
|
||||||
|
- 消 warning 原则:先判断死代码是"残留"还是"漏写的测试",查产品代码确认无对应校验逻辑后才删;绝不用 `#[allow(...)]` 压制
|
||||||
|
|||||||
@@ -88,8 +88,22 @@
|
|||||||
- 配置编辑同时支持表单和 raw JSON 时,必须维护单一真源:`_fullConfig` 更新后立刻同步 JSON 文本,JSON 保存成功后再反向刷新表单字段
|
- 配置编辑同时支持表单和 raw JSON 时,必须维护单一真源:`_fullConfig` 更新后立刻同步 JSON 文本,JSON 保存成功后再反向刷新表单字段
|
||||||
- JSON 编辑模式的错误反馈要区分“解析失败”和“接口保存失败”;前者本地立即拦截,后者通过 SnackBar 暴露服务端/网络错误
|
- JSON 编辑模式的错误反馈要区分“解析失败”和“接口保存失败”;前者本地立即拦截,后者通过 SnackBar 暴露服务端/网络错误
|
||||||
|
|
||||||
|
## 生产机开机自启三实例 + 非全屏修复经验(2026-07-02)
|
||||||
|
- 排查多实例先看 `/proc/<pid>/cgroup`,能直接把每个进程映射到具体 systemd unit,比猜父进程可靠
|
||||||
|
- 自启动入口要系统性穷举:system unit + user unit + ~/.config/autostart/*.desktop + autostart-scripts,四处都可能各藏一份同一程序
|
||||||
|
- OpenCV highgui 的 `set_window_property(FULLSCREEN)` 依赖 WM 已就绪;服务比 kwin 先启动时全屏请求会静默丢失 → user unit 加 ExecStartPre 轮询 `xprop -root _NET_SUPPORTING_WM_CHECK` 等 WM
|
||||||
|
- 持久化全屏用 KWin 窗口规则(~/.config/kwinrulesrc,wmclass 子串匹配 + fullscreenrule=2/noborderrule=2 强制),比 wmctrl 一次性调用可靠
|
||||||
|
- xwininfo -tree 里 GTK 应用会有一个 10x10 未映射的 group-leader 窗口,真正的客户端窗口以 `_NET_CLIENT_LIST`/`_NET_ACTIVE_WINDOW` 为准
|
||||||
|
- 设备时钟偏差会导致 apt TLS 证书 "not yet valid";验证窗口几何用系统自带 xprop/xwininfo 即可,不必依赖 wmctrl/xdotool
|
||||||
|
- 禁用入口用 mv 到带日期的备份目录(如 ~/autostart_backup_20260702/),保留恢复能力,不 rm
|
||||||
|
|
||||||
## Flutter APK v0.3 编译经验(2026-03-14)
|
## Flutter APK v0.3 编译经验(2026-03-14)
|
||||||
- Release 构建前先跑 `flutter analyze` 和 `flutter test`,确保依赖变更不会把问题拖到 Gradle 阶段才暴露
|
- Release 构建前先跑 `flutter analyze` 和 `flutter test`,确保依赖变更不会把问题拖到 Gradle 阶段才暴露
|
||||||
- 遇到 `Expected to find fonts for (packages/cupertino_icons/CupertinoIcons, MaterialIcons)` 时,优先检查 `pubspec.yaml` 是否漏了 `cupertino_icons`;即使业务代码没有显式引用,也可能被图标字体清单间接依赖
|
- 遇到 `Expected to find fonts for (packages/cupertino_icons/CupertinoIcons, MaterialIcons)` 时,优先检查 `pubspec.yaml` 是否漏了 `cupertino_icons`;即使业务代码没有显式引用,也可能被图标字体清单间接依赖
|
||||||
- `flutter build apk --release --android-skip-build-dependency-validation` 在 ARM64 机器上耗时较长,清理或重启 Gradle daemon 能规避旧 daemon 异常退出导致的假失败
|
- `flutter build apk --release --android-skip-build-dependency-validation` 在 ARM64 机器上耗时较长,清理或重启 Gradle daemon 能规避旧 daemon 异常退出导致的假失败
|
||||||
- 最终 APK 统一落到 `configs/downloads/showen-app.apk`,方便交付下载链路复用;本次 release 产物大小约 `51M`
|
- 最终 APK 统一落到 `configs/downloads/showen-app.apk`,方便交付下载链路复用;本次 release 产物大小约 `51M`
|
||||||
|
|
||||||
|
## M1.2 HTTP 集成测试返工教训(2026-07-03)
|
||||||
|
- **测试要先实跑再交付**:m1_2_http.rs 首次交付时本机编不了 aarch64 依赖、没实跑,结果目标机暴露 1 个失败 + 1 个 dead_code warning。编不了也要逐个测试核对前提,不能只靠"看起来对"
|
||||||
|
- **写测试前先核对产品校验(坏前提)**:`test_empty_playlist_does_not_panic` 假设空 playlist 配置能通过 `AppConfig::from_file`,但 config.rs `validate()` 自 init 提交就 `bail!("playlist 不能为空")`。测试的每个 expect/unwrap 前提都要回到产品代码里确认,产品故意拒绝的状态应改测"拒绝行为"(防退化),而不是硬造不可达状态
|
||||||
|
- 测试辅助 struct 里"以后可能用"的方法(如本次的 `sender()`)不要预留;用不上就删,dead_code warning 违反零 warning 铁律
|
||||||
|
|||||||
@@ -78,3 +78,5 @@
|
|||||||
- **必须实际运行并截图,不能只看代码**
|
- **必须实际运行并截图,不能只看代码**
|
||||||
- 2026-03-13:补齐 `src/core/tests.rs` 的关键路径覆盖,重点覆盖动态插件 FFI 返回 null 的降级、无效 manifest 跳过、禁用插件消息跳过、无稳定版本回退失败、以及 `Message` 全变体 JSON round-trip
|
- 2026-03-13:补齐 `src/core/tests.rs` 的关键路径覆盖,重点覆盖动态插件 FFI 返回 null 的降级、无效 manifest 跳过、禁用插件消息跳过、无稳定版本回退失败、以及 `Message` 全变体 JSON round-trip
|
||||||
- 2026-03-14:新增 `tests/m1_2_service_manager.rs`,补齐 M1.2 ServiceManager 集成测试基建,覆盖依赖启动顺序、Shutdown 停机、ConfigReloaded/PlayerStatus/WifiResult/StateChanged/PluginReady 广播,以及禁用插件路由跳过
|
- 2026-03-14:新增 `tests/m1_2_service_manager.rs`,补齐 M1.2 ServiceManager 集成测试基建,覆盖依赖启动顺序、Shutdown 停机、ConfigReloaded/PlayerStatus/WifiResult/StateChanged/PluginReady 广播,以及禁用插件路由跳过
|
||||||
|
- 2026-07-02:M1.2 目标机验收(Linux ARM64)。经验:① 跑全量测试前先 `df -h`——ARM 设备 28G 盘 98% 满导致 ld 链接失败(No space left on device),清 target/debug/incremental + 过期 deps 即可,不必 cargo clean 全量重编;② cargo test 默认 fail-fast,验收要加 `--no-fail-fast` 才能拿到全部 target 的统计;③ "从未实跑过的测试"是最大风险源——test_empty_playlist_does_not_panic 的前提(空 playlist 可加载)与 config.rs 自 init 起的校验矛盾,代码评审没发现,一跑就露馅;④ 同步版本用 git bundle + fetch + merge --ff-only 最安全,先确认祖先关系和设备脏文件不在 diff 内
|
||||||
|
- 2026-07-03:M1.2 第二轮(返工后)验收全绿 147/147 零 warning。经验:scp 未提交文件到设备时必须两端 sha256 对账,并在交付中显式标注设备与 git HEAD 的不一致状态,提醒 commit 后重新同步
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use showen_v2::core::config::AppConfig;
|
use showen_v2::core::config::AppConfig;
|
||||||
use showen_v2::core::message::{Destination, Envelope, Message};
|
use showen_v2::core::message::Message;
|
||||||
use showen_v2::core::plugin::{CapabilityTestResult, Platform, Plugin, PluginContext, PluginInfo};
|
use showen_v2::core::plugin::{CapabilityTestResult, Platform, Plugin, PluginContext, PluginInfo};
|
||||||
use showen_v2::core::plugin_loader::{
|
use showen_v2::core::plugin_loader::{
|
||||||
ErrorPolicy, PluginLoader, PluginManifest, PluginRegistry, PluginRegistryEntry,
|
ErrorPolicy, PluginLoader, PluginManifest, PluginRegistry, PluginRegistryEntry,
|
||||||
@@ -84,21 +84,6 @@ fn manifest(id: &str, version: &str) -> PluginManifest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn manifest_with_caps(id: &str, version: &str, caps: Vec<&str>, required: Vec<&str>) -> PluginManifest {
|
|
||||||
PluginManifest {
|
|
||||||
id: id.to_string(),
|
|
||||||
version: version.to_string(),
|
|
||||||
sdk_version: "0.2.0".to_string(),
|
|
||||||
dependencies: vec![],
|
|
||||||
error_policy: ErrorPolicy::AutoRollback,
|
|
||||||
so_filename: format!("lib{}.so", id.replace('-', "_")),
|
|
||||||
capabilities: caps.iter().map(|s| s.to_string()).collect(),
|
|
||||||
required_capabilities: required.iter().map(|s| s.to_string()).collect(),
|
|
||||||
test_timeout_ms: 5000,
|
|
||||||
auto_test: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn setup_registry(store: &Path, plugin_id: &str, active: &str, stable: Option<&str>) {
|
fn setup_registry(store: &Path, plugin_id: &str, active: &str, stable: Option<&str>) {
|
||||||
let loader = PluginLoader::new(store);
|
let loader = PluginLoader::new(store);
|
||||||
let mut registry = PluginRegistry::default();
|
let mut registry = PluginRegistry::default();
|
||||||
|
|||||||
@@ -7,18 +7,21 @@
|
|||||||
//!
|
//!
|
||||||
//! 经过代码审查,插件管理 API 的 Custom 消息已在 ServiceManager 中完整处理:
|
//! 经过代码审查,插件管理 API 的 Custom 消息已在 ServiceManager 中完整处理:
|
||||||
//! - `plugin_enable` / `plugin_disable` → `set_plugin_enabled()` → `broadcast_plugin_states()`
|
//! - `plugin_enable` / `plugin_disable` → `set_plugin_enabled()` → `broadcast_plugin_states()`
|
||||||
//! - `plugin_rollback` / `plugin_switch` / `plugin_install` / `plugin_check_updates` 已注册但未完整实现业务逻辑
|
//! - `plugin_rollback` / `plugin_switch` / `plugin_install` 均为完整实现:
|
||||||
|
//! `rollback_plugin`(service_manager.rs:432) / `switch_plugin_version`(:617) /
|
||||||
|
//! `install_plugin`(:665),张明远 #25 修复(handle_manager_message Custom 分支)后落地
|
||||||
//! - HTTP routes 的 `plugin_enable_route`/`plugin_disable_route` 发送 `Message::Custom{kind:"plugin_enable",...}`
|
//! - HTTP routes 的 `plugin_enable_route`/`plugin_disable_route` 发送 `Message::Custom{kind:"plugin_enable",...}`
|
||||||
//! 到 `Destination::Manager`,ServiceManager 能够接收并处理。
|
//! 到 `Destination::Manager`,ServiceManager 能够接收并处理。
|
||||||
//! - `/api/plugins` 通过 `HttpState::plugin_states()` 读取状态,状态由
|
//! - `/api/plugins` 通过 `HttpState::plugin_states()` 读取状态,状态由
|
||||||
//! `Message::Custom{kind:"plugin_states",...}` 广播更新,ServiceManager 在每次
|
//! `Message::Custom{kind:"plugin_states",...}` 广播更新,ServiceManager 在每次
|
||||||
//! enable/disable 后调用 `broadcast_plugin_states()` 发出该消息。
|
//! enable/disable 后调用 `broadcast_plugin_states()` 发出该消息。
|
||||||
//! - **结论**:enable/disable 命令闭环已修复(CLAUDE.md #25 已修复项),基本链路可工作。
|
//! - **结论**:Custom 六种 plugin_* kind 全部闭环,enable/disable/rollback/switch/install
|
||||||
//! plugin_rollback/switch/install/check_updates 仅发送消息,ServiceManager 侧仅打印日志,
|
//! 均为完整实现;唯 `plugin_check_updates` 为部分实现——`check_plugin_updates`(:730)
|
||||||
//! 尚无完整业务逻辑,属 M1.2 已知待实现项。
|
//! 会真实查询 repo,但结果仅 println、不回传 HTTP/不广播,结果回传链路属 Phase 2
|
||||||
|
//! 待补(非回归缺陷)。详见 2026-07-03 王浩然风险3全量核查报告(.showen/TEAM_CHAT.md)。
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use showen_v2::core::config::AppConfig;
|
use showen_v2::core::config::{self, AppConfig};
|
||||||
use showen_v2::core::message::{Destination, Envelope, Message, PlayerStatusData};
|
use showen_v2::core::message::{Destination, Envelope, Message, PlayerStatusData};
|
||||||
use showen_v2::core::plugin::{Platform, Plugin, PluginContext, PluginInfo};
|
use showen_v2::core::plugin::{Platform, Plugin, PluginContext, PluginInfo};
|
||||||
use showen_v2::core::service_manager::ServiceManager;
|
use showen_v2::core::service_manager::ServiceManager;
|
||||||
@@ -121,7 +124,6 @@ struct RecordingPlugin {
|
|||||||
id: String,
|
id: String,
|
||||||
deps: Vec<String>,
|
deps: Vec<String>,
|
||||||
events: Arc<Mutex<Vec<String>>>,
|
events: Arc<Mutex<Vec<String>>>,
|
||||||
ctx: Option<PluginContext>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RecordingPlugin {
|
impl RecordingPlugin {
|
||||||
@@ -130,17 +132,12 @@ impl RecordingPlugin {
|
|||||||
id: id.to_string(),
|
id: id.to_string(),
|
||||||
deps: deps.into_iter().map(str::to_string).collect(),
|
deps: deps.into_iter().map(str::to_string).collect(),
|
||||||
events,
|
events,
|
||||||
ctx: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn record(&self, entry: impl Into<String>) {
|
fn record(&self, entry: impl Into<String>) {
|
||||||
lock_events(&self.events).push(entry.into());
|
lock_events(&self.events).push(entry.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sender(&self) -> Option<std::sync::mpsc::Sender<Envelope>> {
|
|
||||||
self.ctx.as_ref().map(|c| c.tx.clone())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Plugin for RecordingPlugin {
|
impl Plugin for RecordingPlugin {
|
||||||
@@ -161,8 +158,7 @@ impl Plugin for RecordingPlugin {
|
|||||||
self.deps.clone()
|
self.deps.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init(&mut self, ctx: PluginContext) -> Result<()> {
|
fn init(&mut self, _ctx: PluginContext) -> Result<()> {
|
||||||
self.ctx = Some(ctx);
|
|
||||||
self.record(format!("init:{}", self.id));
|
self.record(format!("init:{}", self.id));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -412,9 +408,9 @@ fn test_config_update_with_corrupted_json_does_not_reload() {
|
|||||||
)));
|
)));
|
||||||
manager.start_all().expect("start_all should succeed");
|
manager.start_all().expect("start_all should succeed");
|
||||||
|
|
||||||
// 写入损坏的 JSON(模拟 http 路由验证失败后不写文件,Manager 不会收到 reload 请求)
|
// routes.rs 的 handle_config_update 先用 config::parse_str 验证请求体,
|
||||||
// 在 routes.rs 中 handle_config_update 先用 config::parse_str 验证,验证失败则直接返回 400
|
// 损坏的 JSON 验证失败直接返回 400:不写盘、也不发送 ConfigReloadRequest。
|
||||||
// 不会发送 ConfigReloadRequest。因此这里我们验证:不发 ConfigReloadRequest 则不广播 ConfigReloaded。
|
// 因此这里验证链路的后半段:不发 ConfigReloadRequest 则不广播 ConfigReloaded。
|
||||||
|
|
||||||
let sender = manager.sender();
|
let sender = manager.sender();
|
||||||
// 不发 ConfigReloadRequest,只发 Shutdown
|
// 不发 ConfigReloadRequest,只发 Shutdown
|
||||||
@@ -492,23 +488,39 @@ fn test_playlist_snapshot_includes_current_index() {
|
|||||||
fs::remove_dir_all(dir).expect("test dir should be removed");
|
fs::remove_dir_all(dir).expect("test dir should be removed");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 播放列表为空时,系统不应崩溃(边界条件)。
|
/// 播放列表为空时,配置校验应在入口边界拒绝(防退化)。
|
||||||
|
///
|
||||||
|
/// 说明:本测试的原始版本假设空 playlist 配置可以通过 `AppConfig::from_file`
|
||||||
|
/// 加载并启动 ServiceManager,但产品在 config.rs `validate()` 中故意
|
||||||
|
/// `bail!("playlist 不能为空")`(自 init 提交即存在的校验行为)。
|
||||||
|
/// 运行时也不存在把 config.playlist 清空的路径:
|
||||||
|
/// - `DELETE /api/videos/:name` 只删除磁盘上的视频文件,不修改 config.playlist;
|
||||||
|
/// - `POST /api/config` 在写盘前用 `config::parse_str` 验证,空 playlist 直接 400;
|
||||||
|
/// - `ConfigReloadRequest` 走 `from_file`,同样会被 validate 拦下。
|
||||||
|
/// 因此"运行时空 playlist"在 AppConfig 层不可达,本测试改为锁定两个入口
|
||||||
|
/// 边界的拒绝行为,防止该校验未来被误删。
|
||||||
#[test]
|
#[test]
|
||||||
fn test_empty_playlist_does_not_panic() {
|
fn test_empty_playlist_rejected() {
|
||||||
let (mut manager, _events, dir) = setup("empty_playlist", 0);
|
let dir = unique_test_dir("empty_playlist_rejected");
|
||||||
|
let config_path = write_test_config(&dir, "test-title", 0);
|
||||||
|
|
||||||
// 空 playlist 仍能正常启动和关闭
|
// 启动边界:AppConfig::from_file 必须拒绝空 playlist
|
||||||
let sender = manager.sender();
|
let err = AppConfig::from_file(&config_path)
|
||||||
manager.start_all().expect("start_all with empty playlist should succeed");
|
.expect_err("from_file should reject empty playlist config");
|
||||||
sender
|
assert!(
|
||||||
.send(Envelope {
|
format!("{err:#}").contains("playlist 不能为空"),
|
||||||
from: "test".to_string(),
|
"from_file error should mention empty playlist, got: {err:#}"
|
||||||
to: Destination::Manager,
|
);
|
||||||
message: Message::Shutdown,
|
|
||||||
})
|
|
||||||
.expect("shutdown should send");
|
|
||||||
|
|
||||||
manager.run().expect("run with empty playlist should succeed");
|
// HTTP 边界:POST /api/config 依赖 config::parse_str 的这个错误返回 400
|
||||||
|
// (routes.rs handle_config_update 先验证后写盘)
|
||||||
|
let raw = config_json_with_playlist("test-title", 0);
|
||||||
|
let err = config::parse_str(&raw, config_path.clone())
|
||||||
|
.expect_err("parse_str should reject empty playlist config");
|
||||||
|
assert!(
|
||||||
|
format!("{err:#}").contains("playlist 不能为空"),
|
||||||
|
"parse_str error should mention empty playlist, got: {err:#}"
|
||||||
|
);
|
||||||
|
|
||||||
fs::remove_dir_all(dir).expect("test dir should be removed");
|
fs::remove_dir_all(dir).expect("test dir should be removed");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user