plan: phases dstamp, mailu, kuma, drone (queued after bsky) + journal

- dstamp: attribute + fix the discourse abra-stamp drift (env change 06-05→
  06-10, harness-neutral, currently pinning discourse at L1); blast-radius
  sweep; HC1 keeps its teeth
- mailu: backupbot v2 labels recipe PR, restore proven on real seeded mail,
  backup rung earned instead of skipped (operator approved re-entry)
- kuma: uptime-kuma first-run wizard + create-a-monitor functional test
  (Socket.IO or Playwright, real probe evidence, flake-checked)
- drone: gitea-dep enrollment, maximal subset per Phase-2 scoping;
  P0 /etc/timezone host deploy is orchestrator-owned (3bde76f committed)
This commit is contained in:
autonomic-bot
2026-06-11 11:43:03 +00:00
parent f395247da4
commit 327b9f4efe
5 changed files with 319 additions and 0 deletions

View File

@ -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.

View File

@ -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 <autonomic-bot@noreply.git.autonomic.zone>`; 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.

View File

@ -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 <autonomic-bot@noreply.git.autonomic.zone>`; 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.

View File

@ -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 <autonomic-bot@noreply.git.autonomic.zone>`; 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.

View File

@ -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 <autonomic-bot@noreply.git.autonomic.zone>`; 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.