-
Regenerate generated docs (codegen drift gate). If the change touched any
endpoint YAML (tools/codegen/endpoints/*), schemas, docstrings, loaders, or
wrappers, the generated reference subtree is probably stale and CI will fail
on it. Regenerate, then check:
uv run python tools/codegen/generate.py
uv run python tools/codegen/generate.py --check
If --check is non-zero, the generated tree drifted — regenerate and stage
the result. The same gate runs in CI and the sdv-codegen pre-commit hook.
Branch head, not per-task. On a multi-commit / multi-task branch, re-run
the gate at the FINAL branch head even if it passed mid-branch — later
commits that add exports or docstrings silently invalidate an earlier
regeneration (per-task green does not compose; this failed a real
whole-branch review).
Shadow check before regenerating. If the branch added a new module under
a package with generated wrappers, first confirm the filename doesn't shadow
a wrapper function (see /sdv-preflight's new-module check). Regenerating WITH
a shadow in place silently DROPS the shadowed wrapper from the generated
parsed/ module — fix the name first, then regenerate.
-
Update changelog / docs / tutorials (conditional — skip only if truly N/A).
- User-facing change (new function, renamed/removed surface, behavior or
dependency change)? Add a
CHANGELOG.md entry under the unreleased heading
(the sync-docs-changelog pre-commit hook mirrors it into the docs site).
- New/changed public surface? Check whether the relevant example notebook
(
examples/notebooks/0X_<sport>_intro.ipynb) or a hand-authored conceptual
doc page mentions the old surface — update it. Generated reference pages are
already handled by step 1; never hand-edit those.
- Internal-only refactor with zero user-visible effect → note "changelog N/A"
in the todo and move on. Don't invent an entry for noise.
-
Lint + format. The PostToolUse ruff hook formats files as they're edited,
but run the suite-wide pass before committing so nothing slips through:
uv run ruff format sportsdataverse/ tools/ .claude/
uv run ruff check sportsdataverse/ tools/ .claude/
A ruff-format hook can silently abort a commit — if git commit reports
nothing committed, suspect the pre-commit ruff hook rewrote files; re-git add
and re-commit. Confirm the commit actually landed (git log -1 --oneline).
-
Run the full test suite. Not a subset — the whole thing must be green
before declaring done.
uv run pytest
Live-API tests are gated behind SDV_PY_LIVE_TESTS=1 and skip by default;
that's expected. A red suite is a stop-ship — fix before continuing.
-
Commit — then VERIFY it landed. Conventional Commits subject, scoped where
useful. No AI co-author trailer. Split unrelated work into separate commits.
After every git commit, confirm with git log -1 --oneline + git status
that HEAD is your new commit and nothing is left half-staged. Two hooks
silently abort commits while printing mostly-green output: the ruff-format
hook (rewrites files) and doctoc (rewrites any staged README/markdown
with a TOC). In both cases: re-git add the hook-modified files and
re-commit — never --no-verify.
-
Push the feature branch and open the PR (or update it):
git push -u origin HEAD
gh pr create --fill
The pre-push hook re-runs the codegen drift gate (~3-5 min), so a push
regularly outlives a 2-minute foreground tool timeout — run it
run_in_background and confirm the remote head afterwards
(git ls-remote origin <branch>).
-
Triage automated reviews (CodeRabbit / Sourcery / Copilot) — do NOT wait
for CI. The bots post within a few minutes of the push, long before the
pytest matrix finishes; triage them in parallel with CI so review fixes and
the CI run overlap instead of serializing. Run /sdv-address-bot-reviews
(fix the valid ones, decline convention-conflicts with a CLAUDE.md citation,
then reply + resolve each thread). Treat bot findings as leads to VERIFY
against the code, not verdicts — a "Major" can be a false positive
(generated-doc "hand-edit" flags when --check passes) and a real one can
hide behind a bland title (reproduce it with a failing test before fixing).
If a fix lands, push it and let CI restart. Skip only if no bot review
landed.
-
Wait for CI to go green. Do not merge on a yellow/pending or red run.
gh pr checks --watch
If CI fails, read the failing job, fix, and loop back to the relevant step
(often step 1 for docs drift or step 4 for tests). Report the failure — do
not silently retry. Two watcher gotchas: a --watch started before a
re-push keeps watching the OLD head (relaunch it), and after any merge the
PR-branch run is superseded — the definitive signal is main's post-merge
run (gh run list --branch main).
-
Merge — only after CI is green and bot threads are resolved.
gh pr merge --squash
If the human directs an early merge (--admin) past pending/red checks:
only override a failure you have READ and verified as infra flake (Vercel
preview deploy, runner DNS), never an unread one — admin merges silently
accept red required checks (a red codegen gate rode onto main exactly this
way) — and afterwards confirm main's post-merge run goes green.
-
Confirm the merge landed, THEN clean up. Verify before deleting anything:
gh pr view --json state,mergedAt
Only once state == MERGED: delete the branch and git switch main && git pull.
Never delete the branch before this confirmation — a premature cleanup
stranded work in a past session.
-
Write a session note. Capture what shipped while the context is fresh, so
the next session (or a compaction recovery) doesn't re-derive it:
- If the repo has an SDD ledger (
.superpowers/sdd/progress.md), append one
entry there: date, branch, PR # + URL, the commit range, gates passed
(tests/mypy/drift), and any deferred follow-ups.
- Otherwise write
dev/session-notes/YYYY-MM-DD-<slug>.md (dev/ is
gitignored — working notes, not repo docs).
- If the ship changed durable cross-session state (a program milestone, a new
convention, a gotcha worth remembering), also update the memory topic file
for that program.
In each case: stop, surface the exact output, and wait — do not delete branches,
force-push, or skip hooks (--no-verify) to get unstuck.