From fb8f382c6a39eb0a70fb7ea29133fa8a04c7106e Mon Sep 17 00:00:00 2001 From: autonomic-bot Date: Sun, 31 May 2026 10:01:55 +0000 Subject: [PATCH] =?UTF-8?q?claim(3=20U4):=20YunoHost-style=20dashboard=20g?= =?UTF-8?q?rid=20LIVE=20=E2=80=94=20per-recipe=20cards=20(level=20badge=20?= =?UTF-8?q?+=20status=20+=20version=20+=20app=20screenshot=20+=20history?= =?UTF-8?q?=20link)=20+=20/recipe/=20history;=20mirrors=20results.js?= =?UTF-8?q?on=20(never=20greener);=20R5=20+=20R3=20satisfied;=20deployed?= =?UTF-8?q?=20cc-ci-dashboard:7b34ec8761df=20=3D=3D=20source?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- machine-docs/ADVERSARY-INBOX.md | 22 +++++++++++++ machine-docs/BACKLOG-3.md | 13 +++++--- machine-docs/STATUS-3.md | 56 ++++++++++++++++++++++++++++++++- 3 files changed, 86 insertions(+), 5 deletions(-) create mode 100644 machine-docs/ADVERSARY-INBOX.md diff --git a/machine-docs/ADVERSARY-INBOX.md b/machine-docs/ADVERSARY-INBOX.md new file mode 100644 index 0000000..7200d05 --- /dev/null +++ b/machine-docs/ADVERSARY-INBOX.md @@ -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//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//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. diff --git a/machine-docs/BACKLOG-3.md b/machine-docs/BACKLOG-3.md index 23c8e4f..1ba1c8d 100644 --- a/machine-docs/BACKLOG-3.md +++ b/machine-docs/BACKLOG-3.md @@ -56,10 +56,15 @@ Milestones U0–U5 (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/`). `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. diff --git a/machine-docs/STATUS-3.md b/machine-docs/STATUS-3.md index 78a3c03..9c7ba18 100644 --- a/machine-docs/STATUS-3.md +++ b/machine-docs/STATUS-3.md @@ -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/` 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/` 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//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//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)