Cycle 8 retrospective (cycle-end mode): 5 tickets shipped, 17 SP, 4
batches across 1 cycle theme (strict input validation for the 4
AZ-795 child endpoints + AZ-812 region API field rename).
Artifacts:
- _docs/06_metrics/retro_2026-05-23_cycle8.md
- _docs/06_metrics/structure_2026-05-23_cycle8.md (gap-filled; last
structural snapshot was cycle 5)
Key cycle-8 findings (now in _docs/LESSONS.md ring buffer):
- Step-14 security-audit Medium findings under the small-fix
threshold should be resolved in-cycle, not deferred (F-AZ809-1
closed in commit 8fca6e0, ~30 min from discovery to fix).
- Retro recommendations ship end-to-end when they name concrete
tickets/files + size as a coherent cycle theme (cycle 7 Action 3
-> cycle 8 strict-validation slate, first end-to-end traceable
cross-cycle improvement action in project history).
- Contract wire-format updates (new required field / rename) need a
ripgrep probe across all consumer paths (perf script, probe
scripts, README, deploy docs, OpenAPI examples) — partial syncs
surface at Step 15 perf gate (PT-06 missed AZ-809 requestMaps +
createTilesZip, fixed in commit 32bc5c1).
Carry-overs to cycle 9: track PT-07 cache-pollution false positive
(harness, not regression), reduce 3 cycles in a row of misleading
"PT-07 fails on warm/cold ratio" entries in the perf report.
Marks Step 17 completed; cycle 8 closed. Next /autodev invocation
starts cycle 9 from Step 0.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-23 17:17:03 +03:00
4 changed files with 396 additions and 15 deletions
**Tasks**: AZ-812 (Region API field rename `Latitude/Longitude → Lat/Lon`, OSM convention, 3 SP), AZ-808 (Region POST strict validation, 3 SP), AZ-811 (lat/lon GET strict validation, 3 SP), AZ-809 (Route POST strict validation + nested DTO chain, 5 SP), AZ-810 (UAV upload metadata strict validation, multipart envelope, 3 SP). **5 tasks, 17 SP, 4 batches.**
**Mode**: cycle-end (autodev Step 17). Step 16 (Deploy) and Step 16.5 (Release) skipped per user choice (A at both gates) — matches the cycle-1-to-7 historical pattern (`_docs/04_deploy/` empty across all 8 cycles; `_docs/04_release/` likewise). The pushed commits on `origin/dev` (tip `32bc5c1`) are the cycle's release record.
**Previous retro**: `retro_2026-05-22_cycle7.md`
**Cycle shape**: explicit follow-through on cycle 7's Action 3 (AZ-795 child-task sweep across the remaining public endpoints) — 4 of the 4 endpoints cycle 7 named (`POST request`, `POST route`, `POST upload`, `GET tiles/latlon`) shipped a strict-validation surface in cycle 8. First time the project has shipped a **directly-traceable cross-cycle improvement action** end-to-end (cycle-7 retro recommendation → cycle-8 task slate → cycle-8 closure).
**Sequencing rationale**: 4 batches sized 1-2 tasks each (vs cycle 7's single 3-task batch). The split reflects the spec structure: AZ-812 (rename) was a prerequisite for the validator wave because it changed the wire format the validators would enforce; AZ-808 + AZ-811 paired because they shared the same wiring pattern (`.WithValidation<T>()` JSON-body + a query-param filter); AZ-809 stood alone because its 3-DTO-deep nested validator chain (route + per-point + per-polygon-corner) was meaningfully more complex than batches 2/4; AZ-810 stood alone because its multipart-envelope filter was a different shape from the JSON-body endpoints. The 4-batch slicing kept each batch under the "5 SP per batch" implicit complexity ceiling and made the per-batch reviews tractable.
Cycle 8 completed in **8 dev commits** on `dev` (and 1 commit on a pre-cycle prep): the four implementation commits (one per batch — batches 1-3 were committed in their own autodev runs, batch 4 in the closing run), then `bbe8783` (Cycle 8 close + AZ-810 fix-test-coords adjacent), `b763da3` (AZ-810 clamp UAV test fixture coords), then the post-implementation sync chain: `ec0eb90` (test-spec sync, Step 12), `6207ab7` (docs sync, Step 13), `ac40a8b` (security audit, Step 14), `8fca6e0` (F-AZ809-1 fix, Step 14 follow-up), `32bc5c1` (perf run, Step 15). All five trailing commits pushed together at the end of Step 15 per the user's Step 16-gate choice. **+1 commit vs cycle 7** (8 vs 7) — accounted for by the F-AZ809-1 in-cycle resolution commit (cycle 7 had no in-cycle security-finding resolution).
First cycle with a per-batch review file written for every batch (cycle 7 had no per-batch review files; cycle 6 had one per batch but only one batch). The cumulative cross-batch review surfaced no new finding categories beyond the per-batch reviews — i.e., the per-batch reviews caught everything.
| Reason | F-AZ809-1 Medium (DoS via unbounded `geofences.polygons`) resolved in-cycle via `MaxPolygons = 50` cap + unit + integration test + `route-creation.md` v1.0.1 patch bump (commit `8fca6e0`). F-AZ810-1 + F-AZ810-2 (Lows) carried forward as cycle-9 candidates. | new resolved-in-cycle pattern |
| New Critical / High | **0** | unchanged |
| New Medium | **1 found, 1 resolved in-cycle** (F-AZ809-1) | first time a security-audit finding was resolved within the cycle it was discovered |
| New Low | **2** (F-AZ810-1 `JsonException.Message` echo in `UavUploadValidationFilter`; F-AZ810-2 `DateTime` vs `DateTimeOffset` for `CapturedAt`) | -1 (cycle 7 had 3 new Lows) |
| Carry-overs (still OPEN, unchanged from cycle 7) | **4** (F-AZ795-1 + F-AZ795-2 + D-AZ795-1 + D2-cy4) | +1 (D2-cy4 explicitly re-flagged as carry-over in this cycle's dependency scan) |
**Audit shape**: cycle 8 ran the full 5-phase security skill (Dependency Scan, Static Analysis, OWASP Review, Infrastructure Review, Security Report) — second consecutive cycle to run all 5 phases (cycle 7 was the first). Audit was justified by 4 new validator files + 4 new endpoint contracts + 1 new endpoint filter + 1 new multipart envelope filter. **Cycle 8 is the first cycle where a security-audit Medium finding (F-AZ809-1) was resolved within the same cycle it was discovered** (commit `8fca6e0`, ~30 minutes from discovery to fix landed). The user-driven A/B/C gate at Step 14 explicitly enabled this; the autodev orchestrator now treats in-cycle finding resolution as a first-class option rather than always deferring to cycle N+1.
| AZ-808..AZ-812 contract regression check | **PASS** — every cycle-8 validator surface measured below percentile resolution; PT-06 (route create) initially failed with HTTP 400 because the perf script omitted the cycle-8 newly-required `requestMaps` and `createTilesZip` fields (one-line script fix landed in the same commit as the perf report — `32bc5c1`). The miss was a perf-script contract sync gap — the script had been updated for AZ-812's `lat`/`lon` rename but not for AZ-809's new required fields. |
| Cycle-8 validator overhead | **invisible** at percentile resolution. PT-03/04/05/07 (region POST) measurements all within noise band vs cycle 7. PT-06 (route POST) at 83 ms (post-fix) vs cycle 7's 161 ms — both in the noise band. PT-08 (UAV upload) at 379 ms batch p95 vs cycle 7's 284 ms — within historical band (cycle 5-7 range: 284-544 ms). |
| F-AZ809-1 polygon-cap fix overhead | **invisible** — the new `MaxPolygons = 50` check is a single `Count <= 50` comparison; the cap's intent is allocation-bounding under adversarial load, not steady-state latency, and a dedicated adversarial scenario is recommended for cycle 9 (recorded in `perf_2026-05-23_cycle8.md` § Follow-ups). |
| Cross-cycle leftover handling | **0 new leftovers** in `_docs/_process_leftovers/`. The PT-06 sync-miss was fixed inline (Action 3-style mechanical fix), not deferred. |
## 3. Structural Metrics (cycle-8 delta — first snapshot since cycle 5)
| Contract coverage of documented endpoints | **5 / 7** = **71%** | up from cycle 7's 2 / 7 = 29% (cycle 8 closed the documented-but-uncontract gap for region + route + lat/lon) |
| `SatelliteProvider.Api/Validators/` file count | **13** | +9 (cycle 8 added 9 new validator files; cycle 7 had added the 4 foundation files) |
| New unit-test methods in cycle 8 | **63** (across 8 new test files in `SatelliteProvider.Tests/Validators/`) | — |
| New integration-test methods in cycle 8 | **52** (across 5 new test files in `SatelliteProvider.IntegrationTests/*ValidationTests.cs`) | — |
| New probe scripts in cycle 8 | **4** (probe_region_validation.sh + probe_latlon_validation.sh + probe_route_validation.sh + probe_upload_validation.sh) | — |
| Net Architecture delta | **-1** | first negative delta since cycle 4 (Pattern 1 from cycle 7 closed; F-AZ809-1 Medium resolved in-cycle so net contribution 0; only Lows carry forward) |
**Cycle 6 + 7 structure snapshot gap**: cycles 6 and 7 did not write a `structure_*.md`. The cycle-8 snapshot is computed vs cycle 5 (the most recent), so the cycle-6 + cycle-7 deltas are folded into the cycle-8 row. **Process recommendation**: codify the structure-snapshot write as a Step-17 hard requirement in `.cursor/skills/retrospective/SKILL.md` Step 1 self-verification (currently soft-checked).
## 4. Trend Comparison (cycle 7 → cycle 8)
| Trend | Direction | Notes |
|-------|-----------|-------|
| Tasks per cycle | **+2** (3 → 5) | Cycle 8 was the AZ-795 child-task sweep — 4 endpoint validators + 1 prerequisite rename. The increased task count is by design. |
| Complexity per cycle | **+9 SP** (8 → 17) | Largest single-cycle SP delivery in project history. |
| Batches per cycle | **+3** (1 → 4) | Per-batch slicing kept each batch ≤ 5 SP and made per-batch reviews tractable (cycle 7 was 1 batch × 8 SP — heavier review per artifact). |
| Findings volume (post-review) | **+3 Low** (3 → 6) | Code-review Lows are all test-helper DRY (cycle-9 follow-up: promote `FixedTimeProvider` + `PostBatch` to `SatelliteProvider.TestSupport`). Security audit added 2 new Lows + 1 Medium **resolved in-cycle**. |
| Code-review pass rate | **n/a → 100% PASS_WITH_*** (4 / 4 batches reviewed; 0 FAILs) | First cycle with a per-batch review file for every batch; cycle 7 had none. |
| Leftovers carried out | **unchanged** (0 → 0) | Third consecutive cycle with zero new process leftovers (cycle 6 was the first). |
| Architectural cycles introduced | **0** (unchanged) | 5 consecutive cycles with a clean DAG. |
| Contract artifacts produced | **+3** (1 → 4: 3 new + 1 minor bump + 1 patch) | Cycle 8 published 3 new contracts (region-request + route-creation + tile-latlon) and bumped `uav-tile-upload` v1.1.0 → v1.2.0 + `route-creation` v1.0.0 → v1.0.1 (in-cycle F-AZ809-1 follow-up). |
| Step 14 (Security Audit) outcome | **PASS_WITH_WARNINGS** (unchanged — cycle 7 was also PASS_WITH_WARNINGS) | First cycle where a Medium finding was resolved in-cycle (F-AZ809-1 → commit `8fca6e0`). |
| Step 15 (Performance Test) script exit | **0** (unchanged) | Third consecutive clean exit-0; required one in-cycle perf-script fix for the AZ-809 contract sync miss. |
| Cross-cycle bug-introduction pattern | **0 new** | Nothing newly broken this cycle. The strict-validation surface continued to surface latent bugs (`UavUploadTests.NextTestCoordinate` lat-out-of-range — see Pattern 2 below — same family as cycle 7's `IdempotentPostTests` discovery), but they're pre-existing bugs surfaced by the new strict layer, not cycle-8 regressions. |
| Mid-cycle scope decisions (split / defer / re-spec) | **0** | No mid-cycle pivots; all 5 tasks shipped as planned across 4 batches. |
| Post-merge correction commits | **+1** (0 → 1) | Cycle 8 had one in-cycle fix commit (F-AZ809-1) AND one perf-script fix folded into the perf-report commit. Both are policy-driven (security-audit and perf-gate findings respectively), not error-driven (vs cycle 6's AC-5 TLS pivot which was a planning miss). |
| Per-batch review files | **4** (one per batch) | Closes cycle-7 process gap on per-batch reviews. Cycle 7 had 0 review files; cycle 8 has 4. |
| In-cycle security-finding resolution | **NEW** (F-AZ809-1) | First cycle to resolve a security-audit Medium within the cycle it was discovered. |
**Cumulative LESSONS reuse**: 5 lessons from previous cycles were directly applicable this cycle:
- **2026-05-22 process lesson on implement-skill artifact contract (cycle 7)** — directly closed by cycle 8: every cycle-8 batch wrote a per-batch report AND a per-batch review file, the cumulative cross-batch review fired (`cumulative_review_batches_01-04_cycle8_report.md`), the implementation phase ended with a consolidated `implementation_report_strict_validation_cycle8.md` AND a `implementation_completeness_cycle8_report.md`. Four artifact types where cycle 7 had two. The lesson's recommendation B (codify the fallback) was not formally written into the skill files — instead, the implement skill self-corrected by producing the artifacts. Either approach satisfies the underlying need.
- **2026-05-22 testing lesson on strict-validation surfaces latent bugs (cycle 7)** — directly applied this cycle: `UavUploadTests.NextTestCoordinate` had been seeding `(Ticks/TicksPerSecond) % 1_000_000` as the latitude offset since cycle 2, which produced values up to 160° (far above 90°). AZ-488's happy-path test never noticed because there was no lat/lon validator at the upload endpoint. AZ-810 added the validator and the cycle-8 batch-4 smoke run caught the bug. Fix was a 2-file clamp (UavUploadTests + UavUploadValidationTests use non-overlapping clamped ranges to preserve per-source UNIQUE-index safety). Same family as cycle 7's `IdempotentPostTests` discovery — the strict-validation surface continues to surface latent test-fixture bugs that the prior lenient defaults masked.
- **2026-05-23 process lesson on no-regression AC verification (cycle 8 batch 4)** — added inline by the implement skill during the AZ-810 batch-4 batch report (already in the ring buffer from a prior commit, dated 2026-05-23). Directly invoked the next day during the cycle-8 retro Step 1 self-verification.
- **2026-05-12 process lesson on Deferred-NFR ring-buffer (cycle 2)** — cycle 8 reused: the F-AZ809-1 finding was resolved in-cycle rather than deferred to cycle 9, preventing it from becoming a multi-cycle item.
- **2026-05-12 dependencies lesson on Major-version bumps (cycle 4)** — cycle 8 reused (negatively): cycle 8 declined to take the cycle-7 D-AZ795-1 FluentValidation 12.0.0 → 12.1.1 bump per scope discipline. The lesson's "verify transitive drift" precondition was satisfied (D-AZ795-1's static analysis re-confirmed no behavioural change in 12.1.1).
## 5. Patterns and Insights
### Pattern 1 — Cycle 7 Action 3 (AZ-795 child-task sweep) ships end-to-end in cycle 8 (NEW positive pattern)
Cycle 7's retro § 5 Action 3 recommended a per-endpoint child-task sweep under AZ-795 to add strict validation to `POST /api/satellite/request`, `POST /api/satellite/route`, `POST /api/satellite/upload`, and `GET /api/satellite/tiles/latlon`. **Cycle 8 shipped all four** — AZ-808 + AZ-809 + AZ-810 + AZ-811 — plus the prerequisite AZ-812 OSM rename that was a coordination-clause dependency.
**Why this matters**: this is the first cycle in the project's history where a cycle-N retrospective recommendation was both (a) tracker-captured as new PBIs in cycle N+1's spec slate and (b) shipped end-to-end in cycle N+1. Prior cycles had carry-overs (e.g., the cycle-3 perf-harness leftover that lingered until cycle 6), but those were single-task or single-fix items. Cycle 7's recommendation was a 4-task sweep + 1 coordination prerequisite, and cycle 8 delivered all 5 as a coherent cycle theme.
**Insight**: retrospective recommendations have measurable impact when (a) the recommendation explicitly names concrete tracker tickets / files / endpoints (cycle 7's Action 3 named the 3-4 endpoints + the SP sizing), (b) the next cycle's planning phase pulls the recommendation directly into the task slate without re-deriving scope, and (c) the recommendation is sized as a coherent cycle theme rather than a one-off fix. Cycle 7's Action 3 satisfied all three. Cycle 8's retrospective should treat this as the gold standard for recommendation phrasing.
### Pattern 2 — Strict-validation surface surfaced one more latent test-fixture bug (continuing positive pattern from cycle 7)
`UavUploadTests.NextTestCoordinate` had a latent bug since cycle 2: the seed `lat = (Ticks/TicksPerSecond) % 1_000_000` produced lat values far above 90° (at iteration n=200_000 → lat=160°). The bug never fired because (a) AZ-488 had no validator at the upload endpoint, (b) no DB constraint on lat range, (c) the test only checked HTTP 200 (which the unvalidated endpoint returned). AZ-810 added the validator and the cycle-8 smoke run caught it. The 2-file clamp fix landed in batch 4 alongside AZ-810 (`UavUploadTests` to [50,70) lat × [10,40) lon; `UavUploadValidationTests` to [-70,-50) × [-40,-10) for per-source UNIQUE-index safety).
**Why this matters**: cycle 7's identical pattern was `IdempotentPostTests` posting `{"Lat":..., "Lon":...}` against a `[JsonPropertyName("lat")]` DTO. Cycle 8's `NextTestCoordinate` bug is the second instance in two consecutive cycles. **The strict-validation rollout is a multi-cycle latent-bug excavation** — every new validator surface uncovers another bug that lenient defaults had masked.
**Insight**: when a strict-validation child task lands (e.g., one of the AZ-795 child tasks), the test-fixture inspection scope should include not just the new validator's tests but also the older happy-path tests of the same endpoint. A 30-minute "what test data does the prior happy-path test send, and does it satisfy the new validator?" check at spec-write time would have caught the `NextTestCoordinate` bug before the implementation phase began. **Add this to cycle 9's task-spec quality gate.**
### Pattern 3 — Perf-script contract sync is a partial-update class of bug (NEW pattern)
The cycle-8 batch-1 AZ-812 work updated `scripts/run-performance-tests.sh` PT-03/04/05/07 JSON bodies from `latitude/longitude` to `lat/lon`. The cycle-8 batch-3 AZ-809 work added new required fields (`requestMaps`, `createTilesZip`) to the route-creation contract. **The perf script's PT-06 body was NOT updated with the new required fields during batch 3.** The omission was caught at Step 15 (Performance Test gate) when PT-06 returned HTTP 400; a 1-line script fix landed alongside the perf report in commit `32bc5c1`.
**Why this matters**: cross-script wire-format sync is a recurring class of bug. Cycle 7 had the same family of issue when migrating `tile-inventory.md` 1.0.0 → 2.0.0 (`tileZoom/tileX/tileY → z/x/y`) — the perf script was updated, the integration tests were updated, but the cycle-7 deploy-report's example curl was a leftover sync miss that cycle 7's review caught manually. Cycle 8 has the same flavor (perf-script PT-06 partial sync).
**Insight**: there is no single owner for "every place that constructs the wire format outside of the production DTOs." The contract docs are the source of truth for the format, but the consumers (perf script, probe scripts, README example URLs, deploy-report example bodies, blackbox-tests.md trigger excerpts, OpenAPI examples) are scattered across the repo. **Recommendation**: add a `scripts/check_wire_format_consumers.sh` (cycle 9 candidate, ~2 SP) that ripgrep's the canonical contract-doc paths and reports any file path that has fewer wire-key matches than expected. This is a static-check level of defense — not a full schema verifier, just a "the field name is mentioned in N consumers, here are the N consumers, did you update them all?" surface.
### Pattern 4 — In-cycle security-finding resolution is a new tool in the autodev toolbox (NEW positive pattern)
Cycle 8 is the first cycle where a Step-14 security-audit Medium finding (F-AZ809-1) was resolved within the same autodev invocation: discovered in the audit (commit `ac40a8b`), fixed in commit `8fca6e0` (`MaxPolygons = 50` cap + unit test + integration test + `route-creation.md` v1.0.1 patch bump + traceability row AZ-809 AC-1b), all in ~30 minutes. The user-driven A/B/C gate at Step 14 explicitly enabled this: option A was "fix F-AZ809-1 NOW" rather than the historical default "defer to cycle N+1."
**Why this matters**: every prior cycle's security audit deferred all findings to a follow-up cycle (or the deploy-report's "Recommended follow-ups" section). The deferral pattern is correct for Low / informational findings and for any finding whose fix is non-trivial, but for a Medium finding whose fix is a one-line cap + ~5 lines of tests + a contract patch bump, the in-cycle resolution is meaningfully better: (a) the fix ships with the same commit chain that introduced the surface (one history rather than "introduced in cycle N, fixed in cycle N+1"), (b) the contract version reflects the fix immediately (route-creation.md v1.0.1 not v1.0.0), (c) the traceability matrix and blackbox-tests.md sub-cases are written at the time the finding is fresh, not from a stale finding description three weeks later.
**Insight**: the autodev orchestrator's Step-14 Optional Skill Gate should explicitly enumerate "fix-in-cycle" as a first-class A/B/C option for Medium findings whose fix is small (≤2 SP, ≤2 files, ≤1 contract bump). The current cycle-8 prompt did this ad-hoc; cycle 9's autodev flow should codify the threshold. **Recommendation**: amend `.cursor/skills/autodev/flows/existing-code.md` Step-14 action with a sub-clause: "If Step 14 surfaces a Medium finding whose remediation fits the small-fix threshold (≤2 SP, ≤2 files, ≤1 contract bump), present a 3-way gate: A) fix in-cycle then proceed | B) defer to cycle N+1 | C) skip Step 15+16+16.5 and end cycle. Default recommend A."
### Pattern 5 — Cycle 8 sustained the "zero new architecture-layer findings" streak across the project's largest delivery cycle (NEW positive pattern)
Cycle 8 delivered the most code volume in any single cycle of the project's history (5 tasks, 17 SP, 9 new validator files, 63 new unit tests, 52 new integration tests, 3 new contracts, 4 new probe scripts) AND held every structural metric stable:
- 0 new cross-project edges (3 consecutive cycles).
- 0 new csproj (5 consecutive cycles).
- 0 import-graph cycles (5 consecutive cycles).
- 0 new NuGet packages (3 consecutive cycles).
- 0 schema migrations (2 consecutive cycles).
- 0 new architecture-layer findings (after F-AZ809-1 resolution).
**Why this matters**: large-volume cycles historically correlate with new architecture deltas (cycle 1 added 4 csproj; cycle 4 added FluentValidation; cycle 5 added the Uuidv5 cross-cutting + 1 new import edge). Cycle 8 broke that correlation — the entire delivery stayed inside the established layer boundaries (`Api/Validators/` + `Common/DTO` annotations + `Tests/Validators/` + `IntegrationTests/*ValidationTests` + probe scripts + contract docs).
**Insight**: when a cycle's theme can be expressed as "add files in one well-defined directory + extend one existing API contract", the architecture-stability tax is near-zero even at high task volume. Cycles 9+ should explicitly favor task slates that share a single architectural surface (vs cross-cutting slates that touch multiple layers). **Recommendation**: when sizing a cycle's task slate, ask "are all tasks landing in ≤3 new files in the same namespace + ≤2 existing contract bumps?" — if yes, the cycle can safely deliver 4-5 tasks; if no, cap at 2-3 tasks.
## 6. Top 3 Improvement Actions
### Action 1 — Promote `FixedTimeProvider` and `PostBatch` test helpers to `SatelliteProvider.TestSupport`
**Why**: Pattern 1 from § 4 surfaced two DRY follow-ups during the cumulative review: `FixedTimeProvider` is duplicated across 4 test files (cycle-2 advisory crossed by cycle-8 batch 4 — "if a 3rd consumer appears, promote"); `PostBatch` is duplicated between `UavUploadTests.cs` and `UavUploadValidationTests.cs`. Cycle 8 explicitly recorded both as follow-up PBI candidates (`implementation_report_strict_validation_cycle8.md` § Follow-up PBIs).
**Action**: create AZ-NNN-promote-time-and-postbatch (2 SP — promote `FixedTimeProvider` to `SatelliteProvider.TestSupport.Time` + promote `PostBatch` to `SatelliteProvider.TestSupport.UavUploadMultipartFixture` + update 4 + 2 consuming test files). Sized as 2 SP because it's mechanical move + adjust imports + verify suite stays green. **Cycle 9 candidate, single batch.**
**Cost**: ~1 hour of dev work. Counted as 2 SP because it touches 6 files across 2 test projects.
### Action 2 — Add the strict-validation-fixture cross-check to task-spec quality gate
**Why**: Pattern 2 from § 4. The `NextTestCoordinate` latent-bug discovery cost the cycle-8 batch-4 implementation phase an extra ~30 minutes of investigation + a 2-file clamp fix. A 30-minute spec-write-time inspection ("does the prior happy-path test's data satisfy the new validator?") would have caught it before the implementation phase began. This is a process-level change to the task-spec quality gate, not a one-off fix.
**Action**: amend `.cursor/skills/new-task/SKILL.md` (or `.cursor/skills/plan/SKILL.md` if that's where strict-validation child specs are written) with a new spec-quality checklist item: "**Fixture pre-check**: for every existing test file that exercises the endpoint being newly validated, identify the test-data generator (helper, fixture, constant), trace one representative value end-to-end through the new validator rules, and explicitly confirm in the spec that the prior data satisfies the new rules — or document the required test-data update." ~1 SP.
**Cost**: ~30 minutes of skill-author work. Counted as 1 SP because it's a single checklist item added to one (or two) skill files.
### Action 3 — Build a `scripts/check_wire_format_consumers.sh` static-check probe
**Why**: Pattern 3 from § 4. Perf-script PT-06 partial sync was a known class of bug (cycle 7 had a similar instance with `tile-inventory.md` 1.0.0 → 2.0.0). There is no single owner for "every place that constructs the wire format outside the production DTOs," and the consumers are scattered (perf script, probe scripts, README example URLs, deploy-report example bodies, blackbox-tests.md trigger excerpts, OpenAPI examples). A static-check probe at the cycle-8 closure level would have caught the PT-06 omission before Step 15.
**Action**: create AZ-NNN-wire-format-consumer-check (2 SP — write `scripts/check_wire_format_consumers.sh` that ripgrep's the canonical contract-doc paths under `_docs/02_document/contracts/api/` and reports any consumer file path that mentions an old wire-key the contract has retired; integrate into the test-spec sync skill's quality gate). Initial implementation can be a simple "for each contract doc, extract the JSON field names from the contract's example body; for each consumer path, count matches; flag any consumer with fewer matches than expected after a known rename." ~2 SP.
**Cost**: ~1 hour of skill + script work. Counted as 2 SP because it requires (a) the bash script, (b) integration into the test-spec skill's quality gate, and (c) one validation run against cycle 8's actual surface to confirm the cycle-8 PT-06 miss would have been caught.
## 7. Carry-overs (status this cycle)
| Item | Status | Notes |
|------|--------|-------|
| `_docs/_process_leftovers/` folder state | **EMPTY** as of cycle 8 entry and exit | Third consecutive cycle with zero process leftovers. |
| Microsoft.NET.Test.Sdk 17.8.0 transitive `NuGet.Frameworks` NU1902 (D2-cy4, **Medium**) | OPEN (carried from cycles 4 + 5 + 6 + 7 + 8) | No cycle-8 touch. Re-flagged in `dependency_scan_cycle8.md` carry-over table. |
| Microsoft.IdentityModel.Tokens / System.IdentityModel.Tokens.Jwt 7.0.3 NU1902 (Low) | OPEN (carried from cycles 3 + 4 + 5 + 6 + 7 + 8) | No cycle-8 touch. Re-flagged. |
| Serilog.AspNetCore 8.0.3 → 10.x recheck (Low) | OPEN (carried from cycles 4 + 5 + 6 + 7 + 8) | No cycle-8 touch. Re-flagged. |
| ASPDEPR002 `WithOpenApi(...)` deprecation | OPEN (carried from cycles 4 + 5 + 6 + 7 + 8) | No cycle-8 touch. |
| Admin team `iss/aud` confirmation (carried from cycle 3) | OPEN (still required before promoting beyond `dev`) | Re-listed. |
| `metadata.flightId` authenticated provenance (F1-cy5) | OPEN (long-term, not actionable until flight registry exists) | Re-listed. |
| `pgcrypto` ops gap (F2-cy5) | OPEN (doc-only fix, ~30 min) | Re-listed. |
| Deployment runbook: ingress TLS termination + HTTP/2 forwarding (cy6 follow-up) | OPEN (no cycle-7 or cycle-8 touch) | Re-listed. |
| `tile-storage.md` consumer audit post v2.0.0 (cy6 follow-up) | OPEN | Re-listed. |
| Inventory endpoint `estimatedBytes` field (AZ-505 deferral) | OPEN | Re-listed. |
| HTTP/3 / QUIC dev listener (AZ-505 deferral) | OPEN | Re-listed. |
| Cycle-7 D-AZ795-1: FluentValidation 12.0.0 → 12.1.1 bump | OPEN (carried from cycle 7) | Cycle 8 explicitly excluded NuGet hygiene per scope discipline. |
| Cycle-7 F-AZ795-1 + F-AZ795-2: sanitize `JsonException.Message` + `BadHttpRequestException.Message` in 400 detail | OPEN (carried from cycle 7) | Cycle 8 added a third instance of this class (F-AZ810-1 in `UavUploadValidationFilter`) — see new cycle-8 entry below. |
| Cycle-7 implementation-report exit-gate / fallback formalisation | **CLOSED in-cycle by cycle 8** | Cycle 8 produced both per-batch reports AND a consolidated implementation report AND a completeness report AND a cumulative cross-batch review — four artifact types where cycle 7 had two. The implement skill self-corrected without a rule-file change. |
| Cycle-7 AZ-795 child-task sweep across remaining public endpoints | **CLOSED in-cycle by cycle 8** | Cycle 8 shipped all four AZ-795 child tasks (AZ-808 + AZ-809 + AZ-810 + AZ-811) + the prerequisite AZ-812 rename. See § 4 Pattern 1. |
| **NEW (cycle 8)** F-AZ809-1: unbounded `geofences.polygons` DoS | **CLOSED in-cycle** (commit `8fca6e0`) | First cycle-N security-audit Medium resolved within cycle N. |
| **NEW (cycle 8)** F-AZ810-1: `JsonException.Message` echo in `UavUploadValidationFilter` | OPEN — recommended | New instance of the cycle-7 F-AZ795-1 pattern in a second code path. Roll into the cycle-7 F-AZ795-1/2 sanitization PBI. |
| **NEW (cycle 8)** F-AZ810-2: `UavTileMetadata.CapturedAt` typed `DateTime` not `DateTimeOffset` | OPEN — informational | Freshness window drifts in non-UTC dev environments. Zero impact in UTC-deployed prod. Cycle 9 candidate, low priority. |
| **NEW (cycle 8)** Promote `FixedTimeProvider` + `PostBatch` test helpers to `SatelliteProvider.TestSupport` | OPEN — recommended | Action 1 above. ~2 SP. |
| **NEW (cycle 8)** PT-07 perf-harness cross-run cache pollution (hard-coded base coords) | OPEN — perf harness cleanup | Documented in `perf_2026-05-23_cycle8.md` § Known harness quirks. Pre-existing issue surfaced by cycle-8 back-to-back perf runs. ~2 SP cycle-9 candidate. |
| **NEW (cycle 8)** F-AZ809-1 adversarial perf scenario (PT-NN — 50 + 51 polygons → measure validator latency and 400-response time) | OPEN — perf harness extension | Converts F-AZ809-1 cap intent (DoS-bound) into a measurable regression gate. ~3 SP cycle-9 candidate. |
| **NEW (cycle 8)** Structure-snapshot retro hard-gate | OPEN — process | Cycles 6 + 7 didn't write `structure_*.md`; codify as a Step-17 hard requirement in retrospective Step 1 self-verification. ~1 SP. |
| **NEW (cycle 8)** Autodev Step-14 in-cycle-fix Optional Skill Gate codification | OPEN — process | § 4 Pattern 4 — amend `.cursor/skills/autodev/flows/existing-code.md` Step-14 to add "fix-in-cycle" as a first-class A/B/C option for Medium findings whose fix is small (≤2 SP, ≤2 files, ≤1 contract bump). ~1 SP. |
**New leftovers carried out of cycle 8**: **0** (process leftovers folder remains empty). All cycle-8 follow-ups are tracked as recommended PBIs in this retro § 6 + § 7, not as process leftovers.
## 8. Suggested Rule / Skill Updates
| Target file | Change | Rationale |
|-------------|--------|-----------|
| `.cursor/skills/retrospective/SKILL.md` Step 1 self-verification | Promote `Structural snapshot written` from soft check to hard requirement (BLOCKING gate) when `module-layout.md` exists. Add: "If the most recent `structure_*.md` is more than 1 cycle old, compute the snapshot vs the most recent one and fold the intermediate cycles' deltas into the new snapshot's notes." | Pattern: cycles 6 + 7 skipped the snapshot; cycle 8 caught up but had to compute the delta vs cycle 5 directly. The hard gate prevents the gap from compounding. |
| `.cursor/skills/autodev/flows/existing-code.md` Step 14 action | Add: "If Step 14 surfaces a Medium finding whose remediation fits the small-fix threshold (≤2 SP, ≤2 files, ≤1 contract bump), present a 3-way gate: A) fix in-cycle then proceed | B) defer to cycle N+1 | C) skip Step 15+16+16.5 and end cycle. Default recommend A." | § 4 Pattern 4. Codifies the cycle-8 F-AZ809-1 resolution pattern as a first-class option. |
| `.cursor/skills/new-task/SKILL.md` (or `.cursor/skills/plan/SKILL.md` if strict-validation child specs are written there) — spec quality checklist | Add a "Fixture pre-check" item: "For every existing test file that exercises the endpoint being newly validated, identify the test-data generator (helper, fixture, constant), trace one representative value end-to-end through the new validator rules, and explicitly confirm in the spec that the prior data satisfies the new rules — or document the required test-data update." | § 6 Action 2. Would have caught the cycle-8 `NextTestCoordinate` latent bug at spec-write time. |
| `.cursor/skills/test-spec/SKILL.md` cycle-update mode | Add a "wire-format consumer cross-check" step: after any contract `[JsonPropertyName]` rename or new required-field addition, ripgrep the consumer paths (`scripts/run-performance-tests.sh`, `scripts/probe_*.sh`, `README.md` example URLs, `_docs/04_deploy/*.md` example bodies, `_docs/02_document/tests/blackbox-tests.md` trigger excerpts) and verify they reference the new field names. | § 6 Action 3, simplified — instead of a separate script, fold the check into the existing test-spec sync skill that already runs on contract changes. |
| `.cursor/skills/security/SKILL.md` Phase 5 (Security Report) | Add a "Resolved In-Cycle" row category to the consolidated security-report template, distinct from "Carried Forward". Document the cycle-8 F-AZ809-1 resolution as the reference example. | The current security-report template implicitly assumes all findings carry forward; cycle 8 demonstrated that in-cycle resolution is a viable third state. Codifying it in the template makes future reports clearer about what "PASS_WITH_WARNINGS" actually contains. |
## 9. Validations and Sources
- **Cycle-8 implementation artifacts parsed**: 4 batch reports (`batch_01..04_cycle8_report.md`), 4 review files (referenced from each batch report), 1 cumulative review (`cumulative_review_batches_01-04_cycle8_report.md`), 1 consolidated implementation report (`implementation_report_strict_validation_cycle8.md`), 1 completeness report (`implementation_completeness_cycle8_report.md`), 5 task specs in `_docs/02_tasks/done/`, 9 dev commits on the cycle-8 chain (full subject + body parsed for each).
- **Cycle-5 structure snapshot compared**: see § 3 + `structure_2026-05-23_cycle8.md` (cycles 6 + 7 deltas folded into the cycle-8 row).
- **Cross-cycle dependency tracking**: AZ-808 + AZ-809 + AZ-810 + AZ-811 all carry `Relates AZ-795` (the AZ-795 epic parent) in Jira. AZ-812 carries `blocks AZ-808` (the OSM rename must land before the region-POST validator's contract publishes with `lat`/`lon`). The cycle-5/6/7 lessons about explicit dependency-link choice were applied.
- **No skill-level escalations encountered**: no `retry_count: 3` failures in any sub-skill; no FAIL verdicts in any per-batch review or cumulative review; no FAIL verdict in security audit (after in-cycle F-AZ809-1 resolution); no FAIL verdict in perf gate (after in-cycle perf-script fix). Two in-cycle process-driven fixes (F-AZ809-1 + perf-script PT-06) executed cleanly via user A/B/C gates.
- [x] Comparison with cycle-7 retro performed (§ 4 trend table).
- [x] Top 3 improvement actions concrete and actionable (§ 6).
- [x] Suggested rule/skill updates specific and tied to a target file (§ 8).
- [x] New cycle-8 follow-up PBIs (Action 1 + 2 + 3 + F-AZ810-1/2 + perf-harness cleanups + structure-snapshot hard-gate + Step-14 in-cycle-fix codification) cross-referenced between § 6, § 7, and the security/perf reports.
- [x] LESSONS.md ring buffer to be appended with top 3 cycle-8 lessons (§ 5 Patterns 1, 2, 4 distilled to single-sentence form) — applied in next step.
- [x] Structural snapshot written (`structure_2026-05-23_cycle8.md`); cycle-6 + cycle-7 deltas folded; gap noted as cycle-9 follow-up (Suggested Rule Update 1).
Cycle 8 delta against `structure_2026-05-12_cycle5.md` (the most recent snapshot — cycles 6 and 7 did not write snapshots; **process gap** carried forward as a cycle-8 follow-up). Source of truth: `_docs/02_document/module-layout.md` + on-disk `*.csproj` graph + `_docs/02_document/contracts/`.
| 1 (Foundation) | `SatelliteProvider.DataAccess` | **+1 migration in cycle 6** (`015_*.sql` — AZ-505 leaflet covering index); **0 migrations in cycle 7 + cycle 8.** Cycle 8 has zero schema touch — first 2-cycle stretch without schema change since cycle 3-4 (cycle 7 was the first migration-free cycle). |
| 1 (Foundation, shared DTO) | `SatelliteProvider.Common` (DTO sub-folder) | **No new DTO files this cycle**; cycle 8 added `[JsonRequired]` annotations to 5 existing files. |
| 3 (Application) | `SatelliteProvider.Services.{TileDownloader, RegionProcessing, RouteManagement}` | unchanged (zero service-layer changes in cycle 8 — the entire cycle landed in `SatelliteProvider.Api/Validators/` + `Common/DTO`) |
| 6 (Tests) | `SatelliteProvider.IntegrationTests` | **+5 test files in cycle 8** (RegionFieldRenameTests + RegionRequestValidationTests + GetTileByLatLonValidationTests + CreateRouteValidationTests + UavUploadValidationTests); **+52 integration-test methods** total. `Program.cs` updated by every batch to wire the new entry points into both `RunSmokeSuite` and `RunFullSuite`. `ProblemDetailsAssertions.cs` extended with `AssertErrorsContainsMention` shared helper. |
**Project count**: **9** (unchanged from cycle 5 — cycle 8 adds files to existing projects, doesn't add a new csproj).
| IntegrationTests → {TestSupport, Common} | 2 | unchanged (the cycle-5 +1 edge has held) |
**Total ProjectReference edges**: **21** (cycle 5: 21). Net delta across cycles 6 + 7 + 8: **0** — three consecutive cycles with zero new compile-time edges. This is the longest stretch of edge stability in the project's history.
## Source-import sites — cycle 8 delta
| Importer | Imports from | Cycle 8 delta |
|----------|--------------|---------------|
| `SatelliteProvider.Api/Validators/{Create,Get,Region,Route,Uav}*Validator.cs` (9 new files) | `FluentValidation` (12.0.0, cycle-7 dep) + `SatelliteProvider.Common.DTO` | NEW (every cycle-8 validator imports from Common.DTO; no new third-party imports). |
| `SatelliteProvider.Api/Validators/UavUploadValidationFilter.cs` (NEW) | `FluentValidation` + `Microsoft.AspNetCore.Http` + `System.Text.Json` + `SatelliteProvider.Common.DTO` | NEW (bespoke `IEndpointFilter` for the multipart endpoint). |
| `SatelliteProvider.Tests/Validators/*` (8 new files) | `FluentValidation.TestHelper` + `SatelliteProvider.Common.DTO` + `Xunit` | NEW (each test file scoped to one validator). |
| `SatelliteProvider.IntegrationTests/*ValidationTests.cs` (5 new files) | existing `IntegrationTests` infrastructure (`ProblemDetailsAssertions`, `TestRunMode`, `JwtTokenFactory`) + `SatelliteProvider.Common.DTO` | NEW (each file scoped to one endpoint's validation surface). |
| All other source files | unchanged | — |
**~25 new source-level import lines** across the new files; **all internal or framework**. **Zero new third-party imports.** FluentValidation 12.0.0 was added by cycle 7 (it's the foundation that AZ-795 epic builds on); cycle 8 expands its consumer set within the Api project but doesn't introduce a new dependency line.
## Graph properties
- **Cycles in project import graph**: **0** (clean DAG — unchanged for 5 consecutive cycles).
| FluentValidation | 12.0.0 (cycle 7 add) | unchanged | The cycle-7 retro Action 1 recommended a 12.0.0 → 12.1.1 bump (`D-AZ795-1`). Cycle 8 did NOT take the bump — the security audit re-confirmed Low / Hardening severity, and the cycle-8 scope (per-endpoint child tasks) explicitly excluded NuGet hygiene per `coderule.mdc` scope discipline. **Still OPEN, carried forward.** |
| All other NuGet packages across all 9 csproj files | unchanged | **unchanged** | **Zero NuGet bumps this cycle.** Three consecutive zero-bump cycles (cycle 6 closed AZ-505's only NuGet bump; cycle 7 added FluentValidation 12.0.0 + extensions; cycle 8 used FluentValidation entirely against cycle-7's foundation). |
| Carry-overs (still OPEN) | Cycle-3 D2-cy4 (`Microsoft.NET.Test.Sdk 17.8.0` transitive `NuGet.Frameworks` flag — **Medium**); cycle-4 D4 (`Microsoft.IdentityModel.Tokens` / `System.IdentityModel.Tokens.Jwt` 7.0.3 NU1902 — Low); `Serilog.AspNetCore` 8.0.3 fallback (Low) | unchanged | All three remain explicitly out of cycle-8 scope (scope discipline). Re-listed in `_docs/05_security/dependency_scan_cycle8.md` carry-over table. |
## Database schema surface (cycle 8 delta)
| Object | Change | Source |
|--------|--------|--------|
| (no schema changes this cycle) | — | — |
**Zero schema changes in cycle 8** — second consecutive migration-free cycle (cycle 7 was the first). Cycle 8's strict-validation work lives entirely above the persistence layer (deserializer + FluentValidation + endpoint filters); no field validation requires a column change because all rules are *application-level enforced* (the database still accepts any well-formed value the validator lets through).
-`_docs/02_document/contracts/api/region-request.md` v1.0.0 (AZ-808 — published with post-AZ-812 `lat`/`lon` wire format directly per the coordination clause).
-`_docs/02_document/contracts/api/route-creation.md` v1.0.0 → **v1.0.1** (AZ-809 v1.0.0 + an in-cycle PATCH bump for the F-AZ809-1 50-polygon cap added during the Step-14 security-audit follow-up).
- **1 contract MINOR bump**: `uav-tile-upload.md` v1.1.0 → **v1.2.0** (AZ-810 — additive: new "Metadata validation" section).
- **No contract MAJOR bumps this cycle** (cycle 7 shipped the only MAJOR bump in project history — `tile-inventory.md` 1.0.0 → 2.0.0; cycle 8 produced only new contracts + minor + patch).
- **Public-API contract coverage**: now **5 contracts** across **5 documented endpoints** (`region-request`, `route-creation`, `tile-latlon`, `tile-inventory`, `uav-tile-upload`) + the shared `error-shape.md`. Endpoints without a dedicated contract: 2 read-only `GET /api/satellite/{region,route}/{id}` (path-Guid only — no strict-validation surface, per cycle-8 implementation report).
- **Contract-per-endpoint ratio**: **5 / 7** = **71%** (cycle 7: 2 / 7 = 29%, cycle 6: 1 / 7 = 14%). Cycle 8 more than doubled the documented-endpoint coverage in a single cycle.
- **Architecture findings carry-over from cycle 7**: 0 new architecture-layer findings; 0 architecture-layer carry-overs resolved (cycle 7's open recommendations on implement-skill ↔ downstream-skill artifact contract were partially addressed — cycle 8 produced both the per-batch reports AND the consolidated `implementation_report_strict_validation_cycle8.md` per cycle-7 Action 1 recommendation; see `retro_2026-05-23_cycle8.md` § Pattern 1).
## Net Architecture delta vs cycle 7
- **Resolved (closed by this cycle)**: **1** — cycle-7 Pattern 1 (missing implementation report) is closed by `implementation_report_strict_validation_cycle8.md` + `implementation_completeness_cycle8_report.md` + `cumulative_review_batches_01-04_cycle8_report.md` (three artifact types where cycle 7 had none).
- **Newly introduced**:
- 1 Medium **resolved in-cycle**: F-AZ809-1 (unbounded `geofences.polygons` DoS) — found in Step 14 security audit, fixed in commit `8fca6e0` with a `MaxPolygons = 50` cap + unit + integration test + contract v1.0.1 + traceability row AZ-809 AC-1b before Step 14 closure. **Net contribution: 0 (resolved before retrospective).**
- 2 Low (F-AZ810-1 `JsonException.Message` echo in `UavUploadValidationFilter`; F-AZ810-2 `DateTime` vs `DateTimeOffset` for `CapturedAt` — UTC-deployment-only impact). Open; carry to cycle 9.
- 0 new Medium, 0 new High, 0 new Critical (after F-AZ809-1 resolution).
- **Net Architecture delta**: **-1** (Pattern 1 closed; only Low informational findings introduced, both carried forward). **First negative net architecture delta since cycle 4.**
## What this snapshot says about cycle 8's shape
Cycle 8 is the project's **largest single-cycle code volume** to date (5 tasks shipped in 4 batches; 17 SP delivered vs cycle 7's 8 SP; ~115 new test methods; 9 new validator files; 3 new contracts + 1 MINOR + 1 PATCH bump). It is also the **lowest structural-impact cycle of that size**: zero new csproj, zero new NuGet, zero new cross-project edges, zero schema changes, zero new architecture violations. The entire cycle stays inside the `SatelliteProvider.Api/Validators/` namespace + `Common/DTO` annotations + `Tests/Validators/` test directory + 4 probe scripts + 4 new docs — a clean layered addition on top of the cycle-7 foundation (`UnmappedMemberHandling.Disallow`, `GlobalExceptionHandler`, `error-shape.md` v1.0.0, FluentValidation 12.0.0).
Cycle 8 also closes Pattern 1 from cycle 7: the implement skill produced both per-batch reports AND a consolidated implementation report AND a completeness report AND a cumulative cross-batch review — four artifact types where cycle 7 had two (per-batch reports + per-batch reviews only). This is the directly visible execution of cycle 7's Action 1 ("formalise the implement-skill ↔ downstream-skill artifact contract") — done implicitly by the implement skill itself this cycle, rather than via the rule-file change cycle 7 recommended.
The DAG remains acyclic with the same 9 projects; max-in-degree is still `Common` at 7; the project's architectural shape has held stable across cycles 6 + 7 + 8 despite the steady delivery cadence.
@@ -37,11 +37,17 @@ If the enum's wire string happens to match a member name case-insensitively (e.g
## Ring buffer (last 15 entries — newest at top)
- [2026-05-23] [process] Step-14 security-audit Medium findings whose remediation fits the small-fix threshold (≤2 SP, ≤2 files, ≤1 contract bump) should be resolved within the same autodev invocation rather than deferred to cycle N+1 — the fix lands with the same commit chain that introduced the surface, the contract version reflects the fix immediately, and the traceability matrix and blackbox-tests.md sub-cases are written while the finding is fresh; codify the option as a first-class A/B/C choice in `.cursor/skills/autodev/flows/existing-code.md` Step-14 action (cycle 8: F-AZ809-1 unbounded `geofences.polygons` DoS — discovered in commit `ac40a8b`, resolved in commit `8fca6e0` with `MaxPolygons = 50` cap + unit + integration test + `route-creation.md` v1.0.1 patch bump, ~30 minutes from finding to fix landed).
- [2026-05-23] [process] Retrospective recommendations ship end-to-end in the next cycle only when they (a) name concrete tracker tickets / files / endpoints in the action text, (b) are sized as a coherent cycle theme rather than scattered one-off fixes, and (c) the next cycle's planning phase pulls the recommendation directly into the task slate without re-deriving scope — phrase recommendations to satisfy all three or they become multi-cycle carry-overs (cycle 7 Action 3 named the 4 AZ-795 child endpoints + the SP sizing → cycle 8 shipped AZ-808 + AZ-809 + AZ-810 + AZ-811 + AZ-812 as the coherent strict-validation theme, first directly-traceable cross-cycle improvement-action end-to-end in project history).
- [2026-05-23] [tooling] When a contract introduces a new required field or renames a wire key, the test-spec sync step must ripgrep all consumer paths (`scripts/run-performance-tests.sh`, `scripts/probe_*.sh`, `README.md` example URLs, `_docs/04_deploy/*.md` example bodies, `_docs/02_document/tests/blackbox-tests.md` trigger excerpts, OpenAPI examples) and verify they reference the new shape — otherwise partial syncs surface at Step 15 Performance Test gate or worse in production (cycle 8: AZ-812 lat/lon rename updated the perf script but AZ-809's newly-required `requestMaps` + `createTilesZip` fields did not propagate to PT-06; caught at Step 15 with a 1-line script fix in commit `32bc5c1` — a static-check probe at batch closure would have caught it 2 days earlier).
- [2026-05-23] [process] When verifying a "no-regression" AC for an input-validation change ("AZ-NNN does not break existing tests"), the only sound evidence is a green integration-test run — tracing fixture variables back to their generators in source is insufficient because helpers can produce values outside the new bounds and previously slipped through silently when no validator existed; document the standard as "verified by reading source" → unconfirmed, "verified by full test run" → confirmed, and gate the batch report's AC table on the latter before the implement skill closes the batch (cycle 8: AZ-810 batch_04 AC-9 claimed "no AZ-488 regression" based on tracing `latitude = coord.Latitude` in test source, but `NextTestCoordinate` seeded by `(Ticks/TicksPerSecond) % 1_000_000` produced lat far above 90° at runtime; the false-PASS only surfaced at autodev Step 11 when the integration test run returned HTTP 400 from the new validator on the AZ-488 happy path).
- [2026-05-22] [process] When the implement skill ships a cycle's batch commit without writing `_docs/03_implementation/implementation_report_*_cycle{N}.md`, downstream skills (test-spec cycle-update, document task mode, retrospective Step 1) must fall back to reading the cycle's task specs in `_docs/02_tasks/done/` plus the commit body via `git log --grep='[AZ-...]'` — codify the fallback in those skills' instructions instead of leaving it as per-cycle improvisation, because the implicit contract between Step 10 and Steps 11-17 broke silently this cycle and only succeeded because every downstream skill happened to be robust enough to substitute (cycle 7: AZ-794+AZ-795+AZ-796 shipped as commit `865dfdb` with no report artifact; doc-skill auto-walked the diff, test-spec read the task specs, retrospective wrote from the deploy + security + perf reports — all worked, but the contract was never formal).
- [2026-05-22] [process] When the implement skill ships a cycle's batch commit without writing `_docs/03_implementation/implementation_report_*_cycle{N}.md`, downstream skills (test-spec cycle-update, document task mode, retrospective Step 1) must fall back to reading the cycle's task specs in `_docs/02_tasks/done/` plus the commit body via `git log --grep='[AZ-...]'` — codify the fallback in those skills' instructions instead of leaving it as per-cycle improvisation, because the implicit contract between Step 10 and Steps 11-17 broke silently this cycle and only succeeded because every downstream skill happened to be robust enough to substitute (cycle 7: AZ-794+AZ-795+AZ-796 shipped as commit `865dfdb` with no report artifact; doc-skill auto-walked the diff, test-spec read the task specs, retrospective wrote from the deploy + security + perf reports — all worked, but the contract was never formal).**Status**: closed by cycle 8 — the implement skill self-corrected and produced both per-batch reports AND a consolidated implementation report AND a completeness report AND a cumulative cross-batch review.
- [2026-05-22] [testing] When a strict-validation layer ships (`JsonSerializerOptions.UnmappedMemberHandling.Disallow`, FluentValidation rules, explicit DTO `[JsonRequired]`), expect the project's own integration tests to surface latent bugs the prior lenient defaults had been masking — silent PascalCase fallback property names, out-of-range fixture coordinates, wrong-cased JSON keys; correct them in the same PR or the test suite goes red and the strict layer looks like a regression instead of the bug-finder it is (cycle 7: `IdempotentPostTests.RoutePoint` had been posting `{"Lat":...}` against a `[JsonPropertyName("lat")]` DTO for months; the new strict deserializer caught it and the 2-line payload fix landed alongside the strict layer).
- [2026-05-22] [testing] When a strict-validation layer ships (`JsonSerializerOptions.UnmappedMemberHandling.Disallow`, FluentValidation rules, explicit DTO `[JsonRequired]`), expect the project's own integration tests to surface latent bugs the prior lenient defaults had been masking — silent PascalCase fallback property names, out-of-range fixture coordinates, wrong-cased JSON keys; correct them in the same PR or the test suite goes red and the strict layer looks like a regression instead of the bug-finder it is (cycle 7: `IdempotentPostTests.RoutePoint` had been posting `{"Lat":...}` against a `[JsonPropertyName("lat")]` DTO for months; the new strict deserializer caught it and the 2-line payload fix landed alongside the strict layer; **cycle 8 instance**: `UavUploadTests.NextTestCoordinate` produced lat > 90°, caught by AZ-810 validator, 2-file clamp fix in batch 4).
- [2026-05-22] [architecture] Contract MAJOR bumps for projects with ≤2 known consumers should ship without a wire-format adapter — the cost of maintaining a dual-accepting endpoint outweighs the benefit when the operator runbook can coordinate the consumer cut-over directly; only invest in an adapter when consumer count or release-cadence asymmetry makes coordinated cut-over impractical (cycle 7: `tile-inventory.md` 1.0.0 → 2.0.0 renamed `tileZoom/tileX/tileY → z/x/y` and shipped breaking; the only consumer is `gps-denied-onboard` and the AZ-777 follow-up loop handled the coordination via the operator runbook in `deploy_cycle7.md`).
- [2026-05-12] [process] When a scope-protected task newly *exposes* a pre-existing bug elsewhere in the codebase (vs. introducing a new one), surface it as a recommended follow-up PBI in the batch report AND list it as a "newly exposed bug" separate from "newly introduced findings" in the deploy report — bugs that already existed don't count as cycle-introduced regressions, but they must not be silently re-buried (cycle 4: AZ-500's bootstrap fix unmasked the pre-existing `scripts/run-performance-tests.sh:417``grep -o | wc -l` + `pipefail` bug).
- [2026-05-12] [process] When a cycle has a single non-functional task (migration / refactor / dependency hygiene), the retro must reframe the metric set around continuity (0 regressions), forward-resolution (prior findings closed by the bump itself), and unblocking (capabilities now exercisable end-to-end) — task count + complexity points read as misleading flatlines that look like under-productivity (cycle 4: AZ-500 alone delivered 5 SP vs cycle 3's 18 SP, but the cycle's value was forward-resolving 2 cycle-3 advisories and finally executing PT-01..PT-08 end-to-end against the migrated build).
- [2026-05-12] [process] For cross-team blockers (admin team must supply config values, etc.), prefer an Option-B forcing function (ship the validation/scaffolding with prod-empty config that fails-fast at deploy) over deferring the entire task — the fail-fast contract makes the cross-team conversation impossible to skip and ships the in-workspace work in the current cycle (cycle 3: AZ-494 shipped iss/aud validation with empty prod appsettings so deploy must supply real values).
- [2026-05-12] [process] ACs that prescribe a specific measurement or sentinel mechanism (e.g. "per-item latency < 50ms", "guard fires when DB name contains _test") should also prescribe — or explicitly defer — the path for collecting / enforcing it, or implementations will substitute proxies / equivalents that look like spec drift in review (cycle 3: AZ-492 PT-08 per-item gate cost became a derived proxy; AZ-493 DB-name guard became Host-allowlist).
- [2026-05-12] [process] ACs that require cross-repo writes should be tagged with the target workspace and rendered separately in the traceability matrix — mixing them with in-workspace ACs makes "correctly deferred" indistinguishable from "incomplete work" (cycle 3: AZ-494 AC-7 deferred for the suite-repo write; matrix renders as `◐ deferred` which is ambiguous).
detail: "verdict: PASS (8/8 scenarios). Required one in-cycle AZ-809 contract-sync fix to PT-06 body. Report: _docs/06_metrics/perf_2026-05-23_cycle8.md."
phase: 4
name: lessons-log-updated
detail: "Cycle-end retrospective produced: _docs/06_metrics/retro_2026-05-23_cycle8.md + _docs/06_metrics/structure_2026-05-23_cycle8.md + _docs/LESSONS.md (3 new lessons, trimmed to 15 ring-buffer entries). Cycle 8 closed. Next /autodev invocation = cycle 9 Step 0 (orchestrator reset)."
retry_count: 0
cycle: 8
tracker: jira
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.