@andresmassello/uscha 1.56.1 → 1.60.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.
Files changed (30) hide show
  1. package/README.md +3 -3
  2. package/bin/uscha.js +0 -0
  3. package/package.json +2 -1
  4. package/uscha-kit/.claude/skills/uscha-characterize/SKILL.md +18 -0
  5. package/uscha-kit/.claude/skills/uscha-devloop/SKILL.md +21 -0
  6. package/uscha-kit/.claude/skills/uscha-devloop/qa_ledger.py +636 -0
  7. package/uscha-kit/.claude/skills/uscha-mirador/SKILL.md +11 -0
  8. package/uscha-kit/.claude/skills/uscha-mirador/mirador-watch.ps1 +22 -22
  9. package/uscha-kit/.claude/skills/uscha-mirador/mirador-watch.sh +0 -0
  10. package/uscha-kit/.claude/skills/uscha-mirador/mirador.template.html +39 -1
  11. package/uscha-kit/.claude/skills/uscha-status/SKILL.md +8 -0
  12. package/uscha-kit/.claude-plugin/plugin.json +2 -2
  13. package/uscha-kit/.codex-plugin/plugin.json +1 -1
  14. package/uscha-kit/INSTALL.md +128 -128
  15. package/uscha-kit/README.md +90 -1
  16. package/uscha-kit/VERSION +1 -1
  17. package/uscha-kit/hooks/block-approved-writes.py +0 -0
  18. package/uscha-kit/reports/junit/.fastpath-cases.json +1 -0
  19. package/uscha-kit/reports/junit/.goldencov-cases.json +1 -0
  20. package/uscha-kit/reports/junit/.specdrift-cases.json +1 -0
  21. package/uscha-kit/skills/uscha-characterize/SKILL.md +18 -0
  22. package/uscha-kit/skills/uscha-devloop/SKILL.md +21 -0
  23. package/uscha-kit/skills/uscha-devloop/qa_ledger.py +636 -0
  24. package/uscha-kit/skills/uscha-mirador/SKILL.md +11 -0
  25. package/uscha-kit/skills/uscha-mirador/mirador-watch.ps1 +22 -22
  26. package/uscha-kit/skills/uscha-mirador/mirador-watch.sh +0 -0
  27. package/uscha-kit/skills/uscha-mirador/mirador.template.html +39 -1
  28. package/uscha-kit/skills/uscha-status/SKILL.md +8 -0
  29. package/uscha-kit/uscha.config.json +16 -1
  30. package/uscha-kit/workbench-doctor.sh +0 -0
@@ -67,6 +67,17 @@ than inventing a step. Keep the CONTENT in the conversation's language and the l
67
67
  `review_trigger`, `experiment_valid`, `experiment_missing`, and `expired`; top-level
68
68
  `adr_experiments` summarizes open/malformed/expired experiments. This is advisory
69
69
  visibility for measured hypotheses, not readiness scoring.
70
+ - **Fast-path (ADR-003):** `dashboard --json` carries `fast_path` — the latest verdict per
71
+ repo straight from the ledger, or null when none was requested. The template degrades when
72
+ absent, like every other field.
73
+ - **Spec-drift (ADR-005):** `dashboard --json` carries `spec_drift` — the latest advisory
74
+ run (per-document verdicts: SPEC_STALE / CLEAN / UNMAPPED / UNTRACKED) — only when a run
75
+ exists in the ledger; a virgin ledger keeps the exact prior schema. Advisory visibility of
76
+ the spec-maintenance tax, never readiness input.
77
+ - **Modes card:** the template draws one card for both modes — fast-path verdict chips per
78
+ repo (ALLOW green / ESCALATED amber / DENY red) and spec-drift rows per document, labeled
79
+ advisory. The card is hidden entirely when neither key exists (absent block = identical
80
+ view, same rule as the JSON).
70
81
  - **Session telemetry (optional, vendor-reported):** if `.uscha/telemetry.jsonl` exists,
71
82
  the skill aggregates it and MERGES a `telemetry` object into `DATA`. This is the ONE
72
83
  panel that is **narrated by the vendor (Claude Code), not measured by the engine** —
