Skip to content
Closed
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
80 changes: 80 additions & 0 deletions .claude/commands/rhiza_quality.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
---
description: Run the Rhiza code-quality gate and score the repo (lint, types, docs, deps, security, tests)
---

Assess the quality of this repo against Rhiza standards. Follow the
command-execution policy: always prefer `make <target>`; never invoke
`.venv/bin/...` directly. Run the gates in order — cheapest checks first so fast
failures surface before the slow test suite — and collect results:

Comment on lines +5 to +9
1. `make fmt` — pre-commit hooks + linting (ruff format/check, markdownlint, bandit, actionlint, …)
2. `make typecheck` — static type checking (`ty`, and `mypy --strict` if configured) over `src/`
3. `make docs-coverage` — docstring coverage (interrogate) over `src/`
4. `make deptry` — unused/missing/misplaced dependency analysis
5. `make security` — pip-audit + bandit scans
6. `make validate` — validate project structure against the Rhiza template (`.rhiza/template.yml`)
7. `make test` — full test suite **with** its coverage gate (slowest, run last)

Guidelines:

- Run all gates even after an early failure, so the full picture is visible
rather than stopping at the first red.
- If something fails, show the relevant output, diagnose the root cause, and
propose (or apply, if clearly correct, low-risk, **and** the fix is in a
locally-owned file per the scoping rule below) a fix.
- If `$ARGUMENTS` is non-empty, scope the assessment to that path or topic
instead of the whole repo.
- End with a concise PASS/FAIL summary per gate.

**Coverage expectation.** `make test` enforces a coverage gate
(`COVERAGE_FAIL_UNDER`, default 90%; many projects raise it to 100%). Treat
anything below the configured threshold on locally-owned `src/` as a gap to
flag, not an acceptable baseline. When scoring the test-coverage subcategory,
the configured threshold is the bar for a 10; report uncovered lines
(`file:line`) and the test that would close each.

**`make validate`.** A failure means this repo has drifted from the Rhiza
template (a synced file edited locally, or a missing/extra file). That is
in-scope: fix it by re-syncing from Rhiza or by adjusting `.rhiza/template.yml`,
not by editing the synced artifact in place.

Then report:

- A pass/fail summary per step.
- Failures grouped by file, with the specific rule/error and line.
- A prioritized list of what to fix first (blocking errors before style nits).

Then analyse the repo and give marks on a scale of 1 to 10 for all relevant
subcategories. Pick the subcategories that fit what you actually observe — e.g.
linting/style, type safety, test pass rate, test coverage & depth, code
structure & readability, documentation, dependency & security hygiene, CI/tooling
health. For each: the score, a one-line justification grounded in evidence from
the checks above (and a quick look at the code where needed), and what would
raise it. Close with an overall score and the single highest-leverage
improvement.

**Scope the scorecard to locally-owned items — not what the mother repo (Rhiza)
owns.** This project syncs its dev infrastructure from `jebel-quant/rhiza`; see
`CLAUDE.md` for the authoritative split and the `files:` block of
`.rhiza/template.lock` for the machine-generated list of synced files. Score
only what this repo actually controls — `src/`, `tests/`, `pyproject.toml`,
`README.md`, project-specific docs, `.rhiza/template.yml`, and any
locally-hardened config. Do **not** let Rhiza-managed files (the
`.github/workflows/*`, `Makefile`, `.pre-commit-config.yaml`, `pytest.ini`,
`ruff.toml`, the typecheck/mutation/fuzzing targets, etc.) drive the marks — a
gap there is fixed upstream in Rhiza, not here. If a relevant signal is
Rhiza-owned, note it as "upstream/out-of-scope" rather than scoring it against
this repo.
Comment on lines +56 to +67

Then, from the scorecard above, identify **actionable issues to improve the
score** — one per subcategory scoring below 10 (skip any that are maxed). For
each, give: a concrete title, the subcategory and current→target score it moves,
the specific file(s)/lines or config to change, and a crisp acceptance criterion
("done when…"). Keep them in-scope (locally-owned, per the scoping rule above) —
flag anything Rhiza-owned as upstream rather than listing it as a local action.
Order them by leverage (biggest score gain for least effort first). This is a
list of recommendations only — do not create GitHub issues or change code unless
I explicitly ask.

If everything passes, say so plainly — but still produce the 1–10 subcategory
marks. Do not fix anything unless I ask — this command only assesses.
100 changes: 100 additions & 0 deletions .claude/commands/rhiza_update.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
---
description: Update the pinned Rhiza version in .rhiza/template.yml, sync, resolve conflicts, and verify
---

