feat: prepare 2.2.0 with UI and execution fixes

Add dark theme, richer Markdown and readable plugin results.
Improve Android input evidence, response integrity and diagnostics.
Unify lifecycle, guidance receipts and evidence sources across clients.
Keep direct action dispatch without an added AI quota approval layer.
Align version metadata at 2.2.0 and bundle Helper 1.2.2.

Validation: 3063 backend tests before the version bump; 44 after.
Frontend: 317 tests and production build passed.
This commit is contained in:
chenmingxuan committed 2026-10-26 00:44:13 +08:00
1 parent 83bcfd54d5
commit fac4ccb760
146 files changed
+5689 -2033

No files matched your search

+96
View File
@@ -0,0 +1,96 @@
from artemis.runtime.task_progress import progress_snapshot
def test_queued_time_is_not_execution_time_even_with_legacy_started_at():
value = progress_snapshot(job={"status": "queued", "created_at": 10, "started_at": 10}, now=50)
assert value["phase"] == "queued"
assert value["durations"]["queued"] == 40
assert value["durations"]["execution"] is None
def test_progress_splits_wait_pause_review_and_export_without_double_counting():
value = progress_snapshot(
job={
"status": "completed",
"created_at": 10,
"worker_started_at": 20,
"ended_at": 120,
"finalized_at": 125,
},
control={
"status": "running",
"timing": {
"started_at": 20,
"state_started_at": 80,
"seconds": {"queued": 10, "task_paused": 20, "resuming": 10, "running": 20},
},
},
reviews=[{"started_at": 90, "ended_at": 110}, {"started_at": 100, "ended_at": 115}],
now=500,
)
assert value["phase"] == "finished"
assert value["durations"] == {
"total": 115,
"queued": 10,
"resource_wait": 20,
"paused": 20,
"final_review": 25,
"execution": 35,
"report_export": 5,
}
def test_active_review_has_its_own_phase_and_terminal_review_is_not_still_active():
review = {"started_at": 30, "status": "running", "updated_at": 35}
live = progress_snapshot(job={"status": "running"}, reviews=[review], now=40)
assert live["phase"] == "final_review"
assert live["durations"]["final_review"] == 10
stopped = progress_snapshot(
job={"status": "cancelled", "ended_at": 45}, reviews=[review], now=500
)
assert stopped["phase"] == "finished"
assert stopped["durations"]["final_review"] == 5
assert not stopped["review_timing_complete"]
def test_legacy_missing_intervals_are_unknown_rather_than_zero_or_model_speed():
value = progress_snapshot(
session={"status": "completed", "start_time": 20, "end_time": 100}, now=500
)
assert value["durations"]["queued"] is None
assert value["durations"]["execution"] is None
assert value["durations"]["paused"] is None
assert value["durations"]["total"] is None
assert value["observed_seconds"] == 80
def test_waiting_for_resource_and_pause_are_not_running():
for status, phase in (
("queued", "waiting_resources"),
("resuming", "waiting_resources"),
("task_paused", "paused"),
):
value = progress_snapshot(
job={"status": "running", "worker_started_at": 10}, control={"status": status}, now=50
)
assert value["phase"] == phase
def test_terminal_without_end_timestamp_does_not_keep_increasing_or_guess_duration():
job = {"status": "completed", "created_at": 10, "worker_started_at": 20}
first = progress_snapshot(job=job, now=100)
assert first == progress_snapshot(job=job, now=500)
assert first["observed_at"] is None
assert all(first["durations"][key] is None for key in ("total", "execution", "report_export"))
def test_export_in_progress_keeps_total_current_without_extending_execution():
value = progress_snapshot(
job={"status": "finalizing", "created_at": 10, "worker_started_at": 100, "ended_at": 200},
now=230,
)
assert value["phase"] == "report_export"
assert value["observed_at"] == 230
assert value["durations"]["total"] == 220
assert value["durations"]["report_export"] == 30
assert value["worker_ended_at"] == 200