fix(m7): red write always lands on executed + state pill out of Commentaires
User reported two issues on the scenario table:
1. After filling only red_command + executed_at, the pill read
"Reviewed" instead of "Awaiting review". Cause: the auto-promotion
was gated on `state in {pending, skipped, blocked}`, so a test that
blue had already reviewed stayed in `reviewed_by_blue` after a red
edit. That contradicts the implicit lifecycle (red modifying a
reviewed test invalidates the review).
2. The state pill lived inside the Commentaires column, polluting a
cell meant for blue-team comments.
Fixes
- backend/app/services/mission_tests.py: any red-side write now lands
the state on `executed` unconditionally (including from
`reviewed_by_blue`). Same-PUT red+blue still flows
executed → reviewed_by_blue.
- frontend/src/pages/MissionScenarioTable.tsx: state pill moves from
CommentairesCell to the Test column (top of the row, above the
snapshot name + MITRE chips). Commentaires now holds only the
detection_level pill + blue_comment_md.
Tests
- New pytest: `test_red_write_on_reviewed_reverts_to_executed` —
reviewed_by_blue + red edit ⇒ executed. 143 pytest green.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -611,13 +611,17 @@ def update_mission_test_fields(
|
||||
|
||||
# Implicit lifecycle (post-amendement 2026-05-15 bis): the explicit
|
||||
# workflow is gone from the UI. A write to ANY red field implies the
|
||||
# test was executed (auto-stamp executed_at if the operator didn't
|
||||
# supply one); a write to ANY blue field on an executed test implies
|
||||
# the blue team reviewed it. The /transition endpoint stays for
|
||||
# back-fill but is no longer the primary path.
|
||||
# test was executed AND the review (if any) is potentially stale —
|
||||
# so the state always lands on `executed`, even from `reviewed_by_blue`
|
||||
# (red just changed something, blue needs to re-review). A write to
|
||||
# ANY blue field on an executed test implies the blue team reviewed
|
||||
# it. Note that a same-PUT red+blue (e.g. an admin filling both
|
||||
# sides) flows `* → executed → reviewed_by_blue` and lands on
|
||||
# `reviewed_by_blue`. The /transition endpoint stays for back-fill
|
||||
# but is no longer the primary path.
|
||||
red_touched = bool(touched & _RED_FIELDS)
|
||||
blue_touched = bool(touched & _BLUE_FIELDS)
|
||||
if red_touched and test.state in {"pending", "skipped", "blocked"}:
|
||||
if red_touched:
|
||||
if test.executed_at is None:
|
||||
test.executed_at = datetime.now(tz=timezone.utc)
|
||||
test.executed_at_overridden = False
|
||||
|
||||
Reference in New Issue
Block a user