feat(ack): refine intake and validation workflow

This commit is contained in:
2026-08-04 10:52:37 +08:00
parent b9c82b5520
commit 5018a1801d
32 changed files with 1602 additions and 302 deletions
+91
View File
@@ -403,6 +403,41 @@ class AckTaskValidationTests(unittest.TestCase):
"delivery run 只能引用 verified 任务",
)
def test_validation_ready_delivery_run_does_not_require_pull_request(self) -> None:
board = valid_manual_routing_board()
board["project"]["deliveryFile"] = "docs/ack/delivery.yaml"
board["tasks"][0]["status"] = "verified"
board["deliveryRuns"] = [
{
"id": "DR-local-1",
"profile": "local-validation",
"taskIds": ["T-1"],
"status": "validation_ready",
"sourceRevision": "a" * 64,
"configRevision": "b" * 64,
"pullRequest": None,
"artifacts": [
{
"id": "local-service",
"type": "file",
"reference": "music-pilot",
"digest": "sha256:" + "c" * 64,
}
],
"deployments": [
{
"environment": "local-8080",
"result": "succeeded",
"evidence": "HTTP 200 and preflight passed",
}
],
"evidence": ["http://127.0.0.1:8080 ready for user validation"],
"updatedAt": "2026-08-03T23:10:00+08:00",
}
]
self.assert_board_accepted_in_all_modes(board)
def test_delivery_runs_and_delivery_file_must_appear_together(self) -> None:
board = valid_manual_routing_board()
board["deliveryRuns"] = []
@@ -1111,6 +1146,62 @@ class AckTaskValidationTests(unittest.TestCase):
"dispatch.rounds: round 必须从 1 连续递增且不重复",
)
def test_environment_incidents_do_not_consume_round_budget(self) -> None:
board = valid_knowledge_board()
board["tasks"][0]["status"] = "fixed_by_dev"
board["tasks"][0]["dispatch"] = {
"rounds": [],
"environmentIncidents": [
{
"id": f"T-1-ENV-{index}",
"attemptId": f"T-1-A{index}",
"role": "test",
"phase": "browser",
"status": "resolved",
"summary": "browser runtime was unavailable",
"evidence": "browser executable lookup returned no result",
"impact": "interactive acceptance signals were not evaluated",
"recoveryAction": "launch a network-enabled fresh Test worker",
"userAction": "none; Coordinator continues the recovery",
"reportedAt": "2026-08-03T20:00:00+08:00",
"resolvedAt": "2026-08-03T20:05:00+08:00",
}
for index in range(1, 5)
],
}
self.assert_board_accepted_in_all_modes(board)
def test_environment_incidents_require_actionable_reporting(self) -> None:
board = valid_knowledge_board()
board["tasks"][0]["dispatch"] = {
"rounds": [],
"environmentIncidents": [
{
"id": "WRONG-ENV-9",
"role": "observer",
"phase": "unknown",
"status": "resolved",
"summary": "",
"evidence": "",
"impact": "",
"recoveryAction": "",
"userAction": "",
"reportedAt": "",
}
],
}
self.assert_board_rejected_in_all_modes(
board,
"environmentIncidents[0].id: 应为 T-1-ENV-1",
"environmentIncidents[0].role: 必须是 coordinator/developer/test",
"environmentIncidents[0].phase: 非法环境阶段",
"environmentIncidents[0].summary: 必须是非空字符串",
"environmentIncidents[0].userAction: 必须是非空字符串",
"environmentIncidents[0]: resolved 必须填写 resolvedAt",
)
def test_leftover_reason_must_be_nonempty_string_in_all_modes(self) -> None:
board = {
"version": 1,