diff --git a/cc-ci-plan/JOURNAL.md b/cc-ci-plan/JOURNAL.md index 6c71004..17ff509 100644 --- a/cc-ci-plan/JOURNAL.md +++ b/cc-ci-plan/JOURNAL.md @@ -446,3 +446,15 @@ session cc-ci-orchestrator-stale can be killed; recipe-mirrors org still private in rcust M2; DEFERRED carries the re-pin follow-up. Deliverable = green recipe-mirror PR (operator merges) + verified screenshot on the PR runs; DEFERRED entries closed. - .phases-spec now rcust;shot;lvl5;bsky (idx still lvl5); watchdog bounce to load. + +## 2026-06-11 ~12:05 — four more phases queued + DEFERRED housekeeping (operator) +- Queue now: bsky (in progress, idx 3) → dstamp (discourse abra-stamp drift dig) → + mailu (backupbot labels recipe PR) → kuma (uptime-kuma create-a-monitor test) → + drone (gitea-dep enrollment; P0 host /etc/timezone deploy is MINE — nixos-rebuild + switch on cc-ci host with committed 3bde76f, do it before/when phase drone starts or + when STATUS-drone flags BLOCKED). +- DEFERRED.md housekept (cc-ci 823023a): closed plausible-enrollment, discourse-bitnami, + immich-pgdump (PR#2 merge-pending), plausible-Q4.7b (PR#3 merge-pending); re-entered + mailu/drone/kuma/dstamp/bsky with plan pointers. Operator confirmed immich PR#2 + + plausible PR#3 are good — merges pending on operator. +- ORCHESTRATOR ACTION ITEM: deploy /etc/timezone host fix for phase drone P0. diff --git a/cc-ci-plan/plan-phase-drone-enroll.md b/cc-ci-plan/plan-phase-drone-enroll.md new file mode 100644 index 0000000..58230eb --- /dev/null +++ b/cc-ci-plan/plan-phase-drone-enroll.md @@ -0,0 +1,85 @@ +# Phase `drone` — enroll the drone recipe (with gitea SCM dependency) + +**Mission (operator-specified 2026-06-11):** enroll drone — the last §5 recipe — in +cc-ci. Drone is a CI server that requires a git-provider SCM to boot; the viable dep is +gitea. Ship the MAXIMAL SUBSET scoped in Phase 2 (JOURNAL-2 `f86a58a`): drone boots with +gitea SCM — install + upgrade + health + SCM-configured — with the build-creation test +remaining a signed-off sub-deferral. + +State files: `STATUS-drone.md`, `BACKLOG-drone.md`, `REVIEW-drone.md`, +`JOURNAL-drone.md`. DECISIONS.md shared. + +## 0. P0 — HOST PREREQUISITE (orchestrator-owned; verify before any other work) + +gitea binds `/etc/timezone:ro` from the host; NixOS `time.timeZone` creates only +`/etc/localtime`, so the gitea container is REJECTED (`bind source path does not exist`) +— proven on cc-ci. The Nix fix is ALREADY COMMITTED: `3bde76f` +(`environment.etc."timezone" = "UTC\n"` in `nix/hosts/cc-ci/configuration.nix`); it +needs the host-config deploy (sync `/root/cc-ci` + `nixos-rebuild switch +--flake /root/cc-ci#cc-ci`), which the ORCHESTRATOR performs (operator-managed +mechanism; do NOT attempt it from the loops). + +**Builder's first action:** check `test -f /etc/timezone` on the cc-ci host. If absent, +write a BLOCKED note at the top of STATUS-drone.md ("P0 host deploy needed — +orchestrator") and work on P1 prep that needs no gitea deploy (meta scaffolding, test +authoring) until it appears; the orchestrator reads STATUS on its hourly wakes and will +deploy. Verify `/etc/timezone` exists (content `UTC`) before claiming anything gitea +touches. + +## 1. Scope (from the Phase-2 scoping, JOURNAL-2 `f86a58a`) + +1. **gitea as a dependency recipe:** `tests/gitea/recipe_meta.py` enrolling gitea as an + install-time DEPS provider (per the rcust install-time-deps-only system — deps are + installed before the app, fixtures `deps`/`op_state` provide handles). +2. **drone enrollment:** `tests/drone/recipe_meta.py` with `DEPS=["gitea"]`; + install-time steps that create a gitea admin + token + OAuth2 application and wire + `DRONE_GITEA_*` + client secret into drone's install; functional tests proving + health + **SCM-configured** (drone actually talks to gitea, not just an HTTP 200). +3. **Tiers:** install + upgrade (if a previous published version exists — justify + either way) + functional; backup/restore per what the published recipe declares + (structural skip is fine if the recipe has no backup config — document it); lint + (L5) per the now-standard ladder. Screenshot per the shot-phase standard (drone has + a real login/landing UI; default capture expected to work). +4. **Build-creation sub-deferral STAYS deferred:** creating/listing actual CI builds + needs an OAuth user-token + synced repo + .drone.yml + webhook trigger — + disproportionate (the original Phase-2 assessment stands). Ship without it and get + the Adversary's explicit §7.1-style sign-off recorded in REVIEW-drone.md; update + the DEFERRED entry to narrow it to just this gap. + +## 2. Gates + +**M1 — Integration built + green locally.** P0 verified; gitea dep + drone enrollment +implemented; full chosen tier-set green on the harness path with evidence; unit tests +for any new harness-visible surface; no gate weakening anywhere. Adversary cold-verifies +from a clean checkout: deps wiring per the rcust conventions, SCM-configured test has +teeth (a drone WITHOUT gitea wiring must fail it), declared skips justified against the +published recipe. + +**M2 — Proven in real CI.** Full lifecycle green via the drone `!testme`/CI path +(yes — cc-ci's own drone testing a drone recipe deploy; mind resource headroom), +screenshot real + visually verified, level recorded under the de-capped semantics, +canonical/warm enrollment decision documented, DEFERRED entry updated (P0+integration +closed, build-creation gap narrowed + signed off), operator summary in STATUS-drone.md. +Fresh Adversary PASS → `## DONE`. + +## 3. Guardrails (binding) + +- **Host changes are orchestrator/operator-only** (P0 above; same for anything else + host-level you discover — file it in STATUS, don't improvise). +- The deps system rules from rcust apply: install-time deps only, uniform HookCtx + signatures, no new meta keys without registry + docs regeneration. +- Two live deploys (gitea + drone) per run — count them against the ≤2-3 concurrent + budget; coordinate so a second recipe's run isn't racing the same headroom; tear down + BOTH on every exit path, dep included. +- Recipe mirrors: PR only if a recipe defect is found (never push main, never merge). + No secrets in logs/commits (gitea admin password + OAuth client secret are generated + per-run and must stay out of artifacts; the manifest redaction rules apply). +- Commit author `autonomic-bot `; push every + commit. CI host: no python3 on default PATH. + +## 4. Definition of Done + +`/etc/timezone` host fix live; gitea enrolled as a dep provider; drone enrolled and +green (install/upgrade/health/SCM-configured + lint + screenshot) through real CI with +the build-creation gap explicitly signed off and DEFERRED narrowed; levels + records +reconciled; M1+M2 fresh Adversary PASSes. diff --git a/cc-ci-plan/plan-phase-dstamp-discourse-drift.md b/cc-ci-plan/plan-phase-dstamp-discourse-drift.md new file mode 100644 index 0000000..302da68 --- /dev/null +++ b/cc-ci-plan/plan-phase-dstamp-discourse-drift.md @@ -0,0 +1,79 @@ +# Phase `dstamp` — investigate & solve the discourse abra-stamp drift + +**Mission (operator-specified):** since ~2026-06-10, discourse's upgrade tier fails its +HC1 version-stamp check on EVERY run — on both old and new harness at the same ref, so it +is proven harness-neutral env drift, and its mechanism is UNATTRIBUTED. Find the root +cause, fix it properly, restore discourse to its true level in real CI, and determine +whether the same drift silently affects any other recipe's upgrade tier. + +State files: `STATUS-dstamp.md`, `BACKLOG-dstamp.md`, `REVIEW-dstamp.md`, +`JOURNAL-dstamp.md`. DECISIONS.md shared. + +## 1. Known evidence (rcust M2, 2026-06-11 — start here) + +- Baseline: run 184 (2026-06-05) had discourse at L4 with upgrade green. +- Since ~06-10: upgrade-HC1 at ref `7ae7b0f` stamps the **prev-base tag commit + (eb96de94+U)** instead of the expected version — IDENTICAL on old pre-rcust harness + and new main (A/B at same ref + invocation ⇒ rcust exonerated, branch-tip/tag/abra-pin + drift eliminated as causes during M2; what CHANGED in the env between 06-05 and 06-10 + was never attributed). +- Evidence artifacts: `/var/lib/cc-ci-runs/m2p-discourse/`, + `/var/lib/cc-ci-runs/ab-discourse-7ae7b0f-oldmain/`, JOURNAL-rcust 2026-06-11 entries, + machine-docs/DEFERRED.md note. +- Under the new de-capped semantics a failed upgrade rung blocks at L1 — this drift is + actively misrepresenting discourse, which makes it a live quality regression, not + cosmetic. + +## 2. Investigation requirements + +1. **Attribute, don't patch.** Build a timeline of everything stamp-relevant that changed + on the CI host between 06-05 and 06-10: abra binary version/mtime (`abra --version`, + ~/.local/bin or wherever it lives), the recipe catalogue state, `~/.abra/recipes/ + discourse` git state (tags, fetch times, what `git describe`/abra version resolution + sees), the discourse mirror's tags/branches (was a tag re-pointed upstream or in the + mirror?), and the harness's stash/revert dance around `abra recipe lint`/pinned deploy + (`runner/harness/abra.py:109-114`) — plus how upgrade-HC1 derives its EXPECTED stamp. +2. **Reproduce minimally** outside a full run if possible (the abra version-resolution + command against the same checkout) so the Adversary can re-run the attribution cheaply. +3. **Classify the fix target honestly:** env state (fix the host state + document how it + drifted), harness assumption (fix run_recipe_ci/lifecycle WITHOUT weakening HC1 — the + check itself must keep its teeth), or recipe/mirror tag problem (recipe-mirror PR, + never merged). If the expected-stamp derivation is what is wrong, the correction must + be justified against abra's documented behavior, not against "what makes the test + pass". +4. **Blast-radius sweep:** once attributed, check every enrolled recipe's most recent + upgrade-tier evidence for the same signature (prev-base tag commit stamped where a + version was expected). Any other affected recipe gets fixed by the same root-cause fix + and re-proven. + +## 3. Gates + +**M1 — Attribution.** Root cause documented with a reproducible minimal demonstration + +the 06-05→06-10 change identified by direct evidence (not inference alone); fix +implemented (env/harness/recipe per §2.3); blast-radius sweep complete. Adversary +independently reproduces the minimal demonstration and re-derives the attribution. + +**M2 — Proven in real CI.** Discourse full lifecycle green with upgrade-HC1 stamping the +CORRECT value at its true level (expected L4+ / L5 if lint passes); ≥1 run via the drone +`!testme` path; any other affected recipes re-proven; HC1 demonstrably NOT weakened (the +Adversary must show a wrong stamp still fails — synthesize one if needed). DEFERRED +entry closed with pointers. Fresh Adversary PASS → `## DONE`. + +## 4. Guardrails (binding) + +- **HC1 keeps its teeth** — any change that would let a genuinely wrong version stamp + pass is an automatic FAIL. +- Recipe mirrors: PR only, never push main, never merge. Shared checkout race: never + git-checkout `~/.abra/recipes/discourse` while its build runs. Real-CI etiquette: + ≤2-3 concurrent deploys, teardown on every exit path, no secrets in logs/commits. +- Host-state changes (abra binary, catalogue) beyond reading require a DECISIONS.md + entry; if the fix needs an abra version pin/upgrade host-wide, propose it in + STATUS-dstamp.md for the orchestrator/operator instead of doing it unilaterally. +- Commit author `autonomic-bot `; push every + commit. CI host has no python3 on default PATH — use shell or `cc-ci-run`. + +## 5. Definition of Done + +Drift mechanism attributed with reproducible evidence; fixed at the true root; discourse +back at its real level in real CI (drone path included); no other recipe silently +affected; HC1 unweakened and adversarially re-proven; DEFERRED closed; M1+M2 fresh PASSes. diff --git a/cc-ci-plan/plan-phase-kuma-monitor.md b/cc-ci-plan/plan-phase-kuma-monitor.md new file mode 100644 index 0000000..7083654 --- /dev/null +++ b/cc-ci-plan/plan-phase-kuma-monitor.md @@ -0,0 +1,70 @@ +# Phase `kuma` — uptime-kuma create-a-monitor functional test + +**Mission (operator-approved 2026-06-11, DEFERRED re-entry):** add the §4.3-prescribed +functional test that completes uptime-kuma's first-run setup wizard and exercises its +core function — create a monitor, see it actually probe a target — then check off the +DEFERRED entry. This is a cc-ci-repo-only phase (tests/uptime-kuma/), no recipe PR. + +State files: `STATUS-kuma.md`, `BACKLOG-kuma.md`, `REVIEW-kuma.md`, `JOURNAL-kuma.md`. +DECISIONS.md shared. + +## 1. Starting facts + +- DEFERRED entry (2026-05-28): uptime-kuma's first-run setup wizard + monitor CRUD run + over **Socket.IO** (not plain REST) — that's why it was deferred as fiddly. The + existing coverage is install/upgrade/health (+ screenshot, fixed in the shot phase); + the recipe currently earns its level without proving its actual function. +- uptime-kuma has no stable public REST API for this in the pinned version; the web UI + drives everything via socket.io events (`setup`, `login`, `add monitor`, + `uptimeList`). Two viable approaches — pick ONE and justify in DECISIONS.md: + (a) **python-socketio client** speaking the events directly (fast, headless, but + couples to the event names of the pinned version); or + (b) **Playwright through the real UI** (slower, but version-robust and reuses the + harness browser stack like other recipes' playwright tests). +- Wizard creates the admin credential: generated per-run, never logged (secret-safety + rules apply; the manifest redaction conventions cover meta, your test must not print + it either). + +## 2. Work requirements + +1. **Test design:** complete the first-run wizard (admin create) → create an HTTP + monitor pointing at a target the harness controls (e.g. the app's own /; or a + second known-up service in the deploy) → wait bounded time for ≥1 check result → + assert the monitor reports UP with a real probe timestamp. Negative teeth: a monitor + pointed at a dead target must go DOWN (proves the probe isn't a stub) — include it + if it fits the runtime budget, else justify. +2. **Placement per rcust conventions:** `tests/uptime-kuma/functional/` (or + `playwright/` if option b), uniform fixtures (`live_app`, `meta`, ctx hooks), no new + meta keys without registry+docs. +3. **Runtime budget:** the whole addition stays within the recipe's normal functional + tier budget (target ≤ ~90s added; bounded waits, no flaky sleeps — poll with + deadline). +4. **Prove in real CI:** full uptime-kuma lifecycle green with the new test active + (level should hold or rise under the de-capped ladder); ≥1 drone `!testme` run. +5. **Close records:** tick the DEFERRED entry with commit + run pointers. + +## 3. Gates + +**M1 — Test implemented + green.** Approach chosen and justified; test lands with +bounded waits and real assertions; full local-path lifecycle green. Adversary +cold-verifies: the monitor result is REAL (not asserted from config echo — there must +be evidence a probe executed), credentials never leak into logs/artifacts, runtime +budget held, nothing weakened. + +**M2 — Proven in real CI.** Drone-path run green with the new test; flake check (2 +consecutive green runs); levels reconciled; DEFERRED closed. Fresh Adversary PASS → +`## DONE`. + +## 4. Guardrails (binding) + +- No gate weakening; the new test only ADDS coverage. Secret-safety: generated admin + credentials never printed/committed. Real-CI etiquette: ≤2-3 concurrent deploys, + teardown on every exit path, never touch `~/.abra/recipes/uptime-kuma` mid-build. +- Commit author `autonomic-bot `; push every + commit. CI host: no python3 on default PATH (use `cc-ci-run`). + +## 5. Definition of Done + +uptime-kuma proves its actual function in CI (wizard + created monitor genuinely +probing), flake-checked through the drone path, budget held, DEFERRED checked off, +M1+M2 fresh Adversary PASSes. diff --git a/cc-ci-plan/plan-phase-mailu-backup.md b/cc-ci-plan/plan-phase-mailu-backup.md new file mode 100644 index 0000000..3a0d02d --- /dev/null +++ b/cc-ci-plan/plan-phase-mailu-backup.md @@ -0,0 +1,73 @@ +# Phase `mailu` — add backupbot labels to the mailu recipe (backup/restore coverage) + +**Mission (operator-approved 2026-06-11 — the DEFERRED re-entry trigger "operator +approves a cc-ci-authored mailu backupbot recipe-PR" has fired):** mailu ships no +`backupbot.backup` labels, so its backup/restore rung is a structural skip. Author a +recipe-mirror PR adding proper backupbot coverage, prove backup→wipe→restore data +integrity green in real CI at the PR head, and flip mailu's backup rung from +intentional-skip to genuinely earned. + +State files: `STATUS-mailu.md`, `BACKLOG-mailu.md`, `REVIEW-mailu.md`, +`JOURNAL-mailu.md`. DECISIONS.md shared. + +## 1. Starting facts + +- DEFERRED entry (2026-05-29): no `backupbot.backup` label on any service → + `backup_capable=False`, tiers cleanly SKIP. Durable fix = recipe-PR adding labels for + the admin DB (sqlite at /data) + the `mailu` mail volume, "mirroring the immich + Q3.5/Q3.2b pattern". +- mailu install + upgrade + functional (create-mailbox, IMAP login, send/receive + mail-flow) are already covered and green — only backup/restore is missing. +- Backupbot label syntax: use the **backupbot v2** syntax (a v1-vs-v2 syntax mistake + burned the plausible work once — see machine-docs history; verify against the + backupbot docs/other recipes' current labels, e.g. immich's merged pattern). +- Under the new level semantics, mailu currently climbs past backup as an intentional + skip; after this phase it must EARN the rung instead (and its declared-skip meta in + tests/mailu must be updated accordingly — that change is part of this phase). + +## 2. Work requirements + +1. **Research the recipe's real data layout before labeling:** which services hold + state (admin sqlite, mail store, redis?, certificates?), what must be quiesced or is + safe to copy live, and how the published mailu recipe + upstream docs define the + durable set. Justify every labeled path in the PR description; don't label caches. +2. **Recipe-mirror PR** (NEVER push main, NEVER merge): backupbot v2 labels + any + minimal compose plumbing they need + recipe version label bump per conventions. +3. **cc-ci side:** update tests/mailu meta (backup capability declaration) and ensure + the restore tier's data-integrity seed/verify actually exercises MAIL data (a seeded + mailbox + message that survives backup→wipe→restore — extend the existing functional + helpers if the current seed is too shallow; never weaken anything). +4. **Prove at PR head via real CI:** full lifecycle green incl. the now-active + backup/restore rung and lint (L5 expected if all rungs pass); ≥1 drone `!testme` run. + Record the before/after level (intentional-skip climb → earned rung). +5. **Close records:** tick the DEFERRED entry with PR + run pointers; operator handoff + in STATUS-mailu.md (what the PR adds, what to expect post-merge). + +## 3. Gates + +**M1 — PR open + green.** Root data-layout research documented; mirror PR open with +justified labels; full lifecycle green at PR head incl. restore data-integrity on real +seeded mail data; cc-ci meta/test changes minimal and unweakened. Adversary verifies the +labeled set against upstream docs (nothing durable missed, nothing junk included), the +restore proof is genuine (data actually survives a wipe), and the drone path ran. + +**M2 — Operator handoff.** Fresh Adversary cold pass (independent re-trigger at PR head, +restore integrity re-checked); levels reconciled; DEFERRED closed; STATUS-mailu.md +operator summary. `## DONE` with the PR left OPEN for the operator. + +## 4. Guardrails (binding) + +- Recipe mirrors: PR only. No gate weakening — the restore tier's assertions may only + get STRONGER. Mail data in test fixtures must be synthetic (never real addresses + beyond test domains; no secrets in logs/commits/PR text). +- Real-CI etiquette: ≤2-3 concurrent deploys; teardown every dev deploy on every exit + path; never touch `~/.abra/recipes/mailu` during its builds. +- Commit author `autonomic-bot `; push every + commit. CI host: no python3 on default PATH. + +## 5. Definition of Done + +Mirror PR open with evidence-justified backupbot v2 labels; backup→wipe→restore proven +on real seeded mail data at PR head incl. drone path; mailu's backup rung earned (not +skipped) with levels reconciled; DEFERRED closed; M1+M2 fresh Adversary PASSes; PR +unmerged for the operator.