# Phase 5 — REVIEW (Adversary) SSOT: `/srv/cc-ci/cc-ci-plan/plan-phase5-verify-upgrade-flow.md`. DoD = V1–V9. State files (this phase): `machine-docs/{STATUS,BACKLOG,REVIEW,JOURNAL}-5.md`. DECISIONS.md shared. This file is **Adversary-owned** (append-only log). Builder owns STATUS-5, JOURNAL-5. --- ## Orientation — 2026-05-31T13:30Z Phase 5 initiated (Adversary loop start). Current system state: - Phase 3: ## DONE (all R1–R8 Adversary-verified per STATUS-3.md) - Phase 4: not started (no STATUS-4.md exists anywhere) - Phase 5 Builder: not started (no STATUS-5.md exists) - cc-ci services: bridge (1/1), dashboard (1/1), drone (1/1), traefik (2/2) — all healthy - Bridge poll list: recipe-maintainers/{cc-ci, custom-html, keycloak, cryptpad, matrix-synapse, lasuite-docs, n8n, hedgedoc} - `custom-html-tiny` (the Phase 5 sandbox recipe per the plan) is NOT in the bridge poll list - Open PRs: custom-html-tiny PR#1 exists (chore: publish 1.0.2+2.38.0); custom-html PR#2 exists ## Break-it probes initiated — 2026-05-31T13:30Z ### V1 probe 1: !testmexyz on unmonitored repo (custom-html-tiny PR#1) - Comment #13795 posted: `!testmexyz` - Bridge does NOT poll custom-html-tiny (not in poll list) - Result: no trigger expected (but not a useful V1 test — wrong repo) - Action: re-ran probe on custom-html PR#2 (a watched repo) ### V1 probe 2: !testmexyz on watched repo (custom-html PR#2) - Comment #13796 posted: `!testmexyz` on recipe-maintainers/custom-html PR#2 - Bridge source confirmed: `parse_body("!testmexyz") → (False, False)` — explicitly filtered - After multiple 30s poll cycles: bridge logs still at 9 lines, ZERO match for "13796" or "testmexyz" - `!testmexyz` CORRECTLY IGNORED by bridge — does not trigger a Drone build ✓ - V1 partial evidence: `!testmexyz` does NOT fire (confirmed cold by Adversary) ### V1 auth probe: non-collaborator rejection - Auth endpoint verified directly: `GET /orgs/recipe-maintainers/members/nonexistent-user-999` → 404 - Bot auth: `GET /orgs/recipe-maintainers/members/autonomic-bot` → 204 - Bridge source: `is_authorized()` returns False for 404 → triggers `log("rejected: ... not authorized")` - V1 partial evidence: non-collaborator rejection logic confirmed by source + auth endpoint test ✓ ### V2 probe: testme-on-pr.sh reads verdict — CRITICAL GAP FOUND **Problem:** `testme-on-pr.sh POST=0` on known-green custom-html PR#2 (head `db9a95024e9d`) returns: ``` VERDICT=PENDING BUILD=? ``` **Root cause:** The script reads `GET /repos/recipe-maintainers/custom-html/commits/{sha}/status` → Gitea commit statuses. But the bridge NEVER posts commit statuses on recipe repo commits: - Bridge `trigger_build()` fires a Drone build on the `cc-ci` repo (not the recipe repo) - Drone posts `continuous-integration/drone/push` status on `cc-ci` commits ONLY - Recipe PR head SHA has ZERO commit statuses (confirmed: `state: ''`, `statuses: 0`) The bridge only posts PR comments (the YunoHost card+badge comment, U3). It does not call `POST /repos/{owner}/{recipe}/statuses/{sha}`. This is the EXACT gap Phase 5 §2 anticipated: "commit status vs comment — reconcile here." **Fix options:** 1. Bridge: add Gitea commit status posting for the recipe PR's head SHA (pending → on build start; success/failure → on build finish). This makes `testme-on-pr.sh` work unmodified. 2. `testme-on-pr.sh`: read the bridge's PR comment (scan for the `` marker and parse the result text/level from the comment body) instead of commit statuses. Option 1 is preferable (proper SCM integration; commit status is visible in the Gitea PR UI as a checkbox next to the commit). The Builder must implement one and record the decision in DECISIONS.md. **Impact on Phase 5:** V2 CANNOT be verified green until this is fixed. All of V3–V8 also depend on `testme-on-pr.sh` being able to return VERDICT=GREEN. --- ## Adversary findings (Tracked in BACKLOG-5.md)