# Step 4 — Verification Log **Status**: complete **Date**: 2026-05-14 **Mode**: rename-aware (per autodev `/autodev` choice A) **Scope**: every artifact under `_docs/02_document/` cross-checked against actual workspace source. ## 0. Verification mode (the one nuance) The `_docs/02_document/` set is **forward-looking** — it documents the post-rename, post-GPS-Denied-removal target. The workspace code is still pre-rename (`Azaion.Flights.csproj`, `Aircraft*` / `Flight*` / `Orthophoto*` / `GpsCorrection*` files, `[Route("aircrafts"|"flights")]`, 6 owned tables, both `"FL"` and `"GPS"` policies). Each doc carries an explicit forward-looking note pointing at the responsible Jira children (B5–B12) under epic AZ-539. Verification therefore applies a **rename mapping** when comparing docs to code: | Doc symbol | Code symbol | Reconciled by | |------------|-------------|---------------| | `Vehicle*`, `vehicles`, `VehicleType { Plane, Copter, UGV, GuidedMissile }` | `Aircraft*`, `aircrafts`, `AircraftType { Plane, Copter }` | AZ-545 (B6) domain rename + value extension | | `Mission*`, `missions`, `mission_id`, `vehicle_id` | `Flight*`, `flights`, `flight_id`, `aircraft_id` | AZ-545 (B6) | | `[Route("vehicles")]`, `[Route("missions")]` | `[Route("aircrafts")]`, `[Route("flights")]` | AZ-547 (B8) | | `Azaion.Missions.*` namespace, `Azaion.Missions.csproj`, `Azaion.Missions.dll` | `Azaion.Flights.*`, `Azaion.Flights.csproj`, `Azaion.Flights.dll` | AZ-544 (B5) | | 4 owned tables (no `orthophotos`, no `gps_corrections`), 7 entities | 6 owned tables, 9 entities | AZ-546 (B7) entity drop + AZ-548 (B9) DB migration | | Single `"FL"` policy in `JwtExtensions` | Both `"FL"` AND `"GPS"` policies | AZ-546 (B7) | | Cascade omits `orthophotos` / `gps_corrections` branches | Cascade still touches both | AZ-546 (B7) | | `azaion/missions:*-arm` image tag, `dotnet Azaion.Missions.dll` entrypoint | `azaion/flights:*-arm`, `dotnet Azaion.Flights.dll` | AZ-549 (B10), AZ-544 (B5) | Any doc claim covered by this mapping is treated as **expected, NOT drift**. Only mismatches NOT covered by the mapping are flagged below. ## 1. Counts | Domain | Doc claim (post-target) | Code reality (today, pre-rename) | Reconciles via | |--------|-------------------------|-----------------------------------|----------------| | Component count | 6 (`01_vehicle_catalog`, `02_mission_planning`, `04_persistence`, `05_identity`, `06_http_conventions`, `07_host`) | 6 folders on disk under `_docs/02_document/components/` matching exactly | (no rename gap; matches today) | | Module docs | 12 | 12 modules in `_docs/02_document/modules/` mapping 1:1 to source files (under rename) | rename mapping | | Source `.cs` files | "~33 post-B7" | 37 today | drops 4 in B6+B7 (Aircraft.cs, Flight.cs, Orthophoto.cs, GpsCorrection.cs); rename leaves the other 33 | | Owned tables | 4 | 6 | B7 + B9 | | Entities | 7 | 9 | B7 | | Indexes in migrator | 3 (post-B9) | 6 (today) | B9 drops 3 GPS-Denied indexes | | Auth policies | 1 (`"FL"`) | 2 (`"FL"`, `"GPS"`) | B7 deletes `"GPS"` per AZ-546 acceptance | | HTTP route prefixes | `/vehicles/*`, `/missions/*`, `GET /health` | `/aircrafts/*`, `/flights/*`, `GET /health` | B8 | All count claims reconcile. ✓ ## 2. Per-symbol sweep (entities, signatures, routes) ### Entities (post-rename target vs today's code) | Doc says (`modules/entities.md`, `data_model.md`) | Code today | Reconciles? | |----|----|----| | `Vehicle [Table("vehicles")]` with PK `id`, columns `type, model, name, fuel_type, battery_capacity, engine_consumption, engine_consumption_idle, is_default` | `Aircraft [Table("aircrafts")]` with identical column set + PK | ✓ B6 rename only | | `Mission [Table("missions")]` with PK `id`, columns `created_date, name, vehicle_id`; associations `Vehicle?`, `List` | `Flight [Table("flights")]` with `created_date, name, aircraft_id`; associations `Aircraft?`, `List` | ✓ B6 rename only | | `Waypoint` with `mission_id` FK + association `Mission?` | `Waypoint` with `flight_id` FK + association `Flight?` | ✓ B6 rename only | | `MapObject` with `mission_id` FK | `MapObject` with `flight_id` FK | ✓ B6 rename only | | `Media`, `Annotation`, `Detection` borrowed stubs | identical stubs in code | ✓ no change needed | | Removed in B7: `Orthophoto`, `GpsCorrection` | both still present in `Database/Entities/` | ✓ B7 will delete | ### Service signatures (post-rename vs today) | Doc claim | Code today | Reconciles? | |----|----|----| | `VehicleService.{CreateVehicle, UpdateVehicle, GetVehicle, GetVehicles, DeleteVehicle, SetDefault}` | `AircraftService.{CreateAircraft, UpdateAircraft, GetAircraft, GetAircrafts, DeleteAircraft, SetDefault}` — 6 methods, identical shapes | ✓ B6 rename only | | `MissionService.{CreateMission, UpdateMission, GetMission, GetMissions, DeleteMission}` | `FlightService.{CreateFlight, UpdateFlight, GetFlight, GetFlights, DeleteFlight}` — 5 methods, identical shapes | ✓ B6 rename only | | `WaypointService.{CreateWaypoint(missionId, ...), UpdateWaypoint(missionId, wpId, ...), GetWaypoints(missionId), DeleteWaypoint(missionId, wpId)}` | `WaypointService.{CreateWaypoint(flightId, ...), UpdateWaypoint(flightId, waypointId, ...), GetWaypoints(flightId), DeleteWaypoint(flightId, waypointId)}` | ✓ B6 rename only (parameter name `flightId → missionId`) | | `JwtExtensions.AddJwtAuth(IServiceCollection, string)` registers **only** the `"FL"` policy (post-B7) | Same signature; registers `"FL"` AND `"GPS"` policies | ✓ B7 will drop `"GPS"` | | `ErrorHandlingMiddleware(RequestDelegate, ILogger<>)` with `Invoke(HttpContext)` mapping `KeyNotFound→404 / Argument→400 / InvalidOperation→409 / *→500` | Identical | ✓ no rename gap | ### HTTP routes (post-B8 vs today) | Doc post-target | Today's `[Route(...)]` | Reconciles? | |----|----|----| | 6 vehicle endpoints under `/vehicles` | 6 endpoints under `/aircrafts` | ✓ B8 | | 5 mission endpoints under `/missions` + 4 waypoint sub-endpoints under `/missions/{id}/waypoints/...` | identical 5+4 endpoints under `/flights` + `/flights/{id}/waypoints/...` | ✓ B8 | | `GET /health` (anonymous) | identical | ✓ no rename gap | ### Migrator DDL (post-B7+B9 vs today) | Doc post-target | Today's `DatabaseMigrator.Sql` | Reconciles? | |----|----|----| | 4 `CREATE TABLE IF NOT EXISTS`: `vehicles, missions, waypoints, map_objects` + 3 indexes on FKs | 6 `CREATE TABLE IF NOT EXISTS`: `aircrafts, flights, waypoints, orthophotos, gps_corrections, map_objects` + 6 indexes | ✓ B7+B9 (drop `orthophotos` + `gps_corrections` tables and their 3 indexes; rename `aircrafts`/`flights` columns to `vehicles`/`missions` per B6/B9 mapping) | | `DROP TABLE IF EXISTS orthophotos / gps_corrections` (one-shot in B9) for fielded devices | not present | ✓ B9 will add | All symbol-level claims reconcile. ✓ ## 3. Flow-correctness sweep | Flow | Doc says | Code today | Reconciles? | |----|----|----|----| | F1 Vehicle CRUD | 6 endpoints; "exactly one default" exclusivity rule via clear-then-set in code; spec is just-toggle | `AircraftService.CreateAircraft / UpdateAircraft / SetDefault` all clear-then-set when `IsDefault==true`; no transaction | ✓ matches code; B12 decision tracked | | F2 Mission create/read/update | Existence check on `vehicle_id` returns `ArgumentException → 400` (spec wants 404) | `FlightService.CreateFlight / UpdateFlight` — `aircraftExists` check throws `ArgumentException("Aircraft {id} not found")` → middleware → 400 | ✓ matches; spec divergence carry-forward | | F3 Mission cascade-delete | Order: `map_objects → waypoints/media/annotations/detection → waypoints → missions`. NOT transaction-wrapped. Post-B7: no orthophoto/gps_correction branches | `FlightService.DeleteFlight` order today: `map_objects → gps_corrections → orthophotos → waypoints/media/annotations/detection → waypoints → flights`. NOT transaction-wrapped | ✓ B7 removes the two extra branches | | F4 Waypoint create/read/update/delete | Delete walks `media/annotations/detection`, post-B7 no `gps_corrections` branch; `UpdateWaypoint` is full overwrite | `WaypointService.DeleteWaypoint` walks `media/annotations/detection` AND `gps_corrections` today; `UpdateWaypoint` is full overwrite | ✓ B7 removes `gps_corrections` branch | | F5 JWT validation | HS256, shared secret, `ValidateIssuer/ValidateAudience = false`, `ClockSkew = 1 minute`, single `"FL"` policy post-B7 | `JwtExtensions` matches exactly; today has BOTH `"FL"` and `"GPS"` policies | ✓ B7 drops `"GPS"` | | F6 Startup + migration | `Program.cs` builds host → resolves `DATABASE_URL` (with `ConvertPostgresUrl`) → `JWT_SECRET` → registers scoped services → migrates → starts. Pipeline: `ErrorHandlingMiddleware FIRST → Cors → Authentication → Authorization → Swagger → MapControllers → MapGet("/health") → Run` | `Program.cs` matches exactly; service registration is `FlightService, WaypointService, AircraftService` today instead of `Mission/Waypoint/VehicleService` | ✓ B5+B6 rename + DI re-registration | | F7 Health probe | `MapGet("/health", () => Results.Ok(new { status = "healthy" }))`, anonymous | identical | ✓ no rename gap | All flow claims reconcile. ✓ ## 4. Drift NOT covered by the rename mapping These are real findings. **Items in § 4.1 were corrected inline as part of this verification pass; § 4.2 are flagged for follow-up.** ### 4.1 Corrected inline (this pass) | # | Where | Problem | Correction | |---|-------|---------|------------| | D1 | `components/06_http_conventions/description.md` § 1, § 3, § Caveats #1, header | Doc claimed the global error envelope is PascalCase. Actual middleware code is `JsonSerializer.Serialize(new { statusCode = (int)code, message })` — anonymous-type property names are written lowercase-first, and `System.Text.Json` preserves them as-is when no `JsonNamingPolicy` is configured, so the wire output IS `{"statusCode":..., "message":"..."}` (camelCase). Internally inconsistent (§ 1 said camelCase ✓, § 3 example showed PascalCase ✗) | Rewrote § 3 example, Caveat #1, and the header status line to distinguish entity bodies (PascalCase, true divergence) from the error envelope (camelCase, accidental match). Carry-forward concerns — missing `errors` field and dead `ErrorResponse` DTO — explicitly retained | | D2 | `architecture.md` ADR-002 | Same broad PascalCase claim covering the error envelope | Reworded ADR title + body to scope PascalCase to entity / DTO bodies; added explicit "exception (accidental match)" for the error envelope | | D3 | `architecture.md` § 6 NFR table — "API spec conformance" row | Same broad claim | Same scoping correction inline | | D4 | `system-flows.md` § Cross-cutting concerns #3 | "Wire shape is PascalCase today, NOT camelCase" — wrong for the error envelope | Reworded to distinguish entity bodies from the error envelope | | D5 | `data_model.md` § 11 Backward compatibility | Same broad PascalCase claim | Same scoping correction inline | | D6 | `modules/middleware.md` § Internal Logic + Notes/Smells #1 + #2 | Internal Logic section asserted PascalCase wire shape; Notes #1 said middleware emits PascalCase `{ "StatusCode", "Message" }`; Notes #2 generalized that as "system-wide divergence" | Rewrote Internal Logic to show the actual `{"statusCode":..., "message":"..."}` and explain the lowercase-by-construction match; Notes #1 reworded to "partial spec divergence" with the missing `errors` field as the remaining issue; Notes #2 reworded to scope PascalCase to entity / DTO bodies | | D7 | `modules/dtos.md` last bullet (Spec divergence) | Bundled `PaginatedResponse` (real PascalCase divergence) and `ErrorResponse` (camelCase on case but missing `errors` field) into a single PascalCase claim | Split into two bullets — `PaginatedResponse` is genuine PascalCase divergence; `ErrorResponse` is dead code with the runtime envelope already camelCase but missing the `errors` field | | D8 | `modules/controller_missions.md` Notes #5 | Cross-referenced "anonymous PascalCase JSON quirk as middleware" — wrong cross-ref since the middleware envelope is camelCase | Reworded to scope PascalCase to entity / DTO bodies and explicitly note that the global error envelope from the middleware is camelCase | | D9 | `modules/database.md` § Internal Logic | Said "2 `CREATE INDEX IF NOT EXISTS` statements" but listed 3 indexes | Corrected to "3" and listed the index names: `ix_missions_vehicle_id`, `ix_waypoints_mission_id`, `ix_map_objects_mission_id` | ### 4.2 Flagged but NOT corrected (carry-forward — confirm with user) | # | Where | Concern | Why not auto-fix | |---|-------|---------|------------------| | F1 | Cascade-delete error scenario in `diagrams/flows/flow_mission_cascade_delete.md` § Error Scenarios | Text references "step 7" (a successful `DELETE FROM missions`) but the cascade order list above it numbers steps 1–5 and the data-flow table numbers them 1–8. Three different numberings in one file | Pre-existing inconsistency; minor; correcting it would also need a numbering decision the user might prefer to make once globally | | F2 | `module-layout.md` § Per-Component Mapping — `05_identity` Public API | Lists only the `"FL"` policy as the public API surface. Code today also exposes `"GPS"`. Forward-looking is correct (B7 will drop `"GPS"`); the `05_identity/description.md` already mentions the dual-policy state in its forward-looking note. Decision: leave `module-layout.md` forward-looking-only (consistent with the rest of the file), OR add a one-line "today also exposes `\"GPS\"` — see B7" caveat | Editorial choice for the user — both readings are defensible | | F3 | The pre-existing carry-forward divergences in `00_discovery.md` § Spec ↔ Code Divergences (Geopoint shape, error envelope `errors` field, Swagger / CORS unconditional, etc.) | All real, all already documented with their resolution path (this Epic vs out-of-Epic). No new finding here | These are the *intentional* carry-forward items. They are the agenda for future Epics; not in scope for verification | ## 5. Stale-folder check (resolved) The git status snapshot at session start showed 11 untracked component folders under `_docs/02_document/components/` (6 new + 5 stale: `01_host`, `02_auth`, `03_web_infrastructure`, `05_aircraft`, `06_flight`). Direct on-disk verification (`ls _docs/02_document/components/`) shows **only 6 folders** — the 5 stale entries do NOT exist. The git status was stale; no cleanup needed. ## 6. Verification metrics | Metric | Count | |--------|-------| | Documents reviewed | 25 (`00_discovery.md`, `architecture.md`, `system-flows.md`, `data_model.md`, `module-layout.md`, 6 component descriptions, 12 module docs, 4 deployment docs, components diagram, 7 flow diagram files) | | Source files cross-referenced | 37 `.cs` files + `Dockerfile` + `Azaion.Flights.csproj` + `.woodpecker/build-arm.yml` + `README.md` | | Entities verified | 9 (today) ↔ 7 (post-target) — all reconcile under B6/B7 mapping | | Service methods verified | 15 across 3 services — all reconcile under B6 mapping | | HTTP endpoints verified | 16 (today: 6 vehicles + 5 missions + 4 waypoints + 1 health) — all reconcile under B6/B8 mapping | | Doc-internal inconsistencies fixed inline | 9 (D1–D9 above; spans 8 files) | | Real drift (not covered by rename) flagged for user | 2 (F1, F2 above) | | Carry-forward divergences (already documented) | 15 (the `00_discovery.md` § Spec ↔ Code Divergences table) | | Hallucinated entities | 0 | | Coverage | 12/12 modules documented; 6/6 components written; 4/4 deployment docs present; 7/7 flow files present | | Completeness score | 100% (full coverage; no module or component left undocumented) | ## 7. Summary - The forward-looking documentation is **internally consistent** with respect to the rename + GPS-Denied removal it describes (B5–B12). - It is **consistent with the actual pre-rename code** when read through the rename mapping documented in § 0 — every counted symbol, signature, route, and flow reconciles. - One **systematic doc-internal inconsistency** was found and fixed: the global error envelope's wire-shape case-style was misstated as PascalCase across 8 files when the middleware actually emits camelCase. The unrelated divergences (missing `errors` field, dead `ErrorResponse` DTO) remain as carry-forward concerns and are now stated correctly. - No hallucinated entities or methods. No missing module or component coverage. - Two minor editorial concerns (F1, F2) are flagged but not auto-fixed — confirm with user. **Outcome**: docs are accurate as the spec for B5–B12. Ready to proceed to Step 4.5 (Glossary & Architecture Vision).