Files
missions/_docs/02_document/04_verification_log.md
T
Oleksandr Bezdieniezhnykh a26d7b163b [AZ-549] B10a: clean up forward-looking notes; mark image rename done
The .woodpecker/build-arm.yml already pushes ${REGISTRY_HOST}/azaion/missions
(landed earlier as part of the B5 csproj/namespace rename). What this commit
fixes is the missions-internal documentation that still described the legacy
azaion/flights image as the *current* state.

Edits:

- _docs/02_document/deployment/environment_strategy.md: drop "today's edge
  compose still references azaion/flights" — B10 is done. Container/service
  name 'flights' still noted as B6/B11 work.
- _docs/02_document/deployment/containerization.md: drop "today's Dockerfile
  ENTRYPOINT is dotnet Azaion.Flights.dll, image tag base is azaion/flights"
  — both AZ-544 (B5) and AZ-549 (B10) done.
- _docs/02_document/deployment/ci_cd_pipeline.md: same fix.
- _docs/02_document/components/07_host/description.md: same fix.
- _docs/02_document/04_verification_log.md row for AZ-549: explicitly
  marked "done"; Code symbol column converged to post-rename value.
- _docs/00_problem/restrictions.md E6: parenthetical reworded so the row
  reads as a present-state assertion (B10 done) instead of a forward-
  looking note.
