Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/claude-code-marketplace.json",
"name": "clean-code-toolkit",
"version": "3.6.1",
"version": "3.6.2",
"description": "Clean-code and product-handoff tools for AI-assisted builders.",
"owner": {
"name": "Tarik Moody"
Expand All @@ -10,7 +10,7 @@
{
"name": "clean-code-toolkit",
"description": "Review code, assess product readiness, refactor safely, and prepare a developer handoff.",
"version": "3.6.1",
"version": "3.6.2",
"author": {
"name": "Tarik Moody"
},
Expand Down
2 changes: 1 addition & 1 deletion .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "clean-code-toolkit",
"version": "3.6.1",
"version": "3.6.2",
"description": "Practical clean-code, product-readiness, and developer-handoff workflows for AI-assisted projects.",
"author": {
"name": "Tarik Moody"
Expand Down
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
# Changelog

## 3.6.2

A documentation pass that found the README making a promise the code did not keep.

**The Python version guard now exists.** The README said the script "stops with a clear message on anything older" than Python 3.9. No such check was anywhere in the codebase. On 3.8 the reader got `TypeError: 'type' object is not subscriptable` from an import, which is not a message, and the audience for this toolkit is often running the macOS system python3. There is now a guard, it sits above the imports that would crash first, and it names the version you have, the version you need, and two ways to fix it. It exits 2, which is the documented code for "could not run".

**The README and the code are pinned to each other.** Four new tests: the guard must sit above the imports or it can never fire; the version the README states must be the version the code enforces; the skill and command counts in the README must match what is on disk; and every relative link in the README must point at a file that exists. A promise in a document that the software does not keep is the same defect this toolkit exists to find.

**Exit codes are in the README.** 3.6.1 documented them in `--help` and SKILL.md but not where someone wiring a pipeline would look, along with the command to gate CI on the audit.

**The decision log is linked.** Nine decisions are written up in `docs/decisions`, in plain English, with what was given up and how we will know if each was right. Nothing pointed at them, and the repository layout in the README predated the folder.

Tests: 122.

## 3.6.1

A second developer review, run under the stop rule from 3.6.0: look for a new class of defect, not another instance of a closed one. Nine adversarial probes found every closed class still closed. A filename carrying `|` cannot forge a table column, a filename starting `#` cannot forge a heading, a symlink to `~/.ssh/id_ed25519` leaks nothing, binary and invalid-UTF-8 files do not crash it, a 400,000-line file hits the byte cap, a symlink loop does not hang it, 10,000 files take about ten seconds with no blowup, and two runs against the same commit are byte-identical in both markdown and JSON.
Expand Down
23 changes: 21 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,23 @@ To add the standards to a project without the plugin:

It creates or appends to `CLAUDE.md` and refuses to overwrite a section it cannot migrate safely.

To gate a pipeline on the audit, run the script directly and read the exit code:

```bash
python3 skills/prod-readiness-coach/scripts/prod_audit.py \
--repo . --output /dev/null --fail-on critical
```

The exit codes are a contract you can wire CI against:

| Code | Meaning |
|---|---|
| `0` | The audit ran and nothing at or above `--fail-on` failed. |
| `1` | The audit ran and something at or above `--fail-on` failed. |
| `2` | The audit could not run: the path is missing, is a file, or holds no files. |

Exit `2` is never a verdict about your code. It means nothing was scanned, so check the path.

Repository layout:

```text
Expand All @@ -163,10 +180,12 @@ Repository layout:
├── skills/ # the six skills and their reference files
├── scripts/ # installer and validator
├── templates/CLAUDE.md # the always-on standards
└── docs/ # guides, including the release checklist
└── docs/
├── decisions/ # why each non-obvious call was made
└── ... # guides, including the release checklist
```

The root `CLAUDE.md` holds contributor instructions for this repository. User-facing behavior lives in the skills, commands, and the installable template. Maintainers follow the [release checklist](docs/release-checklist.md) before tagging.
The root `CLAUDE.md` holds contributor instructions for this repository. User-facing behavior lives in the skills, commands, and the installable template. Maintainers follow the [release checklist](docs/release-checklist.md) before tagging. Every call that a reasonable person could have made differently is written up in [docs/decisions](docs/decisions), in plain English, with what was given up and how we will know if it was right.

**One of the six tools is a script, and that script is tested.** `prod-readiness-coach` keeps a coverage grid: every check has to prove it fires when a control is missing and stays quiet when the control is there. It sits at 83 of 83 and CI fails if it slips. Run `python3 skills/prod-readiness-coach/scripts/coverage_grid.py` to see it.

Expand Down
14 changes: 14 additions & 0 deletions skills/prod-readiness-coach/scripts/prod_audit.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,20 @@
from datetime import datetime, timedelta, timezone
from pathlib import Path

# The audit modules use syntax that 3.8 cannot parse, so this has to sit ABOVE
# the imports below. Moved under them, it never runs and the reader gets
# "TypeError: 'type' object is not subscriptable" instead of a sentence. The
# audience here is often on the macOS system python3, which is old.
MIN_PYTHON = (3, 9)
if sys.version_info < MIN_PYTHON:
sys.stderr.write(
f"error: this script needs Python {MIN_PYTHON[0]}.{MIN_PYTHON[1]} or newer, "
f"and you are running {sys.version.split()[0]}.\n"
"On macOS the built-in python3 is usually older than the one you installed. "
"Try `python3.12` or `python3.11` in place of `python3`, or install a current "
"Python from python.org or with `brew install python`.\n")
raise SystemExit(2)

from audit.model import ( # noqa: F401 (re-exported for callers and tests)
CHECK_SKIPS_BY_PROFILE, CONTRADICTIONS, MIN_DOC_WORDS, PROFILES,
SEVERITY_LABEL, SEVERITY_PENALTY, SEVERITY_PENALTY_WARN, WAIVER_FIELDS, WAIVER_FILE, WAIVER_MAX_AGE_DAYS,
Expand Down
35 changes: 35 additions & 0 deletions skills/prod-readiness-coach/tests/test_prod_audit.py
Original file line number Diff line number Diff line change
Expand Up @@ -803,5 +803,40 @@ def test_product_context_survives_as_readable_text(self):
self.assertIn("Losing a day of mail would be bad.", md)


class TheReadmeMustMatchTheCode(unittest.TestCase):
"""The README promised a clear message on an old Python and no guard existed.
A promise in a document that the software does not keep is the same defect
this toolkit exists to find, so the two are pinned to each other here."""

ROOT = Path(__file__).resolve().parents[3]
SCRIPT = Path(__file__).resolve().parent.parent / "scripts" / "prod_audit.py"

def test_the_guard_sits_above_the_imports_that_would_crash_first(self):
src = self.SCRIPT.read_text()
self.assertLess(src.index("sys.version_info"), src.index("from audit."),
"the version guard is below the imports, so it can never run")

def test_the_readme_states_the_version_the_code_enforces(self):
readme = (self.ROOT / "README.md").read_text()
major, minor = prod_audit.MIN_PYTHON
self.assertIn(f"Python {major}.{minor} or newer", readme,
f"README does not state the enforced floor of {major}.{minor}")

def test_the_readme_names_the_right_number_of_skills_and_commands(self):
readme = (self.ROOT / "README.md").read_text()
skills = len([d for d in (self.ROOT / "skills").iterdir() if d.is_dir()])
commands = len(list((self.ROOT / "commands").glob("*.md")))
words = {6: "six", 3: "three", 5: "five", 7: "seven", 4: "four"}
self.assertIn(f"{words[skills]} skills and {words[commands]} commands", readme,
f"README count is stale: there are {skills} skills and {commands} commands")

def test_every_link_in_the_readme_points_at_something_real(self):
import re
readme = (self.ROOT / "README.md").read_text()
dead = [t for t in re.findall(r"\]\((?!https?:)([^)#]+)", readme)
if not (self.ROOT / t).exists()]
self.assertEqual(dead, [], f"dead links in README: {dead}")


if __name__ == "__main__":
unittest.main()
Loading