Skip to content

Phase 6 — Mid-Review

Date: 2026-05-04 Reviewer: Claude (first-pass), pending user triage Artifact walked: local docker compose --profile fullstack up from a clean clone, against the MVP slice in CLAUDE.md. User pre-walk note: "Flow works, UI needs a makeover but that's deferred." This review accepts the slice itself as PASS and focuses on Phase 6 scope completion + non-slice findings. Framework: per ~/.claude/collaboration-framework.md, Cluster 1 ritual.

Verdict

Partial. Phase 6 cannot close as-stated. The backbone half is delivered to a high bar (6.6 ingest, 6.7 SSRF, 6.9 cache, 6.11 metering, 6.13 release, 6.14 secrets ADR — 6 items, all merged). The UI half — the entire thematic anchor of the phase ("admin panel usable for a self- hoster... no shell access required for common ops") — has not begun. 8 of 14 work items have no issue, no branch, no PR. The climate-lama-ui repo has had zero Phase 6 commits; its last commit is dated 2026-04-26 (Phase 5 closeout).

Two clean exits are available:

  1. Finish the phase as written. Build the admin-panel surface (6.1– 6.5, 6.10, 6.12) and the polling adapter (6.8). Estimated 8 issues, most cross-stack, ~2–3 weeks at the current cadence.
  2. Re-scope and close. Split Phase 6 into "6a — Backbone admin/ops plumbing" (closed today) and "6b — Admin panel UX" (new phase, owns the unbuilt items + the discussion issues #271/#270/#269). Update phase-6-admin-ops.md and plan.md accordingly.

The mid-review's job is to surface the gap, not pick. Recommendation: Option 2, because (a) the backbone work is genuinely complete and shouldn't sit in an "active" phase indefinitely, (b) the unbuilt items share a UI codebase and a role-model question (#271) that wants resolution before any of 6.1–6.5 ships, and (c) the framework's anti- pattern is "front-loaded planning + back-loaded review" — calling the split now is exactly the mid-review correction it was designed for.

Phase 6 work-item status

Source: phase-6-admin-ops.md §Scope; live state from gh issue list --label phase-6.

# Item Status Issue(s)
6.1 Admin panel shell Unbuilt none
6.2 Users + orgs management Unbuilt none (related: #271)
6.3 Datasets surface (/datasets) Unbuilt none
6.4 Audit log (write side + UI) Unbuilt none
6.5 Dataset catalog admin curation Unbuilt none
6.6 Async ingest pipeline Done #293 + A/B/B.1/B.2/B.3/C/D/E (8 sub)
6.7 SSRF + admin download Done #282
6.8 External dataset polling Unbuilt none
6.9 Result cache Done #283 (follow-up #291)
6.10 In-app notifications (bell) Unbuilt none
6.11 Usage metering observability slice Done #284
6.12 Adaptation measures catalog UX Unbuilt none
6.13 Deployment ADR + release pipeline Done #281 (follow-up #287)
6.14 Secrets + config management ADR Done #102 (follow-up #285)

Done: 6 / 14 (43%). All backbone or docs. Unbuilt: 8 / 14 (57%). All UI-bearing or cross-stack.

Findings against the demoable artifact

The framework's six checks, walked against the MVP slice and the admin-gating side-check from CLAUDE.md.

1. Artifact health — PASS

User confirms docker compose --profile fullstack up launches cleanly from a clean clone, all services come up, no console/log errors during the slice walk. No finding.

2. Happy path — PASS

User confirms the slice works end-to-end: login → configure scenario → run impact → see map + summary → save. No finding.

3. Unhappy paths

  • [ENHANCE-NEXT] SDK smoke check is currently red on Ubuntu 24. Already tracked as bug #310 ("teach scripts/demo.py to authenticate so SDK smoke goes green"). The CI fix for the underlying docker compose up flake landed in 5fc916a; the SDK auth piece is still open. Not a slice failure, but a paid-CI-minutes leak. Action: keep #310; do before Phase 6 close (or 6a close).

  • [ENHANCE-NEXT] Result-cache pre-warm beat process is not running in any deployable. Tracked as #291 ("Result cache follow-up: beat process, curated prewarm, hit-rate validation"). The cache itself is correct (verified by integration test in #283); the curated 20- scenario warmup never executes because no celery-beat container exists in docker-compose.yml or in the worker Dockerfile entrypoint. Self-hosters and demo users see a cold cache. Acceptance criterion in §6.9 says "Celery beat pre-warm job runs hand-curated list" — not yet met. Action: keep #291; mark as required for 6.9 to be considered closed.

  • [BACKLOG] No coded error path for "ingest job stuck in running longer than the chord timeout." The state machine in src/climate_lama/worker/ingest/state_machine.py covers happy + cancel + retry; it does not have a watchdog that flips an abandoned chord to failed. The retry policy from #307 covers per-task retries, not whole-chord wedging. Low risk in dev (no real long ingests yet); becomes real when 6.5 + 6.8 actually exercise the pipeline against external sources. File a follow-up issue if 6.5/6.8 are pulled into 6b.

4. UI/UX presentability

User has marked the UI makeover as deferred ([BACKLOG] per the user). This review respects that and does not enumerate cosmetic gaps. Two exceptions where the gap is structural, not cosmetic:

  • [ENHANCE-NOW] Settings → "Organization" tab is a stub. Tracked as discussion #270. With no admin panel landing this phase, Settings is the only UI surface where org-scoped concerns can live; leaving the stub visible in a "demoable" build is misleading. Either resolve the discussion and wire the tab, or hide the tab behind a feature flag until 6.2 ships.

  • [ENHANCE-NOW] "Try the demo →" CTA on the onboarding banner does not load the seeded result. Tracked as #273. Listed in CLAUDE.md MVP "Explicitly out of MVP scope" bucket — but only because the tour itself is excluded. The CTA is visible in the slice walk regardless and broken-CTA-on-first-run is a worse first impression than no CTA. Hide the banner until #273 ships, or fix #273.

5. User-path completeness

  • [CRITICAL] The admin-gating side-check from CLAUDE.md cannot be exercised because no admin pages exist. The MVP slice doc says: "a non-admin hitting an admin-only path gets a sensible 403/redirect; an admin can reach admin pages." There are no admin pages in climate-lama-ui/src/ (no admin/ directory). The backbone has a partial src/climate_lama/api/v1/admin/ (only downloads.py + usage.py from 6.7 + 6.11). The side-check is vacuously "passing" because the surface doesn't exist — that's not a pass, that's untestable. Action: this is the central Phase 6 deliverable; closing the phase without it requires re-scoping (Option 2 above).

  • [ENHANCE-NEXT] No /datasets route in the UI. §6.3 calls for a user-facing Datasets surface even outside admin scope (Catalog + Upload tabs for hazards and exposures). Today, exposures are uploaded only via HazardUploadModal.tsx reached from the scenario wizard — not URL-discoverable. This is reachable-only-by-clicking rather than reachable-only-by-URL, but a "Datasets" top-nav item is what self-hosters expect. Carry into 6b or a focused follow-up.

  • [ENHANCE-NEXT] No /measures route. §6.12. Same shape as /datasets — measures are configurable inside a scenario but there's no catalog browse. Carry into 6b.

6. Promised-but-unbuilt

  • [CRITICAL] 8 of 14 phase items unbuilt (6.1, 6.2, 6.3, 6.4, 6.5, 6.8, 6.10, 6.12). Listed in §"Phase 6 work-item status" above. This is the Phase 6 anti-pattern from the framework: front-loaded planning produced 14 items, the build pipeline shipped what was easiest to parallelize (backbone, single-repo, well-specified), the UI half was structurally harder (cross-stack, role-model dependent on #271, needs design alignment) and got passed over. Action: mid-review's purpose is to catch exactly this. Pick Option 1 (finish) or Option 2 (split + close 6a, open 6b) and update plan.md accordingly.

  • [ENHANCE-NOW] Audit log (6.4) gap is load-bearing for 6.2/6.5/6.7 visibility. The SSRF download work (6.7, shipped) writes to the downloads table but does not write to an audit_log because the audit table doesn't exist yet. When 6.4 lands, the 6.7 task needs a retroactive audit-write; track that explicitly so it isn't missed.

  • [ENHANCE-NEXT] The role-model discussion (#271, "rethink the role model — who is 'admin'?") is a hard prerequisite for 6.1 and 6.2. Building admin pages without resolving who-can-see-them produces rework. If picking Option 2, 6b should open with #271 as item zero.

Open follow-ups discovered during review

These are concrete, have an acceptance check, and are not yet covered by an issue. Per the framework's auto-follow-up rule, they warrant issues if the user accepts the finding.

Tag Finding Suggested action
[CRITICAL] 8 unbuilt phase items; admin side-check untestable Pick Option 1 or 2; update plan.md
[ENHANCE-NOW] Settings → Organization tab stub visible without 6.2 backing Hide behind flag, or close #270 and wire it
[ENHANCE-NOW] Onboarding banner CTA #273 broken in slice walk Hide banner until #273 ships, or land #273
[ENHANCE-NOW] 6.7 download task lacks audit-log write (table doesn't exist yet) Add retroactive audit_log write when 6.4 lands; track as 6.4 sub-item
[ENHANCE-NEXT] SDK smoke red on Ubuntu 24 (bug #310) Resolve #310 before phase close
[ENHANCE-NEXT] Result-cache beat process not deployed (#291) Block 6.9 closure on #291 — beat container in compose
[ENHANCE-NEXT] Role-model discussion #271 blocks 6.1/6.2 Resolve #271 before any admin-shell branch opens
[ENHANCE-NEXT] No /datasets route (§6.3) Carry into 6b
[ENHANCE-NEXT] No /measures route (§6.12) Carry into 6b
[BACKLOG] Watchdog for wedged ingest chords New issue if 6.5/6.8 are pulled into 6b
[BACKLOG] UI makeover (user-deferred) Already deferred; keep deferred
[DROP] (none — no work was found that should be cancelled outright)

Quality of the shipped work (informational, not a finding)

The 6 closed items are well-executed:

  • 6.6 ingest pipeline is correctly chord-shaped, the dynamic-width dispatcher is documented in pipeline.py with a clear header explaining why Celery couldn't statically express it; the state machine is in its own module; the memory-bound test (#297) gates on RSS, not on a smoke-pass. This is exactly the work that was flagged as the highest-risk item in §Risks of the phase doc ("Run /build --review not auto-merge") and it landed clean.
  • 6.7 SSRF ships with allowlist + DNS resolution + redirect tracking
  • integration tests for malicious URLs; ADR was authored (the phase doc reserved ADR-031, the actual ADR landed as ADR-036).
  • 6.13 release pipeline + 6.14 secrets ADR are pure docs/CI items but the release pipeline is wired to GHCR with latest + semver tags and ${CLIMATE_LAMA_TAG} substitution in compose, so self-hosters can pin today.

The phase pattern looks like: things with clear acceptance criteria and single-repo blast radius shipped; things requiring cross-repo coordination + an unresolved role-model question (#271) did not. This is consistent with the diagnosis in ~/.claude/collaboration-framework.md ("the pipeline optimizes for issue throughput, not product progress").

  1. Decide between Option 1 (finish) and Option 2 (split). This is the only [CRITICAL] decision; everything else cascades from it.
  2. If Option 2: open phase-6b (or rename) covering 6.1–6.5, 6.8, 6.10, 6.12. Open issues for each. Open #271 / #270 / #269 resolution as item-zero. Close phase-6 with the items it actually shipped renamed to "Phase 6 — Backbone admin/ops + ingest." Update plan.md status row + Current Phase banner.
  3. Either way: resolve the three [ENHANCE-NOW] findings (Settings org tab stub, onboarding CTA, 6.7 audit-write tracking) before phase close, since they affect what a self-hoster sees on day one.
  4. Either way: resolve open phase-6 follow-ups #287 (release smoke
  5. arm64 + signing), #285 (hosted secrets backend), #291 (cache beat) — all are concrete and have acceptance checks.