-
Notifications
You must be signed in to change notification settings - Fork 0
Add concise-comments skill; wire into /spec & /process-reviews #9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| --- | ||
| name: concise-comments | ||
| description: Rules for concise code comments/docstrings, plus a pass to trim verbose ones. Use when writing or reviewing code, or when asked to reduce comment verbosity / trim over-commented code / cut docstring bloat. Referenced by /spec and /process-reviews. | ||
| --- | ||
|
|
||
| # Concise comments & docstrings | ||
|
|
||
| Prevention: follow these when writing. Cleanup: run the pass below when invoked as `/concise-comments`. | ||
|
|
||
| ## The test | ||
| Keep a comment only if a competent reader of THIS codebase couldn't infer it from the code and names. Otherwise delete it, or cut it to the one missing fact in one line. | ||
|
|
||
| ## For / not for | ||
| For: the non-obvious *why* (constraint, invariant, footgun, edge-case gotcha) and a one-line *what* on public APIs. | ||
| Not for: design narrative, alternatives-considered, defending the approach, repro steps, byte-count walkthroughs, ticket history, or restating the code. Those go in the PR description, DECISIONS.md, the issue, or a test. | ||
|
|
||
| ## Limits (defaults; exceed only with a stated reason) | ||
| - Inline comment: 1 line. Needing 3+ lines to justify a line of code → rename things or move the rationale out. | ||
| - Function/method docstring: 1-line summary; +≤3 lines only for genuinely subtle behaviour. | ||
| - Module docstring: ≤8 lines. Test docstring: 1 line, or none if the name says it. | ||
| - Section banner: ≤1 label line, no `---` paragraphs. | ||
|
|
||
| Say it once at the definition; don't re-explain at every call site. | ||
|
|
||
| ## Delete on sight | ||
| - **Restates the code** (`# strip prefix` above `x.split(...)`). | ||
| - **Ticket-ID noise** (`DEV-1234:` on every line/attribute; the value is the fact). | ||
| - **Design essay / justification debate** (paragraphs on why this is right and alternatives wrong). | ||
| - **Worked examples & repros** (byte counts, sample output) → move to the test. | ||
| - **Docstring echoing the name** (`def test_x: """Test x."""`). | ||
| - **Emphasis theatre** (ALL-CAPS sentences, "astronomically", "provably", "THE … requirement"). | ||
|
|
||
| Keep, as ≤1 line: a real cross-dialect/edge gotcha, a non-obvious invariant, a "looks wrong but isn't", an ordering/side-effect warning. When unsure a *why* is inferable, keep it but shorten it. | ||
|
|
||
| ## The pass (`/concise-comments`) | ||
| 1. Scope: default to the branch diff (`git diff $(git merge-base <base> HEAD) -- '*.py'`); or the path/file the user names. Only added/modified comments unless told to sweep. | ||
| 2. Edit comments/docstrings ONLY — never code, string literals, test data, asserts, imports, markers. | ||
| 3. Verify: run affected tests + linter (green); confirm `git diff` changed no code line; measure before/after with `scripts/count_comments.py --range <mergebase> <paths>`. | ||
| 4. Report per-file and total lines before → after + ratio, and that tests/lint pass. | ||
|
|
||
| Scale to the ask: "trim a bit" = kill the essays; "3x" / "massively" = apply every limit hard. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,87 @@ | ||
| #!/usr/bin/env python3 | ||
| """Count comment + docstring lines in Python files. | ||
|
|
||
| Comments via tokenize, docstrings via AST (module/class/function first stmt). | ||
|
|
||
| count_comments.py <file>... # per-file + total counts | ||
| count_comments.py --range <ref> <path>... # net added vs a git ref (working tree) | ||
| """ | ||
| from __future__ import annotations | ||
|
|
||
| import ast | ||
| import io | ||
| import subprocess | ||
| import sys | ||
| import tokenize | ||
|
|
||
|
|
||
| def counts(src: str | None) -> tuple[int, int]: | ||
| if src is None: | ||
| return (0, 0) | ||
| try: | ||
| comment = sum( | ||
| 1 for t in tokenize.generate_tokens(io.StringIO(src).readline) | ||
| if t.type == tokenize.COMMENT | ||
| ) | ||
| except Exception: | ||
| comment = 0 | ||
| doc = 0 | ||
| try: | ||
| tree = ast.parse(src) | ||
| except Exception: | ||
| return (comment, 0) | ||
| kinds = (ast.Module, ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef) | ||
| for node in ast.walk(tree): | ||
| if isinstance(node, kinds): | ||
| body = getattr(node, "body", []) | ||
| first = body[0] if body else None | ||
| if ( | ||
| isinstance(first, ast.Expr) | ||
| and isinstance(getattr(first, "value", None), ast.Constant) | ||
| and isinstance(first.value.value, str) | ||
| ): | ||
| doc += first.end_lineno - first.lineno + 1 | ||
| return (comment, doc) | ||
|
|
||
|
|
||
| def git_show(ref: str, path: str) -> str | None: | ||
| r = subprocess.run(["git", "show", f"{ref}:{path}"], capture_output=True, text=True) | ||
| return r.stdout if r.returncode == 0 else None | ||
|
Comment on lines
+47
to
+49
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- file map ---'
ast-grep outline skills/concise-comments/scripts/count_comments.py
printf '%s\n' '--- relevant source ---'
cat -n skills/concise-comments/scripts/count_comments.py | sed -n '1,140p'
printf '%s\n' '--- tracked related files ---'
git ls-files | rg '(^|/)(count_comments|test|tests)' | head -100
printf '%s\n' '--- structural references to git_show ---'
ast-grep run --lang python --pattern 'git_show($_, $_)' skills/concise-comments/scripts/count_comments.pyRepository: MotleyAI/claude-configs Length of output: 3891 🏁 Script executed: #!/bin/bash
set -eu
python3 - <<'PY'
import subprocess
def git_show(ref: str, path: str):
r = subprocess.run(
["git", "show", f"{ref}:{path}"],
capture_output=True,
text=True,
)
return r.stdout if r.returncode == 0 else None, r.returncode, r.stderr.strip()
head = subprocess.run(
["git", "rev-parse", "--verify", "HEAD"],
capture_output=True,
text=True,
check=True,
).stdout.strip()
cases = [
("invalid-ref", "HEAD_DOES_NOT_EXIST", "skills/concise-comments/scripts/count_comments.py"),
("missing-path", head, "skills/concise-comments/scripts/path_does_not_exist.py"),
("valid-path", head, "skills/concise-comments/scripts/count_comments.py"),
]
for name, ref, path in cases:
value, code, error = git_show(ref, path)
print(f"{name}: returncode={code}, result_is_none={value is None}, stdout_len={len(value or '')}, stderr={error!r}")
PYRepository: MotleyAI/claude-configs Length of output: 563 Validate the Git reference before reading the file. 🧰 Tools🪛 ast-grep (0.45.1)[error] 47-47: Command coming from incoming request (subprocess-from-request) 🪛 Ruff (0.16.1)[error] 48-48: (S603) [error] 48-48: Starting a process with a partial executable path (S607) 🤖 Prompt for AI Agents |
||
|
|
||
|
|
||
| def read(path: str) -> str | None: | ||
| try: | ||
| return open(path, encoding="utf-8").read() | ||
| except FileNotFoundError: | ||
| return None | ||
|
Comment on lines
+52
to
+56
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win Make missing-file handling mode-aware.
Also applies to: 77-79 🧰 Tools🪛 ast-grep (0.45.1)[warning] 53-53: File path is request-/variable-derived; validate and normalize to prevent path traversal. (open-filename-from-request) 🤖 Prompt for AI Agents |
||
|
|
||
|
|
||
| def main(argv: list[str]) -> int: | ||
| if argv and argv[0] == "--range": | ||
| ref = argv[1] | ||
| paths = argv[2:] | ||
|
Comment on lines
+59
to
+62
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win Validate
🤖 Prompt for AI Agents |
||
| tc = td = 0 | ||
| for p in paths: | ||
| b = counts(git_show(ref, p)) | ||
| h = counts(read(p)) | ||
| dc, dd = h[0] - b[0], h[1] - b[1] | ||
| print(f"{dc + dd:+5d} comment={dc:+4d} doc={dd:+4d} {p}") | ||
| tc += dc | ||
| td += dd | ||
| print(f"{'=' * 50}\nNET ADDED total={tc + td} (comment {tc}, docstring {td})") | ||
|
Comment on lines
+65
to
+71
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win Align This branch prints only deltas. 🤖 Prompt for AI Agents |
||
| return 0 | ||
| if not argv: | ||
| print(__doc__) | ||
| return 1 | ||
| tc = td = 0 | ||
| for p in argv: | ||
| c, d = counts(read(p)) | ||
| print(f"{c + d:5d} comment={c:4d} doc={d:4d} {p}") | ||
| tc += c | ||
| td += d | ||
| print(f"{'=' * 50}\nTOTAL={tc + td} (comment {tc}, docstring {td})") | ||
| return 0 | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| raise SystemExit(main(sys.argv[1:])) | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
Add solid tests for the shipped utility.
This change adds parsing, Git-reference, file, and CLI behavior without adding tests. Cover valid and malformed Python, module/class/function/async docstrings, missing files, invalid refs, deleted paths, and incomplete
--rangearguments.As per coding guidelines: “Whenever you do any changes to production code ... ALWAYS add solid test coverage for it.”
🤖 Prompt for AI Agents
Source: Coding guidelines