diff --git a/docs/scratchpads/1043-pane-git-identity.md b/docs/scratchpads/1043-pane-git-identity.md index 31da1dc7..8e54df07 100644 --- a/docs/scratchpads/1043-pane-git-identity.md +++ b/docs/scratchpads/1043-pane-git-identity.md @@ -192,6 +192,37 @@ This is the third GNU-host/Alpine-CI portability defect in the lane: GNU `grep` - Workflow definition population: **1/3 pull-request-eligible** (`ci.yml` of `ci.yml`, `ci-image.yml`, `publish.yml`). - Do not re-litigate the settled 311/312 populations; both are valid for their separately named Tess6 and CRUD-core7 sets. +## Round 4 — bound stale-marker observation + +### Objective and plan + +- Make the heartbeat assertion discriminate an initially stale native marker from a fresh marker without changing the production staleness threshold or shortening the polling window. +- Freeze only the sidecar's numeric observation clock during the stale-fixture arm so elapsed assertion time cannot turn a fresh mutant stale. +- Prove two independent mutants RED: disable production stale-marker detection while retaining the stale fixture; replace the stale fixture with a fresh marker. Restore the tree and prove GREEN in the canonical Alpine image. +- Re-derive the changed-path inventory, run applicable quality and independent review gates, commit with environment-only author/committer identity, queue-guard, push once, verify provider attribution using curl stdin config, and stop without CI polling. +- Working budget: 8K tokens. Scope is the launcher test and its scratchpad evidence; production launcher behavior remains unchanged. + +### Root cause and bounded observation + +The 30 × 0.1-second assertion window overlaps the production `now - marker > interval * 2 + 1` threshold at interval 1. Depending on second boundaries and load, a fresh marker can age past the threshold before the assertion ends. A focused pre-fix fresh-mutant attempt returned RED while Review 101's full-suite run returned GREEN; the differing result is itself timing dependence, not a discriminating assertion. + +The test now supplies a fixed numeric epoch only to the stale-fixture sidecar. Its real marker mtime is still read from the filesystem, but assertion runtime cannot advance `now`. Date formatting still delegates to the image's real `/bin/date`. Neither the production threshold nor the 30 × 0.1-second polling window changed. + +### Two-mutant RED / restored GREEN + +All three runs used `git.mosaicstack.dev/mosaicstack/stack/ci-base:latest`: + +1. **Stale-detection mutant RED:** replaced only the production stale-age predicate with `false` while retaining the fixed stale marker; suite exit 1 with `FAIL: heartbeat sidecar did not resume after native marker became stale or absent`. +2. **Fresh-marker mutant RED:** replaced only `touch -t 200001010000.00` with fresh `touch`; suite exit 1 with the same failed stale-resumption assertion. The fixed observation epoch kept the mutant fresh throughout all 30 polls. +3. **Restored tree GREEN:** suite exit 0 with `ok - start-agent-session generated environment boundary`. + +### Re-derived inventory + +- Round-4 delta: **2/2 files** — launcher test plus task scratchpad; production launcher delta is empty. +- Full PR inventory against `origin/main`: **19/19 paths**; Round 4 adds no path. +- Production stale threshold remains `now - marker > iv * 2 + 1`; assertion polling remains 30 × 0.1 seconds. +- Review 101's confirmed enumeration/workflow/CI and attribution evidence is accepted without re-polling or re-derivation. + ## Residual risk - Landing on `main` does not update the currently installed host launcher. Host framework installation/reseed and Jarvis live-seat validation are separate downstream events. diff --git a/packages/mosaic/framework/tools/fleet/test-start-agent-session.sh b/packages/mosaic/framework/tools/fleet/test-start-agent-session.sh index 4e9dfc1f..6775f13e 100755 --- a/packages/mosaic/framework/tools/fleet/test-start-agent-session.sh +++ b/packages/mosaic/framework/tools/fleet/test-start-agent-session.sh @@ -62,6 +62,19 @@ env -0 > "${MOSAIC_HOME:?}/fleet/pane-environment" SHIM chmod +x "$FAKE_BIN/mosaic" +# Freeze numeric epoch reads only when a test arm supplies an observation bound. +# Formatting reads still use the real BusyBox/POSIX date implementation. +cat > "$FAKE_BIN/date" <<'SHIM' +#!/usr/bin/env bash +set -euo pipefail +if [ -n "${MOSAIC_TEST_FIXED_EPOCH:-}" ] && [ "${1:-}" = '+%s' ]; then + printf '%s\n' "$MOSAIC_TEST_FIXED_EPOCH" + exit 0 +fi +exec /bin/date "$@" +SHIM +chmod +x "$FAKE_BIN/date" + write_generated() { local home="$1" local agent="$2" @@ -89,6 +102,7 @@ run_start() { local agent="$2" HOME="$home" PATH="$FAKE_BIN:$PATH" MOSAIC_TEST_TMUX_CALLS="$TMUX_CALLS" \ MOSAIC_TEST_PANE_PID="${MOSAIC_TEST_PANE_PID:-}" \ + MOSAIC_TEST_FIXED_EPOCH="${MOSAIC_TEST_FIXED_EPOCH:-}" \ MOSAIC_TEST_HOME="$home" \ MOSAIC_TEST_FLEET_OWNER=123e4567-e89b-12d3-a456-426614174000 \ MOSAIC_HOME="$home" "$START" "$agent" @@ -403,7 +417,11 @@ write_heartbeat_local "$HOME_NATIVE_STALE" "coder-native-stale" STALE_HB="$HOME_NATIVE_STALE/run/coder-native-stale.hb" printf 'ts=native\npid=1\nstatus=busy\nmodel=stale-model\n' > "$STALE_HB" touch -t 200001010000.00 "$STALE_HB.native" -MOSAIC_TEST_PANE_PID=$$ run_start "$HOME_NATIVE_STALE" coder-native-stale +# Hold the sidecar's observation epoch constant: assertion runtime must not age +# a fresh-marker mutant into the stale state that this fixture must distinguish. +STALE_OBSERVATION_EPOCH=$(date +%s) +MOSAIC_TEST_FIXED_EPOCH="$STALE_OBSERVATION_EPOCH" \ + MOSAIC_TEST_PANE_PID=$$ run_start "$HOME_NATIVE_STALE" coder-native-stale wait_for_sidecar_status "$STALE_HB" HOME_NATIVE_ABSENT="$ROOT/native-absent"