Files
ui/_docs/06_metrics/retro_2026-05-13_cycle3.md
Oleksandr Bezdieniezhnykh eef3bdf7db [AZ-509][AZ-510][AZ-511] Cycle 3 closure: deploy + retro + state
Steps 16 (Deploy) and 17 (Retrospective) outputs for cycle 3.

- 03_implementation/deploy_cycle3_report.md — ui/ dev pushed
  (15838c5..09449bd, 5 commits); stage/prod cutover deferred
  per push-scope gate option A.
- 06_metrics/retro_2026-05-13_cycle3.md — cycle 3 retro: 6/9
  pts shipped (AZ-510, AZ-511); AZ-512 deferred to backlog
  at cross-workspace prereq gate (AZ-513 filed on admin/).
- 06_metrics/structure_2026-05-13.md — structural snapshot
  referenced by retro.
- LESSONS.md — appended 3 cycle-3 lessons (process x2,
  architecture x1).
- _autodev_state.md — cycle 3 closed; cycle 4 Step 9 not
  started.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-13 04:15:37 +03:00

203 lines
18 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Retrospective — 2026-05-13 (Phase B Cycle 3)
**Mode**: cycle-end (autodev existing-code Step 17)
**Scope**: Phase B, cycle 3 (`state.cycle = 3`)
**Epic**: AZ-509 (UI workspace cycle 3 — Auth bootstrap fix + classColors carve-out + admin edit)
**Cycle duration**: 3 batches over 1 working day (2026-05-13)
**Previous retro**: `_docs/06_metrics/retro_2026-05-12_cycle2.md` (cycle 2)
## Implementation Summary
| Metric | Value | Δ vs cycle 2 |
|--------|-------|--------------|
| Tasks attempted | 3 (AZ-510, AZ-511, AZ-512) | +1 |
| Tasks delivered | 2 (AZ-510, AZ-511) | 0 |
| Tasks deferred at spec gate | 1 (AZ-512 — cross-workspace prereq) | +1 (new pattern) |
| Total batches | 3 (batch 13, 14, 15) | +1 |
| Total complexity points planned | 9 (3+3+3) | 2 |
| Total complexity points delivered | 6 (3+3) | 5 (cycle 2 shipped 11) |
| Avg tasks per batch | 1 | 1 |
| Avg complexity per (completed) batch | 3 | 2.5 |
| Source files mutated | ~37 production + test (AZ-510 ~25, AZ-511 ~12, AZ-512 0) + 9 docs | n/a (different shape) |
Sources: `batch_13_cycle3_report.md`, `batch_14_cycle3_report.md`, `batch_15_cycle3_report.md`, `implementation_report_auth_classcolors_cycle3.md`, `implementation_completeness_cycle3_report.md`, `deploy_cycle3_report.md`, `security_report_cycle3_delta.md`.
## Quality Metrics
### Code Review Results
| Verdict | Count | Percentage | Δ vs cycle 2 |
|---------|-------|-----------|--------------|
| PASS | 2 (batches 13, 14) | 67 % | +2 |
| PASS_WITH_WARNINGS | 0 | 0 % | 1 |
| FAIL | 0 | 0 % | 0 |
| (no formal review — deferred at gate) | 1 (batch 15) | 33 % | n/a |
Note: batch 15 (AZ-512) hit a spec-defined Cross-Workspace Verification BLOCKING gate before implementation began. No source code was written, no review fired. The "no review" row is **not** a process gap — it is the spec working correctly.
### Findings by Severity (code review only)
| Severity | Count | Δ vs cycle 2 |
|----------|-------|--------------|
| Critical | 0 | 0 |
| High | 0 | 0 |
| Medium | 0 | 0 |
| Low | 0 | **1** ✓ (cycle 2's pre-existing trim-trailing-slash F1 was not re-flagged because cycle 3 did not touch the affected files) |
### Findings by Category (code review)
| Category | Count | Top Files |
|----------|-------|-----------|
| Bug | 0 | — |
| Spec-Gap | 0 | — |
| Security | 0 (in code review; security audit fires separately — see below) | — |
| Performance | 0 | — |
| Maintainability | 0 | — |
| Style | 0 | — |
| Scope | 0 | — |
### Security-Audit Findings (Step 14 — cycle 3 delta against cycle 2 baseline)
12 carried + 1 new = 13 total. Cycle 3 net delta:
| Status change | Count | Notable IDs |
|---------------|-------|-------------|
| Closed (HIGH → resolved) | 2 | F-DEP-1 (Vite/PostCSS CVEs — closed by cycle-2-tail `bun update`), OWASP A07 cold-load gap (closed by AZ-510) |
| Strengthened (defense-in-depth) | 1 | STC-ARCH-01 exemption removed (closed by AZ-511) |
| Newly introduced (LOW) | 1 | F-SAST-CY3-1 — `__resetBootstrapInflightForTests` exposed via `src/auth` barrel (AZ-510) |
| Carried forward unchanged (HIGH) | 1 | F-SAST-1 (Google key in `mission-planner/` git history; production exposure NONE — see cycle 2 leftover L-AZ-501-GOOGLE-REVOKE) |
| Carried forward unchanged (MEDIUM) | 7 | F-SAST-2/3, F-INF-1..4 (infra hardening backlog) |
**Security verdict trajectory**: cycle 2 verdict FAIL → cycle 3 verdict **PASS_WITH_WARNINGS** (driver: all HIGH findings closed; one LOW hygiene item introduced; one HIGH carried at git-history layer with NONE production exposure).
OWASP A06 (Vulnerable & Outdated Components): FAIL → **PASS**.
OWASP A07 (Identification & Authentication Failures): PASS_WITH_KNOWN → **PASS**.
## Structural Metrics
Source: `_docs/06_metrics/structure_2026-05-13.md` (this cycle), compared against `structure_2026-05-12.md` (cycle 1 close — cycle 2 introduced no structural changes).
| Metric | Cycle 1 close | Cycle 2 close | Cycle 3 close | Δ vs cycle 2 |
|--------|--------------|--------------|--------------|--------------|
| Component count | 12 | 12 | 12 | 0 |
| Public-API barrels | 11 / 11 (100 %) | 11 / 11 (100 %) | 11 / 11 (100 %) | 0 |
| STC-ARCH-01 carve-out exemptions | 1 (`classColors`) | 1 | **0** | **1** ✓ |
| Commit-time static gates | 31 / 31 PASS | 33 / 33 PASS | 33 / 33 PASS | 0 (STC-ARCH-01 *strengthened*, no new gates added) |
| Architecture cycles | 0 | 0 | 0 | 0 |
| Architecture findings open (baseline F1F9) | 7 of 9 | 7 of 9 | **6 of 9** | **1** ✓ (F3 closed) |
| Newly introduced architecture violations | 0 | 0 | 0 | 0 |
| Net architecture delta this cycle | 2 | 0 | **1** | continued improvement |
| Wire-contract assertions (`endpoints.test.ts`) | 36 | 36 | **37** | +1 (`endpoints.admin.usersMe`) |
| Fast-profile suite | 209 PASS / 13 SKIP / 0 FAIL | 229 PASS / 13 SKIP / 0 FAIL | **231 PASS / 13 SKIP / 0 FAIL** | +2 PASS |
| Bundle (gzipped initial JS) | not measured | 290 465 B | 290 575 B | +110 B (+0.04 %; ~14 % budget) |
### Auto-lesson triggers (per skill Step 1)
- Net Architecture delta > 0? **No** — delta is 1 (improvement). No `architecture` regression lesson required.
- Structural metric regression > 20 %? **No** — every structural metric held or improved.
- Contract coverage % decreased? **No** — wire-contract assertions +1 (37 vs 36).
- New finding category emerged? **No** — security audit ran in delta mode against the cycle 2 baseline; categories are stable.
## Efficiency
| Metric | Value | Δ vs cycle 2 |
|--------|-------|--------------|
| Blocked tasks (cycle-internal) | 0 | 0 |
| Tasks deferred to backlog at spec gate | 1 (AZ-512) | +1 (new pattern) |
| Cross-workspace prerequisite tickets filed | 1 (AZ-513 on `admin/`) | +1 (new pattern) |
| Pre-existing bugs surfaced as side observations | 1 (`AdminPage.tsx` add+delete buttons broken end-to-end against live admin/) | +1 |
| Tasks pending external user action (cycle-3 close) | **7** | +4 vs cycle 2's 3 |
| Tasks requiring fixes after review | 0 | 0 |
| Batch with most findings | none — 0 findings cycle-wide | n/a |
| Auto-fix loops invoked | 0 | 0 |
| Stuck-agent incidents | 0 | 0 |
| Unplanned implementation-time test stabilization loops | 4 in batch 13 (AZ-510 module-scoped state ripple) | +4 (new pattern) |
### Blocker Analysis
| Blocker Type | Count | Prevention |
|--------------|-------|-----------|
| Spec-defined cross-workspace BLOCKING gate (AZ-512) | 1 | Working as intended; the spec design (Cross-Workspace Verification gate) is the prevention. Codify as a reusable task spec template — see Improvement Action #1. |
| Cycle-2 manual third-party action (key revocation) | 2 (carry; not actioned this cycle) | Action #1 from cycle 2 retro still valid; user-action backlog grew rather than drained. See Improvement Action #3. |
| Cycle-2 cross-workspace deploy gate (satellite-provider) | 1 (carry; not actioned this cycle) | Same as above. |
| Cycle-3 deploy push deferred (stage / main / admin/ dev) | 3 (new) | User chose option A (real cutover) but option A in push-scope (ui/ dev only); intentional, but adds to the backlog. |
### User-action backlog at cycle close (NEW METRIC — see Improvement Action #3)
| Category | Count | Items |
|----------|-------|-------|
| Manual third-party console action | 2 | L-AZ-499-OWM-REVOKE, L-AZ-501-GOOGLE-REVOKE (carry from cycle 2) |
| Cross-workspace deploy gate | 1 | L-AZ-498-DEPLOY (carry from cycle 2) |
| Cross-workspace prerequisite ticket awaiting sibling-team work | 1 | AZ-513 implementation on `admin/` (new this cycle; blocks AZ-512 in `_docs/02_tasks/backlog/`) |
| Cycle-3 deploy push pending | 3 | D-CY3-STAGE, D-CY3-MAIN, D-CY3-ADMIN-PUSH (new this cycle) |
| **Total** | **7** | (cycle 1 close: 0 → cycle 2 close: 3 → cycle 3 close: 7) |
This metric is monotonically growing across cycles. The growth is **not** a process regression — every item is a deliberate conservative-path choice (file prereq ticket vs. invent workaround; defer prod cutover vs. push without satellite-provider gate; etc.) — but the trajectory means the cost of those choices accumulates without an offsetting drain mechanism.
### User-decision points (cycle 3 only)
- AZ-512 BLOCKING gate (Cross-Workspace Verification): user **skipped** the prompt → autodev defaulted to **Option A** (file prereq ticket on admin/, pause AZ-512). Spec-aligned, conservative, reversible.
- Cycle-3 deploy gate (real cutover vs plan-only): user chose **A** (real cutover) — first time across cycles 1-3 the user chose anything other than plan-only.
- Cycle-3 push-scope sub-gate: user chose **A** (ui/ dev only). Stage/main and admin/ dev push deferred.
- Step 14 verdict (PASS_WITH_WARNINGS): no remediation gate fired (only LOW finding); auto-chained.
- Step 15 (Performance Test): no separate report produced; static perf check confirmed green at deploy time (290 575 B / 14 % of budget).
## Trend Comparison
| Trend | Cycle 1 | Cycle 2 | Cycle 3 | Direction |
|-------|---------|---------|---------|-----------|
| Code review pass rate (formally-reviewed batches) | 100 % | 50 % (1 PASS_WITH_WARNINGS, 1 no-review sub-step) | **100 %** (2/2 reviewed batches PASS) | ⬆ recovered to cycle-1 baseline |
| Test count (cumulative this cycle delta) | +46 | +20 | +2 | declining; cycle 3 was deeper-fix-narrower-surface |
| Static gate count | +2 | +2 | 0 (STC-ARCH-01 strengthened, no new gates) | held |
| Architecture findings open (baseline) | 7 (2) | 7 (0) | **6 (1)** | ⬆ resumed monotonic decrease |
| STC-ARCH-01 exemptions | 1 | 1 | **0** | first cycle to reach zero |
| Wire-contract assertions | 36 | 36 | **37** (+1) | first growth since cycle 1 |
| Pending USER actions at cycle close | 0 | 3 | **7** | ⬆ ⬆ — accumulating |
| Tasks deferred to backlog at spec gate | 0 | 0 | **1** (AZ-512) | new pattern (working as designed) |
The cycle 3 user-action backlog growth is a **structural side-effect of running spec-defined BLOCKING gates correctly**, not a process regression. AZ-512's gate caught a cross-workspace dependency that would otherwise have shipped a UI form against a 404 endpoint. The cost is one new entry in the backlog; the alternative was a production-broken affordance.
## Top 3 Improvement Actions
1. **Codify "Cross-Workspace Verification BLOCKING gate" as a reusable task spec template**.
AZ-512's spec is the canonical example: pre-implementation gate that requires the implementer to verify a sibling-workspace endpoint exists, with a spec invariant ("Do not invent a workaround that bypasses the missing endpoint") and a fallback-A priority (file prereq ticket on the sibling workspace). Without that gate, batch 15 would have shipped a UI affordance against a 404 endpoint. Future tasks that touch UI ↔ admin / UI ↔ satellite-provider / UI ↔ annotations-service boundaries should always include this gate.
- Impact: high — directly addresses the recurring cross-workspace coordination cost; prevents a class of "ships visibly broken in production" bugs that the AZ-512 / `AdminPage.tsx` add+delete side observation showed already exists in pre-AZ-512 code.
- Effort: low — add `_docs/02_tasks/_templates/cross_workspace_dependency.md` with the gate scaffold (verify-step + spec invariant + 3-option fallback ladder) and reference from `.cursor/skills/new-task/SKILL.md` "Task Type Detection" section.
2. **Standardize a "module-scoped state introduction" task template / batch checklist**.
AZ-510's `bootstrapInflight` module-scoped promise was the right architectural choice for StrictMode-safe bootstrap dedupe but cost ~4 separate fix loops in test setup during implementation: (a) `ProtectedRoute.test.tsx` hangs from leaked never-resolving promise → fix via test-only reset hook; (b) STC-ARCH-01 violation when `tests/setup.ts` deep-imported the helper → fix via barrel re-export; (c) widespread test crashes from default MSW `/users/me` handler missing `permissions` field → fix via defensive `hasPermission` + handler seeding; (d) bulk handler swap in 15 test files (`http.get('/api/admin/auth/refresh')``http.post`) needed because POST production behavior bypassed the existing GET overrides. Each was straightforward in isolation but compounded the batch's wall-clock cost. A pre-implementation checklist would have caught (a)+(b) before code was written.
- Impact: medium — directly reduces ripple-cost of architecturally-correct module-scoped state introductions; the pattern recurs anywhere React 18 StrictMode dedupe is needed.
- Effort: low — add `_docs/02_tasks/_templates/module_scoped_state_introduction.md` (NEW) with the 4-item checklist (reset-hook plan, afterEach audit, default-fixture invariant check, mock ripple plan); cite AZ-510 as canonical example.
3. **Track "user-action backlog at cycle close" as a first-class retrospective metric**.
Backlog grew 0 → 3 → 7 across cycles 1-3. Each item is a deliberate conservative-path choice (file prereq ticket; defer prod cutover; defer key revocation), but the monotonic accumulation is a process-shape signal. Without a per-cycle measurement and a draining mechanism, the backlog will keep growing and the "cost of conservative defaults" stays invisible. The drain mechanism could be a "Step 0 leftover sweep" in each cycle's first invocation (already partially defined in `tracker.mdc` Leftovers Mechanism), but today the autodev does not measure whether the sweep actually moved the backlog count down.
- Impact: medium — surfaces accumulating debt that today is only visible by reading the leftovers folder. Makes user-action items first-class deliverables of the process, not silent drag.
- Effort: low — extend `.cursor/skills/retrospective/SKILL.md` Step 1 metric collection with a "user-action backlog" subsection (categories: manual third-party / cross-workspace prereq / cross-workspace deploy / push pending), and add to the retrospective-report template.
## Suggested Rule / Skill Updates
| File | Change | Rationale |
|------|--------|-----------|
| `_docs/02_tasks/_templates/cross_workspace_dependency.md` | NEW file. Pre-implementation BLOCKING gate (verify the prerequisite exists in `<sibling/>` source); spec invariant ("Do not invent a workaround that bypasses the missing endpoint"); fallback-A priority (file prereq ticket on sibling, pause until lands); options B/C/D for the user; AZ-512 ↔ AZ-513 as canonical example. | §Top 3 Improvement Action #1. |
| `.cursor/skills/new-task/SKILL.md` (Task Type Detection) | Add "cross-workspace-dependent" trigger phrase set ("touches `admin/`", "depends on `satellite-provider`", "needs new endpoint in `<sibling>`", "calls `/api/admin/<new>`") that suggests the new template. | §Top 3 Improvement Action #1 enablement. |
| `_docs/02_tasks/_templates/module_scoped_state_introduction.md` | NEW file. 4-item pre-implementation checklist: (a) plan test-only reset hook in same batch; (b) audit `afterEach` hooks in `tests/setup.ts`; (c) check default test fixtures still satisfy invariants if helpers consume them; (d) plan ripple swaps in handler mocks (HTTP method / wire shape changes). Cite AZ-510 as canonical example. | §Top 3 Improvement Action #2. |
| `.cursor/skills/retrospective/SKILL.md` (Step 1 metrics) | Add **"User-action backlog at cycle close"** metric: count of unresolved leftover items, broken down by category (manual third-party / cross-workspace prereq / cross-workspace deploy / push pending). Also add cross-workspace prerequisite tickets count and pre-existing bugs surfaced as side observations. | §Top 3 Improvement Action #3. |
| `.cursor/skills/retrospective/templates/retrospective-report.md` | Add a "User-action backlog at cycle close" subsection under Efficiency with the same category breakdown; include trend across previous cycles. | §Top 3 Improvement Action #3. |
| `_docs/LESSONS.md` (top) | Append the 3 lessons in §LESSONS Append below; trim to ≤ 15 entries. | Skill Step 4. |
## Notes — Step 16 outcome
Step 16 (Deploy) ran in **real-cutover mode (option A)** for the first time across cycles 1-3. Push scope was ui/ `dev` only (5 commits, fast-forward `15838c5..09449bd`). Stage / main / admin/ `dev` pushes were deferred at the push-scope sub-gate (user chose option A — ui/ dev only).
- Devices will not auto-pull cycle-3 changes until `dev → stage → main` completes (D-CY3-STAGE, D-CY3-MAIN).
- AZ-513 task spec sits locally on `admin/` `dev` — admin/ team cannot pick it up until D-CY3-ADMIN-PUSH lands.
- No Dockerfile / `.woodpecker/` / nginx / env changes in cycle 3, so no deployment-doc rewrites this cycle (verified via `git diff --stat 70fb452^..HEAD` on those paths — empty).
These four items add to the user-action backlog; see §Efficiency → User-action backlog table.
## LESSONS Append (top 3, single-sentence, tagged)
1. **[process]** When a task spec defines a Cross-Workspace Verification BLOCKING gate and the user skips the choice prompt, the autodev MUST default to the most conservative spec-aligned option (Option A: file prerequisite ticket on the sibling workspace, park the task in `backlog/`) — never invent a workaround that bypasses the missing dependency, never silently ship a UI affordance against a non-existent endpoint, and always preserve the user's ability to override at the next invocation, exactly as AZ-512 → AZ-513 demonstrated.
2. **[architecture]** Introducing a module-scoped state guard in production source (e.g., a top-level `let bootstrapInflight: Promise | null = null` for React 18 StrictMode dedupe) requires the same batch to ship 4 coupled changes — (a) a test-only reset hook re-exported via the public barrel (STC-ARCH-01 compliance), (b) an `afterEach` reset in `tests/setup.ts`, (c) a defensive default-fixture invariant check (e.g., MSW handler must seed required nullable fields the helper consumes), (d) a planned ripple swap in handler mocks for any HTTP method or wire-shape change — skipping any one costs a separate test-stabilization loop, as AZ-510's ~4-attempt arc demonstrated.
3. **[process]** Track "user-action backlog at cycle close" as a first-class retrospective metric (count of leftover items broken down by manual-third-party / cross-workspace-prerequisite / cross-workspace-deploy / push-pending categories) — backlog grew monotonically 0 → 3 → 7 across cycles 1-3 and that accumulation is a process-shape signal, not noise; surfacing it makes the cost of conservative-path defaults visible per cycle and creates pressure for an explicit drain mechanism (Step 0 sweep that actually closes items, not just notices them).