docs(m7): backfill changelog + testing-m7 for the two post-merge UX fixes

User feedback flagged that the doc didn't reflect the two hotfixes shipped
after the M7 PR:
- evidence whitelist surfaced in the dropzone + OS picker pre-filter
- executed_at override fixed in non-UTC timezones (no more time-snap)

Added a CHANGELOG entry per fix and a §3.5 in tasks/testing-m7.md walking
through the timezone semantics of the datetime-local input. spec.md is
left untouched — these are UX/implementation fixes, not contract changes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Knacky
2026-05-15 09:51:23 +02:00
parent cfcc06cf14
commit 5030f4bd83
2 changed files with 32 additions and 2 deletions

View File

@@ -4,6 +4,18 @@ All notable changes to this project will be documented here. Format: [Keep a Cha
## [Unreleased]
### Fixed (post-M7 UX feedback — evidence whitelist visibility)
- **Evidence dropzone didn't tell the operator which extensions are accepted, and the OS file picker showed "All files"** (`frontend/src/pages/MissionTestPage.tsx`): an operator could spend the time picking a `.exe` only to receive a 400 back. Surfaced the whitelist in the UI:
- Dropzone now prints `Accepted: .png · .jpg · .jpeg · .pdf · .txt · .log · .json · .csv · .evtx · .zip · max 25 MB / file` (testid `evidence-allowed-formats`).
- `<input type="file" accept=".png,.jpg,…">` pre-filters the OS picker to those extensions.
- `handleFiles` rejects drag-and-drops of unsupported extensions client-side (still re-checked server-side — defence in depth, not a security boundary).
- Constants `EVIDENCE_ALLOWED_EXTENSIONS` + `EVIDENCE_MAX_BYTES` in `frontend/src/lib/missions.ts` keep a single source of truth client-side. Manual mirror of `app/services/evidence.py:ALLOWED_EXTS` + `MAX_BYTES`; cross-referenced via comments so the next bump touches both files.
### Fixed (post-M7 UX feedback — executed_at override editable in any timezone)
- **Time portion of the `executed_at` override was un-editable in non-UTC timezones** (`frontend/src/pages/MissionTestPage.tsx:RedZone`): the naive `new Date(executedAt).toISOString().slice(0, 16)` round-trip on every keystroke silently shifted the hour by the local TZ offset, snapping the time field back to UTC each render. The date could be changed (offset shifts both source and target by the same amount), but the hour couldn't stick.
- Fix: keep the local state in `YYYY-MM-DDTHH:MM` form (`executedAtLocal`) and only convert to/from UTC ISO at the boundaries — initial sync from server (`isoToLocalInputValue`) and submit (`localInputValueToIso`).
- Also tightened the `useEffect` reset on both Red and Blue zones to depend on `test.id` instead of the whole `test` object so a polling refetch (every 15 s) no longer wipes an in-progress edit. The 15 s activity poll returns a fresh object reference even when the row's content is unchanged.
### Fixed (post-M7 review pass — spec-reviewer + code-reviewer)
- **Idempotent transition leaked false success to a wrong-side user** (`backend/app/services/mission_tests.py:570`): a blue-only viewer POSTing `target_state="executed"` while the test was already executed got a 200 idempotent response, falsely advertising that they held `mission.write_red_fields`. Reordered the gate so the side-perm check runs *before* the idempotency short-circuit, with a new `_IDEMPOTENT_SIDE` table that asks "which side originally produced this state?" — re-asserting that perm even on no-op replays. Test `test_idempotent_transition_still_checks_side_perm`.
- **Cross-mission evidence access not pinned by a test** (`backend/tests/test_mission_tests.py:test_evidence_member_of_other_mission_gets_404`): added explicit coverage that a user who is a blue member of mission B sees 404 on an evidence row attached to mission A. The chain walk in `_resolve_evidence_chain` already enforced this, but the regression test was missing.