# Mosaic wake component — VERSION metadata manifest (Gate B).
#
# EPIC #892, W2 + W3 of the wake/heartbeat canon.
#
# SCOPE — THIS FILE IS VERSION METADATA ONLY. It declares the wake component's
# semantic version and the RANGE of watch-list schema versions it supports. It
# does NOT authorize file/path ownership: path-ownership remains the sole domain
# of packages/mosaic/framework/framework-manifest.txt (Gate A). Do not read any
# ownership meaning into this file.
#
# Format: KEY=VALUE, one per line. '#' and blank lines ignored.

# Component identity + semantic version.
#   0.1.0  W2 — store+drain lib + ack-wrapper.
#   0.2.0  W3 — cumulative-state digest renderer + non-circular HMAC signer.
#   0.3.0  W4 — per-host single-instance delta-gated detector daemon.
#   0.4.0  W5 — synthetic-canary FN-oracle + source-parity reconciler.
#   0.5.0  W6 — off-host dead-man beacon emitter + pluggable alarm-sink adapter
#              + beacon-absence alarm (fail-loud on unconfigured/unreachable).
#   0.6.0  W7 — A10 idempotent, fail-closed component installer (Gate-A
#              intersect+validate against the framework-manifest SSOT), the
#              mosaic-wake.service detector daemon, the blank-reset retire idiom
#              for the legacy heartbeat timer + snapshot-guard, and fail-closed
#              alarm-target/HMAC-key install-validation. Also folds in the two W6
#              monitor-integration observations (monitor-side ingested_ts
#              staleness + beacon HMAC-verify at record).
#   0.6.1  #908 — UNIFY observed_seq on a SINGLE store-side allocator. store.sh
#              enqueue is now the sole allocator (reads its own cursor, next=+1
#              under an exclusive lock, prints the seq; commits IFF the durable
#              write succeeds). The detector-private observed_seq_counter and its
#              --seq hand-off are DELETED; the reconciler enumerates via the same
#              store allocator (its dual-allocator fail-closed guard retired). This
#              dissolves the three defects rooted in the private-counter seam:
#              burn-before-enqueue (arrow 1), W5 co-feed aliasing (arrow 2), and
#              the migration-restart silent-swallow (arrow 3, now structurally
#              impossible — allocation is always > consumed or fails loud).
#   0.6.2  #914 digest.sh renderer fixes (live wake-pilot findings): (a) the
#              embedded ack copy-run line now bakes an explicit
#              WAKE_AGENT=<render-time-agent> prefix (shell-quoted) so an
#              env-less copy-run resolves to the correct per-agent namespace
#              instead of silently falling back to `default`; (b) the
#              ORIENTATION locator renderer now also recognizes the locator
#              vocabulary detector.sh (A1) actually emits for a digest-class
#              entry (kind/id/observed_hash/remote/path), so a digest-class
#              pointer carries a usable (soft) locator instead of rendering
#              empty. Display-only: the ACTIONABLE-tier hard-locator FAIL-LOUD
#              gate (_has_hard_locator, exit 4) is unchanged.
#   0.6.3  #912 digest.sh scrub PORTABILITY (no contract change): _scrub_ctrl's
#              control/bidi/zero-width byte patterns are now LITERAL bytes (via
#              printf %b) instead of GNU-sed `\xNN` hex escapes. BusyBox sed (the
#              Alpine/musl CI runner, running as root) rejects a `\xNN` character
#              range, which aborted the whole scrub sed and silently VOIDED the
#              scrub in CI — collapsing every scrubbed value to empty and failing
#              the digest suite's D1/D4/D5/D6 only in the Woodpecker runner. The
#              scrub now renders byte-identically under GNU sed (glibc dev) and
#              BusyBox sed (Alpine CI). The two-tier trust, exit-4 hard-locator
#              FAIL-LOUD, and the secret-scrub/SHA-preservation contract are all
#              unchanged — this makes the existing scrub deterministic across
#              runners, it does not weaken it.
#   0.6.4  #920 digest.sh drain-quarantine + reconciler-enumeration render tier
#              (live wake-pilot finding #6, BLOCKING). (a) PER-ENTRY
#              QUARANTINE: a render-refused ACTIONABLE entry (no §2.1 hard
#              locator) is now DEAD-LETTERED to $STATE_DIR/dead-letter.jsonl +
#              a loud per-entry alarm and EXCLUDED, while the REST of the
#              cumulative set still renders (exit 0). Replaces the whole-digest
#              exit-4 that let ONE malformed entry wedge the entire drain (head-
#              of-line blocking — 4 consecutive live timer failures, nothing
#              delivered). Fail-loud is preserved, now per-entry; the bad entry
#              is never silently dropped. (b) Reconciler ENUMERATIONS render
#              ORIENTATION-tier: an entry whose locators carry reconciled==true
#              (set only by reconcile.sh) is EXEMPT from the actionable hard-
#              locator gate and renders as an orientation pointer via
#              _locator_line's digest-class vocabulary — a RENDER-layer change
#              only. reconcile.sh's STORE class is UNCHANGED (non-coalescing), so
#              distinct enumerations never collapse (§2.3/T2/G3-R6 intact); the
#              rejected class=digest alternative would have silently coalesced
#              them. store.sh and reconcile.sh are UNCHANGED by 0.6.4.
#   0.6.5  #927 enqueue TOCTOU fix — move stale-tmp cleanup OFF the hot enqueue
#              path (no concurrent in-flight-write clobber). cmd_enqueue called
#              _wake_init_dir() (which reaped EVERY .wake.tmp.* unconditionally)
#              BEFORE taking the enqueue lock, so a 2nd enqueue's PRE-LOCK cleanup
#              deleted the LIVE in-flight tmp of a 1st enqueue holding the lock
#              through its atomic write -> spurious "durable pending write FAILED"
#              abort of a valid enqueue (reachable under live co-feed: detector +
#              reconciler concurrently enqueue). FIX (_wake-common.sh): (a)
#              _wake_init_dir no longer reaps tmps — it only ensures the layout,
#              so nothing on the enqueue/consume/cursors/ack hot paths can clobber
#              a concurrent live write; (b) _wake_clean_stale_tmp is AGE-SCOPED
#              (mmin +${WAKE_TMP_STALE_MIN:-5}) so it can only remove demonstrably-
#              orphaned crash-left tmps, never a live (ms-old) in-flight write.
#              Reaping now runs as an explicit MAINTENANCE action at store.sh init
#              (daemon-start) and the detector poll tick (detector.sh), keeping
#              accumulation bounded once-per-pass instead of raced per-enqueue.
#              #908 seq-integrity is UNCHANGED (single store-side allocator,
#              atomic allocate+enqueue under flock, arrow-1 no-burn, anti-swallow
#              fail-loud). reconcile.sh is UNCHANGED (its enumeration retry is the
#              structural recovery net: an aborted enqueue advances neither the
#              seen-ledger nor observed_seq, so the source is re-enumerated next
#              cycle — no obligation loss). Files changed: _wake-common.sh,
#              store.sh, detector.sh (+ tests).
component=wake
version=0.6.5

