diff --git a/BUILD-LOG.md b/BUILD-LOG.md index 7eac6f10..19d91652 100644 --- a/BUILD-LOG.md +++ b/BUILD-LOG.md @@ -163,4 +163,33 @@ Configuration-driven Hello World verified. `main` merged with M1 and tagged `con Mission/task layer verified end-to-end. `main` merged with M2 and tagged `mission-task-v1`. +--- + +## Phase 7: Release model and safe updates (M3) + +### Entry 7.1 — before + +- Timestamp: 2026-09-03 +- Intended action: Add the release substrate (Gitea milestone M3, issues #10-#13): RELEASE file single-sources the version (0.0.X line per owner direction), image tags derive from it, scripts/release.sh provides package/activate/rollback/status, activation is health-gated by the M2 task runner, pointer + append-only log under /state/. +- Reason: The owner's top invariant — updates must never corrupt a working installation — needs a mechanism, not a convention: gate-then-flip with recorded history and rollback. +- Expected result: Update, refusal, and rollback drills all green with config checksums unchanged. + +### Entry 7.2 — after + +- Timestamp: 2026-09-03 +- Commands run: scripts/test-release.sh (14 cases); recorded drills: update (0.0.3 -> 0.0.4 package+activate+verify), fault-injected refusal, rollback to 0.0.3. +- Observed result: + - Selftests: 14 passed, 0 failed. + - Update drill: packaged and activated r0.0.4 after exact-marker health gate; verify green under the new tag; config checksum unchanged. + - Refusal drill: health-gate fault injection -> activation refused (exit 1), pointer untouched, refusal appended to the log. + - Rollback drill: health-gated rollback to r0.0.3; pointer restored; log records package/activate/refused/rollback history append-only. +- Failure or correction: + 1. release.sh initially failed with missing state/ directory (no mkdir before pointer/log writes); fixed. + 2. Selftest harness mutated the repo RELEASE and restored the mutated copy (mv-back bug) plus a second trap replacing the first; fixed with inline backup restore and one self-healing exit trap. Product code unaffected. +- Credential check: no credential material in release state, logs, or drills. + +## Result (M3) + +Release model and safe updates verified by drills. `main` merged with M3 and tagged `release-model-v1`. + diff --git a/README.md b/README.md index 5d608c30..3788bc93 100644 --- a/README.md +++ b/README.md @@ -83,6 +83,24 @@ scripts/test-task.sh # selftests (schema negat A run exits 0 only when its expectation is met (`expectExact` match); mismatches, nonzero agent exits, and timeouts record `status: failed` in `result.json` and exit 1. Each run gets a unique directory — rerunning never rewrites history. +## Release model (M3) + +`RELEASE` single-sources the release version (0.0.X until declared stable); the image tag derives from it plus the pinned Pi version. Activation is health-gated and every event is recorded: + +```bash +scripts/release.sh package # build + tag the release image +scripts/release.sh activate # health check (exact marker) -> atomic pointer swap +scripts/release.sh activate --fault-injection # prove the refusal path (drills only) +scripts/release.sh rollback # health-gated return to the previous release +scripts/release.sh status # release, tag, active pointer, recent log +scripts/test-release.sh # release selftests +``` + +- `/state/active.json` — the activation pointer (atomic tmp+rename replace) +- `/state/activation-log.jsonl` — append-only history: package / activate / refused / rollback + +A failed health check never activates; the previously active release remains deployed. Updating the software therefore cannot corrupt the running installation: package beside, gate, then flip. Verified by the update/refusal/rollback drills in BUILD-LOG Phase 7. + See `docs/plans/2026-09-02_atomic-mosaic-foundation.md` for the full plan. Inside the container: @@ -95,7 +113,8 @@ Inside the container: ## How it works -1. `scripts/build.sh` builds `mosaic-poc-agent:0.84.4` with Docker Compose. +1. `scripts/build.sh` builds the release image (`mosaic-poc-agent:-r`, + tag derived from `RELEASE` + the pinned Pi version) with Docker Compose. 2. On each run, `/opt/mosaic/src/load-contracts.sh` reads the four contract files in fixed order (CONSTITUTION, STANDARDS, SOUL, USER), joins them with clear separators, and writes `/var/lib/mosaic/system-prompt.md`. @@ -116,8 +135,10 @@ scripts/build.sh # build the image scripts/hello.sh # one-shot request; prints the model response scripts/verify.sh # full gated test; exit 0 only on exact MOSAIC_HELLO_OK scripts/run-task.sh # run a mission/task file (see Missions & tasks) +scripts/release.sh # package / activate / rollback / status (see Release model) scripts/test-config.sh # fast config-layer selftests (no Docker) scripts/test-task.sh # mission/task selftests (schema + live runs) +scripts/test-release.sh # release selftests scripts/reset.sh # delete the configured data root (safety-checked) ```