Commit Graph

72 Commits

Author SHA1 Message Date
Oleksandr Bezdieniezhnykh dceaddc436 [AZ-794] [AZ-795] [AZ-796] Adopt cycle 7 tasks (API quality follow-up)
Adopt three Jira tickets originally filed by gps-denied-onboard
AZ-777 Phase 1 Jetson probing into satellite-provider cycle 7.

- AZ-794: rename inventory body fields tileZoom/tileX/tileY → z/x/y
  (OSM convention; aligns body shape with URL slippy-map convention).
- AZ-795: epic + shared infra ship for strict input validation across
  all public endpoints (FluentValidation + global ProblemDetails
  filter + JsonSerializerOptions.UnmappedMemberHandling.Disallow).
- AZ-796: first concrete per-endpoint child of AZ-795 — strict
  validation for POST /api/satellite/tiles/inventory; reference
  implementation pattern for sibling per-endpoint tasks.

Re-labels the cross-repo follow-up section in _dependencies_table.md
as Step 9 cycle 7, sets cycle 7 ordering (shared infra → rename →
inventory validator), and bumps the autodev state cursor to Step 10
(Implement) for cycle 7.

Source: gps-denied-onboard AZ-777 Phase 1 Jetson probe (2026-05-22).
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-22 08:53:51 +03:00
Oleksandr Bezdieniezhnykh 7d3ba1c3fd Enhance .cursor documentation and workflows
ci/woodpecker/push/01-test Pipeline was successful
ci/woodpecker/push/02-build-push Pipeline was successful
Updated the README.md to reflect new skill commands and improved descriptions for various workflows, including the addition of new skills like /test-spec, /code-review, and /release. Enhanced clarity on session boundaries and flow resolutions in the auto-chaining process.

Removed the implementer agent file as it is no longer needed. Updated coderule and meta-rule documents to enforce stricter testing and implementation standards, ensuring real results are produced rather than simulated ones.

Revised the autodev flow documentation to include a new release step and clarified the retrospective process. Adjusted the testing rules to specify coverage thresholds for critical paths.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-21 13:52:34 +03:00
Oleksandr Bezdieniezhnykh af661359c7 [AZ-505] Cycle 6 Step 17: retrospective + close cycle
ci/woodpecker/push/01-test Pipeline was successful
ci/woodpecker/push/02-build-push Pipeline was successful
Single-task cycle delivering AZ-505 (3 SP); 1 batch, PASS verdict
after a single auto-fix round (ComputeLocationHash duplication
consolidated into Uuidv5.LocationHashForTile). Step 14 Security
Audit skipped; Step 15 Performance Test PASS (8/8, exit 0) and
closes the cycle-3 perf-harness leftover that carried across
cycles 3-5.

Top 3 lessons appended to LESSONS.md ring buffer:
- Kestrel Http1AndHttp2 requires TLS for ALPN; spec-time decision
- Dapper-bypassing test paths own the Npgsql type contract
- Test fixtures naming specific schema artifacts need migration awareness

Cycle 7 opens at Step 9 (New Task).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-12 23:07:19 +03:00
Oleksandr Bezdieniezhnykh ba3bdb1918 [AZ-505] Cycle 6 Steps 15-16 perf + deploy report
Step 15 (Performance Test): 8/8 PT scenarios PASS in a single
default-parameter run (exit 0). Adapts scripts/run-performance-tests.sh
for the new TLS+ALPN dev listener via CURL_OPTS=(--cacert ./certs/api.crt).
Report at _docs/06_metrics/perf_2026-05-12_cycle6.md. The clean exit-0
satisfies the cycle-3 perf-harness leftover deletion criterion that
carried across cycles 3-5; leftover file deleted.

Step 16 (Deploy): _docs/03_implementation/deploy_cycle6.md captures the
shipping payload (inventory endpoint, HTTP/2 TLS+ALPN, tiles_leaflet_path
covering index, migration 015), the dev-cert plumbing for local-docker +
integration-tests parity, the production-TLS topology note (terminate at
ingress; never promote the dev cert), and the operator runbook for
promoting cycle-6 past dev.

NU1902 / CA2227 / ASPDEPR002 / Serilog-10.x re-listed as carry-overs
unchanged; admin-team iss/aud confirmation unchanged.

State advanced to Step 17 (Retrospective).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-12 23:02:00 +03:00
Oleksandr Bezdieniezhnykh 5d84d2839e [AZ-505] Test-spec sync + task-mode doc updates for cycle 6
ci/woodpecker/push/01-test Pipeline was successful
ci/woodpecker/push/02-build-push Pipeline was successful
Step 12 (Test-Spec Sync, cycle-update mode):
- blackbox-tests.md: append BT-23..BT-26 for AZ-505's new
  observable behaviors (inventory order/shape; leaflet
  most-recent via location_hash; HTTP/2 multiplex over TLS+ALPN;
  request validation).
- performance-tests.md: append PT-09 (inventory p95 ≤ 1000ms /
  2500 tiles); records cycle-6 measured p95=66ms; documents
  promotion path to scripts/run-performance-tests.sh if budget
  ever tightens.
- traceability-matrix.md: resolve the 5 AZ-503 deferrals
  (AC-5/6/9/10/12) by pointing at AZ-505 test names + add 7
  AZ-505 AC rows (AC-1..AC-7) + bump totals (90 -> 94 tests,
  56/56 -> 63/63 in-scope) + add cycle-6 coverage shape notes
  (budget relaxation rationale, voting-filter deferral note,
  TLS+ALPN pivot, NFR propagation).

Step 13 (Update Docs, task mode):
- common_dtos.md: add 5 new TileInventory DTOs.
- common_interfaces.md: add ITileService.GetInventoryAsync.
- services_tile_service.md: document TileService.GetInventoryAsync
  steps + the XOR-validation-in-handler note.
- dataaccess_migrator.md: bump migration count 14 -> 15;
  describe migration 015 (AZ-505 leaflet covering index, lock
  window, INCLUDE-list trade-off).
- system-flows.md: add F7 (Leaflet Tile Serving, AZ-310 +
  AZ-505 location_hash rewire + TLS+ALPN) and F8 (Tile
  Inventory Bulk Lookup) with sequence diagrams, validation
  surface, and AC-4 perf evidence. Update Flow Inventory +
  Dependencies tables accordingly.
- glossary.md: add "Tile Inventory" entry pointing at the
  v1.0.0 contract.
- ripple_log_cycle6.md: new file — exhaustive reverse-dependency
  analysis confirms zero stale downstream module docs.

