@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.
- package/README.md +1 -0
- package/dist/index.js +45 -11
- 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
|
-
|
|
11660
|
-
|
|
11661
|
-
hours:
|
|
11662
|
-
|
|
11663
|
-
|
|
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)
|
|
11679
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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}`, "");
|