@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,490 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: uscha-devloop
|
|
3
|
+
description: >
|
|
4
|
+
Spec-driven, multi-repo development + QA orchestrator. Plans from an ADR, builds,
|
|
5
|
+
then runs a severity-gated review loop (code-review / judgment-day / improve) that
|
|
6
|
+
converges instead of looping forever, with tests as a guardrail between passes.
|
|
7
|
+
Auto-triggers characterization tests when JaCoCo line coverage is below threshold.
|
|
8
|
+
Records every step in a deterministic ledger and stops at the merge gate for human
|
|
9
|
+
approval. Invoke for "run the dev loop", "QA this feature", "do the full cycle".
|
|
10
|
+
allowed-tools: Read, Edit, Write, Glob, Grep, Bash
|
|
11
|
+
disable-model-invocation: false
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# dev-loop orchestrator
|
|
15
|
+
|
|
16
|
+
**Who this is for:** a single operator driving one non-trivial or risk-bearing change,
|
|
17
|
+
kept honest by a deterministic ledger and a human merge gate. **NOT for trivial or
|
|
18
|
+
throwaway work** — a one-file fix or config tweak runs build+test only and skips
|
|
19
|
+
discovery/ADR/uscha-sysdoc entirely (see the risk-profile table in the playbook, play 03).
|
|
20
|
+
|
|
21
|
+
You are running a disciplined development + QA cycle across one or more repositories.
|
|
22
|
+
The measurement engine is `./.claude/skills/uscha-devloop/qa_ledger.py` per project, or the installed Codex/Claude global engine (stdlib Python 3).
|
|
23
|
+
**All metrics come from the ledger — never estimate counts from memory.** Run every
|
|
24
|
+
QA tool through the ledger so the final retrospective is real. The ledger contract has
|
|
25
|
+
two tiers: **measured** records (snapshots, ingest-gate, log-gate — parsed from real
|
|
26
|
+
artifacts; these can block) and **self-reported** agent counts (log-step — narration
|
|
27
|
+
recorded for the retrospective; a measured red always overrides a narrated green).
|
|
28
|
+
|
|
29
|
+
## Non-negotiable principles
|
|
30
|
+
|
|
31
|
+
1. **Converge, don't chase zero.** Block only on findings at or above the severity
|
|
32
|
+
gate (`config.defaults.severity_gate`, default BLOCKER/CRITICAL/HIGH). Everything
|
|
33
|
+
below goes to `ISSUES-DEFERRED.md`, never into the loop. Polishing Medium/Low
|
|
34
|
+
findings forever is the failure mode this skill exists to prevent.
|
|
35
|
+
2. **Tests are a guardrail, not a finale.** Run the repo's test command (`mvn test` /
|
|
36
|
+
`flutter test` / `pytest` / `npm test` / `go test` / `cargo test` / `dotnet test` / `ctest` / `./gradlew test` / `swift test`) after every tool pass that changed code. A red suite
|
|
37
|
+
stops the loop.
|
|
38
|
+
3. **Generating tests is not running tests.** `/improve test` (writing coverage) runs
|
|
39
|
+
ONCE at the end against stabilized code — never inside the loop. Inside the loop you
|
|
40
|
+
only *run* the existing suite.
|
|
41
|
+
4. **Stop at merge.** You create the PR and confirm CI is green. You do NOT merge.
|
|
42
|
+
The human owns the merge gate.
|
|
43
|
+
5. **Tracked-markdown protocol.** Before modifying any tracked `.md`
|
|
44
|
+
(CLAUDE.md, plan/delta docs, docs/adr), ask the human for the current version first.
|
|
45
|
+
Those files carry real progress (checkboxes, notes); never regenerate from scratch.
|
|
46
|
+
6. **The golden is the one artifact you cannot author.** For migration/legacy work,
|
|
47
|
+
`.approved` fixtures are field truth captured from the ORIGINAL code and approved by
|
|
48
|
+
a HUMAN. You emit `.received` and stop; you never write, edit or rename `.approved`
|
|
49
|
+
(a `PreToolUse` hook denies the write — INV-GOLDEN-01).
|
|
50
|
+
|
|
51
|
+
## Setup (once per run)
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
QL="./.claude/skills/uscha-devloop/qa_ledger.py" # instalacion por proyecto
|
|
55
|
+
[ -f "$QL" ] || QL="$HOME/.codex/skills/uscha-devloop/qa_ledger.py" # Codex raw-skills install
|
|
56
|
+
[ -f "$QL" ] || QL="$HOME/plugins/uscha/skills/uscha-devloop/qa_ledger.py" # Codex plugin install
|
|
57
|
+
[ -f "$QL" ] || QL="$HOME/.claude/skills/uscha-devloop/qa_ledger.py" # Claude global install
|
|
58
|
+
python3 $QL init --config uscha.config.json
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Execution policy line (before every phase)
|
|
62
|
+
|
|
63
|
+
Before you start a phase, print the one-line routing note from the ledger, then do the
|
|
64
|
+
work. This tells the human what the methodology is doing and which model/effort policy is
|
|
65
|
+
selected for that phase:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
python3 $QL execution-policy --phase <idea|disc|spec|adr|build|qa|verify|prod>
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
This is **routing metadata only**: it may guide the operator/adapter to use a stronger or
|
|
72
|
+
uncorrelated checker, but it never changes readiness and never overrides fact gates. If
|
|
73
|
+
`model=default`, keep the current agent model; if a phase declares a model/effort and the
|
|
74
|
+
host supports switching, use it for that phase.
|
|
75
|
+
|
|
76
|
+
### Discovery intake: reality can reopen the contract
|
|
77
|
+
|
|
78
|
+
Three facts are allowed to push work back into discovery/SPEC instead of being buried as narration:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
python3 $QL production-finding --repo <REPO> --severity HIGH \
|
|
82
|
+
--source <sentry|support|user|prod-log> --title "..." --evidence "..."
|
|
83
|
+
python3 $QL spec-doubt --repo <REPO> --kind spec-wrong \
|
|
84
|
+
--note "why the SPEC/AC seems wrong" --evidence "demo/log/file pointer"
|
|
85
|
+
python3 $QL spec-change-request --repo <REPO> --source SD-001 \
|
|
86
|
+
--requested-change "what must change in SPEC/ADR" --evidence "demo/log/file pointer"
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
- `production-finding` is for post-merge/prod feedback. It feeds the next discovery/SPEC cycle.
|
|
90
|
+
- `spec-doubt` is the builder's escape hatch when the SPEC conflicts with reality. Do **not** code around a doubtful SPEC silently; log it and ask the human.
|
|
91
|
+
- `spec-change-request` is the structured bridge from evidence/doubt to a human-approved SPEC/ADR amendment; an open SCR keeps the phase escalated.
|
|
92
|
+
- Resolve them only after the feedback was incorporated, explicitly reviewed, or the SPEC/ADR amendment decision was recorded:
|
|
93
|
+
`production-finding --id PF-001 --resolve --note "fed into SPEC"` / `spec-doubt --id SD-001 --resolve --decision "SPEC amended"` / `spec-change-request --id SCR-001 --resolve --decision accepted --amended ACCEPTANCE.md`.
|
|
94
|
+
|
|
95
|
+
The config lists every repo and its type (maven|flutter|python|node|go|rust|dotnet|cpp|gradle|swift). In a multi-repo session the
|
|
96
|
+
other repos must be mounted via `--add-dir` or `additionalDirectories`; the `path`
|
|
97
|
+
fields in the config are relative to where you run `init`.
|
|
98
|
+
|
|
99
|
+
For migration/legacy (risk profile E) work, also wire the golden invariant once:
|
|
100
|
+
install `hooks/block-approved-writes.ps1` (or its bash twin) as a `PreToolUse` hook in
|
|
101
|
+
`settings.json`, and add `*.approved.* binary` to `.gitattributes` (ships in
|
|
102
|
+
`templates/.gitattributes`) so line endings can't lie in the byte-compare.
|
|
103
|
+
|
|
104
|
+
## Phase 0 — Plan (ADR-first)
|
|
105
|
+
|
|
106
|
+
- **Read `CONSTITUTION.md` first (if present).** It lists the project invariants no SPEC
|
|
107
|
+
or ADR may violate. A change that would breach an invariant is a BLOCKER — escalate, do
|
|
108
|
+
not work around it. The CONSTITUTION constrains the whole build.
|
|
109
|
+
- The ADR set + `ACCEPTANCE.md` are the input to this loop. They typically come from the
|
|
110
|
+
`uscha-adr-refine` skill (the front-half counterpart): `/uscha-adr-refine` → ADR set → `/uscha-devloop`.
|
|
111
|
+
- Confirm or write the ADR + PLAN. The plan must state **acceptance criteria** (the
|
|
112
|
+
`ACCEPTANCE.md` checkboxes) and the **severity gate / coverage threshold** up front.
|
|
113
|
+
The loop targets the plan, not "no issues". If acceptance criteria are missing, stop
|
|
114
|
+
and run `uscha-adr-refine` first (or ask the human).
|
|
115
|
+
- Acceptance criteria become the contract tests in Phase 1.
|
|
116
|
+
|
|
117
|
+
## Phase 1 — Coverage gate → conditional characterization (per repo)
|
|
118
|
+
|
|
119
|
+
For each repo, decide whether a safety net exists before any refactoring:
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
python3 $QL snapshot --repo <REPO> --phase pre
|
|
123
|
+
python3 $QL check-coverage --repo <REPO> # exit 0 = OK, exit 1 = BELOW threshold
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
- **Coverage >= threshold:** the existing suite is the guardrail. Skip to Phase 2.
|
|
127
|
+
- **Coverage < threshold (or no report):** write **characterization / contract tests
|
|
128
|
+
at the boundary** (public API, endpoints, input→output behavior) — NOT internals.
|
|
129
|
+
These must survive refactoring. The ADR acceptance criteria are the spec for these.
|
|
130
|
+
**Have the human review these tests before trusting them as a gate** — a test that
|
|
131
|
+
passes for the wrong reason poisons the whole loop.
|
|
132
|
+
- **Migration/legacy (profile E): capture the golden BEFORE touching anything.** Run
|
|
133
|
+
the `uscha-characterize` skill (or `uscha-reverse-discovery` for a whole-system map first): it
|
|
134
|
+
executes the ORIGINAL code against a real input corpus, emits `.received` fixtures,
|
|
135
|
+
and STOPS for the human to approve them as `.approved`. No approved golden = no
|
|
136
|
+
migration build. This is the baseline `golden-diff` gates against in Phase 3.
|
|
137
|
+
|
|
138
|
+
## Phase 2 — Build
|
|
139
|
+
|
|
140
|
+
Implement per the PLAN. Commit per logical step with conventional commits
|
|
141
|
+
(`feat:`, `fix:`, `refactor:`…) so the trail is reviewable and revertible.
|
|
142
|
+
|
|
143
|
+
### ADR discipline during build
|
|
144
|
+
|
|
145
|
+
- **Consult before touching governed areas.** Before working on an area covered by an
|
|
146
|
+
accepted ADR, read it and follow its Implementation Plan (affected paths, patterns,
|
|
147
|
+
tests). Also re-check `CONSTITUTION.md`: if the change would breach an invariant, stop
|
|
148
|
+
and escalate — a constitution breach is a BLOCKER and is never resolved silently in code.
|
|
149
|
+
If the code contradicts the ADR, flag it to the human — never resolve the conflict
|
|
150
|
+
silently in code.
|
|
151
|
+
- **Proactive ADR triggers — stop and propose an ADR** when you are about to: introduce
|
|
152
|
+
a new dependency, create a new architectural pattern others must follow, choose between
|
|
153
|
+
real alternatives with non-obvious trade-offs, or contradict an accepted ADR. Tell the
|
|
154
|
+
human the decision, why it matters, and ask whether to capture it. If no, leave a short
|
|
155
|
+
`// ADR-not-taken: <why>` comment and move on.
|
|
156
|
+
- **Link code ↔ ADR.** When implementing a decision, add one lightweight comment at the
|
|
157
|
+
entry point: `// ADR: <slug> — see docs/adr/ADR-NNN-<slug>.md`. This makes supersede
|
|
158
|
+
safe (you can find all code an ADR governs).
|
|
159
|
+
- **Treat `Status: Experiment` as a visible hypothesis, not a license to improvise.** It
|
|
160
|
+
may proceed only when the ADR declares Hypothesis, Feedback Signal, Review By/Trigger,
|
|
161
|
+
Promote Criteria and Rollback/Supersede Criteria. `dashboard --json`/Mirador expose
|
|
162
|
+
malformed or expired experiment metadata as advisory; it is not a readiness score and
|
|
163
|
+
not a hard PR gate by itself.
|
|
164
|
+
- **Never edit the SPEC/ADR to make the implementation look correct.** If reality forces
|
|
165
|
+
a change, amend the SPEC (version it) and return to Ready.
|
|
166
|
+
|
|
167
|
+
## Phase 2b — Simplicity gate ("Reduce")
|
|
168
|
+
|
|
169
|
+
Before the QA loop, check the change isn't overbuilt. This is the CONSTITUTION's
|
|
170
|
+
**Simplicidad** invariant made deterministic — diff minimality, nesting depth and new
|
|
171
|
+
abstractions, scored over the diff (not AST cyclomatic complexity; honest proxies):
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
git diff --unified=0 <base> | python3 $QL simplicity-check --config uscha.config.json
|
|
175
|
+
# or: python3 $QL simplicity-check --from-git --base <base>
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Reads `SIMPLICITY: NN/100 — SIMPLE | ACCEPTABLE | OVERBUILT`. **OVERBUILT (exit 1) is a
|
|
179
|
+
BLOCKER**: reduce first (guard clauses, drop speculative types/layers, split giant hunks)
|
|
180
|
+
and re-run — do not carry it into the QA loop or converge on it. The flags tell you exactly
|
|
181
|
+
what to cut. Budgets live in `config.defaults.simplicity` (tighten per risk profile). For a
|
|
182
|
+
2-space codebase pass `--indent-width 2`.
|
|
183
|
+
|
|
184
|
+
**Tests are OUTSIDE the budget** (kit 1.11.0): test files (the 9 stack conventions) are
|
|
185
|
+
counted and reported apart (`test_lines_added`) but never gate — writing tests must not
|
|
186
|
+
push a diff toward OVERBUILT (deleting them is already blocked by gate-check). A good
|
|
187
|
+
project can have MORE test code than production code.
|
|
188
|
+
|
|
189
|
+
**Persist the verdict** so convergence and readiness see it (facts block through the
|
|
190
|
+
ledger, not through your goodwill):
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
python3 $QL log-gate --repo <REPO> --iteration <N> --kind simplicity \
|
|
194
|
+
--verdict <pass|fail> [--note "OVERBUILT: +612 lines vs 400 budget"]
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Phase 2c — REUSE-FIRST gate (kit 1.26.0)
|
|
198
|
+
|
|
199
|
+
Simplicity scores the diff in ISOLATION; it cannot see that the new block re-implements
|
|
200
|
+
something the repo already has. `waste-check` closes that gap — deterministic Type-1/2
|
|
201
|
+
clone detection of the diff **vs the repo** (the muda GitClear calls dominant in AI code):
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
python3 $QL waste-check --from-git --base <base> --repo-root . --config uscha.config.json
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Reads `WASTE: NN/100 — LEAN | ACCEPTABLE | WASTEFUL`. **Advisory by default** (exit 0): the
|
|
208
|
+
flags name the existing `file:line` to reuse instead of cloning. It reports a FACT (the block
|
|
209
|
+
exists elsewhere) but "wasteful" is a heuristic with false positives (boilerplate, DTOs,
|
|
210
|
+
embedded SQL/JSON), so it does NOT block unless the human declares it — `defaults.waste.gate:
|
|
211
|
+
true` or `--gate`. When gated and WASTEFUL, reuse/refactor before the QA loop and persist:
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
python3 $QL log-gate --repo <REPO> --iteration <N> --kind waste \
|
|
215
|
+
--verdict <pass|fail> [--note "clona util/money.py:40 — reusar"]
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
It runs on **prod code only** (tests excluded, like simplicity) and skips the files the diff
|
|
219
|
+
touches (no self-match). Honest scope: Type-1/2 over normalized lines, not semantic clones;
|
|
220
|
+
tune `defaults.waste` (`allow_paths` for legit boilerplate, `window_size`, budgets). In risk
|
|
221
|
+
profile A (trivial change) skip it. It **collapses into `readiness`** as a `gate:waste` line.
|
|
222
|
+
|
|
223
|
+
## Phase 3 — QA loop (per repo)
|
|
224
|
+
|
|
225
|
+
Run the tools in `config.defaults.qa_tools_order` (default: code-review → judgment-day
|
|
226
|
+
→ improve). One pass of all tools = one cycle. After **each** tool pass:
|
|
227
|
+
|
|
228
|
+
1. Apply only fixes at/above the severity gate. Send the rest to `ISSUES-DEFERRED.md`.
|
|
229
|
+
2. Run the repo test command. If red and the fix isn't obvious → escalate.
|
|
230
|
+
3. Log the agent QA tools (code-review / judgment-day / improve) with `log-step`,
|
|
231
|
+
using counts from each tool's own summary. These counts are **self-reported
|
|
232
|
+
narration** (recorded for churn/retrospective); the blocking signals in this loop
|
|
233
|
+
are the MEASURED records — ingest-gate, log-gate, snapshots:
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
python3 $QL log-step --repo <REPO> --tool <code-review|judgment-day|improve> \
|
|
237
|
+
--iteration <N> \
|
|
238
|
+
--reported <total findings> --gated-reported <findings at/above gate> \
|
|
239
|
+
--fixed <fixed this pass> --deferred <sent to backlog> --suppressed <false positives> \
|
|
240
|
+
--tests-passed <true|false> --files-changed <count> \
|
|
241
|
+
--fingerprint <stable,finding,ids> # enables oscillation detection
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
3b. **Fact gates — on every pass that changed code**, run gate-check (did the change
|
|
245
|
+
weaken the measuring apparatus? did it ADD a secret? — private keys, cloud tokens and
|
|
246
|
+
key-container files block as facts, kit 1.12.0; generic password/token literals advise;
|
|
247
|
+
new dependencies advise too — the change-budget rule "no new deps without approval" made
|
|
248
|
+
visible, kit 1.30.0)
|
|
249
|
+
and, for migration work, golden-diff (does behavior still match the human-approved
|
|
250
|
+
baseline?). Then PERSIST each verdict with `log-gate` — a failing fact gate blocks
|
|
251
|
+
convergence and caps readiness ≤65 through the ledger:
|
|
252
|
+
|
|
253
|
+
**Rubric — the non-testable layer (kit 1.23.0).** If a `RUBRIC.md` exists (or
|
|
254
|
+
`defaults.rubric.file` declares one), on passes that changed code run the
|
|
255
|
+
`uscha-rubric` grade (isolated context — the grader reads ONLY diff + rubric;
|
|
256
|
+
evidence-or-nothing) and ingest the contract JSON:
|
|
257
|
+
`rubric-ingest --repo <REPO> --report reports/rubric-grade.json --iteration <N>`.
|
|
258
|
+
Advisory by default — it gates ONLY when the human declared
|
|
259
|
+
`defaults.rubric.gate: true` (then a below-threshold score blocks convergence like
|
|
260
|
+
any fact gate). Never declare the gate yourself.
|
|
261
|
+
|
|
262
|
+
**Find Bugs Once (kit 1.16.0).** When a pass you log carries `--fixed > 0`, run
|
|
263
|
+
`regression-check --repo <REPO> --from-git --base <base>`: closing findings without
|
|
264
|
+
adding a single NON-BLANK test-tree line is **NARRATED** closure — the failing test
|
|
265
|
+
goes BEFORE the fix (Tip 31), and every bug is found ONCE (Tip 94). It is a tripwire,
|
|
266
|
+
not a judge: any non-blank test line counts (even a comment — content across 9 stacks
|
|
267
|
+
is not guessed), so honor the `has_test_definition`/`has_assertion` facts and the
|
|
268
|
+
"evidencia DÉBIL" warning; test QUALITY is pit-check's job. NARRATED advises by
|
|
269
|
+
default; persist `log-gate --kind regression --verdict fail` if the team gates it.
|
|
270
|
+
Resolving a `flag-blocker` now REQUIRES `--escape-analysis "<which gate/test should
|
|
271
|
+
have caught this and what was done>"` — reflection is part of closing, not optional.
|
|
272
|
+
|
|
273
|
+
```bash
|
|
274
|
+
python3 $QL gate-check --from-git --base <base> --repo <REPO> # exit 1 = BLOCKER
|
|
275
|
+
python3 $QL log-gate --repo <REPO> --iteration <N> --kind gate-check --verdict <pass|fail>
|
|
276
|
+
|
|
277
|
+
python3 $QL golden-diff [--dir <fixtures-root>] # exit 0 CLEAN · 1 DIVERGE · 2 NOT-RUN
|
|
278
|
+
python3 $QL log-gate --repo <REPO> --iteration <N> --kind golden-diff \
|
|
279
|
+
--verdict <pass|fail|not-run> # not-run records the absence — it is never green
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
(pit-check stays on its scheduled/incremental tier — CONSTITUTION §Tests efectivos —
|
|
283
|
+
but when a PIT report EXISTS and fails the gate, persist it the same way:
|
|
284
|
+
`log-gate --kind pit-check --verdict fail`.)
|
|
285
|
+
|
|
286
|
+
4. The **static analysis gate** (`java-qa-gate`: Checkstyle/PMD/SpotBugs/FindSecBugs)
|
|
287
|
+
is NOT counted by hand. Run the gate so its XML reports are written, then ingest
|
|
288
|
+
them — the ledger parses the reports, normalizes severities to the common gate
|
|
289
|
+
scale, splits FindSecBugs (SECURITY) out from SpotBugs, and computes the real
|
|
290
|
+
`fixed` count by diffing finding-IDs against the previous run:
|
|
291
|
+
|
|
292
|
+
```bash
|
|
293
|
+
# run your java-qa-gate first (it must emit:
|
|
294
|
+
# target/checkstyle-result.xml, target/pmd.xml, target/spotbugsXml.xml)
|
|
295
|
+
python3 $QL ingest-gate --repo <REPO> --iteration <N>
|
|
296
|
+
# one static-gate step is logged per linter; pass --combined to merge into one.
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
Severity normalization: Checkstyle error→HIGH / warning→MEDIUM; PMD priority
|
|
300
|
+
1→BLOCKER … 5→LOW; SpotBugs priority 1→HIGH / 2→MEDIUM / 3→LOW; FindSecBugs
|
|
301
|
+
(category SECURITY) floored to HIGH. A report file that EXISTS but is empty credits the
|
|
302
|
+
fix; an ABSENT report is not treated as clean (means the gate didn't run).
|
|
303
|
+
|
|
304
|
+
**End-of-cycle checks (advisory — you make the final call):**
|
|
305
|
+
|
|
306
|
+
```bash
|
|
307
|
+
python3 $QL converged --repo <REPO> --tools-per-cycle <count> # exit 0 = converged
|
|
308
|
+
python3 $QL oscillation --repo <REPO> --tool <tool> # exit 1 = oscillating
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
Convergence requires ALL of: the latest agent step of EVERY tool in `qa_tools_order`
|
|
312
|
+
clean (zero gated findings, zero files changed, tests green — padding the window with
|
|
313
|
+
extra clean steps does not help, and a red snapshot vetoes a narrated green), AND the
|
|
314
|
+
latest static-gate run of every linter clean at the gate level, AND every persisted
|
|
315
|
+
fact gate (`gate:*`, `blocker:*` records from log-gate/flag-blocker) clean. A clean
|
|
316
|
+
agent cycle alone does not converge if any measured gate still flags something.
|
|
317
|
+
|
|
318
|
+
- **Converged** → leave the loop for this repo.
|
|
319
|
+
- **Not converged** → next cycle, up to `config.defaults.max_iterations`.
|
|
320
|
+
|
|
321
|
+
## Phase 4 — Integration / contract pass (multi-repo)
|
|
322
|
+
|
|
323
|
+
After each repo converges individually, run the cross-repo layer with all repos mounted.
|
|
324
|
+
Run the integration/contract test command from the config and treat contract breakages
|
|
325
|
+
as gated findings. Log under `--repo integration`. This is the second layer of your
|
|
326
|
+
two-layer QA architecture; per-repo green does not imply the seams are green.
|
|
327
|
+
|
|
328
|
+
## Phase 5 — Verify (coverage generation, once)
|
|
329
|
+
|
|
330
|
+
Now that code is stable:
|
|
331
|
+
|
|
332
|
+
```bash
|
|
333
|
+
# /improve test → write the fine-grained coverage you deferred earlier
|
|
334
|
+
# Then run the full suite and regenerate coverage reports.
|
|
335
|
+
python3 $QL snapshot --repo <REPO> --phase post # for every repo + integration
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
Full suite must be green and coverage at/above threshold before proceeding.
|
|
339
|
+
|
|
340
|
+
## Phase 5b — Rebuild test (optional; risk profile C+/E or periodic CI)
|
|
341
|
+
|
|
342
|
+
Completeness of the SPEC, not correctness of the build: is the spec package enough to
|
|
343
|
+
regenerate the system from scratch? Worth running for critical/legacy work or on a
|
|
344
|
+
schedule, not every feature.
|
|
345
|
+
|
|
346
|
+
```bash
|
|
347
|
+
# 1) capture the signature of the system as it stands now
|
|
348
|
+
python3 $QL rebuild --mode baseline --config uscha.config.json
|
|
349
|
+
# 2) in a CLEAN tree / fresh session, regenerate PRODUCTION code from SPEC/ADR/
|
|
350
|
+
# ACCEPTANCE only, PRESERVING the test suite, then run the tests.
|
|
351
|
+
# 3) score the regenerated tree against the baseline
|
|
352
|
+
python3 $QL rebuild --mode compare --baseline REBUILD-BASELINE.json # exit 0 = COVERS
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
The dominant signal is the preserved suite: tests that passed originally but fail on
|
|
356
|
+
regenerated code are behavior the SPEC left implicit. Verdicts: COVERS (≥90), PARTIAL
|
|
357
|
+
(≥70), DIVERGE (<70). Feed the listed gaps back into the SPEC, then re-run — divergence
|
|
358
|
+
is a spec gap, not a code bug.
|
|
359
|
+
|
|
360
|
+
## Phase 6 — PR (stop at merge)
|
|
361
|
+
|
|
362
|
+
- **Gate the PR on the DERIVED state (kit 1.18.0)** — per repo:
|
|
363
|
+
|
|
364
|
+
```bash
|
|
365
|
+
python3 $QL phase --repo <REPO> --require pr-ready # exit 1 = the facts say no
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
The state is COMPUTED from the ledger (converged + green tests + zero
|
|
369
|
+
BLOCKER/CRITICAL + no open escalation), never self-declared — if it exits 1, the
|
|
370
|
+
output lists exactly which facts are missing; do NOT open the PR, close the gap.
|
|
371
|
+
A `spike/*` branch NEVER passes this gate (kit 1.19.0): spike code is disposable
|
|
372
|
+
by contract — its only legitimate output is an ADR with lessons, never a merge.
|
|
373
|
+
- Ensure conventional-commit history is clean.
|
|
374
|
+
- Open the PR(s). Confirm CI is green.
|
|
375
|
+
- **STOP.** Present the PR link(s) and wait for the human to merge.
|
|
376
|
+
|
|
377
|
+
## Phase 7 — Smoke list
|
|
378
|
+
|
|
379
|
+
Produce a concrete manual smoke-test checklist (real user paths / endpoints / device
|
|
380
|
+
flows for this change), so the human can verify the system behaves as intended.
|
|
381
|
+
|
|
382
|
+
## Phase 8 — Hand off to docs + retrospective
|
|
383
|
+
|
|
384
|
+
```bash
|
|
385
|
+
python3 $QL summary # human-readable
|
|
386
|
+
python3 $QL summary --json # machine-readable, includes post_merge_calibration
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
**Readiness KPI — show this after finishing ANY task, not only full runs.** It measures
|
|
390
|
+
the STATE of the result (not effort spent), as a weighted score 0..100 with hard caps:
|
|
391
|
+
|
|
392
|
+
```bash
|
|
393
|
+
python3 $QL readiness --acceptance <ACCEPTANCE.md> --tools-per-cycle <count>
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
**Single-verdict view (kit 1.25.0, anti-ceremony).** By default `readiness` is ONE
|
|
397
|
+
screen: the verdict line, any conditional warning that actually fired (it speaks only
|
|
398
|
+
when it matters), and a `--- gates:` line that COLLAPSES every persisted gate record —
|
|
399
|
+
the per-language linter gates (`*-qa-gate` from `ingest-gate`) plus the discrete fact
|
|
400
|
+
gates (`gate:*` from `log-gate`, `rubric:grade`, `blocker:*` from `flag-blocker`) — into
|
|
401
|
+
`N ok / M bloqueando (repo/gate...)`. This
|
|
402
|
+
is presentation over facts already in the ledger — it never recomputes the score, so
|
|
403
|
+
the KPI is identical to before the rollup existed. When the acceptance file has traceable
|
|
404
|
+
AC-IDs, the default view also prints the honest **`acceptance medido: X%`** line (kit
|
|
405
|
+
1.28.0 — criteria closed by a green name-tagged test / total; the `measured_pct` field in
|
|
406
|
+
`--json`): the one "% done" the kit can sign, MEASURED not narrated, informational and
|
|
407
|
+
never a gate. With no AC-IDs it does not print (a % over bare checkboxes would be
|
|
408
|
+
narrated). Pass `--verbose` to expand the dimensions table, the acceptance/coverage/churn
|
|
409
|
+
summary and the per-repo breakdown.
|
|
410
|
+
Show the human the default; reach for `--verbose` only when they ask what is inside the
|
|
411
|
+
number.
|
|
412
|
+
|
|
413
|
+
Dimensions and default weights: acceptance (traced, MEASURED) 30, ADR/checkbox
|
|
414
|
+
completion 15, coverage 15, static gate 20, convergence 10, integration 10. A
|
|
415
|
+
lint-capable repo whose static gate NEVER ran scores that dimension UNMEASURED (0.0) —
|
|
416
|
+
silence is not success. Hard caps override the weighted score: tests red → ≤35,
|
|
417
|
+
BLOCKER/CRITICAL open → ≤65, unresolved escalation → ≤75 (held until
|
|
418
|
+
`resolve-escalation` — a recorded event, not an implication). A `CONSTITUTION.md`
|
|
419
|
+
breach does NOT reach the engine by itself: **you MUST log it** —
|
|
420
|
+
`flag-blocker --repo <REPO> --kind constitution --note "<invariant breached>"` — and
|
|
421
|
+
once logged it caps readiness ≤65 and blocks convergence until `--resolve`. Bands:
|
|
422
|
+
<50 NOT READY, 50–79 IN PROGRESS, 80–94 RELEASE CANDIDATE, 95–100 READY.
|
|
423
|
+
|
|
424
|
+
**Acceptance traceability (the DOMINANT dimension — kit 1.10.0).** Each ACCEPTANCE
|
|
425
|
+
criterion carries a stable ID: `- [ ] AC-01 — when X then Y`. A criterion counts as
|
|
426
|
+
CLOSED only when ≥1 GREEN testcase whose name carries the tag (`test_ac1_x`,
|
|
427
|
+
`testAC01X`, `"AC-01: ..."` — IDs normalize by number, `AC-01 == AC_1 == ac1`) exists
|
|
428
|
+
in the ingested JUnit reports AND no tagged testcase is red. The checkbox is the
|
|
429
|
+
NARRATIVE; the testcase is the FACT — a checked box without a green tagged test shows
|
|
430
|
+
up as `narrated_only` and does NOT close (measured beats narrated, per criterion).
|
|
431
|
+
A JUnit report older than the repo's source code is treated as STALE (the code changed
|
|
432
|
+
after the tests ran) and is DISCARDED — a criterion backed only by stale reports stays
|
|
433
|
+
UNMEASURED, never falsely closed or vetoed (kit 1.31.0; surfaced as `stale_reports`).
|
|
434
|
+
So: when you write the tests for a criterion, put its AC-n in the test name; run
|
|
435
|
+
`spec-check --acceptance ACCEPTANCE.md` up front (zero traceable criteria / duplicate
|
|
436
|
+
IDs block as structural FACTS). Files without IDs fall back to the checkbox ratio
|
|
437
|
+
with a warning (legacy mode — adopt incrementally).
|
|
438
|
+
|
|
439
|
+
**Heed the two readiness advisories (kit 1.14.0 — they recommend, never gate).**
|
|
440
|
+
`stall:` = gated findings flat or RISING for 3 agent cycles: more iteration is not
|
|
441
|
+
approaching the solution — stop iterating, go back to the ADR / re-plan WITH the human.
|
|
442
|
+
`stop-signal:` = every repo converged and zero blocking facts remain: what's left is
|
|
443
|
+
measurable debt (coverage/acceptance), not findings — raise "candidate to cut and go
|
|
444
|
+
to PR" to the human instead of polishing further.
|
|
445
|
+
|
|
446
|
+
ADR completion is parsed from the **acceptance task list** (markdown `- [x]`/`- [ ]`),
|
|
447
|
+
read-only — set the path via `config.defaults.acceptance_file` or `--acceptance`. Count
|
|
448
|
+
the WHOLE file (the CLI default); only pass `--section` if you have verified the heading
|
|
449
|
+
text matches your template exactly — a mismatched section silently zeroes a heavy
|
|
450
|
+
dimension. Present the single-verdict headline (the number, the capping blocker if any,
|
|
451
|
+
and the collapsed `--- gates:` line); add `--verbose` only if the human wants the
|
|
452
|
+
dimension breakdown behind the number. Cycles/regressions are churn (process health) and
|
|
453
|
+
are reported separately — they never raise readiness.
|
|
454
|
+
|
|
455
|
+
Optionally (on request — reporting, not part of the verified build) invoke the `uscha-sysdoc`
|
|
456
|
+
skill to generate the two-view HTML deck. Finish with a retrospective drawn FROM the
|
|
457
|
+
ledger summary: total steps, %fixed per tool, coverage, prod LOC vs test LOC, test
|
|
458
|
+
count, tests/kLOC, **first-time yield** (kit 1.27.0 — the Lean % of repos that cleared
|
|
459
|
+
QA on the first cycle with no second pass, regression or escalation; passive, derived
|
|
460
|
+
from the ledger, informational only — never a gate), plus concrete methodology
|
|
461
|
+
improvements.
|
|
462
|
+
|
|
463
|
+
## Escalation contract — STOP and ask the human when:
|
|
464
|
+
|
|
465
|
+
- The iteration cap is hit without convergence.
|
|
466
|
+
- Oscillation is detected (a finding set keeps returning).
|
|
467
|
+
- A previously-passing test now fails and the fix is non-trivial.
|
|
468
|
+
- Two tools give contradictory directives on the same code.
|
|
469
|
+
- A fix would require an architectural decision (ADR-level change).
|
|
470
|
+
- A change would breach the `CONSTITUTION.md` (an inviolable invariant) — never trade it
|
|
471
|
+
away; changing the constitution is a separate, explicit human decision.
|
|
472
|
+
|
|
473
|
+
Record every escalation, and record its CLOSURE — the readiness cap holds until the
|
|
474
|
+
human resolves it:
|
|
475
|
+
|
|
476
|
+
```bash
|
|
477
|
+
python3 $QL escalate --repo <REPO> --reason "<what blocked + what you need from me>"
|
|
478
|
+
# ... human reviews/decides ...
|
|
479
|
+
python3 $QL resolve-escalation --repo <REPO> --note "<how it was closed>"
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
A CONSTITUTION breach is escalated AND flagged as a first-class blocker:
|
|
483
|
+
|
|
484
|
+
```bash
|
|
485
|
+
python3 $QL flag-blocker --repo <REPO> --kind constitution --note "<invariant breached>"
|
|
486
|
+
# after the human decision: flag-blocker --repo <REPO> --kind constitution --resolve
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
Never auto-merge, never silently exceed the iteration cap, never fix below the gate to
|
|
490
|
+
make the number look better.
|