Update this repo's Rhiza template to a newer release: bump the pin in
`.rhiza/template.yml`, run the sync, resolve every conflict, verify the quality
gates, and open a PR. Follow the command-execution policy: always prefer
`make <target>`; never invoke `.venv/bin/...` directly.

`$ARGUMENTS` may name a target version (e.g. `v0.19.1`). If empty, target the
**latest** release of the upstream template repo.
Comment on lines +5 to +11

## 1. Determine current and target versions

- Read `.rhiza/template.yml`: the `repository:` field is the upstream template
repo (usually `jebel-quant/rhiza`) and `ref:` is the currently pinned version.
- Resolve the target version:
- If `$ARGUMENTS` names a version, use it (verify the tag exists:
`gh api repos/<repository>/git/ref/tags/<ref>`).
- Otherwise get the latest release:
`gh release view --repo <repository> --json tagName,publishedAt`.
- If `ref:` already equals the target, report "already up to date" and stop.
- Briefly summarize what's between the two versions when it's cheap to do so
(`gh release view`/release notes), so the reviewer knows what's landing.

## 2. Bump the pin and commit (the tree must be clean to sync)

- `make sync` refuses to run on a dirty tree, so the bump lands first.
- Branch off the default branch (don't work on `main`/`master` directly):
`git checkout -b sync/rhiza-<target>`.
- Edit only `ref:` in `.rhiza/template.yml` to the target version.
- Commit just that change (e.g. `Chore: bump rhiza template ref <old> → <target>`).

## 3. Sync

- Run `make sync` (it invokes `rhiza sync`). Expect it to either complete
cleanly or report conflicts. It writes the refreshed `.rhiza/template.lock`.
- If it completes with no conflicts, skip to step 5.

## 4. Resolve every conflict

The sync is a 3-way merge. Two kinds of leftovers can appear — handle both, and
finish with **zero** `*.rej` files and **zero** conflict markers
(`<<<<<<<` / `=======` / `>>>>>>>`) anywhere tracked
(`git grep -lE '^(<<<<<<<|=======|>>>>>>>)'`).

**`*.rej` files (rejected hunks).** The 3-way merge often *already applied* a
hunk and still drops a duplicate `.rej`. For each, verify whether the change is
already present in the file (the added `+` lines exist; no conflict markers
remain). If it is, the `.rej` is spurious — delete it. If a hunk genuinely did
not apply, apply it by hand, then delete the `.rej`.

**Conflict-marked files.** Resolve by the ownership rule (see `CLAUDE.md` and the
`files:` block of `.rhiza/template.lock` for the authoritative managed-file list):
Comment on lines +53 to +54

- **Rhiza-managed files** (the `.github/workflows/*`, `Makefile`,
`.pre-commit-config.yaml`, `pytest.ini`, the `.rhiza/` engine, etc.): take the
**incoming/upstream** side — these are owned by the template and should match
it (`git checkout --theirs -- <file>` then `git add`).
- **Locally-owned or locally-hardened files** (notably `ruff.toml`, plus
`pyproject.toml`, `README.md`, `src/`, your `tests/`): **merge by hand** —
keep the local intent (e.g. stricter lint rules) while folding in genuine
upstream additions, and make the result internally coherent (dedupe, drop
comments that now contradict the config).

Validate every touched workflow/YAML still parses before moving on.

## 5. Verify the gates and fix fallout

A version bump can tighten the gates (new lint rules, `mypy --strict`, expanded
docs-coverage scope, etc.) and surface pre-existing issues. Run them and get
them green:

1. `make fmt` — pre-commit + lint
2. `make typecheck`
3. `make docs-coverage`
4. `make deptry`
5. `make security`
6. `make test`

**Scope your fixes.** Fix issues only in **locally-owned** files (`src/`,
`tests/`, `pyproject.toml`, locally-hardened config). If a gate fails because of
a **Rhiza-managed** file, that is an upstream problem: fix it in
`jebel-quant/rhiza` and bump again — do **not** edit the synced artifact in
place. Call out any such upstream-owned failure explicitly rather than papering
over it locally.

## 6. Commit, push, open a PR

- Commit the resolution and any in-scope fixes with clear messages (one logical
change per commit: the conflict resolution, then each gate fix).
- Push the branch and open a PR (`gh pr create`) titled for the bump, e.g.
`Chore: sync Rhiza template <old> → <target>`. In the body, summarize how each
conflict was resolved, list any gate fallout you fixed, and flag anything that
needs an **upstream** fix in Rhiza.
- Report a concise per-gate PASS/FAIL summary. If the workflow files changed,
note that pushing them needs a token with the `workflow` scope.

Do not merge the PR. Stop after it is open and summarize what landed and what
(if anything) is blocked on an upstream Rhiza change.