mirror of
https://github.com/azaion/satellite-provider.git
synced 2026-06-21 08:21:14 +00:00
ea278afb370a43ef49e8beb9064e0c0c8dc726f4
155 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
ea278afb37 |
[AZ-503] [AZ-504] Cycle 5 Step 17: retrospective + close cycle
retro_2026-05-12_cycle5.md captures the cycle-end retrospective: - Implementation: 2 tasks (AZ-504 + AZ-503-foundation), 4 SP total, 100% first-attempt pass rate, 1 mid-implement scope-split (AZ-503 → AZ-503-foundation + AZ-505, blocked-linked). - Quality: 50/50 PASS/PASS_WITH_WARNINGS, 0 new Medium+, 1 new Low (defensive contentSha256 soft-NULL guard). - Security: PASS_WITH_WARNINGS, 0 new Critical/High/Medium, 2 new Low informational (F1 flightId provenance, F2 pgcrypto runbook gap). - Performance: PASS_WITH_INFRA_WARNINGS — first measurable PT-08 ever (Run #1 199ms, Run #2 117ms vs 2000ms threshold); PT-01/02 failed on recurring local Docker/colima DNS cold-start, not an app regression. - Structural: +1 ProjectReference edge (IntegrationTests → Common), +1 minor contract bump (uav-tile-upload 1.0.0 → 1.1.0), +1 DB migration (014_AddTileIdentityColumns.sql), 0 NuGet bumps, 0 csproj additions, DAG still acyclic at 9 projects. structure_2026-05-12_cycle5.md captures the structural snapshot. LESSONS.md updated with 3 cycle-5 entries (oldest dropped to preserve the 15-entry ring buffer): - [architecture] Cross-repo cryptographic invariants must live as code constants in both repos with reference-vector tests. - [tooling] When perf-mode "one re-run" fires twice with the same DNS root cause, escalate from re-run to harness fix. - [process] Spec contradicts live code by >=2 prerequisites → prefer split into foundation + follow-up (A/B/C option C). Top 3 follow-up actions (cycle 6 candidates): - Action 1 (1 SP): DNS pre-warm in scripts/run-performance-tests.sh → closes the cycle-3 perf-harness leftover. - Action 2 (5 SP): AZ-505 — inventory endpoint + HTTP/2 + Leaflet covering index (blocked-linked on AZ-503-foundation, this cycle). - Action 3 (1 SP): pgcrypto pre-install runbook step (F2-cy5 doc fix). Cycle 5 closed. Autodev state advanced for cycle 6 by the next /autodev invocation. Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
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> |
||
|
|
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> |
||
|
|
c646aa93e2 |
[AZ-503] Tile identity → UUIDv5 + integer UPSERT (foundation)
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>
|
||
|
|
f6197499a4 |
chore: update autodev state after AZ-504 batch 1
Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
ab437a15df |
[AZ-504] Fix grep | wc -l pipefail crash in PT-08 batch counting
scripts/run-performance-tests.sh:416-417 used `grep -o ... | wc -l` to count `"status":"accepted"` and `"status":"rejected"` markers in the PT-08 batch response. On the happy path (rejected=0) grep -o exits 1, and under `set -o pipefail` + `set -e` (line 16) the pipeline killed the script before reaching any of PT-08's reporting code — reproducing twice in the cycle-3 perf-harness leftover (replay #2 + #3 post-AZ-500). Fix: neutralise grep's no-match exit locally with `|| true` on the grep stage of each pipeline. `grep -o | wc -l` is kept (not swapped for `grep -c`) because the PT-08 response is compact JSON — all items live on one line, so `grep -c` would always return 1 and lose occurrence-count semantics. An 8-line comment explains why grep cannot fail for I/O at this code path (file is curl-written, HTTP 200 gated). AC-1 + AC-2 verified in-place against a standalone harness under `set -e -o pipefail` (compact-JSON, mixed-status, edge-empty cases). AC-3 + AC-4 are Step 15 (Performance Test) obligations by spec design — the leftover deletion (AC-4) is "in the same commit" as the green full perf run. Batch report: _docs/03_implementation/batch_01_cycle5_report.md. Code review: _docs/03_implementation/reviews/batch_01_cycle5_review.md — PASS, no findings. Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
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> |
||
|
|
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> |
||
|
|
af4219fce6 |
[AZ-500] Cycle 4 Steps 12-15 sync (test-spec / docs / security / perf)
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>
|
||
|
|
de609cffa1 |
[AZ-500] Cycle 4 implement-skill wrap-up reports
Adds the cycle-4 product implementation completeness gate report (verdict: PASS) and the final implementation report for the .NET 10 migration. Records the Step 16 handoff to Step 11 (test-run skill) to avoid duplicating the full-suite run already executed during AC-6 verification (271/271 unit + full integration suite green). Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
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>
|
||
|
|
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> |
||
|
|
ca0ca9f2a4 |
[AZ-491] [AZ-492] [AZ-493] [AZ-494] [AZ-495] [AZ-496] Cycle 3 Step 17: retrospective + close cycle
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>
|
||
|
|
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>
|
||
|
|
314d1dec39 |
[AZ-491] [AZ-492] [AZ-493] [AZ-494] [AZ-496] Cycle 3 Step 14: security audit refresh
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>
|
||
|
|
e42bf62152 |
[AZ-491] [AZ-492] [AZ-493] [AZ-494] [AZ-495] [AZ-496] Cycle 3 Steps 11-13: test-spec sync + ripple log
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>
|
||
|
|
495605f51b |
[AZ-494] [AZ-492] Cycle 3 Step 16: full test suite green; close batches
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> |
||
|
|
f979e18811 |
[AZ-494] Enable JWT iss/aud validation with fail-fast startup
Option B per user decision: production ships with empty Jwt.Issuer / Jwt.Audience in appsettings.json so the API process refuses to start unless JWT_ISSUER + JWT_AUDIENCE env vars are supplied. Development ships with grep-friendly DEV-ONLY- placeholders so local + docker flows keep working unchanged. AuthenticationServiceCollectionExtensions flips ValidateIssuer + ValidateAudience to true and wires ValidIssuer / ValidAudience via a new ResolveRequiredOrThrow helper that all three required values (secret, iss, aud) now share. JwtTokenFactory.Create + CreateExpired gain optional iss / aud parameters (default null) so existing call sites compile unchanged. JwtTestHelpers adds MintAuthenticated / MintExpired wrappers that resolve iss + aud from env, plus ResolveIssuerOrThrow / ResolveAudienceOrThrow. PerfBootstrap.MintToken + Program.cs JWT bootstrap migrated to the new surface so the perf harness and the integration runner both validate against the same contract. Adds 4 fail-fast unit tests (missing/empty issuer + audience), 2 negative integration scenarios (WrongIssuer_Returns401, WrongAudience_Returns401), and re-tags every existing integration mint site via MintAuthenticated. Compose, .env.example, run-tests.sh, run-performance-tests.sh all load + export JWT_ISSUER + JWT_AUDIENCE alongside JWT_SECRET. Resolves F-AUTH-2 (security_report.md + owasp_review.md). AC-7 (cross-repo suite/_docs/10_auth.md write) deferred — outside this workspace; tracked in deploy_cycle2.md R3 follow-up. Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
080441db5d |
[AZ-492] Cycle 3 batch 4: perf harness PT-07 + PT-08 + JWT-attach
Drains all three deferred perf-harness items in one batch: - PT-01..PT-06 now carry Authorization: Bearer minted via the canonical SatelliteProvider.TestSupport.JwtTokenFactory (AZ-491) — no third copy of JWT logic in the shell. - PT-07 implemented as cold + warm dual-pass distribution (N=20 each), reports p50/p95 for both passes and fails if warm p95 >= cold p95. - PT-08 implemented as 20-batch upload distribution with batch p95 gated at the AZ-488 2000 ms target; per-item gate cost reported as derived proxy (batch_p95 / batch_size). New SatelliteProvider.IntegrationTests/PerfBootstrap.cs adds two CLI short-circuit subcommands (--mint-only and --gen-uav-fixture <path>) invoked by the shell so the perf script never inlines the JWT or JPEG-fixture logic. The dispatch sits at the top of Program.cs Main and runs before any HTTP / DB / readiness setup. performance-tests.md PT-07 + PT-08 flip from Deferred to Implemented. traceability-matrix.md PT-07 + PT-08 rows move from recorded to covered (PT-08 partial due to per-item proxy — flagged Low in batch-4 review). _docs/_process_leftovers/2026-05-11_perf-pt07-harness.md deleted; the leftovers directory is now empty. Closes cycle-2 retro Action 2; LESSONS.md [process] rule about Deferred NFRs remains in force as a guardrail. Also includes the previously-uncommitted cumulative review report for cycle-3 batches 01-03 (generated at the end of batch 3 but not staged). Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
745f4840e6 |
[AZ-493] Cycle 3 batch 3: integration test DB-reset hook
AZ-493 (2 SP): replace the cycle-2 wallclock-seeded _coordinateCounter workaround with a proper Postgres state-reset hook that runs at integration test runner startup, eliminating the per-source-unique-index collision risk that the persistent docker-compose Postgres volume introduced post-AZ-484. The reset is split into two surfaces: * SatelliteProvider.TestSupport.IntegrationTestResetGuard - pure static class, I/O-free, unit-tested. Two independent guards: (a) ASPNETCORE_ENVIRONMENT must equal "Testing", (b) DB_CONNECTION_STRING Host must be in the allowed-host list (postgres, localhost, 127.0.0.1). Failure of either guard surfaces a structured operator-friendly InvalidOperationException. * SatelliteProvider.IntegrationTests.IntegrationTestDatabaseReset - instance class owning the Npgsql side effects. Calls the guard then runs TRUNCATE TABLE route_regions, route_points, routes, regions, tiles RESTART IDENTITY CASCADE inside a single Npgsql transaction. Spec-vs-reality: the task spec prescribed "DB name contains _test" as Guard 2; the actual compose file uses Database=satelliteprovider and DB rename is gated on user confirmation per coderule.mdc. Substituted a Host allowlist as the equivalent guard (intent identical: reject remote / production hosts). Recorded as Low/Spec-Gap in the review. Program.cs adds --keep-state CLI flag and INTEGRATION_KEEP_STATE env var (1/true) opt-outs so a developer can inspect leftover state when debugging. Startup banner shows which path executed. docker-compose.tests.yml gets ASPNETCORE_ENVIRONMENT=Testing + passthrough for INTEGRATION_KEEP_STATE. scripts/run-tests.sh wires the --keep-state flag through to compose. UavUploadTests._coordinateCounter wallclock seed is retained as defense-in-depth (per the task spec's implementer choice). The reset is the primary isolation path; the seed is the belt-and-suspenders fallback for --keep-state runs. 8 new unit tests in SatelliteProvider.Tests/TestSupport/ IntegrationTestResetGuardTests.cs cover Production/Staging/missing-env throw, allowed-host case-insensitivity, disallowed-host rejection with representative prod hostnames, and the AllowedHosts contract. tests_integration.md gains a Reliability section that documents the hook, the two guards, the truncate order, and the three opt-out forms. module-layout.md TestSupport entry extended with the new pure guard and the explicit "Npgsql stays in IntegrationTests" boundary. Test-suite gate (AC-6) deferred to Step 16 Final Test Run per implement skill convention. Per-batch review verdict: PASS_WITH_WARNINGS with 1 Low (spec-vs-reality on Guard 2, non-blocking). Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
c396740644 |
[AZ-491] Cycle 3 batch 2: consolidate JWT test-mint helpers into TestSupport
AZ-491 (3 SP): eliminate the cycle-2 duplicate of JWT-minting logic that existed in both SatelliteProvider.Tests/TestUtilities/ JwtTokenFactory.cs (unit-side) and SatelliteProvider.IntegrationTests/ JwtTestHelpers.cs (integration-side), where the same Expires < NotBefore bug needed parallel fixes in commits |
||
|
|
9cfd80babe |
[AZ-495] [AZ-496] Cycle 3 batch 1: doc convention + AspNetCore 8.0.25
AZ-495 (1 SP): formalize the modules-only documentation convention for the WebApi component. _docs/02_document/module-layout.md now carries an explicit Documentation Layout section anchoring WebApi docs at modules/api_program.md; the components/06_web_api/ folder is intentionally absent. .cursor/skills/new-task/SKILL.md Step 4 directs future agents at the correct path. Cycle-1 + cycle-2 F1 findings in the two batch-review files are marked RESOLVED with back-reference to AZ-495. Cycle-2 retrospective decision-item list F1 updated. AZ-496 (2 SP): bump Microsoft.AspNetCore.OpenApi and JwtBearer in SatelliteProvider.Api.csproj from 8.0.21 to 8.0.25, closing CVE- 2026-26130 (SignalR DoS - not reachable in this app, but the runtime patch is the recommended hardening per cycle-1 D1 + cycle-2 D3). SatelliteProvider.Tests.csproj has no direct JwtBearer reference - it consumes JwtBearer transitively via ProjectReference to Api, so no edit needed there. Dockerfiles use floating mcr.microsoft.com/ dotnet/aspnet:8.0 / sdk:8.0 / runtime:8.0 tags which auto-resolve to >= 8.0.25 on rebuild. Security artifacts (dependency_scan.md, security_report.md) and current-state docs (module-layout.md, architecture.md, modules/api_program.md, modules/tests_unit.md) updated to reflect 8.0.25. Batch report + code review report (verdict PASS_WITH_WARNINGS with 2 Low findings, neither blocking) written under _docs/03_implementation. Test suite gate deferred to Step 16 (Final Test Run) per implement skill convention. Patch-level bump within .NET 8 LTS; regression risk very low. Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
76076cbd90 |
[AZ-491] [AZ-492] [AZ-493] [AZ-494] [AZ-495] [AZ-496] Cycle 3 Step 9: 6 task specs
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> |
||
|
|
b69cf5640e |
[AZ-487] [AZ-488] retro: cycle 2 report + structural snapshot
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> |
||
|
|
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> |
||
|
|
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> |
||
|
|
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> |
||
|
|
e3cd388577 |
[AZ-487] [AZ-488] docs: cycle 2 doc sync (task mode)
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> |
||
|
|
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> |
||
|
|
dc3dabe7bd |
[AZ-488] fix: seed UavUploadTests coordinate counter from wall-clock
Postgres data volume persists across docker-compose runs. The previous `int _coordinateCounter = 0` reset on every test-runner process start so the SECOND `--full` run collided with rows seeded by the first `--smoke` run (the AC-3 MultiSourceCoexistence test does a raw INSERT for the pre-seed step, not an UPSERT, and the unique constraint fires). Seed the counter from a wall-clock value (~Unix epoch seconds mod 1M) so each runner process picks a distinct coordinate band. Eliminates inter-run collisions without coupling the test to docker volume reset. Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
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>
|
||
|
|
11b7074485 |
[AZ-487] fix: integration-test JWT factory handles negative lifetime
Same fix as
|
||
|
|
f64d0d760a |
[AZ-487] fix: JWT factory + tests now pass on net8.0
- JwtTokenFactory.Create: negative `lifetime` produced Expires < NotBefore
which `JwtSecurityToken` rejects at construction time. Shift NotBefore
behind Expires whenever the requested lifetime is non-positive so the
expired-token fixture round-trips and lifetime validation can fire.
- JwtTokenFactoryTests: validate against a handler with
`MapInboundClaims = false` so assertions read the factory's own claim
names ("sub", "email", "permissions") rather than the .NET-default
remapped ClaimTypes.* aliases.
These were latent — masked by the CS0104 build break fixed in
|
||
|
|
753be43d11 |
[AZ-487] fix: resolve CS0104 ambiguity in AuthN tests
`AuthenticationServiceCollectionExtensions` is also a built-in .NET type under `Microsoft.Extensions.DependencyInjection`. With both namespaces imported the unqualified references in this test file failed with CS0104, breaking the entire test project build. Resolved via a `using` alias so the call sites stay short while the build stays unambiguous. Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
96cd3c4495 |
[AZ-487] JWT validation baseline (HS256, all endpoints)
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> |
||
|
|
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 (
|
||
|
|
42a3cc7467 |
[AZ-487] [AZ-488] Cycle 2 Step 9: JWT baseline + UAV upload task specs
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>
|
||
|
|
18609656f9 |
[AZ-484] Cycle 1 Step 17 Retrospective: report + structural snapshot
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> |
||
|
|
51b572108a |
[AZ-484] Cycle 1 Steps 12-16: docs, security, perf, deploy report
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> |
||
|
|
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> |
||
|
|
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> |
||
|
|
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> |
||
|
|
08451df027 |
[AZ-350] Close 03-code-quality-refactoring: Phase 6+7 + FINAL_report
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> |
||
|
|
9a53bff92e |
[AZ-375] [AZ-377] HashSet tile lookup + consolidate Earth constants
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> |
||
|
|
6099d1c86b |
[AZ-376] [AZ-378] [AZ-379] [AZ-380] Repo cleanup: dead code, logger discipline, ColumnList consts
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>
|
||
|
|
534ab41b8e |
[AZ-372] Apply dotnet format whitespace cleanup; archive batch 22
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> |
||
|
|
68359350fc |
[AZ-372] Add .editorconfig, Directory.Build.props, format/coverage wiring
Wires the C19 tooling baseline so dotnet format and Coverlet gate the test script and a small NetAnalyzers ruleset (CA1001, CA1051, CA1816, CA2227) at warning severity is visible from the next build. - .editorconfig (new, root=true): whitespace rules, per-extension indent sizes, C# style preferences as suggestions, initial CA rules. - Directory.Build.props (new): EnableNETAnalyzers=true, AnalysisLevel=latest, AnalysisMode=None so only rules explicitly enabled in .editorconfig fire; EnforceCodeStyleInBuild=false to keep build clean from style. - scripts/run-tests.sh: Step 0 runs dotnet format whitespace --verify-no-changes via Docker SDK; unit/integration test calls now collect XPlat Code Coverage into TestResults/. New --skip-format escape hatch. - .gitignore: TestResults/, coverage.cobertura.xml, *.coverage. - SatelliteProvider.Tests/ToolingConfigurationTests.cs (new, 6 tests): runtime assertions that the config files, script wiring, and coverlet.collector reference are all in place; mirrors the AcceptanceCriteriaRT2Tests pattern. Whitespace cleanup that the new format gate uncovers is staged for the next commit (per AZ-372 spec: "commit cleanup as a separate batch"). Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
8fee955bb5 |
[AZ-350] autodev state: ready for batch 22 (AZ-372)
Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
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> |
||
|
|
fae0d1cc34 |
[AZ-374] Update autodev state: cumulative-review pending
Co-authored-by: Cursor <cursoragent@cursor.com> |