mirror of
https://github.com/azaion/satellite-provider.git
synced 2026-06-22 12:31:15 +00:00
ea278afb37
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>
99 lines
10 KiB
Markdown
99 lines
10 KiB
Markdown
# Structural Snapshot — 2026-05-12 (post-cycle 5, AZ-503-foundation + AZ-504)
|
|
|
|
Cycle 5 delta against `structure_2026-05-12_cycle4.md`. Source of truth: `_docs/02_document/module-layout.md` + on-disk `*.csproj` graph + `_docs/02_document/contracts/`.
|
|
|
|
## Projects
|
|
|
|
| Layer | csproj | Cycle 5 delta |
|
|
|-------|--------|---------------|
|
|
| 1 (Foundation) | `SatelliteProvider.Common` | **+1 file**: `Utils/Uuidv5.cs` (NEW, 80 LoC; RFC 9562 §5.5 SHA-1 UUIDv5 + pinned `TileNamespace` GUID). No new NuGet deps; uses framework-only `System.Security.Cryptography.SHA1` + `System.Buffers.Binary.BinaryPrimitives`. |
|
|
| 1 (Foundation) | `SatelliteProvider.DataAccess` | **+1 migration**: `Migrations/014_AddTileIdentityColumns.sql` (NEW, embedded resource); **+4 properties** on `Models/TileEntity.cs` (`FlightId`, `LocationHash`, `ContentSha256`, `LegacyId`); UPSERT in `Repositories/TileRepository.cs` rewritten for the integer-key + flight-aware contract. No new NuGet deps; `pgcrypto` extension enabled by the migration script (PG-server-side, not a NuGet). |
|
|
| 1 (Foundation, shared DTO) | `SatelliteProvider.Common` (DTO sub-folder) | **+1 property**: `DTO/UavTileMetadata.FlightId` (`Guid?`, init-only, optional). Contract `uav-tile-upload.md` bumped 1.0.0 → 1.1.0 (additive). |
|
|
| 3 (Application) | `SatelliteProvider.Services.TileDownloader` | **+ImportSite**: `using SatelliteProvider.Common.Utils` (for `Uuidv5.Create`) + `using System.Security.Cryptography` (for `SHA256.HashData`) in `TileService.cs` and `UavTileUploadHandler.cs`. `UavTileUploadHandler.BuildUavTileFilePath` gains an optional `Guid? flightId` parameter. No new csproj refs. |
|
|
| 3 (Application) | `SatelliteProvider.Services.RegionProcessing` | unchanged |
|
|
| 3 (Application) | `SatelliteProvider.Services.RouteManagement` | unchanged |
|
|
| 4 (API / Entry) | `SatelliteProvider.Api` | unchanged (`Program.cs` not edited this cycle) |
|
|
| 5 (Test-Support) | `SatelliteProvider.TestSupport` | unchanged |
|
|
| 6 (Tests) | `SatelliteProvider.Tests` | **+1 test class** (`Uuidv5Tests.cs`); **+3 facts** in `UavTileFilePathTests.cs`; **+2 facts** in `UavTileUploadHandlerTests.cs`. |
|
|
| 6 (Tests) | `SatelliteProvider.IntegrationTests` | **+1 ProjectReference** (`SatelliteProvider.Common`) — so raw-SQL seeds can call `Uuidv5.Create` directly; **+2 facts** in `UavUploadTests.cs` (AC-3 multi-flight, AC-4 float-rounding); **+3 facts** in `MigrationTests.cs` (Az503 columns / index / backfill determinism); 1 fact superseded (`NewUniqueConstraintIncludesSourceColumn_AZ484_AC1` → `Az503MigrationSupersedesAz484UniqueIndex`); seed for the pre-existing `MultiSourceCoexistence_AZ484_Cycle2` test repaired to populate `location_hash`. |
|
|
|
|
**Project count**: 9 (unchanged from cycle 4 — AZ-503-foundation adds files to existing projects, doesn't add a new csproj).
|
|
|
|
## Cross-Project Import Edges (compile-time `ProjectReference`)
|
|
|
|
| Edge | Count | Cycle 5 delta |
|
|
|------|-------|----------------|
|
|
| Api → {Common, DataAccess, TileDownloader, RegionProcessing, RouteManagement} | 5 | unchanged |
|
|
| TileDownloader → {Common, DataAccess} | 2 | unchanged |
|
|
| DataAccess → {Common} | 1 | unchanged |
|
|
| RegionProcessing → {Common, DataAccess} | 2 | unchanged |
|
|
| RouteManagement → {Common, DataAccess} | 2 | unchanged |
|
|
| Tests → {Api, TileDownloader, RegionProcessing, RouteManagement, Common, DataAccess, TestSupport} | 7 | unchanged |
|
|
| IntegrationTests → {TestSupport, **Common (NEW)**} | **2** | **+1** edge (motivated by AZ-503 — seeds need the production `Uuidv5.Create` algorithm to compute `location_hash` for raw-SQL inserts) |
|
|
|
|
**Total ProjectReference edges**: **21** (cycle 4: 20). Net delta: +1 edge.
|
|
|
|
## Source-import sites — cycle 5 delta
|
|
|
|
| Importer | Imports from | Cycle 5 delta |
|
|
|----------|--------------|---------------|
|
|
| `SatelliteProvider.Services.TileDownloader/TileService.cs` | `SatelliteProvider.Common.Utils` (Uuidv5), `System.Security.Cryptography` (SHA256) | NEW (AZ-503 deterministic identity + content hash) |
|
|
| `SatelliteProvider.Services.TileDownloader/UavTileUploadHandler.cs` | `SatelliteProvider.Common.Utils` (Uuidv5), `System.Security.Cryptography` (SHA256) | NEW (same — UAV write path) |
|
|
| `SatelliteProvider.IntegrationTests/UavUploadTests.cs` | `SatelliteProvider.Common.Utils` (Uuidv5) | NEW (seed helper for raw-SQL inserts) |
|
|
| `SatelliteProvider.Tests/Uuidv5Tests.cs` | `SatelliteProvider.Common.Utils` | NEW (unit-test class) |
|
|
| All other source files | unchanged | — |
|
|
|
|
**5 new source-level import lines** across 4 files; all to either the new internal `SatelliteProvider.Common.Utils.Uuidv5` utility or the framework `System.Security.Cryptography.SHA256`. **Zero new third-party imports.**
|
|
|
|
## Graph properties
|
|
|
|
- **Cycles in project import graph**: 0 (clean DAG — unchanged)
|
|
- **Average ProjectReferences per component**: 21 / 9 = **~2.3** (cycle 4: ~2.2). Net delta: +0.1 (one new IntegrationTests → Common edge).
|
|
- **Max in-degree**: Common (still highest — now at **7** incoming edges: Api, TileDownloader, DataAccess, RegionProcessing, RouteManagement, Tests, **IntegrationTests (new)**). Cycle 4 had Common at 6.
|
|
- **Max out-degree**: Tests (7 — unchanged).
|
|
- **TestSupport position**: leaf-of-test-subgraph; no production-layer importers (unchanged).
|
|
- **The new IntegrationTests → Common edge is justified**: integration-test seeds need the same deterministic `Uuidv5` algorithm the production code uses, otherwise the new NOT NULL `location_hash` column would force every seed to encode the SHA-1 byte order by hand. Reusing `SatelliteProvider.Common.Utils.Uuidv5` keeps the algorithm in one place (which is also where the cross-repo invariant with `gps-denied-onboard/components/c6_tile_cache/_uuid.py` lives).
|
|
|
|
## NuGet dependency hygiene (cycle 5)
|
|
|
|
| Package | Cycle-4 version | Cycle-5 version | Status |
|
|
|---------|-----------------|-----------------|--------|
|
|
| All NuGet packages across all 9 csproj files | unchanged | **unchanged** | **Zero NuGet bumps this cycle.** AZ-503-foundation uses framework-only types (`SHA1`, `SHA256`, `BinaryPrimitives`); AZ-504 is a 2-line shell-script edit. |
|
|
| Carry-overs (still OPEN) | Cycle-3 D2 (`Microsoft.NET.Test.Sdk 17.8.0` transitive `NuGet.Frameworks` flag), cycle-4 D4 (`Microsoft.IdentityModel.Tokens` 7.0.3 + `System.IdentityModel.Tokens.Jwt` 7.0.3 in TestSupport), `Serilog.AspNetCore` 8.0.3 fallback | unchanged | All three remain explicitly out of cycle-5 scope per `coderule.mdc` "scope discipline". |
|
|
|
|
## Database schema surface (cycle 5 delta)
|
|
|
|
| Object | Change | Source |
|
|
|--------|--------|--------|
|
|
| `tiles` table | **+4 columns**: `flight_id uuid NULL`, `location_hash uuid NOT NULL` (backfilled deterministically for pre-existing rows), `content_sha256 bytea NULL`, `legacy_id uuid NULL` | `014_AddTileIdentityColumns.sql` |
|
|
| `idx_tiles_unique_location_source` (AZ-484, float-based) | **DROPPED** | same |
|
|
| `idx_tiles_unique_location` (pre-AZ-484, defensive duplicate cleanup) | **DROPPED** | same |
|
|
| `idx_tiles_unique_identity` (integer-key + COALESCE(flight_id, zero-UUID)) | **CREATED** (unique) | same |
|
|
| `idx_tiles_location_hash` (location_hash lookups for the future AZ-505 inventory endpoint) | **CREATED** (non-unique) | same |
|
|
| Postgres extension `pgcrypto` | **CREATE EXTENSION IF NOT EXISTS** (used during the migration's session-scoped `pg_temp.uuidv5` PL/pgSQL function only) | same |
|
|
|
|
The migration runs in a single transaction and is idempotent under DbUp's journal. No table or column was renamed (per `coderule.mdc` "Do not rename any database objects without confirmation").
|
|
|
|
## Architecture / contract surface (cycle 5 delta)
|
|
|
|
- **Contract bumped**: `_docs/02_document/contracts/api/uav-tile-upload.md` v1.0.0 → **v1.1.0** (additive — adds optional `metadata.flightId: uuid?`; adds derived `tileId` field in the response). Backward-compatible with cycle-4 clients.
|
|
- **No new public-API contract files.** (AZ-505 will introduce `inventory.md` next cycle.)
|
|
- **New per-flight on-disk path layout** for UAV tiles: `./tiles/uav/{flightId or 'none'}/{z}/{x}/{y}.jpg`. Additive — legacy paths under `./tiles/uav/{z}/{x}/{y}.jpg` are not moved. Documented in `uav-tile-upload.md` "File-path layout" section.
|
|
- **New cross-repo invariant**: the `TileNamespace` GUID `5b8d0c2e-7f1a-4d3b-9c5e-1f3a8e7d2b6c` in `SatelliteProvider.Common/Utils/Uuidv5.cs` must match the same constant in `gps-denied-onboard/components/c6_tile_cache/_uuid.py` (sibling workspace). Cycle-5 commit covers the satellite-provider side; the gps-denied-onboard side will be handled when AZ-505 / the consumer-side work runs.
|
|
|
|
## Net Architecture delta vs cycle 4
|
|
|
|
- **Resolved (closed by this cycle)**: 0 architecture-level findings closed (the cycle-3 perf-harness leftover is half-closed — AZ-504 script fix is verified working, but the exit-0 deletion criterion is blocked by recurring local DNS noise; replay #5 documented).
|
|
- **Newly introduced (informational only)**:
|
|
- 2 Low informational findings in the security audit (F1-cy5 `metadata.flightId` not authenticated provenance; F2-cy5 `pgcrypto` deployment runbook gap on managed Postgres). Both are long-term recommendations, not code defects.
|
|
- 1 Low Maintainability finding in the AZ-503 code review (the `contentSha256` soft-NULL guard in `TileService.BuildTileEntity` when `File.Exists` is false — practically unreachable, defensively kept).
|
|
- 0 new Medium, 0 new High, 0 new Critical.
|
|
- **+1 cross-project edge** (IntegrationTests → Common) — justified (cross-repo invariant deduplication).
|
|
- **Contract delta**: 1 minor version bump on `uav-tile-upload.md` (1.0.0 → 1.1.0, additive).
|
|
- **Schema delta**: +1 migration (014), +4 columns, +2 indexes, -2 indexes, +1 Postgres extension.
|
|
- **Net Architecture delta**: 0 net architecture-level findings (the 3 new Lows are informational only, and the +1 edge + minor contract bump are net-neutral structural additions, not violations).
|
|
|
|
## What this snapshot says about cycle 5's shape
|
|
|
|
Cycle 5 is the project's first **schema-changing cycle since cycle 1's AZ-484** — a database migration with backfill, a new internal cross-component algorithm (`Uuidv5`), a contract minor bump, and a new on-disk layout for one tile source. Quantitatively it's small (4 SP delivered = 3 SP foundation + 1 SP script fix), but it lays foundational identity infrastructure that next cycle's AZ-505 (5 SP — inventory endpoint, HTTP/2, Leaflet covering index) is blocked on. The structural delta is bounded (`+1` import edge, `+1` minor contract version, +1 migration, +4 columns, +2 indexes, -2 indexes, 0 new csproj, 0 new NuGet bumps), and the DAG remains acyclic with the same 9 projects.
|