/retro silently produces empty/misleading output when 'today' anchor is wrong (no stale-base warning)
- Dominant language
- TypeScript
- Stars
- 133k
- Forks
- 19.9k
- Avg merge
- 18h 46m
- Merged PRs (30d)
- 26
Description
## 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=""` 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:
1. **"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.).
2. **Stale worktree base** — the Conductor/`claude/...` branch is days/weeks behind `origin/`, and although the skill does `git fetch origin --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 --quiet` and then immediately starts gathering commits via `git log origin/ --since=""`. There's no sanity-check on the gap between "today" and `origin/`'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:
```bash
git fetch origin --quiet
_LATEST_COMMIT_TS=$(git log origin/ -1 --format="%at" 2>/dev/null || echo 0)
_LATEST_COMMIT_DATE=$(git log origin/ -1 --format="%ad" --date=short 2>/dev/null || echo unknown)
_GAP_DAYS=$(( ($(date +%s) - _LATEST_COMMIT_TS) / 86400 ))
echo "ORIGIN__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/` 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.
Contributor guide
Assessment
This issue has not been assessed yet.