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:
@@ -168,17 +168,16 @@ function CommentairesCell({
|
||||
test: MissionTest;
|
||||
detectionLevels: DetectionLevel[];
|
||||
}) {
|
||||
// Commentaires is blue-team content only — the workflow state lives in
|
||||
// the Test column (cf. user feedback 2026-05-15 ter).
|
||||
const lvl = detectionLevels.find((l) => l.id === test.detection_level_id);
|
||||
return (
|
||||
<div className="flex flex-col gap-1">
|
||||
<div className="flex gap-1 flex-wrap">
|
||||
<Tag accent={MISSION_TEST_STATE_ACCENT[test.state]}>
|
||||
{MISSION_TEST_STATE_LABEL[test.state]}
|
||||
</Tag>
|
||||
{lvl && (
|
||||
{lvl && (
|
||||
<div>
|
||||
<Tag accent={(lvl.color_token as 'red') ?? 'cyan'}>{lvl.label_en}</Tag>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{test.blue_comment_md && (
|
||||
<p className="font-mono text-3xs text-text whitespace-pre-wrap">
|
||||
{truncate(test.blue_comment_md, 220)}
|
||||
@@ -371,6 +370,11 @@ export function MissionScenarioTable({
|
||||
>
|
||||
<td className="py-2 px-2 text-text-bright">
|
||||
<div className="flex flex-col gap-1">
|
||||
<div>
|
||||
<Tag accent={MISSION_TEST_STATE_ACCENT[t.state]}>
|
||||
{MISSION_TEST_STATE_LABEL[t.state]}
|
||||
</Tag>
|
||||
</div>
|
||||
<span>{t.snapshot_name}</span>
|
||||
<div className="flex flex-wrap gap-1">
|
||||
{t.mitre_tags.slice(0, 3).map((tag) => (
|
||||
|
||||
Reference in New Issue
Block a user