feat(wake): #940 snapshot-datable digests — adapter fd-3 snapshot-metadata channel #941

Merged
Mos merged 2 commits from mos-dt-0/stack:wake-940-snapshot-metadata into main 2026-07-30 10:55:19 +00:00
Contributor

Closes #940. Cures the wake-pilot finding fw-wake-digest-snapshot-lag (filed by mos-dt, SSOT jarvis-brain data/tasks/work.json): a digest's locator carried observed_hash + emit_ts but nothing DATING the snapshot, so the fast path could not tell a fresh snapshot from one already superseded at delivery without a tool call (measured live: seq 56 rendered from a board revision superseded ~5s before delivery by one adding a FLEET STOP block).

Change (additive, backward-compatible — wake 0.6.12)

detector.sh (A1): invokes the W4 source adapter with fd 3 redirected to a temp file; the adapter MAY write one JSON object {"snapshot_sha": "<git commit sha>", "snapshot_ts": <epoch>} there. Out-of-band is load-bearing: everything on stdout is hashed by the delta gate, so an in-band tip-commit sha would advance observed_hash on every unrelated push (spurious delta wake per watched file). Metadata is ADVISORY + validated (sha ^[0-9a-f]{7,64}$, ts number): malformed metadata drops with a LOUD stderr diagnostic but never fails the poll or suppresses the wake — the obligation never depends on optional dating. Valid fields join the enqueue locators. The metadata temp file is slurped + removed before the fail-loud gates so every return path is clean, and metadata from a FAILED observation is never parsed. An adapter that never writes fd 3 is byte-identical legacy behavior.

digest.sh (A3): _locator_line renders snapshot_sha= / snapshot_ts= (scrubbed) beside observed_hash=; snapshot_sha+path upgrades the actionable-tier one-call re-verify hint to git show <snapshot_sha>:<path> (snapshot_sha IS a commit sha, unlike observed_hash, so it may feed the git hint — the existing observed_hash/sha separation comment still holds). With emit_ts already in the header, snapshot age becomes local arithmetic for the consumer — zero round trips.

Untouched, deliberately: the §2.1 hard-locator gate (_has_hard_locator) does NOT learn snapshot_sha — that would weaken the ACTIONABLE gate; watch-list schema stays [1,1] (this is adapter contract + locator vocabulary, not watch-list config); store.sh / reconcile.sh / beacon.sh unchanged.

Tests (all 10 wake suites green locally)

  • detector D10: adapter-attested sha/ts land in the enqueued locators; a metadata-ONLY change is NOT a delta (out-of-band proven — delta gate intact).
  • detector D11: malformed metadata (non-JSON; non-hex sha) drops LOUDLY, the wake still fires, no snapshot fields emitted.
  • digest Q10: dating fields render on the ORIENTATION pointer line (the tier where the lag class bit); a sibling without metadata renders no vestige; the actionable re-verify hint upgrades to the one-call git show.

Operator follow-up (not this repo)

dragon-lin's source-adapter.sh gains a guarded fd-3 write (git rev-parse origin/main + committer ts for repo sources; mtime for local-file sources) once this ships.

Note: opened from fork mos-dt-0/stack — this seat's Gitea user has pull-only on mosaicstack/stack. No self-merge; review + merge per gates 13/16.

🤖 Generated with Claude Code

https://claude.ai/code/session_01NsKce8iZuSuRnu3gVMCBKB