Advance autodev state from step 11 -> 14 (skipping 12+13 as
completed in this commit; auto-chain through Step 14 = Security
Audit optional gate).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-12 22:29:22 +03:00
Oleksandr Bezdieniezhnykh c74a2339aa [AZ-505] AC-5 fix: enable TLS for HTTP/2 via ALPN
ci/woodpecker/push/01-test Pipeline was successful
ci/woodpecker/push/02-build-push Pipeline was successful
Kestrel with HttpProtocols.Http1AndHttp2 on a plaintext listener
silently downgrades to HTTP/1.1-only (logs "HTTP/2 is not enabled
... TLS is not enabled"), so AC-5's multiplexed-GET test failed
with HTTP_1_1_REQUIRED. ALPN cannot run over plaintext, so the
fix switches the dev listener to TLS on https://+:8080:

- scripts/run-tests.sh generates a self-signed dev cert idempotently
  (./certs/api.pfx + api.crt) via openssl in an alpine container;
  certs/ is gitignored.
- docker-compose.yml binds Kestrel to ASPNETCORE_URLS=https://+:8080
  with Kestrel__Certificates__Default__Path bound to the .pfx.
- docker-compose.tests.yml mounts api.crt into the integration-tests
  container's CA store and runs update-ca-certificates so HttpClient
  trusts the cert transparently; default API_URL is now https://api:8080.
- Drop the obsolete Http2UnencryptedSupport AppContext switch from
  Http2MultiplexingTests; ALPN over TLS handles negotiation.

Test-data fixes caught on the post-TLS rerun (independent of the TLS
switch but surfaced together):

- Http2MultiplexingTests: switch slippy coords from (154321, 95812)
  -- which Google Maps returns 404 for -- to (158485, 91707), the
  slippy projection of (47.461747, 37.647063) already exercised by
  JwtIntegrationTests.
- TileInventoryTests + LeafletPathIndexOnlyTests: SpecifyKind to
  Unspecified at the binding site for raw Npgsql seed paths writing
  into tiles.captured_at / created_at / updated_at (TIMESTAMP without
  tz). Npgsql v6+ refuses Kind=Utc into plain timestamp columns;
  production goes through Dapper and never hits this code path.
- MigrationTests Az503NewUniqueIndexCoversIntegerKeyAndFlightId:
  accept either idx_tiles_location_hash (migration 014) or its
  AZ-505 successor tiles_leaflet_path (migration 015) -- both have
  location_hash as the leading column, which is the AC-9 intent.

Docs updated to reflect the TLS+ALPN path: tile-inventory.md
Non-Goals, modules/api_program.md, module-layout.md, the AZ-505
task spec's Risk 3, and the cycle 6 implementation + completeness
reports. The full integration test suite passes (mode=full, exit 0).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-12 22:19:26 +03:00
Oleksandr Bezdieniezhnykh da40534b49 chore: advance autodev state to Step 11 (Run Tests) after AZ-505 batch 1
ci/woodpecker/push/01-test Pipeline was successful
ci/woodpecker/push/02-build-push Pipeline was successful
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-12 21:17:23 +03:00
Oleksandr Bezdieniezhnykh 3c7cd4e56b chore: update autodev state to Step 10 (Implement) and refine task details for AZ-505
- Advanced the autodev state to Step 10, reflecting the implementation phase.
- Updated task name for AZ-505 to "Implement" and adjusted its status to "not_started."
- Enhanced the dependencies table with detailed context for AZ-505, clarifying its relationship with AZ-503 and its role in cycle 6.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-12 20:17:57 +03:00
Oleksandr Bezdieniezhnykh aa1a1bf19f chore: open cycle 6 — state advanced to Step 9 (New Task)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-12 18:08:17 +03:00
Oleksandr Bezdieniezhnykh 0e05fc519a [AZ-503] [AZ-504] Cycle 5 Step 16 deploy report
deploy_cycle5.md captures everything operators need to promote
cycle 5 beyond dev:

- Code shipped: AZ-503-foundation (deterministic UUIDv5 tile
  identity, integer-only flight-aware UPSERT, per-flight on-disk
  paths) + AZ-504 (perf script grep-pipefail fix).
- NEW database migration 014_AddTileIdentityColumns.sql adds
  flight_id, location_hash, content_sha256, legacy_id; enables
  pgcrypto; swaps the AZ-484 float index for the new
  idx_tiles_unique_identity integer index. Idempotent under
  DbUp's journal.
- NEW contract version uav-tile-upload.md 1.0.0 → 1.1.0 (adds
  optional flightId; derived tileId in response).
- NEW per-flight on-disk path layout for UAV tiles (additive;
  legacy paths preserved).
- No env-var changes. Container image base unchanged from cycle 4.
- Verification gates passed: PASS (Step 11), PASS (Steps 12+13),
  PASS_WITH_WARNINGS (Step 14), PASS_WITH_INFRA_WARNINGS (Step 15).
- Cycle-3 perf-harness leftover stays OPEN with two clean follow-up
  paths recorded (DNS pre-warm in script, OR move perf gate to CI).
- Operator runbook includes pgcrypto pre-install check for managed
  Postgres providers.

Autodev state advanced to Step 17 (Retrospective).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-12 18:01:49 +03:00
Oleksandr Bezdieniezhnykh 61612044fb [AZ-503] [AZ-504] Cycle 5 Steps 11-15 sync
Wrap up cycle 5 verification + documentation:
- Steps 10/11 wrap-up reports (implementation_completeness +
  implementation_report) for the AZ-503-foundation + AZ-504 batch.
- Step 12 test-spec sync: AZ-503-foundation/AZ-504 ACs appended;
  AZ-505 deferred ACs recorded.
- Step 13 update-docs: architecture, data-model, glossary, module-
  layout, uav-tile-upload contract (v1.1.0), DataAccess + Services
  + Tests module docs synced; new common_uuidv5.md module doc.
- Step 14 security audit: PASS_WITH_WARNINGS; 0 new Critical/High;
  2 new Low informational (F1 flightId provenance, F2 pgcrypto
  deploy gap).
- Step 15 performance test: PASS_WITH_INFRA_WARNINGS; PT-08
  passed twice (AZ-504 fix verified); PT-01/02 failed due to
  recurring local Docker/colima DNS cold-start (not an app
  regression). Cycle-3 perf-harness leftover stays OPEN with
  replay #5 documented.
- Autodev state moved to Step 16 (Deploy).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-12 18:01:27 +03:00
Oleksandr Bezdieniezhnykh c646aa93e2 [AZ-503] Tile identity → UUIDv5 + integer UPSERT (foundation)
ci/woodpecker/push/01-test Pipeline was successful
ci/woodpecker/push/02-build-push Pipeline was successful
Foundation half of original AZ-503 (split during /autodev step 10 batch 2
on user choice; deferred work moved to AZ-505 with a Blocks link).

Adds deterministic tile identity (UUIDv5 over (z, x, y, source, flight_id))
shared cross-repo with gps-denied-onboard via the pinned TileNamespace
5b8d0c2e-7f1a-4d3b-9c5e-1f3a8e7d2b6c, switches the tiles UPSERT key from
floats to integers with per-flight separation, plumbs FlightId through
UavTileMetadata + handler, and writes UAV evidence to per-flight
on-disk directories so two flights at the same (z, x, y) coexist.

- Common: pure-C# RFC 9562 Uuidv5 (no third-party dep) + FlightId DTO
  field; 10 Python-reference unit vectors verify byte parity.
- DataAccess: migration 014 adds flight_id (uuid NULL), location_hash
  (uuid NOT NULL, backfilled via session-scoped pg_temp.uuidv5),
  content_sha256 (bytea NULL), legacy_id (uuid NULL = preserves
  pre-AZ-503 random id one cycle); drops idx_tiles_unique_location_source
  (AZ-484) and adds idx_tiles_unique_identity keyed on
  (tile_zoom, tile_x, tile_y, tile_size_meters, source,
   COALESCE(flight_id, '00000000-...'::uuid)) + idx_tiles_location_hash.
- TileRepository: ColumnList + UPSERT updated; id never updated on
  conflict (preserves AC-2 idempotence). UpdateAsync extended.
- Services: TileService and UavTileUploadHandler compute deterministic
  Id + LocationHash + ContentSha256 before insert; UAV file path
  becomes ./tiles/uav/{flight_id or 'none'}/{z}/{x}/{y}.jpg.
- Tests: Uuidv5Tests (10 reference vectors), UavTileFilePathTests
  (per-flight + anonymous paths), UavTileUploadHandlerTests (AC-2,
  AC-3, AC-7, AC-11 unit-level), UavUploadTests (AC-3 + AC-4
  integration: multi-flight DB coexistence with shared location_hash
  + distinct file_path; float-different lat/lon collapse to 1 row),
  MigrationTests (column shape, idx_tiles_unique_identity supersedes
  AZ-484 index, deterministic backfill).
- IntegrationTests project references Common to reuse Uuidv5 in raw
  SQL seeds.
- AZ-488 MultiSourceCoexistence seed fixed to populate location_hash
  (otherwise migration 014's NOT NULL constraint fails).

ACs covered: AC-1, AC-2, AC-3, AC-4, AC-7, AC-8, AC-11.
ACs deferred to AZ-505: AC-5, AC-6, AC-9, AC-10, AC-12.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-12 17:07:35 +03:00
Oleksandr Bezdieniezhnykh f6197499a4 chore: update autodev state after AZ-504 batch 1
ci/woodpecker/push/01-test Pipeline was successful
ci/woodpecker/push/02-build-push Pipeline was successful
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-12 16:33:08 +03:00
Oleksandr Bezdieniezhnykh 8e509b550c [AZ-503] [AZ-504] cycle 5 new-task: tile identity + perf-script-fix
- AZ-503 (3 SP, epic AZ-483) — Tile identity → UUIDv5 deterministic id;
  integer-only UPSERT with COALESCE(flight_id) per-flight separation;
  content_sha256 column; POST /api/satellite/tiles/inventory bulk-list
  endpoint; HTTP/2 at Kestrel edge. Cross-workspace handoff from
  gps-denied-onboard (AZ-304 / AZ-316 counterpart). Supersedes the
  AZ-484 UPSERT-conflict-key portion.

- AZ-504 (1 SP, epic AZ-483) — Fix scripts/run-performance-tests.sh
  lines 416-417: grep -o | wc -l + set -o pipefail kills PT-08 when
  rejected=0. Closes the replay obligation for the cycle-3 perf-harness
  leftover (leftover deletion gated on green full perf run, AC-4).

Updates _dependencies_table.md with cycle 5 entries and records
replay attempt #4 against the perf-cycle3 leftover (PBI opened —
leftover still stays until AZ-504 lands and full perf run is green).

State advanced to Step 10 (Implement).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-12 16:27:40 +03:00
Oleksandr Bezdieniezhnykh e31f59211d [AZ-500] Cycle 4 Step 17: retrospective + close cycle
Adds retro_2026-05-12_cycle4.md, structure_2026-05-12_cycle4.md, and
the deploy_cycle4.md report that was dropped from the Steps 12-15
sync commit. Appends 3 new lessons to LESSONS.md (12/15 ring buffer)
on transitive major-version bumps, exposed pre-existing bugs, and
single-task-cycle metric framing. State advances to cycle 5 / step 9
(awaiting next New Task invocation).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-12 06:14:43 +03:00
Oleksandr Bezdieniezhnykh af4219fce6 [AZ-500] Cycle 4 Steps 12-15 sync (test-spec / docs / security / perf)
ci/woodpecker/push/01-test Pipeline was successful
ci/woodpecker/push/02-build-push Pipeline was successful
Step 12 (Test-Spec Sync) - cycle-update mode
  - traceability-matrix: 8 AZ-500 AC rows + .NET 10 runtime
    restriction supersession + Cycle-4 coverage shape note
    (no new tests; ACs verified by re-running existing 78-test
    suite + build pipeline + manifest grep)

Step 13 (Update Docs) - task mode
  - FINAL_report, 00_discovery, architecture, module-layout,
    api_program, tests_unit: .NET 8 -> .NET 10 / C# 12 -> 14 /
    Swashbuckle 6.6.2 -> 10.1.7 + Microsoft.OpenApi 2.x
    refactor note in api_program; Serilog.AspNetCore 8.0.3
    fallback documented inline per AZ-500 Risk #4
  - deployment/{containerization, ci_cd_pipeline}: Docker
    aspnet/sdk:8.0 -> :10.0
  - ripple_log_cycle4: empty import-graph ripple recorded
    (Program.cs is entry point; ParameterDescriptionFilter only
    consumed by Program.cs; csproj/global.json/Dockerfile have
    no import edges)

Step 14 (Security Audit) - resume mode
  - dependency_scan_cycle4: AZ-500 19-package delta scanned;
    cycle-3 D1+D3 (CVE-2026-26130) closed by major-version
    bump; cycle-3 D2 (Test.Sdk 17.8.0 NuGet.Frameworks flag)
    carried over - explicitly out of AZ-500 scope
  - security_report_cycle4: PASS_WITH_WARNINGS (only carry-over
    Medium open; AZ-500 introduced 0 new Critical/High); cycle-3
    static_analysis/owasp_review/infrastructure_review carried
    forward unchanged (AZ-500 made no source-level edits to
    those surfaces)

Step 15 (Performance Test) - perf mode, full default-param run
  - perf_2026-05-12_cycle4: 7 Pass + 1 Unverified (PT-08 hit
    pre-existing scripts/run-performance-tests.sh:417 grep-
    pipefail bug, NOT a .NET 10 regression)
  - PT-07 warm p95 = 301ms (7.7x improvement vs cycle-3 short
    variant - .NET 10 pipeline + N=20 dilution); cold p95 =
    2782ms (-14%); PT-06 90ms (-49%)
  - AZ-500 NFR (Performance) MET for 7/8 scenarios
  - Cycle-3 perf-harness leftover updated with replay #3
    results; STAYS OPEN per AZ-500 Constraint (deletes only on
    fully clean run)

Recommended follow-up PBIs (out of cycle-4 scope, surfaced for
the backlog):
  - 1 SP fix scripts/run-performance-tests.sh:416-417 grep-
    pipefail (replace grep -o ... | wc -l with grep -c ... ||
    true) - unblocks PT-08 + closes the cycle-3 perf leftover
  - 3 SP migrate WithOpenApi(...) callsites to ASP.NET Core 10
    minimal-API metadata extensions (clears 8 ASPDEPR002
    warnings; recorded in batch_01_cycle4_review.md)
  - 1 SP Microsoft.OpenApi 2.x nullable cleanup (CS8604 in
    ParameterDescriptionFilter.cs:25)
  - 1 SP bump Microsoft.NET.Test.Sdk 17.8.0 -> 17.13.0+
    (closes cycle-3 D2 NuGet.Frameworks transitive flag)

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-12 06:05:29 +03:00
Oleksandr Bezdieniezhnykh 813136326f [AZ-500] .NET 8 -> .NET 10 migration
Coordinated cross-cutting bump: 9 csproj TFMs net8.0 -> net10.0;
global.json sdk.version 8.0.0 -> 10.0.0; all Dockerfiles + scripts/
+ .woodpecker on mcr.microsoft.com/dotnet/{sdk,aspnet,runtime}:10.0;
all Microsoft.AspNetCore.* (8.0.25) and Microsoft.Extensions.* (9.0.10)
packages -> 10.0.7. Serilog.AspNetCore retained at 8.0.3 (10.0.0
requires Serilog.Sinks.File >= 7.0.0; out of AZ-500 scope per "no
unrelated package bumps") -- documented in AGENTS.md. Swashbuckle
9.x bumped to 10.1.7 to track Microsoft.OpenApi 2.x; Program.cs +
ParameterDescriptionFilter.cs refactored for the 2.x namespace
(Microsoft.OpenApi), OpenApiSecuritySchemeReference, JsonSchemaType
enum, and IOpenApiSchema dictionary properties. Fixed implicit AC-5
prereq: scripts/run-performance-tests.sh PERF_DLL path bin/Release/
net8.0 -> net10.0. Docs sync: architecture.md + AGENTS.md.

ACs verified: AC-1..AC-4 + AC-7 + AC-8 by grep + build; AC-6 by
./scripts/run-tests.sh --full (271/271 unit tests + full integration
suite green); AC-5 short bootstrap-smoke (PERF_REPEAT_COUNT=2
PERF_UAV_BATCH_SIZE=2) succeeded at the bootstrap step (no exit 3),
PT-01..PT-07 PASS. PT-08 surfaced a pre-existing grep-pipefail bug
in run-performance-tests.sh:417 -- not an SDK problem; recorded as
follow-up in the perf-cycle3 leftover. Code review verdict:
PASS_WITH_WARNINGS (2 Medium deferred per scope discipline:
WithOpenApi ASPDEPR002 deprecation x8, CS8604 nullable in
ParameterDescriptionFilter.cs; both targeted at follow-up PBIs).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-12 05:28:01 +03:00
Oleksandr Bezdieniezhnykh c0f004d2c9 [AZ-500] Cycle 4 Step 9: new-task .NET 10 migration
Closes Step 9 (New Task) of cycle 4. AZ-500 spec defines the
.NET 8 -> .NET 10 migration (TFM bump on 9 csprojs, global.json
SDK pin to 10.0.0, both Dockerfiles + run-tests.sh + woodpecker
to mcr.microsoft.com/dotnet/*:10.0, Microsoft.AspNetCore.* and
Microsoft.Extensions.* to the 10.x line, Serilog.AspNetCore to
10.x or documented 8.0.3 fallback, plus arch.md + AGENTS.md doc
sync). Closes the cycle-3 perf-harness leftover via AC-5
(bootstrap smoke after migration).

Also logs the cycle-4 perf-leftover replay attempt that
discovered the host-SDK / project-SDK mismatch and rolls the
state file from cycle 3 -> cycle 4 (Step 9 done -> Step 10
ready).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-12 04:35:52 +03:00
Oleksandr Bezdieniezhnykh ca0ca9f2a4 [AZ-491] [AZ-492] [AZ-493] [AZ-494] [AZ-495] [AZ-496] Cycle 3 Step 17: retrospective + close cycle
ci/woodpecker/push/01-test Pipeline was successful
ci/woodpecker/push/02-build-push Pipeline was successful
Cycle-3 retrospective:
  - 6 tasks (AZ-491..AZ-496), 5 batches, 18 SP delivered.
  - 100% code review pass rate (5/5 PASS_WITH_WARNINGS, 0 FAIL).
  - 0 Critical/High/Medium review findings; 7 distinct Low.
  - Security audit PASS_WITH_WARNINGS: 0 new Medium, 3 Low (all
    test-only or operator-CLI), 2 Informational, 1 False Positive.
  - Net Architecture delta: **-3** (F-AUTH-2 + D1 + D3 RESOLVED;
    only new findings are Low test-side surfaces). First
    net-negative cycle on record.
  - 5 of 6 tasks completed first attempt (no post-review fix
    commits). Cycle-2's 2 prior-retro actions all translated to
    closed work (AZ-491 from Action 1, AZ-492 from Action 2,
    AZ-493 from Action 3).

Top 3 cycle-4 improvement actions surfaced:
  1. Execute the perf harness to capture PT-07/PT-08 baseline.
  2. Bump TestSupport JWT pins 7.0.3 → 7.1.2+ (D4 NU1902 cleanup).
  3. Add `workspace:` tag to cross-repo ACs in task-spec writing
     and render them separately in the traceability matrix.

3 new ring-buffer lessons appended to _docs/LESSONS.md:
  - [process] Option-B forcing functions for cross-team blockers.
  - [process] ACs prescribing a measurement should also prescribe
    the collection path.
  - [process] Cross-repo-write ACs need workspace tags.

Structural snapshot at structure_2026-05-12_cycle3.md records the
new SatelliteProvider.TestSupport project (+2 ProjectReference edges
into it; no production-layer dependents) and the AZ-496 package
bumps (8.0.21 → 8.0.25).

Cycle 3 COMPLETE. State advanced to Step 9 (New Task) for cycle 4
per existing-code flow Re-Entry After Completion.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-12 03:46:41 +03:00
Oleksandr Bezdieniezhnykh 65cdfae970 [AZ-491] [AZ-492] [AZ-493] [AZ-494] [AZ-495] [AZ-496] Cycle 3 Step 15 skip + Step 16 deploy report
Step 15 (Performance Test): SKIPPED. User skipped the optional gate
question. Per meta-rule.mdc, performance tests require explicit
approval; a skipped question is not approval. Recorded as leftover at
_docs/_process_leftovers/2026-05-12_perf-cycle3-harness-execution.md
for replay at next /autodev invocation.

Step 16 (Deploy): COMPLETED. Produced deploy_cycle3.md mirroring the
cycle-2 shape. Covers:
  - 9 cycle-3 commits + zero DB migration
  - Config changes (JWT_ISSUER/JWT_AUDIENCE env vars w/ fail-fast,
    8.0.25 package bumps, new TestSupport project)
  - Pre-deploy gate recap (Steps 11-15)
  - Cycle-3 operational risks R1-R4 (admin-team iss/aud confirm,
    cross-repo doc deferral, cycle-2 R1/R3 carry-overs, test-runner
    log line)
  - Rollback plan, post-deploy verification (incl. wrong-iss / wrong-
    aud smoke probes), CI/CD push policy
  - Resolved this cycle: F-AUTH-2, D1, D3, PT-07/PT-08 leftover
  - Follow-up backlog: D4 NU1902 bump, F-DBR-2 third guard, F-PERF-1
    token-history hardening, image-fixture consolidation, AC-7 cross-
    repo write, no-revocation-list residual

Next: Step 17 (Retrospective, cycle-end mode).
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-12 03:42:10 +03:00
Oleksandr Bezdieniezhnykh 314d1dec39 [AZ-491] [AZ-492] [AZ-493] [AZ-494] [AZ-496] Cycle 3 Step 14: security audit refresh
ci/woodpecker/push/01-test Pipeline was successful
ci/woodpecker/push/02-build-push Pipeline was successful
All 5 phases refreshed against cycle-3 delta:

Phase 1 (Dependency Scan):
  - D1 RESOLVED (AZ-496): Microsoft.AspNetCore.OpenApi 8.0.21 → 8.0.25
  - D3 RESOLVED (AZ-496): JwtBearer 8.0.21 → 8.0.25
  - D4 NEW (Low, test-only): System.IdentityModel.Tokens.Jwt 7.0.3 +
    Microsoft.IdentityModel.Tokens 7.0.3 pinned in TestSupport carry
    CVE-2024-21319 (JWE DoS). Bump to ≥ 7.1.2 tracked as future PBI.

Phase 2 (Static Analysis):
  - F-AUTH-3 (Info): test runner Program.cs logs iss/aud at startup;
    production API does NOT (verified by grep).
  - F-AUTH-4 (Info): DEV-ONLY iss/aud placeholders in
    appsettings.Development.json + .env.example — by design per
    Option B for AZ-494.
  - F-DBR-1: TRUNCATE string interpolation in
    IntegrationTestDatabaseReset.cs — false positive (hard-coded
    table list).
  - F-DBR-2 (Low): TRUNCATE guard is operator-bypassable. Two-guard
    model is conservative-by-default and unit-tested.
  - F-PERF-1 (Low): perf-bootstrap --mint-only writes a 4-hour
    GPS-permission token to stdout. Operator-trusted machine assumed.

Phase 3 (OWASP Top 10):
  - A03 carries D1/D3 RESOLVED + D4 NEW.
  - A07 flips F-AUTH-2 to RESOLVED (AZ-494); residual revocation-list
    Low recorded.
  - A05 status unchanged (F-DBR-1 false positive).
  - A08 picks up F-DBR-2.

Phase 4 (Infrastructure):
  - JWT_ISSUER / JWT_AUDIENCE flow .env → compose → Kestrel config,
    same pattern as JWT_SECRET.
  - INTEGRATION_TEST_DB_RESET + ASPNETCORE_ENVIRONMENT=Testing wired
    for AZ-493 reset gate.
  - SatelliteProvider.TestSupport is IsPackable=false — never ships
    in a production container image.
  - New operational gate added to deploy runbook: grep for DEV-ONLY-
    in the rendered deploy environment must return zero hits.

Phase 5 (Security Report):
  - Verdict: PASS_WITH_WARNINGS (cycle 3 does not escalate).
  - 0 Critical, 0 High, 0 new Medium.
  - Cycle-2 F-AUTH-2 (Medium) RESOLVED; cycle-1 D1 + cycle-2 D3
    RESOLVED.

Autodev state advanced to Step 14 completed. Next: Step 15
(Performance Test, optional gate).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-12 03:13:04 +03:00
Oleksandr Bezdieniezhnykh e42bf62152 [AZ-491] [AZ-492] [AZ-493] [AZ-494] [AZ-495] [AZ-496] Cycle 3 Steps 11-13: test-spec sync + ripple log
ci/woodpecker/push/01-test Pipeline was successful
ci/woodpecker/push/02-build-push Pipeline was successful
Step 11 (Run Tests) is recorded as PASS based on the implement skill's
internal Step 16 gate (./scripts/run-tests.sh --full, all-green) per
test-run/SKILL.md § Functional Mode — same runner, immediately
preceding invocation, no value in a second run.

Step 12 (Test-Spec Sync, cycle-update mode):
  - traceability-matrix.md: rows added for AZ-491 AC-1..AC-6,
    AZ-493 AC-1..AC-6, AZ-495 (doc convention), AZ-496 AC-1..AC-N
    (dependency bump); AZ-494 AC-1/AC-2 rows now cross-reference
    new SEC-12 / SEC-13 blackbox IDs.
  - security-tests.md: SEC-12 (wrong iss returns 401) and SEC-13
    (wrong aud returns 401) appended for AZ-494.
  - environment.md: Environment Variables table extended with
    GOOGLE_MAPS_API_KEY, JWT_SECRET, JWT_ISSUER, JWT_AUDIENCE,
    INTEGRATION_TEST_DB_RESET. Closes a cycle-2 oversight where
    JWT_SECRET was never recorded.

Step 13 (Update Docs, task mode):
  - tests_unit.md: consolidated the duplicate
    AuthenticationServiceCollectionExtensionsTests entry that
    spanned AZ-487 + AZ-494 into one coherent block.
  - ripple_log_cycle3.md created: per-task source files +
    every doc that was touched (architecture, module-layout,
    api_program, tests_unit, tests_integration, traceability,
    performance-tests, security-tests, environment, security_report,
    owasp_review, deploy_cycle2, retro_2026-05-11_cycle2). Notes
    which docs were intentionally NOT touched and the open
    cross-repo doc ripple (AC-7).

Autodev state advanced to Step 13 completed. Next: Step 14 Security
Audit (optional gate).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-12 02:57:45 +03:00
Oleksandr Bezdieniezhnykh 495605f51b [AZ-494] [AZ-492] Cycle 3 Step 16: full test suite green; close batches
ci/woodpecker/push/01-test Pipeline was successful
ci/woodpecker/push/02-build-push Pipeline was successful
Final cumulative review for batches 04-05 (PASS_WITH_WARNINGS, 4 Low
findings, all non-blocking). Combined with the prior 01-03 cumulative,
this closes the per-cycle batch coverage with two PASS_WITH_WARNINGS
verdicts.

scripts/run-tests.sh --full green: format check + 13 cycle-3 unit
tests (including the 4 new AZ-494 fail-fast cases for missing /
empty iss / aud) + the full integration suite (including the 2 new
WrongIssuer / WrongAudience 401 assertions).

Fixed a stale "leave blank to fall back" comment in .env.example
that contradicted the "REQUIRED" line right above it; the integration
runner reads env vars directly with no appsettings fallback so blank
values now fail-fast.

Advanced _docs/_autodev_state.md to mark Step 10 (Implement) status:
completed.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-12 02:35:10 +03:00
Oleksandr Bezdieniezhnykh 76076cbd90 [AZ-491] [AZ-492] [AZ-493] [AZ-494] [AZ-495] [AZ-496] Cycle 3 Step 9: 6 task specs
ci/woodpecker/push/01-test Pipeline was successful
ci/woodpecker/push/02-build-push Pipeline was successful
Drains the cycle-2 retrospective top-3 improvement actions plus three
carried-forward security and process items, into 6 individually-
trackable PBIs:

- AZ-491 (3 SP) consolidate JWT test-mint helpers (Retro Action 1)
- AZ-492 (3 SP) perf harness PT-07 + PT-08 + JWT-attach (Retro Act. 2)
- AZ-493 (2 SP) integration test DB-reset hook (Retro Action 3)
- AZ-494 (2 SP) JWT iss/aud validation (cycle-2 F-AUTH-2 Medium)
- AZ-495 (1 SP) doc-folder convention for WebApi (cycle 1+2 F1 carry)
- AZ-496 (2 SP) bump AspNetCore 8.0.21 -> 8.0.25 (cycle 1+2 D1+D3)

All 6 at-or-below the user-rule 5 SP cap. AZ-494 gated on admin-team
confirming iss/aud values. Cycle 3 total: 13 SP.

Autodev pointer advances to Step 10 Implement.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-12 01:15:21 +03:00
Oleksandr Bezdieniezhnykh b69cf5640e [AZ-487] [AZ-488] retro: cycle 2 report + structural snapshot
ci/woodpecker/push/01-test Pipeline was successful
ci/woodpecker/push/02-build-push Pipeline was successful
Cycle-2 retrospective covering AZ-487 + AZ-488. Captures six patterns
(duplicate JWT helpers diverged then both broke; pre-existing
test bugs unmasked by downstream test pressure; cycle 1 perf-NFR
action stopped adding scenarios but did not drain backlog; doc-path
F1 carried over twice with no decision; integration test DB
isolation = wallclock workaround; 8 SP friction observable even
with user override). Top-3 improvement actions: consolidate JWT
mint helpers, promote PT-07/PT-08/JWT-attach to real PBI, real
integration DB-reset hook.

LESSONS.md ring buffer now holds 6 entries (testing x3, process x2,
estimation x1).

Structural snapshot: 6 components / 12 PR edges unchanged; contract
coverage 14% -> 29%; new external NuGet edges (JwtBearer 8.0.21 +
ImageSharp 3.1.11) tied to cycle-2 security findings.

Autodev pointer advances to cycle 3 / Step 9 New Task.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-12 00:43:27 +03:00
Oleksandr Bezdieniezhnykh e9f4e84adb [AZ-487] [AZ-488] docs: cycle 2 deploy report
Per-cycle deploy report covering AZ-487 (JWT baseline) + AZ-488 (UAV
tile batch upload). Lists all 12 cycle-2 commits already pushed to
origin/dev, recaps Steps 11-15 gate outcomes, flags three
operator-gated risks (R1 consumer Bearer-token coordination, R2
JWT_SECRET prod-distinct verification, R3 GPS-permission claim
provisioning), documents rollback (image flip; zero schema change),
and lists deferred follow-ups (PT-07/PT-08 harness + run-perf script
JWT-attach, F1 doc-folder choice).

Advances autodev pointer to Step 17 (Retrospective).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-12 00:37:32 +03:00
Oleksandr Bezdieniezhnykh cbbb26bd28 [AZ-487] [AZ-488] chore: cycle 2 Step 15 skip + record JWT-attach script rot
Step 15 (Performance Test) — skipped per gate (option B). Recording two
deferred items in the existing perf leftover:

* PT-07 + PT-08 remain Deferred. Both NFRs depend on the same
  baseline-capture harness that has not landed; the integration-test
  fixtures needed for PT-08 already exist (UavUploadTests +
  UavTileImageFactory), so PT-08 attaches to the same harness as PT-07
  when implemented.
* scripts/run-performance-tests.sh PT-01..PT-06 currently return 401
  against the post-AZ-487 build because they attach no Bearer token.
  Script must mint an HS256 token from JWT_SECRET at script start
  before any curl call. Tracked in the leftover so PT-01..PT-06 are
  runnable again the same cycle PT-07/PT-08 are activated.

No code change in this commit — leftover + state advance only.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-12 00:35:18 +03:00
Oleksandr Bezdieniezhnykh 5214a4a647 [AZ-487] [AZ-488] security: cycle 2 delta audit (PASS_WITH_WARNINGS)
Step 14 (Security Audit) for cycle 2 — delta scan against the cycle-1
baseline. Verdict remains PASS_WITH_WARNINGS; no Critical/High.

Scope: JWT auth boundary (AZ-487) and UAV multipart upload + ImageSharp
decode of attacker-controlled bytes (AZ-488). Both new packages
(JwtBearer 8.0.21, ImageSharp 3.1.11 in Services.TileDownloader)
checked.

Cycle-2 delta:
* 0 Critical / 0 High
* 2 Medium: F-AUTH-2 (iss/aud not validated — by design until admin
  team publishes values, AZ-487 § Constraints), F-UAV-1 (ImageSharp
  decode now runs on attacker-controlled bytes — mitigations
  sufficient; pin to GHSA subscribe-and-bump policy).
* 4 Low: F-AUTH-1 (DEV-ONLY secret in appsettings.Development.json —
  accepted), F-AUTH-3 (rate-limit gap extends to 401 floods — folds
  into cycle-1 I3), F-UAV-2 (JsonDocument.Parse on signature-validated
  claims — bounded by Kestrel header cap), D3 (JwtBearer shares D1
  patch line).
* 1 Informational: F-UAV-3 (reject reasons disclose gate structure —
  accepted UX trade-off; documented in contract).

OWASP refresh: A01 / A07 move from N/A (with caveat) to
PASS_WITH_WARNINGS (per-tenant authz absent; iss/aud + revocation
gaps tracked).

Pre-deploy operational gate added: deploy pipeline must verify
JWT_SECRET != DEV-ONLY placeholder before promoting api.

Artifacts: dependency_scan.md, static_analysis.md, owasp_review.md,
infrastructure_review.md, security_report.md — all appended with a
"Cycle 2 Delta" section preserving cycle-1 finding IDs.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-12 00:13:58 +03:00
Oleksandr Bezdieniezhnykh e3cd388577 [AZ-487] [AZ-488] docs: cycle 2 doc sync (task mode)
ci/woodpecker/push/01-test Pipeline was successful
ci/woodpecker/push/02-build-push Pipeline was successful
Step 13 (Update Docs) for cycle 2. Most cross-cutting docs were
already updated during Step 10 (architecture.md, glossary.md,
components/03_tile_downloader, modules/api_program.md, data_model.md,
contracts/api/uav-tile-upload.md). This commit completes the remaining
module-level + module-layout updates and writes the cycle-2 ripple log.

* modules/common_configs.md: + UavQualityConfig section and
  appsettings-section row (UavQuality).
* modules/common_dtos.md: + UavTileMetadata, UavTileBatchMetadataPayload,
  UavTileBatchUploadResponse, UavTileUploadResultItem, UavTileUploadStatus,
  UavTileRejectReasons (closed enumeration v1.0.0).
* module-layout.md: refresh Common (+ UavQualityConfig + UAV DTOs),
  TileDownloader (+ UavTileQualityGate, UavTileUploadHandler, +
  SixLabors.ImageSharp 3.1.11 PackageReference), and WebApi (+
  Authentication/*, DTOs/UavTileBatchUploadRequest, + JwtBearer 8.0.21
  PackageReference). Updates the "Last Updated" stamp to cycle 2.
* modules/tests_unit.md: replace the obsolete "only a dummy test"
  description; add cycle-2 AZ-487 / AZ-488 test classes
  (AuthenticationServiceCollectionExtensionsTests, JwtTokenFactoryTests,
  UavTileQualityGateTests, UavTileUploadHandlerTests, UavTileFilePathTests,
  PermissionsRequirementTests) + new ProjectReference / package
  references.
* modules/tests_integration.md: + JwtIntegrationTests, UavUploadTests
  (incl. wall-clock-seeded coordinate counter rationale from the Step 11
  fix), and the StubAndErrorContractTests update for the removed 501
  stub.
* ripple_log_cycle2.md (new): cycle-2 reverse-dependency scan results
  showing every importer of the new symbols resolves inside the three
  already-updated components (WebApi, TileDownloader, Common). No
  unexpected ripple, no heuristic fallback needed.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-12 00:04:05 +03:00
Oleksandr Bezdieniezhnykh 98cdcd17c1 [AZ-487] [AZ-488] docs: cycle 2 test-spec sync
Append cycle 2 entries to test-spec artifacts (cycle-update mode):

* security-tests.md: SEC-05..SEC-09 (AZ-487 JWT 401/403/parity)
  + SEC-10..SEC-11 (AZ-488 permission + reject-detail leak hygiene).
* blackbox-tests.md: BT-13..BT-17 (UAV happy / mixed / multi-source
  coexistence / same-source UPSERT / rule-ordering) + BT-18 (existing
  endpoints parity with Bearer token).
* resource-limit-tests.md: RL-05..RL-07 (MaxBatchSize, per-item MaxBytes,
  Kestrel/Form envelope cap).
* performance-tests.md: untouched (PT-08 already landed with AZ-488 as
  Deferred — see _docs/_process_leftovers/2026-05-11_perf-pt07-harness).
* traceability-matrix.md: append AC rows for AZ-487 AC-1..AC-8 and
  AZ-488 AC-1..AC-10 + AC-7a..AC-7e; annotate "No authentication"
  restriction as superseded by AZ-487+AZ-488; add NFR rows (perf,
  security, reliability, compatibility) for both tasks; refresh totals
  (78 tests; 47/47 ACs; 8/8 restrictions).

Coverage shape: AZ-487 AC-7 (Swagger Authorize) and the perf NFRs are
recorded but not actively measured this commit (manual UI smoke +
deferred PT-08 harness, respectively).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-12 00:00:14 +03:00
Oleksandr Bezdieniezhnykh 1802d32107 [AZ-488] UAV tile batch upload + 5-rule quality gate
Replaces the 501 stub at POST /api/satellite/upload with a multipart
batch endpoint that ingests UAV-captured tiles, runs each item through
a 5-rule quality gate, and persists accepted tiles via the AZ-484
multi-source storage path with source='uav'.

Quality gate (in fixed order, first failure wins): JPEG format
(content-type + magic), size band 5 KiB-5 MiB, exact 256x256
dimensions, captured-at age (no future >30 s skew, no older than
7 days), luminance variance on 32x32 downsample. Closed reject-reason
enumeration in v1.0.0 contract.

Authorization: custom PermissionsRequirement / PermissionsAuthorization
Handler that reads the JWT `permissions` claim (tolerates both
repeated-string and JSON-array shapes). Endpoint protected by
RequiresGpsPermission policy; 401 without token, 403 without GPS perm.

Persistence: file-first to ./tiles/uav/{z}/{x}/{y}.jpg, then
ITileRepository.InsertAsync UPSERT (per-source UPSERT contract from
AZ-484). Per-item failures reported in response without aborting the
batch. Kestrel MaxRequestBodySize and FormOptions limits set to
MaxBatchSize x MaxBytes (default 100 x 5 MiB = 500 MiB).

New frozen contract: _docs/02_document/contracts/api/uav-tile-upload.md
v1.0.0. PT-08 NFR added to performance-tests.md as Deferred (harness
work tracked in PT-07 leftover, per AZ-488 § Risk 4).

Tests: 11 quality-gate unit tests, 5 handler unit tests, 3 file-path
unit tests, 12 permission-handler unit tests, 7 integration tests
(AC-1..AC-6, AC-8). All 253 unit tests + smoke integration suite
green.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-11 23:50:49 +03:00
Oleksandr Bezdieniezhnykh 96cd3c4495 [AZ-487] JWT validation baseline (HS256, all endpoints)
ci/woodpecker/push/01-test Pipeline failed
ci/woodpecker/push/02-build-push unknown status
Adds Microsoft.AspNetCore.Authentication.JwtBearer 8.0.21 and the
SatelliteProvider.Api.Authentication.AddSatelliteJwt extension that
validates HS256 tokens against a shared JWT_SECRET (>=32 bytes, fail
fast at startup). Every minimal-API endpoint now carries
.RequireAuthorization(); the middleware chain is UseExceptionHandler ->
UseHttpsRedirection -> UseCors -> UseAuthentication -> UseAuthorization
-> endpoints. Swagger UI gets a Bearer security definition so the
Authorize button works.

Test infrastructure: JwtTokenFactory (unit) and JwtTestHelpers
(integration) mint deterministic tokens against the same secret; the
integration test runner attaches a default Bearer token to its shared
HttpClient so existing tests continue to exercise protected endpoints.
JwtIntegrationTests adds AC-1..AC-4 and AC-7 (Swagger advertises
Bearer) end-to-end; AuthenticationServiceCollectionExtensionsTests
covers AC-5 (missing/empty/short secret fail-fast) plus env-var
precedence; JwtTokenFactoryTests covers AC-6 (claims pass through
the JwtSecurityTokenHandler.ValidateToken path JwtBearer uses).

docker-compose and scripts/run-tests.sh now propagate JWT_SECRET to
the api and integration-tests containers, with a >=32-byte guard.
.env.example documents the required keys; .env stays gitignored.

Code review verdict: PASS_WITH_WARNINGS (2 Low findings surfaced
in _docs/03_implementation/reviews/batch_01_cycle2_review.md).

Cross-component coordination: gps-denied-onboard and the mission
planner UI must attach Bearer tokens before this lands in dev.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-11 23:06:23 +03:00
Oleksandr Bezdieniezhnykh 8e15e53782 chore: cycle 2 step 9 task plan artifacts + step 10 state
Carries forward new-task research + solution drafts under
_docs/02_task_plans/uav-batch-upload/ that were not included in
the Step 9 task-spec commit (42a3cc7). Also marks the autodev
state as Step 10 in_progress for cycle 2 implementation.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-11 22:54:36 +03:00
Oleksandr Bezdieniezhnykh 42a3cc7467 [AZ-487] [AZ-488] Cycle 2 Step 9: JWT baseline + UAV upload task specs
ci/woodpecker/push/01-test Pipeline was successful
ci/woodpecker/push/02-build-push Pipeline was successful
Created two PBIs for cycle 2 under epic AZ-483 (multi-source tile
storage + UAV upload). Splits the originally-planned single AZ-485
into 2 cohesive tasks because the combined scope was ~10 SP and
JWT auth is independently shippable:

- AZ-487 (2 SP) JWT validation baseline. Adds HS256 JwtBearer
  middleware against JWT_SECRET env var per the suite-level auth
  contract (suite/_docs/10_auth.md). Applies .RequireAuthorization()
  on all existing endpoints. Skips iss/aud validation (suite doc
  does not specify). No /users/me endpoints. Hard prerequisite for
  AZ-488.

- AZ-488 (8 SP, over-cap user-accepted) UAV tile upload endpoint
  with batch + 5-rule quality gate. Replaces the 501 stub. Multipart
  batch DTO, 5 quality rules (format, size band, dimensions,
  captured_at age 7d, blank/uniform variance heuristic). UAV files
  land at ./tiles/uav/{z}/{x}/{y}.jpg; google_maps grandfathered
  at bare ./tiles/{z}/{x}/{y}.jpg. Per-source UPSERT via the
  AZ-484 ITileRepository.InsertAsync. Sync 200 with per-item
  results. Requires GPS permission claim. Produces frozen contract
  uav-tile-upload.md v1.0.0.

Both Jira tickets created and linked. Dependencies table updated.
Autodev state advanced to cycle 2 Step 10 (Implement).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-11 21:04:49 +03:00
Oleksandr Bezdieniezhnykh 18609656f9 [AZ-484] Cycle 1 Step 17 Retrospective: report + structural snapshot
ci/woodpecker/push/01-test Pipeline was successful
ci/woodpecker/push/02-build-push Pipeline was successful
Closes the AZ-484 cycle:
- retro_2026-05-11.md: 5 patterns identified (code-review-PASS does
  not imply runtime PASS; spec-authorship under-specifies wire
  format / test sites; NFR test-spec entries decoupled from runner
  scripts; pre-existing module doc staleness; pre-existing security
  Mediums now visible). Top-3 actions ranked by impact, with target
  rule/skill files and owners.
- structure_2026-05-11.md: baseline structural snapshot for future
  retro deltas (6 components, 12 ProjectReference edges, 0 cycles
  in import graph, 0 net architecture violations, 1 frozen
  contract, ~14% contract coverage).
- LESSONS.md: header rewritten to describe the two-layer format
  (deep lessons + 15-entry ring buffer); appended 3 new ring-buffer
  entries (testing/process/estimation) sourced from this retro.
- _autodev_state.md: cycle 2 starting at Step 9 New Task.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-11 10:08:47 +03:00
Oleksandr Bezdieniezhnykh 51b572108a [AZ-484] Cycle 1 Steps 12-16: docs, security, perf, deploy report
ci/woodpecker/push/01-test Pipeline was successful
ci/woodpecker/push/02-build-push Pipeline was successful
Captures the post-implementation autodev gates for AZ-484 multi-source
tile storage:

- Step 12 (Test-Spec Sync): added 7 AC rows (AZ-484 AC-1..AC-7) and a
  PT-07 NFR row to traceability-matrix.md; added PT-07 scenario to
  performance-tests.md.
- Step 13 (Update Docs): refreshed data_model.md (tiles columns +
  indexes + selection rule + UPSERT contract + migrations 012/013),
  module-layout.md (Common/Enums section with L-001 guidance,
  DataAccess imports-from now lists 6 sites), 6 module / component
  docs to reflect the new repo signatures, source/captured_at fields,
  and Dapper enum bypass workaround. ripple_log_cycle1.md records
  zero out-of-scope ripple.
- Step 14 (Security Audit): PASS_WITH_WARNINGS - 0 Critical, 0 High,
  5 Medium, 5 Low. AZ-484 itself added zero new findings. Hardening
  items (Postgres default creds, .env in build context, GMaps key
  rotation, ASP.NET Core 8.0.21 -> 8.0.25, rate limiter) recorded
  for separate tickets.
- Step 15 (Performance Test): all PT-01..PT-07 scenarios Unverified
  (non-blocking); PT-07 baseline-comparison harness deferred to a
  leftover for next cycle.
- Step 16 (Deploy): cycle deploy report covering migration safety,
  rollback path, post-deploy verification, security caveats.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-11 10:03:05 +03:00
Oleksandr Bezdieniezhnykh e9d6db077c [AZ-484] Fix multi-source tile reads: drop Dapper enum handler
Two integration-test failures uncovered after the initial commit:

1) GetTilesByRegionAsync outer ORDER BY referenced 'updated_at' but
   the inner DISTINCT ON subquery aliased it to 'UpdatedAt' (Postgres
   folds to 'updatedat'). DISTINCT ON already guarantees one row per
   (latitude, longitude, ...) so the third tiebreak was unreachable;
   removed it.

2) Dapper 2.1.35 silently bypasses SqlMapper.TypeHandler<T> for enum
   types during read deserialization (Dapper issue #259). The
   TileSourceTypeHandler worked for writes but reads fell through to
   Enum.TryParse, which cannot map 'google_maps' to GoogleMaps.

   Pivoted: TileEntity.Source is now a string (the wire value).
   TileSource enum stays as the public producer surface in
   Common.Enums; TileSourceConverter (Common.Enums) provides
   ToWireValue / FromWireValue / IsValidWireValue at the boundary.
   TileSourceTypeHandler deleted; registration removed from
   DapperEnumTypeHandlers.RegisterAll.

   tile-storage.md Inv-5 amended to document the storage choice.
   _docs/LESSONS.md L-001 records the Dapper bypass for future cycles.

Full suite passes (213 unit + integration suite incl. AZ-484
AC-1..AC-5, security SEC-01..SEC-04, AZ-356/362/357).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-11 06:44:34 +03:00
Oleksandr Bezdieniezhnykh 687d6bdd5b [AZ-484] Multi-source tile storage: source + captured_at
Add per-source tile rows to support multi-provider imagery (Google
Maps + future UAV). Migration 013 (transactional) introduces
source/captured_at columns, backfills existing rows to
(source='google_maps', captured_at=created_at), and replaces the
4-column unique index with a 5-column index that includes source.

TileRepository:
- ColumnList includes source + captured_at
- GetByTileCoordinatesAsync returns most-recent row across sources
  (ORDER BY captured_at DESC, updated_at DESC, id DESC)
- GetTilesByRegionAsync uses DISTINCT ON to pick the most-recent
  tile per cell, restoring caller-facing row order
- Insert/Update upsert on the new 5-column conflict key

TileSource enum lives in Common.Enums. Snake_case wire format
(google_maps, uav) is enforced by a focused TileSourceTypeHandler
because the generic ToLowerInvariant pattern would emit
"googlemaps", violating contract v1.0.0.

TileService stamps Source=GoogleMaps + CapturedAt=UtcNow on every
new tile. Tile-storage contract is now frozen at v1.0.0.

AC coverage 7/7. New unit + integration tests cover all ACs;
existing 200 unit + 5 smoke tests preserved.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-11 06:21:59 +03:00
Oleksandr Bezdieniezhnykh 5ba58b6c8d [AZ-484] [AZ-483] Add task spec + tile-storage v1.0.0 contract draft
Step-9 (new-task) cycle 1 artifacts for the AZ-483 multi-source tile
storage epic. AZ-485 (UAV upload + quality gate) deferred to a future
Step-9 loop and recorded as planned in the dependencies table.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-11 06:05:06 +03:00
Oleksandr Bezdieniezhnykh 08451df027 [AZ-350] Close 03-code-quality-refactoring: Phase 6+7 + FINAL_report
ci/woodpecker/push/01-test Pipeline was successful
ci/woodpecker/push/02-build-push Pipeline was successful
Phase 6 (Verification): smoke run green (format gate + 200/200
unit + integration smoke). verification_report.md captures
metric deltas vs Phase 0 baseline; all 5 ACs met, all 4
constraints honored, 0 regressions.

Phase 7 (Documentation):
- module-layout.md: corrected DataAccess->Common dependency
  (was mistakenly documented as "Imports from: (none)" by
  prior AZ-315 baseline; csproj reference + 7 import sites
  have actually been there since AZ-309).
- architecture_compliance_baseline.md: F5 entry revised to
  reflect the actual layering invariant (one-way: Common
  MUST NOT import from DataAccess, but DataAccess MAY
  import from Common).
- 00_discovery.md: added "Updates Since Baseline" section
  enumerating the AZ-309 split + AZ-350 27-change run +
  AZ-372 tooling additions; original tree kept as a
  2026-05-10 snapshot.

FINAL_report: complete run summary (10 batches, 27 tasks,
3 K=3 cumulative reviews, baseline->final metric table,
remaining items, lessons learned).

Autodev state: advance Step 8 -> Step 9 (New Task);
sub_step reset to phase 0 awaiting-invocation.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-11 05:23:35 +03:00
Oleksandr Bezdieniezhnykh 9a53bff92e [AZ-375] [AZ-377] HashSet tile lookup + consolidate Earth constants
ci/woodpecker/push/01-test Pipeline was successful
ci/woodpecker/push/02-build-push Pipeline was successful
Batch 24 of 03-code-quality-refactoring run; closes the run.

AZ-375 (C22): GoogleMapsDownloaderV2.DownloadTilesGridAsync now
builds a HashSet<(int X, int Y, int Z)> once from existingTiles
and tests Contains((x, y, zoomLevel)) per cell. Removes the per-cell
FirstOrDefault tolerance scan and the unused _processingConfig
.LatLonTolerance reference at this site.

AZ-377 (C24): promote Earth + tile-pixel constants to a single
home. GeoUtils now exposes EarthRadiusMeters, EarthEquatorial
CircumferenceMeters, MetersPerDegreeLatitude as public const.
MapConfig adds DefaultTileSizePixels (const) wired as the
TileSizePixels property default. TileRepository and Google
MapsDownloaderV2 read those constants instead of duplicating
the literals 6378137, 40075016.686, 111000.0, and 256.

Tests: +6 new (DownloaderRefactorTests, extended GeoUtils
RefactorTests). 200/200 unit tests pass.

Cumulative K=3 review (batches 22-24): PASS_WITH_WARNINGS,
4 Low findings only — see
_docs/03_implementation/reviews/cumulative_review_22-24.md.

Tooling fix: scripts/run-tests.sh --unit-only path now restores
before testing (was failing on SixLabors resolution in clean
container). Stripped stray BOM from MapConfig.cs to satisfy the
.editorconfig charset gate.

Updates _dependencies_table.md to reflect all 27 03-code-quality-
refactoring tasks done; updates _autodev_state.md to refactor
phase 5 (test-sync).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-11 05:14:51 +03:00
Oleksandr Bezdieniezhnykh 6099d1c86b [AZ-376] [AZ-378] [AZ-379] [AZ-380] Repo cleanup: dead code, logger discipline, ColumnList consts
ci/woodpecker/push/01-test Pipeline was successful
ci/woodpecker/push/02-build-push Pipeline was successful
Batch 23 of refactor 03-code-quality-refactoring (4 tasks, 5 SP):

- AZ-376 (C23): Delete unused FindExistingTileAsync from
  ITileRepository / TileRepository. No callers; method also took the
  obsolete `version` arg removed by C06/AZ-357.
- AZ-378 (C25): Repository _logger discipline.
  TileRepository.GetTilesByRegionAsync now emits LogWarning when the
  query exceeds SlowQueryThresholdMs (500 ms). RegionRepository and
  RouteRepository drop the unused ILogger<TRepo> field, parameter, and
  using; Program.cs DI registrations updated.
- AZ-379 (C26): Extract `private const string ColumnList` per repo
  (TileRepository, RegionRepository, RouteRepository); SELECTs use
  $@"SELECT {ColumnList} FROM ..." (C# 10+ const interpolation).
  INSERT/UPDATE/DELETE unchanged; route_points single-site SELECT left
  inline.
- AZ-380 (C27): Delete dead alias GeoUtils.CalculatePolygonDiagonalDistance.

Tests: +9 new (RepositoryRefactorTests x8, GeoUtilsRefactorTests x1)
covering each AC via reflection / file-content assertions; pattern
mirrors ToolingConfigurationTests (b22) and AcceptanceCriteriaRT2Tests
(b19). Unit suite 181 -> 190, all green. dotnet format clean.

Code review: PASS_WITH_WARNINGS (3 Low findings, all informational or
out-of-scope for this batch). See
_docs/03_implementation/reviews/batch_23_review.md.

Cumulative review counter 2/3; next K=3 review fires after batch 24.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-11 04:57:49 +03:00
Oleksandr Bezdieniezhnykh 534ab41b8e [AZ-372] Apply dotnet format whitespace cleanup; archive batch 22
ci/woodpecker/push/01-test Pipeline was successful
ci/woodpecker/push/02-build-push Pipeline was successful
Pure whitespace-only cleanup uncovered by the new format gate from the
previous commit. Verified via `git diff -w --stat`: only 4 files differ
when whitespace is ignored, and those differ only by the BOM byte.

Cleanup kinds applied across 22 source files:
- BOM removal (MapConfig.cs, SatTile.cs, GeoUtils.cs,
  IntegrationTests/Program.cs)
- CRLF -> LF (IntegrationTests/Program.cs)
- Trailing whitespace on blank lines (Common, Api, DataAccess,
  IntegrationTests, Services.RegionProcessing,
  Services.TileDownloader)
- Final newline added (RoutePoint.cs, GeoPoint.cs, others)

After this commit `dotnet format whitespace SatelliteProvider.sln
--verify-no-changes` exits 0; AC-1 is enforceable from `scripts/
run-tests.sh` going forward.

Also lands the batch 22 report, code-review report
(PASS_WITH_WARNINGS, 2 Low findings — both deferred per spec),
dependency-table status update (AZ-372 -> Done (In Testing)), task
archive (todo/ -> done/), and autodev state update.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-11 04:43:08 +03:00
Oleksandr Bezdieniezhnykh 8fee955bb5 [AZ-350] autodev state: ready for batch 22 (AZ-372)
ci/woodpecker/push/01-test Pipeline was successful
ci/woodpecker/push/02-build-push Pipeline was successful
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-11 04:25:19 +03:00
Oleksandr Bezdieniezhnykh a7c622204f [AZ-350] Cumulative K=3 review for batches 19-21: PASS_WITH_WARNINGS
F1 (Low/Maintainability): module-layout.md docs stale on DataAccess
project reference after AZ-370; tracked for refactor Phase 7.
F2 (Low/Maintainability): redundant builder.Services.AddHttpClient()
in Program.cs after AZ-374; deferred per batch 21 design note.
No Critical/High findings; auto-chain to next batch (AZ-372).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-11 04:23:28 +03:00
Oleksandr Bezdieniezhnykh fae0d1cc34 [AZ-374] Update autodev state: cumulative-review pending
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-11 04:18:08 +03:00
Oleksandr Bezdieniezhnykh 7736cfd761 [AZ-374] Add batch 21 report; autodev state batch 21 complete
ci/woodpecker/push/01-test Pipeline was successful
ci/woodpecker/push/02-build-push Pipeline was successful
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-11 04:11:57 +03:00
Oleksandr Bezdieniezhnykh 1ca8c80d7b [AZ-373] Add batch 20 report; autodev state batch 20 complete
ci/woodpecker/push/01-test Pipeline was successful
ci/woodpecker/push/02-build-push Pipeline was successful
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-11 04:05:45 +03:00
Oleksandr Bezdieniezhnykh 23ab05766d [AZ-370] Refactor C17: status / point-type enums + AC RT2 update
Replaces bare strings with two enums in Common/Enums/:
  RegionStatus { Queued, Processing, Completed, Failed }
  RoutePointType { Start, End, Action, Intermediate }

Adds a Dapper EnumStringTypeHandler<T> (DataAccess/TypeHandlers/)
that round-trips enums to/from lowercase strings, registered once
at startup via DapperEnumTypeHandlers.RegisterAll(). DataAccess now
references Common (project ref) so entities can carry the enum types.

Sites converted: RegionService (5), RouteProcessingService (3),
RoutePointGraphBuilder (4), entity Status/PointType columns. Log
message and summary file format preserved via .ToLowerInvariant().

API JSON contract preserved by adding JsonStringEnumConverter with
JsonNamingPolicy.CamelCase to the http JSON options — single-word
enum members serialize to the same lowercase strings as before.

DTO renamed: Common.DTO.RegionStatus -> RegionStatusResponse to
free the RegionStatus name for the new enum (forced by the task's
explicit enum name); the renamed DTO has no public-API impact at
the JSON wire level. Stale doc references updated.

AC RT2 in _docs/00_problem/acceptance_criteria.md now lists all 4
point types (start/end/action/intermediate).

Tests: 171 / 171 unit + 5 / 5 smoke green (was 141 + 5; +30 new tests
covering type handler round-trip, set/parse, unknown-value rejection,
idempotent registration, and the AC RT2 doc check).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-11 03:55:22 +03:00
Oleksandr Bezdieniezhnykh 6d98c8f8d1 [AZ-350] Cumulative K=3 review for batches 16-18: PASS (0 findings)
ci/woodpecker/push/01-test Pipeline was successful
ci/woodpecker/push/02-build-push Pipeline was successful
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-11 03:34:01 +03:00