@andresmassello/uscha 1.69.0 → 1.70.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.
package/README.md CHANGED
@@ -40,7 +40,7 @@ Requires **Python 3.8+** on the machine (the engine is Python stdlib — no pip
40
40
  runtime dependencies). The npm package is a thin router; the canonical installer is
41
41
  `uscha-kit/install-uscha.py`.
42
42
 
43
- **Kit v1.69.0** <!-- uscha:version --> · [uscha.dev](https://uscha.dev) ·
43
+ **Kit v1.70.0** <!-- uscha:version --> · [uscha.dev](https://uscha.dev) ·
44
44
  [changelog](https://github.com/andresmassello/uscha/blob/main/uscha-kit/CHANGELOG.md)
45
45
  (the per-release changelogs live in the repo, not in the npm tarball)
46
46
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@andresmassello/uscha",
3
- "version": "1.69.0",
3
+ "version": "1.70.0",
4
4
  "description": "Spec-driven development for LLM coding agents: 9 skills + a stdlib evidence engine. Facts block, guesses advise; the human approves.",
5
5
  "author": {
6
6
  "name": "Andres Massello",
@@ -58,6 +58,7 @@ import hashlib
58
58
  import json
59
59
  import math
60
60
  import os
61
+ import posixpath
61
62
  import re
62
63
  import shutil
63
64
  import subprocess
@@ -3913,6 +3914,14 @@ _DELTA_BANNER = ("GENERATED by qa_ledger.py discover (ADR-013). Rendered view of
3913
3914
  + CANDIDATE_DELTA_FILE + " -- hand edits are overwritten on regeneration.")
3914
3915
 
3915
3916
 
3917
+ def _delta_seal(observations, repo, path):
3918
+ """The seal covers everything semantically load-bearing that the content-addressed OBS
3919
+ ids do NOT: the full observation set, the repo, and the bound. `path` changes what the
3920
+ delta MEANS (a partial discovery), so it must be sealed -- a hand edit of any of these is
3921
+ a named malformation (fresh-review MEDIUM)."""
3922
+ return _integrity_hash({"observations": observations, "repo": repo, "path": path})
3923
+
3924
+
3916
3925
  def _obs_id(otype, statement, primary_prov):
3917
3926
  """Content-addressed: OBS-sha256(type + LF + normalized statement + LF + primary
3918
3927
  provenance)[:12]. Normalization = lowercase + whitespace collapse. Re-running discovery
@@ -3998,7 +4007,11 @@ def _extract_static_py(repo_path, tracked):
3998
4007
  return obs, unsupported
3999
4008
 
4000
4009
 
4001
- def _golden_backed_obs(ledger, repo, repo_path):
4010
+ def _under_bound(rel, bound):
4011
+ return bound is None or rel == bound or rel.startswith(bound + "/")
4012
+
4013
+
4014
+ def _golden_backed_obs(ledger, repo, repo_path, bound=None):
4002
4015
  """Measured observations: one per approved golden fixture, backed by the LATEST ingested
4003
4016
  golden-diff gate record (AC-DD-03). Only source: real, ledger-ingested execution. No
4004
4017
  ingested run -> no measured OBS; a fixture on disk that nothing executed is not evidence."""
@@ -4016,6 +4029,8 @@ def _golden_backed_obs(ledger, repo, repo_path):
4016
4029
  if ".approved." not in f:
4017
4030
  continue
4018
4031
  rel = os.path.relpath(os.path.join(root, f), repo_path).replace(os.sep, "/")
4032
+ if not _under_bound(rel, bound):
4033
+ continue
4019
4034
  stmt = "behavior frozen by golden fixture %s matches the approved baseline" % rel
4020
4035
  obs.append({"id": _obs_id("behavior", stmt, rel), "type": "behavior",
4021
4036
  "statement": stmt, "evidence_class": "measured",
@@ -4108,9 +4123,16 @@ def _match_canonical(statement, canon_ids):
4108
4123
 
4109
4124
  def _render_delta_md(delta, verdicts):
4110
4125
  lines = ["<!-- %s -->" % _DELTA_BANNER, "",
4111
- "# CANDIDATE-DELTA (rendered view)", "",
4112
- "| id | type | class | verdict | statement | provenance |",
4113
- "|----|------|-------|---------|-----------|------------|"]
4126
+ "# CANDIDATE-DELTA (rendered view)", ""]
4127
+ if delta.get("path"):
4128
+ # the bound is the artifact the HUMAN curates from -- a partial discovery must not
4129
+ # read as a complete one, or the shrunk INV-CURATION-01 surface is undisclosed
4130
+ # (fresh-review HIGH). The JSON recorded it; the human-facing view must too.
4131
+ lines += ["> **BOUNDED discovery** — mechanical scans were restricted to "
4132
+ "`%s`. Files outside this path were NOT scanned; this delta is PARTIAL "
4133
+ "by construction." % delta["path"], ""]
4134
+ lines += ["| id | type | class | verdict | statement | provenance |",
4135
+ "|----|------|-------|---------|-----------|------------|"]
4114
4136
  for o in delta["observations"]:
4115
4137
  v = verdicts.get(o["id"], "(uncurated)")
4116
4138
  files = ", ".join(o["provenance"].get("files") or []) or "-"
@@ -4177,10 +4199,10 @@ def _load_delta(repo_path):
4177
4199
  # launders narrated inference into measured evidence (fresh-review MEDIUM, reproduced)
4178
4200
  if not errors:
4179
4201
  seal = delta.get("_integrity")
4180
- want = _integrity_hash({"observations": obs})
4202
+ want = _delta_seal(obs, delta.get("repo"), delta.get("path"))
4181
4203
  if seal != want:
4182
- errors.append("integrity seal %s does not match the observations -- the delta "
4183
- "is derived, never hand-edited (regenerate via `discover`)"
4204
+ errors.append("integrity seal %s does not match the delta content -- observations, "
4205
+ "repo or path was hand-edited (regenerate via `discover`)"
4184
4206
  % ("missing" if seal is None else repr(seal)))
4185
4207
  return delta, errors
4186
4208
 
@@ -4224,8 +4246,36 @@ def cmd_discover(args):
4224
4246
  "from tracked files and cannot proceed without it." % repo_path,
4225
4247
  file=sys.stderr)
4226
4248
  sys.exit(2)
4249
+ bound = None
4250
+ if args.path is not None:
4251
+ # the bound restricts the MECHANICAL scans (static, measured); narrated input stays
4252
+ # the skill's to scope. Field-found before the first run (AC-DD-07): "real, bounded"
4253
+ # is unimplementable without it.
4254
+ raw = args.path.replace("\\", "/").strip()
4255
+ if not raw:
4256
+ # an empty --path is the silent-degrade trap (a wrapper passing an unset var):
4257
+ # falsy would mean "no bound" and quietly scan the whole repo (fresh-review MED)
4258
+ print("[qa_ledger] discover: --path is empty -- omit --path to scan the whole "
4259
+ "repo; an empty bound is not a bound.", file=sys.stderr)
4260
+ sys.exit(2)
4261
+ bound = posixpath.normpath(raw).strip("/") # ./src, src/ , /src -> src
4262
+ if bound in (".", "") or bound == ".." or bound.startswith("../"):
4263
+ print("[qa_ledger] discover: --path %r does not name a subtree inside the repo."
4264
+ % args.path, file=sys.stderr)
4265
+ sys.exit(2)
4266
+ if _gc_rel(os.path.join(repo_path, bound.replace("/", os.sep)), repo_path) is None:
4267
+ print("[qa_ledger] discover: --path %r escapes the repo tree." % args.path,
4268
+ file=sys.stderr)
4269
+ sys.exit(2)
4270
+ tracked = [f for f in tracked if _under_bound(f, bound)]
4271
+ if not tracked:
4272
+ # a typo'd bound silently emitting an empty delta is the silent-degrade trap
4273
+ print("[qa_ledger] discover: --path %r matches no tracked file -- refusing to "
4274
+ "emit an empty delta for a bound that points at nothing." % args.path,
4275
+ file=sys.stderr)
4276
+ sys.exit(2)
4227
4277
  static_obs, unsupported = _extract_static_py(repo_path, tracked)
4228
- measured_obs = _golden_backed_obs(ledger, args.repo, repo_path)
4278
+ measured_obs = _golden_backed_obs(ledger, args.repo, repo_path, bound)
4229
4279
  narrated_obs, nerrs = ([], [])
4230
4280
  if args.narrated:
4231
4281
  narrated_obs, nerrs = _load_narrated(args.narrated, repo_path)
@@ -4244,10 +4294,11 @@ def cmd_discover(args):
4244
4294
  o["canonical_match"] = _match_canonical(o["statement"], canon)
4245
4295
  observations = sorted(by_id.values(), key=lambda o: o["id"])
4246
4296
  delta = {"_generated_by": "qa_ledger.py discover (ADR-013) -- machine-canonical; "
4247
- "never hand-edit (ids are content-addressed, the seal "
4248
- "covers the rest)",
4249
- "_integrity": _integrity_hash({"observations": observations}),
4297
+ "never hand-edit (ids are content-addressed; the seal "
4298
+ "covers observations, repo and path)",
4299
+ "_integrity": _delta_seal(observations, args.repo, bound),
4250
4300
  "repo": args.repo,
4301
+ **({"path": bound} if bound else {}),
4251
4302
  "observations": observations,
4252
4303
  "static_unsupported": {"files": unsupported,
4253
4304
  "note": "static extractors are Python-only in v0 "
@@ -8596,6 +8647,10 @@ def build_parser():
8596
8647
  pdd.add_argument("--narrated", default=None,
8597
8648
  help="JSON list of skill-supplied observations {type, statement, files}; "
8598
8649
  "the engine classifies them narrated -- it never calls an LLM")
8650
+ pdd.add_argument("--path", default=None,
8651
+ help="bound the mechanical scans to one subtree/file (repo-relative); "
8652
+ "a bound matching nothing is a refusal, and it is recorded in "
8653
+ "the delta")
8599
8654
  pdd.add_argument("--acceptance", default=None,
8600
8655
  help="acceptance file for canonical_match (default: config "
8601
8656
  "defaults.acceptance_file, else ACCEPTANCE.md)")
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
3
3
  "name": "uscha",
4
- "version": "1.69.0",
4
+ "version": "1.70.0",
5
5
  "displayName": "Uscha",
6
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, 40 subcommands + universal installer + npm/npx router). Facts block, guesses advise; the human approves.",
7
7
  "author": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "uscha",
3
- "version": "1.69.0",
3
+ "version": "1.70.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.69.0 <!-- uscha:version --> · **[uscha.dev](https://uscha.dev)**
3
+ **Kit version:** v1.70.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`,
package/uscha-kit/VERSION CHANGED
@@ -1 +1 @@
1
- uscha-kit 1.69.0
1
+ uscha-kit 1.70.0
@@ -1 +1 @@
1
- {"AC-DD-01": true, "AC-DD-02": true, "AC-DD-03": true, "AC-DD-04": true, "AC-DD-05": true, "AC-DD-06": true, "AC-CU-06": true, "AC-CU-01": true, "AC-CU-02": true, "AC-CU-03": true, "AC-CU-04": true, "AC-CU-05": true, "review-m1": true, "review-m3": true, "review-h1": true}
1
+ {"AC-DD-01": true, "AC-DD-02": true, "AC-DD-03": true, "AC-DD-04": true, "AC-DD-05": true, "AC-DD-06": true, "AC-CU-06": true, "AC-CU-01": true, "AC-CU-02": true, "AC-CU-03": true, "AC-CU-04": true, "AC-CU-05": true, "AC-DD-07": true, "review-m1": true, "review-m3": true, "review-h1": true}
@@ -58,6 +58,7 @@ import hashlib
58
58
  import json
59
59
  import math
60
60
  import os
61
+ import posixpath
61
62
  import re
62
63
  import shutil
63
64
  import subprocess
@@ -3913,6 +3914,14 @@ _DELTA_BANNER = ("GENERATED by qa_ledger.py discover (ADR-013). Rendered view of
3913
3914
  + CANDIDATE_DELTA_FILE + " -- hand edits are overwritten on regeneration.")
3914
3915
 
3915
3916
 
3917
+ def _delta_seal(observations, repo, path):
3918
+ """The seal covers everything semantically load-bearing that the content-addressed OBS
3919
+ ids do NOT: the full observation set, the repo, and the bound. `path` changes what the
3920
+ delta MEANS (a partial discovery), so it must be sealed -- a hand edit of any of these is
3921
+ a named malformation (fresh-review MEDIUM)."""
3922
+ return _integrity_hash({"observations": observations, "repo": repo, "path": path})
3923
+
3924
+
3916
3925
  def _obs_id(otype, statement, primary_prov):
3917
3926
  """Content-addressed: OBS-sha256(type + LF + normalized statement + LF + primary
3918
3927
  provenance)[:12]. Normalization = lowercase + whitespace collapse. Re-running discovery
@@ -3998,7 +4007,11 @@ def _extract_static_py(repo_path, tracked):
3998
4007
  return obs, unsupported
3999
4008
 
4000
4009
 
4001
- def _golden_backed_obs(ledger, repo, repo_path):
4010
+ def _under_bound(rel, bound):
4011
+ return bound is None or rel == bound or rel.startswith(bound + "/")
4012
+
4013
+
4014
+ def _golden_backed_obs(ledger, repo, repo_path, bound=None):
4002
4015
  """Measured observations: one per approved golden fixture, backed by the LATEST ingested
4003
4016
  golden-diff gate record (AC-DD-03). Only source: real, ledger-ingested execution. No
4004
4017
  ingested run -> no measured OBS; a fixture on disk that nothing executed is not evidence."""
@@ -4016,6 +4029,8 @@ def _golden_backed_obs(ledger, repo, repo_path):
4016
4029
  if ".approved." not in f:
4017
4030
  continue
4018
4031
  rel = os.path.relpath(os.path.join(root, f), repo_path).replace(os.sep, "/")
4032
+ if not _under_bound(rel, bound):
4033
+ continue
4019
4034
  stmt = "behavior frozen by golden fixture %s matches the approved baseline" % rel
4020
4035
  obs.append({"id": _obs_id("behavior", stmt, rel), "type": "behavior",
4021
4036
  "statement": stmt, "evidence_class": "measured",
@@ -4108,9 +4123,16 @@ def _match_canonical(statement, canon_ids):
4108
4123
 
4109
4124
  def _render_delta_md(delta, verdicts):
4110
4125
  lines = ["<!-- %s -->" % _DELTA_BANNER, "",
4111
- "# CANDIDATE-DELTA (rendered view)", "",
4112
- "| id | type | class | verdict | statement | provenance |",
4113
- "|----|------|-------|---------|-----------|------------|"]
4126
+ "# CANDIDATE-DELTA (rendered view)", ""]
4127
+ if delta.get("path"):
4128
+ # the bound is the artifact the HUMAN curates from -- a partial discovery must not
4129
+ # read as a complete one, or the shrunk INV-CURATION-01 surface is undisclosed
4130
+ # (fresh-review HIGH). The JSON recorded it; the human-facing view must too.
4131
+ lines += ["> **BOUNDED discovery** — mechanical scans were restricted to "
4132
+ "`%s`. Files outside this path were NOT scanned; this delta is PARTIAL "
4133
+ "by construction." % delta["path"], ""]
4134
+ lines += ["| id | type | class | verdict | statement | provenance |",
4135
+ "|----|------|-------|---------|-----------|------------|"]
4114
4136
  for o in delta["observations"]:
4115
4137
  v = verdicts.get(o["id"], "(uncurated)")
4116
4138
  files = ", ".join(o["provenance"].get("files") or []) or "-"
@@ -4177,10 +4199,10 @@ def _load_delta(repo_path):
4177
4199
  # launders narrated inference into measured evidence (fresh-review MEDIUM, reproduced)
4178
4200
  if not errors:
4179
4201
  seal = delta.get("_integrity")
4180
- want = _integrity_hash({"observations": obs})
4202
+ want = _delta_seal(obs, delta.get("repo"), delta.get("path"))
4181
4203
  if seal != want:
4182
- errors.append("integrity seal %s does not match the observations -- the delta "
4183
- "is derived, never hand-edited (regenerate via `discover`)"
4204
+ errors.append("integrity seal %s does not match the delta content -- observations, "
4205
+ "repo or path was hand-edited (regenerate via `discover`)"
4184
4206
  % ("missing" if seal is None else repr(seal)))
4185
4207
  return delta, errors
4186
4208
 
@@ -4224,8 +4246,36 @@ def cmd_discover(args):
4224
4246
  "from tracked files and cannot proceed without it." % repo_path,
4225
4247
  file=sys.stderr)
4226
4248
  sys.exit(2)
4249
+ bound = None
4250
+ if args.path is not None:
4251
+ # the bound restricts the MECHANICAL scans (static, measured); narrated input stays
4252
+ # the skill's to scope. Field-found before the first run (AC-DD-07): "real, bounded"
4253
+ # is unimplementable without it.
4254
+ raw = args.path.replace("\\", "/").strip()
4255
+ if not raw:
4256
+ # an empty --path is the silent-degrade trap (a wrapper passing an unset var):
4257
+ # falsy would mean "no bound" and quietly scan the whole repo (fresh-review MED)
4258
+ print("[qa_ledger] discover: --path is empty -- omit --path to scan the whole "
4259
+ "repo; an empty bound is not a bound.", file=sys.stderr)
4260
+ sys.exit(2)
4261
+ bound = posixpath.normpath(raw).strip("/") # ./src, src/ , /src -> src
4262
+ if bound in (".", "") or bound == ".." or bound.startswith("../"):
4263
+ print("[qa_ledger] discover: --path %r does not name a subtree inside the repo."
4264
+ % args.path, file=sys.stderr)
4265
+ sys.exit(2)
4266
+ if _gc_rel(os.path.join(repo_path, bound.replace("/", os.sep)), repo_path) is None:
4267
+ print("[qa_ledger] discover: --path %r escapes the repo tree." % args.path,
4268
+ file=sys.stderr)
4269
+ sys.exit(2)
4270
+ tracked = [f for f in tracked if _under_bound(f, bound)]
4271
+ if not tracked:
4272
+ # a typo'd bound silently emitting an empty delta is the silent-degrade trap
4273
+ print("[qa_ledger] discover: --path %r matches no tracked file -- refusing to "
4274
+ "emit an empty delta for a bound that points at nothing." % args.path,
4275
+ file=sys.stderr)
4276
+ sys.exit(2)
4227
4277
  static_obs, unsupported = _extract_static_py(repo_path, tracked)
4228
- measured_obs = _golden_backed_obs(ledger, args.repo, repo_path)
4278
+ measured_obs = _golden_backed_obs(ledger, args.repo, repo_path, bound)
4229
4279
  narrated_obs, nerrs = ([], [])
4230
4280
  if args.narrated:
4231
4281
  narrated_obs, nerrs = _load_narrated(args.narrated, repo_path)
@@ -4244,10 +4294,11 @@ def cmd_discover(args):
4244
4294
  o["canonical_match"] = _match_canonical(o["statement"], canon)
4245
4295
  observations = sorted(by_id.values(), key=lambda o: o["id"])
4246
4296
  delta = {"_generated_by": "qa_ledger.py discover (ADR-013) -- machine-canonical; "
4247
- "never hand-edit (ids are content-addressed, the seal "
4248
- "covers the rest)",
4249
- "_integrity": _integrity_hash({"observations": observations}),
4297
+ "never hand-edit (ids are content-addressed; the seal "
4298
+ "covers observations, repo and path)",
4299
+ "_integrity": _delta_seal(observations, args.repo, bound),
4250
4300
  "repo": args.repo,
4301
+ **({"path": bound} if bound else {}),
4251
4302
  "observations": observations,
4252
4303
  "static_unsupported": {"files": unsupported,
4253
4304
  "note": "static extractors are Python-only in v0 "
@@ -8596,6 +8647,10 @@ def build_parser():
8596
8647
  pdd.add_argument("--narrated", default=None,
8597
8648
  help="JSON list of skill-supplied observations {type, statement, files}; "
8598
8649
  "the engine classifies them narrated -- it never calls an LLM")
8650
+ pdd.add_argument("--path", default=None,
8651
+ help="bound the mechanical scans to one subtree/file (repo-relative); "
8652
+ "a bound matching nothing is a refusal, and it is recorded in "
8653
+ "the delta")
8599
8654
  pdd.add_argument("--acceptance", default=None,
8600
8655
  help="acceptance file for canonical_match (default: config "
8601
8656
  "defaults.acceptance_file, else ACCEPTANCE.md)")
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.69.0",
2
+ "version": "1.70.0",
3
3
  "project": null,
4
4
  "defaults": {
5
5
  "coverage_threshold": 60,