feat: P1-21 ADR 变更级联失效 — 架构变更自动失效已完成任务

- TaskNode 新增 adr_refs 字段(ADR→任务溯源链)
- 新增 INVALIDATED 状态,允许覆盖 DONE/DISPATCHED
- TaskGraph.invalidate_by_adr() 级联失效 + BFS 下游传播
- PlanDelta 新增 rollback_ref(回滚快照引用)
- CascadeReport 数据结构(失效统计 + 任务ID列表)
- Eng dispatch_frozen 冻结调度,ready_tasks() 返回空
- handle_adr_invalidation() 10步处理流程(含 git revert)
- unfreeze_after_replan() Arc 重新规划后解冻
- AirRvr check_invalidated_cleanup() 检查旧代码残留
- INV-15 + L1 保障项 15 写入 SKILL.md
- 11 项功能测试全通过,含 ffmpeg→gstreamer 完整场景

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
AirLongDian
2026-06-11 11:13:53 +08:00
parent 19a4550830
commit f2f49d0094
6 changed files with 709 additions and 5 deletions

View File

@@ -136,6 +136,25 @@ class ReviewRuntime:
"deliveryVerdict": report.get("highRiskAudit", {}).get("deliveryVerdict", "safe-to-ship"), # P1-19.2
}
def check_invalidated_cleanup(self, invalidated_task_ids: list[str]) -> dict:
"""P1-21: 检查 INVALIDATED 任务的代码是否已清理(无残留)。"""
from air_runtime.io import safe_json_load
residual = []
for tid in invalidated_task_ids:
# 检查是否有残留的 result 文件(说明旧代码未被 revert
result_dir = self._state_dir.parent / "airdo" / "tasks" / tid
if result_dir.exists():
result_file = result_dir / "result.json"
if result_file.exists():
data = safe_json_load(result_file)
if data and data.get("status") == "done":
residual.append({"taskId": tid, "reason": "done result still exists — code may not be reverted"})
return {
"cleaned": len(residual) == 0,
"residualCount": len(residual),
"residualDetails": residual,
}
@staticmethod
def _report_to_dict(report: ReviewReport) -> dict:
# P1-19.2: highRiskAudit 序列化