@andresmassello/uscha 1.75.1 → 1.76.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.75.1** <!-- uscha:version --> · [uscha.dev](https://uscha.dev) ·
43
+ **Kit v1.76.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
 
@@ -76,7 +76,7 @@ and see which file, which test, and when.
76
76
  | `/uscha-mirador` | Bird's-eye HTML dashboard: readiness, trail, acceptance, loops |
77
77
  | `/uscha-status` | One-line progress readout, in chat |
78
78
 
79
- **A measurement engine** (`qa_ledger.py`, 47 subcommands, Python stdlib) that ingests
79
+ **A measurement engine** (`qa_ledger.py`, 48 subcommands, Python stdlib) that ingests
80
80
  evidence from **11 language stacks** — maven, gradle, ant, python, node, go, rust, dotnet,
81
81
  cpp, swift, flutter — and computes a readiness score with hard caps and visible provenance.
82
82
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@andresmassello/uscha",
3
- "version": "1.75.1",
3
+ "version": "1.76.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",
@@ -5659,6 +5659,209 @@ def cmd_bench(args):
5659
5659
  sys.exit(0)
5660
5660
 
5661
5661
 
5662
+ # --------------------------------------------------------------------------- #
5663
+ # lang-compare (Diamond controlled-language arm: the SAME canonical package in
5664
+ # free prose vs EARS+STE, judged by the SAME withheld oracle, compiled by the
5665
+ # same models. Measures whether controlled authoring reduces inter-compiler
5666
+ # variance and/or unresolved_intent. The language is demonstrated or discarded
5667
+ # by the delta, never decreed. Deterministic, no LLM. ADR-019.)
5668
+ # --------------------------------------------------------------------------- #
5669
+ _LANG_MARGIN = 0.05 # variance delta below this is NO EFFECT
5670
+ _LANG_PR_MARGIN = 0.02 # mean oracle pass-rate drop counted a regression
5671
+
5672
+
5673
+ def _lang_arm_metrics(arm_dir):
5674
+ """Measure ONE arm: per-compiler oracle green + unresolved_intent, and inter-compiler
5675
+ variance over the arm's compilations. Reuses the M4/M5 organs unchanged."""
5676
+ ir_graph, ir_errors = _load_ir_at(os.path.join(arm_dir, IR_FILE))
5677
+ try:
5678
+ with open(os.path.join(arm_dir, "oracle", "ORACLE.json"), encoding="utf-8-sig") as fh:
5679
+ cases = (json.load(fh) or {}).get("cases") or []
5680
+ except (OSError, ValueError):
5681
+ cases = []
5682
+ rec = {"arm": os.path.basename(arm_dir), "ir_ok": ir_graph is not None and not ir_errors,
5683
+ "compilations": [], "greens": 0, "n": 0, "variance_score": None,
5684
+ "mean_passrate": None, "ui_count": 0.0, "ui_distinct_regions": 0.0,
5685
+ "ui_rationale_len": 0.0}
5686
+ if ir_graph is None or ir_errors or not cases:
5687
+ return rec, ["arm incomplete (missing/invalid IR or oracle)"]
5688
+ comp_dirs = sorted(d for d in os.listdir(arm_dir)
5689
+ if d.startswith("c-") and
5690
+ os.path.isfile(os.path.join(arm_dir, d, "COMPILATION.json")))
5691
+ impl_paths, ui_counts, ui_regions, ui_lens = [], [], [], []
5692
+ for d in comp_dirs:
5693
+ cd = os.path.join(arm_dir, d)
5694
+ cj = os.path.join(cd, "COMPILATION.json")
5695
+ errors, _adv = _validate_compilation(cj, ir_graph)
5696
+ unit, model, uis = None, None, []
5697
+ try:
5698
+ with open(cj, encoding="utf-8-sig") as fh:
5699
+ c = json.load(fh)
5700
+ src = c.get("source") or []
5701
+ unit = src[0].get("unit") if src else None
5702
+ model = (c.get("compilation_report") or {}).get("model")
5703
+ uis = c.get("unresolved_intent") or []
5704
+ except (OSError, ValueError, AttributeError, IndexError):
5705
+ pass
5706
+ impl = os.path.join(cd, unit.replace("/", os.sep)) if unit else None
5707
+ ores = (_bench_oracle_all(impl, cases) if impl and os.path.isfile(impl)
5708
+ else {"passed": 0, "total": len(cases), "green": False})
5709
+ if impl and os.path.isfile(impl):
5710
+ impl_paths.append(impl)
5711
+ ui_counts.append(len(uis))
5712
+ ui_regions.append(len({(u.get("ir_region") or "") for u in uis}))
5713
+ ui_lens.append((sum(len(u.get("rationale") or "") for u in uis) / len(uis))
5714
+ if uis else 0.0)
5715
+ rec["compilations"].append({"dir": d, "model": model, "compile_valid": not errors,
5716
+ "oracle": ores, "ui_count": len(uis)})
5717
+ rec["n"] = len(rec["compilations"])
5718
+ rec["greens"] = sum(1 for i in rec["compilations"] if i["oracle"]["green"])
5719
+ # mean oracle pass-RATE (not just the binary all-green flag): a per-compiler regression that
5720
+ # never reaches all-green is invisible in `greens` but real in the pass-rate, and lower
5721
+ # variance toward a WORSE behaviour must not read as a clean win (the M4 convergence lesson).
5722
+ rates = [(i["oracle"]["passed"] / i["oracle"]["total"]) if i["oracle"]["total"] else 0.0
5723
+ for i in rec["compilations"]]
5724
+ rec["mean_passrate"] = round(sum(rates) / len(rates), 4) if rates else None
5725
+ rec["ui_count"] = round(sum(ui_counts) / len(ui_counts), 3) if ui_counts else 0.0
5726
+ rec["ui_distinct_regions"] = round(sum(ui_regions) / len(ui_regions), 3) if ui_regions else 0.0
5727
+ rec["ui_rationale_len"] = round(sum(ui_lens) / len(ui_lens), 1) if ui_lens else 0.0
5728
+ # inter-compiler variance: mean pairwise normalized structural distance (0 = identical)
5729
+ metrics = [_impl_metrics(p) for p in impl_paths]
5730
+ good = [m for m in metrics if "error" not in m]
5731
+ dists = []
5732
+ for i in range(len(good)):
5733
+ for j in range(i + 1, len(good)):
5734
+ a, b = good[i], good[j]
5735
+ ia, ib = set(a["imports"]), set(b["imports"])
5736
+ jac = (len(ia & ib) / len(ia | ib)) if (ia or ib) else 1.0
5737
+ dloc = abs(a["loc"] - b["loc"]) / max(a["loc"], b["loc"], 1)
5738
+ dast = abs(a["ast_nodes"] - b["ast_nodes"]) / max(a["ast_nodes"], b["ast_nodes"], 1)
5739
+ dists.append((dloc + dast + (1.0 - jac)) / 3.0)
5740
+ rec["variance_score"] = round(sum(dists) / len(dists), 4) if dists else None
5741
+ return rec, []
5742
+
5743
+
5744
+ def _oracle_hash(arm_dir):
5745
+ try:
5746
+ with open(os.path.join(arm_dir, "oracle", "ORACLE.json"), "rb") as fh:
5747
+ return hashlib.sha256(fh.read()).hexdigest()
5748
+ except OSError:
5749
+ return None
5750
+
5751
+
5752
+ def cmd_lang_compare(args):
5753
+ """Compare a FREE-prose arm and a CONTROLLED (EARS+STE) arm of the same canonical package
5754
+ (ADR-019). The two arms MUST share one withheld oracle -- a differing oracle is a mechanical
5755
+ refusal, because the whole comparison rests on the arms targeting the same behaviour. Emits
5756
+ the per-arm metrics, the delta, and a COMPUTED verdict (REDUCED / NO EFFECT / WORSE); a null
5757
+ is a first-class result. Consults no model."""
5758
+ hf, hc = _oracle_hash(args.free), _oracle_hash(args.controlled)
5759
+ if hf is None or hc is None:
5760
+ print("[qa_ledger] lang-compare: an arm has no oracle/ORACLE.json", file=sys.stderr)
5761
+ sys.exit(2)
5762
+ if hf != hc:
5763
+ print("[qa_ledger] lang-compare: the two arms have DIFFERENT oracles (%s.. vs %s..) -- "
5764
+ "the comparison requires the SAME withheld oracle; behaviour must be held fixed "
5765
+ "while only the authoring changes." % (hf[:12], hc[:12]), file=sys.stderr)
5766
+ sys.exit(2)
5767
+ free, ef = _lang_arm_metrics(args.free)
5768
+ ctrl, ec = _lang_arm_metrics(args.controlled)
5769
+ if ef or ec:
5770
+ for e in ef + ec:
5771
+ print("[qa_ledger] lang-compare: %s" % e, file=sys.stderr)
5772
+ sys.exit(2)
5773
+ vf, vc = free["variance_score"], ctrl["variance_score"]
5774
+ d_var = (vc - vf) if (vf is not None and vc is not None) else None
5775
+ d_ui = ctrl["ui_count"] - free["ui_count"]
5776
+ d_green = ctrl["greens"] - free["greens"]
5777
+ pf, pc = free["mean_passrate"], ctrl["mean_passrate"]
5778
+ d_pass = (pc - pf) if (pf is not None and pc is not None) else None
5779
+ # Verdict is BEHAVIOUR-FIRST (the M4 lesson: lower variance toward a WORSE answer is not a
5780
+ # win). A regression is a lost all-green OR a mean pass-rate drop beyond the pass-rate margin.
5781
+ variance_reduced = d_var is not None and d_var <= -_LANG_MARGIN
5782
+ variance_worse = d_var is not None and d_var >= _LANG_MARGIN
5783
+ regressed = (d_green < 0) or (d_pass is not None and d_pass <= -_LANG_PR_MARGIN)
5784
+ if variance_reduced and regressed:
5785
+ verdict = "MIXED" # variance down but behaviour regressed
5786
+ elif variance_reduced:
5787
+ verdict = "REDUCED" # variance down, behaviour held
5788
+ elif variance_worse or regressed:
5789
+ verdict = "WORSE"
5790
+ else:
5791
+ verdict = "NO EFFECT"
5792
+ delta = {"variance_score": round(d_var, 4) if d_var is not None else None,
5793
+ "unresolved_intent_count": round(d_ui, 3), "oracle_green": d_green,
5794
+ "mean_passrate": round(d_pass, 4) if d_pass is not None else None}
5795
+ report = {"free": free, "controlled": ctrl, "delta": delta, "verdict": verdict,
5796
+ "margin": _LANG_MARGIN, "passrate_margin": _LANG_PR_MARGIN, "oracle_shared": True}
5797
+ if args.out:
5798
+ with open(args.out, "w", encoding="utf-8", newline="\n") as fh:
5799
+ fh.write(_render_lang_md(report))
5800
+ if args.json:
5801
+ print(json.dumps(report, indent=2, ensure_ascii=False))
5802
+ else:
5803
+ for a in (free, ctrl):
5804
+ print("LANG %-11s: oracle-green %d/%d · pass-rate %s · variance %s · "
5805
+ "unresolved_intent %.2f (regions %.2f, rationale %.0f chars)"
5806
+ % (a["arm"], a["greens"], a["n"],
5807
+ "%.3f" % a["mean_passrate"] if a["mean_passrate"] is not None else "n/a",
5808
+ "%.4f" % a["variance_score"] if a["variance_score"] is not None else "n/a",
5809
+ a["ui_count"], a["ui_distinct_regions"], a["ui_rationale_len"]))
5810
+ print("DELTA (controlled - free): variance %s · pass-rate %s · unresolved_intent %+.2f "
5811
+ "· green %+d"
5812
+ % ("%+.4f" % delta["variance_score"] if delta["variance_score"] is not None
5813
+ else "n/a",
5814
+ "%+.4f" % delta["mean_passrate"] if delta["mean_passrate"] is not None else "n/a",
5815
+ delta["unresolved_intent_count"], delta["oracle_green"]))
5816
+ print("VERDICT: %s (variance margin %.2f, pass-rate margin %.2f) -- behaviour-first, "
5817
+ "computed from the delta, never decreed" % (verdict, _LANG_MARGIN, _LANG_PR_MARGIN))
5818
+ if args.out:
5819
+ print(" -> %s" % args.out)
5820
+ sys.exit(0)
5821
+
5822
+
5823
+ def _render_lang_md(r):
5824
+ d = r["delta"]
5825
+ lines = ["<!-- GENERATED by qa_ledger.py lang-compare (ADR-019) -- measured run; do not "
5826
+ "hand-edit. -->", "", "# CONTROLLED-LANGUAGE-REPORT", "",
5827
+ "The same canonical package compiled by the same models from **free prose** (arm A) "
5828
+ "and an **EARS+STE rewrite** (arm B), judged by one **shared withheld oracle** "
5829
+ "(behaviour held fixed; only the authoring changes). The verdict is computed from "
5830
+ "the delta.", "",
5831
+ "| Arm | Oracle-green | Mean pass-rate | Inter-compiler variance | unresolved_intent (count · regions · rationale chars) |",
5832
+ "|-----|--------------|----------------|-------------------------|-------------------------------------------------------|"]
5833
+ for a in (r["free"], r["controlled"]):
5834
+ vs = "%.4f" % a["variance_score"] if a["variance_score"] is not None else "n/a"
5835
+ pr = "%.3f" % a["mean_passrate"] if a["mean_passrate"] is not None else "n/a"
5836
+ lines.append("| %s | %d/%d | %s | %s | %.2f · %.2f · %.0f |"
5837
+ % (a["arm"], a["greens"], a["n"], pr, vs, a["ui_count"],
5838
+ a["ui_distinct_regions"], a["ui_rationale_len"]))
5839
+ dv = "%+.4f" % d["variance_score"] if d["variance_score"] is not None else "n/a"
5840
+ dp = "%+.4f" % d["mean_passrate"] if d.get("mean_passrate") is not None else "n/a"
5841
+ lines += ["", "**Delta (controlled − free):** variance %s · mean pass-rate %s · "
5842
+ "unresolved_intent %+.2f · oracle-green %+d."
5843
+ % (dv, dp, d["unresolved_intent_count"], d["oracle_green"]), "",
5844
+ "## Verdict: %s" % r["verdict"], "",
5845
+ {"REDUCED": "Controlled authoring reduced inter-compiler variance beyond the %.2f "
5846
+ "margin WITHOUT a behavioural regression — for this subsystem, at this "
5847
+ "sample size." % r["margin"],
5848
+ "MIXED": "Controlled authoring reduced inter-compiler variance beyond the %.2f "
5849
+ "margin, BUT mean oracle pass-rate regressed beyond the %.2f pass-rate "
5850
+ "margin (or an all-green was lost): the compilers agreed MORE, on a "
5851
+ "marginally WORSE behaviour. Lower variance is not a win when it converges "
5852
+ "toward a worse answer — the honest, two-part finding."
5853
+ % (r["margin"], r.get("passrate_margin", 0.02)),
5854
+ "NO EFFECT": "Within the margins: controlled authoring did not measurably change "
5855
+ "the delta here. A null result, reported as a null — not a failure.",
5856
+ "WORSE": "Controlled authoring increased variance, or regressed behaviour (lost an "
5857
+ "all-green or dropped mean pass-rate) beyond the margins — reported "
5858
+ "honestly."}[r["verdict"]],
5859
+ "", "*The oracle is byte-identical across both arms, so behaviour is held fixed; "
5860
+ "the only variable is the authoring discipline. The judgement of \"same semantic "
5861
+ "content\" between the two canonical packages is human — a stated limitation.*", ""]
5862
+ return "\n".join(lines)
5863
+
5864
+
5662
5865
  # --------------------------------------------------------------------------- #
5663
5866
  # facts (T0 / SYSTEM-FACTS: public claims become compiled artifacts of repo
5664
5867
  # facts -- Diamond applied to Diamond. ADR-012.)
@@ -9782,6 +9985,17 @@ def build_parser():
9782
9985
  pbn.add_argument("--json", action="store_true")
9783
9986
  pbn.set_defaults(func=cmd_bench)
9784
9987
 
9988
+ plc = sub.add_parser(
9989
+ "lang-compare",
9990
+ help="controlled-language arm (ADR-019): compare a FREE-prose arm and an EARS+STE arm of "
9991
+ "the same canonical package, judged by the SAME withheld oracle; the delta on "
9992
+ "variance/unresolved_intent gives a computed REDUCED/NO EFFECT/WORSE verdict")
9993
+ plc.add_argument("--free", required=True, help="the free-prose arm directory")
9994
+ plc.add_argument("--controlled", required=True, help="the EARS+STE arm directory")
9995
+ plc.add_argument("--out", default=None, help="write CONTROLLED-LANGUAGE-REPORT.md here")
9996
+ plc.add_argument("--json", action="store_true")
9997
+ plc.set_defaults(func=cmd_lang_compare)
9998
+
9785
9999
  pcr = sub.add_parser("cleanroom",
9786
10000
  help="run a command against a CLEAN checkout of one commit in a throwaway worktree (ADR-008)")
9787
10001
  pcr.add_argument("--ledger", default="QA-LEDGER.json")
@@ -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.75.1",
4
+ "version": "1.76.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, 47 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, 48 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.75.1",
3
+ "version": "1.76.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.75.1 <!-- uscha:version --> · **[uscha.dev](https://uscha.dev)**
3
+ **Kit version:** v1.76.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.75.1
1
+ uscha-kit 1.76.0
@@ -0,0 +1 @@
1
+ {"AC-CL-01": true, "AC-CL-02": true, "AC-CL-03": true, "AC-CL-04": true, "AC-CL-05": true, "AC-CL-06": true}
@@ -5659,6 +5659,209 @@ def cmd_bench(args):
5659
5659
  sys.exit(0)
5660
5660
 
5661
5661
 
5662
+ # --------------------------------------------------------------------------- #
5663
+ # lang-compare (Diamond controlled-language arm: the SAME canonical package in
5664
+ # free prose vs EARS+STE, judged by the SAME withheld oracle, compiled by the
5665
+ # same models. Measures whether controlled authoring reduces inter-compiler
5666
+ # variance and/or unresolved_intent. The language is demonstrated or discarded
5667
+ # by the delta, never decreed. Deterministic, no LLM. ADR-019.)
5668
+ # --------------------------------------------------------------------------- #
5669
+ _LANG_MARGIN = 0.05 # variance delta below this is NO EFFECT
5670
+ _LANG_PR_MARGIN = 0.02 # mean oracle pass-rate drop counted a regression
5671
+
5672
+
5673
+ def _lang_arm_metrics(arm_dir):
5674
+ """Measure ONE arm: per-compiler oracle green + unresolved_intent, and inter-compiler
5675
+ variance over the arm's compilations. Reuses the M4/M5 organs unchanged."""
5676
+ ir_graph, ir_errors = _load_ir_at(os.path.join(arm_dir, IR_FILE))
5677
+ try:
5678
+ with open(os.path.join(arm_dir, "oracle", "ORACLE.json"), encoding="utf-8-sig") as fh:
5679
+ cases = (json.load(fh) or {}).get("cases") or []
5680
+ except (OSError, ValueError):
5681
+ cases = []
5682
+ rec = {"arm": os.path.basename(arm_dir), "ir_ok": ir_graph is not None and not ir_errors,
5683
+ "compilations": [], "greens": 0, "n": 0, "variance_score": None,
5684
+ "mean_passrate": None, "ui_count": 0.0, "ui_distinct_regions": 0.0,
5685
+ "ui_rationale_len": 0.0}
5686
+ if ir_graph is None or ir_errors or not cases:
5687
+ return rec, ["arm incomplete (missing/invalid IR or oracle)"]
5688
+ comp_dirs = sorted(d for d in os.listdir(arm_dir)
5689
+ if d.startswith("c-") and
5690
+ os.path.isfile(os.path.join(arm_dir, d, "COMPILATION.json")))
5691
+ impl_paths, ui_counts, ui_regions, ui_lens = [], [], [], []
5692
+ for d in comp_dirs:
5693
+ cd = os.path.join(arm_dir, d)
5694
+ cj = os.path.join(cd, "COMPILATION.json")
5695
+ errors, _adv = _validate_compilation(cj, ir_graph)
5696
+ unit, model, uis = None, None, []
5697
+ try:
5698
+ with open(cj, encoding="utf-8-sig") as fh:
5699
+ c = json.load(fh)
5700
+ src = c.get("source") or []
5701
+ unit = src[0].get("unit") if src else None
5702
+ model = (c.get("compilation_report") or {}).get("model")
5703
+ uis = c.get("unresolved_intent") or []
5704
+ except (OSError, ValueError, AttributeError, IndexError):
5705
+ pass
5706
+ impl = os.path.join(cd, unit.replace("/", os.sep)) if unit else None
5707
+ ores = (_bench_oracle_all(impl, cases) if impl and os.path.isfile(impl)
5708
+ else {"passed": 0, "total": len(cases), "green": False})
5709
+ if impl and os.path.isfile(impl):
5710
+ impl_paths.append(impl)
5711
+ ui_counts.append(len(uis))
5712
+ ui_regions.append(len({(u.get("ir_region") or "") for u in uis}))
5713
+ ui_lens.append((sum(len(u.get("rationale") or "") for u in uis) / len(uis))
5714
+ if uis else 0.0)
5715
+ rec["compilations"].append({"dir": d, "model": model, "compile_valid": not errors,
5716
+ "oracle": ores, "ui_count": len(uis)})
5717
+ rec["n"] = len(rec["compilations"])
5718
+ rec["greens"] = sum(1 for i in rec["compilations"] if i["oracle"]["green"])
5719
+ # mean oracle pass-RATE (not just the binary all-green flag): a per-compiler regression that
5720
+ # never reaches all-green is invisible in `greens` but real in the pass-rate, and lower
5721
+ # variance toward a WORSE behaviour must not read as a clean win (the M4 convergence lesson).
5722
+ rates = [(i["oracle"]["passed"] / i["oracle"]["total"]) if i["oracle"]["total"] else 0.0
5723
+ for i in rec["compilations"]]
5724
+ rec["mean_passrate"] = round(sum(rates) / len(rates), 4) if rates else None
5725
+ rec["ui_count"] = round(sum(ui_counts) / len(ui_counts), 3) if ui_counts else 0.0
5726
+ rec["ui_distinct_regions"] = round(sum(ui_regions) / len(ui_regions), 3) if ui_regions else 0.0
5727
+ rec["ui_rationale_len"] = round(sum(ui_lens) / len(ui_lens), 1) if ui_lens else 0.0
5728
+ # inter-compiler variance: mean pairwise normalized structural distance (0 = identical)
5729
+ metrics = [_impl_metrics(p) for p in impl_paths]
5730
+ good = [m for m in metrics if "error" not in m]
5731
+ dists = []
5732
+ for i in range(len(good)):
5733
+ for j in range(i + 1, len(good)):
5734
+ a, b = good[i], good[j]
5735
+ ia, ib = set(a["imports"]), set(b["imports"])
5736
+ jac = (len(ia & ib) / len(ia | ib)) if (ia or ib) else 1.0
5737
+ dloc = abs(a["loc"] - b["loc"]) / max(a["loc"], b["loc"], 1)
5738
+ dast = abs(a["ast_nodes"] - b["ast_nodes"]) / max(a["ast_nodes"], b["ast_nodes"], 1)
5739
+ dists.append((dloc + dast + (1.0 - jac)) / 3.0)
5740
+ rec["variance_score"] = round(sum(dists) / len(dists), 4) if dists else None
5741
+ return rec, []
5742
+
5743
+
5744
+ def _oracle_hash(arm_dir):
5745
+ try:
5746
+ with open(os.path.join(arm_dir, "oracle", "ORACLE.json"), "rb") as fh:
5747
+ return hashlib.sha256(fh.read()).hexdigest()
5748
+ except OSError:
5749
+ return None
5750
+
5751
+
5752
+ def cmd_lang_compare(args):
5753
+ """Compare a FREE-prose arm and a CONTROLLED (EARS+STE) arm of the same canonical package
5754
+ (ADR-019). The two arms MUST share one withheld oracle -- a differing oracle is a mechanical
5755
+ refusal, because the whole comparison rests on the arms targeting the same behaviour. Emits
5756
+ the per-arm metrics, the delta, and a COMPUTED verdict (REDUCED / NO EFFECT / WORSE); a null
5757
+ is a first-class result. Consults no model."""
5758
+ hf, hc = _oracle_hash(args.free), _oracle_hash(args.controlled)
5759
+ if hf is None or hc is None:
5760
+ print("[qa_ledger] lang-compare: an arm has no oracle/ORACLE.json", file=sys.stderr)
5761
+ sys.exit(2)
5762
+ if hf != hc:
5763
+ print("[qa_ledger] lang-compare: the two arms have DIFFERENT oracles (%s.. vs %s..) -- "
5764
+ "the comparison requires the SAME withheld oracle; behaviour must be held fixed "
5765
+ "while only the authoring changes." % (hf[:12], hc[:12]), file=sys.stderr)
5766
+ sys.exit(2)
5767
+ free, ef = _lang_arm_metrics(args.free)
5768
+ ctrl, ec = _lang_arm_metrics(args.controlled)
5769
+ if ef or ec:
5770
+ for e in ef + ec:
5771
+ print("[qa_ledger] lang-compare: %s" % e, file=sys.stderr)
5772
+ sys.exit(2)
5773
+ vf, vc = free["variance_score"], ctrl["variance_score"]
5774
+ d_var = (vc - vf) if (vf is not None and vc is not None) else None
5775
+ d_ui = ctrl["ui_count"] - free["ui_count"]
5776
+ d_green = ctrl["greens"] - free["greens"]
5777
+ pf, pc = free["mean_passrate"], ctrl["mean_passrate"]
5778
+ d_pass = (pc - pf) if (pf is not None and pc is not None) else None
5779
+ # Verdict is BEHAVIOUR-FIRST (the M4 lesson: lower variance toward a WORSE answer is not a
5780
+ # win). A regression is a lost all-green OR a mean pass-rate drop beyond the pass-rate margin.
5781
+ variance_reduced = d_var is not None and d_var <= -_LANG_MARGIN
5782
+ variance_worse = d_var is not None and d_var >= _LANG_MARGIN
5783
+ regressed = (d_green < 0) or (d_pass is not None and d_pass <= -_LANG_PR_MARGIN)
5784
+ if variance_reduced and regressed:
5785
+ verdict = "MIXED" # variance down but behaviour regressed
5786
+ elif variance_reduced:
5787
+ verdict = "REDUCED" # variance down, behaviour held
5788
+ elif variance_worse or regressed:
5789
+ verdict = "WORSE"
5790
+ else:
5791
+ verdict = "NO EFFECT"
5792
+ delta = {"variance_score": round(d_var, 4) if d_var is not None else None,
5793
+ "unresolved_intent_count": round(d_ui, 3), "oracle_green": d_green,
5794
+ "mean_passrate": round(d_pass, 4) if d_pass is not None else None}
5795
+ report = {"free": free, "controlled": ctrl, "delta": delta, "verdict": verdict,
5796
+ "margin": _LANG_MARGIN, "passrate_margin": _LANG_PR_MARGIN, "oracle_shared": True}
5797
+ if args.out:
5798
+ with open(args.out, "w", encoding="utf-8", newline="\n") as fh:
5799
+ fh.write(_render_lang_md(report))
5800
+ if args.json:
5801
+ print(json.dumps(report, indent=2, ensure_ascii=False))
5802
+ else:
5803
+ for a in (free, ctrl):
5804
+ print("LANG %-11s: oracle-green %d/%d · pass-rate %s · variance %s · "
5805
+ "unresolved_intent %.2f (regions %.2f, rationale %.0f chars)"
5806
+ % (a["arm"], a["greens"], a["n"],
5807
+ "%.3f" % a["mean_passrate"] if a["mean_passrate"] is not None else "n/a",
5808
+ "%.4f" % a["variance_score"] if a["variance_score"] is not None else "n/a",
5809
+ a["ui_count"], a["ui_distinct_regions"], a["ui_rationale_len"]))
5810
+ print("DELTA (controlled - free): variance %s · pass-rate %s · unresolved_intent %+.2f "
5811
+ "· green %+d"
5812
+ % ("%+.4f" % delta["variance_score"] if delta["variance_score"] is not None
5813
+ else "n/a",
5814
+ "%+.4f" % delta["mean_passrate"] if delta["mean_passrate"] is not None else "n/a",
5815
+ delta["unresolved_intent_count"], delta["oracle_green"]))
5816
+ print("VERDICT: %s (variance margin %.2f, pass-rate margin %.2f) -- behaviour-first, "
5817
+ "computed from the delta, never decreed" % (verdict, _LANG_MARGIN, _LANG_PR_MARGIN))
5818
+ if args.out:
5819
+ print(" -> %s" % args.out)
5820
+ sys.exit(0)
5821
+
5822
+
5823
+ def _render_lang_md(r):
5824
+ d = r["delta"]
5825
+ lines = ["<!-- GENERATED by qa_ledger.py lang-compare (ADR-019) -- measured run; do not "
5826
+ "hand-edit. -->", "", "# CONTROLLED-LANGUAGE-REPORT", "",
5827
+ "The same canonical package compiled by the same models from **free prose** (arm A) "
5828
+ "and an **EARS+STE rewrite** (arm B), judged by one **shared withheld oracle** "
5829
+ "(behaviour held fixed; only the authoring changes). The verdict is computed from "
5830
+ "the delta.", "",
5831
+ "| Arm | Oracle-green | Mean pass-rate | Inter-compiler variance | unresolved_intent (count · regions · rationale chars) |",
5832
+ "|-----|--------------|----------------|-------------------------|-------------------------------------------------------|"]
5833
+ for a in (r["free"], r["controlled"]):
5834
+ vs = "%.4f" % a["variance_score"] if a["variance_score"] is not None else "n/a"
5835
+ pr = "%.3f" % a["mean_passrate"] if a["mean_passrate"] is not None else "n/a"
5836
+ lines.append("| %s | %d/%d | %s | %s | %.2f · %.2f · %.0f |"
5837
+ % (a["arm"], a["greens"], a["n"], pr, vs, a["ui_count"],
5838
+ a["ui_distinct_regions"], a["ui_rationale_len"]))
5839
+ dv = "%+.4f" % d["variance_score"] if d["variance_score"] is not None else "n/a"
5840
+ dp = "%+.4f" % d["mean_passrate"] if d.get("mean_passrate") is not None else "n/a"
5841
+ lines += ["", "**Delta (controlled − free):** variance %s · mean pass-rate %s · "
5842
+ "unresolved_intent %+.2f · oracle-green %+d."
5843
+ % (dv, dp, d["unresolved_intent_count"], d["oracle_green"]), "",
5844
+ "## Verdict: %s" % r["verdict"], "",
5845
+ {"REDUCED": "Controlled authoring reduced inter-compiler variance beyond the %.2f "
5846
+ "margin WITHOUT a behavioural regression — for this subsystem, at this "
5847
+ "sample size." % r["margin"],
5848
+ "MIXED": "Controlled authoring reduced inter-compiler variance beyond the %.2f "
5849
+ "margin, BUT mean oracle pass-rate regressed beyond the %.2f pass-rate "
5850
+ "margin (or an all-green was lost): the compilers agreed MORE, on a "
5851
+ "marginally WORSE behaviour. Lower variance is not a win when it converges "
5852
+ "toward a worse answer — the honest, two-part finding."
5853
+ % (r["margin"], r.get("passrate_margin", 0.02)),
5854
+ "NO EFFECT": "Within the margins: controlled authoring did not measurably change "
5855
+ "the delta here. A null result, reported as a null — not a failure.",
5856
+ "WORSE": "Controlled authoring increased variance, or regressed behaviour (lost an "
5857
+ "all-green or dropped mean pass-rate) beyond the margins — reported "
5858
+ "honestly."}[r["verdict"]],
5859
+ "", "*The oracle is byte-identical across both arms, so behaviour is held fixed; "
5860
+ "the only variable is the authoring discipline. The judgement of \"same semantic "
5861
+ "content\" between the two canonical packages is human — a stated limitation.*", ""]
5862
+ return "\n".join(lines)
5863
+
5864
+
5662
5865
  # --------------------------------------------------------------------------- #
5663
5866
  # facts (T0 / SYSTEM-FACTS: public claims become compiled artifacts of repo
5664
5867
  # facts -- Diamond applied to Diamond. ADR-012.)
@@ -9782,6 +9985,17 @@ def build_parser():
9782
9985
  pbn.add_argument("--json", action="store_true")
9783
9986
  pbn.set_defaults(func=cmd_bench)
9784
9987
 
9988
+ plc = sub.add_parser(
9989
+ "lang-compare",
9990
+ help="controlled-language arm (ADR-019): compare a FREE-prose arm and an EARS+STE arm of "
9991
+ "the same canonical package, judged by the SAME withheld oracle; the delta on "
9992
+ "variance/unresolved_intent gives a computed REDUCED/NO EFFECT/WORSE verdict")
9993
+ plc.add_argument("--free", required=True, help="the free-prose arm directory")
9994
+ plc.add_argument("--controlled", required=True, help="the EARS+STE arm directory")
9995
+ plc.add_argument("--out", default=None, help="write CONTROLLED-LANGUAGE-REPORT.md here")
9996
+ plc.add_argument("--json", action="store_true")
9997
+ plc.set_defaults(func=cmd_lang_compare)
9998
+
9785
9999
  pcr = sub.add_parser("cleanroom",
9786
10000
  help="run a command against a CLEAN checkout of one commit in a throwaway worktree (ADR-008)")
9787
10001
  pcr.add_argument("--ledger", default="QA-LEDGER.json")
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.75.1",
2
+ "version": "1.76.0",
3
3
  "project": null,
4
4
  "defaults": {
5
5
  "coverage_threshold": 60,