Phase 6 — Mid-Review¶
Date: 2026-05-04 Reviewer: Claude (first-pass), pending user triage Artifact walked: local
docker compose --profile fullstack upfrom 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:
- 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.
- 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 upflake 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.ymlor 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
runninglonger than the chord timeout." The state machine insrc/climate_lama/worker/ingest/state_machine.pycovers happy + cancel + retry; it does not have a watchdog that flips an abandoned chord tofailed. 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/(noadmin/directory). The backbone has a partialsrc/climate_lama/api/v1/admin/(onlydownloads.py+usage.pyfrom 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
/datasetsroute 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 viaHazardUploadModal.tsxreached 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
/measuresroute. §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
downloadstable but does not write to anaudit_logbecause 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.pywith 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 --reviewnot 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").
Recommended actions (for user triage)¶
- Decide between Option 1 (finish) and Option 2 (split). This is the only [CRITICAL] decision; everything else cascades from it.
- 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.
- 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.
- Either way: resolve open phase-6 follow-ups #287 (release smoke
- arm64 + signing), #285 (hosted secrets backend), #291 (cache beat) — all are concrete and have acceptance checks.