# Watch-list schema this component consumes, and the INCLUSIVE range of
# schema_version values it supports. A wake-watch-list.json whose schema_version
# falls outside [schema_min, schema_max] is rejected by the component (fail-loud),
# never silently coerced.
schema=wake-watch-list
schema_min=1
schema_max=1

# Pieces shipped by this component version (informational):
#   store.sh    A2 — three-cursor durable store + drain lib. Stale-tmp reaping is
#                    OFF the hot enqueue path; `init` performs the age-scoped
#                    maintenance reap (#927).                          (W2, #927)
#   ack.sh      A4 — RECEIVED/CONSUMED ack-wrapper (local-write + ship). (W2)
#   digest.sh   A3 — cumulative-state digest renderer (hard locators,
#                    two-tier trust, injection/secret scrub). PER-ENTRY
#                    quarantine: a render-refused entry is dead-lettered +
#                    alarmed + excluded, the rest still renders (no head-of-line
#                    block); reconciler enumerations (reconciled==true) render
#                    ORIENTATION-tier, gate-exempt.                  (W3, #920)
#   sign.sh     A5 — non-circular HMAC signer (independent wake_id,
#                    load_credentials by-name; fills the hmac placeholder). (W3)
#   detector.sh A1 — per-host single-instance delta-gated detector daemon
#                    (flock, anchor-scoped hashing, fail-loud source semantics;
#                    enqueues deltas to store.sh and captures the store-allocated
#                    observed_seq — no private counter, #908). Its poll tick also
#                    runs the age-scoped maintenance stale-tmp reap (#927).     (W4)
#   fn-oracle.sh A6 — synthetic-canary FN-oracle: injects a KNOWN delta at the
#                    source boundary, drives the pipeline through the detector's
#                    public poll-once, asserts CONSUMED within the per-class SLO
#                    (off-domain verdict from the terminal store cursor). §4
#                    requires FN-rate=0; a dropping/disabled detector FAILS.  (W5)
#   reconcile.sh A7 — source-parity reconciler: (i) source-coverage parity
#                    inventory (an omitted source cannot pass the vector
#                    vacuously) + (ii) periodic full reconcile to 0-unaccounted,
#                    enumerating pre-existing/startup state into the store via the
#                    SINGLE store-side allocator (co-feed is safe; the former
#                    dual-allocator fail-closed guard retired, #908).         (W5)
#   beacon.sh   A8 — off-host DEAD-MAN liveness beacon: a monotonic beacon
#                    EMITTER (emit — the primitive the detector run-loop calls
#                    each cycle), the off-host monitor's RECEIVER + beacon-ABSENCE
#                    alarm (record, check), and a pluggable alarm-sink/beacon-sink
#                    ADAPTER INTERFACE. Liveness is SPLIT from work-triggering;
#                    the alarm fires on ABSENCE, routing to a human/other-host
#                    within its SLO (§4/G1). FAIL-CLOSED: an unconfigured OR
#                    unreachable target FAILS LOUD (no silent no-alarm host).
#                    A same-host sibling is REJECTED as non-independent; an
#                    isolated host degrades to a FLAGGED different-supervision-root
#                    beacon; capture-pane is a liveness HINT only.            (W6)
#   wake-install.sh A10 — idempotent, fail-closed COMPONENT installer. Selects the
#                    component file set and INTERSECTS-AND-VALIDATES it against the
#                    single SSOT framework-manifest.txt (Gate A) — this VERSION
#                    manifest authorizes no path. Ships the blank-reset retire
#                    idiom (exactly-one OnUnitActiveUSec) for the legacy heartbeat
#                    timer, the snapshot-guard (no reap without a snapshot), and
#                    fail-closed alarm-target + HMAC-key install-validation (the
#                    installer wires + install-validates the beacon target that
#                    beacon.sh's fail-loud primitive is designed for).           (W7)
# Companion (framework subtree, not under tools/wake/): systemd/user/mosaic-wake.service
#                    — the long-lived detector daemon unit (per-class SLO lives in
#                    the daemon, NOT a systemd interval).                          (W7)
