@kaddo/mcp 3.124.2 → 3.124.4
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/dist/index.js +264 -26
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -10404,6 +10404,29 @@ function buildGuardHistory(dir) {
|
|
|
10404
10404
|
}
|
|
10405
10405
|
|
|
10406
10406
|
// ../cli/src/core/reporting-evidence.ts
|
|
10407
|
+
function graphHintFinding(hint) {
|
|
10408
|
+
const affected = [hint.artifact_id, ...hint.path ? [hint.path] : []];
|
|
10409
|
+
const semantics = {
|
|
10410
|
+
"work-item": { classification: "coverage_gap", priority: "medium", action: "Review whether the active Work Item needs the missing declared relationship." },
|
|
10411
|
+
decision: { classification: "coverage_gap", priority: "low", action: "Review whether this decision should declare governed code paths." },
|
|
10412
|
+
capability: { classification: "coverage_gap", priority: "low", action: "Review whether this capability should connect to existing Work Items; the relationship is optional." },
|
|
10413
|
+
"knowledge-capsule": { classification: "review_hint", priority: "low", action: "Confirm whether this capsule is intended for direct contextual use or Work Item relationships." }
|
|
10414
|
+
};
|
|
10415
|
+
const semantic = semantics[hint.artifact_type];
|
|
10416
|
+
return {
|
|
10417
|
+
id: `graph-hint:${hint.artifact_id}:${hint.missing.join(",")}`,
|
|
10418
|
+
category: "topology",
|
|
10419
|
+
classification: semantic.classification,
|
|
10420
|
+
resolution_status: "open",
|
|
10421
|
+
source: "graph-hints",
|
|
10422
|
+
affected_artifacts: affected,
|
|
10423
|
+
// Graph Hints are intentionally non-blocking; their type determines priority and meaning.
|
|
10424
|
+
priority: semantic.priority,
|
|
10425
|
+
evidence: hint.reason,
|
|
10426
|
+
explanation: hint.message,
|
|
10427
|
+
suggested_action: semantic.action
|
|
10428
|
+
};
|
|
10429
|
+
}
|
|
10407
10430
|
function reportingProjectContext(dir) {
|
|
10408
10431
|
const config = loadConfig(dir);
|
|
10409
10432
|
if (!config) return { state: "unknown", mode: "unknown", repository_structure: "unknown" };
|
|
@@ -10458,7 +10481,11 @@ function buildImpactReport(dir, opts = {}, now = /* @__PURE__ */ new Date()) {
|
|
|
10458
10481
|
const projectContext = reportingProjectContext(dir);
|
|
10459
10482
|
const wis = discoverWorkItems(dir);
|
|
10460
10483
|
const total = wis.length;
|
|
10461
|
-
const
|
|
10484
|
+
const completedWis = wis.filter((wi) => wi.lifecycle === "completed");
|
|
10485
|
+
const verifiedWorkItems = completedWis.filter((wi) => wi.validationStatus === "passed").length;
|
|
10486
|
+
const failedValidationWorkItems = completedWis.filter((wi) => wi.validationStatus === "failed").length;
|
|
10487
|
+
const pendingValidationWorkItems = completedWis.filter((wi) => Boolean(wi.validationStatus) && !["passed", "failed"].includes(wi.validationStatus)).length;
|
|
10488
|
+
const notRecordedValidationWorkItems = completedWis.length - verifiedWorkItems - failedValidationWorkItems - pendingValidationWorkItems;
|
|
10462
10489
|
let withOwnership = 0;
|
|
10463
10490
|
let withSource = 0;
|
|
10464
10491
|
let withInitiative = 0;
|
|
@@ -10531,10 +10558,12 @@ function buildImpactReport(dir, opts = {}, now = /* @__PURE__ */ new Date()) {
|
|
|
10531
10558
|
}
|
|
10532
10559
|
const ownershipOverlaps = gaps.ownership_overlaps.length;
|
|
10533
10560
|
let g;
|
|
10561
|
+
let graphHintEntries = [];
|
|
10534
10562
|
const config = loadConfig(dir);
|
|
10535
10563
|
if (config) {
|
|
10536
10564
|
const graph = buildGraph(dir, config, { scope: resolvedScope }, now);
|
|
10537
10565
|
const hints = buildGraphHints(dir, graph, now);
|
|
10566
|
+
graphHintEntries = hints.hints;
|
|
10538
10567
|
g = { available: true, scope: graph.scope, scopeReason: graph.scope_reason, nodes: graph.nodes.length, edges: graph.edges.length, quality: hints.quality, hints: hints.summary.hints, generatedAt: graph.generated_at };
|
|
10539
10568
|
} else {
|
|
10540
10569
|
g = { available: false, scope: resolvedScope, scopeReason: "", nodes: 0, edges: 0, quality: "unknown", hints: 0, generatedAt: "" };
|
|
@@ -10607,6 +10636,56 @@ function buildImpactReport(dir, opts = {}, now = /* @__PURE__ */ new Date()) {
|
|
|
10607
10636
|
ai_context_readiness: aiReady,
|
|
10608
10637
|
maintenance_readiness: levelFromRatio((coverageRatio(withOwnership) + (deliveryTraceable ? 1 : 0)) / 2)
|
|
10609
10638
|
};
|
|
10639
|
+
const baselineLayers = projectContext.mode === "poc" ? ["Tech", "Delivery"] : ["Business", "Product", "Tech", "Delivery"];
|
|
10640
|
+
const findings = [];
|
|
10641
|
+
for (const layer2 of baselineLayers) {
|
|
10642
|
+
const status = layerStatus(layer2);
|
|
10643
|
+
if (status !== "Weak" && status !== "Missing") continue;
|
|
10644
|
+
findings.push({
|
|
10645
|
+
id: `knowledge-health:${layer2.toLowerCase()}`,
|
|
10646
|
+
category: "knowledge",
|
|
10647
|
+
classification: "coverage_gap",
|
|
10648
|
+
resolution_status: "open",
|
|
10649
|
+
source: "knowledge-health",
|
|
10650
|
+
affected_artifacts: [layer2],
|
|
10651
|
+
priority: status === "Missing" ? "medium" : "low",
|
|
10652
|
+
evidence: `${layer2} knowledge maturity is ${status}.`,
|
|
10653
|
+
explanation: `This assesses documented ${layer2} knowledge, not the quality of the product or implementation.`,
|
|
10654
|
+
suggested_action: `Review ${layer2} knowledge coverage and the artifacts or relationships available for it.`
|
|
10655
|
+
});
|
|
10656
|
+
}
|
|
10657
|
+
for (const gap of gaps.missing_code_ownership) {
|
|
10658
|
+
findings.push({
|
|
10659
|
+
id: `ownership:${gap.id}`,
|
|
10660
|
+
category: "delivery",
|
|
10661
|
+
classification: "coverage_gap",
|
|
10662
|
+
resolution_status: "open",
|
|
10663
|
+
source: "work-item-ownership",
|
|
10664
|
+
affected_artifacts: [gap.id, gap.path],
|
|
10665
|
+
priority: "medium",
|
|
10666
|
+
evidence: "A corrective Work Item has no declared code ownership.",
|
|
10667
|
+
explanation: gap.title,
|
|
10668
|
+
suggested_action: "Review and add relevant code ownership declarations."
|
|
10669
|
+
});
|
|
10670
|
+
}
|
|
10671
|
+
for (const wi of completedWis) {
|
|
10672
|
+
if (!wi.validationStatus || !["not-started", "in-progress", "partial", "failed", "blocked"].includes(wi.validationStatus)) continue;
|
|
10673
|
+
findings.push({
|
|
10674
|
+
id: `completion-validation:${wi.id || wi.title}`,
|
|
10675
|
+
category: "delivery",
|
|
10676
|
+
classification: "review_hint",
|
|
10677
|
+
resolution_status: "open",
|
|
10678
|
+
source: "work-item-lifecycle",
|
|
10679
|
+
affected_artifacts: [wi.id || wi.title, wi.relPath],
|
|
10680
|
+
priority: "medium",
|
|
10681
|
+
evidence: `Lifecycle is completed while persisted validation is ${wi.validationStatus}.`,
|
|
10682
|
+
explanation: "This requires review against the Work Item completion contract; it is not automatically a failed or invalid completion.",
|
|
10683
|
+
suggested_action: "Review the validation evidence and confirm whether the completed lifecycle state is consistent with the Work Item completion contract."
|
|
10684
|
+
});
|
|
10685
|
+
}
|
|
10686
|
+
findings.push(...graphHintEntries.map(graphHintFinding));
|
|
10687
|
+
const priorityOrder = { high: 0, medium: 1, low: 2, unknown: 3 };
|
|
10688
|
+
findings.sort((a2, b2) => priorityOrder[a2.priority] - priorityOrder[b2.priority] || a2.id.localeCompare(b2.id));
|
|
10610
10689
|
let score = null;
|
|
10611
10690
|
let score_breakdown = null;
|
|
10612
10691
|
if (total > 0) {
|
|
@@ -10644,17 +10723,18 @@ function buildImpactReport(dir, opts = {}, now = /* @__PURE__ */ new Date()) {
|
|
|
10644
10723
|
else if (g.scope === "active" && g.quality === "empty") actions.push("Run `kaddo impact --scope all` to measure accumulated knowledge impact.");
|
|
10645
10724
|
if (exp.roadmap.remaining > 0) actions.push(`Materialize the ${exp.roadmap.remaining} remaining roadmap candidate(s) with \`kaddo create --from roadmap\`.`);
|
|
10646
10725
|
for (const a2 of [
|
|
10647
|
-
groupedAction(gaps.
|
|
10648
|
-
groupedAction(gaps.missing_source, "Add `source`/`source_id` to"),
|
|
10649
|
-
groupedAction(gaps.missing_acceptance_criteria, "Add Acceptance Criteria to"),
|
|
10650
|
-
groupedAction(gaps.missing_definition_of_done, "Add a Definition of Done to"),
|
|
10651
|
-
groupedAction(gaps.missing_validation, "Add a validation (How to test it) section to")
|
|
10726
|
+
groupedAction(gaps.missing_source, "Add `source`/`source_id` to")
|
|
10652
10727
|
]) if (a2) actions.push(a2);
|
|
10653
10728
|
if (gaps.broad_ownership_globs.length > 0) actions.push(`Narrow ${gaps.broad_ownership_globs.length} broad ownership glob(s) into specific paths.`);
|
|
10654
|
-
|
|
10729
|
+
for (const finding of findings) {
|
|
10730
|
+
if (!actions.includes(finding.suggested_action)) actions.push(finding.suggested_action);
|
|
10731
|
+
}
|
|
10655
10732
|
if (skills.length === 0) actions.push("Install reusable skills with `kaddo add skills`.");
|
|
10656
10733
|
actions.push("Run `kaddo guard` before committing to catch knowledge drift.");
|
|
10657
10734
|
const summary = [];
|
|
10735
|
+
if (completedWis.length > 0) {
|
|
10736
|
+
summary.push(`Delivery evidence: ${completedWis.length} completed; ${verifiedWorkItems} validation passed; ${notRecordedValidationWorkItems} not confirmed by persisted validation.`);
|
|
10737
|
+
}
|
|
10658
10738
|
if (total > 0) summary.push(`${withOwnership}/${total} Work Items include code ownership.`);
|
|
10659
10739
|
if (g.available) summary.push(`The knowledge graph is ${g.quality} with ${g.nodes} nodes and ${g.edges} edges (${g.scope} scope).`);
|
|
10660
10740
|
else summary.push("The knowledge graph has not been exported yet.");
|
|
@@ -10676,6 +10756,15 @@ function buildImpactReport(dir, opts = {}, now = /* @__PURE__ */ new Date()) {
|
|
|
10676
10756
|
default_scope: "all",
|
|
10677
10757
|
scope_source: scopeSource,
|
|
10678
10758
|
executive_summary: summary,
|
|
10759
|
+
delivery_evidence: {
|
|
10760
|
+
completed: completedWis.length,
|
|
10761
|
+
validation_passed: verifiedWorkItems,
|
|
10762
|
+
validation_failed: failedValidationWorkItems,
|
|
10763
|
+
validation_pending: pendingValidationWorkItems,
|
|
10764
|
+
validation_not_recorded: notRecordedValidationWorkItems,
|
|
10765
|
+
completion_with_passed_validation_percent: completedWis.length > 0 ? Math.round(verifiedWorkItems / completedWis.length * 1e3) / 10 : null
|
|
10766
|
+
},
|
|
10767
|
+
findings,
|
|
10679
10768
|
knowledge_health,
|
|
10680
10769
|
knowledge_coverage,
|
|
10681
10770
|
ownership_coverage: {
|
|
@@ -10721,7 +10810,7 @@ function buildImpactReport(dir, opts = {}, now = /* @__PURE__ */ new Date()) {
|
|
|
10721
10810
|
function ratio(have, total) {
|
|
10722
10811
|
return `${have}/${total}`;
|
|
10723
10812
|
}
|
|
10724
|
-
function renderImpactMarkdown(r2) {
|
|
10813
|
+
function renderImpactMarkdown(r2, opts = {}) {
|
|
10725
10814
|
const L = [];
|
|
10726
10815
|
L.push("# Kaddo Knowledge Impact Report", "");
|
|
10727
10816
|
L.push(`Generated at: ${r2.generated_at}`);
|
|
@@ -10739,6 +10828,27 @@ function renderImpactMarkdown(r2) {
|
|
|
10739
10828
|
L.push("## Executive Summary", "");
|
|
10740
10829
|
for (const s2 of r2.executive_summary) L.push(`- ${s2}`);
|
|
10741
10830
|
L.push("");
|
|
10831
|
+
L.push("## Key Findings", "");
|
|
10832
|
+
if (r2.findings.length === 0) L.push("No current findings detected by the executed deterministic checks.");
|
|
10833
|
+
if (r2.findings.length > 0) {
|
|
10834
|
+
const cell = (value) => value.replace(/\|/g, "\\|").replace(/\r?\n/g, " ");
|
|
10835
|
+
L.push("| Classification | Priority | Status | Source | Affected | Finding | Suggested action |");
|
|
10836
|
+
L.push("|---|---|---|---|---|---|---|");
|
|
10837
|
+
for (const finding of r2.findings) {
|
|
10838
|
+
L.push(`| ${finding.classification} | ${finding.priority} | ${finding.resolution_status} | ${cell(finding.source)} | ${cell(finding.affected_artifacts.join(", ") || "not available")} | ${cell(finding.explanation)} Evidence: ${cell(finding.evidence)} | ${cell(finding.suggested_action)} |`);
|
|
10839
|
+
}
|
|
10840
|
+
}
|
|
10841
|
+
L.push("");
|
|
10842
|
+
L.push("## Delivery Evidence", "");
|
|
10843
|
+
const de = r2.delivery_evidence;
|
|
10844
|
+
L.push(`- Completed Work Items: ${de.completed}`);
|
|
10845
|
+
L.push(`- Validation passed: ${de.validation_passed}`);
|
|
10846
|
+
L.push(`- Validation failed: ${de.validation_failed}`);
|
|
10847
|
+
L.push(`- Validation pending: ${de.validation_pending}`);
|
|
10848
|
+
L.push(`- Validation not recorded: ${de.validation_not_recorded}`);
|
|
10849
|
+
L.push(`- Completion with passed validation: ${de.completion_with_passed_validation_percent === null ? "not available" : `${de.completion_with_passed_validation_percent}%`}`);
|
|
10850
|
+
L.push("- \u201CNot recorded\u201D means persisted evidence is absent; it does not prove validation never happened.");
|
|
10851
|
+
L.push("");
|
|
10742
10852
|
L.push("## Evidence and Applicability", "");
|
|
10743
10853
|
for (const item of r2.evidence) L.push(`- ${item.label}: ${item.classification} \u2014 ${item.reason}`);
|
|
10744
10854
|
L.push("");
|
|
@@ -10837,14 +10947,9 @@ function renderImpactMarkdown(r2) {
|
|
|
10837
10947
|
}
|
|
10838
10948
|
L.push("");
|
|
10839
10949
|
};
|
|
10840
|
-
gapSection("Work Items missing source", gp.missing_source);
|
|
10841
|
-
gapSection("Work Items missing
|
|
10842
|
-
|
|
10843
|
-
gapSection("Work Items missing knowledge level", gp.missing_knowledge_level);
|
|
10844
|
-
gapSection("Work Items missing acceptance criteria", gp.missing_acceptance_criteria);
|
|
10845
|
-
gapSection("Work Items missing Definition of Done", gp.missing_definition_of_done);
|
|
10846
|
-
gapSection("Work Items missing validation", gp.missing_validation);
|
|
10847
|
-
if (gp.broad_ownership_globs.length > 0) {
|
|
10950
|
+
if (opts.details) gapSection("Work Items missing source", gp.missing_source);
|
|
10951
|
+
if (opts.details) gapSection("Work Items missing code ownership", gp.missing_code_ownership);
|
|
10952
|
+
if (opts.details && gp.broad_ownership_globs.length > 0) {
|
|
10848
10953
|
L.push("### Broad ownership globs", "");
|
|
10849
10954
|
for (const b2 of gp.broad_ownership_globs) {
|
|
10850
10955
|
L.push(`- ${b2.id} \u2014 ${b2.title}`);
|
|
@@ -10855,17 +10960,43 @@ function renderImpactMarkdown(r2) {
|
|
|
10855
10960
|
}
|
|
10856
10961
|
if (gp.ownership_overlaps.length > 0) {
|
|
10857
10962
|
L.push("### Shared code-path history (review only)", "");
|
|
10858
|
-
|
|
10859
|
-
|
|
10860
|
-
|
|
10861
|
-
|
|
10963
|
+
if (opts.details) {
|
|
10964
|
+
for (const o2 of gp.ownership_overlaps) {
|
|
10965
|
+
L.push(`- \`${o2.code_path}\``);
|
|
10966
|
+
L.push(` - Owned by: ${o2.work_items.join(", ")}`);
|
|
10967
|
+
L.push(` - Suggested action: ${o2.suggested_action}`);
|
|
10968
|
+
}
|
|
10969
|
+
} else {
|
|
10970
|
+
L.push(`- ${gp.ownership_overlaps.length} shared path declaration(s) detected. These are historical relationships, not necessarily ownership conflicts.`);
|
|
10971
|
+
const areas = gp.ownership_overlaps.slice(0, 3).map((o2) => `\`${o2.code_path}\``);
|
|
10972
|
+
if (areas.length > 0) L.push(`- Most involved paths: ${areas.join(", ")}.`);
|
|
10973
|
+
L.push("- Run `kaddo impact --details` for the complete shared-path inventory.");
|
|
10862
10974
|
}
|
|
10863
10975
|
L.push("");
|
|
10864
10976
|
}
|
|
10865
|
-
const anyGaps = gp.missing_source.length + gp.
|
|
10977
|
+
const anyGaps = gp.missing_source.length + gp.missing_code_ownership.length + gp.broad_ownership_globs.length;
|
|
10866
10978
|
if (anyGaps === 0) {
|
|
10867
10979
|
L.push("No actionable knowledge gaps detected. \u{1F389}", "");
|
|
10980
|
+
} else if (!opts.details) {
|
|
10981
|
+
L.push("- Current actionable items are listed in Key Findings. Run `kaddo impact --details` for the full artifact inventory.");
|
|
10982
|
+
L.push("");
|
|
10983
|
+
}
|
|
10984
|
+
const historical = [
|
|
10985
|
+
["knowledge level", gp.missing_knowledge_level],
|
|
10986
|
+
["Acceptance Criteria", gp.missing_acceptance_criteria],
|
|
10987
|
+
["Definition of Done", gp.missing_definition_of_done],
|
|
10988
|
+
["validation section", gp.missing_validation]
|
|
10989
|
+
];
|
|
10990
|
+
L.push("## Historical Documentation Completeness", "");
|
|
10991
|
+
for (const [label, items] of historical) {
|
|
10992
|
+
const completed = items.filter((item) => item.status === "completed");
|
|
10993
|
+
if (completed.length > 0) L.push(`- Completed Work Items without detected ${label}: ${completed.length}`);
|
|
10994
|
+
}
|
|
10995
|
+
if (!historical.some(([, items]) => items.some((item) => item.status === "completed"))) {
|
|
10996
|
+
L.push("No historical documentation completeness gaps were detected.");
|
|
10868
10997
|
}
|
|
10998
|
+
L.push("- This is an inventory for review, not a recommendation to rewrite historical Work Items merely to increase a metric.");
|
|
10999
|
+
L.push("");
|
|
10869
11000
|
if (r2.score_breakdown) {
|
|
10870
11001
|
L.push("## Score Breakdown", "");
|
|
10871
11002
|
const b2 = r2.score_breakdown;
|
|
@@ -11015,6 +11146,16 @@ function buildSavingsReport(dir, opts = {}, now = /* @__PURE__ */ new Date()) {
|
|
|
11015
11146
|
} else {
|
|
11016
11147
|
actions.push("Use drift history to calibrate `rework_hours_avoided_per_resolved_drift`.");
|
|
11017
11148
|
}
|
|
11149
|
+
const calibrationOpportunities = !a2.calibrated_at ? {
|
|
11150
|
+
available: true,
|
|
11151
|
+
reason: source3 === "default" ? "Default assumptions are uncalibrated estimates." : "Project assumptions are not marked as calibrated.",
|
|
11152
|
+
opportunities: [
|
|
11153
|
+
{ area: "Context preparation", suggested_evidence: "Compare preparation effort on comparable tasks before and after using the knowledge artifacts." },
|
|
11154
|
+
{ area: "Review effort", suggested_evidence: "Record a baseline for comparable reviews with similar ownership coverage." },
|
|
11155
|
+
{ area: "Clarification reduction", suggested_evidence: "Estimate effort spent resolving repeated scope or context questions." },
|
|
11156
|
+
{ area: "Architecture discovery", suggested_evidence: "Compare discovery time for similar dependency or relationship analyses." }
|
|
11157
|
+
]
|
|
11158
|
+
} : { available: false, reason: `Assumptions are marked as calibrated on ${a2.calibrated_at}.`, opportunities: [] };
|
|
11018
11159
|
return {
|
|
11019
11160
|
generated_at: now.toISOString(),
|
|
11020
11161
|
project: impact.project,
|
|
@@ -11066,6 +11207,7 @@ function buildSavingsReport(dir, opts = {}, now = /* @__PURE__ */ new Date()) {
|
|
|
11066
11207
|
},
|
|
11067
11208
|
total: { estimated_hours_saved: observedHours, estimated_value: observedValue, currency: a2.currency },
|
|
11068
11209
|
confidence: { level, reasons },
|
|
11210
|
+
calibration_opportunities: calibrationOpportunities,
|
|
11069
11211
|
suggested_actions: actions
|
|
11070
11212
|
};
|
|
11071
11213
|
}
|
|
@@ -11100,7 +11242,7 @@ function renderSavingsMarkdown(r2) {
|
|
|
11100
11242
|
L.push("");
|
|
11101
11243
|
L.push("## Evidence Used", "");
|
|
11102
11244
|
const e = r2.evidence;
|
|
11103
|
-
L.push(`- Knowledge Impact Score: ${e.knowledge_impact_score ?? "not available"}${e.knowledge_impact_score !== null ? "/100" : ""}`);
|
|
11245
|
+
L.push(`- Legacy Knowledge Impact Score: ${e.knowledge_impact_score ?? "not available"}${e.knowledge_impact_score !== null ? "/100" : ""} (deprecated; informational only and not used for confidence)`);
|
|
11104
11246
|
L.push(`- Completed Work Items: ${e.completed_work_items}`);
|
|
11105
11247
|
L.push(`- Ownership coverage: ${e.ownership_coverage_percent}%`);
|
|
11106
11248
|
L.push(`- Work Items with Acceptance Criteria: ${e.work_items_with_acceptance_criteria}`);
|
|
@@ -11147,6 +11289,17 @@ function renderSavingsMarkdown(r2) {
|
|
|
11147
11289
|
L.push(`Confidence: ${r2.confidence.level}`, "", "Reason:");
|
|
11148
11290
|
for (const reason of r2.confidence.reasons) L.push(`- ${reason}`);
|
|
11149
11291
|
L.push("");
|
|
11292
|
+
L.push("## Calibration Opportunities", "");
|
|
11293
|
+
if (!r2.calibration_opportunities.available) {
|
|
11294
|
+
L.push(`- ${r2.calibration_opportunities.reason}`);
|
|
11295
|
+
} else {
|
|
11296
|
+
L.push(`- ${r2.calibration_opportunities.reason}`);
|
|
11297
|
+
L.push("- Use external, aggregate project observations; do not collect or store personal data.");
|
|
11298
|
+
for (const opportunity of r2.calibration_opportunities.opportunities) {
|
|
11299
|
+
L.push(`- ${opportunity.area}: ${opportunity.suggested_evidence}`);
|
|
11300
|
+
}
|
|
11301
|
+
}
|
|
11302
|
+
L.push("");
|
|
11150
11303
|
L.push("## Suggested Actions", "");
|
|
11151
11304
|
r2.suggested_actions.forEach((act, i) => L.push(`${i + 1}. ${act}`));
|
|
11152
11305
|
L.push("");
|
|
@@ -11164,13 +11317,49 @@ function buildDriftReport(dir, now = /* @__PURE__ */ new Date()) {
|
|
|
11164
11317
|
const workItems = discoverWorkItems(dir);
|
|
11165
11318
|
const verificationEvidence = workItems.filter((wi) => wi.validationStatus && wi.validationStatus !== "not-started");
|
|
11166
11319
|
const plans = getDeprecationPlans(dir);
|
|
11167
|
-
const
|
|
11320
|
+
const planDetails = plans.map((plan) => getDeprecationPlan(dir, plan.id)).filter((plan) => plan !== null);
|
|
11321
|
+
const plansWithoutTargets = planDetails.filter((plan) => plan.targets.length === 0);
|
|
11322
|
+
const plansWithTargets = planDetails.filter((plan) => plan.targets.length > 0);
|
|
11323
|
+
const targetFindingsByPlan = new Map(plansWithTargets.map((plan) => [
|
|
11324
|
+
plan.id,
|
|
11325
|
+
plan.targets.flatMap(validateTarget)
|
|
11326
|
+
]));
|
|
11327
|
+
const deprecationFindings = [...targetFindingsByPlan.values()].flat();
|
|
11328
|
+
const plansWithoutStructuralFindings = plansWithTargets.filter((plan) => (targetFindingsByPlan.get(plan.id) ?? []).length === 0);
|
|
11168
11329
|
const config = loadConfig(dir);
|
|
11169
11330
|
const topology = config ? buildGraph(dir, config, { scope: "all" }, now) : null;
|
|
11170
|
-
const
|
|
11331
|
+
const graphHints = topology ? buildGraphHints(dir, topology, now) : null;
|
|
11332
|
+
const topologyHints = graphHints?.summary.hints ?? null;
|
|
11333
|
+
const currentConsistencyFindings = [
|
|
11334
|
+
...graphHints?.hints.map(graphHintFinding) ?? [],
|
|
11335
|
+
...deprecationFindings.map((finding, index) => ({
|
|
11336
|
+
id: `deprecation-target:${index + 1}`,
|
|
11337
|
+
category: "consistency",
|
|
11338
|
+
classification: "consistency_violation",
|
|
11339
|
+
resolution_status: "open",
|
|
11340
|
+
source: "deprecation-target-validation",
|
|
11341
|
+
affected_artifacts: finding.target ? [finding.target] : [],
|
|
11342
|
+
priority: finding.severity === "error" ? "high" : "medium",
|
|
11343
|
+
evidence: finding.message,
|
|
11344
|
+
explanation: "A deterministic deprecation target consistency check reported a finding.",
|
|
11345
|
+
suggested_action: "Review the affected deprecation target and its declared lifecycle evidence."
|
|
11346
|
+
})),
|
|
11347
|
+
...h2.available && h2.total_runs >= 2 ? h2.threads.filter((thread) => thread.status === "open").map((thread) => ({
|
|
11348
|
+
id: `guard-history:${thread.code_path}`,
|
|
11349
|
+
category: "consistency",
|
|
11350
|
+
classification: "historical_drift",
|
|
11351
|
+
resolution_status: "open",
|
|
11352
|
+
source: "guard-history",
|
|
11353
|
+
affected_artifacts: [thread.code_path, ...thread.related_artifacts],
|
|
11354
|
+
priority: "medium",
|
|
11355
|
+
evidence: `Recorded Guard observations from ${thread.first_detected} through ${thread.last_seen} remain unresolved.`,
|
|
11356
|
+
explanation: "Comparable Guard runs observed a possible code/knowledge drift thread over time.",
|
|
11357
|
+
suggested_action: "Review the recorded drift thread and update the relevant knowledge or ownership evidence."
|
|
11358
|
+
})) : []
|
|
11359
|
+
];
|
|
11171
11360
|
const actions = [];
|
|
11172
11361
|
if (!h2.available) {
|
|
11173
|
-
actions.push("
|
|
11362
|
+
actions.push("Start recording Guard runs at relevant delivery checkpoints with `kaddo guard --record`; one run creates an observation, while multiple comparable runs are needed for a historical trend.");
|
|
11174
11363
|
} else {
|
|
11175
11364
|
if (h2.open > 0) actions.push("Review open drift warnings and update related Work Items or ownership.");
|
|
11176
11365
|
actions.push("Run `kaddo guard --record` before important commits.");
|
|
@@ -11183,9 +11372,19 @@ function buildDriftReport(dir, now = /* @__PURE__ */ new Date()) {
|
|
|
11183
11372
|
consistency_evidence: [
|
|
11184
11373
|
{ id: "guard-current-consistency", label: "Current Guard consistency", classification: h2.available ? "observed" : "unknown", reason: h2.available ? `${h2.total_runs} recorded Guard run(s) provide deterministic consistency evidence.` : "No recorded Guard history is available." },
|
|
11185
11374
|
{ id: "lifecycle-consistency", label: "Lifecycle evidence consistency", classification: verificationEvidence.length > 0 ? "observed" : "unknown", reason: verificationEvidence.length > 0 ? `${verificationEvidence.length} Work Item(s) persist an implementation validation status.` : "No persisted Work Item validation status is available." },
|
|
11186
|
-
{ id: "deprecation-consistency", label: "Deprecation consistency", classification: plans.length === 0 ? "not_applicable" : deprecationFindings.length === 0 ? "derived" : "observed", reason: plans.length === 0 ? "No deprecation plans exist in this project." : deprecationFindings.length === 0 ? `${
|
|
11375
|
+
{ id: "deprecation-consistency", label: "Deprecation consistency", classification: plans.length === 0 ? "not_applicable" : plansWithTargets.length === 0 ? "unknown" : deprecationFindings.length === 0 ? "derived" : "observed", reason: plans.length === 0 ? "No deprecation plans exist in this project." : plansWithTargets.length === 0 ? `${plansWithoutTargets.length} plan(s) have no targets, so target consistency was not evaluated.` : deprecationFindings.length === 0 ? `${plansWithTargets.length} plan(s) with targets passed deterministic target consistency checks; ${plansWithoutTargets.length} plan(s) remain unevaluated because they have no targets.` : `${deprecationFindings.length} deterministic deprecation consistency finding(s) were detected.` },
|
|
11187
11376
|
{ id: "topology-consistency", label: "Knowledge topology consistency", classification: topology === null ? "unknown" : topologyHints === 0 ? "derived" : "observed", reason: topology === null ? "No project configuration is available to construct the topology." : topologyHints === 0 ? `The in-memory topology has ${topology.nodes.length} node(s) and no open deterministic hints.` : `The in-memory topology has ${topologyHints} open deterministic hint(s).` }
|
|
11188
11377
|
],
|
|
11378
|
+
current_consistency_findings: currentConsistencyFindings,
|
|
11379
|
+
structural_consistency: {
|
|
11380
|
+
deprecation_target_checks: plans.length === 0 ? "not_applicable" : plansWithTargets.length === 0 ? "not_evaluated" : deprecationFindings.length === 0 ? "passed" : "findings_detected",
|
|
11381
|
+
plans_discovered: plans.length,
|
|
11382
|
+
plans_without_targets: plansWithoutTargets.length,
|
|
11383
|
+
plans_with_targets_evaluated: plansWithTargets.length,
|
|
11384
|
+
structural_findings: deprecationFindings.length,
|
|
11385
|
+
plans_without_structural_findings: plansWithoutStructuralFindings.length,
|
|
11386
|
+
note: plans.length === 0 ? "No deprecation plans exist in this project." : "Target consistency checks validate declared structural state only; they do not verify operational removal from infrastructure, production or external consumers."
|
|
11387
|
+
},
|
|
11189
11388
|
guard_history: {
|
|
11190
11389
|
available: h2.available,
|
|
11191
11390
|
total_runs: h2.total_runs,
|
|
@@ -11211,6 +11410,43 @@ function renderDriftMarkdown(r2) {
|
|
|
11211
11410
|
L.push("## Consistency Evidence", "");
|
|
11212
11411
|
for (const item of r2.consistency_evidence) L.push(`- ${item.label}: ${item.classification} \u2014 ${item.reason}`);
|
|
11213
11412
|
L.push("");
|
|
11413
|
+
const findingGroups = [
|
|
11414
|
+
{ classification: "consistency_violation", title: "Consistency Violations" },
|
|
11415
|
+
{ classification: "coverage_gap", title: "Coverage Gaps" },
|
|
11416
|
+
{ classification: "review_hint", title: "Review Hints" },
|
|
11417
|
+
{ classification: "historical_drift", title: "Historical Drift" }
|
|
11418
|
+
];
|
|
11419
|
+
L.push("## Current Findings Summary", "");
|
|
11420
|
+
for (const group of findingGroups) {
|
|
11421
|
+
const count = r2.current_consistency_findings.filter((finding) => finding.classification === group.classification).length;
|
|
11422
|
+
const unavailable = group.classification === "historical_drift" && !r2.guard_history.available;
|
|
11423
|
+
L.push(`- ${group.title}: ${unavailable ? "not available \u2014 no recorded Guard runs" : count}`);
|
|
11424
|
+
}
|
|
11425
|
+
L.push("");
|
|
11426
|
+
L.push("## Current Consistency Findings", "");
|
|
11427
|
+
if (r2.current_consistency_findings.length === 0) L.push("No findings detected by the executed consistency checks.", "");
|
|
11428
|
+
const cell = (value) => value.replace(/\|/g, "\\|").replace(/\r?\n/g, " ");
|
|
11429
|
+
for (const group of findingGroups) {
|
|
11430
|
+
const findings = r2.current_consistency_findings.filter((finding) => finding.classification === group.classification);
|
|
11431
|
+
if (findings.length === 0) continue;
|
|
11432
|
+
L.push(`### ${group.title}`, "");
|
|
11433
|
+
L.push("| Classification | Priority | Status | Source | Affected | Finding | Suggested action |");
|
|
11434
|
+
L.push("|---|---|---|---|---|---|---|");
|
|
11435
|
+
for (const finding of findings) {
|
|
11436
|
+
L.push(`| ${finding.classification} | ${finding.priority} | ${finding.resolution_status} | ${cell(finding.source)} | ${cell(finding.affected_artifacts.join(", ") || "not available")} | ${cell(finding.explanation)} Evidence: ${cell(finding.evidence)} | ${cell(finding.suggested_action)} |`);
|
|
11437
|
+
}
|
|
11438
|
+
L.push("");
|
|
11439
|
+
}
|
|
11440
|
+
L.push("## Structural Consistency Boundaries", "");
|
|
11441
|
+
L.push(`- Deprecation target checks: ${r2.structural_consistency.deprecation_target_checks}`);
|
|
11442
|
+
L.push(`- Plans discovered: ${r2.structural_consistency.plans_discovered}`);
|
|
11443
|
+
L.push(`- Plans without targets: ${r2.structural_consistency.plans_without_targets}`);
|
|
11444
|
+
L.push(`- Plans with targets evaluated: ${r2.structural_consistency.plans_with_targets_evaluated}`);
|
|
11445
|
+
L.push(`- Structural findings: ${r2.structural_consistency.structural_findings}`);
|
|
11446
|
+
L.push(`- Plans without structural findings: ${r2.structural_consistency.plans_without_structural_findings}`);
|
|
11447
|
+
if (r2.structural_consistency.plans_without_targets > 0) L.push("- Target consistency for plans without targets: not evaluated \u2014 no targets defined.");
|
|
11448
|
+
L.push(`- Note: ${r2.structural_consistency.note}`);
|
|
11449
|
+
L.push("");
|
|
11214
11450
|
if (!r2.guard_history.available) {
|
|
11215
11451
|
L.push("## Guard History", "");
|
|
11216
11452
|
L.push("No guard history recorded yet.");
|
|
@@ -11282,6 +11518,8 @@ function serializeDriftJson(r2) {
|
|
|
11282
11518
|
project: r2.project,
|
|
11283
11519
|
project_context: r2.project_context,
|
|
11284
11520
|
consistency_evidence: r2.consistency_evidence,
|
|
11521
|
+
current_consistency_findings: r2.current_consistency_findings,
|
|
11522
|
+
structural_consistency: r2.structural_consistency,
|
|
11285
11523
|
guard_history: r2.guard_history,
|
|
11286
11524
|
drift_warnings: r2.drift_warnings,
|
|
11287
11525
|
hotspots: r2.hotspots,
|
package/package.json
CHANGED