Files
stack/briefs/PACKAGING-PLAN-HEARTBEAT-CANON-MS-LEAD.md

108 lines
8.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Wake/Heartbeat Canon — FRAMEWORK PACKAGING PLAN (MS-LEAD)
**Author:** MS-LEAD (framework packaging role, named in CONVERGED-DESIGN footer) · **Date:** 2026-07-25
**Input:** `jarvis-brain@31f1f6fd5 docs/scratchpads/heartbeat-planning/CONVERGED-DESIGN.md` (GO-WITH-GATES,
RATIFIED) + `ENHANCE-CADENCE-WRITER-FIX.md` + `ENHANCE-BASELINE.md`.
**Scope:** §6 category-A framework-component items (A1A11) + WAKE-DOCTRINE guide. NOT pilot (B*, mos-dt-0)
or operator-config values (C*). Proposal only — **no framework PR cut until Mos acks this plan** (per Mos).
**Repo facts verified** against `mosaicstack/stack` origin/main (read-only ls-tree) — not assumed.
---
## 1. Repo layout (grounded in verified paths)
Framework source lives in `packages/mosaic/framework/` and installs to `~/.config/mosaic/`. Verified:
`tools/<subdir>/` (git, tmux, fleet, orchestrator, lease-broker, context, …); `guides/*.md`;
`install.sh`; `systemd/`; `tools/tmux/agent-send.sh` (+ `agent-send.test.sh`).
| Item | Source path (new unless noted) | Installs to |
|---|---|---|
| A1 detector daemon | `framework/tools/wake/detector.sh` | `~/.config/mosaic/tools/wake/` |
| A2 store+drain lib | `framework/tools/wake/store.sh` (three-cursor, atomic write-tmp+rename) | XDG state `~/.local/state/mosaic/wake/` |
| A3 digest renderer | `framework/tools/wake/digest.sh` | " |
| A4 ack-wrapper | `framework/tools/wake/ack.sh` (RECEIVED/CONSUMED, local-write+async) | ledger under XDG state |
| A5 HMAC signer | `framework/tools/wake/sign.sh` (non-circular tuple, `load_credentials` by-name) | " |
| A6 FN-oracle · A7 reconciler | `framework/tools/wake/{fn-oracle,reconcile}.sh` | " |
| A8 off-host beacon | `framework/tools/wake/beacon.sh` + alarm integration | off-host monitor |
| A9 `digest` class validator | **MODIFY** `framework/tools/tmux/agent-send.sh` (+ `.test.sh`) | — |
| A10 idempotent installer | **MODIFY** `framework/install.sh` + `framework/systemd/user/mosaic-wake.service` | `~/.config/systemd/user/` |
| A11 WAKE-DOCTRINE | `framework/guides/WAKE-DOCTRINE.md` (lift §"WAKE-DOCTRINE" verbatim) | `~/.config/mosaic/guides/` |
| C1 watch-list SCHEMA (framework) | `framework/defaults/wake-watch-list.schema.json` | operator supplies values |
Note: `gitea-pr-watch` / `mos-comms` (the pollers the detector generalizes) are NOT under
`framework/tools/` on main — they are host/operator artifacts today. A1 becomes the canonical framework
generalization; it does not depend on those existing in-repo. The detector runs as a **long-lived
service** (not a timer) — the whole point is retiring unconditional timers; fallback cadence is a
per-class SLO bound inside the daemon, not a systemd interval.
## 2. PR slicing (dependency-ordered, ≤2 concurrent builders, each builder→indep-review→Mos id-11)
Dependency spine: store/ack (A2/A4) → digest/sign (A3/A5) → detector (A1) → oracle/reconciler (A6/A7);
beacon (A8), A9, A11 are near-independent; installer (A10) lands last (needs all files present).
| PR | Contents | Notes |
|---|---|---|
| **W0** | A11 WAKE-DOCTRINE.md | docs-only, independent; lands first as normative reference. Resolves #889 (see §5). |
| **W1** | A9 `agent-send.sh` digest-class validator + test | tiny, independent, red-first (like Patch 2b). Good opener. |
| **W2** | A2 store+drain lib **+** A4 ack-wrapper | core three-cursor transaction; red-first heavy. The heart. |
| **W3** | A3 digest renderer **+** A5 HMAC signer | depends on W2 store; hard-locator + scrub + non-circular MAC tests. |
| **W4** | A1 detector daemon | depends on W2/W3; repo-section/anchor-scoped hashing; flock; in mos-comms loop. |
| **W5** | A6 FN-oracle **+** A7 reconciler | depends on W4; the non-optional G3/§4 cost, built explicitly. |
| **W6** | A8 off-host beacon + alarm | semi-independent; the independent liveness leg (G1). |
| **W7** | A10 idempotent install.sh (blank-reset idiom + snapshot-guard) + `mosaic-wake.service` + C1 schema | LAST; **absorbs batch (d)**; #869 publish-gate (enforcement path). |
~8 PRs pipelined; at ≤2 lanes this is several convergence cycles. Each: fresh-clone builder
(`mosaic-coder`), author≠reviewer independent review at exact head, RoR packet, Mos id-11 stamp+merge.
Red-first mandatory on all code PRs; `test:framework-shell` chain extended per PR.
## 3. Versioning + #869 compatibility
- Component ships **inside the framework** (`packages/mosaic/framework/`) → inherits framework version.
- **§5.4 decoupling requirement:** a host must adopt "just the component + its watch-list without a full
framework bump." Enabler: the **watch-list carries an explicit `schema_version`**; the detector
**validates schema-version and FAILS LOUD on incompatible** (no silent degrade — #869 discipline,
same fail-loud posture as Patch 2b). WAKE-DOCTRINE is version-agnostic doctrine.
- **A10 installer is an enforcement path** → #869 publish-gate: fail-closed, idempotent, snapshot-guard
blocks a reap/clean-checkout without a snapshot; post-apply verify = exactly one `OnUnitActiveUSec`.
- **web1 rides #869 Point-2** (currently HELD/non-autonomous). **dragon-lin pilots NOW** (separate host,
outside the #869 freeze) — so canon PRs can land + be piloted without touching the web1 release hold.
## 4. Rollout sequence (§5, retire-net-LAST)
1. **Snapshot-first** (B5, mos-dt-0/pilot): dragon-lin `jarvis-heartbeat.{service,timer}` — snapshot
already present at `heartbeat-planning/pilot/snapshot-dragon-lin/`. Canon is version-controlled from
day one (the failure class — deployed-from-uncommitted — cannot recur).
2. Land W0→W7 to main (reviewed framework PRs).
3. dragon-lin: enable canon **alongside** ad-hoc (B1) → dual-ledger compare (B2) → run §4 vector (B3) →
delete ad-hoc units **after pass** (B4). Every step leaves old-or-new live (sol F7).
4. web1: adopt component + watch-list **on #869 resolution**.
- **Do NOT land the ad-hoc `infra/fleet/*` subsystem to main first** (§5.1, Mos ruling) — it is exactly
what canon retires.
## 5. Disposition of adjacent items
- **Batch (d) — ABSORBED into A10.** The blank-reset bug is in `infra/fleet/install.sh`
(deployed-from-uncommitted, NOT on main — confirms my "could not verify on main"). Host drop-ins
already corrected + live-verified 2026-07-25 (planner-opus/planner-sol now fire 30min not 15min).
**Nothing standalone to land**; the proven idiom (byte-identical to `installer-7`) becomes an A10
requirement + a post-apply test. Batch item (d) is therefore closed-as-absorbed, not a separate PR.
- **PR #889 (my layering note) — recommend CLOSE-SUPERSEDED.** Its constraints (one liveness substrate,
framework-vs-product split, state location, blank-reset invariant) are now **canonized in
CONVERGED-DESIGN §0/§1.1/§1.4/§5.2** (W-jarvis confirmed the constraint was accepted for relay). The
canonical heartbeat docs live in jarvis-brain `heartbeat-planning/`; keeping a superseded duplicate in
`mosaicstack/stack docs/scratchpads/` is cross-repo drift. **Lean: close #889 without merge** (design
input delivered + absorbed). Defer to Mos: close-superseded (my rec) vs merge-as-historical-record.
## 6. Open questions for Mos (before I cut W0)
1. **Repo home**`framework/tools/wake/` for A1A8 + `framework/defaults/` for C1 schema: confirm names.
2. **#889** — close-superseded (my rec) vs merge-as-record?
3. **PR granularity** — ~8 pipelined PRs OK, or coarser (fewer, larger) / finer?
4. **Pilot boundary** — design assigns pilot (B1B5) to **mos-dt-0**; I own framework packaging (A*). I do
NOT build pilot items unless you reassign. Confirm.
5. **Sequencing vs tooling batch**#890 (a) in flight for id-11; (b) held on scopes; (c) HALTED. Does W0
start now (dragon-lin outside #869), or after the tooling batch clears? My lean: **W0/W1 can start
now** (doc + tiny validator, no #869 dependency), heavier W2+ after (b)/(c) resolve to keep ≤2 lanes.
6. **Tracking issue/EPIC** — create a `mosaicstack/stack` EPIC for the canon component (parent for W0W7),
analogous to Matrix EPIC #887 / tooling umbrella #891? I'll open it on your nod.