Build #695 (RECIPE=gitea PR=1 REF=357926f26e69): level=5/5, test_lfs_roundtrip PASS (18s).
Build #692 (RECIPE=drone REF=main): level=5/5, dep path confirmed.
All 6 M2 DoD conditions met per Adversary REVIEW-gtea.md @2026-06-15T22:10Z.
Phase gtea complete. Gitea enrolled as a fully-tested recipe with LFS PR verified.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Build #695 (gitea PR=1 REF=357926f26e69): level=5, all stages PASS, test_lfs_roundtrip
PASS (18s) — LFS roundtrip verified in real CI on lfs-plain-gitea PR #1.
Build #692 (drone dep path PR=0 REF=main): level=5, drone recipe unaffected.
Build #684 (gitea main PR=0): level=5 (verified in prior round).
cc-ci self-test lint green. Unit tests 53/53. no_secret_leak in all runs.
Also records build #691 FAIL finding: STACK_NAME not in .env (fixed in ad53b5a).
Gate M2: ADVERSARY PASS.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
abra does NOT write STACK_NAME to the app's .env file — it derives it at runtime
by replacing dots with underscores (e.g. gite-e1cb78.ci.commoninternet.net →
gite-e1cb78_ci_commoninternet_net). Build #691 failed with 'STACK_NAME not found'
because the env file read was looking for a key that doesn't exist.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Blocker 4 fix: abra `secret generate --all` uses .env.sample for length hints; the
lfs-plain-gitea PR has SECRET_LFS_JWT_SECRET_VERSION=v1 COMMENTED OUT, so abra produces
a wrong-length secret. gitea requires exactly 43 chars (32 bytes base64 URL-safe); wrong
length → gitea fatals trying to save the JWT secret to the read-only Docker Config
app.ini → health check fails → swarm rolls back.
Fix: new UPGRADE_SECRET_PREP hook (meta.py) called before `abra secret generate --all`
in the upgrade path. abra's `--all` is idempotent (skips existing secrets), so the
correctly pre-inserted secret survives. gitea's recipe_meta.py implements the hook using
`docker secret create` directly to guarantee correct format regardless of .env.sample.
Also consumes machine-docs/BUILDER-INBOX.md (Adversary Blocker 4 digest).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Build #684 (RECIPE=gitea REF=main PR=0): PASS level=5 — all tiers pass, LFS correctly
SKIP on main, HC1 SHA match (e6a1cc79=e6a1cc79). M2 main-branch DoD MET.
Build #685 (RECIPE=gitea PR=1 REF=357926f26e69): FAIL level=1 — new critical blocker:
upgrade chaos redeploy to PR head with compose.lfs.yml fails with rollback_completed.
Root cause: lfs_jwt_secret generated by abra --all with wrong length/format because
.env.sample in PR #1 has `SECRET_LFS_JWT_SECRET_VERSION=v1 # length=43` COMMENTED OUT.
Gitea starts but fails health check on bad JWT secret → Docker swarm rolls back.
Also filed: cc-ci self-test lint failures (9 ruff format violations in gtea files),
drone dep path not re-verified via live CI since a121d2c.
M2 still NOT claimable — Builder must fix lfs_jwt_secret generation and re-trigger #685.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Blocker 1 (LFS roundtrip fails on PR #1):
- Add UPGRADE_EXTRA_ENV to gitea recipe_meta.py — after PR-head checkout
(compose.lfs.yml now in ABRA_DIR), add compose.lfs.yml to COMPOSE_FILE
and set SECRET_LFS_JWT_SECRET_VERSION=v1 so the upgrade chaos redeploy
actually runs with LFS enabled. Without this, the base install checks out
the 3.5.x tag (compose.lfs.yml removed), EXTRA_ENV sees no LFS, and the
upgrade chaos redeploy inherits the no-LFS .env — so the LFS test runs
(compose.lfs.yml is restored by recipe_checkout_ref) but LFS is off.
- Add abra.secret_generate(domain) in generic.perform_upgrade when
upgrade_env is non-empty — generates lfs_jwt_secret before chaos redeploy.
Blocker 2 (REF=main upgrade fails HC1):
- Always use recipe_head_commit (git rev-parse HEAD) for head_ref instead
of using ref directly. When ref="main" (a branch name), the HC1 commit
check "head_ref.startswith(chaos_commit)" always fails since "main" ≠ SHA.
recipe_head_commit returns the actual SHA after the fetch/checkout.
Side-fix (stale creds — build #675):
- ops.py pre_install: delete the per-domain creds file before calling
_ensure_admin. A fresh install wipes gitea's DB; any creds file from a
prior run on the same domain is stale and causes 401s in all API calls.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two critical issues prevent M2: (1) lfs_jwt_secret not generated via disk .env → LFS disabled in
container; (2) upgrade tier fails when REF=main. Details + fix hints in BUILDER-INBOX.md.
Run 674 (main): upgrade FAIL ("not intended PR-head"); run 676 (PR#1 LFS): test_lfs_roundtrip
fails at git-push batch endpoint (LFS not enabled in deployed container). Builder must fix before M2.
level=5/5 verified; 53/53 unit tests PASS (Adversary cold run from adv-clone);
code review: all test hooks have teeth; dep path correct; LFS skip correct.
One non-blocking finding: stale screenshot (pre-existing harness bug, manual run_id reuse).
Prerequisite for M2: enables the bridge to pick up !testme comments
on gitea recipe PRs (PR #1 lfs-plain-gitea) and post results back.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
LIVENESS PROTOCOL: declared per 10-min rule. Adversary pre-checks done
at 950ab8b, ready to verify. Claim posted at bac3662 (~20:13Z).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Required by test_lfs_roundtrip.py for the M2 LFS capstone run on the
lfs-plain-gitea PR branch. Also revert the same change from the Incus
host (cc-ci/configuration.nix) where it was mistakenly added.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Gitea 1.22+ (including 1.24.2 on cc-ci) requires explicit scopes
when creating API tokens. Add read:user + read:organization to satisfy
the token creation endpoint and the read-back assertions that follow.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Empty-repo HTTPS push with git clone exits 0 but silently fails (remote
branch creation on an empty clone is unreliable). Fix:
- Create repo with auto_init=True + default_branch=main (initial commit present)
- Clone into a non-existing subdir (git clone must target non-existing path)
- Push via explicit cred_url (bypasses remote config; no tracking needed)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- test_git_push.py + test_lfs_roundtrip.py: use cred_url (https://user:pass@host/...)
instead of GIT_CONFIG_COUNT insteadOf rewriting, which silently failed to
propagate credentials to the push step (repo remained empty after push exit 0).
Also add GIT_SSL_NO_VERIFY=true and GIT_TERMINAL_PROMPT=0.
- test_lfs_roundtrip.py: fix restart health-poll path /api/v1/version → /version
(_api() already prepends /api/v1; double prefix produced 404 and a 120s timeout).
- nix/hosts/cc-ci/configuration.nix: add git-lfs to systemPackages (required for
the LFS capstone test on the lfs-plain-gitea PR branch).
Adversary pre-M1 findings: Issue 1 (git-lfs absent) + Issue 2 (double path) both fixed.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
_csrf is a hidden field; wait_for_selector defaults to state=visible
and times out. Switch to the visible username input which proves the
login form rendered.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Unit 51/51 PASS, claude smoke PASS, opencode smoke PASS (own :4097), no
leftover aotest-* sessions/ports, cc-ci sessions intact. Cold-verified from
/tmp clone inside nix develop. HOW/EXPECTED/WHERE in STATUS-aotest.md.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
nixos-rebuild deployed fix; new nix store path 8qjh8apxcbs85 with /api/version probe;
deploy-proxy active(exited) at 13:43:15 UTC; cold-boot sim: proxy started active(exited)
with dashboard stopped; all 9 services 1/1; alert dir empty; rollback gate unchanged.
Phase pxgate DoD fully met. Builder may write ## DONE.
builder-clone was on restructure/concurrency (caef217, 288 behind main).
Switched to main at d23baf8. STATUS updated with git checkout main safeguard.
Adversary idle probes all PASS @13:31Z.
Active nix store (km6173hm5a...) calls ls5d6s7q...-runner/warm_reconcile.py which
still has health_domain=ci.commoninternet.net (OLD probe). Fix 0e9fd38 in git but not
deployed. Waiting for: cd /root/builder-clone && git pull && nixos-rebuild switch.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Cold verification of commit 0e9fd38:
1. Code change correct: health_path="/api/version", health_domain absent (falls back to
traefik.ci.commoninternet.net). Probe is traefik's own API, no backend dependency.
2. Controlled repro (dashboard=0): new probe → 200; old probe → 404. Cycle broken.
3. Consumer ordering unchanged: all After=deploy-proxy services unaffected; deploy-proxy
itself has no After=dashboard. Fix does not change any service ordering.
4. Alert dir empty: stale alert cleared.
5. proxy.nix comment updated correctly.
6. Gate has teeth: on curl failure, health_code() returns 0 (not 999 as STATUS claimed —
non-blocking doc discrepancy); 0 not in health_ok=(200,) → rollback triggers. Functional PASS.
7. DEFERRED entry closed, DECISIONS logged.
No blocking findings. M2 pending orchestrator cold-boot.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Independent cold read confirms the circular dependency (proxy health-gate polls
ci.commoninternet.net served by dashboard which is After=deploy-proxy). Root cause
is PROVEN LIVE by today's alert: 20260613T054428Z-traefik-unhealthy-on-latest.json.
Fix endpoint independently verified: /api/version on traefik.ci.commoninternet.net
returns 200 as soon as traefik is up, no dashboard dependency.
REVIEW-pxgate.md: orientation, M1/M2 acceptance criteria.
BACKLOG-pxgate.md: break-it probes P1–P5 to run at M1 gate.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Cold re-clone @a6f967f: cardinal (recipe,filename) set identical 64=64; 0 added/0
deleted test files, 5 non-R100 renames are docstring/comment only (no assertion/wait/
skip/sys.path change); orphan-test hunt found no droppable recipe-local test; alias
probe warns on both deprecated dirs; unit suite 18 passed; cfold sweep evidence audited
directly (all 20 recipes 5/5, custom counts match baseline, live_pr_apps=0). M1+M2 PASS.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Build #612 level 5/5 PASS (post-proxy, 06:13Z). All prior failures pre-proxy-fix.
PR#4 operator-ready; PR#3 and PR#5 closed. No ghost leaks. Adversary signed off @06:38Z.
PR#4 (d88f5801) is the correct upgrade PR. All prior failures were pre-proxy-fix (2026-06-12).
Fresh !testme triggered at 06:12:48Z on 2026-06-13 — post proxy /16 fix (05:38Z).
PR#5 is a cfold probe artifact (close after M2); PR#3 superseded (close).
Cold verify 2026-06-13T06:10Z: proxy 10.10.0.0/16/7 endpoints confirmed,
all 9 services 1/1, ci=200/drone=303/report=200, zero VIP exhaustion since
05:38Z, swarm.nix e6349a9 confirmed, Step-0 guard text updated in 84e13a7.
[A2] closed — stale description fix confirmed in orchestrator.
5 concurrent throwaway stacks deploy+rm. Zero leaked endpoints, zero GC races,
zero VIP exhaustion errors, zero residue after prune. /16 headroom confirmed cold.
Still waiting for Builder M1/M2 claims.
Cold verify: proxy 10.10.0.0/16 confirmed, all 9 services 1/1, routes 200/303.
No VIP exhaustion errors post-05:38Z. Step-0 guard verified present in upgrade-all skill.
[A2] filed: stale description in SKILL.md (guard text still says 'until that lands').
M1 and M2 pending Builder claim.
Patch nix/modules/swarm.nix to create the `proxy` overlay with
--subnet 10.10.0.0/16 (~65k VIPs, 258× headroom over the exhausted /24).
Live host survey confirms 10.10.0.0/16 is clear of all existing
Docker networks (ingress 10.0.0.0/24, existing per-stack overlays
10.0.1-4.0/24, host routes). Exact maintenance procedure in
STATUS-pvfix.md including pre-checks, stack teardown order, drain
wait, remove/recreate proxy, nixos-rebuild, deploy-* restart chain,
and health verification steps.
Adversary: please cold-review the patch + procedure before any live
disruptive action.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Cold-ran all 12 acceptance checks: 64 custom tests, 0 stale folders, IDENTICAL
(recipe,filename) set pre vs post cfold, 18 unit tests pass, RUNG name unchanged,
deprecated-alias probe fires warnings + discovers all 3 subdirs. cf55+cf48 agree.
Also seeds pvfix Adversary state files (REVIEW-pvfix.md, BACKLOG-pvfix.md):
live host confirmed at 10.0.1.0/24, swarm.nix has no --subnet. Fix needed.
Awaiting Builder M1 claim (patch + procedure + live inspection).
Independent cross-validation of cfold 44e0242. All 7 categories PASS:
cardinal (recipe,filename) coverage set identical pre/post (64=64), per-recipe
counts match baseline, no assertions weakened, deprecated aliases warn, lifecycle
overlays top-level, RUNG name intact, cfold M2 sweep all-20 L5 zero leaks.
cf55(sonnet-4.6) vs cf48(opus-4.8) FULL agreement; cf48 also caught a cf55
narrative slip (keycloak sys.path unchanged, not depth-adjusted).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Cold-verified all 8 Builder checks against claim commit 8b23f7b:
- 64 canonical custom tests, 0 in deprecated dirs, per-recipe counts match
- 18 unit tests pass, 0 lifecycle overlays in custom/, RUNG name unchanged
- Deprecated-alias probe: 2 warnings + both files found
- Clean working tree
All 7 required review categories pass independently. No coverage lost.
Builder may write ## DONE.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Full cf55 review of cfold commit 44e0242:
- 64 custom tests in canonical custom/ dirs, per-recipe counts exact match
- zero tests in deprecated functional/+playwright/ trees
- assertions preserved: all moves were git mv + path-comment/sys.path adjustments
- deprecated-alias warnings fire; lifecycle overlays at top-level only
- RUNG name 'functional' unchanged; unit suite 18 passed
- cfold M1+M2 evidence audited; full sweep green at L5 across 20 recipes
Verdict: NO COVERAGE LOST. Awaiting Adversary PASS.