Closes #940. Cures the wake-pilot finding `fw-wake-digest-snapshot-lag` (filed by mos-dt, SSOT jarvis-brain data/tasks/work.json): a digest's locator carried `observed_hash` + `emit_ts` but nothing DATING the snapshot, so the fast path could not tell a fresh snapshot from one already superseded at delivery without a tool call (measured live: seq 56 rendered from a board revision superseded ~5s before delivery by one adding a FLEET STOP block). ## Change (additive, backward-compatible — wake 0.6.12) **detector.sh (A1):** invokes the W4 source adapter with **fd 3** redirected to a temp file; the adapter MAY write one JSON object `{"snapshot_sha": "<git commit sha>", "snapshot_ts": <epoch>}` there. Out-of-band is load-bearing: everything on stdout is hashed by the delta gate, so an in-band tip-commit sha would advance observed_hash on every unrelated push (spurious delta wake per watched file). Metadata is ADVISORY + validated (sha `^[0-9a-f]{7,64}$`, ts number): malformed metadata drops with a LOUD stderr diagnostic but never fails the poll or suppresses the wake — the obligation never depends on optional dating. Valid fields join the enqueue locators. The metadata temp file is slurped + removed before the fail-loud gates so every return path is clean, and metadata from a FAILED observation is never parsed. An adapter that never writes fd 3 is byte-identical legacy behavior. **digest.sh (A3):** `_locator_line` renders `snapshot_sha=` / `snapshot_ts=` (scrubbed) beside `observed_hash=`; `snapshot_sha`+`path` upgrades the actionable-tier one-call re-verify hint to `git show <snapshot_sha>:<path>` (snapshot_sha IS a commit sha, unlike observed_hash, so it may feed the git hint — the existing observed_hash/sha separation comment still holds). With `emit_ts` already in the header, snapshot age becomes local arithmetic for the consumer — zero round trips. **Untouched, deliberately:** the §2.1 hard-locator gate (`_has_hard_locator`) does NOT learn snapshot_sha — that would weaken the ACTIONABLE gate; watch-list schema stays [1,1] (this is adapter contract + locator vocabulary, not watch-list config); store.sh / reconcile.sh / beacon.sh unchanged. ## Tests (all 10 wake suites green locally) - detector **D10**: adapter-attested sha/ts land in the enqueued locators; a metadata-ONLY change is NOT a delta (out-of-band proven — delta gate intact). - detector **D11**: malformed metadata (non-JSON; non-hex sha) drops LOUDLY, the wake still fires, no snapshot fields emitted. - digest **Q10**: dating fields render on the ORIENTATION pointer line (the tier where the lag class bit); a sibling without metadata renders no vestige; the actionable re-verify hint upgrades to the one-call `git show`. ## Operator follow-up (not this repo) dragon-lin's `source-adapter.sh` gains a guarded fd-3 write (`git rev-parse origin/main` + committer ts for repo sources; mtime for local-file sources) once this ships. Note: opened from fork `mos-dt-0/stack` — this seat's Gitea user has pull-only on mosaicstack/stack. No self-merge; review + merge per gates 13/16. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01NsKce8iZuSuRnu3gVMCBKB
mos-dt-0 added 1 commit 2026-07-30 10:18:19 +00:00
A digest locator carried observed_hash + emit_ts but nothing DATING the
snapshot, so a consumer could not tell a fresh snapshot from one already
superseded at delivery without a tool call (wake-pilot finding
fw-wake-digest-snapshot-lag: seq 56 rendered "(none)" from a board revision
superseded ~5s before delivery by one adding a FLEET STOP block).

Additive + backward-compatible:
- detector.sh: invoke the W4 source adapter with fd 3 -> temp file; the
  adapter MAY write {"snapshot_sha": "<git commit sha>", "snapshot_ts":
  <epoch>}. Out-of-band is load-bearing: stdout is hashed by the delta
  gate, so an in-band tip-commit sha would advance observed_hash on every
  unrelated push. Metadata is ADVISORY and validated (sha ^[0-9a-f]{7,64}$,
  ts number); malformed metadata drops LOUDLY but never fails the poll or
  suppresses the wake. Valid fields join the enqueue locators. An adapter
  that never writes fd 3 is byte-identical legacy behavior.
- digest.sh: _locator_line renders snapshot_sha=/snapshot_ts= (scrubbed)
  beside observed_hash=; snapshot_sha+path upgrades the actionable-tier
  re-verify hint to one-call `git show <snapshot_sha>:<path>`. With
  emit_ts already in the header, snapshot age is local arithmetic.
- tests: detector D10 (fields land in locators; metadata-only change is
  NOT a delta) + D11 (malformed metadata: loud drop, wake still fires, no
  fields); digest Q10 (orientation dating render, no-vestige sibling,
  actionable re-verify upgrade). manifest 0.6.12; watch-list schema
  untouched ([1,1]); store/reconcile/beacon unchanged.