@@ -1,22 +1,22 @@
1
- # mirador-watch.ps1 -- live second-screen mirador (uscha-kit 1.34.0), Windows.
2
- # Regenerates mirador.html every N seconds from the current ledger; the page is rendered
3
- # with a meta-refresh at the same interval, so a browser open on it updates on its own.
4
- #
5
- # Usage (run in a spare terminal, from the project root):
6
- # powershell -NoProfile -File <kit>\.claude\skills\uscha-mirador\mirador-watch.ps1 [-Interval 30]
7
- # then open mirador.html in a browser on your second screen. Ctrl-C to stop.
8
- #
9
- # Overridable via env: ENGINE, LEDGER, TEMPLATE, OUT, PYTHON.
10
- param([int]$Interval = 30)
11
- $here = Split-Path -Parent $MyInvocation.MyCommand.Path
12
- $engine = if ($env:ENGINE) { $env:ENGINE } else { Join-Path $here "..\uscha-devloop\qa_ledger.py" }
13
- $ledger = if ($env:LEDGER) { $env:LEDGER } else { "QA-LEDGER.json" }
14
- $template = if ($env:TEMPLATE) { $env:TEMPLATE } else { Join-Path $here "mirador.template.html" }
15
- $out = if ($env:OUT) { $env:OUT } else { "mirador.html" }
16
- $py = if ($env:PYTHON) { $env:PYTHON } else { "python" }
17
- Write-Host "mirador-watch: regenerating $out every ${Interval}s (Ctrl-C to stop). Open $out in a browser."
18
- while ($true) {
19
- & $py (Join-Path $here "mirador-render.py") --engine $engine --ledger $ledger --template $template --out $out --refresh $Interval --no-open
20
- if ($LASTEXITCODE -ne 0) { Write-Host "mirador-watch: render failed (ledger missing? run uscha-devloop first) -- retrying" }
21
- Start-Sleep -Seconds $Interval
22
- }
1
+ # mirador-watch.ps1 -- live second-screen mirador (uscha-kit 1.34.0), Windows.
2
+ # Regenerates mirador.html every N seconds from the current ledger; the page is rendered
3
+ # with a meta-refresh at the same interval, so a browser open on it updates on its own.
4
+ #
5
+ # Usage (run in a spare terminal, from the project root):
6
+ # powershell -NoProfile -File <kit>\.claude\skills\uscha-mirador\mirador-watch.ps1 [-Interval 30]
7
+ # then open mirador.html in a browser on your second screen. Ctrl-C to stop.
8
+ #
9
+ # Overridable via env: ENGINE, LEDGER, TEMPLATE, OUT, PYTHON.
10
+ param([int]$Interval = 30)
11
+ $here = Split-Path -Parent $MyInvocation.MyCommand.Path
12
+ $engine = if ($env:ENGINE) { $env:ENGINE } else { Join-Path $here "..\uscha-devloop\qa_ledger.py" }
13
+ $ledger = if ($env:LEDGER) { $env:LEDGER } else { "QA-LEDGER.json" }
14
+ $template = if ($env:TEMPLATE) { $env:TEMPLATE } else { Join-Path $here "mirador.template.html" }
15
+ $out = if ($env:OUT) { $env:OUT } else { "mirador.html" }
16
+ $py = if ($env:PYTHON) { $env:PYTHON } else { "python" }
17
+ Write-Host "mirador-watch: regenerating $out every ${Interval}s (Ctrl-C to stop). Open $out in a browser."
18
+ while ($true) {
19
+ & $py (Join-Path $here "mirador-render.py") --engine $engine --ledger $ledger --template $template --out $out --refresh $Interval --no-open
20
+ if ($LASTEXITCODE -ne 0) { Write-Host "mirador-watch: render failed (ledger missing? run uscha-devloop first) -- retrying" }
21
+ Start-Sleep -Seconds $Interval
22
+ }
File without changes
@@ -278,6 +278,11 @@ svg{display:block;width:100%;height:auto}
278
278
  The verdict above is all you need to look at. These roll up into it; they're here if you want to dig.
279
279
  </p>
280
280
  </div>
281
+
282
+ <div class="card col6" id="card-modes" hidden>
283
+ <h2>Fast-path &middot; Spec-drift <span class="n" id="modes-n">&mdash;</span></h2>
284
+ <div class="speclist" id="modes"></div>
285
+ </div>
281
286
  </section>
282
287
 
283
288
  <section class="telemetry" id="telemetry" hidden>
@@ -654,6 +659,39 @@ function renderTelemetry(){
654
659
  if(sec)sec.hidden=false;
655
660
  }
656
661
 
