feat(m7-amend2): implicit lifecycle — writes drive state, no workflow UI

User: «Enlève également le workflow d'un test, quand on saisit des
informations côtés redteam cela signifie qu'il a été exécuté et donc
en attente d'une review blueteam.»

Backend (update_mission_test_fields)
- At the end of every PUT, inspect the touched-field set:
  - any red write on state in {pending, skipped, blocked} → state=executed
    + auto-stamp executed_at=now() if absent
  - any blue write on state=executed → state=reviewed_by_blue
- /transition endpoint kept for back-fill/admin use, not called from UI.

Frontend MissionTestPage
- Removed the transition-buttons header block and the `transition`
  mutation. State pill stays as a passive indicator.
- New labels: "Not started" / "Awaiting review" / "Reviewed" describe
  the implicit lifecycle, no longer exposing the state-machine concept.

E2E
- The SPA test that clicked `transition-executed` now verifies the
  implicit promotion: typing red fields and saving flips the pill from
  "Not started" → "Awaiting review", no button click required.

Spec
- §4 reword: "Cycle de vie implicite, piloté par les écritures" replaces
  the old "Workflow par test instance" bullet.

Tests
- 3 new pytest: red_command-alone implicit execute + auto-stamp,
  blue write promotes executed→reviewed, blue write on pending no-op.
- 142 pytest + 49 Playwright green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Knacky
2026-05-15 16:09:26 +02:00
parent 40114d041b
commit 28b8855e88
7 changed files with 141 additions and 70 deletions

View File

@@ -382,19 +382,16 @@ test.describe('M7 — Test execution', () => {
await page.goto(`/missions/${m.id}/tests/${testId}`);
await expect(page.getByTestId('mission-test-page')).toBeVisible();
await expect(page.getByTestId('state-pill')).toContainText(/Pending/);
await expect(page.getByTestId('state-pill')).toContainText(/Not started/);
// Fill the red command + comment, then save.
// Fill the red command + comment, then save. Post-amendement 2026-05-15
// bis: writing red fields implicitly promotes the state — no transition
// button click required.
await page.getByTestId('red-command').fill('whoami /priv');
await page.getByTestId('red-comment').fill('Verified locally');
await page.getByTestId('red-save').click();
// After save the state-pill stays Pending (only transitions change it).
await expect(page.getByTestId('state-pill')).toContainText(/Pending/);
// Now transition to executed via the header button.
await page.getByTestId('transition-executed').click();
await expect(page.getByTestId('state-pill')).toContainText(/Executed/);
await expect(page.getByTestId('state-pill')).toContainText(/Awaiting review/);
// The "last touched" line should now mention the red user.
await expect(page.locator('text=/Last touched/')).toBeVisible();