Files
cc-ci/machine-docs/BACKLOG-3.md
autonomic-bot bdf27289a7 review(3 U2): honesty correction — R7 re-tested with correct signature; file A3-1
(1) Prior U2 R7 'empirical' line used a wrong-signature call to render_card_png/
render_badge_svg, so its TypeError was my test's bug not an R7 violation. Re-ran
correctly: render_card_png(nonexistent html_path) -> None, no raise, 'non-fatal'.
R7 holds (empirical + structural). U2 verdict UNCHANGED, still PASS.
(2) Eyeballed the real served u1-uk-shot summary.png — content matches results.json.
(3) Filed A3-1 [adversary] (HEAD->501 on /runs/, low-sev); Builder added do_HEAD in
9a47aa2 — Adversary to re-test live before closing.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 07:47:18 +00:00

73 lines
5.1 KiB
Markdown
Raw 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.

# Phase 3 — Beautiful YunoHost-style results — BACKLOG
Single source of truth: `/srv/cc-ci/cc-ci-plan/plan-phase3-results-ux.md`.
Milestones U0U5 (plan §5); each ends with an Adversary gate. DoD items R1R8 (plan §2).
## Build backlog
### U0 — Results schema + level (R1)
- [x] U0.1 — Pure `level()` function (harness/level.py): L0L6 gap-caps semantics; 15 unit tests
(incl L4-pass + L2-cap); Adversary fuzz-clean 729/729 (REVIEW-3 @df54693).
- [x] U0.2 — Per-tier pytest emits JUnit XML (parsed by harness/results.py) → results.json per-stage
AND per-test ✔/✘ breakdown.
- [x] U0.3 — `run_recipe_ci.py` writes `results.json` per run (level, cap_reason, rungs, stages,
flags) to the run-scoped artifact dir; assembly wrapped so it NEVER changes the verdict (R7).
- [x] U0.4 — Artifact hosting path decided + recorded in DECISIONS (`${CCCI_RUNS_DIR:-/var/lib/cc-ci-runs}/
<run_id>/`; dashboard serves `/runs/<id>/` in U2/U4 via host bind-mount).
- GATE U0: **PASS** (Adversary REVIEW-3 @18d2bd1, 2026-05-31) — R1 cold-verified, no inflation, no VETO.
### U1 — App screenshot (R4)
- [x] U1.1 — Harness captures a real Playwright screenshot of the deployed app while it is up
(default landing page = secret-safe; recipes opt into a post-login view via a SCREENSHOT meta
hook, never shoot a credentials page). Wired into run_recipe_ci.py post-healthy, pre-teardown.
- [x] U1.2 — Screenshot saved to run artifact dir (`screenshot.png`); results.json `screenshot` field
set ONLY when capture succeeds; degrades gracefully (capture() swallows all errors → None →
field null → run/verdict unaffected, R7).
- GATE U1: **PASS** (Adversary REVIEW-3 @74a6993, 2026-05-31) — R4 cold-verified (real screenshot of
working UI, no secrets, R7-safe wiring, graceful degradation), no VETO.
### U2 — Summary card + badge (R3, R6)
- [x] U2.1 — HTML results-card (recipe+version, level badge, per-stage/per-test ✔/✘ table, embedded
app screenshot) → PNG via Playwright; wired into run_recipe_ci.py, R7-best-effort.
- [x] U2.2 — Per-run SVG level badge (`badge.svg`) generated per run (shields-style, colour by level).
- [x] U2.3 — Card + badge + screenshot + results.json served at stable URLs
`/runs/<id>/{summary.png,badge.svg,screenshot.png,results.json}` (allow-list + traversal-guarded;
runs dir bind-mounted RO into the dashboard swarm service). LIVE over HTTPS, verified.
- GATE U2: **PASS** (Adversary REVIEW-3 @324d84d, 2026-05-31) — card+badge render correct for pass &
fail, served traversal-guarded, never-greener, leak-clean, R7-safe, no VETO. (R3/R6 stay partial
until embedded in PR comment (U3) + dashboard (U4) + per-recipe badge (U5).)
- Adversary polish items to fold in (low-sev, not gates): (a) dashboard `/runs/` HEAD→501 (no do_HEAD)
→ add do_HEAD (also enables a cheap bridge existence-check for U3 fallback); (b) per-recipe
latest-level badge endpoint → U5.
### U3 — YunoHost-style PR comment (R2)
- [ ] U3.1 — Bridge posts a placeholder comment on run start (⏳ + live-logs link).
- [ ] U3.2 — On completion, update the SAME comment to 🌻 + level/status badge + summary card image,
both linking to the run/dashboard. Re-`!testme` refreshes it. Fallback to text on render failure.
- GATE U3: live on a scratch PR — comment shows badge + card + screenshot, updates on re-run, no secrets.
### 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.
### U5 — Badges + docs + hardening (R6, R7, R8)
- [ ] U5.1 — Embeddable per-recipe latest-level badge documented for README embedding.
- [ ] U5.2 — `docs/` explains the level ladder, card/screenshot/badge generation, how to embed a badge.
- [ ] U5.3 — Hardening: render failure degrades to text (R7); secret-scan over published
images/screenshots/comments finds nothing; killing the renderer doesn't affect the verdict.
- GATE U5: Adversary leak-scan clean; graceful degradation proven; flip STATUS-3 to `## DONE`.
## Adversary findings
(Adversary owns this section — Builder does not edit.)
- [ ] **A3-1 [adversary] — `/runs/<id>/<file>` returned 501 to HEAD requests** (low severity, polish).
The dashboard `BaseHTTP` handler implemented only `do_GET`, so `HEAD /runs/u1-uk-shot/summary.png`
→ `HTTP 501 Unsupported method`. GET worked fine (200), so the card/badge/comment/dashboard embeds
all function, but stricter markdown/image clients (and `curl -I`) probe with HEAD first and a stray
501 could make an embed look broken. Repro:
`curl -sSI https://ci.commoninternet.net/runs/u1-uk-shot/summary.png` → `HTTP/2 501`.
Found during U2 cold-verify @2026-05-31T07:48Z; NOT a U2 blocker (U2 PASSED). The Builder added a
`do_HEAD` in `9a47aa2` — **Adversary to re-test the live HEAD response before closing this.**