662
+ function renderModes(){
663
+ /* fast_path: latest measured verdict per repo (ADR-003). spec_drift: latest advisory
664
+ run (ADR-005) -- advisory means it never feeds readiness; this card only makes the
665
+ ledger fact visible. BOTH keys are conditional in dashboard --json, so a project
666
+ that never used either sees no card at all (absent block = identical view). */
667
+ const card=$("#card-modes");if(!card)return;
668
+ const fp=DATA.fast_path,sd=DATA.spec_drift;
669
+ if(!fp&&!sd){card.hidden=true;return;}
670
+ const host=$("#modes");host.replaceChildren();
671
+ const parts=[];
672
+ if(fp){
673
+ const cls={ALLOW:"st-done",ESCALATED:"st-prog",DENY:"st-block"};
674
+ Object.keys(fp).forEach(r=>{const e=fp[r]||{};
675
+ append(host,append(node("div","spec"),node("span","id","fast-path"),
676
+ node("span","t",r+(e.intent?(" — "+e.intent):"")),
677
+ node("span","chip "+(cls[e.verdict]||"st-todo"),String(e.verdict||"?"))));});
678
+ parts.push(Object.keys(fp).length+" repo"+(Object.keys(fp).length>1?"s":""));
679
+ }
680
+ if(sd){
681
+ const cls={SPEC_STALE:"st-block",CLEAN:"st-done",UNMAPPED:"st-todo",UNTRACKED:"st-todo"};
682
+ const res=sd.results||[];
683
+ res.forEach(d=>{const extra=d.verdict==="SPEC_STALE"
684
+ ?(" — "+(d.newer_files_total||0)+" file(s) newer than the spec"):"";
685
+ append(host,append(node("div","spec"),node("span","id","spec-drift"),
686
+ node("span","t",String(d.file||"")+extra),
687
+ node("span","chip "+(cls[d.verdict]||"st-todo"),String(d.verdict||"?"))));});
688
+ const stale=res.filter(d=>d.verdict==="SPEC_STALE").length;
689
+ parts.push(stale?stale+" stale spec"+(stale>1?"s":""):"no drift measured");
690
+ host.appendChild(emptyHint("spec-drift is ADVISORY (ADR-005): it prompts a human look, it never gates."));
691
+ }
692
+ $("#modes-n").textContent=parts.join(" · ");
693
+ card.hidden=false;
694
+ }
657
695
  /* ==== status story: cómo viene / qué lo traba / qué sigue — all from measured DATA ==== */
658
696
  function renderStatus(){
659
697
  const sec=$("#status");if(!sec)return;
@@ -741,7 +779,7 @@ function applySnapshot(i){
741
779
  scrub.addEventListener("input",()=>applySnapshot(+scrub.value));
742
780
 
743
781
  /* ==== init ==== */
744
- renderStatus();renderAcceptance();renderAdrs();renderInv();renderHeat();renderLoops();renderSubs();renderExecutionPolicy();renderTelemetry();
782
+ renderStatus();renderModes();renderAcceptance();renderAdrs();renderInv();renderHeat();renderLoops();renderSubs();renderExecutionPolicy();renderTelemetry();
745
783
  $("#asof").textContent=snaps.length?snaps[snaps.length-1].date:"no history yet (readiness --record)";
746
784
  renderTrail(null);
747
785
  </script>
@@ -86,6 +86,14 @@ Line guide:
86
86
  WHEN the evidence was captured — facts do not move without new evidence. If the
87
87
  field is absent (nothing recorded yet), omit the line; never guess a timestamp.
88
88
 
89
+ **Fast-path mode (ADR-003):** if the ledger carries `fast_path` entries, add ONE line to the
90
+ block with the latest verdict per repo (`fast-path: ALLOW (intent...)` / `ESCALATED`). Absent
91
+ entries → no line at all: silence is honest when no mode was requested.
92
+
93
+ **Spec-drift (ADR-005):** if the ledger carries a `spec_drift` run, add ONE line:
94
+ `spec-drift: N stale / M docs (advisory)` — or `spec-drift: no drift measured` when zero are
95
+ stale. Always label it advisory; it never explains a blocked phase. Absent key → no line.
96
+
89
97
  ## Degradation (honest, specific)
90
98
 
91
99
  - `measured` missing entirely → print: *"No measurement recorded yet — the trail
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.56.1",
2
+ "version": "1.60.1",
3
3
  "project": null,
4
4
  "defaults": {
5
5
  "coverage_threshold": 60,
@@ -40,6 +40,21 @@
40
40
  "blocker_critical": 65,
41
41
  "escalation": 75
42
42
  },
43
+ "fast_path": {
44
+ "enabled": true,
45
+ "max_files_changed": 3,
46
+ "max_loc_delta": 80,
47
+ "protected_paths": [
48
+ "**/migrations/**",
49
+ "**/*.approved",
50
+ "db/**"
51
+ ],
52
+ "require_asserting_test": true,
53
+ "forbid_when_golden_touched": false
54
+ },
55
+ "spec_drift": {
56
+ "max_lag_days": 30
57
+ },
43
58
  "static_gate_zero_at": 10,
44
59
  "constitution_file": "CONSTITUTION.md",
45
60
  "rebuild": {
File without changes