# BACKLOG — phase cfold

## Build backlog
(Builder-only section — read-only to Adversary)

- [x] Seed `STATUS-cfold.md` + `JOURNAL-cfold.md`; consume Adversary inbox
- [x] Record deprecated-folder policy in `DECISIONS.md`
- [x] Update discovery + manifest to make `custom/` canonical without silent coverage loss
- [x] Update unit tests for discovery/manifest behavior and ordering
- [x] Migrate all cc-ci custom tests/helper modules into `tests/<recipe>/custom/`
- [x] Update docs (`docs/recipe-customization.md`, `docs/testing.md`, `docs/enroll-recipe.md`)
- [x] Produce M1 coverage-diff proof: discovered custom-test set identical before/after
- [x] Claim M1 with WHAT/HOW/EXPECTED/WHERE in `STATUS-cfold.md`
- [x] Await Adversary M1 verdict
- [x] Build the pre-sweep recipe baseline matrix for M2
- [x] Run the full real-CI `!testme` sweep and capture recipe-by-recipe evidence
- [x] Claim M2 only after the sweep is green and zero leaks are confirmed

## Adversary findings

No findings yet. Pre-migration baseline recorded below for reference during M1 verification.

### Baseline inventory (pre-migration, 2026-06-11T22:54Z)

**64 custom test files** across 20 recipes, all in `functional/` or `playwright/` subdirs:

| Recipe | functional/ | playwright/ | Helper modules |
|---|---|---|---|
| bluesky-pds | 4 | 0 | — |
| cryptpad | 2 | 2 | — |
| custom-html | 3 | 1 | — |
| custom-html-tiny | 1 | 0 | — |
| discourse | 3 | 0 | _discourse.py |
| drone | 1 | 0 | __init__.py |
| ghost | 4 | 0 | _ghost.py |
| hedgedoc | 2 | 0 | — |
| immich | 3 | 0 | — |
| keycloak | 3 | 0 | — |
| lasuite-docs | 5 | 0 | — |
| lasuite-drive | 3 | 0 | — |
| lasuite-meet | 3 | 0 | — |
| mailu | 3 | 0 | _mailu.py |
| matrix-synapse | 3 | 0 | — |
| mattermost-lts | 3 | 0 | _mm.py |
| mumble | 5 | 0 | _mumble_proto.py |
| n8n | 4 | 0 | — |
| plausible | 2 | 0 | — |
| uptime-kuma | 3 | 1 | — |
| **TOTAL** | **59** | **5** | **6 helper modules** |

Full file list (64 test files):
```
tests/bluesky-pds/functional/test_account_and_post.py
tests/bluesky-pds/functional/test_describe_server.py
tests/bluesky-pds/functional/test_health_check.py
tests/bluesky-pds/functional/test_session_auth.py
tests/cryptpad/functional/test_health_check.py
tests/cryptpad/functional/test_spa_assets.py
tests/cryptpad/playwright/test_pad_content_roundtrip.py
tests/cryptpad/playwright/test_pad_create.py
tests/custom-html/functional/test_content_roundtrip.py
tests/custom-html/functional/test_content_type_header.py
tests/custom-html/functional/test_health_check.py
tests/custom-html/playwright/test_browser_smoke.py
tests/custom-html-tiny/functional/test_serves_content.py
tests/discourse/functional/test_create_topic.py
tests/discourse/functional/test_health_check.py
tests/discourse/functional/test_site_basic.py
tests/drone/functional/test_scm_configured.py
tests/ghost/functional/test_admin_redirect.py
tests/ghost/functional/test_content_api.py
tests/ghost/functional/test_health_check.py
tests/ghost/functional/test_post_roundtrip.py
tests/hedgedoc/functional/test_branding.py
tests/hedgedoc/functional/test_health_check.py
tests/immich/functional/test_asset_processing.py
tests/immich/functional/test_asset_upload.py
tests/immich/functional/test_health_check.py
tests/keycloak/functional/test_create_client_and_use.py
tests/keycloak/functional/test_health_check.py
tests/keycloak/functional/test_password_grant_token.py
tests/lasuite-docs/functional/test_auth_required.py
tests/lasuite-docs/functional/test_create_doc.py
tests/lasuite-docs/functional/test_health_check.py
tests/lasuite-docs/functional/test_oidc_login.py
tests/lasuite-docs/functional/test_oidc_with_keycloak.py
tests/lasuite-drive/functional/test_health_check.py
tests/lasuite-drive/functional/test_minio_storage.py
tests/lasuite-drive/functional/test_oidc_with_keycloak.py
tests/lasuite-meet/functional/test_health_check.py
tests/lasuite-meet/functional/test_meeting_flow.py
tests/lasuite-meet/functional/test_oidc_with_keycloak.py
tests/mailu/functional/test_health_check.py
tests/mailu/functional/test_mailbox.py
tests/mailu/functional/test_mail_flow.py
tests/matrix-synapse/functional/test_federation_version.py
tests/matrix-synapse/functional/test_health_check.py
tests/matrix-synapse/functional/test_register_and_message.py
tests/mattermost-lts/functional/test_create_message.py
tests/mattermost-lts/functional/test_health_check.py
tests/mattermost-lts/functional/test_multiuser_message.py
tests/mumble/functional/test_protocol_handshake.py
tests/mumble/functional/test_server_config_limits.py
tests/mumble/functional/test_tcp_health.py
tests/mumble/functional/test_web_client.py
tests/mumble/functional/test_welcome_text_roundtrip.py
tests/n8n/functional/test_health_check.py
tests/n8n/functional/test_login_state.py
tests/n8n/functional/test_rest_settings.py
tests/n8n/functional/test_workflow_roundtrip.py
tests/plausible/functional/test_health_check.py
tests/plausible/functional/test_event_tracking.py
tests/uptime-kuma/functional/test_health_check.py
tests/uptime-kuma/functional/test_socketio_handshake.py
tests/uptime-kuma/functional/test_spa_branding.py
tests/uptime-kuma/playwright/test_monitor_wizard.py
```

Helper modules also in functional/ dirs (must move to custom/ alongside tests):
- tests/discourse/functional/_discourse.py
- tests/drone/functional/__init__.py
- tests/ghost/functional/_ghost.py
- tests/mailu/functional/_mailu.py
- tests/mattermost-lts/functional/_mm.py
- tests/mumble/functional/_mumble_proto.py

**String literal audit** — all places that name the FOLDER (not the playwright package):
- runner/harness/discovery.py:113 — `subdirs = ("functional", "playwright")`
- runner/harness/manifest.py:55 — comment `# functional | playwright`
- docs/recipe-customization.md — multiple §5.3 references
- docs/enroll-recipe.md — multiple references
- docs/testing.md:117,120 — placement rule
- tests/unit/test_discovery_phase2.py — creates functional/ and playwright/ dirs
- tests/unit/test_manifest.py — creates functional/ and playwright/ dirs; asserts `{"functional": 2, "playwright": 1}`
- tests/unit/test_discovery.py:83,84 — creates functional/ dirs

NOT to touch (playwright package references, not folder):
- runner/harness/browser.py (playwright package import)
- runner/harness/screenshot.py (playwright package import)
- runner/harness/card.py:232 (playwright package import)
- level.py, results.py (rung name "functional" — NOT a folder name)
