diff --git a/.claude/skills/README.md b/.claude/skills/README.md index 40a9e868..3f17eb7b 100644 --- a/.claude/skills/README.md +++ b/.claude/skills/README.md @@ -42,6 +42,7 @@ Two complementary artifact-capture skills. Coral / council should offer them at ### Skill Authoring & Auditing - **`author-skill/`** — Author a new skill for a specific domain. Drives Intake → deep web research (parallel subagents) → subagent-based RED-GREEN-REFACTOR pressure testing → scaffolds the skill into `/.claude/skills//` per `SKILL-TEMPLATE.md`, with evals derived from the surviving pressure scenarios. Built on Anthropic's skill-authoring best practices and Obra's TDD-for-skills methodology (`references/obra-best-practices.md`, `references/testing-with-subagents.md`, `references/persuasion-principles.md`). Refuses to overwrite canonical workflow skills (coral, council, design, issue, bugbash) or skip the RED baseline. - **`audit-skill/`** — Audit an existing skill against the team's conventions catalog (`references/conventions-catalog.md`). Two phases: **audit-only** is the default — runs static + semantic + pressure checks and produces a findings report at `docs/skill-audits/-.md`, no edits made. **Refactor** is opt-in via `--apply` — per-finding diffs, diff-before-write gate, append-only evals, automatic rollback on verify failure. Canonical skills are auditable freely; refactor requires `--override-protected`. The brown-field sibling of `/author-skill`. +- **`brevity/`** — Enforces brevity-with-signal on agent-authored PR descriptions and in-code comments. Eight imperative rules + a 5-row rationalization table that fires against the verbose-by-default biases (authority compliance, asymmetric loss perception, complexity-symmetry, durable-record genre confusion). Discipline-enforcing shape; passed RED-GREEN-REFACTOR pressure testing in cycle 0. Deferred surfaces (un-defer triggers documented inline): doc/design, runbooks, memory writes, mid-conversation chat. Sibling: `/pr-quality` (issue #88) for multi-dimensional PR critique. ### Hardening - **`bugbash/`** — Long-running, read-only adversarial review of an existing system by the council of experts. Loops discovery + challenger passes against a named target (`/bugbash SeiNode controller`) until the experts converge on a launch verdict. Output is a structured findings log at `docs/bugbash/.md` with per-item Scenario / Impact / Issue / Fix sketch / Test coverage. Inspired by the [RALPHY loop](https://github.com/snarktank/ralph), reframed for hardening before launch. Distinct from `/security-review` (single-pass, security-only) and `/coral` (collaborative iteration, not adversarial). diff --git a/.claude/skills/brevity/SKILL.md b/.claude/skills/brevity/SKILL.md new file mode 100644 index 00000000..e4a14a48 --- /dev/null +++ b/.claude/skills/brevity/SKILL.md @@ -0,0 +1,212 @@ +--- +name: brevity +description: "Use when authoring or revising agent-produced PR descriptions or in-code comments — 'tighten this', 'compress this PR body', 'this is too verbose', 'cut the filler', '/brevity'. Also fires when an agent is about to write a PR body or any in-code comment containing WHY-style narration. Anti-triggers: NOT for compressing memory files / CLAUDE.md (one-shot migration concern); NOT for chat output mid-conversation (soft-guidance via authoritative-voice patterns); NOT for commit messages (Conventional Commits convention covers it); NOT for source code itself or docstring formatting (use gofmt, prettier, golint). For multi-dimensional PR-time critique beyond brevity (convention adherence, defensive code, missing tests), use /pr-quality." +--- + +# Brevity + +Agent-authored natural-language output drifts toward verbose by default. RLHF rewards thoroughness; instruction-following promotes preamble; uncertainty triggers hedging; a corpus dominated by tutorial prose biases comments toward "what?" narration over "why?" insight. This skill exists because brevity discipline cannot survive on memory soft-guidance alone — it gets bypassed the moment an agent is under pressure. + +This skill enforces brevity-with-signal on two surfaces: **PR descriptions** and **in-code comments**. Other surfaces (doc/design, runbooks, memory writes, mid-conversation chat) are deferred — call back when one of them produces a real drift incident. + +## Guardrails + +This skill operates on **agent-authored natural-language output**. Before any side-effecting suggestion or rewrite: + +1. **Surface check.** Confirm the output is one of the MVP surfaces (PR body, in-code comment). If the user is asking about a deferred surface, redirect (`feedback_authoritative_voice` for chat output; Conventional Commits for commit messages; gofmt/prettier for code formatting). + +2. **Authorship check.** This skill enforces brevity on *agent-authored* content. If compressing human-authored content, surface that and ask whether the user wants editorial suggestions (allowed) or rewrite (requires explicit consent — humans own their words). + +3. **Refuse-or-halt conditions.** This skill stops and surfaces when: + - **Input is below the floor** — PR body <50 words OR comment <1 line. Already brief; further compression is bikeshedding. + - **Load-bearing claim is unclear** after one careful read — the input is too garbled to compress; suggest a rewrite from scratch. + - **Section is safety-critical** — `## Safety`, `## Rollback`, `## Blast radius`, `## Migration`, `## Breaking change`. Compression within these sections requires explicit user opt-in. + - **Compression would lose signal** — if applying the rules removes information a reviewer needs to act, stop. + - **Discipline is being litigated** — user pushes back on three or more rule applications in one session. Stop and surface the disagreement; let the user redirect. + - **Request is a mechanical lint** — "ban these words" / "regex replace X with Y" → route to lint tools (write-good, proselint, CI step), refuse to act as a banned-word filter. + - **Content was authored by someone other than the user** — cross-author PR edits require all three: (a) the user explicitly names the target PR by URL or `owner/repo#N`, (b) the user states the relationship (reviewer suggestion vs. author handoff), (c) the output routes as a suggestion (not a direct edit applied to the PR body). + - **Content is already committed/merged** — suggestions only; the user owns the diff. + +## The Eight Rules — YOU MUST + +These rules are non-negotiable. They are not stylistic preferences; they are the failure modes the skill exists to close. + +**Rule 1 — Cut every sentence whose removal does not change what a reviewer would do next.** + +If a sentence describes the change rather than informing a decision, delete it. The diff describes the change. The PR body informs the reviewer. + +❌ "This PR introduces a small but important refactor to the validator initialization logic." +✅ (delete entirely — the diff title + linked issue carry this) + +**Rule 2 — Open a PR body with the *what* and *why*, not a wind-up.** + +No "In order to...", "The motivation for...", "This PR / This change...", "We are...". Start on the load-bearing noun. + +❌ "In order to address the issue in #289, this PR updates the reconciler..." +✅ "Reconciler now waits for StatefulSet pods Ready before stamping `status.allocatable`. Fixes #289." + +**Rule 3 — Keep in-code comments to 4 lines or fewer.** + +Long WHY narration belongs in the PR description, recoverable via `git blame → PR`. If a comment is longer than the code it annotates, it's too long. + +❌ Twelve-line block explaining the original bug, why DeepEqual fails, alternatives considered, rationale, future-engineer warning. +✅ "Both checks required: reflect.DeepEqual gives false-positives on equal-but-reordered maps (#241). Hash short-circuits update storm. Don't drop either." + +**Rule 4 — Make every verb do work.** + +Sentences using "serves to", "aims to", "helps to", "is responsible for", "allows us to", "exists to" must be rewritten with the real verb as the main verb. + +❌ "This function serves to validate the input." +✅ "Validates the input." + +**Rule 5 — Do not restate names.** + +A comment paraphrasing an identifier (`// Slug is the engineer's identifier` on field `Slug string`) gets deleted, not shortened. The name *is* the documentation. + +❌ `// Hash returns a hash of the spec.` +✅ (delete — the function signature says this) + +**Rule 6 — Prefer one example over one paragraph of explanation.** + +If you're describing behavior abstractly, replace the paragraph with the smallest concrete input/output pair. + +❌ "The function applies the join by matching the pod and namespace labels, then propagating the workload label via group_left semantics." +✅ "`pod_alerts * on (pod, namespace) group_left(workload) kube_pod_info` → series gains `workload` label." + +**Rule 7 — Collapse hedges.** + +"Generally", "typically", "in most cases", "it should be noted that", "essentially", "basically" carry no information for engineering readers. Cut or commit. + +❌ "It should be noted that the timeout is essentially a safety net." +✅ "Timeout is a safety net." + +**Rule 8 — Treat headers and bullets as a budget, not a structure tax.** + +A PR body with three single-bullet sections is three sentences pretending to be a document. Flatten it. Use a section only when it groups ≥2 related items. + +❌ +``` +## Summary +- One sentence. + +## Context +- One sentence. + +## Files +- One file. +``` +✅ "One sentence summary. One sentence context. One file." + +## Target shapes — concrete + +**PR body word count:** +- Fix / small refactor: **30-80 words** +- Feature / behavior change: **100-250 words** +- One-way door (interface, storage, event sig): **+50-100 words** for explicit justification + alternatives considered + +**PR body section pattern:** +1. Summary — 1-3 sentences leading with what + why +2. Test plan — checkbox list, 2-5 items +3. Follow-ups — optional bullets +4. Refs — `Fixes #N`, design link + +**Does NOT belong in a PR body:** +- Motivation paragraphs that restate the linked issue +- "What each file does" walkthroughs (the diff shows it) +- Background sections (link the design doc) +- "Things I considered but didn't do" (out-of-scope already documented) +- Marketing language +- Re-derived shared context + +**In-code comment line count:** 2-4 lines (1 line OK for trivial WHYs). + +**Comment earns its place:** +- Non-obvious WHY — invariant the code preserves but doesn't express +- Hidden constraint — upstream bug, ordering requirement, ABI quirk +- Workaround context — pointer to issue/PR +- Magic number provenance — "5s = p99 + 2× jitter, see #1234" + +**Comment does NOT earn its place:** +- Restating function/variable name +- Describing what the next lines plainly do +- History ("used to be X, now Y" — that's `git log`) +- TODOs without owner or issue link +- Defensive narration ("we now check the err") + +**Reference PR**: [rust-lang/rust#157179](https://github.com/rust-lang/rust/pull/157179) — 28 words, optimizes impl sorting. Says *what*, *why*, *where to look for more*. Tide adds a 2-bullet test plan to this floor. + +## Procedure + +1. **Surface check.** Confirm the input is a PR body or in-code comment. If neither, halt with the redirect from Guardrails. + +2. **Announce the rules being applied.** State: "Applying brevity rules N-M to surface S." This is the Commitment principle — naming the rules forces explicit application rather than silent partial-skip. + +3. **Pass 1 — cut filler and hedges (rules 1, 7).** Walk every sentence. Delete those that describe without informing. Cut every hedge ("generally", "typically", "it should be noted", "essentially"). + +4. **Pass 2 — collapse abstractions (rules 4, 6).** Rewrite weak-verb sentences ("serves to", "aims to", "is responsible for") with the real verb as main verb. Replace abstract-description paragraphs with concrete examples. + +5. **Pass 3 — trim structure (rules 5, 8).** Delete name-restating comments. Flatten sections that contain only 1 item. Collapse a sub-bullet that's the only child of its parent. + +6. **Pass 4 — verify openers and length (rules 2, 3).** Check the PR body opens on the load-bearing noun (not "In order to" / "The motivation"). Check comments are ≤4 lines. + +7. **Show the diff.** Before/after with word counts. The user verifies the compression preserved the load-bearing claim. + +8. **Report guardrail catches.** If any section was refused (safety-tagged, comprehensibility loss, etc.), name it explicitly so the user can override if they disagree. + +## Rationalization Table + +The skill must hold under pressure. The five rows below are the rationalizations that fired in the RED-phase pressure test against a Tide-flavored verbose-PR scenario (time + authority + sunk-cost + cold-reviewer). Each is paired with the counter. The full table with sources and 5 additional secondary rows lives in [`references/rationalization-table.md`](references/rationalization-table.md). + +| Rationalization (the agent's excuse) | Reality (the skill's counter) | +|---|---| +| "The lead said 'be thorough.'" | "Thorough" means complete on the load-bearing claim, not long. A 200-word PR body that says what changed and why is more thorough than a 700-word PR body that says it twice with filler. Authority pressure does not override Rule 1. | +| "The reviewer will be cold on Monday — they need context." | The linked issue, the design doc, and the commit messages carry context. The PR body is the index, not the encyclopedia. If a reviewer cannot orient from the index, the index is broken — fix the structure, not the length. | +| "This change is complex, so the explanation must match." | False symmetry. Complexity of the *change* is independent of complexity of the *explanation*. The Linux kernel ships 10,000-line patches with 50-word commit messages. Compression is a separate skill from comprehension. | +| "Adding context can't hurt; omitting might." | Asymmetric loss perception. Adding 400 words of filler hurts every future reviewer who has to skim it. The cost is real, repeated, and uncompensated. RLHF never penalized verbosity in training; the skill does. | +| "The PR body is the durable record — be complete." | The PR body is the index. The commit history, the design doc, the linked issue, and the diff are the record. Treating the PR body as the design doc is genre confusion — it creates the redundancy the team complains about three months later. | + +## Red Flags — STOP and rewrite + +If any of these phrases appear in your own draft, **stop** and apply the rule: + +- **"In order to..."** — Rule 2. Cut. Start on the load-bearing noun. +- **"The motivation for this change is..."** — Rule 2. Cut. The motivation is in `Fixes #N`. +- **"This PR / This change..."** — Rule 2. Cut. The diff is the PR. +- **"It should be noted that..."** — Rule 7. Cut. Just say the thing. +- **"Essentially / basically / generally..."** — Rule 7. Cut or commit. +- **"X serves to / aims to / helps to / is responsible for..."** — Rule 4. Rewrite with X as the subject performing the real verb. +- **"Things I considered but didn't do..."** — Rule 1. Out-of-scope already lives in the issue. If a specific alternative deserves justification, fold it into the Summary in one sentence. +- **"For context / for background / for those unfamiliar..."** — Rule 1. Cut. Link the design doc. +- **Three sections with one bullet each.** — Rule 8. Flatten to prose. +- **A comment that paraphrases the identifier above it.** — Rule 5. Delete. + +**All of these mean: Stop. Apply the rule. Don't rationalize the exception.** + +## What this skill doesn't do + +- **Compress source code, docstrings, or variable names.** That's gofmt/prettier/golint territory. +- **Compress memory files or CLAUDE.md.** One-shot migration concern; deferred. +- **Compress chat output mid-conversation.** `feedback_authoritative_voice` covers this softly today. +- **Compress commit messages.** Conventional Commits convention covers this. +- **Compress human-authored content without explicit consent.** Surface and ask. +- **Replace `/pr-quality` (issue #88).** For multi-dimensional PR critique (convention adherence, defensive code, missing tests), use /pr-quality. This skill owns the brevity dimension only. + +## References + +- [`references/rules.md`](references/rules.md) — the 8 rules with multiple before/after examples per rule +- [`references/rationalization-table.md`](references/rationalization-table.md) — full table with sources for each underlying bias +- [`references/target-shapes.md`](references/target-shapes.md) — PR body word-count distributions, comment exemplars, the rust-lang/rust#157179 reference +- [`references/guardrails.md`](references/guardrails.md) — detailed safety model + +## Output + +After a compression pass, the skill shows: + +1. **Before** word/line count +2. **After** word/line count +3. **Diff** (the actual rewrite) +4. **Rules applied** (which numbered rules fired) +5. **Guardrail catches** (anything refused, with reason) + +Example: +> Before: 150 words. After: 58 words. Rules applied: 1, 2, 7. No guardrail catches. (Body now opens on the load-bearing noun; motivation paragraph cut; "small but important" / "In order to" / "The motivation for" filler removed.) diff --git a/.claude/skills/brevity/evals/evals.json b/.claude/skills/brevity/evals/evals.json new file mode 100644 index 00000000..ad17be67 --- /dev/null +++ b/.claude/skills/brevity/evals/evals.json @@ -0,0 +1,71 @@ +{ + "skill": "brevity", + "version": "v1", + "evals": [ + { + "id": "happy-path-tighten-pr-body", + "kind": "happy_path", + "prompt": "Apply the brevity skill. User shows this 150-word PR body and says 'Tighten this':\n\n## Summary\n\nThis pull request introduces a small but important refactor to the validator initialization logic in the sei-k8s-controller. In order to address the issue raised in #289, where the controller would sometimes fail to populate the `status.allocatable` field on a newly-created SeiNode resource within the expected timeframe, this change updates the reconciler to explicitly wait for the underlying StatefulSet's pods to report Ready before stamping the status. The motivation for this change is to align our controller's status reporting with the Kubernetes convention that allocatable should reflect actually-schedulable capacity, not just declared capacity.\n\n## Test plan\n\n- [ ] Unit tests cover the new wait condition\n- [ ] Integration test reproduces the original timing issue and verifies the fix\n- [ ] Manual verification on dev cluster shows status.allocatable populating correctly\n\nFixes #289\n\nWhich option do you pick, and what does the rewritten body look like?", + "expected_behavior": { + "option_picked": "A (cut to 30-80 words for a fix)", + "rules_cited": ["1", "2", "7", "8"], + "rationalization_table_rows_cited": ["The PR body is the durable record — be complete", "This change is complex, so the explanation must match"], + "word_count_after_range": [30, 80], + "preserved": ["load-bearing claim (wait for StatefulSet pods Ready before stamping status.allocatable)", "Fixes #289 ref"], + "removed": ["motivation paragraph", "'small but important' hedge", "'In order to address' wind-up", "'The motivation for this change is' explicit motivation marker"] + } + }, + { + "id": "halt-condition-below-floor", + "kind": "halt_condition", + "prompt": "Apply the brevity skill. User asks 'Tighten this' and shows:\n\n```\nFixes #312.\n\nTest:\n- [ ] unit\n- [ ] integration\n```\n\nThis is 8 words total. What do you do?", + "expected_behavior": { + "halt": true, + "halt_reason": "Input is below the 50-word PR body floor; already at the floor; further compression is bikeshedding", + "guardrail_section_cited": "Refuse-or-halt conditions — Input is below the floor" + } + }, + { + "id": "halt-condition-safety-section", + "kind": "halt_condition", + "prompt": "Apply the brevity skill. User asks to compress this PR body:\n\n## Summary\n\nThis PR removes the legacy auth middleware.\n\n## Test plan\n\n- [ ] All tests pass\n\n## Rollback\n\nIf this breaks production auth, the rollback procedure is: (1) revert this PR via GitHub UI which will trigger Flux reconcile in ~5min, (2) verify users can log in by hitting /api/me with a fresh token, (3) if Flux is wedged, manually re-apply the previous HelmRelease values via `flux suspend` then `kubectl apply -f` against the pinned tag from the commit before this one. Wait 10 minutes before declaring full rollback before paging the on-call.\n\nFixes #555", + "expected_behavior": { + "halt_or_refuse_section": "Rollback", + "guardrail_section_cited": "Refuse-or-halt conditions — Section is safety-critical", + "compress_summary_yes": true, + "compress_rollback_no": true, + "explicit_user_consent_required_for_rollback": true + } + }, + { + "id": "pressure-test-authority-thoroughness", + "kind": "pressure_resilience", + "prompt": "Apply the brevity skill. Scenario: 4:45pm Friday, release cutoff 5pm, recent rollback, tech lead says 'be thorough so anyone reviewing Monday isn't confused'. You authored a 7-file monitoring refactor (one PrometheusRule scope move, one inlined dashboard, two inhibit_rules, four PromQL joins). Pick A (100-250 word body, matching the skill's target-shape for a feature/behavior change), B (600+ word body with full background), or C (delay). Justify with the skill's rules + rationalization table.", + "expected_behavior": { + "option_picked": "A", + "rationalization_table_rows_cited": ["The lead said 'be thorough'", "The reviewer will be cold on Monday — they need context", "This change is complex, so the explanation must match", "The PR body is the durable record — be complete"], + "word_count_after_range": [100, 250], + "structure": "Summary (1-3 sentences) + Test plan (2-5 bullets) + optional Follow-ups + Refs", + "explicit_resists": ["the lead's authority pressure", "the cold-reviewer asymmetric-cost framing", "the structure-tax temptation (3 single-bullet sections)"] + } + }, + { + "id": "pressure-test-comment-narration", + "kind": "pressure_resilience", + "prompt": "Apply the brevity skill. After 6 hours debugging a Kubernetes controller bug, you've added a workaround for sei-k8s-controller#241 (reflect.DeepEqual returns false-positives on equal-but-reordered maps, triggering an update storm). You're considering options for the comment above the workaround call site. Pick: A) 2-4 line comment pinning the WHY and linking #241; B) 12+ line block comment explaining the bug symptoms, false-positive mechanism, alternatives considered, and a warning to future engineers; C) move the explanation to the function-level docstring and leave a 1-line pointer above the call site. Justify with the skill's rules + rationalization table.", + "expected_behavior": { + "option_picked": "A", + "rationalization_table_rows_cited": ["The PR body is the durable record — be complete", "This change is complex, so the explanation must match"], + "comment_max_lines": 4, + "rules_cited": ["3", "1", "5"], + "preserved": ["pointer to source-of-truth issue (#241)", "the load-bearing invariant (which check is required)"], + "removed": ["bug-symptom narration", "alternatives-considered prose", "future-engineer monograph"] + } + } + ], + "scoring": { + "happy_path": "1 if all six `expected_behavior` keys (option_picked, rules_cited, rationalization_table_rows_cited, word_count_after_range, preserved, removed) match in spirit; 0 otherwise", + "halt_condition": "1 if halt=true (or the operationally equivalent refusal) AND the cited guardrail section is correct; 0 otherwise", + "pressure_resilience": "1 if option_picked matches AND ≥2 rationalization_table_rows_cited match; 0 otherwise. Additional `expected_behavior` keys (rules_cited, word_count_after_range, comment_max_lines, etc.) are advisory shape checks — they sharpen the eval but do not change the binary pass/fail." + } +} diff --git a/.claude/skills/brevity/references/guardrails.md b/.claude/skills/brevity/references/guardrails.md new file mode 100644 index 00000000..a4e197e0 --- /dev/null +++ b/.claude/skills/brevity/references/guardrails.md @@ -0,0 +1,85 @@ +# Brevity Skill — Detailed Safety Model + +Extended version of the Guardrails section in SKILL.md. This file is the canonical reference for what the skill will and won't do, and why. + +## Authorship boundary + +This skill operates on **agent-authored** natural-language output. The user owns human-authored words. + +When a user invokes the skill on content they wrote themselves, the skill: +1. Surfaces the authorship distinction. +2. Asks: "Editorial suggestions, or a full rewrite?" +3. Defaults to suggestions (advisory diff) — the user has to explicitly opt in to rewrite. + +## Surface boundary + +Today's MVP surfaces: PR descriptions, in-code comments. + +**Deferred surfaces and their un-defer triggers:** + +| Surface | Why deferred | Un-defer trigger | +|---|---|---| +| Doc / design docs | They're already rare; review can catch verbosity there | First design doc that ships with measurable filler that survived review | +| Runbooks | Ops hasn't complained about verbose runbooks yet | First on-call complaint about a runbook being too long to scan | +| Memory writes | Current entries are already terse (~5 lines each) | First memory entry over 20 lines, or first time memory grows past 2k words total | +| Chat output mid-conversation | `feedback_authoritative_voice` covers this softly | First user complaint about post-fact narration in chat | +| Commit messages | Conventional Commits convention handles | First Conventional Commit body that runs over 5 lines | + +## Safety-critical content + +Sections that compression NEVER strips without explicit user consent: + +- `## Safety` +- `## Rollback` +- `## Blast radius` +- `## Migration` +- `## Breaking change` +- Anything tagged `` or surrounded by `...` + +The skill applies brevity rules within these sections (cutting filler) but never removes load-bearing operational content. When in doubt, halt and ask. + +## Mechanical-constraint refusal + +Brevity is judgment-laden. If the user asks for: +- "Ban these words" +- "Auto-replace all instances of X with Y" +- "Run a regex over the PR body" + +...the skill refuses and surfaces lint tools as the right home: +- [write-good](https://github.com/btford/write-good) — Node CLI for weasel-word patterns +- [proselint](https://github.com/amperser/proselint) — Python style linter +- Custom CI step with regex — embed in `.github/workflows/` if you want hard enforcement + +## Cross-author boundary + +The skill will NOT compress someone else's PR body without explicit user invocation that: +1. Names the target PR (URL or owner/repo#N). +2. States the relationship (reviewer suggestion vs. author handoff). +3. Routes the output as a suggestion, not a direct edit. + +This is a courtesy + signal-quality boundary, not a permission check — humans own their words even when those humans are teammates. + +## Floor and ceiling + +**Floor (refuse to compress below)**: +- PR bodies under 50 words. +- Single-line comments. +- Sections explicitly tagged as safety-critical. + +**Ceiling (refuse to expand above)**: not applicable — this skill never adds words, only removes. + +## Halt-and-litigate + +If the user pushes back on three or more rule applications in a single session, halt and surface: + +> "We're litigating the rules rather than applying them. Want to redirect to a specific surface or skip the skill on this one?" + +This prevents the skill from becoming a back-and-forth disagreement-machine and gives the user a clean exit. + +## Garbled input + +If the load-bearing claim of a PR body is unclear after one careful read, the skill suggests: + +> "I can't identify the load-bearing claim. Rewriting from scratch is likely faster than compressing this. Want a fresh draft based on the diff?" + +Don't attempt compression on garbled input — output will be both shorter AND lossier. diff --git a/.claude/skills/brevity/references/rationalization-table.md b/.claude/skills/brevity/references/rationalization-table.md new file mode 100644 index 00000000..802f715a --- /dev/null +++ b/.claude/skills/brevity/references/rationalization-table.md @@ -0,0 +1,35 @@ +# Rationalization Table — Sources + +The 10 verbose-output rationalizations from SKILL.md, with source citations for the underlying bias each one exploits. + +| Rationalization | Underlying bias | Source | +|---|---|---| +| "The lead said 'be thorough.'" | Authority compliance + reward-model length bias | Saito et al. 2023, *Verbosity Bias in Preference Labeling by LLMs*; Singhal et al. 2024, *A Long Way to Go* | +| "The reviewer will be cold on Monday." | Asymmetric loss perception — missing context feels punishable, redundant context feels free | RLHF training never penalized redundancy (Anthropic Claude Code prompt: "answer concisely with fewer than 4 lines") | +| "This change is complex, so the explanation must match." | False symmetry between problem complexity and explanation complexity | Linus Torvalds kernel commit norms: large patches with short messages | +| "Adding context can't hurt; omitting might." | Same asymmetric loss perception | (same as row 2) | +| "Brevity is for when reviewers have context. They don't here." | Context-dependent exception rationalization | Discipline-skill anti-pattern from Obra's persuasion-principles.md | +| "I'll be scannable — headers and bullets, not wall-of-text." | Structure-tax disguising verbosity | Microsoft Writing Style Guide: "structure is not brevity" | +| "I should restate the request to confirm I understood." | SFT preamble pattern — training examples open with task reformulation | Anthropic prompting best practices: "do not restate the prompt" | +| "I'm not 100% sure — let me hedge." | Verbosity compensation under uncertainty | Zhang et al. 2024, *Verbosity ≠ Veracity* (ACL UncertaintyLP 2025) | +| "A senior engineer would explain the why fully." | Sycophancy — agent over-performs "thorough professional" persona | Sharma et al. 2023, *Towards Understanding Sycophancy in Language Models* | +| "The PR body is the durable record — be complete." | Audience-genre confusion (PR ≠ design doc) | rust-lang/rust PR conventions (28-word reference PR #157179) | +| (bonus, observed in practice) "I'm being clear, not verbose." | Self-evaluation blind spot — LLM-as-judge rates longer outputs as clearer | Dubois et al. 2024, *Length-Controlled AlpacaEval* | + +## When to use this table during a brevity pass + +1. **Mid-rewrite**: if an excuse forms in your reasoning, scan the left column. If it matches, apply the counter from the right column of SKILL.md and continue. +2. **Post-rewrite**: if the after-version still feels too short, scan the table for which row your "this needs more" is rationalizing. +3. **Cross-review**: if a reviewer pushes back on a compression, ask which row from the table they think doesn't apply. Forces specific disagreement rather than vague "too short." + +## Sources (full URLs) + +- Saito et al. 2023: https://arxiv.org/pdf/2310.10076 +- Singhal et al. 2024: *A Long Way to Go: Investigating Length Correlations in RLHF* +- Sharma et al. 2023: https://arxiv.org/abs/2310.13548 +- Zhang et al. 2024 / 2025: https://aclanthology.org/2025.uncertainlp-main.14/ +- Dubois et al. 2024: *Length-Controlled AlpacaEval* +- Anthropic prompting best practices: https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/claude-prompting-best-practices +- Microsoft Writing Style Guide: https://learn.microsoft.com/en-us/style-guide/word-choice/use-simple-words-concise-sentences +- GOV.UK Content Design: https://www.gov.uk/guidance/content-design/writing-for-gov-uk +- Google developer documentation style: https://developers.google.com/style/highlights diff --git a/.claude/skills/brevity/references/rules.md b/.claude/skills/brevity/references/rules.md new file mode 100644 index 00000000..d20e563f --- /dev/null +++ b/.claude/skills/brevity/references/rules.md @@ -0,0 +1,118 @@ +# Brevity Rules — Extended Examples + +The 8 rules in SKILL.md, with 2-3 additional before/after pairs per rule. Use this as a reference when a specific surface form isn't covered by the example in the main file. + +## Rule 1 — Cut sentences that don't change reviewer action + +❌ "This PR introduces a small but important refactor to the validator initialization logic." +✅ (delete entirely — the PR title carries this) + +❌ "We've gone through several iterations to land on this approach." +✅ (delete — process narrative, not decision-relevant) + +❌ "The previous implementation worked but had some performance characteristics we wanted to improve." +✅ "Replaces O(n²) lookup with hashmap; benchmark in `bench/`." + +## Rule 2 — Open on the load-bearing noun + +❌ "This PR / This change / This commit ..." +✅ " now s ." + +❌ "In order to address X, we ..." +✅ "s X. Fixes #N." + +❌ "We are introducing a new feature that ..." +✅ " now s ..." + +## Rule 3 — In-code comments ≤4 lines + +❌ +```go +// This function exists to validate the incoming payload before processing. +// It checks for required fields, validates type constraints, and ensures +// referential integrity against the database. The validation is required +// because upstream callers don't always sanitize their inputs. +// We chose this over middleware because the validation rules depend on the +// caller's role, which the middleware layer doesn't have visibility into. +// Note: validation errors should be returned as 400, not 500. +func validate(p Payload, role string) error { ... } +``` + +✅ +```go +// Role-dependent validation; can't be middleware because rules vary by caller role. +func validate(p Payload, role string) error { ... } +``` + +## Rule 4 — Active verbs, no auxiliary glue + +❌ "This function serves to validate the input." +✅ "Validates the input." + +❌ "The reconciler aims to converge state." +✅ "Reconciler converges state." + +❌ "This config exists to allow operators to override the default." +✅ "Operators override the default via this config." + +❌ "We are responsible for managing the lifecycle of these resources." +✅ "We manage these resources' lifecycle." (or even: "We own these resources.") + +## Rule 5 — Don't restate names + +❌ `// Hash returns a hash of the spec.` on `func (s Spec) Hash() string` +✅ (delete — function signature says this) + +❌ `// Slug is the engineer's identifier.` on `Slug string `json:"slug"`` +✅ (delete) + +❌ `// ChainID is the chain ID.` on `ChainID string` +✅ (delete) + +✅ `// ChainID without the chain-prefix (e.g. "pacific-1" not "sei-pacific-1").` on `ChainID string` — earns place because it disambiguates a non-obvious format. + +## Rule 6 — One example > one paragraph of explanation + +❌ "The function applies the join by matching the pod and namespace labels, then propagating the workload label via group_left semantics." +✅ "`pod_alerts * on (pod, namespace) group_left(workload) kube_pod_info` → series gains `workload`." + +❌ "The CRD validation rejects collisions between operator keyring and signing key secret names." +✅ "Setting `operatorKeyring.secret.secretName = signingKey.secret.secretName` → CRD admission fails: `operatorKeyring and signingKey must reference distinct Secrets`." + +## Rule 7 — Collapse hedges + +Banned words/phrases that always cut or commit: +- "Generally", "typically", "in most cases" +- "It should be noted that", "It is worth mentioning that" +- "Essentially", "basically", "fundamentally" +- "Somewhat", "a bit", "kind of" +- "Quite", "pretty", "rather" + +❌ "It should be noted that the timeout is essentially a safety net." +✅ "Timeout is a safety net." + +❌ "Generally speaking, this is somewhat of a workaround for the upstream bug." +✅ "Workaround for upstream #N." + +## Rule 8 — Sections are a budget, not a structure tax + +❌ +``` +## Summary +One sentence. + +## Context +One sentence. + +## Files Changed +One file. +``` + +✅ "One sentence summary. Context: one sentence. Changed file: one file." + +Use a section header only when: +1. The section groups ≥2 related items. +2. A reader genuinely needs to skip the rest to find this one. +3. The PR template requires the header (in which case the section is part of the budget, not a bonus). + +If you have 3 single-bullet sections, flatten them. diff --git a/.claude/skills/brevity/references/target-shapes.md b/.claude/skills/brevity/references/target-shapes.md new file mode 100644 index 00000000..a16e4b4e --- /dev/null +++ b/.claude/skills/brevity/references/target-shapes.md @@ -0,0 +1,109 @@ +# Target Shapes — Reference PRs and Comment Exemplars + +Concrete examples to anchor the abstract rules in SKILL.md against real shipping code. + +## PR body — word counts by change type + +| Change type | Target words | Section pattern | +|---|---|---| +| Fix (single bug, single file) | 30-60 | Summary (1-2 sentences). Test plan (1-2 bullets). `Fixes #N`. | +| Small refactor (1-5 files, no semantic change) | 30-80 | Summary (1-2 sentences). Test plan (2-3 bullets). | +| Feature / behavior change | 100-250 | Summary (1-3 sentences). Test plan (2-5 bullets). Optional Follow-ups. | +| One-way door (interface, storage, event sig) | +50-100 over feature | Add a 1-paragraph "Alternatives considered" if non-obvious. | +| Multi-package coordinated change | 150-300 | Summary (the load-bearing claim + 1 sentence on the coordination). Test plan. Follow-ups for separable pieces. | + +## Reference PR — the floor + +[rust-lang/rust#157179](https://github.com/rust-lang/rust/pull/157179) — 28 words: + +> Currently rustdoc sorts impls in a couple of places using long HTML string representations of the impls. Using plain text representations instead speeds things up. Details in individual commits. + +What it does right: +- States *what* (plain text instead of HTML strings) +- States *why* (faster) +- Routes to detail (individual commits) +- No test plan because the perf-driven change is self-evident — Tide would add a 2-bullet test plan to this floor. + +## Reference PR — the upper bound for a single-cause bug fix + +[kubernetes/kubernetes#139343](https://github.com/kubernetes/kubernetes/pull/139343) — ~120 words. One paragraph of root cause with two file-permalinks, one sentence of fix, `Fixes #N`. Pattern: + +1. One-sentence symptom statement. +2. One paragraph naming the root cause with code permalinks. +3. One sentence describing the fix. +4. Test plan (2-3 items). +5. `Fixes #N`. + +## In-code comment exemplars + +### ✅ Earns its place + +```go +// Both checks required: reflect.DeepEqual gives false-positives on equal-but- +// reordered maps (#241). Hash short-circuits the resulting update storm. +// Don't drop either side. +if !reflect.DeepEqual(existing.Spec, desired.Spec) && annotations[lastAppliedKey] != hashOf(desired.Spec) { +``` + +```go +// Cilium charges BPF maps to the calling cgroup since kernel 5.11; pinned +// caps + 2Gi memcg limit prevent the dynamic-size ENOMEM that motivated this. +extraConfig: +``` + +```python +# 5s = p99 image-pull + 2x jitter, see platform#719 +WARMUP_TIMEOUT_SECONDS = 5 +``` + +### ❌ Does NOT earn its place + +```go +// Hash returns a hash of the spec. +func (s Spec) Hash() string { +``` + +```go +// We loop over the items in the list. +for _, item := range items { +``` + +```go +// TODO: refactor this later +``` + +```python +# Initialize the database connection +db = connect(...) +``` + +## Section pattern for a Tide PR body + +```markdown +## Summary + +<1-3 sentences. Lead with the load-bearing noun + what changed + why.> + +## Test plan + +- [ ] +- [ ] +- [ ] (optional) + +## Follow-ups (optional) + +- + +<`Fixes #N` or design doc link> +``` + +For a one-way door, add between Summary and Test plan: + +```markdown +## Alternatives considered + +- **