Files
missions/_docs/02_document/04_verification_log.md
T
Oleksandr Bezdieniezhnykh 78dea8ebab
ci/woodpecker/push/build-arm Pipeline was successful
chore: update configuration and Docker setup for JWT and test results
Enhanced the .gitignore to exclude test results and updated the Dockerfile to include a new entrypoint script for improved container initialization. Refactored JWT configuration to support additional parameters for automatic refresh intervals, ensuring better control over token management. Updated the ConfigurationResolver to enforce required environment variables without hardcoded fallbacks, enhancing security and flexibility.
2026-05-15 03:23:23 +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/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<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).