diff --git a/.claude/skills/git-commit/SKILL.md b/.claude/skills/git-commit/SKILL.md index 92a4f2722..c236b9e3f 100644 --- a/.claude/skills/git-commit/SKILL.md +++ b/.claude/skills/git-commit/SKILL.md @@ -88,6 +88,19 @@ Use the project subsystem as scope. Examples: - Never combine unrelated changes (e.g., don't mix a crash fix with new features). - When in doubt, prefer more smaller commits over fewer large ones. +### Clerk safety valve (`[clerk-skip]`) + +The pre-push clerk reviews each commit for D-record consistency. For a pure bulk +content commit — e.g. shipping thousands of generated planetary description files +— that review is moot and just burns agents on noise. Put the token `[clerk-skip]` +anywhere in the commit message and `tooling/clerk-review` auto-approves that commit +without spawning an agent. Use it only for content/data dumps, never for commits +that touch `decisions/`, code, or ticket-bearing work. + +``` +data(content): generate 5000 planetary description files [clerk-skip] +``` + ### Examples ``` diff --git a/tooling/clerk-review b/tooling/clerk-review index 28673794d..cad1d72a4 100755 --- a/tooling/clerk-review +++ b/tooling/clerk-review @@ -11,6 +11,11 @@ agents and the verdicts aggregated. This avoids the single-agent failure mode where one `claude -p` ran out of turns on a huge combined diff and never emitted a verdict (which defaulted to REJECTED). +Safety valve: a commit whose message contains the token `[clerk-skip]` is +auto-approved without spawning an agent — for bulk content commits (e.g. shipping +thousands of generated planetary description files) where D-record review is moot +and the diff would only burn agents on noise. + Outputs exactly one word as the LAST stdout line: APPROVED, REJECTED, or TIMEOUT. Writes verbose findings to .cache/pre-push-review.md. @@ -48,6 +53,9 @@ WORKERS = int(os.environ.get("SR_CLERK_WORKERS", "4")) MAX_TURNS = os.environ.get("SR_CLERK_MAX_TURNS", "6") TIMEOUT_SECONDS = int(os.environ.get("SR_CLERK_TIMEOUT", "150")) +# Safety valve: a commit message containing this token is auto-approved (no agent). +SKIP_TOKEN = "[clerk-skip]" + CLERK_PROMPT = """You are the CLERK, the institutional guardrail for The Settled Reach. You are reviewing ONE COMMIT ({label}) from a larger pre-push for D-record @@ -102,16 +110,24 @@ def list_commits(rng): def commit_unit(sha): - """Return (subject, full text = message + diff, truncated to budget).""" + """Return (subject, text, skip) for one commit. + + `skip` is True when the commit message contains SKIP_TOKEN (the safety valve); + `text` is the message + diff, truncated to COMMIT_BUDGET. + """ subject = subprocess.check_output( ["git", "show", "-s", "--format=%h %s", sha], text=True ).strip() + message = subprocess.check_output( + ["git", "show", "-s", "--format=%B", sha], text=True + ) + skip = SKIP_TOKEN.lower() in message.lower() text = subprocess.check_output( ["git", "show", "--format=fuller", sha], text=True ) if len(text) > COMMIT_BUDGET: text = text[:COMMIT_BUDGET] + f"\n\n... (commit diff truncated; {len(text)} total chars)\n" - return subject, text + return subject, text, skip def run_clerk(label, diff_text, index): @@ -156,27 +172,32 @@ def main(): print("APPROVED") return 0 - units = [commit_unit(sha) for sha in commits] # [(subject, text), ...] + units = [commit_unit(sha) for sha in commits] # [(subject, text, skip), ...] if plan_only: print(f"clerk plan: {len(commits)} commit(s) over {rng} " f"(budget {COMMIT_BUDGET} chars, {WORKERS} workers, {MAX_TURNS} turns each)") - for i, (subject, text) in enumerate(units): - print(f" commit {i + 1}/{len(commits)}: {len(text):>9} chars {subject}") + for i, (subject, text, skip) in enumerate(units): + tag = "SKIP (auto-approve)" if skip else "review" + print(f" commit {i + 1}/{len(commits)}: {len(text):>9} chars [{tag}] {subject}") return 0 index = load_index() - print(f" clerk: reviewing {len(commits)} commit(s), {WORKERS} parallel...", + reviewable = sum(1 for _, _, skip in units if not skip) + print(f" clerk: {len(commits)} commit(s) — {reviewable} to review, " + f"{len(commits) - reviewable} auto-approved ([clerk-skip]); {WORKERS} parallel...", file=sys.stderr) - def task(i, subject, text): + def task(i, subject, text, skip): label = f"commit {i + 1}/{len(commits)} ({subject})" + if skip: + return i, label, "APPROVED", f"{label}: auto-approved via [clerk-skip] safety valve." verdict, findings = run_clerk(label, text, index) return i, label, verdict, findings results = [None] * len(commits) with ThreadPoolExecutor(max_workers=WORKERS) as ex: - futures = [ex.submit(task, i, s, t) for i, (s, t) in enumerate(units)] + futures = [ex.submit(task, i, s, t, skip) for i, (s, t, skip) in enumerate(units)] for fut in as_completed(futures): i, label, verdict, findings = fut.result() results[i] = (label, verdict, findings)