# Test — Annotations Endpoint & Payload Shape **Task**: AZ-460_test_annotations_endpoint **Name**: Annotation save URL + payload contract **Description**: Implement the two blackbox tests that pin the annotation-save endpoint URL (AC-N5 doubly-prefixed canary) and the full required-fields payload shape (`Source`, `WaypointId`, `videoTime`, `mediaId`, `detections`, `status`). **Complexity**: 2 points **Dependencies**: AZ-456_test_infrastructure **Component**: 06_annotations (Blackbox Tests) **Tracker**: AZ-460 **Epic**: AZ-455 ## Problem Two prior regressions (`_docs/02_document/modules/src__features__annotations.md` finding #32 and the AC-N5 doubly-prefixed URL) are silent if no test pins the contract. The annotation save path is one mutation away from leaking AI vs Manual provenance or dropping the waypoint association — both impossible to recover after-the-fact. ## Outcome - 2 test scenarios pass per the contract. - Tests assert ALL six required keys are present in every save, regardless of which UI path issued the save (AI suggestion accept, manual draw, multi-edit). - The endpoint URL canary detects doubly-prefixed regressions immediately. ## Scope ### Included | Scenario | Profile | Source file | results_report row | |----------|---------|-------------|--------------------| | FT-P-07 — annotation save endpoint URL is doubly-prefixed | fast + e2e | blackbox-tests.md | per FT-P-07 | | FT-P-08 — annotation save body contains all required fields | fast + e2e | blackbox-tests.md | row 23 | ### Excluded - Bulk-validate path (covered in 09_test_bulk_validate). - Annotation-status SSE (covered in 03_test_sse_lifecycle). - Tile-split path (covered in 19_test_tile_split_zoom). ## Acceptance Criteria **AC-1: URL canary** FT-P-07 captures the outbound URL for every annotation save in the test and asserts it equals the expected canary (`/api/annotations/annotations/...`). **AC-2: Required-fields presence** FT-P-08 captures the outbound body for every annotation save and asserts ALL of `Source`, `WaypointId`, `videoTime`, `mediaId`, `detections`, `status` are present, with `Source` ∈ `{AI, Manual}` per the wire contract. **AC-3: Multiple entry points** The required-fields check runs for at least three save entry points: AI suggestion accept, manual draw, and bulk-edit save — to catch path-specific regressions. ## System Under Test Boundary - System under test: `` + `` + `src/api/client.ts` save call path. - Allowed stubs: MSW for the suite's annotations endpoint (fast); real `annotations/` service (e2e). - Disallowed: stubbing the components above; reading their internal state. - Expected observables compared against `results_report.md` row 23 + the row for FT-P-07. ## Constraints - Tests MUST use the typed wire shape from `src/types/index.ts` (enum compliance is in 04_test_wire_contract_enums; here we only check key presence). - E2E tests run after a fresh seed so the test can issue multiple saves without polluting state. ## Risks & Mitigation **Risk 1 — Source field default** - *Risk*: If a future commit defaults `Source` to one branch unconditionally, the test may pass but the provenance is lost. - *Mitigation*: AC-3 — the test runs for both AI and Manual entry points and asserts the specific value, not just presence.