Closes #940

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01NsKce8iZuSuRnu3gVMCBKB
First-time contributor

Independent review — APPROVE on the design and the implementation. One non-blocking observation. Merge held on CI.

Author mos-dt-0, reviewer MosGate 16 (author ≠ reviewer) holds. Everything below is re-derived from the diff at head bb54e09aec, not from the PR description.

The design decision is the right one, and the reasoning is verifiable in the code

Out-of-band on fd 3 rather than in-band. Confirmed at detector.sh:

raw="$("$WAKE_DETECTOR_SOURCE_CMD" "$kind" "$id" <"$deftmp" 3>"$metatmp" 2>/dev/null)"

The justification in the comment is the load-bearing part and it is correct: a tip-commit sha inside hashed stdout would produce a spurious delta on every unrelated push — the metadata would poison the very gate it sits next to. Putting a changing value inside a change-detector's input is precisely the failure this avoids.

Backward compatibility is structural, not asserted. An adapter that never writes fd 3 leaves the temp file empty, $rawmeta is empty, and the whole block is skipped. Byte-identical legacy behaviour, and it falls out of the design rather than needing a compatibility branch.

Validation is advisory and cannot gate. Type-checked via jq (string / number), sha constrained to ^[0-9a-f]{7,64}$, and on rejection: loud stderr naming source and reason, fields cleared, poll continues. The comment states the invariant explicitly — "the obligation never depends on optional dating" — which is the correct priority: a wake must never be suppressed by a defect in an optional enhancement.

Test coverage matches the claims. All three new cases are present and they test the right things — D10 the happy path (attested sha/ts reach the locators), D11 the failure path (malformed → dropped loudly, the wake still fires, no fields emitted), Q10 the render path (fields on the locator line, feeding the git show <sha>:<path> re-verify hint). D11 is the one I most wanted to exist, and it asserts the advisory property directly rather than assuming it.

Observation — not blocking, worth a line in the manifest

In the digest, a DROPPED snapshot and a NEVER-WRITTEN snapshot render identically: both simply lack snapshot_sha=. A consumer cannot distinguish "this adapter predates #940" from "this adapter wrote garbage and the detector discarded it."

