- sickdays: normalise_keep raises TypeError (not ValueError) for a bare string -- ruff 0.17.2 TRY004; it is a caller type error, the CLI always passes a list. - sickdays: remove_sick_day and set_kept_lockers share require_sick(), which clears pylint R0801 (duplicate-code, 9.99/10 under --fail-under=10). - repo_contract/web.py: tomllib sorts as stdlib under ruff 0.17.x (I001). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NBScELfMUiieK9ManFbS3Y |
||
|---|---|---|
| .. | ||
| templates | ||
| tests | ||
| __init__.py | ||
| agent_ready_gate.py | ||
| bootstrap.py | ||
| check.py | ||
| contract.py | ||
| infer.py | ||
| install_web.py | ||
| install.py | ||
| isolate.py | ||
| precommit.py | ||
| README.md | ||
| sources.py | ||
| stacks.py | ||
| sweep.py | ||
| web.py | ||
repo_contract
Shared gate: every repo tells an agent how to run and test it, so nobody has to
explore. Enforced like the other shared gates (real gate in ~/src/utils, a
thin shim per repo, pre-commit + CI).
The contract
CLAUDE.md (or AGENTS.md that CLAUDE.md symlinks to) has a ## Commands
section with one line per key, exactly - <key>: \``:
## Commands
- run: `<command>` | n/a: library
- test: `<full suite>`
- test-changed: `scripts/test_changed.sh`
- lint: `<command>`
- coverage: `<command writing a report>`
- coverage-gaps: `coverage-gaps <report>`
Rules (all machine-checked):
- All six keys present, once each. A value is a backticked command or
n/a: <reason>/n/a (<reason>). A baren/afails: n/a carries a reason. test-changedinvokes an existing, executablescripts/test_changed.sh-style script that runs only tests related to files changed vs HEAD, falls back to the full suite when it cannot map, and prints failures plus a one-line summary only.coverage-gapsruns the shared listercoverage-gaps <report>(~/src/utils/coverage_gaps).test,test-changed,lint,coverageare quiet: no-v/--verbose/ expanded reporter, in the command or in the script's runner lines.- No placeholders (
<FILL IN>,TODO,...). - If
testis n/a, thentest-changed,coverage,coverage-gapsare n/a too, and the repo must contain no tests (bounded scan).
Use
python3 ~/src/utils/repo_contract/check.py --repo <path> # 0 pass / 1 violations / 2 unreadable
python3 ~/src/utils/repo_contract/bootstrap.py --repo <path> # print proposal
python3 ~/src/utils/repo_contract/bootstrap.py --repo <path> --write
python3 ~/src/utils/repo_contract/sweep.py # ~/data/claude-scratch/repo-contract/SWEEP.md
Bootstrap never overwrites: it appends the section (or inserts missing lines at
the end of an existing ## Commands), creates CLAUDE.md -> AGENTS.md when
only AGENTS.md exists, and writes scripts/test_changed.sh only if absent.
Sources, in priority order: existing CLAUDE.md, scripts/<key>.sh, Makefile,
package.json (node only), CI workflows, stack defaults. Anything it cannot infer
is written as <FILL IN>, which the gate rejects until a human fills it.
Adding the gate to a repo
Run this on every new repo right after git init (idempotent):
~/src/utils/scripts/install_repo_contract_gate.sh <repo> # --check to preview
It writes the scripts/check_repo_contract.sh shim, the pre-commit hook, the
CI workflow (skipped when the repo has .dep-freshness-no-workflow, i.e. no
GitHub Actions), then bootstraps the ## Commands section and
scripts/test_changed.sh. It exits 1 while a <FILL IN> remains. Never copy
scripts/check_repo_contract.sh from this repo (it is the real gate, not a shim).
The hook only fires on commits touching CLAUDE.md/AGENTS.md/test_changed.sh,
so a repo that never got the installer is caught only by sweep.py.
Websites: the AgentReady gate
Every website kuhy owns must pass ~/src/utils/agent_ready (decided
2026-10-22). A repo is a website when repo-contract.toml has an
[agent_ready] table, or when detection finds a node web build: a build
script in package.json plus a Vite or Astro config or a root index.html.
check.py fails a detected repo that has no table. Keys:
dist = "<build dir>" with optional build and install, or
url = "https://..." for server-rendered sites, or skip = "<reason>" for a
repo that is not a website. act = true turns on the act checks.
For a website, the installer also writes the proposed table (it never
overwrites one), the scripts/check_agent_ready.sh shim, the agent-ready
pre-commit hook, and .github/workflows/agent-ready.yml. That workflow checks
out kuhyx/utils into .utils, sets up Node, and runs
check_agent_ready.sh --strict --install. The shared gate
scripts/check_agent_ready.sh builds the site and runs
agent_ready/check.sh dist|url. The build runs in a throwaway copy of the
working tree (isolate.py), because a live dist/ may be bind-mounted into
Caddy and must never be emptied by a commit. The hook only fires when a
web-relevant file is staged (web.DEFAULT_FILES, overridable with
files = "<regex>"); CI rebuilds on every push. Without --strict, an unreachable url
degrades to a pass, and the gate defers to that workflow when run inside
another GitHub Actions job.
Tests
PYTHONPATH=. python -m pytest repo_contract/tests -q --cov=repo_contract --cov-branch --cov-fail-under=100