crapkit 0.3.0__tar.gz → 0.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {crapkit-0.3.0/src/crapkit.egg-info → crapkit-0.4.0}/PKG-INFO +22 -13
- {crapkit-0.3.0 → crapkit-0.4.0}/README.md +21 -12
- {crapkit-0.3.0 → crapkit-0.4.0}/pyproject.toml +1 -1
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/__init__.py +1 -1
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/_pygdefer.py +6 -3
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/analyze.py +162 -3
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/cli/__init__.py +32 -0
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/cli/admin.py +70 -0
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/cli/analyses.py +21 -8
- crapkit-0.4.0/src/crapkit/cli/claude_hook.py +307 -0
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/cli/parser.py +46 -5
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/cli/scoring.py +19 -3
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/cli/verifying.py +49 -1
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/config.py +7 -1
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/discover.py +22 -7
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/doctor.py +55 -0
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/hook.py +3 -26
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/lizardcognitive.py +63 -8
- crapkit-0.4.0/src/crapkit/lizardpowershell.py +288 -0
- crapkit-0.4.0/src/crapkit/lizardrust.py +137 -0
- crapkit-0.4.0/src/crapkit/lizardshell.py +389 -0
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/mutate.py +60 -1
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/scaffold.py +6 -0
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/universe.py +14 -0
- {crapkit-0.3.0 → crapkit-0.4.0/src/crapkit.egg-info}/PKG-INFO +22 -13
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit.egg-info/SOURCES.txt +4 -0
- {crapkit-0.3.0 → crapkit-0.4.0}/LICENSE +0 -0
- {crapkit-0.3.0 → crapkit-0.4.0}/setup.cfg +0 -0
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/__main__.py +0 -0
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/cache.py +0 -0
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/churn.py +0 -0
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/churn_cache.py +0 -0
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/churn_log.py +0 -0
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/cli/_shared.py +0 -0
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/cli/queue.py +0 -0
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/cli/ratchet_cmds.py +0 -0
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/cli/reports.py +0 -0
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/coupling.py +0 -0
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/coverage_istanbul.py +0 -0
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/coverage_py.py +0 -0
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/covstream.py +0 -0
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/diffparse.py +0 -0
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/digest.py +0 -0
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/dup.py +0 -0
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/errors.py +0 -0
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/gitio.py +0 -0
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/junitparse.py +0 -0
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/lanes.py +0 -0
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/mcp_server.py +0 -0
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/merge.py +0 -0
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/mutate_pool.py +0 -0
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/override.py +0 -0
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/packet.py +0 -0
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/ratchet.py +0 -0
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/ratchet_report.py +0 -0
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/report.py +0 -0
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/sarif.py +0 -0
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/sarifio.py +0 -0
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/score.py +0 -0
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/snapshot.py +0 -0
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/store.py +0 -0
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/uncovered.py +0 -0
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/verify.py +0 -0
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/watch.py +0 -0
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit/worklist.py +0 -0
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit.egg-info/dependency_links.txt +0 -0
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit.egg-info/entry_points.txt +0 -0
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit.egg-info/requires.txt +0 -0
- {crapkit-0.3.0 → crapkit-0.4.0}/src/crapkit.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: crapkit
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Deterministic CRAP-score framework: per-function complexity x coverage risk, worklists, ratchets, refactor verification
|
|
5
5
|
Author: Jean-Francois Gagne
|
|
6
6
|
License: MIT
|
|
@@ -28,11 +28,14 @@ Dynamic: license-file
|
|
|
28
28
|
|
|
29
29
|
crapkit scores every function in your repo on complexity times uncovered risk, ranks the
|
|
30
30
|
worst ones by how often the file changes, and blocks commits that add more. It reads
|
|
31
|
-
TypeScript, TSX, JavaScript, Python, Swift
|
|
31
|
+
TypeScript, TSX, JavaScript, Python, Swift, Go, Rust, shell, PowerShell, C and C++,
|
|
32
|
+
Objective-C, Vue, Java and Zig through [lizard](https://github.com/terryyin/lizard),
|
|
32
33
|
and joins per-function branch coverage from istanbul or coverage.py artifacts your own test
|
|
33
|
-
command already produces.
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
command already produces. Those two parsers are the whole list, so Swift, Go, Rust, shell,
|
|
35
|
+
PowerShell, C and C++, Objective-C, Java and Zig have no coverage to join: declare those
|
|
36
|
+
scopes `coverage_optional` and they score on complexity alone. Vue joins istanbul coverage
|
|
37
|
+
when your own vitest run reports on `.vue` files. Every read-side command speaks JSON with a
|
|
38
|
+
pinned schema, because half the callers are coding agents.
|
|
36
39
|
|
|
37
40
|
```
|
|
38
41
|
CRAP = ccn^2 * (1 - cov)^3 + ccn
|
|
@@ -77,7 +80,7 @@ Check the install:
|
|
|
77
80
|
|
|
78
81
|
```
|
|
79
82
|
$ crapkit --version
|
|
80
|
-
crapkit 0.
|
|
83
|
+
crapkit 0.4.0
|
|
81
84
|
```
|
|
82
85
|
|
|
83
86
|
`python -m crapkit` works identically to the `crapkit` console script, and is what to use
|
|
@@ -473,11 +476,15 @@ without touching the repo-wide cache, and refuses the commit when a staged funct
|
|
|
473
476
|
its scope ceiling. It needs no coverage data and no snapshot, so it costs the size of the
|
|
474
477
|
commit, not the size of the repo.
|
|
475
478
|
|
|
476
|
-
|
|
479
|
+
Three limits to know. The gate judges files a `[[scope]]` claims; a staged source file no
|
|
477
480
|
scope claims is not gated, and the hook says so on stderr (`N staged file(s) belong to no
|
|
478
481
|
scope and were not gated`) so the hole is visible the moment a new top-level directory
|
|
479
|
-
appears.
|
|
480
|
-
|
|
482
|
+
appears. A function the committed ratchet already carries a mark for is not gated either,
|
|
483
|
+
so touching signed debt does not refuse the commit; the hook reports the count on stderr
|
|
484
|
+
(`N staged function(s) carry a ratchet mark and were not gated`) and `crapkit verify` is
|
|
485
|
+
what fails a mark that rose. And git runs hooks outside your shell's activated venv: bare
|
|
486
|
+
`python` must resolve to an interpreter that has crapkit installed, or use the absolute
|
|
487
|
+
form
|
|
481
488
|
(`exec /path/to/venv/Scripts/python -m crapkit hook-precommit`).
|
|
482
489
|
|
|
483
490
|
### Route 1: `.git/hooks/pre-commit` (local, not committed)
|
|
@@ -726,7 +733,8 @@ advances the baseline nor tightens the ratchet, exit 9 included.
|
|
|
726
733
|
## Subcommands
|
|
727
734
|
|
|
728
735
|
Every subcommand takes `--repo PATH` (default `.`), and the flag goes **after** the
|
|
729
|
-
subcommand:
|
|
736
|
+
subcommand. `claude-hook` is the one exception: it has no `--repo`, because it takes its
|
|
737
|
+
root from the file named in the hook payload it reads.
|
|
730
738
|
|
|
731
739
|
```
|
|
732
740
|
$ crapkit worklist --repo /path/to/repo --scope util --top 1
|
|
@@ -747,7 +755,7 @@ crapkit: error: argument command: invalid choice: '/path/to/repo' (choose from '
|
|
|
747
755
|
| Command | What it does |
|
|
748
756
|
|---|---|
|
|
749
757
|
| `init` | Sniffs tracked source into per-directory scopes, writes a self-validated starter `crapkit.toml` whose lanes report into `.crapkit/cov/`, and appends `.crapkit/` plus each runner's own droppings to `.gitignore`. Writes a live `[[lane]]` when it can detect the test runner, otherwise a commented template. Refuses to clobber an existing config. |
|
|
750
|
-
| `doctor [--show-files] [--json] [--tune]` | Checks the config still describes the repo: unknown keys (with the accepted spellings), zero-file scopes, tracked source no scope claims, scopes no lane covers, lane cwds and commands that no longer resolve, lizard importable, oversized files, lanes writing their artifacts at the repo root instead of under `.crapkit/` (WARN), committed hooks under `core.hooksPath` that are not executable in the index (WARN), directories whose functions are all `untested` while their tests exist (WARN), and scopes a lane measures with no `[crapkit.scoped_tests]` template behind them (WARN), which is the loop's step 4 with nothing to run. `--tune` prints suggested parallelism knobs and writes nothing. See [docs/agent-json.md](docs/agent-json.md#doctor---json). |
|
|
758
|
+
| `doctor [--show-files] [--json] [--tune] [--plugin-root PATH]` | Checks the config still describes the repo: unknown keys (with the accepted spellings), zero-file scopes, tracked source no scope claims, scopes no lane covers, lane cwds and commands that no longer resolve, lizard importable, oversized files, lanes writing their artifacts at the repo root instead of under `.crapkit/` (WARN), committed hooks under `core.hooksPath` that are not executable in the index (WARN), directories whose functions are all `untested` while their tests exist (WARN), and scopes a lane measures with no `[crapkit.scoped_tests]` template behind them (WARN), which is the loop's step 4 with nothing to run. `--tune` prints suggested parallelism knobs and writes nothing. `--plugin-root PATH` reads no repo at all: it checks an installed [plugin](plugin/) against this CLI, comparing `.claude-plugin/plugin.json`'s version against the running crapkit and every `--protocol` in `hooks/hooks.json` against the protocol `claude-hook` answers, one line per disagreement and silence when they agree. See [docs/agent-json.md](docs/agent-json.md#doctor---json). |
|
|
751
759
|
| `inventory [--db PATH] [--export PATH] [--json]` | Two lizard passes over every in-scope file into a SQLite snapshot run, cached by content hash. `--db` is the only way to point crapkit at a store outside `.crapkit/`, and only this command accepts it. |
|
|
752
760
|
| `coverage [--lane NAME] [--reuse-artifacts] [--reuse-unchanged] [--export PATH] [--sarif PATH] [--github] [--json]` | Runs the lanes, joins branch coverage onto a fresh inventory, writes a scored run. A failed lane is recorded, not fatal: its scopes fall back to `no-lane` and the run is typed `partial`, so it can never serve as a baseline. See [docs/lanes.md](docs/lanes.md). |
|
|
753
761
|
| `verify [--baseline ID \| --base REF \| --baseline-tsv PATH] [--emit-baseline PATH] [--override REASON] [--reuse-artifacts] [--reuse-unchanged] [--sarif PATH] [--github] [--json]` | The full verdict against the trusted baseline: gate on touched functions, ratchet, no new test failures, optional diff-coverage ceiling. The three baseline selectors are mutually exclusive; `--baseline ID` also bypasses the taint rule ([The trusted baseline](#the-trusted-baseline)), and `--baseline-tsv` reads a commit-stamped file so a fresh clone verifies with no store. Findings a dirty tree produced are tagged `dirty` and counted apart. |
|
|
@@ -765,9 +773,10 @@ crapkit: error: argument command: invalid choice: '/path/to/repo' (choose from '
|
|
|
765
773
|
| `report [--out PATH]` | One self-contained HTML page written to `.crapkit/report.html` (or `--out PATH`, repo-relative), with the path printed on stdout. It renders what `worklist --json` and `trend --json` already answer at their defaults: the ranked worklist capped at `worklist_top`, the per-scope grades off the newest run, the trend series, and a banner naming every stale lane. It measures nothing, opens no network connection, and carries no per-function CRAP or coverage, because no repo-wide payload has them; each row prints the `crapkit explain` call that does. |
|
|
766
774
|
| `duplication [--min-lines N] [--similarity F] [--top N] [--json]` | Near-duplicate functions by normalized line shingles with containment scoring. Defaults: `--min-lines 8`, `--similarity 0.8`, `--top 50`. `--top` truncates the list. |
|
|
767
775
|
| `coupling [--min-support N] [--min-confidence F] [--top N] [--json]` | File pairs that keep landing in the same commits. Defaults: `--min-support 5` shared commits, `--min-confidence 0.5` max-direction ratio, `--top 50`. Bulk commits never couple pairs, and a young repo returns nothing at the default support. |
|
|
768
|
-
| `mutate [--files F ...] [--max-mutants N] [--json]` | Diff-scoped mutation testing: flips comparisons, boundary shifts, boolean connectives and boolean literals on changed lines, runs `mutation_command` per mutant, lists survivors. `--files` replaces diff scope with the whole file. `--max-mutants` (default 100) caps the run and the cap warning goes to stderr only, so `mutants` in `--json` is the capped count. |
|
|
776
|
+
| `mutate [--files F ...] [--max-mutants N] [--json]` | Diff-scoped mutation testing: flips comparisons, boundary shifts, boolean connectives and boolean literals on changed lines, runs `mutation_command` per mutant, lists survivors. `--files` replaces diff scope with the whole file. `--max-mutants` (default 100) caps the run and the cap warning goes to stderr only, so `mutants` in `--json` is the capped count. Shell and PowerShell files are refused by name on stderr rather than mutated: `<` and `>` are redirections there, not comparisons. |
|
|
769
777
|
| `test-scoped FILE ...` | Runs each owning scope's `[crapkit.scoped_tests]` template on the files (quoted, longest-prefix scope wins). A template with no `{files}` runs as written, which is how a scope whose tests live outside its own paths runs its whole suite. Exit code only; a nonzero runner exits 1. |
|
|
770
778
|
| `hook-precommit` | The cc-only gate on staged blobs. No coverage, no snapshot, no repo-wide cache. Exit 6 on a violation. |
|
|
779
|
+
| `claude-hook [--protocol N]` | Reads one Claude Code PostToolUse payload from stdin and judges the file it edited: ccn against the scope ceiling, on functions the edit changed, minus functions a ratchet mark already covers. Advisory only: the edit has landed and nothing is blocked, and `hook-precommit` stays the enforcement point. Exit 2 with three lines on stderr is the only thing it ever says. No `crapkit.toml` above the edited file, an unscoped file, mid-rebase or mid-merge, a `--protocol` other than 1, source that parses to no functions, or any internal failure: exit 0, silence, empty stderr. Takes no `--repo` — the root is the first `crapkit.toml` above the edited file and the upward walk stops at a `.git` entry, so a worktree never borrows its parent's config. It opens no snapshot, writes nothing, and leaves stdout empty. |
|
|
771
780
|
| `watch [--interval SECONDS] [--cycles N]` | Rescores tracked files as they change (mtime polling, default 2s, subprocess-isolated so a half-saved syntax error never kills the watcher). `--cycles N` polls exactly N times and exits 0; without it the loop runs until ctrl-c. |
|
|
772
781
|
| `mcp` | A dependency-free stdio MCP server (newline JSON-RPC 2.0) exposing nine read-only tools. See [docs/agent-json.md](docs/agent-json.md#mcp-server). |
|
|
773
782
|
|
|
@@ -781,7 +790,7 @@ crapkit: error: argument command: invalid choice: '/path/to/repo' (choose from '
|
|
|
781
790
|
| [docs/ratchet.md](docs/ratchet.md) | Seeding, pruning, the git merge driver, metric stamps, debt policy, overrides. |
|
|
782
791
|
| [docs/agent-json.md](docs/agent-json.md) | The machine surface: `schema`, every payload field, real captured examples. |
|
|
783
792
|
| [docs/adoption.md](docs/adoption.md) | The judgment layer over the quickstarts: scope granularity, exclude vs lane, scoped_tests wiring, the first-verify taint hazard. |
|
|
784
|
-
| [
|
|
793
|
+
| [plugin/](plugin/) | The Claude Code plugin: three skills (`crapkit`, `crapkit-recover`, `crapkit-onboard`), the read-side MCP server, and the advisory PostToolUse hook. Install with `claude plugin marketplace add JeanFrancoisGagne/crapkit` then `claude plugin install crapkit@crapkit`; other runtimes copy `plugin/skills/*` into their skills directory. |
|
|
785
794
|
|
|
786
795
|
[crapkit.schema.json](crapkit.schema.json) is the authority on the config file shape.
|
|
787
796
|
|
|
@@ -2,11 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
crapkit scores every function in your repo on complexity times uncovered risk, ranks the
|
|
4
4
|
worst ones by how often the file changes, and blocks commits that add more. It reads
|
|
5
|
-
TypeScript, TSX, JavaScript, Python, Swift
|
|
5
|
+
TypeScript, TSX, JavaScript, Python, Swift, Go, Rust, shell, PowerShell, C and C++,
|
|
6
|
+
Objective-C, Vue, Java and Zig through [lizard](https://github.com/terryyin/lizard),
|
|
6
7
|
and joins per-function branch coverage from istanbul or coverage.py artifacts your own test
|
|
7
|
-
command already produces.
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
command already produces. Those two parsers are the whole list, so Swift, Go, Rust, shell,
|
|
9
|
+
PowerShell, C and C++, Objective-C, Java and Zig have no coverage to join: declare those
|
|
10
|
+
scopes `coverage_optional` and they score on complexity alone. Vue joins istanbul coverage
|
|
11
|
+
when your own vitest run reports on `.vue` files. Every read-side command speaks JSON with a
|
|
12
|
+
pinned schema, because half the callers are coding agents.
|
|
10
13
|
|
|
11
14
|
```
|
|
12
15
|
CRAP = ccn^2 * (1 - cov)^3 + ccn
|
|
@@ -51,7 +54,7 @@ Check the install:
|
|
|
51
54
|
|
|
52
55
|
```
|
|
53
56
|
$ crapkit --version
|
|
54
|
-
crapkit 0.
|
|
57
|
+
crapkit 0.4.0
|
|
55
58
|
```
|
|
56
59
|
|
|
57
60
|
`python -m crapkit` works identically to the `crapkit` console script, and is what to use
|
|
@@ -447,11 +450,15 @@ without touching the repo-wide cache, and refuses the commit when a staged funct
|
|
|
447
450
|
its scope ceiling. It needs no coverage data and no snapshot, so it costs the size of the
|
|
448
451
|
commit, not the size of the repo.
|
|
449
452
|
|
|
450
|
-
|
|
453
|
+
Three limits to know. The gate judges files a `[[scope]]` claims; a staged source file no
|
|
451
454
|
scope claims is not gated, and the hook says so on stderr (`N staged file(s) belong to no
|
|
452
455
|
scope and were not gated`) so the hole is visible the moment a new top-level directory
|
|
453
|
-
appears.
|
|
454
|
-
|
|
456
|
+
appears. A function the committed ratchet already carries a mark for is not gated either,
|
|
457
|
+
so touching signed debt does not refuse the commit; the hook reports the count on stderr
|
|
458
|
+
(`N staged function(s) carry a ratchet mark and were not gated`) and `crapkit verify` is
|
|
459
|
+
what fails a mark that rose. And git runs hooks outside your shell's activated venv: bare
|
|
460
|
+
`python` must resolve to an interpreter that has crapkit installed, or use the absolute
|
|
461
|
+
form
|
|
455
462
|
(`exec /path/to/venv/Scripts/python -m crapkit hook-precommit`).
|
|
456
463
|
|
|
457
464
|
### Route 1: `.git/hooks/pre-commit` (local, not committed)
|
|
@@ -700,7 +707,8 @@ advances the baseline nor tightens the ratchet, exit 9 included.
|
|
|
700
707
|
## Subcommands
|
|
701
708
|
|
|
702
709
|
Every subcommand takes `--repo PATH` (default `.`), and the flag goes **after** the
|
|
703
|
-
subcommand:
|
|
710
|
+
subcommand. `claude-hook` is the one exception: it has no `--repo`, because it takes its
|
|
711
|
+
root from the file named in the hook payload it reads.
|
|
704
712
|
|
|
705
713
|
```
|
|
706
714
|
$ crapkit worklist --repo /path/to/repo --scope util --top 1
|
|
@@ -721,7 +729,7 @@ crapkit: error: argument command: invalid choice: '/path/to/repo' (choose from '
|
|
|
721
729
|
| Command | What it does |
|
|
722
730
|
|---|---|
|
|
723
731
|
| `init` | Sniffs tracked source into per-directory scopes, writes a self-validated starter `crapkit.toml` whose lanes report into `.crapkit/cov/`, and appends `.crapkit/` plus each runner's own droppings to `.gitignore`. Writes a live `[[lane]]` when it can detect the test runner, otherwise a commented template. Refuses to clobber an existing config. |
|
|
724
|
-
| `doctor [--show-files] [--json] [--tune]` | Checks the config still describes the repo: unknown keys (with the accepted spellings), zero-file scopes, tracked source no scope claims, scopes no lane covers, lane cwds and commands that no longer resolve, lizard importable, oversized files, lanes writing their artifacts at the repo root instead of under `.crapkit/` (WARN), committed hooks under `core.hooksPath` that are not executable in the index (WARN), directories whose functions are all `untested` while their tests exist (WARN), and scopes a lane measures with no `[crapkit.scoped_tests]` template behind them (WARN), which is the loop's step 4 with nothing to run. `--tune` prints suggested parallelism knobs and writes nothing. See [docs/agent-json.md](docs/agent-json.md#doctor---json). |
|
|
732
|
+
| `doctor [--show-files] [--json] [--tune] [--plugin-root PATH]` | Checks the config still describes the repo: unknown keys (with the accepted spellings), zero-file scopes, tracked source no scope claims, scopes no lane covers, lane cwds and commands that no longer resolve, lizard importable, oversized files, lanes writing their artifacts at the repo root instead of under `.crapkit/` (WARN), committed hooks under `core.hooksPath` that are not executable in the index (WARN), directories whose functions are all `untested` while their tests exist (WARN), and scopes a lane measures with no `[crapkit.scoped_tests]` template behind them (WARN), which is the loop's step 4 with nothing to run. `--tune` prints suggested parallelism knobs and writes nothing. `--plugin-root PATH` reads no repo at all: it checks an installed [plugin](plugin/) against this CLI, comparing `.claude-plugin/plugin.json`'s version against the running crapkit and every `--protocol` in `hooks/hooks.json` against the protocol `claude-hook` answers, one line per disagreement and silence when they agree. See [docs/agent-json.md](docs/agent-json.md#doctor---json). |
|
|
725
733
|
| `inventory [--db PATH] [--export PATH] [--json]` | Two lizard passes over every in-scope file into a SQLite snapshot run, cached by content hash. `--db` is the only way to point crapkit at a store outside `.crapkit/`, and only this command accepts it. |
|
|
726
734
|
| `coverage [--lane NAME] [--reuse-artifacts] [--reuse-unchanged] [--export PATH] [--sarif PATH] [--github] [--json]` | Runs the lanes, joins branch coverage onto a fresh inventory, writes a scored run. A failed lane is recorded, not fatal: its scopes fall back to `no-lane` and the run is typed `partial`, so it can never serve as a baseline. See [docs/lanes.md](docs/lanes.md). |
|
|
727
735
|
| `verify [--baseline ID \| --base REF \| --baseline-tsv PATH] [--emit-baseline PATH] [--override REASON] [--reuse-artifacts] [--reuse-unchanged] [--sarif PATH] [--github] [--json]` | The full verdict against the trusted baseline: gate on touched functions, ratchet, no new test failures, optional diff-coverage ceiling. The three baseline selectors are mutually exclusive; `--baseline ID` also bypasses the taint rule ([The trusted baseline](#the-trusted-baseline)), and `--baseline-tsv` reads a commit-stamped file so a fresh clone verifies with no store. Findings a dirty tree produced are tagged `dirty` and counted apart. |
|
|
@@ -739,9 +747,10 @@ crapkit: error: argument command: invalid choice: '/path/to/repo' (choose from '
|
|
|
739
747
|
| `report [--out PATH]` | One self-contained HTML page written to `.crapkit/report.html` (or `--out PATH`, repo-relative), with the path printed on stdout. It renders what `worklist --json` and `trend --json` already answer at their defaults: the ranked worklist capped at `worklist_top`, the per-scope grades off the newest run, the trend series, and a banner naming every stale lane. It measures nothing, opens no network connection, and carries no per-function CRAP or coverage, because no repo-wide payload has them; each row prints the `crapkit explain` call that does. |
|
|
740
748
|
| `duplication [--min-lines N] [--similarity F] [--top N] [--json]` | Near-duplicate functions by normalized line shingles with containment scoring. Defaults: `--min-lines 8`, `--similarity 0.8`, `--top 50`. `--top` truncates the list. |
|
|
741
749
|
| `coupling [--min-support N] [--min-confidence F] [--top N] [--json]` | File pairs that keep landing in the same commits. Defaults: `--min-support 5` shared commits, `--min-confidence 0.5` max-direction ratio, `--top 50`. Bulk commits never couple pairs, and a young repo returns nothing at the default support. |
|
|
742
|
-
| `mutate [--files F ...] [--max-mutants N] [--json]` | Diff-scoped mutation testing: flips comparisons, boundary shifts, boolean connectives and boolean literals on changed lines, runs `mutation_command` per mutant, lists survivors. `--files` replaces diff scope with the whole file. `--max-mutants` (default 100) caps the run and the cap warning goes to stderr only, so `mutants` in `--json` is the capped count. |
|
|
750
|
+
| `mutate [--files F ...] [--max-mutants N] [--json]` | Diff-scoped mutation testing: flips comparisons, boundary shifts, boolean connectives and boolean literals on changed lines, runs `mutation_command` per mutant, lists survivors. `--files` replaces diff scope with the whole file. `--max-mutants` (default 100) caps the run and the cap warning goes to stderr only, so `mutants` in `--json` is the capped count. Shell and PowerShell files are refused by name on stderr rather than mutated: `<` and `>` are redirections there, not comparisons. |
|
|
743
751
|
| `test-scoped FILE ...` | Runs each owning scope's `[crapkit.scoped_tests]` template on the files (quoted, longest-prefix scope wins). A template with no `{files}` runs as written, which is how a scope whose tests live outside its own paths runs its whole suite. Exit code only; a nonzero runner exits 1. |
|
|
744
752
|
| `hook-precommit` | The cc-only gate on staged blobs. No coverage, no snapshot, no repo-wide cache. Exit 6 on a violation. |
|
|
753
|
+
| `claude-hook [--protocol N]` | Reads one Claude Code PostToolUse payload from stdin and judges the file it edited: ccn against the scope ceiling, on functions the edit changed, minus functions a ratchet mark already covers. Advisory only: the edit has landed and nothing is blocked, and `hook-precommit` stays the enforcement point. Exit 2 with three lines on stderr is the only thing it ever says. No `crapkit.toml` above the edited file, an unscoped file, mid-rebase or mid-merge, a `--protocol` other than 1, source that parses to no functions, or any internal failure: exit 0, silence, empty stderr. Takes no `--repo` — the root is the first `crapkit.toml` above the edited file and the upward walk stops at a `.git` entry, so a worktree never borrows its parent's config. It opens no snapshot, writes nothing, and leaves stdout empty. |
|
|
745
754
|
| `watch [--interval SECONDS] [--cycles N]` | Rescores tracked files as they change (mtime polling, default 2s, subprocess-isolated so a half-saved syntax error never kills the watcher). `--cycles N` polls exactly N times and exits 0; without it the loop runs until ctrl-c. |
|
|
746
755
|
| `mcp` | A dependency-free stdio MCP server (newline JSON-RPC 2.0) exposing nine read-only tools. See [docs/agent-json.md](docs/agent-json.md#mcp-server). |
|
|
747
756
|
|
|
@@ -755,7 +764,7 @@ crapkit: error: argument command: invalid choice: '/path/to/repo' (choose from '
|
|
|
755
764
|
| [docs/ratchet.md](docs/ratchet.md) | Seeding, pruning, the git merge driver, metric stamps, debt policy, overrides. |
|
|
756
765
|
| [docs/agent-json.md](docs/agent-json.md) | The machine surface: `schema`, every payload field, real captured examples. |
|
|
757
766
|
| [docs/adoption.md](docs/adoption.md) | The judgment layer over the quickstarts: scope granularity, exclude vs lane, scoped_tests wiring, the first-verify taint hazard. |
|
|
758
|
-
| [
|
|
767
|
+
| [plugin/](plugin/) | The Claude Code plugin: three skills (`crapkit`, `crapkit-recover`, `crapkit-onboard`), the read-side MCP server, and the advisory PostToolUse hook. Install with `claude plugin marketplace add JeanFrancoisGagne/crapkit` then `claude plugin install crapkit@crapkit`; other runtimes copy `plugin/skills/*` into their skills directory. |
|
|
759
768
|
|
|
760
769
|
[crapkit.schema.json](crapkit.schema.json) is the authority on the config file shape.
|
|
761
770
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "crapkit"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.4.0"
|
|
8
8
|
description = "Deterministic CRAP-score framework: per-function complexity x coverage risk, worklists, ratchets, refactor verification"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "MIT" }
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"""crapkit: deterministic CRAP-score framework."""
|
|
2
|
-
__version__ = "0.
|
|
2
|
+
__version__ = "0.4.0"
|
|
@@ -6,9 +6,12 @@ importlib.metadata, email, zipfile and socket. Measured on this box: 42ms with
|
|
|
6
6
|
pygments, 16ms without, paid by every process that touches the analysis stack,
|
|
7
7
|
the pre-commit hook included.
|
|
8
8
|
|
|
9
|
-
crapkit analyzes
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
crapkit analyzes fourteen languages (typescript, tsx, javascript, python, swift,
|
|
10
|
+
go, rust, shell, powershell, cpp, objectivec, vue, java, zig). Erlang is not one
|
|
11
|
+
of them and no scope can name it, which is the whole argument for stubbing its
|
|
12
|
+
reader, so a test pins this list to `config.SUPPORTED_LANGUAGES`. The readers
|
|
13
|
+
that need pygments are still SHIPPED, not removed: `deferred_pygments()` puts
|
|
14
|
+
proxies in
|
|
12
15
|
sys.modules for the duration of the lizard import, so the readers bind stand-ins
|
|
13
16
|
and the real package loads the first time anything reads or calls one. An .erl
|
|
14
17
|
file analyzed through lizard directly gets the same answer; it just pays the
|
|
@@ -5,9 +5,11 @@ nested node_modules (measured hang on the first consumer repo).
|
|
|
5
5
|
"""
|
|
6
6
|
from __future__ import annotations
|
|
7
7
|
|
|
8
|
+
import codecs
|
|
8
9
|
import hashlib
|
|
9
10
|
import json
|
|
10
11
|
import os
|
|
12
|
+
import sys
|
|
11
13
|
import time
|
|
12
14
|
from concurrent.futures import ProcessPoolExecutor
|
|
13
15
|
from pathlib import Path
|
|
@@ -17,17 +19,40 @@ from ._pygdefer import deferred_pygments
|
|
|
17
19
|
with deferred_pygments(): # lizard's Erlang reader would load pygments here
|
|
18
20
|
import lizard
|
|
19
21
|
|
|
22
|
+
from .lizardpowershell import register as _register_powershell
|
|
23
|
+
from .lizardrust import register as _register_rust
|
|
24
|
+
from .lizardshell import register as _register_shell
|
|
25
|
+
|
|
20
26
|
from .cache import partition_by_cache, updated_cache
|
|
21
27
|
from .errors import ToolError
|
|
22
28
|
from .lizardcognitive import LizardExtension as _Cognitive
|
|
23
29
|
from .merge import FunctionRecord
|
|
30
|
+
from .packet import bare_name
|
|
31
|
+
|
|
32
|
+
# lizard picks a reader by extension off a hardcoded list, and none of these is
|
|
33
|
+
# on it: `.rs` resolves to a reader that counts no `match` arm (lizard #494),
|
|
34
|
+
# and `.sh` and `.ps1` resolve to nothing at all, which lizard answers with
|
|
35
|
+
# CLikeReader rather than a failure. All three belong HERE, at the module scope
|
|
36
|
+
# of the module a ProcessPoolExecutor child imports, or spawned workers measure
|
|
37
|
+
# with the readers lizard shipped and report plausible wrong numbers.
|
|
38
|
+
#
|
|
39
|
+
# lizardshell and lizardpowershell already register themselves on import and
|
|
40
|
+
# lizardrust deliberately does not (rebinding a name in another package's
|
|
41
|
+
# namespace is not something an import should do quietly). Calling all three
|
|
42
|
+
# keeps the wiring readable in one place and costs nothing: each is idempotent.
|
|
43
|
+
_register_rust()
|
|
44
|
+
_register_shell()
|
|
45
|
+
_register_powershell()
|
|
24
46
|
|
|
25
47
|
_POOL_THRESHOLD = 16
|
|
26
48
|
|
|
27
49
|
# Bump whenever analysis semantics change (merge rules, extension set, record
|
|
28
50
|
# extraction): the fingerprint must invalidate cached records produced by older
|
|
29
51
|
# logic even when file content and tool versions are identical.
|
|
30
|
-
ANALYSIS_VERSION =
|
|
52
|
+
ANALYSIS_VERSION = 6 # 6: five more C-family extension sets and .ps1/.psm1 are
|
|
53
|
+
# admitted, a C++ rvalue reference is no longer a
|
|
54
|
+
# cognitive condition, and source bytes decode utf-8
|
|
55
|
+
# then cp1252 instead of by machine locale
|
|
31
56
|
|
|
32
57
|
# The three tokens lizard's modified rule reacts to. Membership is checked before
|
|
33
58
|
# anything else runs, so the common token pays one frozenset lookup.
|
|
@@ -122,11 +147,145 @@ def _record(rel_path: str, fn) -> FunctionRecord:
|
|
|
122
147
|
)
|
|
123
148
|
|
|
124
149
|
|
|
150
|
+
# How many colliding names one warning prints before it stops. A generated file
|
|
151
|
+
# can hold hundreds; the point is that the file needs looking at, not the list.
|
|
152
|
+
_NAMES_SHOWN = 5
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def _colliding_names(records: list[FunctionRecord]) -> list[str]:
|
|
156
|
+
"""Names this file gives to more than one function, in first-seen order.
|
|
157
|
+
|
|
158
|
+
Anonymous functions are exempt. lizard calls every one of them
|
|
159
|
+
`(anonymous)`, so a file with two arrow callbacks collides by construction
|
|
160
|
+
and a warning would name nothing anyone could act on; `packet.handles`
|
|
161
|
+
answers that collision with the `(anonymous)#N` ordinal instead.
|
|
162
|
+
"""
|
|
163
|
+
seen: set[str] = set()
|
|
164
|
+
colliding: dict[str, None] = {}
|
|
165
|
+
for record in records:
|
|
166
|
+
if bare_name(record.long_name) and record.long_name in seen:
|
|
167
|
+
colliding[record.long_name] = None
|
|
168
|
+
seen.add(record.long_name)
|
|
169
|
+
return list(colliding)
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def _warn_on_collisions(rel_path: str, records: list[FunctionRecord]) -> None:
|
|
173
|
+
"""One stderr line for a file whose records cannot all reach the ratchet.
|
|
174
|
+
|
|
175
|
+
A mark is keyed on (path, long_name), and so is the row a run writes, so the
|
|
176
|
+
last function under a colliding name is the only one marked and the only one
|
|
177
|
+
gated. C makes this ordinary: both arms of an `#ifdef` fork are textually
|
|
178
|
+
present, so a platform shim defines the same function twice in one file.
|
|
179
|
+
Python makes it ordinary too, because a method's long_name carries no class.
|
|
180
|
+
Neither is fixable here — the ratchet cannot key on a span, which drifts with
|
|
181
|
+
every edit — so the loss is announced rather than silent.
|
|
182
|
+
"""
|
|
183
|
+
names = _colliding_names(records)
|
|
184
|
+
if not names:
|
|
185
|
+
return
|
|
186
|
+
print(f"crapkit: {rel_path} defines {_listed(names)} more than once; the ratchet keys "
|
|
187
|
+
f"on (path, long_name) and keeps the last, so the earlier ones are neither "
|
|
188
|
+
f"marked nor gated", file=sys.stderr)
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def _listed(names: list[str]) -> str:
|
|
192
|
+
if len(names) <= _NAMES_SHOWN:
|
|
193
|
+
return ", ".join(names)
|
|
194
|
+
return f"{', '.join(names[:_NAMES_SHOWN])} and {len(names) - _NAMES_SHOWN} more name(s)"
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def _file_records(rel_path: str, functions) -> list[FunctionRecord]:
|
|
198
|
+
records = [_record(rel_path, fn) for fn in functions]
|
|
199
|
+
_warn_on_collisions(rel_path, records)
|
|
200
|
+
return records
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
# --- how a source file's bytes become text -------------------------------------
|
|
204
|
+
#
|
|
205
|
+
# lizard opens a source file with `io.open(path, 'r')` and no encoding, so the
|
|
206
|
+
# MACHINE'S LOCALE decides what a repo scores. Measured on one function,
|
|
207
|
+
# `function Write-Café`, written once as UTF-8 and once as cp1252, read on a
|
|
208
|
+
# cp1252 interpreter and on a UTF-8 one:
|
|
209
|
+
#
|
|
210
|
+
# source cp1252 reader utf-8 reader
|
|
211
|
+
# utf-8 no function at all Write-Café
|
|
212
|
+
# cp1252 Write-Café Write-Caf
|
|
213
|
+
#
|
|
214
|
+
# The empty cell is not a rounding error: `é` arrives as `Ã` plus `©`, the `©`
|
|
215
|
+
# is no word character, and the declaration stops being one. The ratchet keys on
|
|
216
|
+
# path::long_name, so those are three different rows for one commit, and a
|
|
217
|
+
# Windows developer and a Linux CI cannot see each other's baseline.
|
|
218
|
+
#
|
|
219
|
+
# utf-8 first, cp1252 second, replacement for the five bytes cp1252 leaves
|
|
220
|
+
# undefined. That is the whole rule and it is fixed rather than environmental:
|
|
221
|
+
# all four cells above read `Write-Café`. The fallback is cp1252 rather than
|
|
222
|
+
# latin-1 because Windows PowerShell 5.1 writes cp1252, and because latin-1
|
|
223
|
+
# decodes every byte and so can never say it was wrong.
|
|
224
|
+
#
|
|
225
|
+
# UTF-16 is NOT handled. `Out-File` and the ISE write it, and such a file
|
|
226
|
+
# decodes here as NUL-separated cp1252 text that reports no function; it
|
|
227
|
+
# reported none before this change either, so nothing regressed and the narrow
|
|
228
|
+
# rule stays narrow.
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
def _characters(raw: bytes) -> str:
|
|
232
|
+
if raw.startswith(codecs.BOM_UTF8):
|
|
233
|
+
raw = raw[len(codecs.BOM_UTF8):]
|
|
234
|
+
try:
|
|
235
|
+
return raw.decode("utf-8")
|
|
236
|
+
except UnicodeDecodeError:
|
|
237
|
+
return raw.decode("cp1252", "replace")
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
def decode_source(raw: bytes) -> str:
|
|
241
|
+
"""Source bytes as text, decoded by content rather than by machine locale.
|
|
242
|
+
|
|
243
|
+
The single rule for every path into lizard: a file on disk, and a staged
|
|
244
|
+
blob the pre-commit gate never writes down. Those two must agree or the
|
|
245
|
+
gate judges different content than the inventory scores.
|
|
246
|
+
|
|
247
|
+
Line endings are normalized the way `io.open(path, 'r')` normalized them,
|
|
248
|
+
because that is what lizard did and every recorded line number and NLOC in
|
|
249
|
+
every cache depends on it: a lone `\\r` left in the stream is one more
|
|
250
|
+
whitespace token, not one more line.
|
|
251
|
+
"""
|
|
252
|
+
return _characters(raw).replace("\r\n", "\n").replace("\r", "\n")
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
def read_source(path: str) -> str:
|
|
256
|
+
return decode_source(Path(path).read_bytes())
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def _install_decoder() -> None:
|
|
260
|
+
"""Point lizard's own file read at `read_source`. Idempotent.
|
|
261
|
+
|
|
262
|
+
A rebind rather than a replacement for `FileAnalyzer.__call__`, so lizard
|
|
263
|
+
keeps the IOError branch that answers a file deleted mid-run with an empty
|
|
264
|
+
result instead of a traceback, and keeps reading each file exactly once.
|
|
265
|
+
`lizard.py` binds `auto_read` into its own module namespace at import, and
|
|
266
|
+
`FileAnalyzer.__call__` resolves it there on every call.
|
|
267
|
+
|
|
268
|
+
Raises when that name is gone, which is what a lizard release that reads
|
|
269
|
+
source some other way would look like. Loud beats an attribute nobody
|
|
270
|
+
reads and a decode that silently went back to the locale's.
|
|
271
|
+
"""
|
|
272
|
+
if not hasattr(lizard, "auto_read"):
|
|
273
|
+
raise RuntimeError(
|
|
274
|
+
f"crapkit.analyze._install_decoder() found no lizard.auto_read to "
|
|
275
|
+
f"rebind: lizard {lizard.version} reads source some other way. "
|
|
276
|
+
f"Rewrite this against the new mechanism; leaving it undone makes "
|
|
277
|
+
f"every non-ASCII file score by the machine's locale.")
|
|
278
|
+
lizard.auto_read = read_source
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
_install_decoder()
|
|
282
|
+
|
|
283
|
+
|
|
125
284
|
def analyze_one(args: tuple[str, str]) -> tuple[str, list[FunctionRecord]]:
|
|
126
285
|
abs_path, rel_path = args
|
|
127
286
|
try:
|
|
128
287
|
analysis = lizard.FileAnalyzer(_extensions_for(rel_path))(abs_path)
|
|
129
|
-
return rel_path,
|
|
288
|
+
return rel_path, _file_records(rel_path, analysis.function_list)
|
|
130
289
|
except Exception as exc: # loud, with the file named
|
|
131
290
|
raise ToolError(f"lizard failed on {rel_path}: {exc}") from exc
|
|
132
291
|
|
|
@@ -142,7 +301,7 @@ def analyze_source(rel_path: str, code: str) -> list[FunctionRecord]:
|
|
|
142
301
|
try:
|
|
143
302
|
analyzer = lizard.FileAnalyzer(_extensions_for(rel_path))
|
|
144
303
|
analysis = analyzer.analyze_source_code(rel_path, code)
|
|
145
|
-
return
|
|
304
|
+
return _file_records(rel_path, analysis.function_list)
|
|
146
305
|
except Exception as exc: # loud, with the file named
|
|
147
306
|
raise ToolError(f"lizard failed on {rel_path}: {exc}") from exc
|
|
148
307
|
|
|
@@ -19,16 +19,21 @@ _OWNER = {
|
|
|
19
19
|
"_BriefLoader": "queue",
|
|
20
20
|
"_Corpus": "scoring",
|
|
21
21
|
"_Handles": "queue",
|
|
22
|
+
"_CLAUDE_SUBCOMMANDS": "parser",
|
|
22
23
|
"_SCRIPT_SUFFIXES": "admin",
|
|
23
24
|
"_VersionAction": "parser",
|
|
25
|
+
"_advise": "claude_hook",
|
|
26
|
+
"_advisory_lines": "claude_hook",
|
|
24
27
|
"_actionable": "queue",
|
|
25
28
|
"_analysis_tools": "_shared",
|
|
26
29
|
"_analysis_workers": "scoring",
|
|
30
|
+
"_answerable": "claude_hook",
|
|
27
31
|
"_analyzed_corpus": "scoring",
|
|
28
32
|
"_apply_verify_override": "verifying",
|
|
29
33
|
"_at_level": "admin",
|
|
30
34
|
"_baseline_behind": "verifying",
|
|
31
35
|
"_baseline_failures": "verifying",
|
|
36
|
+
"_baseline_rows": "scoring",
|
|
32
37
|
"_batch_json": "queue",
|
|
33
38
|
"_batch_rows": "queue",
|
|
34
39
|
"_brief_batch": "queue",
|
|
@@ -42,8 +47,10 @@ _OWNER = {
|
|
|
42
47
|
"_brief_twins": "queue",
|
|
43
48
|
"_brief_versions": "queue",
|
|
44
49
|
"_build_inventory": "scoring",
|
|
50
|
+
"_breaches": "claude_hook",
|
|
45
51
|
"_by_scope": "scoring",
|
|
46
52
|
"_ceiling_breaches": "scoring",
|
|
53
|
+
"_changed": "claude_hook",
|
|
47
54
|
"_churn_text": "queue",
|
|
48
55
|
"_claim_matches": "queue",
|
|
49
56
|
"_claimable": "queue",
|
|
@@ -51,10 +58,12 @@ _OWNER = {
|
|
|
51
58
|
"_claims_to_release": "queue",
|
|
52
59
|
"_collect_lanes": "scoring",
|
|
53
60
|
"_collect_mutants": "analyses",
|
|
61
|
+
"_config": "claude_hook",
|
|
54
62
|
"_contexts_for_span": "reports",
|
|
55
63
|
"_coverage_summary": "scoring",
|
|
56
64
|
"_covered_scope_names": "admin",
|
|
57
65
|
"_diff_cover_breach": "verifying",
|
|
66
|
+
"_diff_proc": "claude_hook",
|
|
58
67
|
"_digest_pair": "reports",
|
|
59
68
|
"_dirty_tag": "_shared",
|
|
60
69
|
"_doctor_findings": "admin",
|
|
@@ -63,6 +72,7 @@ _OWNER = {
|
|
|
63
72
|
"_doctor_lane_summary": "admin",
|
|
64
73
|
"_doctor_lanes": "admin",
|
|
65
74
|
"_doctor_oversized": "admin",
|
|
75
|
+
"_doctor_plugin": "admin",
|
|
66
76
|
"_doctor_report": "admin",
|
|
67
77
|
"_doctor_scope_files": "admin",
|
|
68
78
|
"_doctor_scopes": "admin",
|
|
@@ -71,6 +81,8 @@ _OWNER = {
|
|
|
71
81
|
"_doctor_unclaimed": "admin",
|
|
72
82
|
"_doctor_uncovered": "admin",
|
|
73
83
|
"_doctor_unmeasured": "admin",
|
|
84
|
+
"_edited_file": "claude_hook",
|
|
85
|
+
"_edited_path": "claude_hook",
|
|
74
86
|
"_emit_baseline": "verifying",
|
|
75
87
|
"_emit_coverage_findings": "scoring",
|
|
76
88
|
"_emit_doctor": "admin",
|
|
@@ -92,13 +104,17 @@ _OWNER = {
|
|
|
92
104
|
"_flake_retry": "verifying",
|
|
93
105
|
"_gate_candidates": "scoring",
|
|
94
106
|
"_gate_line": "_shared",
|
|
107
|
+
"_gated_violations": "verifying",
|
|
95
108
|
"_grant_env_override": "verifying",
|
|
96
109
|
"_group_files_by_scope": "verifying",
|
|
97
110
|
"_guard_ratchet_stamp": "verifying",
|
|
98
111
|
"_handle": "queue",
|
|
112
|
+
"_hook_handlers": "admin",
|
|
99
113
|
"_hook_modes": "admin",
|
|
114
|
+
"_hook_protocols": "admin",
|
|
100
115
|
"_interpreter": "admin",
|
|
101
116
|
"_is_test_path": "verifying",
|
|
117
|
+
"_judge": "claude_hook",
|
|
102
118
|
"_junit_seconds": "admin",
|
|
103
119
|
"_lane_command_problems": "admin",
|
|
104
120
|
"_lane_durations": "admin",
|
|
@@ -116,9 +132,11 @@ _OWNER = {
|
|
|
116
132
|
"_load_ratchet_or_die": "_shared",
|
|
117
133
|
"_load_repo_config": "_shared",
|
|
118
134
|
"_load_sources": "_shared",
|
|
135
|
+
"_manifest_version": "admin",
|
|
119
136
|
"_mark_text": "queue",
|
|
120
137
|
"_matching_rows": "queue",
|
|
121
138
|
"_maybe_claim": "queue",
|
|
139
|
+
"_marks_for": "claude_hook",
|
|
122
140
|
"_maybe_flake_retry": "verifying",
|
|
123
141
|
"_merge_stamp": "ratchet_cmds",
|
|
124
142
|
"_missing_named_script": "admin",
|
|
@@ -127,6 +145,7 @@ _OWNER = {
|
|
|
127
145
|
"_name_prefix": "queue",
|
|
128
146
|
"_named_baseline": "verifying",
|
|
129
147
|
"_named_claims": "queue",
|
|
148
|
+
"_named_protocol": "admin",
|
|
130
149
|
"_newest_coverage_run": "admin",
|
|
131
150
|
"_newest_run_report": "admin",
|
|
132
151
|
"_next_head": "queue",
|
|
@@ -140,6 +159,7 @@ _OWNER = {
|
|
|
140
159
|
"_no_line_message": "queue",
|
|
141
160
|
"_no_match_message": "queue",
|
|
142
161
|
"_no_scopes_reason": "admin",
|
|
162
|
+
"_note_marked_staged": "verifying",
|
|
143
163
|
"_note_stale_staged": "verifying",
|
|
144
164
|
"_open_store": "_shared",
|
|
145
165
|
"_owning_scope": "verifying",
|
|
@@ -148,8 +168,10 @@ _OWNER = {
|
|
|
148
168
|
"_packet_context": "queue",
|
|
149
169
|
"_packet_gate": "queue",
|
|
150
170
|
"_packet_scope": "queue",
|
|
171
|
+
"_payload": "claude_hook",
|
|
151
172
|
"_pick_baseline": "verifying",
|
|
152
173
|
"_pick_function": "queue",
|
|
174
|
+
"_plugin_json": "admin",
|
|
153
175
|
"_policy_findings": "ratchet_cmds",
|
|
154
176
|
"_present_markers": "admin",
|
|
155
177
|
"_present_on_disk": "scoring",
|
|
@@ -185,9 +207,12 @@ _OWNER = {
|
|
|
185
207
|
"_ratchet_move": "ratchet_cmds",
|
|
186
208
|
"_ratchet_report": "ratchet_cmds",
|
|
187
209
|
"_ratchet_sha256": "verifying",
|
|
210
|
+
"_reconfigure_streams": "parser",
|
|
211
|
+
"_records": "claude_hook",
|
|
188
212
|
"_records_by_scope": "scoring",
|
|
189
213
|
"_release_claims": "verifying",
|
|
190
214
|
"_release_target": "queue",
|
|
215
|
+
"_report": "claude_hook",
|
|
191
216
|
"_report_lanes": "reports",
|
|
192
217
|
"_report_payload": "reports",
|
|
193
218
|
"_report_verify": "verifying",
|
|
@@ -214,13 +239,16 @@ _OWNER = {
|
|
|
214
239
|
"_runs_prune": "reports",
|
|
215
240
|
"_scope_config": "queue",
|
|
216
241
|
"_scope_rollup_from_agg": "reports",
|
|
242
|
+
"_scoped": "claude_hook",
|
|
217
243
|
"_scoped_command": "verifying",
|
|
218
244
|
"_scored_run": "scoring",
|
|
219
245
|
"_scored_store": "queue",
|
|
220
246
|
"_select_lanes": "scoring",
|
|
221
247
|
"_send_digest_alert": "reports",
|
|
248
|
+
"_sequencing": "claude_hook",
|
|
222
249
|
"_settle_verify": "verifying",
|
|
223
250
|
"_skip_reason": "queue",
|
|
251
|
+
"_split_marked": "verifying",
|
|
224
252
|
"_split_worklist": "queue",
|
|
225
253
|
"_stale_warning": "queue",
|
|
226
254
|
"_store_if_any": "admin",
|
|
@@ -228,6 +256,7 @@ _OWNER = {
|
|
|
228
256
|
"_store_report": "admin",
|
|
229
257
|
"_taint_note": "verifying",
|
|
230
258
|
"_traced_lane": "scoring",
|
|
259
|
+
"_tracked": "claude_hook",
|
|
231
260
|
"_tracked_files": "scoring",
|
|
232
261
|
"_trend_payload": "reports",
|
|
233
262
|
"_trend_row": "reports",
|
|
@@ -239,7 +268,9 @@ _OWNER = {
|
|
|
239
268
|
"_under_scope_path": "verifying",
|
|
240
269
|
"_unknown_key_text": "admin",
|
|
241
270
|
"_unmarked_breaches": "scoring",
|
|
271
|
+
"_unknown_claude_command": "parser",
|
|
242
272
|
"_untracked_of": "scoring",
|
|
273
|
+
"_verdict": "claude_hook",
|
|
243
274
|
"_verify_attribution": "verifying",
|
|
244
275
|
"_verify_baseline": "verifying",
|
|
245
276
|
"_verify_basis": "verifying",
|
|
@@ -266,6 +297,7 @@ _OWNER = {
|
|
|
266
297
|
"build_parser": "parser",
|
|
267
298
|
"cmd_brief": "queue",
|
|
268
299
|
"cmd_claims": "queue",
|
|
300
|
+
"cmd_claude_hook": "claude_hook",
|
|
269
301
|
"cmd_coupling": "analyses",
|
|
270
302
|
"cmd_coverage": "scoring",
|
|
271
303
|
"cmd_digest": "reports",
|