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>
The AZ-810 metadata validator rejects lat outside [-90, 90] and lon
outside [-180, 180]. Two NextTestCoordinate() helpers seeded their
counter from `(Ticks/TicksPerSecond) % 1_000_000` and returned
`60 + n*0.0005`, producing lat well above 90° for almost any seed
(e.g. n=200000 -> lat=160). Pre-AZ-810 there was no validator and no
DB constraint, so the out-of-range values were silently accepted; the
new validator (correctly) rejected them at HTTP 400.
Clamp both helpers to non-overlapping OSM-valid ranges:
- UavUploadTests.cs: lat in [50, 70), lon in [10, 40)
- UavUploadValidationTests.cs: lat in [-70, -50), lon in [-40, -10)
Non-overlap (not the prior +5_000_000 counter offset) is what now
guarantees AZ-488 and AZ-810 suites don't collide on the per-source
UNIQUE index when both run against the same DB.
No production code change; AZ-810 validator behaviour is unchanged.
Also:
- Correct AC-9 in batch_04_cycle8_report.md: the original claim
("verified by tracing source") was a false-PASS; the autodev
Step 11 test run surfaced the gap. Now confirmed by full-suite
green (scripts/run-tests.sh --full).
- Add ring-buffer lesson on AC-verification standards for input-
validation changes: tracing fixture variables to their generators
is insufficient; only a green integration-test run is sound
evidence for a "no-regression" AC.
Co-authored-by: Cursor <cursoragent@cursor.com>
Cycle 7 retrospective (cycle-end mode) — three-task pure-quality
cycle (AZ-794 rename + AZ-795 epic shared infra + AZ-796 inventory
validator). PASS gate end-to-end; first cycle to ship a contract
MAJOR bump; second consecutive cycle with zero new process
leftovers; first cycle to run the full 5-phase security audit
since cycle 5.
Top 3 improvement actions for cycle 8:
1. Formalise the implement-skill <-> downstream-skill artifact
contract — cycle 7 shipped without an implementation report
and the doc / test-spec / retrospective skills successfully
fell back to task-spec + commit-body reading, but the
fallback is implicit and should be codified.
2. Sanitize JsonException.Message + BadHttpRequestException.Message
before surfacing them in ValidationProblemDetails.detail —
F-AZ795-1 / F-AZ795-2 in the cycle-7 security audit.
3. AZ-795 child-task sweep across the remaining public endpoints
(request / route / upload / latlon) using AZ-796 as the
reference pattern; 2-3 SP per endpoint, spread across cycles
8-10.
LESSONS.md ring buffer updated with 3 cycle-7 entries (process /
testing / architecture); 3 oldest cycle-2 entries dropped to
maintain the 15-entry buffer.
State pointer advanced to cycle 8 step 9 (New Task) — Re-Entry
After Completion per autodev existing-code flow.
Co-authored-by: Cursor <cursoragent@cursor.com>
Single-task cycle delivering AZ-505 (3 SP); 1 batch, PASS verdict
after a single auto-fix round (ComputeLocationHash duplication
consolidated into Uuidv5.LocationHashForTile). Step 14 Security
Audit skipped; Step 15 Performance Test PASS (8/8, exit 0) and
closes the cycle-3 perf-harness leftover that carried across
cycles 3-5.
Top 3 lessons appended to LESSONS.md ring buffer:
- Kestrel Http1AndHttp2 requires TLS for ALPN; spec-time decision
- Dapper-bypassing test paths own the Npgsql type contract
- Test fixtures naming specific schema artifacts need migration awareness
Cycle 7 opens at Step 9 (New Task).
Co-authored-by: Cursor <cursoragent@cursor.com>
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>
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>
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>
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>