diff --git a/retro/SKILL.md b/retro/SKILL.md index 92d58f7b8e..2bc9cc7245 100644 --- a/retro/SKILL.md +++ b/retro/SKILL.md @@ -823,7 +823,7 @@ When the user types `/retro`, run this skill. Parse the argument to determine the time window. Default to 7 days if no argument given. All times should be reported in the user's **local timezone** (use the system default — do NOT set `TZ`). -**Midnight-aligned windows:** For day (`d`) and week (`w`) units, compute an absolute start date at local midnight, not a relative string. For example, if today is 2026-03-18 and the window is 7 days: the start date is 2026-03-11. Use `--since="2026-03-11T00:00:00"` for git log queries — the explicit `T00:00:00` suffix ensures git starts from midnight. Without it, git uses the current wall-clock time (e.g., `--since="2026-03-11"` at 11pm means 11pm, not midnight). For week units, multiply by 7 to get days (e.g., `2w` = 14 days back). For hour (`h`) units, use `--since="N hours ago"` since midnight alignment does not apply to sub-day windows. +**Midnight-aligned windows:** Treat the shell system date (`date +%Y-%m-%d`) as the source of truth for "today"; do not derive today from session reminders, model memory, or prior conversation context. For day (`d`) and week (`w`) units, compute an absolute start date at local midnight, not a relative string. For example, if the system date is 2026-03-18 and the window is 7 days: the start date is 2026-03-11. Use `--since="2026-03-11T00:00:00"` for git log queries — the explicit `T00:00:00` suffix ensures git starts from midnight. Without it, git uses the current wall-clock time (e.g., `--since="2026-03-11"` at 11pm means 11pm, not midnight). For week units, multiply by 7 to get days (e.g., `2w` = 14 days back). For hour (`h`) units, use `--since="N hours ago"` since midnight alignment does not apply to sub-day windows. **Argument validation:** If the argument doesn't match a number followed by `d`, `h`, or `w`, the word `compare` (optionally followed by a window), or the word `global` (optionally followed by a window), show this usage and stop: ``` @@ -888,11 +888,50 @@ Check for non-git context that should be included in the retro: If `RETRO_CONTEXT_FOUND`: read `~/.gstack/retro-context.md`. This file is user-authored and may contain meeting notes, calendar events, decisions, and other context that doesn't appear in git history. Incorporate this context into the retro narrative where relevant. -### Step 1: Gather Raw Data +### Date/window pre-flight + +Run this dedicated pre-flight after resolving the requested window and before the main data-gathering commands. For `/retro compare`, run it against the current window before computing the prior window. For `/retro global`, run it once per discovered repo after detecting that repo's default branch and before collecting its git-log data. + +Resolve: +- `` to the exact `--since` value used for the current window, such as `2026-05-13T00:00:00`. +- `` to the numeric current-window length in days. Use `7` for the default window, `N` for `Nd`, `N * 7` for `Nw`, and `ceil(N / 24)` with a minimum of `1` for `Nh`. -First, fetch origin and identify the current user: ```bash git fetch origin --quiet + +_RETRO_SYSTEM_DATE=$(date +%Y-%m-%d) +_RETRO_WINDOW_DAYS="" +case "$_RETRO_WINDOW_DAYS" in ''|*[!0-9]*) _RETRO_WINDOW_DAYS=7 ;; esac +if [ "$_RETRO_WINDOW_DAYS" -lt 1 ]; then _RETRO_WINDOW_DAYS=1; fi +_ORIGIN_LATEST_UNIX=$(git log origin/ -1 --format="%at" 2>/dev/null || echo 0) +_ORIGIN_LATEST_DATE=$(git log origin/ -1 --format="%ad" --date=short 2>/dev/null || echo unknown) +case "$_ORIGIN_LATEST_UNIX" in ''|*[!0-9]*) _ORIGIN_LATEST_UNIX=0 ;; esac +if [ "$_ORIGIN_LATEST_UNIX" -gt 0 ]; then + _ORIGIN_GAP_DAYS=$(( ($(date +%s) - _ORIGIN_LATEST_UNIX) / 86400 )) +else + _ORIGIN_GAP_DAYS=9999 +fi +_WINDOW_COMMITS=$(git rev-list --count origin/ --since="" 2>/dev/null || echo 0) +case "$_WINDOW_COMMITS" in ''|*[!0-9]*) _WINDOW_COMMITS=0 ;; esac +echo "RETRO_SYSTEM_DATE: $_RETRO_SYSTEM_DATE" +echo "RETRO_WINDOW_DAYS: $_RETRO_WINDOW_DAYS" +echo "ORIGIN_DEFAULT_LATEST: $_ORIGIN_LATEST_DATE (${_ORIGIN_GAP_DAYS}d before system date)" +echo "RETRO_WINDOW_COMMIT_COUNT: $_WINDOW_COMMITS" +if [ "$_ORIGIN_GAP_DAYS" -gt "$_RETRO_WINDOW_DAYS" ]; then + echo "STALE-BASE WARNING: latest origin/ commit is ${_ORIGIN_GAP_DAYS} days before the system date, which is older than the ${_RETRO_WINDOW_DAYS}d retro window. Confirm the 'today' anchor and whether origin/ is current before writing the retro." +fi +if [ "$_WINDOW_COMMITS" -eq 0 ]; then + echo "EMPTY-WINDOW WARNING: origin/ has zero commits in the requested retro window. Treat this as a possible wrong today/window anchor, not proof that no work happened." +fi +``` + +If the date you used to compute a day/week window does not match `RETRO_SYSTEM_DATE`, print `TODAY-ANCHOR WARNING`, recompute the window from `RETRO_SYSTEM_DATE`, and rerun the pre-flight. If `STALE-BASE WARNING` or `EMPTY-WINDOW WARNING` appears, call it out before any normal retro narrative. Do not produce a clean-looking "nothing happened" retro without explaining the suspect system date/window/base-branch evidence. This window-aware threshold intentionally catches the #1624 9-day-gap/7d reproducer: if the latest default-branch commit is 9 days before the system date and the current retro window is 7 days, the pre-flight must print `STALE-BASE WARNING`. + +### Step 1: Gather Raw Data + +First, identify the current user: + +```bash # Identify who is running the retro git config user.name git config user.email @@ -1440,6 +1479,8 @@ git -C fetch origin --quiet 2>/dev/null Detect the default branch for each repo: first try `git symbolic-ref refs/remotes/origin/HEAD`, then check common branch names (`main`, `master`), then fall back to `git rev-parse --abbrev-ref HEAD`. Use the detected branch as `` in the commands below. +Run the **Date/window pre-flight** for each repo before the commands below. For remote repos, use `origin/$DEFAULT` where that pre-flight says `origin/`. For local-only repos, use `HEAD` in place of `origin/`, skip the fetch line, and label warnings with the repo name. In the global summary, list any repos that emitted `STALE-BASE WARNING` or `EMPTY-WINDOW WARNING` before presenting aggregate totals. + ```bash # Commits with stats git -C log origin/$DEFAULT --since="T00:00:00" --format="%H|%aN|%ai|%s" --shortstat @@ -1687,11 +1728,12 @@ Use the Write tool to save JSON to `~/.gstack/retros/global-${today}-${next}.jso When the user runs `/retro compare` (or `/retro compare 14d`): -1. Compute metrics for the current window (default 7d) using the midnight-aligned start date (same logic as the main retro — e.g., if today is 2026-03-18 and window is 7d, use `--since="2026-03-11T00:00:00"`) -2. Compute metrics for the immediately prior same-length window using both `--since` and `--until` with midnight-aligned dates to avoid overlap (e.g., for a 7d window starting 2026-03-11: prior window is `--since="2026-03-04T00:00:00" --until="2026-03-11T00:00:00"`) -3. Show a side-by-side comparison table with deltas and arrows -4. Write a brief narrative highlighting the biggest improvements and regressions -5. Save only the current-window snapshot to `.context/retros/` (same as a normal retro run); do **not** persist the prior-window metrics. +1. Run the **Date/window pre-flight** for the current window (default 7d). If it emits `TODAY-ANCHOR WARNING`, `STALE-BASE WARNING`, or `EMPTY-WINDOW WARNING`, show that warning before any comparison output. +2. Compute metrics for the current window using the midnight-aligned start date (same logic as the main retro — e.g., if today is 2026-03-18 and window is 7d, use `--since="2026-03-11T00:00:00"`) +3. Compute metrics for the immediately prior same-length window using both `--since` and `--until` with midnight-aligned dates to avoid overlap (e.g., for a 7d window starting 2026-03-11: prior window is `--since="2026-03-04T00:00:00" --until="2026-03-11T00:00:00"`) +4. Show a side-by-side comparison table with deltas and arrows +5. Write a brief narrative highlighting the biggest improvements and regressions +6. Save only the current-window snapshot to `.context/retros/` (same as a normal retro run); do **not** persist the prior-window metrics. ## Tone diff --git a/retro/SKILL.md.tmpl b/retro/SKILL.md.tmpl index 93aed3d43e..dc05998693 100644 --- a/retro/SKILL.md.tmpl +++ b/retro/SKILL.md.tmpl @@ -66,7 +66,7 @@ When the user types `/retro`, run this skill. Parse the argument to determine the time window. Default to 7 days if no argument given. All times should be reported in the user's **local timezone** (use the system default — do NOT set `TZ`). -**Midnight-aligned windows:** For day (`d`) and week (`w`) units, compute an absolute start date at local midnight, not a relative string. For example, if today is 2026-03-18 and the window is 7 days: the start date is 2026-03-11. Use `--since="2026-03-11T00:00:00"` for git log queries — the explicit `T00:00:00` suffix ensures git starts from midnight. Without it, git uses the current wall-clock time (e.g., `--since="2026-03-11"` at 11pm means 11pm, not midnight). For week units, multiply by 7 to get days (e.g., `2w` = 14 days back). For hour (`h`) units, use `--since="N hours ago"` since midnight alignment does not apply to sub-day windows. +**Midnight-aligned windows:** Treat the shell system date (`date +%Y-%m-%d`) as the source of truth for "today"; do not derive today from session reminders, model memory, or prior conversation context. For day (`d`) and week (`w`) units, compute an absolute start date at local midnight, not a relative string. For example, if the system date is 2026-03-18 and the window is 7 days: the start date is 2026-03-11. Use `--since="2026-03-11T00:00:00"` for git log queries — the explicit `T00:00:00` suffix ensures git starts from midnight. Without it, git uses the current wall-clock time (e.g., `--since="2026-03-11"` at 11pm means 11pm, not midnight). For week units, multiply by 7 to get days (e.g., `2w` = 14 days back). For hour (`h`) units, use `--since="N hours ago"` since midnight alignment does not apply to sub-day windows. **Argument validation:** If the argument doesn't match a number followed by `d`, `h`, or `w`, the word `compare` (optionally followed by a window), or the word `global` (optionally followed by a window), show this usage and stop: ``` @@ -95,11 +95,50 @@ Check for non-git context that should be included in the retro: If `RETRO_CONTEXT_FOUND`: read `~/.gstack/retro-context.md`. This file is user-authored and may contain meeting notes, calendar events, decisions, and other context that doesn't appear in git history. Incorporate this context into the retro narrative where relevant. -### Step 1: Gather Raw Data +### Date/window pre-flight + +Run this dedicated pre-flight after resolving the requested window and before the main data-gathering commands. For `/retro compare`, run it against the current window before computing the prior window. For `/retro global`, run it once per discovered repo after detecting that repo's default branch and before collecting its git-log data. + +Resolve: +- `` to the exact `--since` value used for the current window, such as `2026-05-13T00:00:00`. +- `` to the numeric current-window length in days. Use `7` for the default window, `N` for `Nd`, `N * 7` for `Nw`, and `ceil(N / 24)` with a minimum of `1` for `Nh`. -First, fetch origin and identify the current user: ```bash git fetch origin --quiet + +_RETRO_SYSTEM_DATE=$(date +%Y-%m-%d) +_RETRO_WINDOW_DAYS="" +case "$_RETRO_WINDOW_DAYS" in ''|*[!0-9]*) _RETRO_WINDOW_DAYS=7 ;; esac +if [ "$_RETRO_WINDOW_DAYS" -lt 1 ]; then _RETRO_WINDOW_DAYS=1; fi +_ORIGIN_LATEST_UNIX=$(git log origin/ -1 --format="%at" 2>/dev/null || echo 0) +_ORIGIN_LATEST_DATE=$(git log origin/ -1 --format="%ad" --date=short 2>/dev/null || echo unknown) +case "$_ORIGIN_LATEST_UNIX" in ''|*[!0-9]*) _ORIGIN_LATEST_UNIX=0 ;; esac +if [ "$_ORIGIN_LATEST_UNIX" -gt 0 ]; then + _ORIGIN_GAP_DAYS=$(( ($(date +%s) - _ORIGIN_LATEST_UNIX) / 86400 )) +else + _ORIGIN_GAP_DAYS=9999 +fi +_WINDOW_COMMITS=$(git rev-list --count origin/ --since="" 2>/dev/null || echo 0) +case "$_WINDOW_COMMITS" in ''|*[!0-9]*) _WINDOW_COMMITS=0 ;; esac +echo "RETRO_SYSTEM_DATE: $_RETRO_SYSTEM_DATE" +echo "RETRO_WINDOW_DAYS: $_RETRO_WINDOW_DAYS" +echo "ORIGIN_DEFAULT_LATEST: $_ORIGIN_LATEST_DATE (${_ORIGIN_GAP_DAYS}d before system date)" +echo "RETRO_WINDOW_COMMIT_COUNT: $_WINDOW_COMMITS" +if [ "$_ORIGIN_GAP_DAYS" -gt "$_RETRO_WINDOW_DAYS" ]; then + echo "STALE-BASE WARNING: latest origin/ commit is ${_ORIGIN_GAP_DAYS} days before the system date, which is older than the ${_RETRO_WINDOW_DAYS}d retro window. Confirm the 'today' anchor and whether origin/ is current before writing the retro." +fi +if [ "$_WINDOW_COMMITS" -eq 0 ]; then + echo "EMPTY-WINDOW WARNING: origin/ has zero commits in the requested retro window. Treat this as a possible wrong today/window anchor, not proof that no work happened." +fi +``` + +If the date you used to compute a day/week window does not match `RETRO_SYSTEM_DATE`, print `TODAY-ANCHOR WARNING`, recompute the window from `RETRO_SYSTEM_DATE`, and rerun the pre-flight. If `STALE-BASE WARNING` or `EMPTY-WINDOW WARNING` appears, call it out before any normal retro narrative. Do not produce a clean-looking "nothing happened" retro without explaining the suspect system date/window/base-branch evidence. This window-aware threshold intentionally catches the #1624 9-day-gap/7d reproducer: if the latest default-branch commit is 9 days before the system date and the current retro window is 7 days, the pre-flight must print `STALE-BASE WARNING`. + +### Step 1: Gather Raw Data + +First, identify the current user: + +```bash # Identify who is running the retro git config user.name git config user.email @@ -624,6 +663,8 @@ git -C fetch origin --quiet 2>/dev/null Detect the default branch for each repo: first try `git symbolic-ref refs/remotes/origin/HEAD`, then check common branch names (`main`, `master`), then fall back to `git rev-parse --abbrev-ref HEAD`. Use the detected branch as `` in the commands below. +Run the **Date/window pre-flight** for each repo before the commands below. For remote repos, use `origin/$DEFAULT` where that pre-flight says `origin/`. For local-only repos, use `HEAD` in place of `origin/`, skip the fetch line, and label warnings with the repo name. In the global summary, list any repos that emitted `STALE-BASE WARNING` or `EMPTY-WINDOW WARNING` before presenting aggregate totals. + ```bash # Commits with stats git -C log origin/$DEFAULT --since="T00:00:00" --format="%H|%aN|%ai|%s" --shortstat @@ -871,11 +912,12 @@ Use the Write tool to save JSON to `~/.gstack/retros/global-${today}-${next}.jso When the user runs `/retro compare` (or `/retro compare 14d`): -1. Compute metrics for the current window (default 7d) using the midnight-aligned start date (same logic as the main retro — e.g., if today is 2026-03-18 and window is 7d, use `--since="2026-03-11T00:00:00"`) -2. Compute metrics for the immediately prior same-length window using both `--since` and `--until` with midnight-aligned dates to avoid overlap (e.g., for a 7d window starting 2026-03-11: prior window is `--since="2026-03-04T00:00:00" --until="2026-03-11T00:00:00"`) -3. Show a side-by-side comparison table with deltas and arrows -4. Write a brief narrative highlighting the biggest improvements and regressions -5. Save only the current-window snapshot to `.context/retros/` (same as a normal retro run); do **not** persist the prior-window metrics. +1. Run the **Date/window pre-flight** for the current window (default 7d). If it emits `TODAY-ANCHOR WARNING`, `STALE-BASE WARNING`, or `EMPTY-WINDOW WARNING`, show that warning before any comparison output. +2. Compute metrics for the current window using the midnight-aligned start date (same logic as the main retro — e.g., if today is 2026-03-18 and window is 7d, use `--since="2026-03-11T00:00:00"`) +3. Compute metrics for the immediately prior same-length window using both `--since` and `--until` with midnight-aligned dates to avoid overlap (e.g., for a 7d window starting 2026-03-11: prior window is `--since="2026-03-04T00:00:00" --until="2026-03-11T00:00:00"`) +4. Show a side-by-side comparison table with deltas and arrows +5. Write a brief narrative highlighting the biggest improvements and regressions +6. Save only the current-window snapshot to `.context/retros/` (same as a normal retro run); do **not** persist the prior-window metrics. ## Tone diff --git a/test/gen-skill-docs.test.ts b/test/gen-skill-docs.test.ts index c594ea4bcd..185f2c030b 100644 --- a/test/gen-skill-docs.test.ts +++ b/test/gen-skill-docs.test.ts @@ -1085,6 +1085,22 @@ describe('Retro plan completion section', () => { expect(retroSkill).toContain('plan_items_total'); expect(retroSkill).toContain('Plan Completion This Period'); }); + + test('retro SKILL.md warns on stale base or empty windows', () => { + expect(retroSkill).toContain('### Date/window pre-flight'); + expect(retroSkill).toContain('RETRO_SYSTEM_DATE'); + expect(retroSkill).toContain('RETRO_WINDOW_DAYS'); + expect(retroSkill).toContain('ORIGIN_DEFAULT_LATEST'); + expect(retroSkill).toContain('RETRO_WINDOW_COMMIT_COUNT'); + expect(retroSkill).toContain('TODAY-ANCHOR WARNING'); + expect(retroSkill).toContain('STALE-BASE WARNING'); + expect(retroSkill).toContain('EMPTY-WINDOW WARNING'); + expect(retroSkill).toContain('$_ORIGIN_GAP_DAYS" -gt "$_RETRO_WINDOW_DAYS'); + expect(retroSkill).toContain('#1624 9-day-gap/7d reproducer'); + expect(retroSkill).toContain('For `/retro compare`, run it against the current window'); + expect(retroSkill).toContain('For `/retro global`, run it once per discovered repo'); + expect(retroSkill).toContain('git rev-list --count origin/ --since=""'); + }); }); // --- Plan status footer in preamble ---