diff --git a/cc-ci-plan/plan-recipe-report-skill.md b/cc-ci-plan/plan-recipe-report-skill.md new file mode 100644 index 0000000..1bddd08 --- /dev/null +++ b/cc-ci-plan/plan-recipe-report-skill.md @@ -0,0 +1,75 @@ +# Plan — `/recipe-report` skill + report.ci.commoninternet.net + +**Status:** PROPOSED. **Created:** 2026-06-02. +**Goal:** after the weekly `/upgrade-all`, generate a public HTML **"Recipe Report"** that reviews how +the upgrade went and the state of every recipe + open PR — served at **report.ci.commoninternet.net**, +one page per week, with a home-page index of all reports. + +## Why it's cheap to build +The serving model already exists (dashboard): a Nix-built image → Swarm service → traefik +`Host(...)` + wildcard TLS, bind-mounting a host dir read-only. We mirror it for reports. +- **DNS:** `report.ci.commoninternet.net` already resolves (wildcard `*.ci.commoninternet.net` → the + host) — **no operator DNS step.** +- **TLS:** the same wildcard cert (`/var/lib/ci-certs/live/`) that serves ci./drone./backups. covers + `report.ci.*` — **no cert step** (confirm at deploy). +- **Data:** `/upgrade-all` already writes `/srv/cc-ci/.cc-ci-logs/upgrades/upgrade-all-.md`; open + PRs + CI verdicts come from the Gitea/Drone APIs (creds in `.testenv`). + +## A. Serving infra — new `nix/modules/reports.nix` (cc-ci product repo) +A tiny static-file server mirroring `dashboard.nix`: +- Image: `nginx:alpine` (or reuse the dashboard's Python `http.server`), content-hash tag, deployed by a + `deploy-reports.service` reconcile oneshot (same pattern as dashboard/bridge). +- Bind-mount **`/var/lib/cc-ci-reports`** (read-only) as the web root. +- traefik labels: `Host(`report.ci.commoninternet.net`)`, entrypoint `web-secure`, `tls=true`. +- Web root layout: `index.html` + `week-.html` (one per report). **Public, unauthenticated.** +- *(Lighter alternative: add a second traefik router `Host(report.ci…)` → the existing `ccci-dashboard` + service and serve `/var/lib/cc-ci-reports` from `dashboard.py`. Recommend the separate server for clean + decoupling.)* + +## B. The skill — `.claude/skills/recipe-report/` (orchestrator repo) +A SKILL.md (LLM-driven review + HTML generation) + a helper script for the deterministic survey/scaffold. +- **Runs:** right after the weekly `/upgrade-all` completes. **Recommended:** the upgrader invokes + `/recipe-report` as its final step (it has the fresh run context + the dated summary). *(Alt: a separate + `cc-ci-recipe-report` systemd service `After=` the upgrade timer.)* +- **Inputs:** the dated `upgrade-all-.md` summary; open PRs per recipe (Gitea API); each recipe's + current vs latest version + CI verdict (Drone); the **previous** week's report (to note "new since last + week"). Runs from the orchestrator; writes the HTML to `cc-ci:/var/lib/cc-ci-reports` over ssh. +- **Review/judgment (the skill's job):** summarize the run (green / stale-test / failed / skipped counts, + notable regressions), then **classify** every item into: + - **Needs attention** — PRs ready to merge (GREEN), and errors/failures to investigate. + - **Routine** — minor bumps, stale-test (needs `--with-tests`), up-to-date / skipped-by-design. + +## C. HTML output (per-week page + index) +Each `week-.html`: +- **Title:** "The Recipe Report" · **Subtitle:** "Week of ". +- **① Needs attention** (top, prominent): important PRs to merge + errors to look into — short prose per + item with the PR/build link. +- **② Routine** (below): the less-important items (minor upgrades, stale-test, skipped) — compact. +- **③ Comprehensive table** (bottom): every recipe → `current → target` · upgrade status · CI verdict · + open PR (link) · notes. +- **Footer:** generated timestamp, link to the live dashboard (ci.commoninternet.net), link back to the index. + +`index.html` (home): "The Recipe Report" + a reverse-chronological list of all weekly reports (date + +one-line headline), each linking to its page. The skill **regenerates the index** each run. + +Styling: self-contained, inline CSS, clean + mobile-friendly, no JS (fully static). + +## D. Public-safety (unauthenticated page) +- Include only public-safe data: recipe names, version bumps, PR titles + links, CI verdicts, concise + error summaries. **No secrets, tokens, internal IPs, or raw logs** (summarize — never dump logs that + could contain generated app secrets; the build already redacts, but the report must not re-introduce). +- PR links point to the private `git.autonomic.zone` mirror — viewers need access to follow them; the + report's prose must stand on its own. + +## E. Definition of Done +1. `reports.nix` deployed; `https://report.ci.commoninternet.net/` serves the index over TLS. +2. `/recipe-report` skill generates `week-.html` (3 sections + full table) and regenerates `index.html`. +3. Wired to run automatically after the weekly `/upgrade-all`; produces a report end-to-end on the next run. +4. Page is public-safe (no secrets); renders cleanly on desktop + mobile. +5. NOT merged anything; the report only *reports* (read-only on PRs/CI). + +## F. Open decisions +- Trigger: upgrader final step (recommended) vs separate timer. +- Static server: `nginx:alpine` new stack (recommended) vs extend the dashboard. +- Embed the dashboard's per-run summary-card images in the report, or just link them? +- Retention: keep all weekly reports indefinitely (they're tiny static HTML) — assumed yes.