fix(task-worktree): build/bench 分锁 TTL + done 自动接管陈旧锁

A:LOCK_TTL_HOURS 由全局 6h 改为按锁分设(build 1h / bench 6h)——
   兜底窗口应与操作真实时长同量级:编译是秒~分钟级,6h 太钝。
   并支持 lock acquire --ttl 自报窗口(keil_build 按其 --timeout 自报,
   timeout/3600+15min,下限 0.5h),使 build 锁窗口自动跟随构建上限。
B:done 收口前置把陈旧锁视为空闲并自动释放(原为硬失败),
   仅当锁仍被有效占用时才拒绝。

新增 lock_ttl_hours / lock_is_stale / release_stale_locks 三个辅助;
lock status 显示各锁 TTL;cmd_done 改调 release_stale_locks。

验证:20 项 TTL 探针 + 5 项 lock_cli 接线探针全绿;
假 UV4 端到端(exit 0 自持自释、payload ttl=0.5)与 busy 路径(exit 4)。
This commit is contained in:
2026-10-12 18:59:49 +08:00
parent 3c7ad9c75c
commit e5d3dc1205
5 changed files with 119 additions and 31 deletions
@@ -180,13 +180,20 @@ D:/Code/DTU Code/
- ST-LINK SN `0B250D12A218303030303032`
- 设备 IP `192.168.1.100`
机制:`_wt/.state/locks/{build,bench}.lock` 记录持有者(任务 ID + pid + 时间戳 + 备注)。
机制:`_wt/.state/locks/{build,bench}.lock` 记录持有者(任务 ID + pid + 时间戳 + 备注 + 自报 TTL)。
**锁不绑定进程存活**:`lock acquire` 本身是短命进程,而真正用资源的烧录/构建在另一个进程里跑。
若按 pid 判活,acquire 一退出锁就被判为陈旧 → 锁形同虚设(实测踩到)。
故判「陈旧」只看**时效**(`LOCK_TTL_HOURS` = 6 小时)加显式 `--force`;pid 仅作排障记录。
故判「陈旧」只看**时效**(该锁的 TTL)加显式 `--force`;pid 仅作排障记录。
同任务重复 acquire 幂等;他人持锁时 acquire 拒绝(`--wait` 可轮询等待)。
`done` 前置检查会在任一锁被占用时拒绝回收。
**TTL 按锁分设**(2026-10-12):`LOCK_TTL_HOURS = {"build": 1.0, "bench": 6.0}`。
口径 = 兜底窗口应与**操作真实时长**同量级:编译是秒~分钟级(`keil_build.py` 自持自释,
窗口 ≈ UV4 运行时长),1h 已足够宽松;bench 是**会话级**(flash→`@test`→探针),才配得上 6h。
持有者还可用 `lock acquire ... --ttl <小时>` **自报**更精确的窗口——
`keil_build.py` 即按其 `--timeout` 自报(`timeout/3600 + 15min`,下限 0.5h)。
`done` 前置检查:**陈旧锁自动接管释放**(不再硬失败),仅当锁仍被有效占用时才拒绝回收。
> ⚠ 台架相关的既有陷阱(`--require-selftest-pass` 的陈旧台账、回读校验会复位目标)
> 不因引入工作树而改变,仍按 `docs/测试说明/自动化测试流程.md` 执行。
@@ -366,7 +373,7 @@ docs\内存管理\RAM使用分析与优化方案.md:585 [路径引用] docs/内
**实测暴露并已修复的 4 个缺陷**:
1. **锁绑定进程存活 → 形同虚设**:`lock acquire` 是短命进程,一退出锁就被判陈旧、下次必被接管。
改为**时效判定**(6 小时 TTL)+ 显式 `--force`,pid 仅作记录。
改为**时效判定**(当时全局 6h;2026-10-12 起改为按锁分设 TTL,见 §7.1)+ 显式 `--force`,pid 仅作记录。
2. **`git branch -d` 按环境 HEAD 判「已合并」**:集成点被改走时误判、拒绝删除。
改为显式 `merge-base --is-ancestor <branch> <base>` 后再删。
3. **直调 Win32 建联接被拒**(Win32 4392):改走 `mklink /J`(详见 3.3)。