Failure mode
When /retro runs on a worktree-style setup (Conductor, etc.) and the agent's understanding of "today" is off by enough days, the skill silently produces a clean-looking retro that misses recent reality. The git log --since="<midnight-aligned-start>" window quietly returns zero or near-zero commits, but nothing in the output flags that the window is wrong.
Both inputs to the window can be wrong:
- "today" anchor drift — the agent computes
today from session-context cues that don't match the actual system date (model error, session-reminder mismatch, etc.).
- Stale worktree base — the Conductor/
claude/... branch is days/weeks behind origin/<default>, and although the skill does git fetch origin <default> --quiet, nothing surfaces that the latest commit is materially older than "today" would suggest.
Either way, the retro renders successfully, the metrics table looks legitimate, and the user gets a confidently-wrong report.
Reproducer
I hit this on a real project today:
today per system date: 2026-05-20
- Agent computed
today (incorrectly): 2026-05-15
/retro (default 7d): analyzed --since="2026-05-08T00:00:00", returned 18 commits (all from May 8-11), missed 4 commits on origin/main from May 19-20 including the latest version bump
- Output: a clean retro narrative ending "Streak: 0d (4-day burst May 8-11)" — looks coherent, completely missed v0.21.0 → v0.22.0 work that had already shipped
The user caught it only when version-bumping for the next PR: "version number is way old."
Why it's silent
Step 1: Gather Raw Data runs git fetch origin <default> --quiet and then immediately starts gathering commits via git log origin/<default> --since="<window>". There's no sanity-check on the gap between "today" and origin/<default>'s latest commit. If the gap exceeds the window length, the window is empty — but the retro keeps going and the model fills in narrative from whatever (possibly zero) commits it found.
Suggested fix (sketch)
Inject a stale-base sanity check right after the fetch, before the data-gathering. Always echo the latest commit date + gap so the agent has the data point; escalate to an explicit warning when the gap is suspect:
git fetch origin <default> --quiet
_LATEST_COMMIT_TS=$(git log origin/<default> -1 --format="%at" 2>/dev/null || echo 0)
_LATEST_COMMIT_DATE=$(git log origin/<default> -1 --format="%ad" --date=short 2>/dev/null || echo unknown)
_GAP_DAYS=$(( ($(date +%s) - _LATEST_COMMIT_TS) / 86400 ))
echo "ORIGIN_<default>_LATEST: $_LATEST_COMMIT_DATE (${_GAP_DAYS}d before today)"
if [ "$_GAP_DAYS" -gt 3 ]; then
echo "⚠ STALE-BASE WARNING: latest commit is ${_GAP_DAYS} days before today."
echo " If your window is shorter than ${_GAP_DAYS}d, the retro will contain few or zero commits."
echo " Sanity-check the 'today' anchor against the actual system date before proceeding —"
echo " a clean-looking retro on the wrong window silently misses recent reality."
fi
Plus a prose follow-up after the bash block: "If the stale-base warning fires: confirm that today matches the system date, and that origin/<default> actually has the recent activity you expect. If the gap exceeds the window length, the retro will report empty or near-empty results — that's evidence the anchor or fetch is wrong, not that the team didn't ship."
Always echoing the data point (even when no warning fires) gives the agent a fact to cross-check against. The 3-day threshold is comfortably above typical weekly cadence (so weekend gaps don't false-positive) but low enough to catch the 9-day case I hit. The threshold is debatable — could be window-aware (e.g., gap > window_days) if the skill exposes the parsed window length as a bash var.
Why I'm filing an issue instead of a PR
I have a working local patch (tested against the repo where the bug surfaced) but want to confirm with you whether:
- The 3-day threshold is right, or whether it should be window-aware
- The warning text matches gstack's voice/conventions
- This belongs in
Step 1: Gather Raw Data or as its own pre-flight step before Step 1
- The fix should also apply to
/retro compare and /retro global (the global mode has its own multi-repo discovery — the same failure mode could occur there)
Happy to send a PR shaped however you'd prefer. Context: hit while running /retro from a Claude Code (Conductor) worktree branch that was 4 commits behind origin/main.
If helpful: the lesson also landed in my local project memory as "high-confidence 'obviously fine' moments are exactly when the second pair of eyes catches the thing that isn't" — same pattern across the stale-base miss, a self-judged bug diagnosis, and a /ship declaring-done gate where I skipped the advisor. The /retro skill is the most fixable of these because the check is mechanical.
Failure mode
When
/retroruns on a worktree-style setup (Conductor, etc.) and the agent's understanding of "today" is off by enough days, the skill silently produces a clean-looking retro that misses recent reality. Thegit log --since="<midnight-aligned-start>"window quietly returns zero or near-zero commits, but nothing in the output flags that the window is wrong.Both inputs to the window can be wrong:
todayfrom session-context cues that don't match the actual system date (model error, session-reminder mismatch, etc.).claude/...branch is days/weeks behindorigin/<default>, and although the skill doesgit fetch origin <default> --quiet, nothing surfaces that the latest commit is materially older than "today" would suggest.Either way, the retro renders successfully, the metrics table looks legitimate, and the user gets a confidently-wrong report.
Reproducer
I hit this on a real project today:
todayper system date: 2026-05-20today(incorrectly): 2026-05-15/retro(default 7d): analyzed--since="2026-05-08T00:00:00", returned 18 commits (all from May 8-11), missed 4 commits onorigin/mainfrom May 19-20 including the latest version bumpThe user caught it only when version-bumping for the next PR: "version number is way old."
Why it's silent
Step 1: Gather Raw Datarunsgit fetch origin <default> --quietand then immediately starts gathering commits viagit log origin/<default> --since="<window>". There's no sanity-check on the gap between "today" andorigin/<default>'s latest commit. If the gap exceeds the window length, the window is empty — but the retro keeps going and the model fills in narrative from whatever (possibly zero) commits it found.Suggested fix (sketch)
Inject a stale-base sanity check right after the fetch, before the data-gathering. Always echo the latest commit date + gap so the agent has the data point; escalate to an explicit warning when the gap is suspect:
Plus a prose follow-up after the bash block: "If the stale-base warning fires: confirm that
todaymatches the system date, and thatorigin/<default>actually has the recent activity you expect. If the gap exceeds the window length, the retro will report empty or near-empty results — that's evidence the anchor or fetch is wrong, not that the team didn't ship."Always echoing the data point (even when no warning fires) gives the agent a fact to cross-check against. The 3-day threshold is comfortably above typical weekly cadence (so weekend gaps don't false-positive) but low enough to catch the 9-day case I hit. The threshold is debatable — could be window-aware (e.g.,
gap > window_days) if the skill exposes the parsed window length as a bash var.Why I'm filing an issue instead of a PR
I have a working local patch (tested against the repo where the bug surfaced) but want to confirm with you whether:
Step 1: Gather Raw Dataor as its own pre-flight step before Step 1/retro compareand/retro global(the global mode has its own multi-repo discovery — the same failure mode could occur there)Happy to send a PR shaped however you'd prefer. Context: hit while running
/retrofrom a Claude Code (Conductor) worktree branch that was 4 commits behindorigin/main.If helpful: the lesson also landed in my local project memory as "high-confidence 'obviously fine' moments are exactly when the second pair of eyes catches the thing that isn't" — same pattern across the stale-base miss, a self-judged bug diagnosis, and a
/shipdeclaring-done gate where I skipped the advisor. The/retroskill is the most fixable of these because the check is mechanical.