Scope Lock: pre-task declaration, git history scan, pre-commit audit script

This commit is contained in:
2026-08-26 09:58:33 -07:00
parent 67baac6fdd
commit f81048849a
3 changed files with 94 additions and 2 deletions
+32
View File
@@ -64,6 +64,38 @@ at a problem.
- **No-Fluff Mode is available on request** — unpadded, ruthless review that
argues rather than reassures (see `ai.md`). Optional, never the default.
## Scope Lock
BEFORE editing any file, declare the exact file list for the task. Every file you
touch must be either in that list OR you must state the specific dependency that
requires it (e.g. "method X's signature changed, callers must update"). No "while
I'm here" edits. No refactoring. No style tweaks. If you spot a problem in a file
you're already editing, note it in HANDOFF.md as a follow-up — do not fix it in
this change.
> *The commit `d2114c7` touched 11 files across 4 layers because the AI decided
> to refactor the world. This rule exists because of that incident.*
### Before editing a file — git history scan
```
git log --oneline -5 -- <file>
```
If the file hasn't been touched in many commits and the current task doesn't
directly require changing it, that is a red flag — stop and justify the edit or
don't make it. A stable file touched by an unrelated task is a bug, not a feature.
### Pre-commit audit
Before every commit, run `scripts/scope-check.sh` with the declared file list.
If any file appears in `git diff` but not in the declared scope, either justify
it or revert the change. The script enforces what the rule demands.
```bash
./scripts/scope-check.sh "Models/Scene.cs" "ViewModels/MainViewModel.cs" "MainWindow.xaml"
```
## Build
From WSL, ALWAYS use the Windows dotnet host — Linux `dotnet` re-downloads the
+5 -2
View File
@@ -1,7 +1,7 @@
# HANDOFF — Session State
## Branch
**`main`** @ `89ab83b`, committed LOCALLY, working tree clean. **NOT pushed — user rule: never
**`main`** @ `67baac6`, committed LOCALLY, working tree clean. **NOT pushed — user rule: never
push without explicit instruction (2026-08-24).** No feature branches pre-1.0: all work lands on
`main` per work unit.
@@ -23,7 +23,10 @@ push without explicit instruction (2026-08-24).** No feature branches pre-1.0: a
- `HotkeyConfigDialog.xaml` + `.cs` — click-to-capture, Unbind per row, Reset/Save/Cancel
- `ViewModels/MainViewModel.cs` — loads bindings, `OpenHotkeyConfigCommand`, `HotkeyBindingsChanged` callback
- `MainWindow.xaml.cs` — passes bindings to manager, re-attaches on dialog save
- Tests: `HotkeyConfigTests` (round-trip, display string, storage serialization)
- Tests: `HotkeyConfigTests` (round-trip, display string, storage serialization)
- **Thumbnail strip hotkey labels** (`d4aa5e1`): each scene shows its current binding (e.g. "Starting F1").
- **Pull-out tab renamed** to "Stream Settings"; **right-click Start Stream** → Change Account / Logout context menu (`67baac6`).
- **Scope Lock rules** (`AGENTS.md` + `scripts/scope-check.sh`): pre-task scope declaration, git history scan before editing, pre-commit audit script that validates `git diff` against declared file list. Born from the `d2114c7` incident.
- Suite: 231 total, 230 pass — only failure is the known pre-existing `AudioPipelineTests.Mix_HonorsProviderGains_AndGameMute_KillsTheLoopback`. Build 0 warnings.
## ⚠️ Landmines
+57
View File
@@ -0,0 +1,57 @@
#!/usr/bin/env bash
# scope-check.sh — Validate that git diff only touches declared files.
# Usage: ./scripts/scope-check.sh "file1.cs" "file2.cs" ...
# Exit 0 if all changed files are in scope, 1 if any are outside.
#
# Checks staged, unstaged, and untracked changes against the allowed list.
# Supports glob patterns in the allowed list (e.g. "ytLive.Tests/*").
set -euo pipefail
if [ $# -eq 0 ]; then
echo "Usage: $0 \"file1.cs\" \"file2.cs\" ..."
echo " Pass the declared file list as arguments."
exit 1
fi
# Collect allowed patterns into an array
allowed=("$@")
# Gather all changed files: working tree vs HEAD (tracked) + staged + untracked
changed=$({
git diff --name-only HEAD 2>/dev/null || true
git diff --name-only --cached 2>/dev/null || true
git ls-files --others --exclude-standard 2>/dev/null || true
} | sort -u)
if [ -z "$changed" ]; then
echo "✓ No changes detected."
exit 0
fi
violations=()
while IFS= read -r file; do
matched=false
for pattern in "${allowed[@]}"; do
if [[ "$file" == $pattern ]]; then
matched=true
break
fi
done
if [ "$matched" = false ]; then
violations+=("$file")
fi
done <<< "$changed"
if [ ${#violations[@]} -eq 0 ]; then
echo "✓ Scope check passed — all changed files are in scope."
exit 0
fi
echo "✗ SCOPE VIOLATION — the following files are outside the declared scope:"
for f in "${violations[@]}"; do
echo " - $f"
done
echo ""
echo "Either justify the edit or revert the change."
exit 1