# STATUS — phase mailu (backupbot labels for mailu recipe)

**Phase plan:** `/srv/cc-ci/cc-ci-plan/plan-phase-mailu-backup.md`
**Builder:** autonomic-bot / Claude (Builder loop)
**Started:** 2026-06-11T18:00Z

---

## Current state

**Gate M1: PASS** (Adversary verified @2026-06-11T21:00Z — see REVIEW-mailu.md)

**Gate M2: PASS** (Adversary verified @2026-06-11T21:15Z — build #483 L5; all DoD satisfied)

## DONE

Phase `mailu` complete. M1 PASS @2026-06-11T21:00Z + M2 PASS @2026-06-11T21:15Z.

**PR left open for operator merge:**
https://git.autonomic.zone/recipe-maintainers/mailu/pulls/3
(branch `add-backupbot-labels`, head `edc0201a79d36bc87696b0f93f1ee88ad7bd10ed`)

**Evidence:**
- Drone build #477 (ADV-mailu-01 fix re-claim): LEVEL 5, all rungs PASS
- Drone build #483 (Adversary fresh independent re-trigger): LEVEL 5, all rungs PASS
- Both builds: `test_backup_captures_mailbox`, `test_backup_captures_mail_message`,
  `test_restore_returns_mailbox`, `test_restore_returns_mail_message` — all PASS
- DEFERRED entry closed; PARITY.md updated; operator summary in this file

**What operator does next:** merge PR#3 on `recipe-maintainers/mailu`.

---

## DoD tracker (M1) — COMPLETE

- [x] Data-layout research documented (which volumes hold durable state, justification in PR desc)
- [x] Recipe-mirror PR open with backupbot v2 labels (admin `/data` + imap `/mail`)
  - **PR#3**: https://git.autonomic.zone/recipe-maintainers/mailu/pulls/3
  - Branch: `add-backupbot-labels`, head commit: `edc0201a79d36bc87696b0f93f1ee88ad7bd10ed`
  - Version bump: `3.0.1+2024.06.52` → `3.0.2+2024.06.52`
  - Adds `deploy.labels: {backupbot.backup: "true", backupbot.backup.path: "/data"}` to `admin`
  - Adds `deploy.labels: {backupbot.backup: "true", backupbot.backup.path: "/mail"}` to `imap`
- [x] cc-ci: `tests/mailu/ops.py` — pre_backup seeds account + injects mail message; pre_restore wipes both sqlite record AND Maildir
- [x] cc-ci: `tests/mailu/test_backup.py` — two tests: mailbox + mail message present at backup time
- [x] cc-ci: `tests/mailu/test_restore.py` — two tests: mailbox + mail message restored after restore
- [x] cc-ci: `tests/mailu/PARITY.md` updated (P4 COVERED with dual-volume evidence)
- [x] Drone build #477: LEVEL 5 PASS at PR head — all rungs including backup/restore on both volumes
  - `test_backup_captures_mailbox` PASS — SQLite `/data` covered
  - `test_backup_captures_mail_message` PASS — Maildir `/mail` covered
  - `test_restore_returns_mailbox` PASS — SQLite `/data` restored
  - `test_restore_returns_mail_message` PASS — Maildir `/mail` restored
  - `clean_teardown: true`, `no_secret_leak: true`
- [x] Before/after: BEFORE = L4 (backup intentional-skip); AFTER = L5 (earned)
- [x] M1 Adversary PASS @2026-06-11T21:00Z; ADV-mailu-01 closed

## DoD tracker (M2) — IN PROGRESS

- [x] DEFERRED entry closed (DEFERRED.md — mailu entry marked CLOSED @2026-06-11 with PR+run pointers)
- [x] Levels reconciled (PARITY.md updated; before=L4-skip, after=L5-earned, proven in builds #473/#477)
- [x] Operator summary written (this STATUS-mailu.md — see below)
- [ ] Fresh Adversary cold pass (independent re-trigger at PR#3 head, restore integrity re-checked)
- [ ] REVIEW-mailu.md shows M2 PASS (within 24h of M1)

---

## Verification recipe (for Adversary M2 check)

```bash
# 1. Verify PR#3 is still open and unmerged, head commit unchanged
GITEA_PASSWORD=$(grep GITEA_PASSWORD /srv/cc-ci/.testenv | cut -d= -f2-)
curl -s "https://git.autonomic.zone/api/v1/repos/recipe-maintainers/mailu/pulls/3" \
  -u "autonomic-bot:${GITEA_PASSWORD}" | python3 -c "
import sys,json; pr=json.load(sys.stdin)
print('state:', pr['state'])
print('head sha:', pr['head']['sha'])
print('merged:', pr.get('merged', False))
"
# Expected: state=open, head sha=edc0201a79d36bc87696b0f93f1ee88ad7bd10ed, merged=False

# 2. Re-trigger via !testme on PR#3 (Adversary does this independently)
# Expected: new drone build reaches LEVEL 5, all backup/restore tests PASS

# 3. Verify DEFERRED.md mailu entry is closed
grep -A3 "2026-05-29 — mailu" /srv/cc-ci/cc-ci-adv/machine-docs/DEFERRED.md
# Expected: [x] CLOSED @2026-06-11 with PR#3 + build #477 pointer

# 4. Verify PARITY.md updated with full dual-volume coverage
cat /srv/cc-ci/cc-ci-adv/tests/mailu/PARITY.md | grep -A20 "Backup data-integrity"
# Expected: mentions both /data (SQLite) and /mail (Maildir), both volumes seeded+wiped+verified

# 5. Confirm levels: before=L4, after=L5
# BEFORE: git.autonomic.zone/recipe-maintainers/mailu main — no backupbot labels → backup_capable=False → skip → L4
# AFTER: PR#3 head edc0201a79d3 — backupbot labels present → backup_capable=True → L5 (all rungs earned)
```

---

## Operator summary (for handoff)

### What this phase delivered

**PR#3 on `git.autonomic.zone/recipe-maintainers/mailu`** (branch `add-backupbot-labels`,
head `edc0201a79d36bc87696b0f93f1ee88ad7bd10ed`) — **open, awaiting operator merge.**

**What the PR adds:**
- Backupbot v2 labels on `admin` service: `backupbot.backup: "true"` + `backupbot.backup.path: "/data"`
  — backs up the SQLite database at `/data` (all accounts, mailboxes, domains, DKIM config)
- Backupbot v2 labels on `imap` service: `backupbot.backup: "true"` + `backupbot.backup.path: "/mail"`
  — backs up the Maildir at `/mail` (all stored messages for all users)
- Version bump: `3.0.1+2024.06.52` → `3.0.2+2024.06.52` (recipe version convention)
- No other compose changes; minimal diff

**What CI proved at PR head (drone build #477):**
- Install ✅ — fresh deploy of mailu at PR version
- Upgrade ✅ — previous published version → PR head, reconverges
- Backup ✅ — creates a mailbox + injects a real mail message; backup snapshot taken; both present at backup time
- Restore ✅ — wipes both the sqlite account record AND the Maildir; restore brings back both the account AND the stored message
- Functional ✅ — health check, mail flow (send/receive via postfix→dovecot), mailbox create+read
- Lint ✅ — abra recipe lint passes
- Clean teardown, no secret leak

**Before/after:**
- BEFORE (main, no labels): `backup_capable=False` → backup rung = intentional skip → max **L4**
- AFTER (PR#3 head): `backup_capable=True` (auto-detected from backupbot labels) → backup rung earned → **L5**

**To act:** merge PR#3 on `recipe-maintainers/mailu`. After merge, mailu will earn L5 on main
(`!testme` against main should hit L5 once the recipe is published with the new version).

No cc-ci config changes are needed post-merge — the harness auto-detects `backup_capable` from the labels.

---

## Blocked items

(none)

---

## DONE

Not yet. Written here only when M1+M2 Adversary PASS appear in REVIEW-mailu.md.
