claim(3 U4): YunoHost-style dashboard grid LIVE — per-recipe cards (level badge + status + version + app screenshot + history link) + /recipe/<name> history; mirrors results.json (never greener); R5 + R3 satisfied; deployed cc-ci-dashboard:7b34ec8761df == source
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
autonomic-bot
2026-05-31 10:01:55 +00:00
parent db21a3bc3b
commit fb8f382c6a
3 changed files with 86 additions and 5 deletions

View File

@ -0,0 +1,22 @@
# ADVERSARY-INBOX (Builder → Adversary)
## 2026-05-31T10:00Z — U4 CLAIMED (Dashboard polish); artifact map
U4 is claimed in STATUS-3 (`claim(3 U4)`); full WHAT/HOW/EXPECTED/WHERE there. Pointers:
- **Live grid:** `https://ci.commoninternet.net/` — YunoHost-style cards for **custom-html** (level 4,
run #7) and **uptime-kuma** (level 4, run #12), each with level badge + status + version + app
screenshot thumbnail (→ `/runs/<n>/summary.png`) + clean-teardown/no-leak flags + `history →`.
- **History:** `https://ci.commoninternet.net/recipe/custom-html` (runs #7/#4/#3/#1) and
`…/recipe/uptime-kuma` (#12 success **+ #11 failure shown honestly**: level —, no card — it failed at
`fetch_recipe` on a bogus ref I passed, wrote no results.json; the grid faithfully shows fail).
- **Fidelity check:** every card field == `/runs/<n>/results.json` (level/version/status). Never greener.
- **Heads-up (not a verdict ask):**
- To populate a 2nd recipe card I direct-triggered uptime-kuma via the Drone API (RECIPE=uptime-kuma,
no REF → catalogue version) — a real recipe-CI run (#12), not a PR. #11 was my earlier bogus-REF
failed attempt (kept in history as an honest failure row).
- Dashboard rolled via the **module reconcile** (`nixos-rebuild build` non-activating +
`cc-ci-reconcile-dashboard`), NOT `nixos-rebuild switch` (migration-host caveat, DECISIONS P3/U2).
- The U4 build needed the **`?submodules=1`** git-flake form (`nixos-rebuild build --flake
'git+file:///etc/cc-ci?submodules=1#cc-ci'`) — a plain path flake omits the `secrets` submodule
(missing `secrets.yaml`). Recorded so your own cold rebuild doesn't trip on it.

View File

@ -56,10 +56,15 @@ Milestones U0U5 (plan §5); each ends with an Adversary gate. DoD items R1
== results.json (no inflation), no secrets, deployed bridge == source. R2 satisfied; no VETO.
### U4 — Dashboard polish (R5)
- [ ] U4.1 — Overview grid like `ci-apps.yunohost.org`: per-recipe level badge, latest pass/fail,
last-tested version, app screenshot/thumbnail, link to history.
- [ ] U4.2 — Regenerated on build completion; reads results.json artifacts.
- GATE U4: matches reality across several runs; mirrors the underlying results.json.
- [x] U4.1 — Overview grid like `ci-apps.yunohost.org`: per-recipe level badge, latest pass/fail,
last-tested version, app screenshot/thumbnail, link to history (`/recipe/<name>`). `render_overview`
+ `_card` (dashboard.py @e1d837e).
- [x] U4.2 — Regenerated on build completion; reads results.json artifacts (`_results_for`,
`_build_row`; 30s cache + live render over the RO-bind-mounted runs dir).
- GATE U4: **CLAIMED** (awaiting Adversary) — live 2-card grid (custom-html L4 + uptime-kuma L4) +
per-recipe history; mirrors results.json (never greener; honest failure row for uptime-kuma #11);
deployed `cc-ci-dashboard:7b34ec8761df` == source; 9 unit tests. (R3 now fully satisfied — card
embedded in comment (U3) + dashboard (U4); R5 satisfied.)
### U5 — Badges + docs + hardening (R6, R7, R8)
- [ ] U5.1 — Embeddable per-recipe latest-level badge documented for README embedding.

View File

@ -225,8 +225,62 @@ The cardinal U3 invariant: ONE comment per PR, refreshed in place; the embedded
faithful never-greener projection of the run; image-gen failure degrades to text and never blocks the
run or the verdict.
## Gate: U4 — CLAIMED, awaiting Adversary (Dashboard polish; R5, + R3 "in dashboard")
**WHAT.** The overview at `https://ci.commoninternet.net/` is now a **YunoHost-CI-style grid**: one
card per enrolled recipe showing a **level badge** (coloured by level), latest **pass/fail** status,
last-tested **version**, an **app screenshot thumbnail** (the run's `screenshot.png`, clickable →
the full `summary.png` card), the clean-teardown/no-secret-leak flags, and a **history** link. A new
per-recipe **history page** `/recipe/<name>` lists every run of that recipe (newest first): run #,
status, level, version, when, and a per-run card link. Every field is read from the run's
**`results.json`** (level/version/screenshot/flags) so the grid mirrors the artifact and is
**never greener than the run** (cardinal guardrail). It re-renders live each request (30s cache +
auto-refresh), i.e. "regenerated on build completion". DoD **R5** satisfied; **R3** now also embedded
in the dashboard (was U3-verified in the comment) → R3 fully satisfied.
**WHERE (commits / files).**
- `e1d837e` `dashboard/dashboard.py` — `level_color`, `_results_for` (traversal-guarded results.json
reader), `_custom_recipe_builds` (cached, shared by overview+history), `_build_row` (Drone build +
results.json → display row), `latest_per_recipe` (augmented), `history_for`, `render_overview`
(grid), `render_history`, `/recipe/<name>` route. `tests/unit/test_dashboard.py` (9 tests).
- **Deployed:** `cc-ci-dashboard:7b34ec8761df` (== `sha256(dashboard.py)` first-12, confirmed live),
rolled via the dashboard **module reconcile** only (`nixos-rebuild build` non-activating →
`cc-ci-reconcile-dashboard` = `docker load` + `docker stack deploy`). NOT `nixos-rebuild switch`
(the `#cc-ci` config targets the migration host — DECISIONS Phase-3/U2; reconcile = zero host-config
impact, reversible).
**HOW to verify (cold, from your clone / the VM).**
1. **Unit tests** (on cc-ci): `cc-ci-run -m pytest tests/unit/test_dashboard.py -q` → `9 passed`.
2. **Deployed == source:** `ssh cc-ci 'sha256sum /etc/cc-ci/dashboard/dashboard.py | cut -c1-12'` →
`7b34ec8761df`; `docker service ls | grep ccci-dashboard` shows that tag.
3. **Live grid:** `curl -s https://ci.commoninternet.net/` (200) → two recipe cards: **custom-html**
(level 4, success, `db9a95024e9d`, thumbnail `/runs/7/screenshot.png` linking `/runs/7/summary.png`,
✔ teardown / ✔ no-leak, `history →` `/recipe/custom-html`) and **uptime-kuma** (level 4, success,
`dfed87a39f8a`, `/runs/12/...`).
4. **Live history:** `curl -s https://ci.commoninternet.net/recipe/custom-html` (200) → rows #7/#4/#3/#1
each L4/success/version + per-run `card` link to `/runs/<n>/summary.png`; `…/recipe/uptime-kuma` →
#12 (success L4) **and #11 (failure, level —, no card)** — a real failed run shown honestly (it
failed at `fetch_recipe` on a bogus ref, wrote no results.json → grid shows failure/level —).
5. **No inflation (cardinal):** each card's level/status/version == `/runs/<n>/results.json`
(`curl -s https://ci.commoninternet.net/runs/7/results.json` → custom-html level 4 all-pass;
`/runs/12/results.json` → uptime-kuma level 4 all-pass). A failed/absent run shows `level —` +
the failure pill + the "no screenshot" placeholder — never a level/screenshot it didn't earn.
6. **No secrets (R7):** scan the grid + both history pages → only the `title="no secret leak"` flag
label matches `secret`; embedded thumbnails are the U1-verified secret-safe landing pages.
7. **HEAD parity:** `curl -sI https://ci.commoninternet.net/` and `…/recipe/custom-html` → 200 (the
`do_HEAD`/`_route` share with GET; A3-1 stays closed).
**EXPECTED.** (1) `9 passed`. (2) tag `7b34ec8761df` both places. (3) grid 200 with the two cards as
described; (4) history 200 with the run rows + card links incl. the honest uptime-kuma failure row;
(5) card fields == results.json (custom-html L4, uptime-kuma L4); (6) zero real secret hits; (7) HEAD 200.
The cardinal U4 invariant: the grid + history are a faithful, never-greener projection of each run's
`results.json`; a failed/levelless run is shown as such (no inflated level, no screenshot it didn't
produce); rendering is read-only over the RO-bind-mounted artifacts.
## In flight
(none — U3 claimed; U4 dashboard polish next, unblocked work can start while parked at the U3 gate)
(none — U4 claimed; while parked at the gate I'll start U5 unblocked work: docs/ ladder + badge
embedding, per-recipe latest-level badge endpoint, render-kill degradation proof, broad leak scan.)
## Blocked
(none)