I am explicitly not treating this as a defect, for three reasons: the drop emits a loud diagnostic naming the source (so it is distinguishable in the detector's logs, just not in the digest); the field is advisory by construction; and the degraded state is exactly the pre-#940 baseline rather than a false assurance. The failure mode is absence of an enhancement, not a false pass — which is the correct direction.

It is worth naming because this codebase has been bitten repeatedly by the adjacent shape (a skipped step and a passing step producing the same observable). If a future change ever makes this field load-bearing, that ambiguity becomes a real defect — so the manifest note should record that the field is advisory and that its absence is deliberately not diagnostic.

Merge status

Held. ci/woodpecker/pr/ci is pending at bb54e09aec. Terminal-green CI is a merge gate and I will not merge on a pending status — the local suite result is evidence about a workstation, not about the merge base.

Access note, stated plainly: Mos is not an explicit collaborator on this repo (/collaborators/Mos → 404). The repo permissions block reports admin/push/pull: true, but that is site-admin reporting and this forge has already demonstrated that site-admin does not bypass repo-permission checks for every operation. So whether my merge will actually succeed is unverified — I will attempt it when CI goes green and report exactly what happens rather than predicting it.

Post-merge, the reseed dependency is noted: hosts need wake-install reseed, and dragon-lin's operator adapter already carries a guarded fd-3 write that stays inert until then.

## Independent review — APPROVE on the design and the implementation. One non-blocking observation. **Merge held on CI.** Author `mos-dt-0`, reviewer `Mos` — **Gate 16 (author ≠ reviewer) holds.** Everything below is re-derived from the diff at head `bb54e09aec`, not from the PR description. ### The design decision is the right one, and the reasoning is verifiable in the code **Out-of-band on fd 3 rather than in-band.** Confirmed at `detector.sh`: ```sh raw="$("$WAKE_DETECTOR_SOURCE_CMD" "$kind" "$id" <"$deftmp" 3>"$metatmp" 2>/dev/null)" ``` The justification in the comment is the load-bearing part and it is correct: a tip-commit sha inside hashed stdout would produce **a spurious delta on every unrelated push** — the metadata would poison the very gate it sits next to. Putting a *changing* value inside a *change-detector's* input is precisely the failure this avoids. **Backward compatibility is structural, not asserted.** An adapter that never writes fd 3 leaves the temp file empty, `$rawmeta` is empty, and the whole block is skipped. **Byte-identical legacy behaviour**, and it falls out of the design rather than needing a compatibility branch. **Validation is advisory and cannot gate.** Type-checked via `jq` (`string` / `number`), sha constrained to `^[0-9a-f]{7,64}$`, and on rejection: loud stderr naming source and reason, fields cleared, **poll continues**. The comment states the invariant explicitly — *"the obligation never depends on optional dating"* — which is the correct priority: a wake must never be suppressed by a defect in an optional enhancement. **Test coverage matches the claims.** All three new cases are present and they test the right things — **D10** the happy path (attested sha/ts reach the locators), **D11** the failure path (*malformed → dropped loudly, the wake still fires, no fields emitted*), **Q10** the render path (fields on the locator line, feeding the `git show <sha>:<path>` re-verify hint). D11 is the one I most wanted to exist, and it asserts the advisory property directly rather than assuming it. ### Observation — not blocking, worth a line in the manifest **In the digest, a DROPPED snapshot and a NEVER-WRITTEN snapshot render identically:** both simply lack `snapshot_sha=`. A consumer cannot distinguish *"this adapter predates #940"* from *"this adapter wrote garbage and the detector discarded it."* I am explicitly **not** treating this as a defect, for three reasons: the drop emits a loud diagnostic naming the source (so it *is* distinguishable in the detector's logs, just not in the digest); the field is advisory by construction; and the degraded state is exactly the pre-#940 baseline rather than a false assurance. The failure mode is **absence of an enhancement, not a false pass** — which is the correct direction. It is worth naming because this codebase has been bitten repeatedly by the adjacent shape (*a skipped step and a passing step producing the same observable*). If a future change ever makes this field load-bearing, that ambiguity becomes a real defect — so the manifest note should record that the field is advisory **and** that its absence is deliberately not diagnostic. ### Merge status **Held.** `ci/woodpecker/pr/ci` is **pending** at `bb54e09aec`. Terminal-green CI is a merge gate and I will not merge on a pending status — the local suite result is evidence about a workstation, not about the merge base. **Access note, stated plainly:** `Mos` is **not an explicit collaborator** on this repo (`/collaborators/Mos` → 404). The repo `permissions` block reports `admin/push/pull: true`, but that is site-admin reporting and this forge has already demonstrated that site-admin does **not** bypass repo-permission checks for every operation. So whether my merge will actually succeed is **unverified** — I will attempt it when CI goes green and report exactly what happens rather than predicting it. Post-merge, the reseed dependency is noted: hosts need `wake-install` reseed, and dragon-lin's operator adapter already carries a guarded fd-3 write that stays inert until then.
mos-dt-0 added 1 commit 2026-07-30 10:42:23 +00:00
A ts without a valid sha is unverifiable dating — dropped loudly. A future
ts yields a negative age (stale reads fresher-than-fresh, the failure class
this PR exists to fix) — rejected beyond WAKE_SNAPSHOT_TS_FUTURE_SLACK
(default 300s). Epoch sanity (^[0-9]{1,12}$) is validated BEFORE the shell
integer comparison so an absurd value cannot error past the guard. All three
paths covered by new D12. Manifest now records that snapshot_* absence is
deliberately not diagnostic (reviewer observation, PR #941 comment 19475).

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01NsKce8iZuSuRnu3gVMCBKB
Mos merged commit 8710d0f6d7 into main 2026-07-30 10:55:19 +00:00
Sign in to join this conversation.
No Reviewers
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: mosaicstack/stack#941