# Structural Snapshot — 2026-05-12 (post-cycle 4, AZ-500)

Cycle 4 delta against `structure_2026-05-12_cycle3.md`. Source of truth: `_docs/02_document/module-layout.md` + on-disk `*.csproj` graph + `_docs/02_document/contracts/`.

## Projects

| Layer | csproj | Cycle 4 delta |
|-------|--------|---------------|
| 1 (Foundation) | `SatelliteProvider.Common` | TFM `net8.0` → `net10.0` |
| 1 (Foundation) | `SatelliteProvider.DataAccess` | TFM `net8.0` → `net10.0`; M.E.* 9.0.10 → 10.0.7 (Configuration.Abstractions, Logging.Abstractions) |
| 3 (Application) | `SatelliteProvider.Services.TileDownloader` | TFM `net8.0` → `net10.0`; M.E.* 9.0.10 → 10.0.7 (Caching.Memory, Http, Logging.Abstractions, Options.ConfigurationExtensions) |
| 3 (Application) | `SatelliteProvider.Services.RegionProcessing` | TFM `net8.0` → `net10.0`; M.E.* 9.0.10 → 10.0.7 (DependencyInjection.Abstractions, Hosting.Abstractions, Logging.Abstractions, Options.ConfigurationExtensions) |
| 3 (Application) | `SatelliteProvider.Services.RouteManagement` | TFM `net8.0` → `net10.0`; M.E.* 9.0.10 → 10.0.7 (DependencyInjection.Abstractions, Hosting.Abstractions, Logging.Abstractions, Options.ConfigurationExtensions) |
| 4 (API / Entry) | `SatelliteProvider.Api` | TFM `net8.0` → `net10.0`; `Microsoft.AspNetCore.Authentication.JwtBearer` 8.0.25 → **10.0.7**; `Microsoft.AspNetCore.OpenApi` 8.0.25 → **10.0.7**; `Swashbuckle.AspNetCore` 6.6.2 → **10.1.7** (drove transitive `Microsoft.OpenApi` 1.x → 2.3.x); `Serilog.AspNetCore` retained at 8.0.3 (Risk #4 fallback); `Program.cs` Microsoft.OpenApi 2.x setup refactor (3 internal edits — namespace, `OpenApiSecuritySchemeReference`, `JsonSchemaType` + `IOpenApiSchema`); `Swagger/ParameterDescriptionFilter.cs` namespace update |
| 5 (Test-Support) | `SatelliteProvider.TestSupport` | TFM `net8.0` → `net10.0`; NuGet refs unchanged (still pinned to `Microsoft.IdentityModel.Tokens 7.0.3` + `System.IdentityModel.Tokens.Jwt 7.0.3` — cycle-3 D4 carry-over) |
| 6 (Tests) | `SatelliteProvider.Tests` | TFM `net8.0` → `net10.0`; M.E.* 9.0.10 → 10.0.7 (Caching.Memory, Configuration.Json, DependencyInjection, Http, Logging.Abstractions, Logging.Console, Options); `Microsoft.AspNetCore.Authentication.JwtBearer` 8.0.25 → 10.0.7 (transitively via ProjectReference to Api) |
| 6 (Tests) | `SatelliteProvider.IntegrationTests` | TFM `net8.0` → `net10.0`; transitive bumps via TestSupport + Api |

**Project count**: 9 (unchanged from cycle 3 — AZ-500 is a runtime/SDK migration, not a project-graph change).

## Cross-Project Import Edges (compile-time `ProjectReference`)

| Edge | Count | Cycle 4 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} (+ runtime DTOs only) | 1 | unchanged |

**Total ProjectReference edges**: 20 (unchanged from cycle 3). AZ-500 added zero cross-project import edges.

## Source-import sites — cycle 4 delta

| Importer | Imports from | Cycle 4 delta |
|----------|--------------|---------------|
| `SatelliteProvider.Api/Program.cs` | `Microsoft.OpenApi` (was `Microsoft.OpenApi.Models`) | namespace move (1.x → 2.x); same conceptual surface, different package layout |
| `SatelliteProvider.Api/Swagger/ParameterDescriptionFilter.cs` | `Microsoft.OpenApi` (was `Microsoft.OpenApi.Models`) | same namespace move |
| All other source files | unchanged | — |

**No new source-level imports introduced.** The two changed `using` directives are namespace renames forced by the Microsoft.OpenApi 2.x layout, not new dependencies.

## Graph properties

- **Cycles in project import graph**: 0 (clean DAG — unchanged)
- **Average ProjectReferences per component**: 20 / 9 = ~2.2 (unchanged from cycle 3)
- **Max in-degree**: Common (still highest at 6 — Api, TileDownloader, DataAccess, RegionProcessing, RouteManagement, Tests).
- **Max out-degree**: Tests (7 — unchanged from cycle 3).
- **TestSupport position**: leaf-of-test-subgraph; no production-layer importers (unchanged).

## NuGet dependency hygiene (cycle 4)

