@kaddo/cli 3.25.0 → 3.25.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 (3) hide show
  1. package/README.md +1 -0
  2. package/dist/index.js +45 -11
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -515,6 +515,7 @@ create --from roadmap → owners → guard → explain`.
515
515
  | v3.23.2 | Impact report defaults to `all` scope (accumulated impact), graph built in memory; `--scope active`; `scope_source`/`default_scope` in JSON |
516
516
  | v3.24 | Estimated Savings Model: `kaddo savings` (+ `savings init`, `.kaddo/savings.yml`); evidence-based time/value estimates, confidence; MCP resource + tool |
517
517
  | v3.25 | Guard history & drift trend: `kaddo guard --record`, `kaddo drift`; feeds impact Guard Activity + savings Drift Prevention; MCP drift/guard-history resources + tool |
518
+ | v3.25.1 | Savings guard-history messaging fix: distinguishes "no history" from "history with 0 resolved warnings" (drift prevention available at 0 h) |
518
519
 
519
520
  **Optional modules (installed with `kaddo add`):**
520
521
 
package/dist/index.js CHANGED
@@ -11656,11 +11656,23 @@ function buildSavingsReport(dir, opts = {}, now = /* @__PURE__ */ new Date()) {
11656
11656
  const graphMult = GRAPH_MULT[graphQuality] ?? 0;
11657
11657
  const archH = round2(a.architecture_discovery_hours_saved_when_graph_good * graphMult);
11658
11658
  const guard = buildGuardHistory(dir);
11659
- const driftSavings = guard.available && guard.resolved > 0 ? {
11660
- available: true,
11661
- hours: round2(guard.resolved * a.rework_hours_avoided_per_resolved_drift),
11662
- formula: `${guard.resolved} resolved drift warnings \xD7 ${a.rework_hours_avoided_per_resolved_drift} h`
11663
- } : { available: false, hours: 0, reason: "Guard history is not persisted yet." };
11659
+ let driftSavings;
11660
+ if (!guard.available) {
11661
+ driftSavings = { available: false, hours: 0, reason: "Guard history is not persisted yet." };
11662
+ } else if (guard.resolved > 0) {
11663
+ driftSavings = {
11664
+ available: true,
11665
+ hours: round2(guard.resolved * a.rework_hours_avoided_per_resolved_drift),
11666
+ formula: `${guard.resolved} resolved drift warnings \xD7 ${a.rework_hours_avoided_per_resolved_drift} h`
11667
+ };
11668
+ } else {
11669
+ driftSavings = {
11670
+ available: true,
11671
+ hours: 0,
11672
+ formula: `0 resolved drift warnings \xD7 ${a.rework_hours_avoided_per_resolved_drift} h`,
11673
+ reason: "Guard history exists, but no resolved drift warnings have been recorded yet."
11674
+ };
11675
+ }
11664
11676
  const totalHours = round2(ctxPrepH + reviewH + clarH + onboardH + archH + driftSavings.hours);
11665
11677
  const totalValue = Math.round(totalHours * a.hourly_cost);
11666
11678
  const reasons = [];
@@ -11675,15 +11687,27 @@ function buildSavingsReport(dir, opts = {}, now = /* @__PURE__ */ new Date()) {
11675
11687
  level = "Medium";
11676
11688
  reasons.push("Strong knowledge and graph evidence.");
11677
11689
  }
11678
- if (!guard.available) reasons.push("Guard history is not persisted yet \u2014 avoided rework is not estimated.");
11679
- else reasons.push(`Guard history available (${guard.resolved} resolved drift warning(s)).`);
11690
+ if (!guard.available) {
11691
+ reasons.push("Guard history is not persisted yet \u2014 avoided rework is not estimated.");
11692
+ } else if (guard.resolved > 0) {
11693
+ reasons.push(`Guard history available (${guard.resolved} resolved drift warning(s)).`);
11694
+ } else {
11695
+ reasons.push("Guard history available, but no resolved drift warnings have been recorded yet.");
11696
+ }
11680
11697
  reasons.push(source === "file" ? "Assumptions come from `.kaddo/savings.yml`." : "Savings assumptions are defaults and should be calibrated.");
11681
11698
  const actions = [];
11682
11699
  if (source === "default") actions.push("Run `kaddo savings init` to customize assumptions.");
11683
11700
  actions.push("Calibrate hourly cost and team assumptions with real team data.");
11684
11701
  actions.push("Run `kaddo impact` to verify the underlying evidence quality.");
11685
11702
  actions.push("Use this report as directional evidence, not accounting data.");
11686
- actions.push("Future: persist Guard history to estimate avoided rework.");
11703
+ if (!guard.available) {
11704
+ actions.push("Future: persist Guard history to estimate avoided rework.");
11705
+ } else if (guard.resolved === 0) {
11706
+ actions.push("Continue running `kaddo guard --record` before important commits to capture resolved drift warnings.");
11707
+ if (guard.open > 0) actions.push("Review open drift warnings with `kaddo drift`.");
11708
+ } else {
11709
+ actions.push("Use drift history to calibrate `rework_hours_avoided_per_resolved_drift`.");
11710
+ }
11687
11711
  return {
11688
11712
  generated_at: now.toISOString(),
11689
11713
  project: impact.project,
@@ -11709,7 +11733,9 @@ function buildSavingsReport(dir, opts = {}, now = /* @__PURE__ */ new Date()) {
11709
11733
  graph_nodes: impact.graph_quality.available ? impact.graph_quality.nodes : null,
11710
11734
  graph_edges: impact.graph_quality.available ? impact.graph_quality.edges : null,
11711
11735
  context_readiness: readiness,
11712
- guard_history_available: guard.available
11736
+ guard_history_available: guard.available,
11737
+ guard_runs_recorded: guard.total_runs,
11738
+ resolved_drift_warnings: guard.resolved
11713
11739
  },
11714
11740
  estimated_savings: {
11715
11741
  context_preparation: { hours: ctxPrepH, formula: `${completed} Work Items \xD7 ${a.context_preparation_minutes_saved_per_work_item} min` },
@@ -11759,7 +11785,13 @@ function renderSavingsMarkdown(r) {
11759
11785
  if (e.graph_nodes !== null) L.push(`- Graph nodes: ${e.graph_nodes}`);
11760
11786
  if (e.graph_edges !== null) L.push(`- Graph edges: ${e.graph_edges}`);
11761
11787
  L.push(`- Context readiness: ${e.context_readiness}`);
11762
- L.push("- Guard history: not available");
11788
+ if (e.guard_history_available) {
11789
+ L.push("- Guard history: available");
11790
+ L.push(`- Guard runs recorded: ${e.guard_runs_recorded}`);
11791
+ L.push(`- Resolved drift warnings: ${e.resolved_drift_warnings}`);
11792
+ } else {
11793
+ L.push("- Guard history: not available");
11794
+ }
11763
11795
  L.push("");
11764
11796
  L.push("## Estimated Savings", "");
11765
11797
  const s = r.estimated_savings;
@@ -11776,7 +11808,9 @@ function renderSavingsMarkdown(r) {
11776
11808
  L.push("### Drift Prevention", "");
11777
11809
  if (s.drift_prevention.available) {
11778
11810
  L.push(`- Formula: ${s.drift_prevention.formula}`);
11779
- L.push(`- Estimated: ${s.drift_prevention.hours} h`, "");
11811
+ L.push(`- Estimated: ${s.drift_prevention.hours} h`);
11812
+ if (s.drift_prevention.reason) L.push(`- Reason: ${s.drift_prevention.reason}`);
11813
+ L.push("");
11780
11814
  } else {
11781
11815
  L.push("- Not available yet.");
11782
11816
  L.push(`- Reason: ${s.drift_prevention.reason}`, "");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaddo/cli",
3
- "version": "3.25.0",
3
+ "version": "3.25.1",
4
4
  "description": "Knowledge Driven Development toolkit",
5
5
  "license": "MIT",
6
6
  "repository": {