@andresmassello/uscha 1.63.0 → 1.65.0

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.
@@ -5,8 +5,10 @@ description: >
5
5
  inverse of discovery: the system already exists and its behavior IS the truth, so you
6
6
  EXTRACT facts instead of proposing shape. Produce ONLY facts — a system map (endpoints,
7
7
  contracts, dependency graph, module candidates via static analysis) and a golden suite
8
- captured mechanically at the boundaries. NEVER author an inferred SPEC or ADR of the old
9
- system; the human writes those reading your facts. Invoke for "reverse-discovery",
8
+ captured mechanically at the boundaries plus CANDIDATE specs in quarantine
9
+ (discovery/, evidence + confidence mandatory), which NEVER promote without a human
10
+ verdict in BEHAVIOR-LEDGER.md (ADR-009, INV-CURATION-01: the engine measures the gate).
11
+ Invoke for "reverse-discovery",
10
12
  "migrar/modernizar este sistema", "caracterizar el sistema viejo antes de tocarlo".
11
13
  allowed-tools: Read, Write, Glob, Grep, Bash
12
14
  disable-model-invocation: false
@@ -15,8 +17,9 @@ disable-model-invocation: false
15
17
  # reverse-discovery — extract the facts of an existing system before migrating it
16
18
 
17
19
  `uscha-discovery` is greenfield: you only have an idea, so you PROPOSE the shape. This is the
18
- opposite. The system already runs; its observable behavior is the ground truth. **You do
19
- not invent anything you characterize what is already there, as facts.**
20
+ opposite. The system already runs; its observable behavior is the ground truth. **Facts
21
+ first, alwaysand what cannot be fact yet becomes a CANDIDATE in quarantine: evidenced,
22
+ confidence-tagged, and promoted to the contract only by a human verdict (ADR-009).**
20
23
 
21
24
  ## First contact (show ONCE, then never again)
22
25
 
@@ -29,11 +32,11 @@ breadcrumb. Repeating it every run would be exactly the ceremony the method forb
29
32
  [uscha · reverse-discovery · START]
30
33
  Method: you bring the idea, the method builds the rest. Facts block, guesses advise;
31
34
  nothing closes on a checkbox, and the human approves the merge.
32
- Here: I EXTRACT facts from the system that already exists. I never invent its spec -- you write that reading my facts.
35
+ Here: I EXTRACT facts and CANDIDATES from the system that already exists. Candidates stay quarantined until YOUR verdict promotes them.
33
36
  Output: SYSTEM-MAP.md · DISCOVERY-SUMMARY.md -- endpoints, contracts, dependency graph,
34
- module candidates. Facts only: the SPEC and the ADRs are yours to write.
37
+ module candidates + discovery/ candidates + BEHAVIOR-LEDGER.md. The verdicts are yours.
35
38
  Next: `/uscha-characterize` freezes current behavior and a HUMAN approves the golden;
36
- only then do you write the migration SPEC, reading these facts + that golden.
39
+ only judged candidates reach the migration SPEC; the golden stays the oracle.
37
40
  Stop: say so at any point -- whatever is already written stays.
