# Parity — gitea (phase gtea)

Phase-gtea P2 mapping table. The Adversary cold-verifies parity by reading the source
`recipe-info/gitea/tests/<file>` and the cc-ci file side-by-side.

**Source note:** `recipe-maintainers/gitea` (git.autonomic.zone) has **no `tests/` directory** on
`main` or `lfs-plain-gitea`. The reference tests exist ONLY in the local
`references/recipe-maintainer/recipe-info/gitea/tests/` corpus (the recipe-info collection kept on
the orchestrator VM for parity reference). They are not part of the upstream recipe repo itself.
The cc-ci implementations are ports of those reference tests, not of upstream recipe-repo tests.

| recipe-info source file | cc-ci file | what's verified | status |
|---|---|---|---|
| `references/recipe-maintainer/recipe-info/gitea/tests/health_check.py` | `tests/gitea/custom/test_health.py` | HTTP 200 from the root URL (`https://<domain>`). Original: resolves domain from testsecrets/. cc-ci port: uses `live_app` fixture (ephemeral per-run domain). Assertion shape preserved. | **ported from recipe-info corpus** |
| `references/recipe-maintainer/recipe-info/gitea/tests/git_push.py` | `tests/gitea/custom/test_git_push.py` | Create repo via API → clone → commit → push over HTTPS → verify commit landed via API → delete. Original: reads admin creds from CLI args/testsecrets. cc-ci port: admin creds from `ops.admin_creds()` (the `ci_admin` user created by `ops.pre_install`). Full SCM round-trip exercised. | **ported from recipe-info corpus** |

## Recipe-specific tests (≥2 beyond parity)

| cc-ci file | what's verified | rationale |
|---|---|---|
| `tests/gitea/custom/test_admin_api.py` | **Beyond-parity.** Admin API CRUD lifecycle: create user + org + API token → read-back via the generated token (authenticates as test user) → delete all. Tests two distinct auth paths (admin basic-auth + user token). | Proves the full admin-API contract: user management, org management, and token issuance. Non-vacuous: a broken DB or broken API router fails at least one assertion. Not covered by any upstream recipe-info test. |
| `tests/gitea/custom/test_lfs_roundtrip.py` | **Beyond-parity + PR #1 capstone.** Git LFS object upload→download OID round-trip + JWT-secret stability across `abra app restart`. Skips when `compose.lfs.yml` is absent (gitea main — LFS not deployed). Runs and must pass on `lfs-plain-gitea` (PR #1 head). | The mechanism that PROVES PR #1: red/skipped on main (feature absent), green on PR head (feature present). A rotating JWT secret fails the stability assertion (the exact regression the PR fixes). See §3 of the phase plan. |

## Backup / restore — REAL tiers

`compose.yml` carries `backupbot.backup=true` labels. `BACKUP_CAPABLE = True` is set explicitly
in `recipe_meta.py`. Backup and restore are REAL tiers (not N/A skips). Data integrity is proved
by the marker-repo mechanism (see `ops.py`):
- `pre_install`: creates `ci_admin` user + `ci-marker` repo (auto_init → README.md commit)
- `pre_upgrade`: re-asserts marker exists before chaos redeploy
- `pre_backup`: re-asserts marker exists before backup
- `pre_restore`: DELETES marker (diverges from backup state)
- `test_upgrade`: asserts marker survived upgrade (sqlite3 continuity)
- `test_backup`: asserts marker present at backup time
- `test_restore`: asserts marker returned (restore reverted deletion — non-vacuous: a no-op restore leaves it absent)

## Database choice

sqlite3 (`compose.sqlite3.yml`) — matches the dep config (drone uses gitea with sqlite3), minimal
footprint. No MariaDB/Postgres dependency needed for the CI test suite.

## Dep-vs-recipe-under-test split (§2 of phase plan)

`EXTRA_ENV(ctx)` applies to BOTH roles (dep deploy for drone AND recipe-under-test). The split
mechanism uses TWO conditions to guard LFS-overlay activation:
1. `compose.lfs.yml` exists in `$ABRA_DIR/recipes/gitea/` — only true on the `lfs-plain-gitea`
   PR branch (not on `main`).
2. `RECIPE=gitea` — set by the orchestrator only when gitea is the recipe-under-test.

Both conditions required: this ensures the dep path is **byte-for-byte identical** regardless of
whether the LFS PR branch is checked out, and ensures recipe-under-test with LFS overlay doesn't
accidentally activate for a dep deploy on the PR branch. Documented in DECISIONS.md (phase gtea).

## LFS capstone — EXPECTED_NA on main

The LFS test (`test_lfs_roundtrip.py`) uses `pytest.skip()` when `compose.lfs.yml` is absent:
```
Skips when compose.lfs.yml absent in gitea recipe checkout — LFS is not enabled on this branch.
This test runs on lfs-plain-gitea (PR #1) and is EXPECTED_NA on main.
```
No `EXPECTED_NA` key in `recipe_meta.py` because this is a custom-tier test that self-skips, not
a lifecycle rung. The phase M1 gate (suite green on main) is met WITH the LFS test skipped.
The phase M2 gate requires the LFS test GREEN on the `lfs-plain-gitea` PR head.

## Screenshot

`SCREENSHOT` hook in `recipe_meta.py` navigates to `/user/login` — the sign-in page. This is
credential-free and shows the gitea UI (form, branding). Default capture covers the install tier.
