Scope Lock: pre-task declaration, git history scan, pre-commit audit script
This commit is contained in:
@@ -64,6 +64,38 @@ at a problem.
|
|||||||
- **No-Fluff Mode is available on request** — unpadded, ruthless review that
|
- **No-Fluff Mode is available on request** — unpadded, ruthless review that
|
||||||
argues rather than reassures (see `ai.md`). Optional, never the default.
|
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
|
## Build
|
||||||
|
|
||||||
From WSL, ALWAYS use the Windows dotnet host — Linux `dotnet` re-downloads the
|
From WSL, ALWAYS use the Windows dotnet host — Linux `dotnet` re-downloads the
|
||||||
|
|||||||
+4
-1
@@ -1,7 +1,7 @@
|
|||||||
# HANDOFF — Session State
|
# HANDOFF — Session State
|
||||||
|
|
||||||
## Branch
|
## 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
|
push without explicit instruction (2026-08-24).** No feature branches pre-1.0: all work lands on
|
||||||
`main` per work unit.
|
`main` per work unit.
|
||||||
|
|
||||||
@@ -24,6 +24,9 @@ push without explicit instruction (2026-08-24).** No feature branches pre-1.0: a
|
|||||||
- `ViewModels/MainViewModel.cs` — loads bindings, `OpenHotkeyConfigCommand`, `HotkeyBindingsChanged` callback
|
- `ViewModels/MainViewModel.cs` — loads bindings, `OpenHotkeyConfigCommand`, `HotkeyBindingsChanged` callback
|
||||||
- `MainWindow.xaml.cs` — passes bindings to manager, re-attaches on dialog save
|
- `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.
|
- Suite: 231 total, 230 pass — only failure is the known pre-existing `AudioPipelineTests.Mix_HonorsProviderGains_AndGameMute_KillsTheLoopback`. Build 0 warnings.
|
||||||
|
|
||||||
## ⚠️ Landmines
|
## ⚠️ Landmines
|
||||||
|
|||||||
@@ -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
|
||||||
Reference in New Issue
Block a user