style(no-slop): remove every em-dash + banned words across all modules + capstone
Apply the no-ai-slop standard (now binding in AGENTS.md): the em-dash character is banned outright (restructured, not blind-replaced), plus the banned word/phrase list (delve, leverage, robust, seamless, truly, unlock, etc.). 0 em-dashes remain in modules + capstone; the only "robust" left is the planted M10 ai-change.patch trap. Module H1 titles use a colon separator. All deliberate teaching devices preserved; labs compile/parse (py/sh/yaml/json); no junk. AGENTS.md updated with the hard no-slop rules. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TfzV5QvtPDz8LJS3Pu5VLT
This commit is contained in:
@@ -6,13 +6,13 @@
|
||||
"file": "cli.py",
|
||||
"line": 49,
|
||||
"severity": "blocker",
|
||||
"comment": "The `clear` branch never calls save(tlist). The list is emptied in memory and the process exits, so tasks.json is untouched. It prints 'cleared all tasks' but the next `list` shows everything still there — a silent no-op. Add save(tlist) before printing."
|
||||
"comment": "The `clear` branch never calls save(tlist). The list is emptied in memory and the process exits, so tasks.json is untouched. It prints 'cleared all tasks' but the next `list` shows everything still there, a silent no-op. Add save(tlist) before printing."
|
||||
},
|
||||
{
|
||||
"file": "tasks.py",
|
||||
"line": 28,
|
||||
"severity": "suggestion",
|
||||
"comment": "No test covers clear(). Add one that adds two tasks, calls clear(), and asserts the list is empty — matching the Module 13 suite style."
|
||||
"comment": "No test covers clear(). Add one that adds two tasks, calls clear(), and asserts the list is empty, matching the Module 13 suite style."
|
||||
},
|
||||
{
|
||||
"file": "tasks.py",
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
# Label taxonomy — the triage agent's instructions
|
||||
# Label taxonomy: the triage agent's instructions
|
||||
|
||||
The triage agent reads this file, then reads one incoming issue, and proposes labels, a priority,
|
||||
and where the issue should be routed. Like the review rubric, this is committed and versioned: your
|
||||
triage taxonomy is a project decision, not a setting buried in some bot's web UI.
|
||||
|
||||
**The labels below are the only labels that exist.** The agent must choose from this list. If it
|
||||
invents a label that isn't here, the lab's `triage.py` rejects the whole suggestion — that rejection
|
||||
invents a label that isn't here, the lab's `triage.py` rejects the whole suggestion; that rejection
|
||||
is a guardrail, not a bug. An agent that can mint arbitrary labels is an agent that can quietly
|
||||
reshape your taxonomy; keeping the allowed set in version control and validating against it is how
|
||||
you keep the agent inside its lane (the least-privilege idea from Module 22).
|
||||
@@ -13,27 +13,27 @@ you keep the agent inside its lane (the least-privilege idea from Module 22).
|
||||
## Allowed labels
|
||||
|
||||
Type (exactly one):
|
||||
- `type:bug` — something is broken or behaves wrong
|
||||
- `type:feature` — a request for new behavior
|
||||
- `type:docs` — documentation only
|
||||
- `type:question` — a usage question, not a code change
|
||||
- `type:bug`: something is broken or behaves wrong
|
||||
- `type:feature`: a request for new behavior
|
||||
- `type:docs`: documentation only
|
||||
- `type:question`: a usage question, not a code change
|
||||
|
||||
Priority (exactly one):
|
||||
- `priority:p0` — data loss, security, or the app is unusable for everyone
|
||||
- `priority:p1` — a serious bug with no good workaround
|
||||
- `priority:p2` — a real bug with a workaround, or a wanted feature
|
||||
- `priority:p3` — minor, cosmetic, or nice-to-have
|
||||
- `priority:p0`: data loss, security, or the app is unusable for everyone
|
||||
- `priority:p1`: a serious bug with no good workaround
|
||||
- `priority:p2`: a real bug with a workaround, or a wanted feature
|
||||
- `priority:p3`: minor, cosmetic, or nice-to-have
|
||||
|
||||
Area (zero or more):
|
||||
- `area:cli` — the command-line front end (`cli.py`)
|
||||
- `area:core` — task logic (`tasks.py`)
|
||||
- `area:docs` — README and lesson text
|
||||
- `area:cli`: the command-line front end (`cli.py`)
|
||||
- `area:core`: task logic (`tasks.py`)
|
||||
- `area:docs`: README and lesson text
|
||||
|
||||
Readiness (exactly one) — this is the one that decides routing, and it's the Module 9 idea made
|
||||
Readiness (exactly one). This is the one that decides routing, and it's the Module 9 idea made
|
||||
concrete: an issue can go to a person *or* be handed to an agent.
|
||||
- `ready:ai-ready` — small, well-scoped, reproducible; safe to hand to an issue-to-PR agent (the
|
||||
- `ready:ai-ready`: small, well-scoped, reproducible; safe to hand to an issue-to-PR agent (the
|
||||
kind of agent Module 25 builds). Route `assignee_type: agent`.
|
||||
- `ready:needs-human` — ambiguous, risky, or needs a product decision. Route `assignee_type: human`.
|
||||
- `ready:needs-human`: ambiguous, risky, or needs a product decision. Route `assignee_type: human`.
|
||||
|
||||
## Output format
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
# Review rubric — the AI reviewer's instructions
|
||||
# Review rubric: the AI reviewer's instructions
|
||||
|
||||
This is the committed instruction set the AI reviewer reads before it looks at a diff. It lives in
|
||||
the repo on purpose: like the committed AI config from Module 5 and the skills from Module 21, a
|
||||
review rubric is a durable, versioned artifact. Change how the reviewer behaves and that change
|
||||
arrives as a diff in a PR, reviewable like any other.
|
||||
|
||||
Keep it short and opinionated. A vague rubric produces vague, noisy comments — the fastest way to
|
||||
Keep it short and opinionated. A vague rubric produces vague, noisy comments, the fastest way to
|
||||
get a team to ignore the AI reviewer entirely.
|
||||
|
||||
## What to check, in priority order
|
||||
@@ -17,7 +17,7 @@ get a team to ignore the AI reviewer entirely.
|
||||
3. **Security smells (Module 15).** Hardcoded secrets, shelling out on unsanitized input, a new
|
||||
dependency that doesn't obviously exist.
|
||||
4. **Correctness on edge cases.** Empty input, bad index, missing file.
|
||||
5. **Style nits — last, and clearly labeled.** Only if they matter. Nits drown signal.
|
||||
5. **Style nits, last, and clearly labeled.** Only if they matter. Nits drown signal.
|
||||
|
||||
## How to comment
|
||||
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
"""Assistive AI reviewer — local simulation of a PR-reviewer bot.
|
||||
"""Assistive AI reviewer: local simulation of a PR-reviewer bot.
|
||||
|
||||
This stands in for a forge-native reviewer (an app/bot triggered when a PR opens, running on a
|
||||
runner from Module 19) without needing any hosted account. It does the two deterministic halves of
|
||||
the job and leaves the one judgment call — what actually happens to the PR — to you.
|
||||
the job and leaves the one judgment call (what actually happens to the PR) to you.
|
||||
|
||||
python reviewer.py prompt # assemble the prompt: rubric + diff, for the agent to review
|
||||
python reviewer.py apply ai-review.sample.json # ingest the agent's JSON, render it, gate it
|
||||
|
||||
The point of this module: the agent produces comments and a recommendation. It never approves,
|
||||
never requests-changes-as-a-gate, never merges. The `apply` step ends at a HUMAN DECISION, every
|
||||
time. Stdlib only — no pip install.
|
||||
time. Stdlib only, no pip install.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
@@ -68,7 +68,7 @@ def cmd_apply(args: argparse.Namespace) -> int:
|
||||
comments = review.get("comments", [])
|
||||
|
||||
print("=" * 70)
|
||||
print("AI REVIEWER — first pass (advisory only)")
|
||||
print("AI REVIEWER: first pass (advisory only)")
|
||||
print("=" * 70)
|
||||
print(f"\nSummary: {summary}\n")
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Title: `done` command crashes on an empty list
|
||||
|
||||
When I run `python cli.py done 0` right after a fresh checkout — before adding any tasks — it throws
|
||||
When I run `python cli.py done 0` right after a fresh checkout, before adding any tasks, it throws
|
||||
an IndexError and dumps a stack trace instead of a friendly message. Every other command handles the
|
||||
empty-list case fine, so this one feels like an oversight.
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
"""Assistive issue-triage agent — local simulation of a triage bot.
|
||||
"""Assistive issue-triage agent: local simulation of a triage bot.
|
||||
|
||||
Stands in for a forge-native triage agent (triggered when an issue opens) without a hosted account.
|
||||
It assembles the prompt, then validates and renders the AI's suggestion — and stops at a human
|
||||
It assembles the prompt, then validates and renders the AI's suggestion, and stops at a human
|
||||
confirm. The agent proposes labels and a route; it does not apply them.
|
||||
|
||||
python triage.py prompt # taxonomy + issue -> prompt for the agent
|
||||
python triage.py apply ai-triage.sample.json # validate + render + confirm gate
|
||||
|
||||
The validation step matters: the agent may only use labels that exist in label-taxonomy.md. A
|
||||
hallucinated label is rejected. Stdlib only — no pip install.
|
||||
hallucinated label is rejected. Stdlib only, no pip install.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
@@ -31,7 +31,7 @@ and a rationale for the issue that follows. Return ONLY the JSON object the taxo
|
||||
"""
|
||||
|
||||
# Allowed labels are the backticked `prefix:value` tokens in the taxonomy file. Keeping the source
|
||||
# of truth in the committed markdown — not hardcoded here — is the point.
|
||||
# of truth in the committed markdown (not hardcoded here) is the point.
|
||||
LABEL_RE = re.compile(r"`([a-z]+:[a-z0-9-]+)`")
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ def cmd_apply(args: argparse.Namespace) -> int:
|
||||
bogus = [l for l in labels if l not in allowed]
|
||||
if bogus:
|
||||
print("=" * 70)
|
||||
print("REJECTED — the agent suggested labels that aren't in the taxonomy:")
|
||||
print("REJECTED: the agent suggested labels that aren't in the taxonomy:")
|
||||
for l in bogus:
|
||||
print(f" - {l}")
|
||||
print(
|
||||
@@ -85,7 +85,7 @@ def cmd_apply(args: argparse.Namespace) -> int:
|
||||
return 1
|
||||
|
||||
print("=" * 70)
|
||||
print("TRIAGE AGENT — suggestion (advisory only)")
|
||||
print("TRIAGE AGENT: suggestion (advisory only)")
|
||||
print("=" * 70)
|
||||
print(f"\n Labels: {', '.join(labels) or '(none)'}")
|
||||
print(f" Route to: {sug.get('assignee_type', '?')}")
|
||||
@@ -99,7 +99,7 @@ def cmd_apply(args: argparse.Namespace) -> int:
|
||||
" - confirm apply the labels and route as proposed\n"
|
||||
" - edit change a label or the route, then apply\n"
|
||||
" - reject the triage is wrong; do it yourself\n"
|
||||
"\nA wrong label here costs one glance and one click to fix — which is exactly why\n"
|
||||
"\nA wrong label here costs one glance and one click to fix, which is exactly why\n"
|
||||
"triage is the safe place to let an agent in first.\n"
|
||||
)
|
||||
return 0
|
||||
|
||||
Reference in New Issue
Block a user