feat(workbench): add dynamic task approval lifecycle
This commit is contained in:
@@ -88,7 +88,6 @@ def test_runtime_endpoint_returns_typed_empty_projection(monkeypatch):
|
||||
async def no_operations(_conn):
|
||||
return WorkbenchOperationsAvailability(
|
||||
schedules=False,
|
||||
work_orders=False,
|
||||
alerts=False,
|
||||
)
|
||||
|
||||
@@ -192,7 +191,6 @@ def test_runtime_endpoint_keeps_analysis_projection_out_of_conditions(monkeypatc
|
||||
async def no_operations(_conn):
|
||||
return WorkbenchOperationsAvailability(
|
||||
schedules=False,
|
||||
work_orders=False,
|
||||
alerts=False,
|
||||
)
|
||||
|
||||
@@ -374,7 +372,7 @@ def test_analysis_run_endpoint_returns_404_for_an_unknown_run(monkeypatch):
|
||||
assert response.status_code == 404
|
||||
|
||||
|
||||
def test_runtime_endpoint_reads_work_order_and_alert_storage(monkeypatch):
|
||||
def test_runtime_endpoint_reads_alert_storage_without_legacy_work_orders(monkeypatch):
|
||||
app = build_test_app(workbench_runtime.router, "/api/v1")
|
||||
configure_dependencies(app)
|
||||
now = datetime(2026, 9, 17, 2, 30, tzinfo=timezone.utc)
|
||||
@@ -386,46 +384,9 @@ def test_runtime_endpoint_reads_work_order_and_alert_storage(monkeypatch):
|
||||
async def operations_available(_conn):
|
||||
return WorkbenchOperationsAvailability(
|
||||
schedules=False,
|
||||
work_orders=True,
|
||||
alerts=True,
|
||||
)
|
||||
|
||||
async def work_orders(_conn, project_id):
|
||||
assert project_id == str(PROJECT_CONTEXT.project_id)
|
||||
return [{
|
||||
"id": "wo-1",
|
||||
"code": "WO-1",
|
||||
"scheduled_at": now,
|
||||
"title": "阀门复核",
|
||||
"summary": "现场复核阀门。",
|
||||
"status": "completed",
|
||||
"risk_level": "normal",
|
||||
"updated_at": now,
|
||||
"detail": "正式工单同步记录。",
|
||||
"recommendation": None,
|
||||
"duration_minutes": 30,
|
||||
"source": "生产工单系统",
|
||||
"dispatcher": "调度中心",
|
||||
"priority": "normal",
|
||||
"subtasks": [{
|
||||
"id": "inspect-valve",
|
||||
"title": "阀门复核",
|
||||
"summary": "现场复核阀门。",
|
||||
"status": "completed",
|
||||
"scheduled_at": now,
|
||||
"location": "V-1",
|
||||
"assignee": "现场班组",
|
||||
"duration_minutes": 30,
|
||||
"reply_window_minutes": 15,
|
||||
"stages": [
|
||||
{"id": "dispatch", "sequence": 1, "title": "派发", "status": "done", "owner": "调度中心", "time_label": "10:30", "description": "已派发。"},
|
||||
{"id": "execution", "sequence": 2, "title": "执行", "status": "done", "owner": "现场班组", "time_label": "10:30—11:00", "description": "已执行。"},
|
||||
{"id": "reply", "sequence": 3, "title": "复令", "status": "done", "owner": "现场班组", "time_label": "11:00—11:15", "description": "已复令。"},
|
||||
],
|
||||
"reply_requirements": ["回传结果"],
|
||||
}],
|
||||
}]
|
||||
|
||||
async def alerts(_conn, project_id):
|
||||
assert project_id == str(PROJECT_CONTEXT.project_id)
|
||||
return [{
|
||||
@@ -445,7 +406,6 @@ def test_runtime_endpoint_reads_work_order_and_alert_storage(monkeypatch):
|
||||
|
||||
monkeypatch.setattr(workbench_runtime.AnalysisRepository, "list_recent_runs", empty_runs)
|
||||
monkeypatch.setattr(workbench_runtime.WorkbenchOperationsRepository, "availability", operations_available)
|
||||
monkeypatch.setattr(workbench_runtime.WorkbenchOperationsRepository, "list_work_orders", work_orders)
|
||||
monkeypatch.setattr(workbench_runtime.WorkbenchOperationsRepository, "list_alerts", alerts)
|
||||
|
||||
response = TestClient(app).get("/api/v1/workbench/runtime")
|
||||
@@ -455,9 +415,8 @@ def test_runtime_endpoint_reads_work_order_and_alert_storage(monkeypatch):
|
||||
assert payload["source"] == "none"
|
||||
assert payload["schedule_availability"] == "not_configured"
|
||||
assert payload["conditions"] == []
|
||||
assert payload["work_order_availability"] == "ready"
|
||||
assert payload["work_orders"][0]["code"] == "WO-1"
|
||||
assert payload["work_orders"][0]["status"] == "completed"
|
||||
assert payload["work_order_availability"] == "not_configured"
|
||||
assert payload["work_orders"] == []
|
||||
assert payload["alert_availability"] == "ready"
|
||||
assert payload["alerts"][0]["title"] == "泵站通信告警"
|
||||
assert payload["alerts"][0]["source"] == {
|
||||
@@ -465,44 +424,3 @@ def test_runtime_endpoint_reads_work_order_and_alert_storage(monkeypatch):
|
||||
"task_id": "diagnosis-5m",
|
||||
"run_id": "trigger-1",
|
||||
}
|
||||
|
||||
|
||||
def test_runtime_endpoint_isolates_invalid_work_order_documents(monkeypatch):
|
||||
app = build_test_app(workbench_runtime.router, "/api/v1")
|
||||
configure_dependencies(app)
|
||||
|
||||
async def empty_runs(_conn, *, limit):
|
||||
assert limit == 100
|
||||
return []
|
||||
|
||||
async def operations_available(_conn):
|
||||
return WorkbenchOperationsAvailability(
|
||||
schedules=False,
|
||||
work_orders=True,
|
||||
alerts=False,
|
||||
)
|
||||
|
||||
async def invalid_work_orders(_conn, _project_id):
|
||||
return [{"id": "wo-invalid", "subtasks": []}]
|
||||
|
||||
monkeypatch.setattr(workbench_runtime.AnalysisRepository, "list_recent_runs", empty_runs)
|
||||
monkeypatch.setattr(
|
||||
workbench_runtime.WorkbenchOperationsRepository,
|
||||
"availability",
|
||||
operations_available,
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
workbench_runtime.WorkbenchOperationsRepository,
|
||||
"list_work_orders",
|
||||
invalid_work_orders,
|
||||
)
|
||||
|
||||
response = TestClient(app).get("/api/v1/workbench/runtime")
|
||||
|
||||
assert response.status_code == 200
|
||||
payload = response.json()
|
||||
assert payload["source"] == "none"
|
||||
assert payload["schedule_availability"] == "not_configured"
|
||||
assert payload["work_order_availability"] == "degraded"
|
||||
assert payload["availability"] == "degraded"
|
||||
assert payload["work_orders"] == []
|
||||
|
||||
Reference in New Issue
Block a user