@kaddo/mcp 3.124.2 → 3.124.3

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 (2) hide show
  1. package/dist/index.js +169 -14
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -10404,6 +10404,20 @@ 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
+ return {
10410
+ id: `graph-hint:${hint.artifact_id}:${hint.missing.join(",")}`,
10411
+ category: "topology",
10412
+ source: "graph-hints",
10413
+ affected_artifacts: affected,
10414
+ // Graph Hints are intentionally informational; review is useful but not a blocking error.
10415
+ priority: "medium",
10416
+ evidence: hint.reason,
10417
+ explanation: hint.message,
10418
+ suggested_action: `Review the declared relationships for ${hint.artifact_id}${hint.path ? ` at ${hint.path}` : ""}.`
10419
+ };
10420
+ }
10407
10421
  function reportingProjectContext(dir) {
10408
10422
  const config = loadConfig(dir);
10409
10423
  if (!config) return { state: "unknown", mode: "unknown", repository_structure: "unknown" };
@@ -10458,7 +10472,11 @@ function buildImpactReport(dir, opts = {}, now = /* @__PURE__ */ new Date()) {
10458
10472
  const projectContext = reportingProjectContext(dir);
10459
10473
  const wis = discoverWorkItems(dir);
10460
10474
  const total = wis.length;
10461
- const verifiedWorkItems = wis.filter((wi) => wi.validationStatus === "passed").length;
10475
+ const completedWis = wis.filter((wi) => wi.lifecycle === "completed");
10476
+ const verifiedWorkItems = completedWis.filter((wi) => wi.validationStatus === "passed").length;
10477
+ const failedValidationWorkItems = completedWis.filter((wi) => wi.validationStatus === "failed").length;
10478
+ const pendingValidationWorkItems = completedWis.filter((wi) => Boolean(wi.validationStatus) && !["passed", "failed"].includes(wi.validationStatus)).length;
10479
+ const notRecordedValidationWorkItems = completedWis.length - verifiedWorkItems - failedValidationWorkItems - pendingValidationWorkItems;
10462
10480
  let withOwnership = 0;
10463
10481
  let withSource = 0;
10464
10482
  let withInitiative = 0;
@@ -10531,10 +10549,12 @@ function buildImpactReport(dir, opts = {}, now = /* @__PURE__ */ new Date()) {
10531
10549
  }
10532
10550
  const ownershipOverlaps = gaps.ownership_overlaps.length;
10533
10551
  let g;
10552
+ let graphHintEntries = [];
10534
10553
  const config = loadConfig(dir);
10535
10554
  if (config) {
10536
10555
  const graph = buildGraph(dir, config, { scope: resolvedScope }, now);
10537
10556
  const hints = buildGraphHints(dir, graph, now);
10557
+ graphHintEntries = hints.hints;
10538
10558
  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
10559
  } else {
10540
10560
  g = { available: false, scope: resolvedScope, scopeReason: "", nodes: 0, edges: 0, quality: "unknown", hints: 0, generatedAt: "" };
@@ -10607,6 +10627,37 @@ function buildImpactReport(dir, opts = {}, now = /* @__PURE__ */ new Date()) {
10607
10627
  ai_context_readiness: aiReady,
10608
10628
  maintenance_readiness: levelFromRatio((coverageRatio(withOwnership) + (deliveryTraceable ? 1 : 0)) / 2)
10609
10629
  };
10630
+ const baselineLayers = projectContext.mode === "poc" ? ["Tech", "Delivery"] : ["Business", "Product", "Tech", "Delivery"];
10631
+ const findings = [];
10632
+ for (const layer2 of baselineLayers) {
10633
+ const status = layerStatus(layer2);
10634
+ if (status !== "Weak" && status !== "Missing") continue;
10635
+ findings.push({
10636
+ id: `knowledge-health:${layer2.toLowerCase()}`,
10637
+ category: "knowledge",
10638
+ source: "knowledge-health",
10639
+ affected_artifacts: [layer2],
10640
+ priority: status === "Missing" ? "high" : "medium",
10641
+ evidence: `${layer2} knowledge maturity is ${status}.`,
10642
+ explanation: `This assesses documented ${layer2} knowledge, not the quality of the product or implementation.`,
10643
+ suggested_action: `Review ${layer2} knowledge coverage and the artifacts or relationships available for it.`
10644
+ });
10645
+ }
10646
+ for (const gap of gaps.missing_code_ownership) {
10647
+ findings.push({
10648
+ id: `ownership:${gap.id}`,
10649
+ category: "delivery",
10650
+ source: "work-item-ownership",
10651
+ affected_artifacts: [gap.id, gap.path],
10652
+ priority: "medium",
10653
+ evidence: "A corrective Work Item has no declared code ownership.",
10654
+ explanation: gap.title,
10655
+ suggested_action: gap.suggested_action
10656
+ });
10657
+ }
10658
+ findings.push(...graphHintEntries.map(graphHintFinding));
10659
+ const priorityOrder = { high: 0, medium: 1, low: 2, unknown: 3 };
10660
+ findings.sort((a2, b2) => priorityOrder[a2.priority] - priorityOrder[b2.priority] || a2.id.localeCompare(b2.id));
10610
10661
  let score = null;
10611
10662
  let score_breakdown = null;
10612
10663
  if (total > 0) {
@@ -10645,16 +10696,18 @@ function buildImpactReport(dir, opts = {}, now = /* @__PURE__ */ new Date()) {
10645
10696
  if (exp.roadmap.remaining > 0) actions.push(`Materialize the ${exp.roadmap.remaining} remaining roadmap candidate(s) with \`kaddo create --from roadmap\`.`);
10646
10697
  for (const a2 of [
10647
10698
  groupedAction(gaps.missing_code_ownership, "Add `code:` ownership to"),
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")
10699
+ groupedAction(gaps.missing_source, "Add `source`/`source_id` to")
10652
10700
  ]) if (a2) actions.push(a2);
10653
10701
  if (gaps.broad_ownership_globs.length > 0) actions.push(`Narrow ${gaps.broad_ownership_globs.length} broad ownership glob(s) into specific paths.`);
10654
- if (g.available && g.hints > 0) actions.push("Review graph hints (`kaddo://graph-hints` or `.kaddo/graph-hints.md`).");
10702
+ for (const finding of findings) {
10703
+ if (!actions.includes(finding.suggested_action)) actions.push(finding.suggested_action);
10704
+ }
10655
10705
  if (skills.length === 0) actions.push("Install reusable skills with `kaddo add skills`.");
10656
10706
  actions.push("Run `kaddo guard` before committing to catch knowledge drift.");
10657
10707
  const summary = [];
10708
+ if (completedWis.length > 0) {
10709
+ summary.push(`Delivery evidence: ${completedWis.length} completed; ${verifiedWorkItems} validation passed; ${notRecordedValidationWorkItems} not confirmed by persisted validation.`);
10710
+ }
10658
10711
  if (total > 0) summary.push(`${withOwnership}/${total} Work Items include code ownership.`);
10659
10712
  if (g.available) summary.push(`The knowledge graph is ${g.quality} with ${g.nodes} nodes and ${g.edges} edges (${g.scope} scope).`);
10660
10713
  else summary.push("The knowledge graph has not been exported yet.");
@@ -10676,6 +10729,15 @@ function buildImpactReport(dir, opts = {}, now = /* @__PURE__ */ new Date()) {
10676
10729
  default_scope: "all",
10677
10730
  scope_source: scopeSource,
10678
10731
  executive_summary: summary,
10732
+ delivery_evidence: {
10733
+ completed: completedWis.length,
10734
+ validation_passed: verifiedWorkItems,
10735
+ validation_failed: failedValidationWorkItems,
10736
+ validation_pending: pendingValidationWorkItems,
10737
+ validation_not_recorded: notRecordedValidationWorkItems,
10738
+ completion_with_passed_validation_percent: completedWis.length > 0 ? Math.round(verifiedWorkItems / completedWis.length * 1e3) / 10 : null
10739
+ },
10740
+ findings,
10679
10741
  knowledge_health,
10680
10742
  knowledge_coverage,
10681
10743
  ownership_coverage: {
@@ -10739,6 +10801,27 @@ function renderImpactMarkdown(r2) {
10739
10801
  L.push("## Executive Summary", "");
10740
10802
  for (const s2 of r2.executive_summary) L.push(`- ${s2}`);
10741
10803
  L.push("");
10804
+ L.push("## Key Findings", "");
10805
+ if (r2.findings.length === 0) L.push("No current findings detected by the executed deterministic checks.");
10806
+ if (r2.findings.length > 0) {
10807
+ const cell = (value) => value.replace(/\|/g, "\\|").replace(/\r?\n/g, " ");
10808
+ L.push("| Priority | Source | Affected | Finding | Suggested action |");
10809
+ L.push("|---|---|---|---|---|");
10810
+ for (const finding of r2.findings) {
10811
+ L.push(`| ${finding.priority} | ${cell(finding.source)} | ${cell(finding.affected_artifacts.join(", ") || "not available")} | ${cell(finding.explanation)} Evidence: ${cell(finding.evidence)} | ${cell(finding.suggested_action)} |`);
10812
+ }
10813
+ }
10814
+ L.push("");
10815
+ L.push("## Delivery Evidence", "");
10816
+ const de = r2.delivery_evidence;
10817
+ L.push(`- Completed Work Items: ${de.completed}`);
10818
+ L.push(`- Validation passed: ${de.validation_passed}`);
10819
+ L.push(`- Validation failed: ${de.validation_failed}`);
10820
+ L.push(`- Validation pending: ${de.validation_pending}`);
10821
+ L.push(`- Validation not recorded: ${de.validation_not_recorded}`);
10822
+ L.push(`- Completion with passed validation: ${de.completion_with_passed_validation_percent === null ? "not available" : `${de.completion_with_passed_validation_percent}%`}`);
10823
+ L.push("- \u201CNot recorded\u201D means persisted evidence is absent; it does not prove validation never happened.");
10824
+ L.push("");
10742
10825
  L.push("## Evidence and Applicability", "");
10743
10826
  for (const item of r2.evidence) L.push(`- ${item.label}: ${item.classification} \u2014 ${item.reason}`);
10744
10827
  L.push("");
@@ -10838,12 +10921,7 @@ function renderImpactMarkdown(r2) {
10838
10921
  L.push("");
10839
10922
  };
10840
10923
  gapSection("Work Items missing source", gp.missing_source);
10841
- gapSection("Work Items missing initiative", gp.missing_initiative);
10842
10924
  gapSection("Work Items missing code ownership", gp.missing_code_ownership);
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
10925
  if (gp.broad_ownership_globs.length > 0) {
10848
10926
  L.push("### Broad ownership globs", "");
10849
10927
  for (const b2 of gp.broad_ownership_globs) {
@@ -10862,10 +10940,26 @@ function renderImpactMarkdown(r2) {
10862
10940
  }
10863
10941
  L.push("");
10864
10942
  }
10865
- const anyGaps = gp.missing_source.length + gp.missing_initiative.length + gp.missing_code_ownership.length + gp.missing_knowledge_level.length + gp.missing_acceptance_criteria.length + gp.missing_definition_of_done.length + gp.missing_validation.length + gp.broad_ownership_globs.length;
10943
+ const anyGaps = gp.missing_source.length + gp.missing_code_ownership.length + gp.broad_ownership_globs.length;
10866
10944
  if (anyGaps === 0) {
10867
10945
  L.push("No actionable knowledge gaps detected. \u{1F389}", "");
10868
10946
  }
10947
+ const historical = [
10948
+ ["knowledge level", gp.missing_knowledge_level],
10949
+ ["Acceptance Criteria", gp.missing_acceptance_criteria],
10950
+ ["Definition of Done", gp.missing_definition_of_done],
10951
+ ["validation section", gp.missing_validation]
10952
+ ];
10953
+ L.push("## Historical Documentation Completeness", "");
10954
+ for (const [label, items] of historical) {
10955
+ const completed = items.filter((item) => item.status === "completed");
10956
+ if (completed.length > 0) L.push(`- Completed Work Items without detected ${label}: ${completed.length}`);
10957
+ }
10958
+ if (!historical.some(([, items]) => items.some((item) => item.status === "completed"))) {
10959
+ L.push("No historical documentation completeness gaps were detected.");
10960
+ }
10961
+ L.push("- This is an inventory for review, not a recommendation to rewrite historical Work Items merely to increase a metric.");
10962
+ L.push("");
10869
10963
  if (r2.score_breakdown) {
10870
10964
  L.push("## Score Breakdown", "");
10871
10965
  const b2 = r2.score_breakdown;
@@ -11015,6 +11109,16 @@ function buildSavingsReport(dir, opts = {}, now = /* @__PURE__ */ new Date()) {
11015
11109
  } else {
11016
11110
  actions.push("Use drift history to calibrate `rework_hours_avoided_per_resolved_drift`.");
11017
11111
  }
11112
+ const calibrationOpportunities = !a2.calibrated_at ? {
11113
+ available: true,
11114
+ reason: source3 === "default" ? "Default assumptions are uncalibrated estimates." : "Project assumptions are not marked as calibrated.",
11115
+ opportunities: [
11116
+ { area: "Context preparation", suggested_evidence: "Compare preparation effort on comparable tasks before and after using the knowledge artifacts." },
11117
+ { area: "Review effort", suggested_evidence: "Record a baseline for comparable reviews with similar ownership coverage." },
11118
+ { area: "Clarification reduction", suggested_evidence: "Estimate effort spent resolving repeated scope or context questions." },
11119
+ { area: "Architecture discovery", suggested_evidence: "Compare discovery time for similar dependency or relationship analyses." }
11120
+ ]
11121
+ } : { available: false, reason: `Assumptions are marked as calibrated on ${a2.calibrated_at}.`, opportunities: [] };
11018
11122
  return {
11019
11123
  generated_at: now.toISOString(),
11020
11124
  project: impact.project,
@@ -11066,6 +11170,7 @@ function buildSavingsReport(dir, opts = {}, now = /* @__PURE__ */ new Date()) {
11066
11170
  },
11067
11171
  total: { estimated_hours_saved: observedHours, estimated_value: observedValue, currency: a2.currency },
11068
11172
  confidence: { level, reasons },
11173
+ calibration_opportunities: calibrationOpportunities,
11069
11174
  suggested_actions: actions
11070
11175
  };
11071
11176
  }
@@ -11147,6 +11252,17 @@ function renderSavingsMarkdown(r2) {
11147
11252
  L.push(`Confidence: ${r2.confidence.level}`, "", "Reason:");
11148
11253
  for (const reason of r2.confidence.reasons) L.push(`- ${reason}`);
11149
11254
  L.push("");
11255
+ L.push("## Calibration Opportunities", "");
11256
+ if (!r2.calibration_opportunities.available) {
11257
+ L.push(`- ${r2.calibration_opportunities.reason}`);
11258
+ } else {
11259
+ L.push(`- ${r2.calibration_opportunities.reason}`);
11260
+ L.push("- Use external, aggregate project observations; do not collect or store personal data.");
11261
+ for (const opportunity of r2.calibration_opportunities.opportunities) {
11262
+ L.push(`- ${opportunity.area}: ${opportunity.suggested_evidence}`);
11263
+ }
11264
+ }
11265
+ L.push("");
11150
11266
  L.push("## Suggested Actions", "");
11151
11267
  r2.suggested_actions.forEach((act, i) => L.push(`${i + 1}. ${act}`));
11152
11268
  L.push("");
@@ -11167,10 +11283,24 @@ function buildDriftReport(dir, now = /* @__PURE__ */ new Date()) {
11167
11283
  const deprecationFindings = plans.flatMap((plan) => getDeprecationPlan(dir, plan.id)?.targets.flatMap(validateTarget) ?? []);
11168
11284
  const config = loadConfig(dir);
11169
11285
  const topology = config ? buildGraph(dir, config, { scope: "all" }, now) : null;
11170
- const topologyHints = topology ? buildGraphHints(dir, topology, now).summary.hints : null;
11286
+ const graphHints = topology ? buildGraphHints(dir, topology, now) : null;
11287
+ const topologyHints = graphHints?.summary.hints ?? null;
11288
+ const currentConsistencyFindings = [
11289
+ ...graphHints?.hints.map(graphHintFinding) ?? [],
11290
+ ...deprecationFindings.map((finding, index) => ({
11291
+ id: `deprecation-target:${index + 1}`,
11292
+ category: "consistency",
11293
+ source: "deprecation-target-validation",
11294
+ affected_artifacts: [],
11295
+ priority: "medium",
11296
+ evidence: String(finding),
11297
+ explanation: "A deterministic deprecation target consistency check reported a finding.",
11298
+ suggested_action: "Review the affected deprecation target and its declared lifecycle evidence."
11299
+ }))
11300
+ ];
11171
11301
  const actions = [];
11172
11302
  if (!h2.available) {
11173
- actions.push("Run `kaddo guard --record` to start recording guard history.");
11303
+ 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
11304
  } else {
11175
11305
  if (h2.open > 0) actions.push("Review open drift warnings and update related Work Items or ownership.");
11176
11306
  actions.push("Run `kaddo guard --record` before important commits.");
@@ -11186,6 +11316,11 @@ function buildDriftReport(dir, now = /* @__PURE__ */ new Date()) {
11186
11316
  { 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 ? `${plans.length} plan(s) passed deterministic target consistency checks.` : `${deprecationFindings.length} deterministic deprecation consistency finding(s) were detected.` },
11187
11317
  { 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
11318
  ],
11319
+ current_consistency_findings: currentConsistencyFindings,
11320
+ structural_consistency: {
11321
+ deprecation_target_checks: plans.length === 0 ? "not_applicable" : deprecationFindings.length === 0 ? "passed" : "findings_detected",
11322
+ 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."
11323
+ },
11189
11324
  guard_history: {
11190
11325
  available: h2.available,
11191
11326
  total_runs: h2.total_runs,
@@ -11211,6 +11346,24 @@ function renderDriftMarkdown(r2) {
11211
11346
  L.push("## Consistency Evidence", "");
11212
11347
  for (const item of r2.consistency_evidence) L.push(`- ${item.label}: ${item.classification} \u2014 ${item.reason}`);
11213
11348
  L.push("");
11349
+ L.push("## Current Consistency Findings", "");
11350
+ if (r2.current_consistency_findings.length === 0) {
11351
+ L.push("No findings detected by the executed consistency checks.");
11352
+ L.push("");
11353
+ }
11354
+ if (r2.current_consistency_findings.length > 0) {
11355
+ const cell = (value) => value.replace(/\|/g, "\\|").replace(/\r?\n/g, " ");
11356
+ L.push("| Priority | Source | Affected | Finding | Suggested action |");
11357
+ L.push("|---|---|---|---|---|");
11358
+ for (const finding of r2.current_consistency_findings) {
11359
+ L.push(`| ${finding.priority} | ${cell(finding.source)} | ${cell(finding.affected_artifacts.join(", ") || "not available")} | ${cell(finding.explanation)} Evidence: ${cell(finding.evidence)} | ${cell(finding.suggested_action)} |`);
11360
+ }
11361
+ L.push("");
11362
+ }
11363
+ L.push("## Structural Consistency Boundaries", "");
11364
+ L.push(`- Deprecation target checks: ${r2.structural_consistency.deprecation_target_checks}`);
11365
+ L.push(`- Note: ${r2.structural_consistency.note}`);
11366
+ L.push("");
11214
11367
  if (!r2.guard_history.available) {
11215
11368
  L.push("## Guard History", "");
11216
11369
  L.push("No guard history recorded yet.");
@@ -11282,6 +11435,8 @@ function serializeDriftJson(r2) {
11282
11435
  project: r2.project,
11283
11436
  project_context: r2.project_context,
11284
11437
  consistency_evidence: r2.consistency_evidence,
11438
+ current_consistency_findings: r2.current_consistency_findings,
11439
+ structural_consistency: r2.structural_consistency,
11285
11440
  guard_history: r2.guard_history,
11286
11441
  drift_warnings: r2.drift_warnings,
11287
11442
  hotspots: r2.hotspots,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaddo/mcp",
3
- "version": "3.124.2",
3
+ "version": "3.124.3",
4
4
  "description": "MCP server for Kaddo project knowledge: read-only resources/tools/prompts plus safe derived generation under .kaddo/.",
5
5
  "license": "MIT",
6
6
  "repository": {