# STATUS — phase cfold (custom-folder collapse) **Phase:** cfold — collapse `functional/`+`playwright/` into `custom/` **Builder:** autonomic-bot **Updated:** 2026-06-13 --- ## M1 — PASS Gate result: `REVIEW-cfold.md` 2026-06-12T16:20Z -> **M1 PASS** Inputs for verification: - Implementation commit: `44e0242` (`feat(cfold): canonicalize custom test layout`) Completed in this checkpoint: - discovery.py: `custom/` canonical + deprecated aliases with warnings - `git mv` all 64 custom tests (60 functional + 4 playwright) across 20 recipes - helper modules moved alongside their tests into `custom/` - sys.path refs updated in mailu lifecycle overlays - docs updated (`README.md`, `recipe-customization.md`, `testing.md`, `enroll-recipe.md`) - unit tests updated (`test_discovery.py`, `test_discovery_phase2.py`, `test_manifest.py`) - manifest.py now reports canonical `custom` counts WHAT: - M1 implementation is complete: custom-test discovery is canonicalized to `custom/`, deprecated aliases warn loudly instead of silently dropping coverage, all cc-ci custom tests/helpers moved to `tests//custom/`, manifest counts are canonicalized, and the placement-rule docs/unit tests were updated. HOW: - `git ls-files "tests/*/custom/test_*.py" | wc -l` - `git ls-files "tests/*/functional/*" "tests/*/playwright/*"` - `for recipe in bluesky-pds cryptpad custom-html custom-html-tiny discourse drone ghost hedgedoc immich keycloak lasuite-docs lasuite-drive lasuite-meet mailu matrix-synapse mattermost-lts mumble n8n plausible uptime-kuma; do count=$(git ls-files "tests/$recipe/custom/test_*.py" | wc -l); printf "%s %s\n" "$recipe" "$count"; done` - `nix shell nixpkgs#python311Packages.pytest -c pytest tests/unit/test_discovery.py tests/unit/test_discovery_phase2.py tests/unit/test_manifest.py -q` EXPECTED: - Total canonical custom tests: `64` - Old tracked trees: no output for `functional/*` or `playwright/*` - Per-recipe counts exactly match the baseline table below - Focused unit suite: `18 passed` WHERE: - Discovery + alias warnings: `runner/harness/discovery.py` - Canonical manifest counts: `runner/harness/manifest.py` - Migrated custom tests/helpers: `tests/*/custom/` - Focused unit coverage: `tests/unit/test_discovery.py`, `tests/unit/test_discovery_phase2.py`, `tests/unit/test_manifest.py` - Placement-rule docs: `docs/recipe-customization.md`, `docs/testing.md`, `docs/enroll-recipe.md`, `README.md` Adversary verdict: - `machine-docs/REVIEW-cfold.md` lines 52-77 - PASS facts include: 64 canonical custom tests, zero old tracked custom trees, focused unit suite `18 passed`, deprecated-alias warning probe green, normalized `(recipe, filename)` coverage set preserved exactly (`missing []`, `extra []`). --- ## DONE Phase result: `REVIEW-cfold.md` 2026-06-13T04:11:00Z -> **M2 PASS** Done criteria satisfied: - M1 PASS at `REVIEW-cfold.md` 2026-06-12T16:20Z - M2 PASS at `REVIEW-cfold.md` 2026-06-13T04:11:00Z - Full real-CI `!testme` sweep green across all 20 enrolled recipes with canonical `custom/` coverage intact - Zero leaked live `-pr` stacks after the sweep Final proof points: - Ghost blocker closure: build `585` on PR #5 ref `d42d0f7c7cf9` -> `level 5`, all stages pass, custom JUnit `4`, upgrade JUnit `2` - Same-code-path Ghost repro after the fix: `/var/lib/cc-ci-runs/ghost-repro-cfold-3/results.json` -> `install=pass`, `upgrade=pass` - cfold implementation commit: `44e0242` - Ghost closure fix commit: `d44f799` --- ## M2 — PASS Gate: M2 — CLAIMED, awaiting Adversary Current work item: - full real-CI `!testme` sweep is now green across the enrolled recipe set, including the formerly-blocking Ghost PR head - Ghost's upgrade blocker was fixed in cc-ci via the `tests/ghost/compose.ccci.yml` overlay: the app now waits in its entrypoint for the replacement DB socket before starting during the base->head crossover, while preserving Ghost's normal `/abra-entrypoint.sh node current/index.js` boot path - bridge replay-guard fix remains live on `cc-ci` (image tag `eb32876581d9`); the Ghost duplicate-trigger side issue is separately closed and no longer affects the cfold sweep result ### M2 baseline matrix (built from live PR heads + fresh post-cfold evidence) | Recipe | PR / ref | Expected level | Custom tests | Fresh evidence | |---|---|---:|---:|---| | bluesky-pds | PR #2 `f7b6c8df` | 5 | 4 | build `556` -> L5 | | cryptpad | PR #5 `9c18c176` | 5 | 4 | build `554` -> L5 | | custom-html | PR #2 `db9a9502` | 5 | 4 | build `541` -> L5 | | custom-html-tiny | PR #7 `526502ba` | 5 | 1 | build `510` -> L5 | | discourse | PR #2 `b7d8a244` | 5 | 3 | build `521` -> L5 | | drone | PR #1 `049438e1` | 5 | 1 | build `506` -> L5 | | ghost | PR #5 `d42d0f7c` | 5 | 4 | build `585` -> L5 | | hedgedoc | PR #1 `441c411c` | 5 | 2 | build `555` -> L5 | | immich | PR #2 `17f1649c` | 5 | 3 | build `522` -> L5 | | keycloak | PR #3 `bfe0d16f` | 5 | 3 | build `553` -> L5 | | lasuite-docs | PR #5 `8a06cfc2` | 5 | 5 | build `523` -> L5 | | lasuite-drive | PR #2 `6771622b` | 5 | 3 | build `524` -> L5 | | lasuite-meet | PR #6 `05cdafb5` | 5 | 3 | build `525` -> L5 | | mailu | PR #4 `682ccaaa` | 5 | 3 | build `526` -> L5 | | matrix-synapse | PR #2 `72f0176a` | 5 | 3 | build `527` -> L5 | | mattermost-lts | PR #2 `966c6d61` | 5 | 3 | build `529` -> L5 | | mumble | PR #1 `2b50b2f7` | 5 | 5 | build `558` -> L5 | | n8n | PR #5 `989c44b3` | 5 | 4 | build `528` -> L5 | | plausible | PR #3 `709a294d` | 5 | 2 | build `530` -> L5 | | uptime-kuma | PR #3 `b0ce7942` | 5 | 4 | build `531` -> L5 | ### Ghost closure `ghost` was the final M2 blocker and is now green on the real `!testme` path. - Historical failing same-ref comparison remains the strongest pre-fix proof: - build `559` on `d42d0f7c7cf9` -> L1; install/backup/restore/custom/lint pass, upgrade fail - build `585` on `d42d0f7c7cf9` -> L5; install/upgrade/backup/restore/custom/lint pass - Root cause of the upgrade failure: during the base->head crossover, Ghost's app task started before the replacement DB service was accepting connections, so the new task exited on `ENOTFOUND`/`ECONNREFUSED` against `${STACK_NAME}_db` and swarm paused the update before the head spec could settle. - Fix landed in `cc-ci` commit `d44f799` (`fix(cfold): wait for ghost db in entrypoint`): `tests/ghost/compose.ccci.yml` now keeps the existing 15m app/db healthcheck grace and wraps the app `entrypoint` with a tiny TCP wait that execs the normal `/abra-entrypoint.sh node current/index.js` path only after the DB socket is reachable. - Focused same-code-path repro after the fix: - `/var/lib/cc-ci-runs/ghost-repro-cfold-3/results.json` -> `install=pass`, `upgrade=pass` - log `/root/ghost-repro-cfold-3.log` includes `upgrade-converged: ghos-ce3c44_ci_commoninternet_net_app swarm UpdateStatus=completed` and `upgrade->PR-head: head_ref=d42d0f7c chaos-version=d42d0f7c+U version=1.2.0+6.21.2-alpine->1.4.0+6.44.0-alpine` ### Fresh Adversary state - `REVIEW-cfold.md` 2026-06-12T23:45:11Z: cold Ghost follow-up audit only, no new finding, no M2 claim pending. - `REVIEW-cfold.md` 2026-06-13T00:23:55Z: cold M2 artifact/teardown audit only, no new finding, no M2 claim pending; zero leaked live `-pr` stacks confirmed. WHAT: - M2 is now met: the full real-CI `!testme` recipe sweep is green, the formerly-blocking Ghost recipe is green again on the same PR head that previously failed, custom-tier coverage remains intact, and there are zero leaked live `-pr` stacks. HOW: - `ssh cc-ci 'tok=$(cat /run/secrets/bridge_drone_token); curl -fsS -H "Authorization: Bearer $tok" https://drone.ci.commoninternet.net/api/repos/recipe-maintainers/cc-ci/builds/585 | jq -r "[.number,.status,.after,.params.RECIPE,.params.PR,.params.REF] | @tsv"'` - `ssh cc-ci 'jq -r "{level,recipe,ref,results,stages:(.stages|map({name,status}))}" /var/lib/cc-ci-runs/585/results.json'` - `ssh cc-ci 'printf "ghost custom junit="; ls /var/lib/cc-ci-runs/585/junit/custom__cc-ci__*.xml | wc -l; printf " ghost upgrade junit="; ls /var/lib/cc-ci-runs/585/junit/upgrade*.xml | wc -l'` - `ssh cc-ci 'printf "live_pr_apps="; docker stack ls --format "{{.Name}}" | grep -c -- "-pr" || true'` - `ssh cc-ci 'jq -r ".results, .stages" /var/lib/cc-ci-runs/ghost-repro-cfold-3/results.json'` EXPECTED: - Drone build query returns build `585`, status `success`, `after=d44f799de945d0775933aad58726d46509154a64`, recipe `ghost`, PR `5`, ref `d42d0f7c7cf9946077a583ffa3f7c96abfe94a77` - `results.json` for build `585` shows `level: 5` and `results.install=pass`, `results.upgrade=pass`, `results.backup=pass`, `results.restore=pass`, `results.custom=pass`; stages include `install`, `upgrade`, `backup`, `restore`, `custom`, `lint` all `pass` - JUnit counts for build `585`: `ghost custom junit=4`, `ghost upgrade junit=2` - Teardown check returns `live_pr_apps=0` - Focused repro `ghost-repro-cfold-3` shows `install=pass`, `upgrade=pass` WHERE: - Fix commit: `d44f799` (`fix(cfold): wait for ghost db in entrypoint`) - Ghost overlay: `tests/ghost/compose.ccci.yml` - Real CI proof: `/var/lib/cc-ci-runs/585/results.json`, `/var/lib/cc-ci-runs/585/junit/` - Focused repro proof: `/var/lib/cc-ci-runs/ghost-repro-cfold-3/results.json`, `/root/ghost-repro-cfold-3.log` --- ## Baseline (pre-cfold) — custom test count per recipe | Recipe | Count | |--------|-------| | bluesky-pds | 4 | | cryptpad | 4 | | custom-html | 4 | | custom-html-tiny | 1 | | discourse | 3 | | drone | 1 | | ghost | 4 | | hedgedoc | 2 | | immich | 3 | | keycloak | 3 | | lasuite-docs | 5 | | lasuite-drive | 3 | | lasuite-meet | 3 | | mailu | 3 | | matrix-synapse | 3 | | mattermost-lts | 3 | | mumble | 5 | | n8n | 4 | | plausible | 2 | | uptime-kuma | 4 | | **TOTAL** | **64** |