autonomic-bot 3131e39f64 review(redfix): wake #41 — merge target b5f2b10 CONFIRMED behaviourally, not by sha
Broke the pattern of re-probing B-redfix-8 (wakes #37-40, operator-only, adds nothing) and instead
attacked the artefact the operator acts on: "merge b5f2b10, NOT 07fc6d4".

Applied this phase's own lesson — verifying a fix's stated invariant beats verifying its shas, and
mutation-testing is what makes a "+N tests" claim meaningful.

- Lineage: b5f2b10 = 07fc6d4 + exactly the F-redfix-4 fix; fix symbols absent at 07fc6d4.
- Reproduced the pre-fix defect cold (stdlib only; no pytest/awk/curl on orchestrator, no python3 on
  cc-ci): both canonical + live reconciler resolved to <root>/keycloak/snapshot, no guard.
- Invariants GREEN at b5f2b10. Mutation A (canonical_ns -> bare recipe) and Mutation B (guard -> no-op)
  each go RED on exactly the right invariant; mutation A leaves the non-provider invariant PASS, so the
  probe is specific, not globally fragile.
- Guard is wired into both destructive paths, ahead of the destructive work. Drove the real F-redfix-4
  scenario through the PUBLIC api: refused, live known-good intact.
- Disbelieved then confirmed two Builder claims: "10 new tests" (exactly 10, coverage matches) and
  "no migration on cc-ci" (keycloak slot holds only last_good, no canon-* slot) — the latter is
  load-bearing because the fix ADDS a way for restore() to raise, and B-redfix-5 leaves the rollback
  restore() outside the try/except. Unreachable today; recorded as a merge precondition.
- B-redfix-5 re-verified accurate at b5f2b10 (warm_reconcile.py:533-537).
- "Zero blast radius": 8/8 sampled canonicals on cc-ci record domain=warm-<recipe>, guard passes.

Verdict: merge guidance CONFIRMED. No new finding. M1+M2 PASS stand, DONE stands, no VETO.
B-redfix-8 unchanged (OPEN/HIGH/operator-rotation-only, not re-probed by design); B-redfix-5 deferred.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SoraVF2hkEMExHswFX1g4M
2026-07-09 08:10:56 +00:00

cc-ci — Co-op Cloud recipe CI server

Comment !testme on a PR in an enrolled Co-op Cloud recipe repo and cc-ci deploys the recipe at that commit onto a real single-node Docker Swarm, runs install / upgrade / backup-restore tests (Python + Playwright) end-to-end, and reports a live, tail-able run with pass/fail back to the PR.

This repo declares the entire server as a NixOS flake and holds the test harness, the per-recipe test trees, and the docs to enroll a recipe or rebuild the box from scratch.

Status: under active autonomous construction. See machine-docs/STATUS.md for the live phase and plan.md-driven milestones in machine-docs/BACKLOG.md. Definition of Done is D1D10 (see the build plan).

Layout

flake.nix              NixOS entry point + devshells (`#cc-ci` = live Hetzner host, `#cc-ci-incus` = legacy Incus host)
nix/hosts/cc-ci/       legacy Incus VM host config (fallback / historical)
nix/hosts/cc-ci-hetzner/ live Hetzner host config
nix/modules/           drone, comment-bridge, swarm, dashboard, secrets (Nix modules)
secrets/               sops-encrypted infra secrets (cc-ci-secrets submodule)
bridge/                !testme webhook listener source
runner/                run_recipe_ci.py + shared pytest harness
dashboard/             results overview generator
tests/<recipe>/        per-recipe install/upgrade/backup tests + custom/
docs/                  install, enroll-recipe, secrets, architecture, runbook, baseline

All .nix code lives under nix/; flake.nix/flake.lock stay at the repo root. Host targets are:

  • #cc-ci = canonical live Hetzner server
  • #cc-ci-hetzner = explicit alias for the same live Hetzner server
  • #cc-ci-incus = legacy Incus VM definition only; do not use on Hetzner

Docs

  • docs/install.md — rebuild the server from scratch (D8)
  • docs/testing.md — test architecture: generic lifecycle suite + layered recipe overlays (override/extend, discovery precedence, custom install-steps hook)
  • docs/enroll-recipe.md — add a recipe under CI (D5)
  • docs/secrets.md — secret model + rotation (D6)
  • docs/architecture.md, docs/runbook.md — design + debugging failed runs
  • docs/baseline.md — bootstrap snapshot / rollback reference

Linting & formatting

The codebase is kept formatted + lint-clean by a single entrypoint, run from the pinned lint devshell so local and CI use identical tool versions:

nix develop .#lint --command bash scripts/lint.sh         # check-only (what CI runs)
nix develop .#lint --command bash scripts/lint.sh --fix   # auto-format + apply fixes

Covers Nix (nixpkgs-fmt · statix · deadnix), Python (ruff lint+format), Shell (shellcheck · shfmt), and YAML (yamllint). Config lives in ruff.toml / .yamllint.yaml; tool/strictness choices are in machine-docs/DECISIONS.md. CI enforces it: the lint step in the .drone.yml push pipeline runs the same command and fails the build on any unclean file, so keep commits clean (--fix before pushing).

Loop state (autonomous build)

The multi-agent loop state lives under machine-docs/: STATUS.md (phase/blockers), BACKLOG.md (work + adversary findings), REVIEW.md (independent verification), JOURNAL.md (build log), DECISIONS.md (architecture choices) — plus the phase-namespaced *-1b.md / *-1c.md variants. See the build plan for the two-loop Builder/Adversary protocol.

Description
Co-op Cloud recipe CI server (autonomous build)
Readme 12 MiB
Languages
Python 91.1%
Nix 5.4%
Shell 3.2%
HCL 0.3%