General-purpose coding policy for Baruch's AI agents
73
91%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Low
Low-risk findings worth noting
#!/usr/bin/env bash
# Outcome-based tests for check-git-sync.sh.
#
# The hook shells out to real git, so tests build real local repos (a bare
# "origin" plus working clones) and drive git offline — no network, fully
# deterministic. The injected clock (SYNC_NOW) drives the throttle assertions.
#
# Each scenario builds its OWN bare origin + seed (mk_origin) so scenarios share
# no mutable state and run in any order (rules/testing-standards.md Independence).
# The harness drops `set -e` to aggregate results, so every fixture-setup command
# is checked explicitly and aborts with a fatal diagnostic on failure
# (rules/error-handling.md aggregate-reporting carve-out).
#
# Covers:
# 1. Behind -> fast-forwards the default branch (on it or off it); a
# Herdr worker only reports; a refused fast-forward reports.
# 2. Up to date -> emits a marker "in sync" status, exit 0.
# 3. Throttle -> with a fixed injected clock: a call inside the window
# skips the fetch and reports "not verified" (never a
# definitive "in sync"/"behind" against the stale ref); a
# call past the window fetches and fires "behind".
# 4. Not a repo -> silent no-op, exit 0.
# 5. No origin -> silent no-op, exit 0.
# 6. Fetch failure -> marker "not verified" (never a false "in sync" against a
# stale ref), exit 0 (offline/broken remote tolerated).
# 7. Bad clock -> silent no-op, exit 0 (never aborts SessionStart).
# 8. Diverged -> marker notice names divergence and recommends rebase, not
# a fast-forward (local both ahead and behind origin).
# 10. Worker fetch -> a Herdr worker session leaves refs/remotes/origin/*
# unchanged while origin has moved; the foreman fetches.
# 11. Role unknown -> HERDR_ENV set and the role probes fail (git shim): no
# fetch (refs unchanged) and a sync-not-verified notice.
# 12. Empty HERDR_ENV -> set-but-empty still marks Herdr: a linked worktree
# does not fetch.
# 13. Portable worktree -> SESSION_START_MODE=portable in a linked worktree
# (env stripped by tessl): no fetch, sync not verified.
# 9. Future stamp -> a schema_version > 1 record is not throttled on and is
# preserved (not downgraded to version 1).
#
# Run: bash hooks/tests/test_check_git_sync.sh
set -uo pipefail
die() { echo "fatal: $*" >&2; exit 2; }
# 0 when <a> and <b> name the same commit in <repo>, 1 when they differ. Called
# in the harness's own shell, never in $(...): a ref that does not resolve stops
# the harness, so an unresolved ref can never read as "different".
same_commit() { # <repo> <a> <b>
local x y
x="$(git -C "$1" rev-parse --verify --quiet "$2^{commit}")" || die "cannot resolve $2 in $1"
y="$(git -C "$1" rev-parse --verify --quiet "$3^{commit}")" || die "cannot resolve $3 in $1"
[[ "$x" == "$y" ]]
}
cleanup() { [[ -n "${TMP:-}" ]] && ! rm -rf "$TMP" && echo "warn: could not remove $TMP" >&2; return 0; }
g() { git "$@"; }
commit_push() { # <clone-dir> <message>
local dir="$1" msg="$2"
printf '%s\n' "$msg" >> "$dir/f" || die "commit_push: write to $dir/f failed"
g -C "$dir" add f || die "commit_push: git add failed in $dir"
g -C "$dir" commit -q -m "$msg" || die "commit_push: git commit failed in $dir"
g -C "$dir" push -q origin main || die "commit_push: git push from $dir failed"
}
mk_origin() { # <prefix>: sets globals BARE, SEED to a fresh, independent origin
local prefix="$1"
BARE="$TMP/${prefix}.git"; SEED="$TMP/${prefix}-seed"
g init -q --bare -b main "$BARE" || die "mk_origin: git init --bare failed for $BARE"
g clone -q "$BARE" "$SEED" 2>/dev/null || die "mk_origin: git clone failed for $SEED"
g -C "$SEED" symbolic-ref HEAD refs/heads/main || die "mk_origin: git symbolic-ref failed in $SEED"
commit_push "$SEED" "c1"
}
clone_from() { # <bare> <dest>: a working clone, checked explicitly
g clone -q "$1" "$2" || die "clone_from: git clone $1 -> $2 failed"
}
# run <repo-dir> <state-dir> [extra env...] -> OUT, RC
run() {
local repo="$1" state="$2"; shift 2
# Scrub the ambient HERDR_ENV so a suite run from a Herdr pane still sees
# the non-Herdr cases as non-Herdr; a case opts in by passing it in "$@".
OUT="$(cd "$repo" && env -u HERDR_ENV SYNC_STATE_DIR="$state" "$@" bash "$SCRIPT" </dev/null 2>/dev/null)"
RC=$?
}
pass() { PASS=$((PASS+1)); }
fail() { FAIL=$((FAIL+1)); echo " ✗ FAIL: $1" >&2; }
main() {
SCRIPT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)/check-git-sync.sh"
[[ -f "$SCRIPT" && -r "$SCRIPT" ]] || die "hook not found/readable at $SCRIPT"
command -v jq >/dev/null 2>&1 || die "jq required for these tests"
command -v git >/dev/null 2>&1 || die "git required for these tests"
TMP="$(mktemp -d -t git-sync-test.XXXXXX)" || die "mktemp failed"
trap cleanup EXIT
# Isolate git from the operator's global/system config so identity and defaults
# are deterministic across machines. This isolation is load-bearing — an
# unchecked mkdir failure would silently defeat it, so guard it explicitly.
export HOME="$TMP/home"
mkdir -p "$HOME" || die "could not create isolated HOME at $HOME"
export GIT_CONFIG_NOSYSTEM=1
export GIT_AUTHOR_NAME=t GIT_AUTHOR_EMAIL=t@t GIT_COMMITTER_NAME=t GIT_COMMITTER_EMAIL=t@t
# An ambient HERDR_ENV, as when the suite runs from a Herdr pane: every
# non-Herdr case now depends on run's scrub, and each Herdr case sets its own.
export HERDR_ENV=1
FAIL=0; PASS=0
# 1. Behind, read first from a linked worktree with HERDR_ENV set -- a Herdr
# worker. The shared checkout is the foreman's (skills/herdr-foreman/references/team-operation.md
# Writers and Checkouts), so the hook reports the drift and moves nothing.
mk_origin o1
clone_from "$BARE" "$TMP/r1"
commit_push "$SEED" "c2"
# The foreman's earlier fetch: the worker reads drift from these refs as-is.
git -C "$TMP/r1" fetch -q origin || die "r1 fetch failed"
git -C "$TMP/r1" worktree add -q "$TMP/r1-wt" -b feat/worker >/dev/null 2>&1 \
|| die "r1 worktree add failed"
run "$TMP/r1-wt" "$TMP/s1b" HERDR_ENV=1
if [[ $RC -eq 0 ]] && printf '%s' "$OUT" | jq -e '.additionalContext | test("Herdr worker session") and test("1 behind") and test("Do not sync") and (test("fast-forward") | not)' >/dev/null 2>&1 \
&& ! same_commit "$TMP/r1" main origin/main; then
pass; else fail "worker session: expected a no-sync notice and main unmoved, got RC=$RC OUT=$OUT"; fi
# 1b. The same drift from the MAIN checkout (on main) is the foreman or a
# standalone agent: the hook fast-forwards main and says so, without running
# the repo's own post-merge hook.
printf '#!/bin/sh\ntouch "%s"\n' "$TMP/post-merge-ran" > "$TMP/r1/.git/hooks/post-merge" \
|| die "could not write the post-merge hook"
chmod +x "$TMP/r1/.git/hooks/post-merge" || die "could not make the post-merge hook executable"
run "$TMP/r1" "$TMP/s1c" HERDR_ENV=1
if [[ $RC -eq 0 ]] && printf '%s' "$OUT" | jq -e '.additionalContext | test("Session-start status") and test("fast-forwarded local `main` by 1")' >/dev/null 2>&1 \
&& same_commit "$TMP/r1" main origin/main \
&& [[ ! -e "$TMP/post-merge-ran" ]]; then
pass; else fail "behind on main: expected a fast-forward with no repo hook run, got RC=$RC OUT=$OUT"; fi
# 1e. Behind under tessl (session-start portable mode): report, never move.
mk_origin o1e
clone_from "$BARE" "$TMP/r1e"
commit_push "$SEED" "c2"
run "$TMP/r1e" "$TMP/s1f" SESSION_START_MODE=portable
if [[ $RC -eq 0 ]] && printf '%s' "$OUT" | jq -e '.additionalContext | test("not fast-forwarded here")' >/dev/null 2>&1 \
&& ! same_commit "$TMP/r1e" main origin/main; then
pass; else fail "portable: expected a report and main unmoved, got RC=$RC OUT=$OUT"; fi
# 1f. The fetch never runs repo code: a reference-transaction hook, which a
# ref-updating fetch triggers, leaves no marker.
mk_origin o1f
clone_from "$BARE" "$TMP/r1f"
commit_push "$SEED" "c2"
printf '#!/bin/sh\ntouch "%s"\n' "$TMP/sync-ref-hook-ran" > "$TMP/r1f/.git/hooks/reference-transaction" \
|| die "could not write the reference-transaction hook"
chmod +x "$TMP/r1f/.git/hooks/reference-transaction" || die "could not make the hook executable"
run "$TMP/r1f" "$TMP/s1g"
if [[ $RC -eq 0 && ! -e "$TMP/sync-ref-hook-ran" ]]; then
pass; else fail "repo hooks: the reference-transaction hook ran during the sync fetch or fast-forward (OUT=$OUT)"; fi
# 1c. Behind while a feature branch is checked out: main moves without a
# checkout, and the feature branch is untouched.
mk_origin o1c
clone_from "$BARE" "$TMP/r1c"
git -C "$TMP/r1c" checkout -q -b feat/x || die "r1c checkout failed"
commit_push "$SEED" "c2"
run "$TMP/r1c" "$TMP/s1d"
if [[ $RC -eq 0 ]] && printf '%s' "$OUT" | jq -e '.additionalContext | test("fast-forwarded")' >/dev/null 2>&1 \
&& same_commit "$TMP/r1c" main origin/main \
&& [[ "$(git -C "$TMP/r1c" symbolic-ref --short HEAD)" == "feat/x" ]]; then
pass; else fail "behind off main: expected main fast-forwarded in place, got RC=$RC OUT=$OUT"; fi
# 1d. Behind on main with a local edit the incoming commit would overwrite:
# git refuses, the hook reports it, and the edit survives.
mk_origin o1d
clone_from "$BARE" "$TMP/r1d"
printf 'local edit\n' >> "$TMP/r1d/f" || die "r1d edit failed"
commit_push "$SEED" "c2"
run "$TMP/r1d" "$TMP/s1e"
if [[ $RC -eq 0 ]] && printf '%s' "$OUT" | jq -e '.additionalContext | test("fast-forward was refused")' >/dev/null 2>&1 \
&& grep -q "local edit" "$TMP/r1d/f" \
&& ! same_commit "$TMP/r1d" main origin/main; then
pass; else fail "refused fast-forward: expected a report and the edit kept, got RC=$RC OUT=$OUT"; fi
# 2. up to date -> marker "in sync" status.
mk_origin o2
clone_from "$BARE" "$TMP/r2"
run "$TMP/r2" "$TMP/s2"
if [[ $RC -eq 0 ]] && printf '%s' "$OUT" | jq -e '.additionalContext | test("Session-start status") and test("in sync")' >/dev/null 2>&1; then
pass; else fail "up-to-date: expected in-sync status, got RC=$RC OUT=$OUT"; fi
# 2b. ahead only -> "ahead ... unpushed", never "in sync" (ahead>0, behind==0).
# Clone up to date, add a local commit without pushing; origin unchanged.
mk_origin o2b
clone_from "$BARE" "$TMP/r2b"
g -C "$TMP/r2b" commit -q --allow-empty -m "local ahead" || die "git commit in r2b failed"
run "$TMP/r2b" "$TMP/s2b"
if [[ $RC -eq 0 ]] && printf '%s' "$OUT" | jq -e '.additionalContext | test("Session-start status") and test("ahead") and (test("in sync") | not)' >/dev/null 2>&1; then
pass; else fail "ahead-only: expected \"ahead\" (not \"in sync\"), got RC=$RC OUT=$OUT"; fi
# 3. throttle. Clone up to date. First call fetches, stamps, and reports a
# definitive "in sync". Move origin ahead WITHOUT the hook fetching: a call
# +60s is throttled, so it does not fetch and reports "not verified" (never
# a definitive "in sync"/"behind" against a stale ref). A call past the 1h
# window fetches the new commit and fires "behind".
mk_origin o3
clone_from "$BARE" "$TMP/r3"
run "$TMP/r3" "$TMP/s3" SYNC_THROTTLE_HOURS=1 SYNC_NOW=2000000 # fetch, stamp, up to date -> in sync
# This establishes the throttle stamp the next two assertions depend on, so a
# failure here must abort, not merely tally (aggregate-reporting carve-out:
# later checks may not depend on an earlier one merely having incremented FAIL).
{ [[ $RC -eq 0 ]] && printf '%s' "$OUT" | jq -e '.additionalContext | test("in sync")' >/dev/null 2>&1; } \
|| die "throttle setup: first call should report in sync, got RC=$RC OUT=$OUT"
commit_push "$SEED" "c3" # origin moves; r3's tracking ref still old
run "$TMP/r3" "$TMP/s3" SYNC_THROTTLE_HOURS=1 SYNC_NOW=2000060 # +60s: throttled -> no fetch -> not verified
if [[ $RC -eq 0 ]] && printf '%s' "$OUT" | jq -e '.additionalContext | test("Session-start status") and test("not verified") and (test("in sync") | not) and (test("behind") | not)' >/dev/null 2>&1; then
pass; else fail "throttle active: inside window should report 'not verified' (not 'in sync'/'behind'), got OUT=$OUT"; fi
run "$TMP/r3" "$TMP/s3" SYNC_THROTTLE_HOURS=1 SYNC_NOW=2003601 # +>1h: fetch -> behind -> fast-forwards
if [[ $RC -eq 0 ]] && printf '%s' "$OUT" | jq -e '.additionalContext | test("fast-forwarded")' >/dev/null 2>&1; then
pass; else fail "throttle expired: past window should fetch and fire, got OUT=$OUT"; fi
# 3b. By default the hook fetches every session: a recent stamp does not stop
# it, so origin moving is seen and fast-forwarded, never "not verified".
mk_origin o3b
clone_from "$BARE" "$TMP/r3b"
run "$TMP/r3b" "$TMP/s3b" SYNC_NOW=2000000
commit_push "$SEED" "c2"
run "$TMP/r3b" "$TMP/s3b" SYNC_NOW=2000060
if [[ $RC -eq 0 ]] && printf '%s' "$OUT" | jq -e '.additionalContext | test("fast-forwarded")' >/dev/null 2>&1; then
pass; else fail "default: expected a fetch every session, got OUT=$OUT"; fi
# 4. not a repo -> silent no-op.
mkdir -p "$TMP/notrepo" || die "could not create $TMP/notrepo"
run "$TMP/notrepo" "$TMP/s4"
if [[ $RC -eq 0 && -z "$OUT" ]]; then pass; else fail "not a repo: expected silent exit 0, got RC=$RC OUT=$OUT"; fi
# 5. no origin remote -> silent no-op.
g init -q -b main "$TMP/noorigin" || die "git init noorigin failed"
printf 'x\n' > "$TMP/noorigin/f" || die "write noorigin/f failed"
g -C "$TMP/noorigin" add f || die "git add in noorigin failed"
g -C "$TMP/noorigin" commit -q -m x || die "git commit in noorigin failed"
run "$TMP/noorigin" "$TMP/s5"
if [[ $RC -eq 0 && -z "$OUT" ]]; then pass; else fail "no origin: expected silent exit 0, got RC=$RC OUT=$OUT"; fi
# 6. fetch failure -> "not verified" (broken remote tolerated, no crash, and
# never a false "in sync" against a stale ref — sync-before-work). Clone,
# then delete the bare origin so the fetch fails; the hook reports
# not-verified and exits 0 without crashing.
mk_origin o6
clone_from "$BARE" "$TMP/r6"
rm -rf "$BARE" || die "could not remove $BARE"
run "$TMP/r6" "$TMP/s6"
if [[ $RC -eq 0 ]] && printf '%s' "$OUT" | jq -e '.additionalContext | test("Session-start status") and test("not verified") and (test("in sync") | not)' >/dev/null 2>&1; then
pass; else fail "fetch failure: expected 'not verified' (not 'in sync') exit 0, got RC=$RC OUT=$OUT"; fi
# 7. malformed clock -> no-op, exit 0.
mk_origin o7
clone_from "$BARE" "$TMP/r7"
run "$TMP/r7" "$TMP/s7" SYNC_NOW="not-a-number"
if [[ $RC -eq 0 && -z "$OUT" ]]; then pass; else fail "bad clock: expected silent exit 0, got RC=$RC OUT=$OUT"; fi
# 8. diverged -> divergence notice (rebase, not fast-forward). Clone, add a
# local commit (ahead by 1), and push a different commit to origin (behind
# by 1); the hook fetches and reports the diverged state.
mk_origin o8
clone_from "$BARE" "$TMP/r8"
printf 'local\n' >> "$TMP/r8/f" || die "write r8/f failed"
g -C "$TMP/r8" add f || die "git add in r8 failed"
g -C "$TMP/r8" commit -q -m local || die "git commit in r8 failed" # ahead by 1
commit_push "$SEED" "c2" # origin moves -> behind by 1
run "$TMP/r8" "$TMP/s8"
if [[ $RC -eq 0 ]] && printf '%s' "$OUT" | jq -e '.additionalContext | test("Session-start status") and test("diverged") and test("rebase")' >/dev/null 2>&1; then
pass; else fail "diverged: expected marker divergence notice, got RC=$RC OUT=$OUT"; fi
# 9. future-version throttle stamp -> not throttled on, and preserved (never
# downgraded). Pre-seed a "2 <recent>" record at the stamp path the hook
# derives (cksum of the repo toplevel), move origin ahead, and run inside
# the window: a v1 stamp would throttle to silence, but the future record
# must be ignored (the hook fires) and left untouched.
mk_origin o9
clone_from "$BARE" "$TMP/r9"
commit_push "$SEED" "c2" # origin ahead -> a non-throttled run fires
local top9 key9 stampdir9 sv9
top9="$(cd "$TMP/r9" && git rev-parse --show-toplevel)" || die "r9 toplevel failed"
key9="$(printf '%s' "$top9" | cksum | cut -d' ' -f1)" || die "r9 key derivation failed"
stampdir9="$TMP/s9"
mkdir -p "$stampdir9" || die "could not create $stampdir9"
printf '2 %s\n' 2000000 > "$stampdir9/sync-$key9" || die "could not seed future stamp"
run "$TMP/r9" "$stampdir9" SYNC_THROTTLE_HOURS=1 SYNC_NOW=2000060 # within window, but future schema
if [[ $RC -eq 0 ]] && printf '%s' "$OUT" | jq -e '.additionalContext | test("fast-forwarded")' >/dev/null 2>&1; then
pass; else fail "future stamp: expected fire (not throttled), got RC=$RC OUT=$OUT"; fi
sv9=""; read -r sv9 _ < "$stampdir9/sync-$key9" || sv9=""
if [[ "$sv9" == "2" ]]; then pass; else fail "future stamp: expected preserved version 2, got '$sv9'"; fi
# 10. A Herdr worker never fetches: the remote-tracking refs are shared with
# the foreman's checkout. Origin moves, the worker session runs, and
# refs/remotes/origin/* is byte-for-byte what it was; the notice still
# tells the worker not to sync. The foreman in the main checkout then
# fetches and sees the new tip.
mk_origin o10
clone_from "$BARE" "$TMP/r10"
git -C "$TMP/r10" worktree add -q "$TMP/r10-wt" -b feat/worker >/dev/null 2>&1 \
|| die "r10 worktree add failed"
commit_push "$SEED" "c2"
local refs10_before refs10_after refs10_foreman seed10 tip10
refs10_before="$(git -C "$TMP/r10" for-each-ref refs/remotes/origin)" || die "r10 for-each-ref (before) failed"
[[ -n "$refs10_before" ]] || die "r10 has no refs/remotes/origin refs to compare"
run "$TMP/r10-wt" "$TMP/s10" HERDR_ENV=1
refs10_after="$(git -C "$TMP/r10" for-each-ref refs/remotes/origin)" || die "r10 for-each-ref (after worker) failed"
if [[ "$refs10_before" == "$refs10_after" ]]; then
pass; else fail "worker fetch: refs/remotes/origin changed in a worker session (before=$refs10_before after=$refs10_after)"; fi
if [[ $RC -eq 0 ]] && printf '%s' "$OUT" | jq -e '.additionalContext | test("Herdr worker session") and test("does not fetch") and test("Do not sync")' >/dev/null 2>&1; then
pass; else fail "worker fetch: expected the no-fetch worker notice, got RC=$RC OUT=$OUT"; fi
run "$TMP/r10" "$TMP/s10f" HERDR_ENV=1
refs10_foreman="$(git -C "$TMP/r10" for-each-ref refs/remotes/origin)" || die "r10 for-each-ref (after foreman) failed"
seed10="$(git -C "$SEED" rev-parse --verify --quiet 'main^{commit}')" || die "cannot resolve main in $SEED"
tip10="$(git -C "$TMP/r10" rev-parse --verify --quiet 'origin/main^{commit}')" || die "cannot resolve origin/main in r10"
if [[ $RC -eq 0 && "$refs10_foreman" != "$refs10_before" && "$tip10" == "$seed10" ]]; then
pass; else fail "foreman fetch: expected the main checkout to fetch the moved origin, got RC=$RC OUT=$OUT"; fi
# 11. HERDR_ENV set but the role probes fail: the session may be a worker,
# so the hook neither fetches nor fast-forwards, and says how to
# diagnose. A git shim on PATH fails only the two role probes.
mk_origin o11
clone_from "$BARE" "$TMP/r11"
commit_push "$SEED" "c2"
local realgit refs11_before refs11_after main11_before main11_after
realgit="$(command -v git)" || die "cannot locate git"
mkdir -p "$TMP/shim11" || die "could not create $TMP/shim11"
# shellcheck disable=SC2016 # the shim's own "$@"/"$a" must stay literal in its source
printf '#!/usr/bin/env bash\nfor a in "$@"; do case "$a" in --absolute-git-dir|--git-common-dir) echo "shim: role probe refused" >&2; exit 1 ;; esac; done\nexec %q "$@"\n' "$realgit" > "$TMP/shim11/git" \
|| die "could not write the git shim"
chmod +x "$TMP/shim11/git" || die "could not make the git shim executable"
refs11_before="$(git -C "$TMP/r11" for-each-ref refs/remotes/origin)" || die "r11 for-each-ref (before) failed"
[[ -n "$refs11_before" ]] || die "r11 has no refs/remotes/origin refs to compare"
main11_before="$(git -C "$TMP/r11" rev-parse --verify --quiet 'main^{commit}')" || die "cannot resolve main in r11"
run "$TMP/r11" "$TMP/s11" HERDR_ENV=1 PATH="$TMP/shim11:$PATH"
refs11_after="$(git -C "$TMP/r11" for-each-ref refs/remotes/origin)" || die "r11 for-each-ref (after) failed"
main11_after="$(git -C "$TMP/r11" rev-parse --verify --quiet 'main^{commit}')" || die "cannot resolve main in r11 after the run"
if [[ "$refs11_before" == "$refs11_after" ]]; then
pass; else fail "role unknown: refs/remotes/origin changed (before=$refs11_before after=$refs11_after)"; fi
if [[ $RC -eq 0 ]] && printf '%s' "$OUT" | jq -e '.additionalContext | test("sync not verified") and test("could not tell a Herdr worker") and test("git rev-parse --absolute-git-dir") and (test("fast-forwarded local") | not)' >/dev/null 2>&1 \
&& [[ "$main11_before" == "$main11_after" ]]; then
pass; else fail "role unknown: expected a no-fetch sync-not-verified notice, got RC=$RC OUT=$OUT"; fi
# 12. HERDR_ENV set but empty is still a Herdr session (rules/agent-team-operation.md
# Two Modes): a linked worktree is a worker and never fetches.
mk_origin o12
clone_from "$BARE" "$TMP/r12"
git -C "$TMP/r12" worktree add -q "$TMP/r12-wt" -b feat/worker >/dev/null 2>&1 \
|| die "r12 worktree add failed"
commit_push "$SEED" "c2"
local refs12_before refs12_after
refs12_before="$(git -C "$TMP/r12" for-each-ref refs/remotes/origin)" || die "r12 for-each-ref (before) failed"
[[ -n "$refs12_before" ]] || die "r12 has no refs/remotes/origin refs to compare"
run "$TMP/r12-wt" "$TMP/s12" HERDR_ENV=
refs12_after="$(git -C "$TMP/r12" for-each-ref refs/remotes/origin)" || die "r12 for-each-ref (after) failed"
if [[ "$refs12_before" == "$refs12_after" ]]; then
pass; else fail "empty HERDR_ENV: refs/remotes/origin changed (before=$refs12_before after=$refs12_after)"; fi
if [[ $RC -eq 0 ]] && printf '%s' "$OUT" | jq -e '.additionalContext | test("Herdr worker session") and test("Do not sync")' >/dev/null 2>&1; then
pass; else fail "empty HERDR_ENV: expected the worker notice, got RC=$RC OUT=$OUT"; fi
# 13. Under tessl the environment is stripped, so a linked worktree may be a
# worker's: no fetch, no fast-forward, and a sync-not-verified notice.
mk_origin o13
clone_from "$BARE" "$TMP/r13"
git -C "$TMP/r13" worktree add -q "$TMP/r13-wt" -b feat/maybe-worker >/dev/null 2>&1 \
|| die "r13 worktree add failed"
commit_push "$SEED" "c2"
local refs13_before refs13_after main13_before main13_after
refs13_before="$(git -C "$TMP/r13" for-each-ref refs/remotes/origin)" || die "r13 for-each-ref (before) failed"
[[ -n "$refs13_before" ]] || die "r13 has no refs/remotes/origin refs to compare"
main13_before="$(git -C "$TMP/r13" rev-parse --verify --quiet 'main^{commit}')" || die "cannot resolve main in r13"
run "$TMP/r13-wt" "$TMP/s13" SESSION_START_MODE=portable
refs13_after="$(git -C "$TMP/r13" for-each-ref refs/remotes/origin)" || die "r13 for-each-ref (after) failed"
main13_after="$(git -C "$TMP/r13" rev-parse --verify --quiet 'main^{commit}')" || die "cannot resolve main in r13 after the run"
if [[ "$refs13_before" == "$refs13_after" && "$main13_before" == "$main13_after" ]]; then
pass; else fail "portable worktree: refs or main changed (refs before=$refs13_before after=$refs13_after)"; fi
if [[ $RC -eq 0 ]] && printf '%s' "$OUT" | jq -e '.additionalContext | test("sync not verified") and test("tessl") and test("Herdr worker")' >/dev/null 2>&1; then
pass; else fail "portable worktree: expected a sync-not-verified notice, got RC=$RC OUT=$OUT"; fi
echo "─────────────────────────────────────────────" >&2
if [[ $FAIL -gt 0 ]]; then echo "FAILED: ${FAIL} failed, ${PASS} passed" >&2; exit 1; fi
echo "PASSED: all ${PASS} checks" >&2
}
if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
main "$@"
fi.tessl-plugin
hooks
rules
skills
adopt-fork-pr
herdr-foreman
classify
foreman
references
templates
tests
herdr-standup
migrate-to-plugin
onboard-repo
release
references
tests