feat(wake): W7 A10 idempotent component installer + mosaic-wake.service
Framework install machinery for the wake component (EPIC #892 W7, the last build slice). ADDITIVE per #869: adds an `install.sh --component wake` early dispatch that never enters the full-framework sync, never alters framework-manifest ownership behavior, and touches nothing the #869 install-ordering-guard covers (no runtime-asset linking, no lease-enforcement hook wiring). (i) Idempotent component-manifest install + Gate A (wake-install.sh install): the wake manifest.txt is VERSION METADATA ONLY; the component file set is INTERSECTED-AND-VALIDATED against the single SSOT framework-manifest.txt. A candidate the SSOT does not own is REFUSED fail-closed with no partial write. Re-running writes zero files (no diff). (ii) systemd/user/mosaic-wake.service — the long-lived detector daemon (detector.sh run). Per-class SLO lives inside the daemon, not a systemd interval; it is a SERVICE not a timer, so blank-reset does not apply. (iii) blank-reset idiom on the legacy mosaic-heartbeat@<agent>.timer cadence drop-in during the §5 overlap->retire lifecycle (empty OnUnitActiveSec= reset before the new value => exactly one OnUnitActiveUSec), with a reset->verify->retire acceptance path (retire LAST, only on §4-vector pass). (iv) snapshot-guard — a reap/clean-checkout of a deployed unit is REFUSED without a prior snapshot (the deployed-from-uncommitted failure class). (v) fail-closed alarm-target + HMAC-key install-validation (G1/G2a): the operator W6 alarm sink must be configured + reachable and the W3/W7 HMAC key must resolve BY NAME; missing/unreachable => FAIL LOUD. The installer ships/writes NO endpoint value and NO secret, and echoes neither. Red-first harness test-wake-install.sh (6 groups) wired into test:framework-shell; Gate-A parity extended to prove bash+TS both resolve the wake component paths framework-owned. wake component manifest bumped 0.5.0 -> 0.6.0. Part of #892 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0158NZqN2n2ymKFeJAZ4GUCb
This commit is contained in:
@@ -39,10 +39,19 @@ INSTALL_MODE="${MOSAIC_INSTALL_MODE:-prompt}"
|
||||
# never an environment variable — so this opt-out can never sit silently
|
||||
# inherited in a shell profile. See #869 Point-1 C2.
|
||||
ALLOW_INACTIVE_ENFORCEMENT=0
|
||||
# Component-scoped install (#892 W7): `install.sh --component <name>` runs an
|
||||
# additive, self-contained component installer and EXITS — it never enters the
|
||||
# full-framework sync below and never modifies framework-manifest ownership
|
||||
# behavior (#869: the diff is ADDITIVE). Parsed as a two-token flag here.
|
||||
COMPONENT=""
|
||||
_prev_arg=""
|
||||
for _arg in "$@"; do
|
||||
case "$_arg" in
|
||||
--allow-inactive-enforcement) ALLOW_INACTIVE_ENFORCEMENT=1 ;;
|
||||
--component=*) COMPONENT="${_arg#--component=}" ;;
|
||||
esac
|
||||
[[ "$_prev_arg" == "--component" ]] && COMPONENT="$_arg"
|
||||
_prev_arg="$_arg"
|
||||
done
|
||||
|
||||
# Shared framework path-ownership manifest reader (#791). Parity with
|
||||
@@ -605,6 +614,46 @@ run_migrations() {
|
||||
fi
|
||||
}
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
# Component-scoped install (#892 W7) — additive early dispatch.
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
# `install.sh --component <name>` delegates to the component's own idempotent,
|
||||
# fail-closed installer and EXITS. This path is ADDITIVE (#869): it does NOT run
|
||||
# the full-framework sync, does NOT alter framework-manifest ownership behavior,
|
||||
# and touches NOTHING the #869 install-ordering-guard covers (no runtime-asset
|
||||
# linking, no lease-enforcement hook wiring). Each component installer is
|
||||
# INTERSECTED-AND-VALIDATED against the single SSOT framework-manifest.txt, so a
|
||||
# component manifest can never authorize a write outside framework ownership.
|
||||
run_component_install() {
|
||||
local name="$1"
|
||||
case "$name" in
|
||||
wake)
|
||||
local wi="$SOURCE_DIR/tools/wake/wake-install.sh"
|
||||
if [[ ! -x "$wi" && ! -f "$wi" ]]; then
|
||||
fail "Component 'wake' installer not found at $wi"
|
||||
exit 1
|
||||
fi
|
||||
step "Installing Mosaic component: wake"
|
||||
WAKE_INSTALL_SOURCE="$SOURCE_DIR" WAKE_INSTALL_TARGET="$TARGET_DIR" \
|
||||
bash "$wi" install
|
||||
;;
|
||||
"")
|
||||
fail "--component requires a name (e.g. --component wake)."
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
fail "Unknown component '$name'. Supported: wake."
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
if [[ -n "$COMPONENT" ]]; then
|
||||
mkdir -p "$TARGET_DIR"
|
||||
run_component_install "$COMPONENT"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
# Main
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
Reference in New Issue
Block a user