38
41
  ```
39
42
 
@@ -88,17 +91,30 @@ and say exactly what unblocks it.
88
91
  Keep the CONTENT in the conversation's language, but keep the labels (`CLOSED`, `Produced`,
89
92
  `Blocks`, `Next`, `Run`) verbatim — they are the method's vocabulary and the smoke checks them.
90
93
 
91
- ## The one non-negotiable: produce ONLY facts
94
+ ## The one non-negotiable: quarantine, not judgment (ADR-009)
92
95
 
93
96
  A system map (from static analysis) and a golden suite (byte-captured) are FACTS —
94
- verifiable, not opinions. **You do NOT author a SPEC of "what it does" or ADRs of "why it
95
- is built this way."** Those are inference, and if the agent writes them it encodes its own
96
- (mis)reading of the code — the exact blind spot the golden exists to counter. The golden
97
- is field truth; a SPEC the agent writes about legacy code is a claim. So this skill emits
98
- facts, and the human infers meaning from them.
99
-
100
- If you catch yourself writing a requirement or a rationale, stop: that belongs to the human
101
- (and to `/uscha-adr-refine` for the FORWARD decisions), not here.
97
+ verifiable, not opinions. What you read out of the code beyond that is a CLAIM, and an
98
+ LLM's claim about legacy code is plausible on the surface and divergent from reality
99
+ the exact blind spot the golden exists to counter. The old rule banned authoring such
100
+ claims outright; ADR-009 renegotiated it: **you may author them as CANDIDATES, in
101
+ quarantine, and you may NEVER judge or promote them.**
102
+
103
+ - Every candidate lives in `discovery/`, with mandatory frontmatter: `evidence.type`
104
+ (`test | code | inference`), `evidence.refs` (real `file:line(s)` — the engine resolves
105
+ them; a ref that does not resolve makes the candidate invalid, named), and `confidence`
106
+ (`inference` is ALWAYS `low`).
107
+ - **You capture; you do not judge.** Never decide whether a behavior is bug or feature —
108
+ that is the verdict (`preserve` / `fix` / `undefined`), it belongs to the human, and it
109
+ lands in `BEHAVIOR-LEDGER.md` with an ADR per verdict. You may present a candidate with
110
+ its evidence and ASK; you may write the skeleton row once the human decides; the verdict
111
+ itself is theirs.
112
+ - The gate is MEASURED, not promised: `qa_ledger.py curation-check` blocks the forward flow
113
+ while any candidate lacks a verdict (INV-CURATION-01) — and a malformed candidate or a
114
+ tampered ledger blocks harder (`exit 2`), because "could not validate" must never read
115
+ as judged.
116
+ - The ledger is append-only (verified against git): reverting a verdict is a NEW row plus a
117
+ new ADR, never an edit.
102
118
 
103
119
  ## Phase 1 — Map (fact)
104
120
 
@@ -127,7 +143,29 @@ Delegate to the `uscha-characterize` skill; if it is not installed, follow its c
127
143
  inputs of past bugs. A boundary whose corpus does not exercise its known branches is
128
144
  marked **PARTIAL**, never covered.
129
145
 
130
- ## Phase 3 — Summary (facts, no opinion)
146
+ ## Phase 3 — Candidates (claims, quarantined)
147
+
148
+ For every observable behavior the map + golden surface, emit one candidate file in
149
+ `discovery/` (`NNN-short-slug.md`): frontmatter per the section above, then a short
150
+ description of the behavior — what it does, not whether it should. Undesigned edge cases
151
+ are captured too, as `inference`/`low`. Then run:
152
+
153
+ ```bash
154
+ python qa_ledger.py curation-check --repo <name>
155
+ ```
156
+
157
+ Echo its output verbatim — it names invalid candidates and everything awaiting verdict.
158
+ The skill wires; the engine measures.
159
+
160
+ ## Phase 4 — Curation (the human's verdicts)
161
+
162
+ Present one candidate at a time: the behavior, its evidence refs, its confidence. Ask for
163
+ the verdict. On each answer, append the ledger row (`| # | candidate | evidence |
164
+ confidence | verdict | ADR-RD-NNN |`) and write the skeleton `ADR-RD-NNN` (5-10 lines:
165
+ context, evidence, verdict, consequence) for the human to complete. Re-run `curation-check`
166
+ after the pass: exit 0 means every candidate is judged and the quarantine is clear.
167
+
168
+ ## Phase 5 — Summary (facts, no opinion)
131
169
 
132
170
  Write `DISCOVERY-SUMMARY.md`: the system map + the golden coverage report (which boundaries
133
171
  are captured and approved, which are PARTIAL and why). This is the fact base the human reads
@@ -135,8 +173,9 @@ to write the migration SPEC. Do not editorialize.
135
173
 
136
174
  ## What you do NOT do (the human's job)
137
175
 
138
- - Do NOT write a SPEC of the old system's behavior the golden IS the executable spec.
139
- - Do NOT write ADRs of the old system's implicit decisions.
176
+ - Do NOT record a verdict, promote a candidate, or skip the ledger the quarantine gate
177
+ is the human's, and the engine measures it (INV-CURATION-01).
178
+ - Do NOT write the migration SPEC — only judged candidates feed it, and the human writes it.
140
179
  - Do NOT decide the NEW structure (module boundaries, shared kernel, sync vs events). Those
141
180
  are forward decisions → `/uscha-adr-refine`.
142
181
 
@@ -150,15 +189,17 @@ to write the migration SPEC. Do not editorialize.
150
189
  ## Convergence — finish when
151
190
 
152
191
  The map is complete (every boundary and dependency accounted for, or explicitly marked
153
- unknown), the golden is captured and **human-approved**, and the coverage report states
192
+ unknown), the golden is captured and **human-approved**, every candidate has a verdict
193
+ (`curation-check` exits 0 — measured, not remembered), and the coverage report states
154
194
  what is covered vs PARTIAL. State plainly that the facts are ready, then hand off.
155
195
 
156
196
  ## Handoff
157
197
 
158
- > "Read SYSTEM-MAP.md and DISCOVERY-SUMMARY.md, and inspect the approved golden. These are
159
- > FACTS about the current system. Now write the migration SPEC behavior == golden,
160
- > structure == the new module boundaries and take the partition decisions via /uscha-adr-refine.
161
- > Do not treat any of my output as a requirement or a rationale; those are yours to decide."
198
+ > "Read SYSTEM-MAP.md, DISCOVERY-SUMMARY.md and BEHAVIOR-LEDGER.md, and inspect the
199
+ > approved golden. The facts are measured; the verdicts are yours and recorded. Now write
200
+ > the migration SPEC from the JUDGED candidates`preserve` == golden must match, `fix` ==
201
+ > divergence declared by its ADR, `undefined` == out of contract and take the partition
202
+ > decisions via /uscha-adr-refine."
162
203
 
163
204
  Flow (migration): `uscha-reverse-discovery` (facts) → human writes SPEC + `/uscha-adr-refine` (forward
164
205
  module decisions) → `/uscha-devloop` (restructure; `golden-diff` + `ApplicationModules.verify()`
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
3
3
  "name": "uscha",
4
- "version": "1.63.0",
4
+ "version": "1.65.0",
5
5
  "displayName": "Uscha",
6
- "description": "Spec-driven development for LLM coding agents: 9 skills (discovery, adr-refine, reverse-discovery, characterize, devloop, sysdoc, rubric, mirador, status) + a stdlib measurement engine (qa_ledger.py, 33 subcommands + universal installer + npm/npx router). Facts block, guesses advise; the human approves.",
6
+ "description": "Spec-driven development for LLM coding agents: 9 skills (discovery, adr-refine, reverse-discovery, characterize, devloop, sysdoc, rubric, mirador, status) + a stdlib measurement engine (qa_ledger.py, 35 subcommands + universal installer + npm/npx router). Facts block, guesses advise; the human approves.",
7
7
  "author": {
8
8
  "name": "Andres Massello",
9
9
  "url": "https://github.com/andresmassello"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "uscha",
3
- "version": "1.63.0",
3
+ "version": "1.65.0",
4
4
  "description": "Uscha spec-driven development methodology for coding agents. Includes npm/npx router.",
5
5
  "author": {
6
6
  "name": "Andres Massello",
@@ -1,6 +1,6 @@
1
1
  # uscha-kit
2
2
 
3
- **Kit version:** v1.63.0 <!-- uscha:version --> · **[uscha.dev](https://uscha.dev)**
3
+ **Kit version:** v1.65.0 <!-- uscha:version --> · **[uscha.dev](https://uscha.dev)**
4
4
 
5
5
  Spec-driven orchestrator + multi-repo QA for Claude Code, with a deterministic ledger.
6
6
  **Nine skills** (`uscha-discovery`, `uscha-adr-refine`, `uscha-devloop`, `uscha-sysdoc`, `uscha-reverse-discovery`,
@@ -178,6 +178,44 @@ Honest limit: this is **not** a substitute for CI. A local worktree runs on your
178
178
  OS, your shell - environment variance is invisible to it. Different failure class, different
179
179
  instrument.
180
180
 
181
+ ## Curation (ADR-009/010) - candidates in quarantine, verdicts on the record
182
+
183
+ Reverse discovery's brownfield entry: the agent may author CANDIDATE specs of a legacy
184
+ system - in `discovery/`, with mandatory `evidence` (`test|code|inference`) and
185
+ `confidence` frontmatter, refs the engine resolves against real files - and **nothing is
186
+ promoted without a human verdict**:
187
+
188
+ ```bash
189
+ python qa_ledger.py curation-check --repo <name> [--json]
190
+ ```
191
+
192
+ Verdicts live in `BEHAVIOR-LEDGER.md` (`preserve` / `fix` / `undefined`, one ADR each) -
193
+ a human-readable table with machine-enforced rules: strict shape (`exit 2` on malformed,
194
+ because under this gate a silent "no verdicts" would UNBLOCK what it guards), append-only
195
+ verified against git (revert = new row + new ADR, never an edit; latest row wins). While
196
+ any candidate lacks a verdict, `pr-ready` is blocked naming it (INV-CURATION-01) - the
197
+ quarantine is measured, not promised. No `discovery/` directory -> the feature does not
198
+ exist and nothing changes.
199
+
200
+ ## Oracle divergences + roundtrip (slice 2)
201
+
202
+ A `fix` verdict means the new system must NOT match the legacy golden - and that divergence
203
+ is **declared**, never tolerated implicitly:
204
+
205
+ ```json
206
+ // golden.divergences.json
207
+ { "divergences": { "invoice-totals.approved.json": {
208
+ "adr": "ADR-RD-003", "reason": "IVA now rounds; legacy truncated" } } }
209
+ ```
210
+
211
+ `golden-diff` then reads the pair as `expected_divergence` (named, with its ADR) instead of
212
+ a blocker - and a declared pair that comes back **identical** goes red: the fix the
213
+ declaration describes is not in the output. Malformed declarations exit 2.
214
+
215
+ `roundtrip --repo <name>` is the advisory closing of the loop, v1: which promoted
216
+ candidates are traceable in the code via an embedded `uscha-spec: <candidate>` marker -
217
+ coverage by id, deliberately not semantic matching, exit 0 always.
218
+
181
219
  ## End-to-end flow
182
220
 
183
221
  `uscha-discovery` is the front for something new (you only have the idea); `uscha-adr-refine` is the front
package/uscha-kit/VERSION CHANGED
@@ -1 +1 @@
1
- uscha-kit 1.63.0
1
+ uscha-kit 1.65.0
@@ -0,0 +1 @@
1
+ {"AC-RD-07": true, "AC-RD-01": true, "AC-RD-02": true, "AC-RD-03": true, "AC-RD-06": true, "AC-RD-04": true, "AC-RD-05": true}
@@ -0,0 +1 @@
1
+ {"AC-RD-08": true, "AC-RD-09": true, "AC-RD-10": true, "AC-RD-11": true}