Commit Graph

3 Commits

Author SHA1 Message Date
Hermes Agent
0a5e703a70 test(mosaic): gate #797 ledger upgrade-survival + harden manifest parity (#791)
All checks were successful
ci/woodpecker/pr/ci Pipeline was successful
Fold the Mos-elevated #797 Runtime-Ledger survival sentinel into #791 PR1 and
harden the .txt-format parity test per the accepted-format conditions.

- framework-manifest.txt: annotate the existing fleet/run/** operator carve-out
  to name the #797 ledger (fleet/run/sessions/) so it reads as load-bearing.
  The glob already matches the #797 spec exactly — no location divergence.
- HARD GATE (test-upgrade-manifest-guard.sh): seed a populated ledger
  (events.ndjson journal + ledger.json projection, 0600 under 0700) as an
  operator sentinel; assert byte-identical + mtime-unchanged + dir-perms
  unchanged after a keep-mode upgrade. Relabel the prune check as the explicit
  negative control. 48 -> 58 checks.
- Parity (manifest-parity.spec.ts): add format-edge fixtures driven through
  BOTH resolvers via MANIFEST_FILE — comments/blanks/whitespace, duplicate and
  overlapping globs (deny-wins), section/glob-ordering independence, and an
  explicit UNKNOWN->operator negative probe; add ledger probe paths.
- manifest.spec.ts: isolate the carve-out's load-bearing value with a resolver
  red->green — under a hypothetical fleet/** framework glob, the ledger is
  pruned WITHOUT the fleet/run/** carve-out and protected WITH it (deny-wins).

Gates: typecheck, lint, format:check green; mosaic vitest 1069 passed;
HARD GATE 58/58; migration 21/21. Commits forward on 34e55d4a (no rebase).

Part of #791
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 16:11:06 -05:00
Hermes Agent
34e55d4a2e feat(mosaic): manifest-owned upgrade guard so updates never wipe operator config (#791)
All checks were successful
ci/woodpecker/pr/ci Pipeline was successful
Invert the framework updater from a denylist ("framework owns everything unless
preserved") to an explicit allow-list manifest ("operator owns everything unless
framework"). A path the manifest never anticipated resolves to operator-owned by
the fail-safe default, so it is structurally unreachable by any write or prune.

Root cause (#791): `mosaic update` re-seeds via `install.sh` keep-mode, whose
`rsync -a --delete` + hand-maintained PRESERVE_PATHS denylist wiped operator
paths the denylist forgot (agents/*.conf, policy/*.md, *.local.md, harvester
SOP, tools/_lib/credentials.json, unanticipated fleet files).

- framework-manifest.txt: single SSOT ([framework]/[operator], deny-wins,
  UNKNOWN=>operator fail-safe), read by BOTH installers.
- src/framework/manifest.ts: pure resolver (parse/matchGlob/resolveOwnership/
  frameworkSubtreeRoots/planPrune) — the testable seam.
- tools/_lib/manifest.sh: bash resolver (compiled globs, fork-free hot path),
  sourced by install.sh; parity-tested against the TS resolver.
- install.sh keep mode is now manifest-driven (no --delete): overlay-copy
  framework files, scoped-prune only retired framework files inside shipped
  subtrees. Operator + unknown paths are never written or deleted.
- file-ops.syncDirectory gains an isOperatorOwned guard; file-adapter derives it
  from the shared manifest, replacing the drifted hardcoded preservePaths.

Tests (TDD, red->green):
- HARD GATE test-upgrade-manifest-guard.sh: 10 operator sentinels (incl. an
  unanticipated one) survive a keep-mode reseed byte-identical + mtime-unchanged;
  retired framework file pruned; secret value absent from output. RED 31 fail on
  the old installer -> GREEN 48 pass. Wired merge-blocking into CI.
- manifest-parity.spec.ts (§6.1): bash<->TS agree on 34 paths + subtree roots.
- manifest.spec.ts: 18 tests incl. planPrune property test + shipped-tree
  completeness (§6.2).
- test-install-migration.sh F6 flipped: an unanticipated operator fleet file now
  MUST survive keep-mode reseed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 15:47:28 -05:00
Hermes Agent
87e21fd933 docs(791): Phase-1 design for upgrade config protection
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>
2026-07-16 15:14:50 -05:00