- _docs/02_document/glossary.md "Synonym pairs" heading flipped from
  "today's code ↔ post-rename target" to "pre-rename ↔ post-rename"
  (adjacent hygiene — B5-B9+B10 are done across the missions rename
  Epic; the table's "today" framing no longer matches reality).

Spec _docs/tasks/todo/AZ-549a_missions_rename_b10_pipeline.md moved to
_docs/tasks/done/.

rg -F 'azaion/flights' missions/ | grep -v done/ now returns only
intentional pre-rename historical references in glossary.md /
architecture.md / restrictions.md / verification_log.md — the "current
state" wording is gone.

Suite-side slice (AZ-549b — _infra/deploy/*/docker-compose.yml image
ref + ci/README.md example) shipped separately in the suite repo.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-16 11:57:09 +03:00

22 KiB
Raw Blame History

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 (B5B12) 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/missions:*-arm, dotnet Azaion.Missions.dll (post-B5+B10) AZ-549 (B10), AZ-544 (B5) — done

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<Waypoint> Flight [Table("flights")] with created_date, name, aircraft_id; associations Aircraft?, List<Waypoint> ✓ 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 / UpdateFlightaircraftExists 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 REISSUED 2026-05-14 — ECDSA-SHA256 against admin's JWKS (cached via ConfigurationManager<JsonWebKeySet> with HttpDocumentRetriever{RequireHttps=true} + private JwksRetriever); ValidateIssuer = true against JWT_ISSUER; ValidateAudience = true against JWT_AUDIENCE; ClockSkew = 30 seconds; ValidAlgorithms = [EcdsaSha256]; RequireSignedTokens = true; RequireExpirationTime = true. Single "FL" policy post-B7 Auth/JwtExtensions.cs matches the reissued claim exactly; today has BOTH "FL" and "GPS" policies ✓ B7 drops "GPS". The previous verdict ("matches exactly" against the HS256 / shared-secret doc) was wrong — the underlying docs were stale; corrected via the 2026-05-14 re-verification pass and rewritten in modules/auth.md, components/05_identity/description.md, diagrams/flows/flow_jwt_validation.md, architecture.md § 7 + Tech Stack, system-flows.md Cross-cutting #1 + F5, and 00_problem/* (see § 4.3 below)
F6 Startup + migration REISSUED 2026-05-14Program.cs builds host → ConfigurationResolver.ResolveRequiredOrThrow resolves DATABASE_URL (with ConvertPostgresUrl) → resolves JWT_ISSUER + JWT_AUDIENCE + JWT_JWKS_URL (all required, no fallback) → registers scoped services + JWT bearer + JWKS ConfigurationManager → reads CorsConfig:AllowedOrigins + CorsConfig:AllowAnyOriginCorsConfigurationValidator.EnsureSafeForEnvironment (throws in Production with implicit-permissive config) → registers CORS policy (permissive OR WithOrigins) → migrates → starts. Pipeline: ErrorHandlingMiddleware FIRST → Cors → Authentication → Authorization → Swagger → MapControllers → MapGet("/health") → Run. May emit PermissiveDefaultWarning startup log when implicit-permissive CORS applies Program.cs matches the reissued claim exactly; service registration is FlightService, WaypointService, AircraftService today instead of Mission/Waypoint/VehicleService ✓ B5+B6 rename + DI re-registration. The previous verdict ("matches exactly" against docs claiming hardcoded JWT_SECRET fallback + unconditional permissive CORS) was wrong — corrected via the 2026-05-14 re-verification pass and rewritten in modules/program.md, components/07_host/description.md, diagrams/flows/flow_startup_migration.md, architecture.md § 3 deployment table + ADR-005, and system-flows.md F6
F7 Health probe MapGet("/health", () => Results.Ok(new { status = "healthy" })), anonymous identical ✓ no rename gap

All flow claims reconcile after the 2026-05-14 reissue. ✓

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 15 and the data-flow table numbers them 18. 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 unconditional, etc.) — note: "CORS unconditional" was REMOVED from this list on 2026-05-14. CORS is gated by Infrastructure/CorsConfigurationValidator.cs; it throws in Production with implicit-permissive config and falls back to permissive (with PermissiveDefaultWarning) only in non-Production. See § 4.3 below All remaining items are real, already documented with their resolution path These are the intentional carry-forward items

4.3 Re-verification pass on 2026-05-14 (targeted)

While preparing autodev Step 4 (Code Testability Revision), a targeted code-level cross-check of Auth/JwtExtensions.cs, Program.cs, Infrastructure/{ConfigurationResolver, CorsConfigurationValidator}.cs, Database/DatabaseMigrator.cs, and Services/*.cs against the corresponding _docs/ artifacts surfaced that the original § 3 verdicts for F5 (JWT) and F6 (Startup) had been performed doc-vs-doc rather than against actual source. The actual code state is materially different from what the docs described. The findings were captured in _docs/02_document/05_drift_findings_2026-05-14.md; the doc revisions applied in this pass:

Doc Sections rewritten
modules/auth.md Full rewrite — ECDSA + JWKS + ConfigurationManager + iss/aud + 30s skew + alg pin; no fallback
modules/program.md Internal Logic block; Configuration table (6 keys); Security; External Integrations; Notes
modules/database.md Internal Logic — explicit TIMESTAMP (not TIMESTAMPTZ), explicit REFERENCES, explicit DEFAULT clauses
components/05_identity/description.md Full rewrite — same scope as modules/auth.md
components/07_host/description.md Header source-of-truth note; Implementation Details (Configuration table + CORS gating); Caveats
diagrams/flows/flow_jwt_validation.md Full rewrite — new sequence with JWKS resolver + algorithm-pin step + iss/aud branches
diagrams/flows/flow_startup_migration.md Preconditions + sequence + flowchart + data-flow + error-scenarios — 4 required env vars + CORS gate
architecture.md Architecture Vision; § 5 External Integrations; § 7 Security Architecture; § 3 Environment-specific config table; Tech Stack JWT row; ADR-005 (scope reduced)
data_model.md § 5 ERD — column-type annotations; § 6 Owned-table invariants — explicit FK / TIMESTAMP notes
system-flows.md Cross-cutting #1 (JWT); F5 sequence + error table; F6 sequence + error table
04_verification_log.md (this file) § 3 rows F5 + F6 reissued; § 4.2 row F3 corrected; this § 4.3 block added
00_problem/* (Phase 2 — next session) AC-5 group, AC-6.1/6.2, AC-9.1, AC-1.5/1.6/2.3, E1, E3, E4, E9 — see 05_drift_findings_2026-05-14.md Phase 2
_docs/02_document/tests/* (Phase 2 — next session) environment.md (JWKS mock), test-data.md, blackbox-tests.md (case-insensitive + ordering), security-tests.md (full NFT-SEC revision), resilience-tests.md (NFT-RES-05 + NFT-RES-07), traceability-matrix.md — see drift findings Phase 2

Root cause (recorded in _autodev_state.md for the retrospective): the prior verification step did doc-vs-doc consistency checks for these areas instead of opening the actual .cs files. The docs were internally consistent describing a stale HS256 / shared-secret / permissive-CORS / dev-fallback world that no longer exists in code. Subsequent verification passes (Step 4 prep, this reissue) must open source files for any flow whose verdict is "matches exactly" and explicitly note which files were read.

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 (D1D9 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 (B5B12).
  • 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, after the 2026-05-14 reissue corrected the F5 (JWT) and F6 (Startup) flow descriptions to match actual code.
  • One systematic doc-internal inconsistency was found and fixed in the initial pass: the global error envelope's wire-shape case-style was misstated as PascalCase across 8 files when the middleware actually emits camelCase.
  • One doc-vs-code drift was found and fixed in the 2026-05-14 reissue: the JWT model (ECDSA + JWKS + iss/aud + 30s skew + alg pin, fail-fast on missing env), the configuration model (ResolveRequiredOrThrow — no hardcoded fallbacks), the CORS model (gated; Production hard-fail), and the DB schema details (TIMESTAMP, REFERENCES, DEFAULTs). The downstream test-spec re-issue is queued for the next autodev session (Phase 2 in 05_drift_findings_2026-05-14.md).
  • No hallucinated entities or methods. No missing module or component coverage.

Outcome: docs are now accurate as the spec for B5B12 AND faithful to the actual current behavior of the JWT / config / CORS / DB-schema surfaces. The next autodev pass continues from Phase 2 (test-spec scoped re-issue), then Phase 3 (resume Step 4 — Code Testability Revision).