@andresmassello/uscha 1.40.1
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.
- package/LICENSE +21 -0
- package/README.md +104 -0
- package/bin/README.md +6 -0
- package/bin/uscha.js +28 -0
- package/package.json +38 -0
- package/uscha-kit/.claude/skills/uscha-adr-refine/SKILL.md +161 -0
- package/uscha-kit/.claude/skills/uscha-characterize/SKILL.md +124 -0
- package/uscha-kit/.claude/skills/uscha-devloop/SKILL.md +490 -0
- package/uscha-kit/.claude/skills/uscha-devloop/qa_ledger.py +5602 -0
- package/uscha-kit/.claude/skills/uscha-discovery/SKILL.md +161 -0
- package/uscha-kit/.claude/skills/uscha-mirador/SKILL.md +145 -0
- package/uscha-kit/.claude/skills/uscha-mirador/mirador-render.py +112 -0
- package/uscha-kit/.claude/skills/uscha-mirador/mirador-watch.ps1 +22 -0
- package/uscha-kit/.claude/skills/uscha-mirador/mirador-watch.sh +26 -0
- package/uscha-kit/.claude/skills/uscha-mirador/mirador.template.html +586 -0
- package/uscha-kit/.claude/skills/uscha-mirador/telemetry-extract.py +130 -0
- package/uscha-kit/.claude/skills/uscha-reverse-discovery/SKILL.md +116 -0
- package/uscha-kit/.claude/skills/uscha-rubric/SKILL.md +79 -0
- package/uscha-kit/.claude/skills/uscha-sysdoc/SKILL.md +88 -0
- package/uscha-kit/.claude-plugin/plugin.json +24 -0
- package/uscha-kit/.codex-plugin/plugin.json +37 -0
- package/uscha-kit/CHANGELOG-1.10.0.md +84 -0
- package/uscha-kit/CHANGELOG-1.11.0.md +67 -0
- package/uscha-kit/CHANGELOG-1.12.0.md +46 -0
- package/uscha-kit/CHANGELOG-1.13.0.md +33 -0
- package/uscha-kit/CHANGELOG-1.14.0.md +42 -0
- package/uscha-kit/CHANGELOG-1.15.0.md +58 -0
- package/uscha-kit/CHANGELOG-1.16.0.md +55 -0
- package/uscha-kit/CHANGELOG-1.17.0.md +44 -0
- package/uscha-kit/CHANGELOG-1.18.0.md +42 -0
- package/uscha-kit/CHANGELOG-1.19.0.md +41 -0
- package/uscha-kit/CHANGELOG-1.2.2.md +16 -0
- package/uscha-kit/CHANGELOG-1.2.3.md +20 -0
- package/uscha-kit/CHANGELOG-1.2.4.md +10 -0
- package/uscha-kit/CHANGELOG-1.2.5.md +23 -0
- package/uscha-kit/CHANGELOG-1.2.6.md +11 -0
- package/uscha-kit/CHANGELOG-1.2.7.md +15 -0
- package/uscha-kit/CHANGELOG-1.2.8.md +24 -0
- package/uscha-kit/CHANGELOG-1.2.9.md +4 -0
- package/uscha-kit/CHANGELOG-1.20.0.md +29 -0
- package/uscha-kit/CHANGELOG-1.21.0.md +33 -0
- package/uscha-kit/CHANGELOG-1.22.0.md +60 -0
- package/uscha-kit/CHANGELOG-1.23.0.md +75 -0
- package/uscha-kit/CHANGELOG-1.24.0.md +50 -0
- package/uscha-kit/CHANGELOG-1.25.0.md +55 -0
- package/uscha-kit/CHANGELOG-1.26.0.md +70 -0
- package/uscha-kit/CHANGELOG-1.27.0.md +45 -0
- package/uscha-kit/CHANGELOG-1.28.0.md +35 -0
- package/uscha-kit/CHANGELOG-1.29.0.md +20 -0
- package/uscha-kit/CHANGELOG-1.3.0.md +74 -0
- package/uscha-kit/CHANGELOG-1.30.0.md +46 -0
- package/uscha-kit/CHANGELOG-1.31.0.md +59 -0
- package/uscha-kit/CHANGELOG-1.32.0.md +50 -0
- package/uscha-kit/CHANGELOG-1.33.0.md +46 -0
- package/uscha-kit/CHANGELOG-1.34.0.md +55 -0
- package/uscha-kit/CHANGELOG-1.35.0.md +30 -0
- package/uscha-kit/CHANGELOG-1.36.0.md +33 -0
- package/uscha-kit/CHANGELOG-1.37.0.md +41 -0
- package/uscha-kit/CHANGELOG-1.38.0.md +11 -0
- package/uscha-kit/CHANGELOG-1.39.0.md +14 -0
- package/uscha-kit/CHANGELOG-1.4.0.md +68 -0
- package/uscha-kit/CHANGELOG-1.40.0.md +16 -0
- package/uscha-kit/CHANGELOG-1.40.1.md +11 -0
- package/uscha-kit/CHANGELOG-1.5.0.md +64 -0
- package/uscha-kit/CHANGELOG-1.6.0.md +57 -0
- package/uscha-kit/CHANGELOG-1.7.0.md +74 -0
- package/uscha-kit/CHANGELOG-1.8.0.md +46 -0
- package/uscha-kit/CHANGELOG-1.9.0.md +112 -0
- package/uscha-kit/LICENSE +21 -0
- package/uscha-kit/README.md +497 -0
- package/uscha-kit/VERSION +1 -0
- package/uscha-kit/WORKBENCH.md +178 -0
- package/uscha-kit/hooks/block-approved-writes.ps1 +46 -0
- package/uscha-kit/hooks/hooks.json +15 -0
- package/uscha-kit/install-uscha.py +344 -0
- package/uscha-kit/skills/uscha-adr-refine/SKILL.md +161 -0
- package/uscha-kit/skills/uscha-characterize/SKILL.md +124 -0
- package/uscha-kit/skills/uscha-devloop/SKILL.md +490 -0
- package/uscha-kit/skills/uscha-devloop/qa_ledger.py +5602 -0
- package/uscha-kit/skills/uscha-discovery/SKILL.md +161 -0
- package/uscha-kit/skills/uscha-mirador/SKILL.md +145 -0
- package/uscha-kit/skills/uscha-mirador/mirador-render.py +112 -0
- package/uscha-kit/skills/uscha-mirador/mirador-watch.ps1 +22 -0
- package/uscha-kit/skills/uscha-mirador/mirador-watch.sh +26 -0
- package/uscha-kit/skills/uscha-mirador/mirador.template.html +586 -0
- package/uscha-kit/skills/uscha-mirador/telemetry-extract.py +130 -0
- package/uscha-kit/skills/uscha-reverse-discovery/SKILL.md +116 -0
- package/uscha-kit/skills/uscha-rubric/SKILL.md +79 -0
- package/uscha-kit/skills/uscha-sysdoc/SKILL.md +88 -0
- package/uscha-kit/templates/.gitattributes +6 -0
- package/uscha-kit/templates/CLAUDE.md +56 -0
- package/uscha-kit/templates/CONSTITUTION.md +149 -0
- package/uscha-kit/templates/RUBRIC.md +38 -0
- package/uscha-kit/templates/docs/adr/README.md +19 -0
- package/uscha-kit/templates/rubric-grader-prompt.md +63 -0
- package/uscha-kit/tests/smoke-engine.sh +1739 -0
- package/uscha-kit/uscha.config.json +181 -0
- package/uscha-kit/workbench-doctor.sh +45 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Andres Massello
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,497 @@
|
|
|
1
|
+
# uscha-kit
|
|
2
|
+
|
|
3
|
+
**Kit version:** v1.40.1 <!-- uscha:version -->
|
|
4
|
+
|
|
5
|
+
Spec-driven orchestrator + multi-repo QA for Claude Code, with a deterministic ledger.
|
|
6
|
+
**Eight skills** (`uscha-discovery`, `uscha-adr-refine`, `uscha-devloop`, `uscha-sysdoc`, `uscha-reverse-discovery`,
|
|
7
|
+
`uscha-characterize`, `uscha-rubric`, `uscha-mirador`) and a measurement engine (`qa_ledger.py`).
|
|
8
|
+
|
|
9
|
+
**Who it's for:** a solo operator carrying ONE non-trivial or risky change, kept
|
|
10
|
+
honest by a deterministic ledger and a human gate at the merge. It is NOT for trivial
|
|
11
|
+
changes (a one-liner runs build+test and that's it).
|
|
12
|
+
|
|
13
|
+
## What's inside
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
uscha-kit/
|
|
17
|
+
├─ uscha.config.json # config: repos, thresholds, commands
|
|
18
|
+
├─ hooks/
|
|
19
|
+
│ └─ block-approved-writes.ps1 # PreToolUse: the agent CANNOT write .approved (INV-GOLDEN-01)
|
|
20
|
+
├─ templates/
|
|
21
|
+
│ ├─ CLAUDE.md # permanent repo protocol
|
|
22
|
+
│ ├─ CONSTITUTION.md # inviolable invariants (fill in the domain)
|
|
23
|
+
│ ├─ .gitattributes # *.approved.* binary — so line endings don't lie
|
|
24
|
+
│ └─ docs/adr/ # ADR scaffold
|
|
25
|
+
?? .codex-plugin/plugin.json # Codex plugin manifest
|
|
26
|
+
?? skills/ # Codex plugin mirror of .claude/skills (smoke checks sync)
|
|
27
|
+
└─ .claude/skills/
|
|
28
|
+
├─ uscha-discovery/ # vague idea → 1x1 grilling → CONSTITUTION/SPEC/ADR/ACCEPTANCE…
|
|
29
|
+
├─ uscha-adr-refine/ # known feature: precision interview → ADR + ACCEPTANCE
|
|
30
|
+
├─ uscha-reverse-discovery/ # brownfield: FACTS map of the existing system (does not propose shape)
|
|
31
|
+
├─ uscha-characterize/ # captures the golden by running the ORIGINAL code (stops at human approval)
|
|
32
|
+
├─ uscha-devloop/
|
|
33
|
+
│ ├─ SKILL.md # orchestrator: plan → build → QA loop → PR
|
|
34
|
+
│ └─ qa_ledger.py # measurement + ledger + gates (ingest/log-gate/golden-diff/gate-check/pit/simplicity/rebuild)
|
|
35
|
+
├─ uscha-sysdoc/ # (optional) two-view HTML deck from the ledger
|
|
36
|
+
└─ uscha-rubric/ # (optional) rubric grading — thin adapter; the core is agnostic
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## End-to-end flow
|
|
40
|
+
|
|
41
|
+
`uscha-discovery` is the front for something new (you only have the idea); `uscha-adr-refine` is the front
|
|
42
|
+
for a known feature; `uscha-devloop` builds and verifies. They meet at the `ACCEPTANCE.md`.
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
/uscha-discovery # idea only + reference material → 1x1 grilling (proposes, you decide)
|
|
46
|
+
↓ # writes CONTEXT.md, CONSTITUTION.md, SPEC.md, docs/adr/*.md, ACCEPTANCE.md, RISKS.md, HANDOFF.md
|
|
47
|
+
/uscha-devloop # plan → build → QA loop (fact gates to the ledger) → PR (stops at the merge)
|
|
48
|
+
↓
|
|
49
|
+
/uscha-sysdoc # (optional, on request) documents the system from the ledger
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
(For an already known feature, instead of `/uscha-discovery` you use `/uscha-adr-refine`.)
|
|
53
|
+
|
|
54
|
+
**Migration/legacy on-ramp (profile E):** the golden is the field truth and is captured
|
|
55
|
+
BEFORE touching anything.
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
/uscha-reverse-discovery # FACTS map of the old system (endpoints, contracts, dependencies)
|
|
59
|
+
↓
|
|
60
|
+
/uscha-characterize # runs the ORIGINAL code with a real corpus → .received → STOPS:
|
|
61
|
+
↓ # a HUMAN approves the .approved (the agent never writes them — hook)
|
|
62
|
+
/uscha-devloop # migrates; golden-diff byte-compares against the .approved on each pass
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Requirements
|
|
66
|
+
|
|
67
|
+
- **Python 3.8+** (stdlib only — no `pip install`). `cloc` is NOT needed; the LOC is
|
|
68
|
+
counted in Python.
|
|
69
|
+
- For `ingest-gate` and coverage to work, your Maven build must emit the
|
|
70
|
+
reports (your `java-qa-gate` already has the plugins; these are the paths the ledger
|
|
71
|
+
expects):
|
|
72
|
+
|
|
73
|
+
| data | plugin / goal | file |
|
|
74
|
+
|-------------|--------------------------------------------------|---------|
|
|
75
|
+
| coverage | `jacoco-maven-plugin` (`report`) | `target/site/jacoco/jacoco.xml` (or `jacoco-aggregate/`) |
|
|
76
|
+
| test count | `maven-surefire-plugin` / `failsafe` | `target/surefire-reports/TEST-*.xml` |
|
|
77
|
+
| checkstyle | `maven-checkstyle-plugin` (`checkstyle`) | `target/checkstyle-result.xml` |
|
|
78
|
+
| pmd | `maven-pmd-plugin` (`pmd`) | `target/pmd.xml` |
|
|
79
|
+
| spotbugs+fsb| `spotbugs-maven-plugin` (+ findsecbugs) | `target/spotbugsXml.xml` |
|
|
80
|
+
|
|
81
|
+
Flutter: coverage from `coverage/lcov.info` (`flutter test --coverage`);
|
|
82
|
+
the test count is approximate (it counts `test(`/`testWidgets(`).
|
|
83
|
+
|
|
84
|
+
Python (`type: python`, kit 1.4.0):
|
|
85
|
+
|
|
86
|
+
| data | command | file |
|
|
87
|
+
|-------------|---------------------------------------------------|---------|
|
|
88
|
+
| coverage | `pytest --cov --cov-report=xml:reports/coverage.xml` | `coverage.xml` or `reports/coverage.xml` (Cobertura) |
|
|
89
|
+
| test count | `pytest --junitxml=reports/junit.xml` | `reports/junit.xml` (wrapped root `<testsuites>` supported) |
|
|
90
|
+
| ruff | `ruff check --output-format=json > reports/ruff.json` | `reports/ruff.json` (S*/E9*/F82*→HIGH · B*→MEDIUM · rest→LOW) |
|
|
91
|
+
| mypy | `mypy src > reports/mypy.txt` | `reports/mypy.txt` (error→HIGH · warning→MEDIUM · note→INFO) |
|
|
92
|
+
|
|
93
|
+
`ingest-gate` finds them automatically by the repo's type, or with explicit `--ruff/--mypy`.
|
|
94
|
+
Contract identical to Java: a missing report = the gate didn't run (it never credits fixes).
|
|
95
|
+
|
|
96
|
+
TypeScript/JS (`type: node`, kit 1.5.0):
|
|
97
|
+
|
|
98
|
+
| data | command | file |
|
|
99
|
+
|-------------|---------------------------------------------------|---------|
|
|
100
|
+
| coverage | `jest --coverage` (or vitest with lcov reporter) | `coverage/lcov.info` (same parser as Flutter) |
|
|
101
|
+
| test count | `jest-junit` / `vitest --reporter=junit` | `reports/junit.xml` or `junit.xml` (wrapped root supported) |
|
|
102
|
+
| eslint | `eslint . --format json > reports/eslint.json` | `reports/eslint.json` (error→HIGH · warn→MEDIUM · `security/*` floor HIGH · ruleId null→HIGH) |
|
|
103
|
+
| tsc | `tsc --noEmit > reports/tsc.txt` | `reports/tsc.txt` (error TS → HIGH) |
|
|
104
|
+
|
|
105
|
+
`ingest-gate` finds them by the repo's type, or with explicit `--eslint/--tsc`.
|
|
106
|
+
Same absence contract.
|
|
107
|
+
|
|
108
|
+
Go (`type: go`, kit 1.6.0):
|
|
109
|
+
|
|
110
|
+
| data | command | file |
|
|
111
|
+
|-------------|---------------------------------------------------|---------|
|
|
112
|
+
| coverage | `go test -coverprofile=coverage.out ./...` | `coverage.out` (native cover profile — % by STATEMENTS, the Go convention) |
|
|
113
|
+
| test count | `gotestsum --junitfile reports/junit.xml -- ./...`| `reports/junit.xml` (wrapped JUnit supported) |
|
|
114
|
+
| golangci | `golangci-lint run --output.checkstyle.path=reports/golangci.xml` (v2; in v1: `--out-format checkstyle > ...`) | `reports/golangci.xml` (checkstyle format: error→HIGH · warning→MEDIUM; includes gosec if enabled) |
|
|
115
|
+
|
|
116
|
+
`ingest-gate` finds it by the repo's type, or with explicit `--golangci`. The
|
|
117
|
+
`_test.go` tests live alongside the code (Go convention) — the LOC classifies them by suffix.
|
|
118
|
+
`vendor/` and `testdata/` are excluded from the LOC. Same absence contract.
|
|
119
|
+
**Watch out for severities**: golangci-lint emits `severity=error` for EVERYTHING unless you
|
|
120
|
+
configure `severity:` rules — without that, even style nits gate as HIGH;
|
|
121
|
+
configure severities (or a lean linter set) so that MEDIUM really exists.
|
|
122
|
+
|
|
123
|
+
Rust (`type: rust`, kit 1.7.0):
|
|
124
|
+
|
|
125
|
+
| data | command | file |
|
|
126
|
+
|-------------|---------------------------------------------------|---------|
|
|
127
|
+
| coverage | `cargo llvm-cov --cobertura --output-path reports/coverage.xml` | `reports/coverage.xml` (Cobertura — same parser as Python) |
|
|
128
|
+
| test count | `cargo nextest run` + copy (see note) | `reports/junit.xml` (wrapped JUnit supported) |
|
|
129
|
+
| clippy | `cargo clippy --message-format=json > reports/clippy.json` | `reports/clippy.json` (JSONL: error→HIGH · warning→MEDIUM · `code:null` compile-error→HIGH; summaries without span ignored) |
|
|
130
|
+
|
|
131
|
+
`ingest-gate` with explicit `--clippy` or by type. The inline `#[cfg(test)]` tests
|
|
132
|
+
count as prod LOC (documented limitation); `tests/` = integration.
|
|
133
|
+
**Watch out for junit**: nextest does NOT emit JUnit by default — you have to enable it in
|
|
134
|
+
`.config/nextest.toml` (`[profile.default.junit] path = "junit.xml"`) and the file
|
|
135
|
+
lands in `target/nextest/default/junit.xml`; copy it to `reports/junit.xml`
|
|
136
|
+
(`cp target/nextest/default/junit.xml reports/junit.xml`, already included in the
|
|
137
|
+
example `test_command_rust`).
|
|
138
|
+
|
|
139
|
+
C#/.NET (`type: dotnet`, kit 1.7.0):
|
|
140
|
+
|
|
141
|
+
| data | command | file |
|
|
142
|
+
|-------------|---------------------------------------------------|---------|
|
|
143
|
+
| coverage | coverlet.msbuild: `/p:CollectCoverage=true /p:CoverletOutputFormat=cobertura /p:CoverletOutput=$PWD/reports/coverage.xml` | `reports/coverage.xml` (Cobertura) |
|
|
144
|
+
| test count | `dotnet test --logger "junit;LogFilePath=$PWD/reports/junit.xml"` (JUnitXml.TestLogger package) | `reports/junit.xml` |
|
|
145
|
+
| roslyn | `dotnet build /p:ErrorLog="reports/analysis.sarif,version=2"` | `reports/analysis.sarif` (SARIF: error→HIGH · warning→MEDIUM · note→INFO; suppressed ignored) |
|
|
146
|
+
|
|
147
|
+
`ingest-gate` with explicit `--sarif` or by type. SARIF is the universal static-analysis
|
|
148
|
+
format — the parser works for any tool that emits it.
|
|
149
|
+
**Watch out for paths**: relative `LogFilePath` and `CoverletOutput` resolve against the
|
|
150
|
+
TEST PROJECT directory, not the repo root — hence the `$PWD`
|
|
151
|
+
(absolute anchoring). With multiple test projects, merge (`/p:MergeWith`) or use one
|
|
152
|
+
report per project. `ErrorLog` without `,version=2` emits SARIF **v1**; the parser
|
|
153
|
+
has a v1 fallback, but ask for v2 (the comma requires the quotes).
|
|
154
|
+
|
|
155
|
+
C++ (`type: cpp`, kit 1.8.0):
|
|
156
|
+
|
|
157
|
+
| data | command | file |
|
|
158
|
+
|-------------|---------------------------------------------------|---------|
|
|
159
|
+
| coverage | `gcovr --cobertura reports/coverage.xml` (over gcov) | `reports/coverage.xml` (Cobertura — same parser) |
|
|
160
|
+
| test count | `ctest --test-dir build --output-junit ../reports/junit.xml` (CMake ≥3.21) or `--gtest_output=xml:...` | `reports/junit.xml` (flat AND wrapped root supported) |
|
|
161
|
+
| clang-tidy | `clang-tidy <files> > reports/clang-tidy.txt` | `reports/clang-tidy.txt` (error→HIGH · warning→MEDIUM · `cert-*`/security floor HIGH) |
|
|
162
|
+
|
|
163
|
+
`ingest-gate` with explicit `--clang-tidy` or by type. The build system (CMake/
|
|
164
|
+
Bazel/make) belongs to the per-repo adapter — the kit only requires that the reports exist.
|
|
165
|
+
`cmake-build-*` (any CLion profile) and `_deps` are excluded from the LOC.
|
|
166
|
+
|
|
167
|
+
Kotlin/JVM with Gradle (`type: gradle`, kit 1.9.0) — **Kotlin over Maven already
|
|
168
|
+
works with `type: maven`** (`.kt` has always counted; JaCoCo/Surefire don't
|
|
169
|
+
distinguish JVM language). This type is for the common Gradle case:
|
|
170
|
+
|
|
171
|
+
| data | command | file |
|
|
172
|
+
|-------------|---------------------------------------------------|---------|
|
|
173
|
+
| coverage | `./gradlew test jacocoTestReport` | `build/reports/jacoco/test/jacocoTestReport.xml` (JaCoCo — same parser as maven) |
|
|
174
|
+
| test count | (same `./gradlew test`) | `build/test-results/**/TEST-*.xml` (per-class, like surefire) |
|
|
175
|
+
| detekt | `./gradlew detekt` **separately** (see note) | `build/reports/detekt/detekt.xml` (checkstyle format: error→HIGH · warning→MEDIUM; absolute paths relativized) |
|
|
176
|
+
|
|
177
|
+
`ingest-gate` with explicit `--detekt` or by type. It works the same for Java-over-
|
|
178
|
+
Gradle. LOC: `src/main` = prod; `src/test` AND custom source sets (`src/
|
|
179
|
+
integrationTest`, `src/functionalTest` — any `src/*Test`) = test
|
|
180
|
+
(`.kt`/`.kts`/`.java`). The JaCoCo requirement: `jacoco` plugin +
|
|
181
|
+
`jacocoTestReport { reports { xml.required = true } }`.
|
|
182
|
+
**Watch out for detekt**: do NOT chain it to the test command — its default is `maxIssues: 0`,
|
|
183
|
+
meaning ONE finding breaks the build and the test run would read red even though
|
|
184
|
+
the tests pass. Run `./gradlew detekt` separately, before the `ingest-gate`
|
|
185
|
+
(the lint gate has its own channel).
|
|
186
|
+
|
|
187
|
+
Swift (`type: swift`, kit 1.9.0):
|
|
188
|
+
|
|
189
|
+
| data | command | file |
|
|
190
|
+
|-------------|---------------------------------------------------|---------|
|
|
191
|
+
| coverage | `swift test --enable-code-coverage` + `llvm-cov export -format=lcov ... > coverage/lcov.info` | `coverage/lcov.info` (lcov — same parser as Flutter/node) |
|
|
192
|
+
| test count | `swift test --xunit-output reports/junit.xml` | `reports/junit.xml` **+ `reports/junit-swift-testing.xml`** (they are SUMMED — see note) |
|
|
193
|
+
| swiftlint | `swiftlint lint --reporter checkstyle > reports/swiftlint.xml` | `reports/swiftlint.xml` (checkstyle format: error→HIGH · warning→MEDIUM; absolute paths relativized) |
|
|
194
|
+
|
|
195
|
+
`ingest-gate` with explicit `--swiftlint` or by type. LOC: SwiftPM convention
|
|
196
|
+
(`Sources/` = prod, `Tests/` + `*Tests.swift` = test). The lcov export needs
|
|
197
|
+
the `llvm-cov export` step against the tests binary (the `.profdata` alone is
|
|
198
|
+
not enough) — leave it in your repo's `test_command_swift`; on macOS it is
|
|
199
|
+
`xcrun llvm-cov`, on Linux plain `llvm-cov` (and the binary lives in
|
|
200
|
+
`.build/debug/<Pkg>PackageTests.xctest`).
|
|
201
|
+
**Watch out for Swift Testing**: `--xunit-output` writes the XCTest results to
|
|
202
|
+
`junit.xml` and the **Swift Testing** ones (the default in Swift 6) to a SECOND
|
|
203
|
+
file `junit-swift-testing.xml` — the engine sums BOTH; if it only read the
|
|
204
|
+
first, a Swift 6 package would measure `tests=0` and a real failure would be
|
|
205
|
+
invisible (fail-open).
|
|
206
|
+
|
|
207
|
+
## Installation
|
|
208
|
+
|
|
209
|
+
**Preferred public install (kit 1.40.1): use npm/npx.** The npm package is a
|
|
210
|
+
thin router over the canonical Python installer, so adoption is easy without
|
|
211
|
+
duplicating installer logic. You need Node/npm for this path and Python 3.8+ for
|
|
212
|
+
the underlying installer.
|
|
213
|
+
|
|
214
|
+
Codex-only machine:
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
npx @andresmassello/uscha@latest version
|
|
218
|
+
npx @andresmassello/uscha@latest install --target codex --dry-run
|
|
219
|
+
npx @andresmassello/uscha@latest install --target codex
|
|
220
|
+
npx @andresmassello/uscha@latest doctor --target codex
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Machine used by both Codex and Claude:
|
|
224
|
+
|
|
225
|
+
```bash
|
|
226
|
+
npx @andresmassello/uscha@latest install --target both --dry-run
|
|
227
|
+
npx @andresmassello/uscha@latest install --target both
|
|
228
|
+
npx @andresmassello/uscha@latest doctor --target both
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
**Repo checkout install still works and is preferred when developing the kit
|
|
232
|
+
itself.** One interface, two adapters: Codex gets a personal local plugin
|
|
233
|
+
(`~/plugins/uscha` + `~/.agents/plugins/marketplace.json`), Claude gets global
|
|
234
|
+
skills/hooks under `~/.claude`. Use `--dry-run` first on every new machine.
|
|
235
|
+
|
|
236
|
+
```bash
|
|
237
|
+
python uscha-kit/install-uscha.py version
|
|
238
|
+
python uscha-kit/install-uscha.py install --target codex --dry-run
|
|
239
|
+
python uscha-kit/install-uscha.py install --target codex
|
|
240
|
+
python uscha-kit/install-uscha.py doctor --target codex
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
For the machine where you DEVELOP the kit, use links instead of copies so the
|
|
244
|
+
installed skills follow the canonical repo after `git pull`:
|
|
245
|
+
|
|
246
|
+
```bash
|
|
247
|
+
python uscha-kit/install-uscha.py install --target both --mode link --dry-run
|
|
248
|
+
python uscha-kit/install-uscha.py install --target both --mode link
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
Prepare a repo after the machine install:
|
|
252
|
+
|
|
253
|
+
```bash
|
|
254
|
+
npx @andresmassello/uscha@latest init --repo <repo> --dry-run
|
|
255
|
+
npx @andresmassello/uscha@latest init --repo <repo>
|
|
256
|
+
# or from a checkout:
|
|
257
|
+
python uscha-kit/install-uscha.py init --repo <repo>
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
What remains PER PROJECT (state, not installable): `uscha.config.json` in the
|
|
261
|
+
repo root where you run the run (the `path` values are relative to there ? and your declared
|
|
262
|
+
quality bar lives there), the `QA-LEDGER.json`, the `ACCEPTANCE.md`, and for migration
|
|
263
|
+
work the `.gitattributes` from `templates/` (`*.approved.* binary`).
|
|
264
|
+
|
|
265
|
+
**Legacy/manual install** still works: copy `.claude/` and `uscha.config.json`
|
|
266
|
+
per project, or copy the `uscha-*` skills to `~/.claude/skills/`. Prefer the
|
|
267
|
+
installer unless you are debugging the installer itself.
|
|
268
|
+
|
|
269
|
+
**Claude Code plugin** remains available for Claude Code users:
|
|
270
|
+
|
|
271
|
+
```
|
|
272
|
+
/plugin marketplace add andresmassello/uscha
|
|
273
|
+
/plugin install uscha@uscha
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
Updates: `/plugin update uscha@uscha` for Claude Code plugin installs,
|
|
277
|
+
`npx @andresmassello/uscha@latest install ...` for npm installs, or rerun
|
|
278
|
+
`install-uscha.py install ...` from a repo checkout.
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
**Verify the installation with `doctor`** (kit 1.22.0, in the spirit of flutter doctor —
|
|
283
|
+
Windows and Linux, ASCII output, exit 1 only on errors):
|
|
284
|
+
|
|
285
|
+
```bash
|
|
286
|
+
python uscha-kit/install-uscha.py doctor --target both
|
|
287
|
+
# or engine-only: python3 ~/.claude/skills/uscha-devloop/qa_ledger.py doctor
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
It checks: Python >=3.8 · git · the 8 skills alongside the engine (frontmatter
|
|
291
|
+
verified) · the INV-GOLDEN-01 hook (present + registered in settings.json +
|
|
292
|
+
powershell/pwsh interpreter) · and if there is a `uscha.config.json` in the cwd:
|
|
293
|
+
config parseable, ACCEPTANCE with AC-IDs, ledger integrity, the QA skills
|
|
294
|
+
from `qa_tools_order` (the loop orchestrates them without bringing them in) and the
|
|
295
|
+
primary toolchain of each repo by type (its absence is a WARNING — it may live only in CI).
|
|
296
|
+
|
|
297
|
+
## Configure
|
|
298
|
+
|
|
299
|
+
Edit `uscha.config.json`:
|
|
300
|
+
|
|
301
|
+
- `repos[]`: name, `path` (relative to the primary repo), `type` (`maven`|`flutter`|`python`|`node`|`go`|`rust`|`dotnet`|`cpp`|`gradle`|`swift`).
|
|
302
|
+
- `defaults.coverage_threshold`: triggers the characterization phase if below it.
|
|
303
|
+
- `defaults.severity_gate`: which severities block (default BLOCKER/CRITICAL/HIGH).
|
|
304
|
+
- `defaults.id_granularity`: `line` or `file` (default `file`: more stable if you refactor a lot).
|
|
305
|
+
- `defaults.acceptance_file`: path of the **acceptance task list** (markdown checkboxes) that feeds the ADR completion of readiness. Default `ACCEPTANCE.md`.
|
|
306
|
+
- `defaults.constitution_file`: path of the **CONSTITUTION** (inviolable invariants). Default `CONSTITUTION.md`.
|
|
307
|
+
- `defaults.rebuild.coverage_tolerance`: coverage points the rebuild can drop without penalty (default 5).
|
|
308
|
+
- `defaults.readiness_weights` / `readiness_caps` / `static_gate_zero_at`: weights and caps of the KPI.
|
|
309
|
+
- `defaults.execution_policy`: phase-level routing metadata (`method`, `tier`, `model`, `effort`) shown by `execution-policy` and Mirador. It guides the operator; it does **not** affect readiness.
|
|
310
|
+
- Discovery intake commands (`production-finding`, `spec-doubt`, `spec-change-request`) persist post-merge production facts, SPEC doubts, and human contract-change bridges so the next cycle reopens discovery/SPEC instead of hiding reality in narration.
|
|
311
|
+
- ADRs may use `Status: Experiment` when a decision is an explicit, measured hypothesis. `dashboard --json`/Mirador expose `adr_status`, feedback/review metadata, malformed/expired counts; this is advisory visibility, not readiness scoring.
|
|
312
|
+
- `defaults.max_iterations`, `tools_per_cycle`, test commands.
|
|
313
|
+
|
|
314
|
+
## Multi-repo: mounting the other repos
|
|
315
|
+
|
|
316
|
+
The skill runs from the primary repo; the others are mounted in the session:
|
|
317
|
+
|
|
318
|
+
```bash
|
|
319
|
+
cd <repo-primario>
|
|
320
|
+
claude --add-dir ../backend-api --add-dir ../mobile-app
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
(or `additionalDirectories` in `.claude/settings.json`).
|
|
324
|
+
|
|
325
|
+
## Use
|
|
326
|
+
|
|
327
|
+
Inside Claude Code, invoke the orchestrator (with the ADR/PLAN ready or ask it for one):
|
|
328
|
+
|
|
329
|
+
```
|
|
330
|
+
/dev-loop
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
The skill handles the phases on its own: plan → coverage gate → (characterization if needed)
|
|
334
|
+
→ build → per-repo QA loop → integration → verify → PR (stops at the merge, you approve
|
|
335
|
+
it) → smoke list. It logs every step in `QA-LEDGER.json`. At the end:
|
|
336
|
+
|
|
337
|
+
```
|
|
338
|
+
/uscha-sysdoc # generates docs/system-deck.html (CEO + technical, navigable)
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
## Quick check (engine dry run, without the skill)
|
|
342
|
+
|
|
343
|
+
To confirm the engine parses your reports correctly BEFORE trusting it with the loop:
|
|
344
|
+
|
|
345
|
+
```bash
|
|
346
|
+
cd <repo-primario>
|
|
347
|
+
QL=".claude/skills/uscha-devloop/qa_ledger.py"
|
|
348
|
+
|
|
349
|
+
python3 $QL --help # see subcommands
|
|
350
|
+
python3 $QL init --config uscha.config.json # creates QA-LEDGER.json
|
|
351
|
+
|
|
352
|
+
# run your build with the reports, then:
|
|
353
|
+
python3 $QL snapshot --repo backend-api --phase pre
|
|
354
|
+
python3 $QL check-coverage --repo backend-api # exit 0 = OK, 1 = below threshold
|
|
355
|
+
python3 $QL ingest-gate --repo backend-api --iteration 1
|
|
356
|
+
python3 $QL summary # human summary
|
|
357
|
+
python3 $QL summary --json # includes post_merge_calibration
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
If `snapshot`/`ingest-gate` say "no report found", it's because the build hasn't generated
|
|
361
|
+
the XML yet — run `mvn test` with the plugins active first.
|
|
362
|
+
|
|
363
|
+
## Readiness KPI (when finishing any task)
|
|
364
|
+
|
|
365
|
+
Shows the "ready for release" status as a 0..100 score, **based on the state of the
|
|
366
|
+
result, not on effort spent**:
|
|
367
|
+
|
|
368
|
+
```bash
|
|
369
|
+
python3 $QL readiness --acceptance ACCEPTANCE.md
|
|
370
|
+
python3 $QL readiness --json # consumed by sys-doc (traffic-light widget)
|
|
371
|
+
python3 $QL execution-policy --phase qa # one-line methodology/model/effort routing
|
|
372
|
+
python3 $QL production-finding --repo backend-api --severity HIGH --title "..." --evidence "..."
|
|
373
|
+
python3 $QL spec-doubt --repo backend-api --kind spec-wrong --note "..." --evidence "..."
|
|
374
|
+
python3 $QL spec-change-request --repo backend-api --source SD-001 --requested-change "..." --evidence "..."
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
- Dimensions/weights: **acceptance traced (MEASURED) 30**, ADR/checkboxes 15, coverage 15,
|
|
378
|
+
static gate 20, convergence 10, integration 10. The **ADR completion** comes from your
|
|
379
|
+
acceptance task list (checkboxes `- [x]`/`- [ ]`, read-only) — count the whole file
|
|
380
|
+
(CLI default); `--section` only if you verified that the heading matches
|
|
381
|
+
exactly (a mismatch silently zeroes the dimension).
|
|
382
|
+
- **Traceability (kit 1.10.0, the dominant dimension)**: each criterion carries a stable ID
|
|
383
|
+
— `- [ ] AC-01 — when X then Y`. A criterion closes MEASURED only when there exists
|
|
384
|
+
≥1 GREEN testcase with its tag in the name (`test_ac1_x` / `testAC01X` / `"AC-01: ..."`
|
|
385
|
+
— normalized by number: `AC-01 == AC_1 == ac1`) in the already-ingested JUnit reports,
|
|
386
|
+
and no tagged testcase in red. The checkbox is NARRATIVE; the testcase is FACT: an
|
|
387
|
+
`[x]` without a green test appears as `narrated_only` and does NOT close. Anti-Goodhart: the agent
|
|
388
|
+
can no longer raise the KPI by polishing coverage — only by closing criteria with named
|
|
389
|
+
tests. `spec-check --acceptance ACCEPTANCE.md` validates the structure as a FACT (zero
|
|
390
|
+
traceable criteria or duplicate IDs = BLOCKED). Without IDs: it falls back to the checkbox ratio
|
|
391
|
+
with a warning (legacy, incremental adoption). Flutter doesn't emit JUnit: its criteria don't
|
|
392
|
+
close measured (documented limitation).
|
|
393
|
+
- A lintable repo whose static gate **never ran** scores that dimension UNMEASURED (0.0)
|
|
394
|
+
— silence is not success.
|
|
395
|
+
- **Hard caps** (they override the ceiling): tests in red → ≤35, open BLOCKER/CRITICAL → ≤65,
|
|
396
|
+
unresolved escalation → ≤75 (holds until `resolve-escalation`, a recorded event).
|
|
397
|
+
- Bands: `<50 NOT READY` · `50–79 IN PROGRESS` · `80–94 RELEASE CANDIDATE` · `95–100 READY`.
|
|
398
|
+
- Multi-repo: per-repo and aggregate (min() for blockers, LOC-weighted for quality).
|
|
399
|
+
- Cycles/regressions are **churn** (process health), reported separately and never
|
|
400
|
+
raise readiness.
|
|
401
|
+
|
|
402
|
+
## Rebuild test (SPEC completeness)
|
|
403
|
+
|
|
404
|
+
A different question for the ledger: not "did this build pass?" (correctness) but "is the SPEC
|
|
405
|
+
enough to regenerate the system?" (completeness). For profiles C+/E or periodic in CI.
|
|
406
|
+
|
|
407
|
+
```bash
|
|
408
|
+
# 1) in the ORIGINAL tree: capture the signature the rebuild must match
|
|
409
|
+
python3 $QL rebuild --mode baseline --config uscha.config.json # → REBUILD-BASELINE.json
|
|
410
|
+
# 2) in a CLEAN tree / new session: regenerate ONLY the production code from
|
|
411
|
+
# SPEC/ADR/ACCEPTANCE, PRESERVING the tests, and run the suite.
|
|
412
|
+
# 3) score the regenerated tree against the baseline
|
|
413
|
+
python3 $QL rebuild --mode compare --baseline REBUILD-BASELINE.json # exit 0 = COVERS
|
|
414
|
+
python3 $QL rebuild --mode compare --baseline REBUILD-BASELINE.json --json # consumed by sys-doc
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
- Dimensions/weights: tests 60, acceptance 20, coverage 15, surface 5. The dominant signal
|
|
418
|
+
is the **preserved suite**: a test that passed and fails in the regenerated code = behavior
|
|
419
|
+
the SPEC left implicit.
|
|
420
|
+
- Verdicts: `COVERS ≥90` · `PARTIAL ≥70` · `DIVERGE <70`. The score lists the concrete
|
|
421
|
+
**gaps** — feed them back into the SPEC and re-run. Divergence is a spec hole, not a code bug.
|
|
422
|
+
|
|
423
|
+
## Simplicity gate — "Reduce" (minimality of the change)
|
|
424
|
+
|
|
425
|
+
The **Simplicity** invariant of the CONSTITUTION made a deterministic gate: it scores the *diff*
|
|
426
|
+
(not CC by AST — they are measurable proxies: minimality, nesting, new abstractions).
|
|
427
|
+
|
|
428
|
+
```bash
|
|
429
|
+
git diff --unified=0 <base> | python3 $QL simplicity-check --config uscha.config.json
|
|
430
|
+
python3 $QL simplicity-check --from-git --base main # uses git for you
|
|
431
|
+
python3 $QL simplicity-check --diff changes.diff --json # consumed by sys-doc / CI
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
- Dimensions/weights: diff_size 35, nesting 30, net_growth 20, fan_out 8, blob 7
|
|
435
|
+
(abstraction does NOT weigh in the score — it's a guessy proxy, kept as a metric + advisory flag).
|
|
436
|
+
- Verdicts: `SIMPLE ≥85` · `ACCEPTABLE ≥65` · `OVERBUILT <65` (exit 1 = BLOCKER: trim and re-run).
|
|
437
|
+
A gross excess (2× budget, or very deep nesting) caps the score at 60 no matter what.
|
|
438
|
+
- **Tests OUT of the budget** (kit 1.11.0): the test files (conventions of the
|
|
439
|
+
9 stacks) are counted and reported separately (`test_lines_added`) but do not gate — writing
|
|
440
|
+
tests never pushes the diff to OVERBUILT (deleting them is already blocked by gate-check).
|
|
441
|
+
- The flags tell you what to trim (guard clauses, speculative types/layers, giant hunks).
|
|
442
|
+
- Budgets in `defaults.simplicity`; adjustable per risk profile. 2-space → `--indent-width 2`.
|
|
443
|
+
|
|
444
|
+
## Ledger subcommands
|
|
445
|
+
|
|
446
|
+
`doctor · init · snapshot · check-coverage · log-step · ingest-gate · log-gate · flag-blocker ·
|
|
447
|
+
converged · oscillation · escalate · resolve-escalation · summary · readiness · execution-policy · production-finding · spec-doubt · rebuild ·
|
|
448
|
+
simplicity-check · pit-check · gate-check · spec-check · golden-diff · regression-check ·
|
|
449
|
+
phase · rubric-ingest · doctor` — each with `--help`.
|
|
450
|
+
|
|
451
|
+
The **fact gates** (golden-diff, gate-check, pit-check, simplicity) are PERSISTED with
|
|
452
|
+
`log-gate`: a fail blocks convergence and caps readiness ≤65 via the ledger. A CONSTITUTION
|
|
453
|
+
violation is recorded with `flag-blocker` (same effect, until `--resolve`).
|
|
454
|
+
|
|
455
|
+
## Notes
|
|
456
|
+
|
|
457
|
+
- **It doesn't merge on its own.** It creates the PR and stops; the merge is yours.
|
|
458
|
+
- **ADR experiments are visible hypotheses.** `Status: Experiment` requires Hypothesis, Feedback Signal, Review By/Trigger, Promote Criteria and Rollback/Supersede Criteria. Missing or expired metadata is shown by `dashboard --json`/Mirador as advisory, not as a hard PR gate.
|
|
459
|
+
- **Tracked `.md` protocol.** Before touching CLAUDE.md / plan/delta docs / docs/adr,
|
|
460
|
+
the skill asks for the current version of the file (it doesn't regenerate and overwrite real progress).
|
|
461
|
+
- `ingest-gate` credits a fix only if the report EXISTS and came back clean; a missing
|
|
462
|
+
report = the gate didn't run (it doesn't invent zeros).
|
|
463
|
+
|
|
464
|
+
## Setting up the workbench (generic setup)
|
|
465
|
+
|
|
466
|
+
Before using the skills you need the base toolchain (Claude Code + Python + git/gh +
|
|
467
|
+
the skills installed). It's all in **`WORKBENCH.md`**: installation, verification and
|
|
468
|
+
update, without the specifics of each stack (Java/MSSQL/linters = per-repo adapter).
|
|
469
|
+
|
|
470
|
+
- What I have installed: `bash workbench-doctor.sh`
|
|
471
|
+
- Kit version: `python uscha-kit/install-uscha.py version` or `cat VERSION`
|
|
472
|
+
|
|
473
|
+
## Templates for the repo (so the repo becomes "methodology-ready")
|
|
474
|
+
|
|
475
|
+
The kit installs the skills; these templates leave the **repo** ready. Copy them to the root
|
|
476
|
+
of the repo where you're going to work:
|
|
477
|
+
|
|
478
|
+
```
|
|
479
|
+
cp uscha-kit/templates/CLAUDE.md <repo>/CLAUDE.md # permanent repo protocol
|
|
480
|
+
cp uscha-kit/templates/CONSTITUTION.md <repo>/CONSTITUTION.md # inviolable invariants (fill in the domain)
|
|
481
|
+
cp -r uscha-kit/templates/docs <repo>/docs # docs/adr scaffold
|
|
482
|
+
# if you use other agents besides Claude Code: cp <repo>/CLAUDE.md <repo>/AGENTS.md
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
Then, complete the "Project adapter" block of the `CLAUDE.md` with the build/test/gate
|
|
486
|
+
commands of that stack (it's the only project-specific thing).
|
|
487
|
+
|
|
488
|
+
## Verify the agent reads the kit
|
|
489
|
+
|
|
490
|
+
Inside Claude Code, ask it:
|
|
491
|
+
|
|
492
|
+
```
|
|
493
|
+
List the active rules from CLAUDE.md and the available skills.
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
The protocol rules and the commands /uscha-discovery /uscha-adr-refine
|
|
497
|
+
/uscha-devloop /uscha-sysdoc should appear. (For the machine's toolchain: `bash uscha-kit/workbench-doctor.sh`.)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
uscha-kit 1.40.1
|