| .. | ||
| tests | ||
| MANIFEST.sha256 | ||
| README.md | ||
| ROLLBACK.md | ||
Phase 2B Stage 2 — installed-state verification and daemon reload
Status: prepared for review only, 2026-07-12. Do not run until these uncommitted files have been reviewed and committed. Stage 2 does not authorize runtime activation.
Scope
tests/40-verify-stage2.sh is the only Stage 2 operator entry point. It runs as root and:
- requires a clean committed worktree and verifies this Stage 2 manifest, the unchanged Stage 1 artifact manifest, and the Stage 1 inventory checksums;
- proves that the Stage 1 artifact directory is unchanged since the commit recorded in the installed checksummed state;
- strictly resolves
/var/lib/le-app-codex-phase2b/stage1/current, requires aCOMPLETEstate with exactly 16 files and no pending records, and binds its manifest digest to the recorded source commit; - verifies all 16 destinations against the committed sources and state records by SHA-256, byte size, UID, GID, mode, regular-file type, and single-link count;
- confirms the runtime is inert, then runs the sole Stage 2 mutation:
systemctl daemon-reload; - validates the installed system units and drop-ins with
systemd-analyze verify,systemctl cat, and exact or membership-checkedsystemctl showproperties; parses the installed Docker unit with an explicit user-unit search path without starting a user manager; - runs root-capable
nft --check -f /etc/nftables.d/50-le-app-codex.nftand never loads the policy; - explicitly rechecks the namespace helper and rootless launcher hashes; and
- repeats every inert-state assertion after the reload and static validation.
The inert-state gates require the approval marker, namespace, namespace path, project veth, rootless Docker socket, lingering, UID-1200 processes, and both Phase 2B nftables tables to be absent. They require le-app-codex-netns.service and user@1200.service to be inactive and the namespace service to remain static rather than enabled.
Explicit exclusions
Stage 2 does not create the approval marker; start, restart, or enable any unit; use systemctl --user; enable lingering; invoke the namespace helper; create a namespace or veth; load nftables; start Docker or Codex; authenticate Codex; copy a repository, migration source, data, or secrets; contact production services; or modify production.
The script makes no cleanup attempt after a failure. It preserves evidence and exits nonzero. See ROLLBACK.md for the Stage 2 no-op rollback and the separately approval-gated Stage 1 removal path.
Review and future execution
Before committing, run only the non-operational tests/41-stage2-static-tests.sh. It checks syntax, manifests, immutable Stage 1 bytes, prohibited command literals, exact 16-file specifications, and the existing temporary-filesystem Stage 1 state tests. It never runs the Stage 2 operator script.
After review, commit the Stage 2 package. From a clean checkout of that commit, the future operator invocation is:
sudo /bin/bash docs/le-app-database-migration/phase2b-stage2-verification/tests/40-verify-stage2.sh
Require the final summary to report daemon_reload=1, installed_files=16, and failures=0. Any other result is a hard stop; do not continue to namespace or runtime activation.