Design-only planning artifact for #791. Traces the wipe mechanism (install.sh:199 rsync --delete gated by PRESERVE_PATHS denylist) and specifies the ratified (b)+(a)+(d) fix: framework-owned manifest allow-list with fail-safe unknown=>operator default and manifest-scoped prune, a transactional pre-update snapshot with mosaic restore, and a projection-only mosaic fleet regen recovery path. No implementation changes. Refs #791 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
47 lines
3.1 KiB
Markdown
47 lines
3.1 KiB
Markdown
# Scratchpad — #791 Upgrade config protection (ms-791 worker lane)
|
|
|
|
**Lane:** web1:ms-791 → reports to MS-LEAD (web1:mosaic-100). Do NOT contact Jason/Mos directly.
|
|
**Worktree:** `/home/hermes/agent-work/stack-agents-dir-791`, branch `feat/791-upgrade-config-protection`
|
|
off `origin/main` `9745bc3f` (verified exact head).
|
|
|
|
## Mission prompt (verbatim intent)
|
|
Protect operator-owned config under `~/.config/mosaic` from framework-upgrade wipes. Ratified
|
|
combination (Mos-approved, do NOT re-litigate): (b) strict ownership separation [PRIMARY] + (a)
|
|
transactional pre-update snapshot [safety net] + (d) regeneration-from-SSOT [recovery]. (c) periodic
|
|
timer DEFERRED. HARD GATE: unit test that an upgrade run touches NO path outside the manifest.
|
|
Design-first: write design doc, send to MS-LEAD, WAIT for confirmation before impl.
|
|
|
|
## Session 1 (2026-07-16) — Phase 1 design
|
|
|
|
### Evidence gathered (wipe mechanism, file/line)
|
|
- `mosaic update` → `update-checker.ts:509` `buildReseedCommand` → `bash install.sh`
|
|
(`MOSAIC_SYNC_ONLY=1`, `MOSAIC_INSTALL_MODE=keep`).
|
|
- Wipe = `packages/mosaic/framework/install.sh:199` `rsync -a --delete` + `PRESERVE_PATHS` denylist
|
|
(`install.sh:47`). cp-fallback `install.sh:223` `find ... -exec rm -rf`.
|
|
- Denylist gaps → WIPED: `agents/*.conf`, `policy/*.md`, `*.local.md`, harvester/SOP,
|
|
`tools/_lib/credentials.json`.
|
|
- Stale comment `update-checker.ts:492` claims `*.local` preserved — PRESERVE_PATHS has no such entry.
|
|
- TS path `file-adapter.ts:157` → `file-ops.ts:66` `syncDirectory` = non-destructive copy-overlay, BUT
|
|
its preserve list (`file-adapter.ts:164`) already DRIFTED from install.sh (missing `fleet/backlog`,
|
|
`fleet/roles.local`). Evidence for single shared manifest SSOT.
|
|
- Existing snapshot (`install.sh:76`) = /tmp, crash-trap only, deleted on success → inadequate; no
|
|
`mosaic restore`.
|
|
- `fleet-reconciler.ts:93,234` already has `regenerate-projections-from-roster` phase separate from
|
|
lifecycle → `mosaic fleet regen` = thin projection-only wrapper (no restart), no FCM-M4/M5 preemption.
|
|
|
|
### Design decisions
|
|
- **(b)** Invert to allow-list: shared `framework/framework-manifest.json` (framework globs +
|
|
operatorReserved carve-outs); resolve per-path, deny-wins; **UNKNOWN ⇒ operator (fail-safe)**.
|
|
Mechanism: drop `--delete`; non-deleting bulk copy + explicit manifest-scoped prune pass (iterate
|
|
framework globs only → operator/unknown structurally unreachable). Pure prune-planner fn for tests.
|
|
- **(a)** Snapshot to `~/.local/state/mosaic/backups/pre-update-<ts>/` 0700/0600, retention N=5,
|
|
post-sync verify+restore, `mosaic restore --list/--from`. No secret values in output.
|
|
- **(d)** `mosaic fleet regen` projection-only, preview-first, never restart.
|
|
- HARD GATE test includes a deliberately-unanticipated operator path to prove fail-safe default.
|
|
- **PR split:** PR1 manifest+guard (root fix, ships alone) → PR2 snapshot/restore (secrev) → PR3
|
|
regen+docs. PR2/PR3 depend on PR1.
|
|
|
|
### Status
|
|
Design doc written: `docs/design/791-upgrade-config-protection.md`. Sent to MS-LEAD. **WAITING for
|
|
confirmation before Phase 2 implementation.** No impl started.
|