From 91179f872cabcf51e3ddf7939d024fd9f913ad1c Mon Sep 17 00:00:00 2001 From: autonomic-bot Date: Mon, 3 Aug 2026 22:41:16 +0000 Subject: [PATCH] =?UTF-8?q?skills:=20add=20/recipe-enroll=20=E2=80=94=20en?= =?UTF-8?q?d-to-end=20enrollment=20of=20a=20new=20maintained=20recipe?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Codifies the full path walked for the 2026-08-03 wordpress enrollment (cc-ci PR #14): survey -> mirror create+sync from coopcloud -> author test suite (health floor + non-vacuous recipe-specific tests incl. sec4.3 create-an-object round-trip, recipe-local setup helper, PARITY.md) -> bridge POLL_REPOS -> used-recipes.md weekly row + upstream/.md registry -> full-suite-green verification with the new tests -> bridge deploy via test-before-switch -> merge-on-green + report (PR-visibility policy). Includes the traps hit live: creds injection over stdin for cc-ci-side helpers, fresh- deploy wizard state in HEALTH_OK, repo-dev-shell ruff, swarm serialization, stale bridge secret 401s silently dropping !testme. --- .claude/skills/recipe-enroll/SKILL.md | 14 +++ .opencode/skills/recipe-enroll/SKILL.md | 137 ++++++++++++++++++++++++ 2 files changed, 151 insertions(+) create mode 100644 .claude/skills/recipe-enroll/SKILL.md create mode 100644 .opencode/skills/recipe-enroll/SKILL.md diff --git a/.claude/skills/recipe-enroll/SKILL.md b/.claude/skills/recipe-enroll/SKILL.md new file mode 100644 index 0000000..c306804 --- /dev/null +++ b/.claude/skills/recipe-enroll/SKILL.md @@ -0,0 +1,14 @@ +--- +name: recipe-enroll +description: Add a NEW recipe to cc-ci's maintained set, end to end — create + sync the recipe-maintainers mirror from coopcloud upstream, author a real test suite (health floor + non-vacuous recipe-specific tests incl. a create-an-object round-trip), enroll it in the !testme bridge (POLL_REPOS) and the weekly /upgrade-all inventory (used-recipes.md weekly row + upstream registry), then VERIFY the whole thing: full harness suite green with the new tests, bridge deployed (test-before-switch) and healthy. Opens the cc-ci PR for visibility and merges it directly once verification is green (the skill invocation is the authorization); the report lists merged PR links + what changed. Invoke as /recipe-enroll . +--- + +# recipe-enroll (thin wrapper) + +The canonical definition of this skill lives in the **opencode** position: + +**`.opencode/skills/recipe-enroll/SKILL.md`** + +Read that file for the full procedure. This `.claude/skills/` copy is kept as a +thin pointer for Claude Code compatibility; opencode loads the canonical +definition from `.opencode/skills/` directly. diff --git a/.opencode/skills/recipe-enroll/SKILL.md b/.opencode/skills/recipe-enroll/SKILL.md new file mode 100644 index 0000000..de21841 --- /dev/null +++ b/.opencode/skills/recipe-enroll/SKILL.md @@ -0,0 +1,137 @@ +--- +name: recipe-enroll +description: Add a NEW recipe to cc-ci's maintained set, end to end — create + sync the recipe-maintainers mirror from coopcloud upstream, author a real test suite (health floor + non-vacuous recipe-specific tests incl. a create-an-object round-trip), enroll it in the !testme bridge (POLL_REPOS) and the weekly /upgrade-all inventory (used-recipes.md weekly row + upstream registry), then VERIFY the whole thing: full harness suite green with the new tests, bridge deployed (test-before-switch) and healthy. Opens the cc-ci PR for visibility and merges it directly once verification is green (the skill invocation is the authorization); the report lists merged PR links + what changed. Invoke as /recipe-enroll . +--- + +# recipe-enroll + +Enroll a coopcloud recipe as a **maintained** recipe: mirrored, test-covered, `!testme`-triggerable, +and picked up by the weekly `/upgrade-all`. This is the full end-to-end path — worked example: +the 2026-08-03 wordpress enrollment (cc-ci PR #14). + +**"Maintained" = ALL of:** +1. Mirror `recipe-maintainers/` exists, `main` = coopcloud upstream main, tags synced. +2. `tests//` enrolled in the cc-ci repo (this is what `/upgrade-all` + `ci-test-review` + enumerate). +3. `POLL_REPOS` in `nix/modules/bridge.nix` includes the mirror (the `!testme` bridge). +4. `cc-ci-plan/used-recipes.md` has a ` weekly` row (orchestrator repo — `/upgrade-all` + skips recipes without it or tagged `external`). +5. `cc-ci-plan/upstream/.md` registry entry (release-notes URLs + standing notes). + +## Preconditions + +- The recipe exists upstream: `ssh cc-ci 'script -qec "abra recipe fetch " /dev/null'` + succeeds (every recipe must have a coop-cloud correspondent). +- `GITEA_*` creds in `/srv/cc-ci/.testenv` (orchestrator side; the cc-ci host does NOT have this + file — inject creds over stdin when running helper scripts there, see step 2). +- The shared Swarm is quiescent for step 6 (verification deploys the recipe) — do NOT verify + concurrent with `/upgrade-all` or other verify runs; author everything first, verify when clear. + +## Procedure + +### 1. Survey the recipe (read-only) + +On cc-ci, after `abra recipe fetch `, read `~/.abra/recipes//`: +- `compose.yml` — services + images (for the upstream registry), healthcheck (`start_period` + informs `DEPLOY_TIMEOUT`), traefik labels. +- `.env.sample` — is the app self-initializing, or does a fresh deploy sit in a setup wizard + (e.g. wordpress without `POST_DEPLOY_CMDS core_install`)? The tests must handle the state a + fresh CI deploy actually lands in. +- Auth model — how will a test create an object? (REST + token, session login, XML-RPC, …) + Check overlay configs (htaccess/nginx templates) for blocked endpoints before relying on one. + +### 2. Create + sync the mirror + +Create `recipe-maintainers/` (Gitea API: `POST /orgs/recipe-maintainers/repos`, +`{"name":…,"private":true,"default_branch":"main","auto_init":false}`), then force-sync from +coopcloud with the existing helper **run on cc-ci with creds injected via stdin** (the host has +no `.testenv`): +``` +set -a; . /srv/cc-ci/.testenv; set +a +{ printf 'export GITEA_USERNAME=%q GITEA_PASSWORD=%q GITEA_URL=%q\n' "$GITEA_USERNAME" "$GITEA_PASSWORD" "$GITEA_URL"; + cat /srv/cc-ci-orch/.claude/skills/recipe-upgrade/open-recipe-pr.sh; } \ + | ssh cc-ci 'bash -s -- --reconcile-only' +``` +Expect: repo created (or exists), `main` force-synced to upstream, published tags pushed. + +### 3. Author the test suite (dedicated cc-ci clone + branch) + +``` +git clone ssh://git@git.autonomic.zone:2222/recipe-maintainers/cc-ci.git /home/loops/work/cc-ci-tests- +cd … && git checkout -b test/-enroll-$(date -u +%Y%m%d) +``` +`tests//` contents (template: `tests/uptime-kuma/`, `tests/wordpress/`): +- **`recipe_meta.py`** — `HEALTH_PATH` / `HEALTH_OK` (accept the fresh-deploy state, e.g. a + 302 to a setup wizard), `DEPLOY_TIMEOUT` (recipe healthcheck `start_period` + DB init + + first-boot copy, be generous), `HTTP_TIMEOUT`, `WARM_CANONICAL = True` (canon §2.B — all + recipes enroll as data-warm canonicals, operator 2026-06-17). +- **`custom/`** — the health floor + **≥2 recipe-specific, non-vacuous tests**, one of which is + the §4.3 **create-an-object + read-it-back** (write through the app's real API, read back via + a *different* path where possible — e.g. wordpress: XML-RPC write → REST read → permalink + HTML). If the app needs setup/auth, put it in a recipe-local `_.py` helper + (idempotent `ensure_*` so test ordering doesn't matter; run-scoped class-B credentials — + the app is destroyed at teardown). Design assertions to name the broken layer (e.g. assert + both the rewrite-dependent and rewrite-independent API routes separately). +- **`PARITY.md`** — table of tests × what's verified × why non-vacuous; note there's no + recipe-maintainer parity corpus if so. +- Lint with the **repo dev-shell ruff**: `nix develop -c ruff check tests// && nix + develop -c ruff format tests//` (pre-existing drift in other files is not yours). + +### 4. Bridge enrollment (same branch) + +`nix/modules/bridge.nix`: append `,recipe-maintainers/` to the `POLL_REPOS=` CSV. + +### 5. Inventory + registry (orchestrator repo, direct to main) + +- `cc-ci-plan/used-recipes.md`: add ` weekly` row (alphabetical). +- `cc-ci-plan/upstream/.md`: images table (source repo + releases/changelog links) + + standing notes (setup-wizard behavior, auth caveats, known upgrade traps). +- Commit + push (doc commits go direct to main in this repo). + +### 6. Verify end-to-end — full suite GREEN with the new tests (swarm-serialized) + +Open the cc-ci PR first (visibility): `TITLE=… BODY_FILE=… bash +/srv/cc-ci-orch/.claude/skills/ci-test-review/open-cc-ci-pr.sh`. The body: what's enrolled, +the test design rationale, the verify + deploy plan. + +Then, when the swarm is clear: +``` +ssh cc-ci 'rm -rf /root/cc-ci-test-verify && git clone --branch test/-enroll- \ + ssh://git@git.autonomic.zone:2222/recipe-maintainers/cc-ci.git /root/cc-ci-test-verify && \ + cd /root/cc-ci-test-verify && git submodule update --init secrets 2>/dev/null || true' +RECIPE= REMOTE_ROOT=/root/cc-ci-test-verify \ + bash /srv/cc-ci-orch/.claude/skills/ci-test-review/verify-pr.sh # no REF — recipe main +``` +Required: **cold full-suite green** (install/upgrade/backup/restore/custom). Iterate the tests +(bounded, ≤3 attempts) if red — fix the TESTS to match real app behavior, never weaken. Clean up +`/root/cc-ci-test-verify` after. + +### 7. Deploy the bridge change to the cc-ci host (test-before-switch) + +The `POLL_REPOS` change only takes effect via a host rebuild. Per `/cc-ci-server-update` steps +5a-e: stage the branch to `/root/cc-ci-deploy` (+ secrets copy), `nixos-rebuild build`, detached +`nixos-rebuild test`, verify reachable + healthy, then `switch`. Confirm the bridge is polling +the new repo: `ssh cc-ci 'docker service inspect ccci-bridge_app --format "{{json +.Spec.TaskTemplate.ContainerSpec.Env}}"' | grep ` and the bridge task is 1/1 with no +auth errors in its logs (a stale Gitea secret 401s silently — see the 2026-08-03 finding). + +### 8. Merge + report + +Merge the cc-ci PR (invocation = authorization; PR is the visible record — comment the +verification evidence first). Report to the operator: merged PR link + change summary, the +verify log path, and the note that the **next weekly `/upgrade-all` picks the recipe up +automatically** (it enumerates `tests//` dirs × `weekly` rows). + +## Guardrails + +- **Full-suite green is the enrollment gate** — an enrolled-but-red recipe poisons every future + sweep. Don't merge on partial green. +- **Never weaken**: the tests assert the app's real current behavior, incl. asserting removed + auth paths are rejected where that's the upstream intent. +- **Single-writer**: dedicated clones/branches; never push `main` of cc-ci; never touch + `/root/builder-clone` or the loops' clones; `/root/cc-ci-test-verify` is yours — remove after. +- **Serialize on the swarm**: authoring is free, verification + bridge deploy wait for + `/upgrade-all`/other runs to finish. +- **abra over ssh needs the pseudo-TTY wrap**: `ssh cc-ci 'script -qec "abra …" /dev/null'`. +- **PRs for visibility, merged directly once verified**; failed enrollment leaves the PR open + with an explanatory comment and the report says exactly what's missing.