| Package | Cycle-3 version | Cycle-4 version | Status |
|---------|-----------------|-----------------|--------|
| `Microsoft.AspNetCore.Authentication.JwtBearer` | 8.0.25 | **10.0.7** | RESOLVED cycle-3 D1 forward (now on the 10.x line; same underlying CVE patch, current line) |
| `Microsoft.AspNetCore.OpenApi` | 8.0.25 | **10.0.7** | RESOLVED cycle-3 D3 forward (same as above) |
| `Swashbuckle.AspNetCore` | 6.6.2 | **10.1.7** | NEW major line — 0 known vulnerabilities; bumped to land Microsoft.OpenApi 2.x compat required by ASP.NET Core 10 |
| `Microsoft.OpenApi` (transitive via Swashbuckle) | 1.x | **2.3.x** | NEW major line — 0 known vulnerabilities; drove the 3 internal `Program.cs` setup edits |
| `Serilog.AspNetCore` | 8.0.3 | **8.0.3 (unchanged)** | Risk #4 fallback — no 10.x line published as of cycle 4; restores cleanly on `net10.0` via netstandard 2.0; recheck per cycle |
| `Microsoft.Extensions.*` (11 distinct package IDs) | 9.0.10 | **10.0.7** | Coordinated bump across 6 csproj files; 0 known vulnerabilities on 10.0.7 line; historical CVE-2024-43483 already not applicable in cycle 3 (9.0.10 baseline post-rc.1 cutoff) |
| `Microsoft.IdentityModel.Tokens` (TestSupport) | 7.0.3 | **7.0.3 (unchanged)** | Cycle-3 D4 carry-over — explicitly out of AZ-500 scope per "no unrelated package bumps" Constraint; recommend separate PBI |
| `System.IdentityModel.Tokens.Jwt` (TestSupport) | 7.0.3 | **7.0.3 (unchanged)** | Same disposition as above |
| `Microsoft.NET.Test.Sdk` | 17.8.0 | **17.8.0 (unchanged)** | Cycle-3 D2 carry-over (transitive `NuGet.Frameworks` flag); explicitly out of AZ-500 scope |
| `SixLabors.ImageSharp` | 3.1.11 | **3.1.11 (unchanged)** | clean |
| `Npgsql` | 9.0.2 | **9.0.2 (unchanged)** | clean |
| `Newtonsoft.Json` | 13.0.4 | **13.0.4 (unchanged)** | clean |
| `Dapper` | 2.1.35 | **2.1.35 (unchanged)** | clean |
| `dbup-postgresql` | 6.0.3 | **6.0.3 (unchanged)** | clean |

## Architecture / contract surface (cycle 4 delta)

- **No new public-API contracts** under `_docs/02_document/contracts/` this cycle. AZ-500 preserves every endpoint shape, every DTO, the JWT validation contract (signature + lifetime + iss + aud + 30s clock skew), the multi-source `tile-storage` contract v1.0.0, the `uav-tile-upload` contract v1.0.0, and the AZ-488 permissions claim policy.
- `_docs/02_document/architecture.md` updated to reference .NET 10 / ASP.NET Core 10 / JwtBearer 10.0.7 (Authentication & Authorization paragraph + §2 Tech Stack table); the Architecture Vision prose is unchanged.
- The 8 `WithOpenApi(...)` callsites in `Program.cs` now emit `ASPDEPR002` deprecation warnings — recorded as a follow-up PBI (3 SP). API surface is unchanged.

## Net Architecture delta vs cycle 3

- **Resolved**: cycle-3 D1 (CVE-2026-26130 SignalR DoS, JwtBearer 8.0.21 line) **forward-resolved by major-version bump**; cycle-3 D3 (Microsoft.AspNetCore.OpenApi 8.0.21 line) similarly forward-resolved. The cycle-3 perf-harness leftover stays OPEN per AZ-500 Constraint, NOT closed by this cycle. **Total resolved: 2 (both Low/forward).**
- **Newly introduced (informational only)**: 5 new Low informational findings in `dependency_scan_cycle4.md` (F1-cy4..F5-cy4 — all "no known vulnerabilities" confirmations on the 10.x lines); 0 new Medium; 0 new High; 0 new Critical. 2 new Maintainability Mediums in code review (F1 ASPDEPR002 deprecation, F2 CS8604 nullable) — both deferred per "scope discipline" + the AZ-500 contract of "preserve behaviour during migration".
- **Net Architecture delta**: 0 net architecture-level findings. The cycle is structurally neutral — same component count, same edges, same DAG, same contract surface. The only structural-equivalence change is the 11-package M.E.* + 3-package ASP.NET + 1 Swashbuckle major-line bump, all forward-clean against advisories.

Cycle 4 is the first runtime/SDK-migration cycle. Net-zero is the expected outcome for that PBI shape — there is no business-logic delta to add structure. The graph properties confirming this is a "preserve-behaviour" migration: same imports, same edges, same cycles (zero), same in-degree distribution, same DAG.
