kibi-cli 0.10.0 → 0.11.0

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 (46) hide show
  1. package/dist/cli.d.ts.map +1 -1
  2. package/dist/cli.js +11 -0
  3. package/dist/commands/check.d.ts.map +1 -1
  4. package/dist/commands/check.js +204 -3
  5. package/dist/commands/init-helpers.d.ts.map +1 -1
  6. package/dist/commands/init-helpers.js +11 -14
  7. package/dist/commands/sync/manifest.d.ts +8 -2
  8. package/dist/commands/sync/manifest.d.ts.map +1 -1
  9. package/dist/commands/sync/manifest.js +56 -11
  10. package/dist/commands/sync.d.ts +1 -0
  11. package/dist/commands/sync.d.ts.map +1 -1
  12. package/dist/commands/sync.js +9 -7
  13. package/dist/commands/usage-metrics.d.ts +8 -0
  14. package/dist/commands/usage-metrics.d.ts.map +1 -0
  15. package/dist/commands/usage-metrics.js +323 -0
  16. package/dist/extractors/manifest.d.ts +30 -0
  17. package/dist/extractors/manifest.d.ts.map +1 -1
  18. package/dist/extractors/manifest.js +60 -7
  19. package/dist/extractors/symbol-coordinates.d.ts +15 -0
  20. package/dist/extractors/symbol-coordinates.d.ts.map +1 -0
  21. package/dist/extractors/symbol-coordinates.js +83 -0
  22. package/dist/public/extractors/manifest.d.ts +1 -1
  23. package/dist/public/extractors/manifest.d.ts.map +1 -1
  24. package/dist/public/extractors/manifest.js +1 -1
  25. package/dist/traceability/evidence-model.d.ts +142 -0
  26. package/dist/traceability/evidence-model.d.ts.map +1 -0
  27. package/dist/traceability/evidence-model.js +70 -0
  28. package/dist/traceability/git-staged.d.ts +1 -0
  29. package/dist/traceability/git-staged.d.ts.map +1 -1
  30. package/dist/traceability/git-staged.js +28 -3
  31. package/dist/traceability/staged-diagnostics.d.ts +25 -0
  32. package/dist/traceability/staged-diagnostics.d.ts.map +1 -0
  33. package/dist/traceability/staged-diagnostics.js +67 -0
  34. package/dist/traceability/staged-impact-contract.d.ts +57 -0
  35. package/dist/traceability/staged-impact-contract.d.ts.map +1 -0
  36. package/dist/traceability/staged-impact-contract.js +202 -0
  37. package/dist/traceability/staged-symbols-manifest.d.ts +23 -0
  38. package/dist/traceability/staged-symbols-manifest.d.ts.map +1 -0
  39. package/dist/traceability/staged-symbols-manifest.js +269 -0
  40. package/dist/traceability/symbol-extract.d.ts.map +1 -1
  41. package/dist/traceability/symbol-extract.js +33 -9
  42. package/dist/utils/manifest-paths.d.ts +8 -0
  43. package/dist/utils/manifest-paths.d.ts.map +1 -0
  44. package/dist/utils/manifest-paths.js +62 -0
  45. package/package.json +1 -1
  46. package/src/public/extractors/manifest.ts +2 -0
@@ -0,0 +1,142 @@
1
+ /**
2
+ * Stable contract for staged Kibi impact evidence.
3
+ *
4
+ * This module is intentionally explicit and non-heuristic. Upstream staged-file
5
+ * analysis decides whether a source edit is behavior-changing; this contract only
6
+ * records that decision and the staged KB artifacts that cover it.
7
+ */
8
+ /** User-facing KB schema documentation cited by staged diagnostics. */
9
+ export declare const KIBI_ENTITY_SCHEMA_DOC = "docs/entity-schema.md";
10
+ /** Canonical symbols manifest path used by staged traceability enforcement. */
11
+ export declare const KIBI_SYMBOLS_MANIFEST_PATH = "documentation/symbols.yaml";
12
+ /** Canonical symbol coordinates artifact used by staged traceability enforcement. */
13
+ export declare const KIBI_SYMBOL_COORDINATES_PATH = "documentation/symbol-coordinates.yaml";
14
+ /** Explicit declaration string for audited no-impact overrides. */
15
+ export declare const KIBI_NO_IMPACT_DECLARATION = "Kibi-Impact: none";
16
+ /** Canonical Kibi entity types that can provide staged evidence. */
17
+ export type KibiEntityType = "req" | "scenario" | "test" | "adr" | "flag" | "event" | "symbol" | "fact";
18
+ /**
19
+ * Explicit source-edit classification from upstream staged analysis.
20
+ *
21
+ * - `behavior_source_edit`: a supported staged source change already classified
22
+ * as behavior-changing or traceability-relevant by the caller.
23
+ * - `non_behavior_source_edit`: a supported staged source change that remains in
24
+ * scope for auditing but does not require KB changes.
25
+ */
26
+ export type SourceChangeKind = "behavior_source_edit" | "non_behavior_source_edit";
27
+ /** One staged source file participating in Kibi impact evaluation. */
28
+ export interface KibiImpactSourceChange {
29
+ /** Repo-relative staged source path. */
30
+ path: string;
31
+ /** Explicit upstream classification; this module does not infer it. */
32
+ kind: SourceChangeKind;
33
+ }
34
+ /**
35
+ * Staged KB markdown evidence linked to one or more staged source files.
36
+ *
37
+ * Evidence is explicit only when the staged artifact names concrete KB entities
38
+ * and lists the staged source paths it is intended to cover.
39
+ */
40
+ export interface KibiImpactKbArtifact {
41
+ /** Artifact category. Kept narrow to avoid heuristic interpretation. */
42
+ kind: "entity_markdown" | "symbols_manifest";
43
+ /** Repo-relative staged KB artifact path. */
44
+ path: string;
45
+ /** Canonical Kibi entity types present in the staged artifact. */
46
+ entityTypes: KibiEntityType[];
47
+ /** Concrete KB entities updated by the staged artifact. */
48
+ entityIds: string[];
49
+ /** Repo-relative source paths explicitly covered by this artifact. */
50
+ sourcePaths: string[];
51
+ }
52
+ /**
53
+ * Deterministic symbol coordinates artifact state for the staged change-set.
54
+ *
55
+ * - `not_required`: symbol extraction output did not change for the listed
56
+ * staged source paths.
57
+ * - `fresh`: a staged coordinate refresh covers the listed source paths.
58
+ * - `stale`: coordinate artifact content is reverted, outdated, or otherwise does not match
59
+ * the staged symbol extraction result.
60
+ * - `missing`: a refresh is required but no staged coordinate artifact exists.
61
+ */
62
+ export interface KibiImpactSymbolsManifest {
63
+ /** Canonical repo-relative symbol coordinate artifact path. */
64
+ path: string;
65
+ /** Explicit manifest freshness state. */
66
+ state: "not_required" | "fresh" | "stale" | "missing";
67
+ /** Repo-relative staged source paths whose symbol output this state describes. */
68
+ sourcePaths: string[];
69
+ }
70
+ /** Supported audited reasons for a no-impact override. */
71
+ export type KibiNoImpactReason = "false_positive" | "non_behavioral_source_edit";
72
+ /**
73
+ * Explicit no-impact override record.
74
+ *
75
+ * Overrides are only valid for non-behavioral edits or classifier false
76
+ * positives. They never satisfy real behavior-changing source edits.
77
+ */
78
+ export interface KibiNoImpactOverride {
79
+ /** Required literal declaration. */
80
+ declaration: typeof KIBI_NO_IMPACT_DECLARATION;
81
+ /** Repo-relative staged record path carrying the override. */
82
+ path: string;
83
+ /** Repo-relative source paths covered by the override record. */
84
+ sourcePaths: string[];
85
+ /** Audited reason for allowing the override. */
86
+ reason: KibiNoImpactReason;
87
+ /** Human-readable justification stored with the override record. */
88
+ rationale: string;
89
+ }
90
+ /** Explicit evidence state: staged KB artifacts are present. */
91
+ export interface KibiImpactKbChangesMode {
92
+ kind: "kb_changes";
93
+ /** Staged KB markdown artifacts linked to staged source changes. */
94
+ kbArtifacts: KibiImpactKbArtifact[];
95
+ }
96
+ /** Explicit evidence state: a staged no-impact override is being used. */
97
+ export interface KibiImpactNoImpactOverrideMode {
98
+ kind: "no_impact_override";
99
+ /** Staged override record for false positives or non-behavioral edits. */
100
+ override: KibiNoImpactOverride;
101
+ }
102
+ /** Explicit evidence state: no staged KB evidence or override exists. */
103
+ export interface KibiImpactMissingMode {
104
+ kind: "missing";
105
+ }
106
+ /** Discriminated union describing how the staged change-set is justified. */
107
+ export type KibiImpactMode = KibiImpactKbChangesMode | KibiImpactNoImpactOverrideMode | KibiImpactMissingMode;
108
+ /**
109
+ * Full evidence snapshot for staged Kibi impact enforcement.
110
+ *
111
+ * `sourceChanges` is always required so diagnostics can cite exact staged source
112
+ * files. `mode` captures whether those files are backed by KB changes, by an
113
+ * audited no-impact override, or by nothing. `symbolsManifest` records whether a
114
+ * staged manifest refresh is part of that evidence.
115
+ */
116
+ export interface KibiImpactEvidence {
117
+ /** All staged source files in scope for Kibi impact enforcement. */
118
+ sourceChanges: KibiImpactSourceChange[];
119
+ /** Deterministic staged symbols manifest state for the same change-set. */
120
+ symbolsManifest: KibiImpactSymbolsManifest;
121
+ /** Explicit evidence mode for the staged change-set. */
122
+ mode: KibiImpactMode;
123
+ }
124
+ /** Returns staged behavior-changing source paths only. */
125
+ export declare function getBehaviorSourcePaths(evidence: KibiImpactEvidence): string[];
126
+ /** Returns staged source paths covered by explicit KB artifacts. */
127
+ export declare function getKbCoveredSourcePaths(evidence: KibiImpactEvidence): string[];
128
+ /** Returns staged source paths covered by a fresh symbol coordinate refresh. */
129
+ export declare function getFreshSymbolsManifestSourcePaths(evidence: KibiImpactEvidence): string[];
130
+ /**
131
+ * Returns all staged evidence file paths that a later CLI integration can cite
132
+ * in diagnostics or logs.
133
+ */
134
+ export declare function getKbEvidencePaths(evidence: KibiImpactEvidence): string[];
135
+ /** True when a staged no-impact override includes a non-empty rationale. */
136
+ export declare function hasOverrideRationale(evidence: KibiImpactEvidence): boolean;
137
+ /**
138
+ * Returns behavior-changing staged source files that still lack valid Kibi
139
+ * impact evidence.
140
+ */
141
+ export declare function getMissingBehaviorSourcePaths(evidence: KibiImpactEvidence): string[];
142
+ //# sourceMappingURL=evidence-model.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evidence-model.d.ts","sourceRoot":"","sources":["../../src/traceability/evidence-model.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Stable contract for staged Kibi impact evidence.
3
+ *
4
+ * This module is intentionally explicit and non-heuristic. Upstream staged-file
5
+ * analysis decides whether a source edit is behavior-changing; this contract only
6
+ * records that decision and the staged KB artifacts that cover it.
7
+ */
8
+ /** User-facing KB schema documentation cited by staged diagnostics. */
9
+ export const KIBI_ENTITY_SCHEMA_DOC = "docs/entity-schema.md";
10
+ /** Canonical symbols manifest path used by staged traceability enforcement. */
11
+ export const KIBI_SYMBOLS_MANIFEST_PATH = "documentation/symbols.yaml";
12
+ /** Canonical symbol coordinates artifact used by staged traceability enforcement. */
13
+ export const KIBI_SYMBOL_COORDINATES_PATH = "documentation/symbol-coordinates.yaml";
14
+ /** Explicit declaration string for audited no-impact overrides. */
15
+ export const KIBI_NO_IMPACT_DECLARATION = "Kibi-Impact: none";
16
+ function uniqueSorted(values) {
17
+ return Array.from(new Set(values)).sort();
18
+ }
19
+ /** Returns staged behavior-changing source paths only. */
20
+ export function getBehaviorSourcePaths(evidence) {
21
+ return evidence.sourceChanges
22
+ .filter((change) => change.kind === "behavior_source_edit")
23
+ .map((change) => change.path)
24
+ .sort();
25
+ }
26
+ /** Returns staged source paths covered by explicit KB artifacts. */
27
+ export function getKbCoveredSourcePaths(evidence) {
28
+ if (evidence.mode.kind !== "kb_changes") {
29
+ return [];
30
+ }
31
+ return uniqueSorted(evidence.mode.kbArtifacts.flatMap((artifact) => artifact.sourcePaths));
32
+ }
33
+ /** Returns staged source paths covered by a fresh symbol coordinate refresh. */
34
+ export function getFreshSymbolsManifestSourcePaths(evidence) {
35
+ if (evidence.symbolsManifest.state !== "fresh") {
36
+ return [];
37
+ }
38
+ return [...evidence.symbolsManifest.sourcePaths].sort();
39
+ }
40
+ /**
41
+ * Returns all staged evidence file paths that a later CLI integration can cite
42
+ * in diagnostics or logs.
43
+ */
44
+ export function getKbEvidencePaths(evidence) {
45
+ const paths = [];
46
+ if (evidence.mode.kind === "kb_changes") {
47
+ paths.push(...evidence.mode.kbArtifacts.map((artifact) => artifact.path));
48
+ }
49
+ if (evidence.symbolsManifest.state === "fresh") {
50
+ paths.push(evidence.symbolsManifest.path);
51
+ }
52
+ return uniqueSorted(paths);
53
+ }
54
+ /** True when a staged no-impact override includes a non-empty rationale. */
55
+ export function hasOverrideRationale(evidence) {
56
+ return (evidence.mode.kind === "no_impact_override" &&
57
+ evidence.mode.override.rationale.trim().length > 0);
58
+ }
59
+ /**
60
+ * Returns behavior-changing staged source files that still lack valid Kibi
61
+ * impact evidence.
62
+ */
63
+ export function getMissingBehaviorSourcePaths(evidence) {
64
+ const behaviorPaths = getBehaviorSourcePaths(evidence);
65
+ const coveredPaths = new Set([
66
+ ...getKbCoveredSourcePaths(evidence),
67
+ ...getFreshSymbolsManifestSourcePaths(evidence),
68
+ ]);
69
+ return behaviorPaths.filter((path) => !coveredPaths.has(path));
70
+ }
@@ -8,6 +8,7 @@ export interface StagedFile {
8
8
  status: Status;
9
9
  oldPath?: string;
10
10
  hunkRanges: HunkRange[];
11
+ diffText?: string;
11
12
  content?: string;
12
13
  }
13
14
  type ExecFn = (cmd: string, opts: {
@@ -1 +1 @@
1
- {"version":3,"file":"git-staged.d.ts","sourceRoot":"","sources":["../../src/traceability/git-staged.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,MAAM,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;AAE3C,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,SAAS,EAAE,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,KAAK,MAAM,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,KAAK,MAAM,CAAC;AAalE;;GAEG;AAEH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,MAAM,GACZ,KAAK,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAwB5C;AAiDD;;GAEG;AACH,wBAAgB,kBAAkB,CAEhC,QAAQ,EAAE,MAAM,EAChB,SAAS,UAAQ,GAChB,SAAS,EAAE,CAuBb;AAED;;GAEG;AAEH,wBAAgB,cAAc,CAAC,IAAI,GAAE,MAAiB,GAAG,UAAU,EAAE,CAuGpE;AAED,eAAe,cAAc,CAAC"}
1
+ {"version":3,"file":"git-staged.d.ts","sourceRoot":"","sources":["../../src/traceability/git-staged.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,MAAM,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;AAE3C,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,SAAS,EAAE,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,KAAK,MAAM,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,KAAK,MAAM,CAAC;AAalE;;GAEG;AAEH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,MAAM,GACZ,KAAK,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAwB5C;AAsED;;GAEG;AACH,wBAAgB,kBAAkB,CAEhC,QAAQ,EAAE,MAAM,EAChB,SAAS,UAAQ,GAChB,SAAS,EAAE,CAuBb;AAED;;GAEG;AAEH,wBAAgB,cAAc,CAAC,IAAI,GAAE,MAAiB,GAAG,UAAU,EAAE,CAwGpE;AAED,eAAe,cAAc,CAAC"}
@@ -1,5 +1,6 @@
1
1
  import { execSync } from "node:child_process";
2
2
  import { isCliTraceOrDebugEnabled } from "../env.js";
3
+ import { loadConfig } from "../utils/config.js";
3
4
  function runGit(cmd, exec) {
4
5
  try {
5
6
  return exec(cmd, { encoding: "utf8" });
@@ -47,8 +48,20 @@ const SUPPORTED_EXT = new Set([
47
48
  ".mjs",
48
49
  ".cjs",
49
50
  ]);
50
- const SUPPORTED_MANIFEST = new Set(["symbols.yaml", "symbols.yml"]);
51
- const ENTITY_MARKDOWN_DIRS = ["/requirements/", "/scenarios/", "/tests/"];
51
+ const SUPPORTED_MANIFEST = new Set([
52
+ "symbols.yaml",
53
+ "symbols.yml",
54
+ "symbol-coordinates.yaml",
55
+ ]);
56
+ const ENTITY_MARKDOWN_DIRS = [
57
+ "/requirements/",
58
+ "/scenarios/",
59
+ "/tests/",
60
+ "/facts/",
61
+ "/adr/",
62
+ "/flags/",
63
+ "/events/",
64
+ ];
52
65
  function shouldLogTraceDebug() {
53
66
  return isCliTraceOrDebugEnabled();
54
67
  }
@@ -72,13 +85,24 @@ function isEntityMarkdown(p) {
72
85
  return false;
73
86
  }
74
87
  function isManifestFile(p) {
75
- const base = p.split(/[\/]/).pop();
88
+ const base = p.split(/[\\/]/).pop();
76
89
  if (!base)
77
90
  return false;
78
91
  for (const name of SUPPORTED_MANIFEST) {
79
92
  if (base === name)
80
93
  return true;
81
94
  }
95
+ try {
96
+ const config = loadConfig(process.cwd());
97
+ if (config.paths.symbols) {
98
+ const configuredBase = config.paths.symbols.split(/[\\/]/).pop();
99
+ if (configuredBase && base === configuredBase)
100
+ return true;
101
+ }
102
+ }
103
+ catch {
104
+ // ignore config read errors
105
+ }
82
106
  return false;
83
107
  }
84
108
  /**
@@ -198,6 +222,7 @@ export function getStagedFiles(exec = execSync) {
198
222
  status,
199
223
  ...(oldPath !== undefined ? { oldPath } : {}),
200
224
  hunkRanges,
225
+ diffText,
201
226
  content,
202
227
  });
203
228
  }
@@ -0,0 +1,25 @@
1
+ import { type KibiImpactEvidence } from "./evidence-model.js";
2
+ export type KibiImpactDiagnosticId = "kibi_impact_evidence_missing" | "symbols_manifest_stale" | "kibi_impact_override_missing_rationale";
3
+ export interface KibiImpactDiagnostic {
4
+ /** Stable staged-enforcement diagnostic identifier. */
5
+ id: KibiImpactDiagnosticId;
6
+ /** Hard-gate severity for staged enforcement. */
7
+ severity: "error";
8
+ /** Repo-relative files that explain why the diagnostic fired. */
9
+ files: string[];
10
+ /** User-facing docs that explain the policy. */
11
+ docs: string[];
12
+ /** Exact CLI-facing diagnostic message. */
13
+ message: string;
14
+ /** Deterministic remediation guidance. */
15
+ suggestion: string;
16
+ }
17
+ /**
18
+ * Collects deterministic staged diagnostics for Kibi impact enforcement.
19
+ *
20
+ * This function assumes upstream staged analysis has already classified source
21
+ * files and manifest freshness. It only evaluates explicit predicates recorded in
22
+ * `KibiImpactEvidence`.
23
+ */
24
+ export declare function collectStagedKibiDiagnostics(evidence: KibiImpactEvidence): KibiImpactDiagnostic[];
25
+ //# sourceMappingURL=staged-diagnostics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"staged-diagnostics.d.ts","sourceRoot":"","sources":["../../src/traceability/staged-diagnostics.ts"],"names":[],"mappings":"AAAA,OAAO,EAOL,KAAK,kBAAkB,EACxB,MAAM,qBAAqB,CAAC;AAE7B,MAAM,MAAM,sBAAsB,GAC9B,8BAA8B,GAC9B,wBAAwB,GACxB,wCAAwC,CAAC;AAE7C,MAAM,WAAW,oBAAoB;IACnC,uDAAuD;IACvD,EAAE,EAAE,sBAAsB,CAAC;IAC3B,iDAAiD;IACjD,QAAQ,EAAE,OAAO,CAAC;IAClB,iEAAiE;IACjE,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,gDAAgD;IAChD,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,2CAA2C;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,0CAA0C;IAC1C,UAAU,EAAE,MAAM,CAAC;CACpB;AAsDD;;;;;;GAMG;AACH,wBAAgB,4BAA4B,CAC1C,QAAQ,EAAE,kBAAkB,GAC3B,oBAAoB,EAAE,CAoCxB"}
@@ -0,0 +1,67 @@
1
+ import { KIBI_ENTITY_SCHEMA_DOC, KIBI_SYMBOL_COORDINATES_PATH, KIBI_SYMBOLS_MANIFEST_PATH, getBehaviorSourcePaths, getMissingBehaviorSourcePaths, hasOverrideRationale, } from "./evidence-model.js";
2
+ function formatFileList(paths) {
3
+ return paths.join(", ");
4
+ }
5
+ function createMissingEvidenceDiagnostic(paths) {
6
+ return {
7
+ id: "kibi_impact_evidence_missing",
8
+ severity: "error",
9
+ files: [...paths],
10
+ docs: [KIBI_ENTITY_SCHEMA_DOC],
11
+ message: `Behavior-changing staged files are missing Kibi impact evidence (see ${KIBI_ENTITY_SCHEMA_DOC}): ${formatFileList(paths)}`,
12
+ suggestion: `Query Kibi via MCP before deciding, then stage requirement/scenario/test/fact/symbol markdown evidence, staged authored ${KIBI_SYMBOLS_MANIFEST_PATH} metadata, or refreshed ${KIBI_SYMBOL_COORDINATES_PATH}. Re-run kibi check --staged after staging the evidence.`,
13
+ };
14
+ }
15
+ function createSymbolsManifestStaleDiagnostic(paths) {
16
+ return {
17
+ id: "symbols_manifest_stale",
18
+ severity: "error",
19
+ files: [KIBI_SYMBOL_COORDINATES_PATH, ...paths],
20
+ docs: [KIBI_ENTITY_SCHEMA_DOC],
21
+ message: `${KIBI_SYMBOL_COORDINATES_PATH} is stale or missing for staged source files: ${formatFileList(paths)}`,
22
+ suggestion: `Run kibi sync --refresh-symbol-coordinates && git add ${KIBI_SYMBOL_COORDINATES_PATH} ${KIBI_SYMBOLS_MANIFEST_PATH}, then re-run kibi check --staged.`,
23
+ };
24
+ }
25
+ function createMissingOverrideRationaleDiagnostic(evidence) {
26
+ if (evidence.mode.kind !== "no_impact_override") {
27
+ throw new Error("Override rationale diagnostic requires a no-impact override");
28
+ }
29
+ const paths = [...evidence.mode.override.sourcePaths].sort();
30
+ return {
31
+ id: "kibi_impact_override_missing_rationale",
32
+ severity: "error",
33
+ files: [evidence.mode.override.path, ...paths],
34
+ docs: [KIBI_ENTITY_SCHEMA_DOC],
35
+ message: `Kibi-Impact: none override is missing rationale for staged source files: ${formatFileList(paths)}`,
36
+ suggestion: "Add a non-empty rationale in the same staged override record, keep overrides limited to false positives or non-behavioral source edits, and re-run kibi check --staged.",
37
+ };
38
+ }
39
+ /**
40
+ * Collects deterministic staged diagnostics for Kibi impact enforcement.
41
+ *
42
+ * This function assumes upstream staged analysis has already classified source
43
+ * files and manifest freshness. It only evaluates explicit predicates recorded in
44
+ * `KibiImpactEvidence`.
45
+ */
46
+ export function collectStagedKibiDiagnostics(evidence) {
47
+ const diagnostics = [];
48
+ if (evidence.mode.kind === "no_impact_override" &&
49
+ !hasOverrideRationale(evidence)) {
50
+ diagnostics.push(createMissingOverrideRationaleDiagnostic(evidence));
51
+ }
52
+ if ((evidence.symbolsManifest.state === "stale" ||
53
+ evidence.symbolsManifest.state === "missing") &&
54
+ evidence.symbolsManifest.sourcePaths.length > 0) {
55
+ diagnostics.push(createSymbolsManifestStaleDiagnostic([...evidence.symbolsManifest.sourcePaths].sort()));
56
+ }
57
+ const missingBehaviorPaths = getMissingBehaviorSourcePaths(evidence);
58
+ if (missingBehaviorPaths.length > 0) {
59
+ diagnostics.push(createMissingEvidenceDiagnostic(missingBehaviorPaths));
60
+ }
61
+ if (evidence.mode.kind === "no_impact_override" &&
62
+ evidence.mode.override.sourcePaths.length === 0 &&
63
+ getBehaviorSourcePaths(evidence).length === 0) {
64
+ return diagnostics;
65
+ }
66
+ return diagnostics;
67
+ }
@@ -0,0 +1,57 @@
1
+ export declare const KIBI_IMPACT_DIAGNOSTIC_IDS: readonly ["kibi_impact_evidence_missing", "symbols_manifest_stale", "kibi_impact_override_missing_rationale"];
2
+ export type KibiImpactDiagnosticId = (typeof KIBI_IMPACT_DIAGNOSTIC_IDS)[number];
3
+ export type KibiImpactEvidenceKind = "entity_markdown" | "symbols_manifest" | "audited_no_impact";
4
+ export interface KibiImpactDiagnosticContract {
5
+ id: KibiImpactDiagnosticId;
6
+ title: string;
7
+ resolution: [string, string, string];
8
+ }
9
+ export interface KibiImpactEvidenceInput {
10
+ filePath?: string;
11
+ extractionOutputChanged?: boolean;
12
+ overrideDeclared?: boolean;
13
+ overrideRationale?: string | null;
14
+ symbolsManifestPath?: string;
15
+ }
16
+ export interface BehaviorSourceEditInput {
17
+ path: string;
18
+ diffText: string;
19
+ intersectsBehaviorBearingSymbol: boolean;
20
+ knownUserFacingSurface?: boolean;
21
+ }
22
+ export interface ParsedKibiImpactOverride {
23
+ declared: boolean;
24
+ rationale: string | null;
25
+ }
26
+ export interface AuditedNoImpactOverrideInput {
27
+ behaviorSourceEdit: boolean;
28
+ override: ParsedKibiImpactOverride;
29
+ }
30
+ /**
31
+ * Staged Kibi impact contract for `kibi check --staged`.
32
+ *
33
+ * This is intentionally a small, stable contract for tests and future staged
34
+ * enforcement wiring:
35
+ * - `behavior_source_edit` is a supported source-file edit whose staged hunks
36
+ * intersect exported or other behavior-bearing/user-facing surfaces and whose
37
+ * changed lines are not comment-only or formatting-only.
38
+ * - `kibi_impact_evidence` is staged entity markdown, staged authored
39
+ * `documentation/symbols.yaml` metadata, refreshed
40
+ * `documentation/symbol-coordinates.yaml` when extraction output changes, or
41
+ * an explicit audited `Kibi-Impact: none` declaration with
42
+ * rationale for false positives/non-behavior-only edits.
43
+ * - `Kibi-Impact: none` never satisfies a genuine behavior change.
44
+ * - Test-only edits do not require new KB evidence unless they introduce
45
+ * executable test symbols that need traceability.
46
+ *
47
+ * This contract deliberately avoids broad semantic diffing and stays
48
+ * conservative so later staged-check enforcement can share exact diagnostic IDs
49
+ * and operator-facing remediation steps.
50
+ */
51
+ export declare const KIBI_IMPACT_DIAGNOSTICS: Record<KibiImpactDiagnosticId, KibiImpactDiagnosticContract>;
52
+ export declare function classifyKibiImpactEvidence(input: KibiImpactEvidenceInput): KibiImpactEvidenceKind | null;
53
+ export declare function parseKibiImpactOverride(text: string): ParsedKibiImpactOverride;
54
+ export declare function isAuditedNoImpactOverrideAllowed(input: AuditedNoImpactOverrideInput): boolean;
55
+ export declare function isBehaviorSourceEdit(input: BehaviorSourceEditInput): boolean;
56
+ export declare function isSupportedBehaviorSourcePath(filePath: string): boolean;
57
+ //# sourceMappingURL=staged-impact-contract.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"staged-impact-contract.d.ts","sourceRoot":"","sources":["../../src/traceability/staged-impact-contract.ts"],"names":[],"mappings":"AAqBA,eAAO,MAAM,0BAA0B,+GAI7B,CAAC;AAEX,MAAM,MAAM,sBAAsB,GAChC,CAAC,OAAO,0BAA0B,CAAC,CAAC,MAAM,CAAC,CAAC;AAE9C,MAAM,MAAM,sBAAsB,GAC9B,iBAAiB,GACjB,kBAAkB,GAClB,mBAAmB,CAAC;AAExB,MAAM,WAAW,4BAA4B;IAC3C,EAAE,EAAE,sBAAsB,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;CACtC;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,+BAA+B,EAAE,OAAO,CAAC;IACzC,sBAAsB,CAAC,EAAE,OAAO,CAAC;CAClC;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,MAAM,WAAW,4BAA4B;IAC3C,kBAAkB,EAAE,OAAO,CAAC;IAC5B,QAAQ,EAAE,wBAAwB,CAAC;CACpC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,uBAAuB,EAAE,MAAM,CAC1C,sBAAsB,EACtB,4BAA4B,CA6B7B,CAAC;AAEF,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,uBAAuB,GAC7B,sBAAsB,GAAG,IAAI,CAsB/B;AAED,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,MAAM,GACX,wBAAwB,CAS1B;AAED,wBAAgB,gCAAgC,CAC9C,KAAK,EAAE,4BAA4B,GAClC,OAAO,CAMT;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,uBAAuB,GAAG,OAAO,CA8B5E;AAED,wBAAgB,6BAA6B,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAQvE"}
@@ -0,0 +1,202 @@
1
+ const SUPPORTED_BEHAVIOR_SOURCE_EXTENSIONS = new Set([
2
+ ".ts",
3
+ ".tsx",
4
+ ".js",
5
+ ".jsx",
6
+ ".mts",
7
+ ".cts",
8
+ ".mjs",
9
+ ".cjs",
10
+ ]);
11
+ const ENTITY_EVIDENCE_SEGMENTS = [
12
+ "/requirements/",
13
+ "/scenarios/",
14
+ "/tests/",
15
+ "/facts/",
16
+ "/adr/",
17
+ "/flags/",
18
+ "/events/",
19
+ ];
20
+ export const KIBI_IMPACT_DIAGNOSTIC_IDS = [
21
+ "kibi_impact_evidence_missing",
22
+ "symbols_manifest_stale",
23
+ "kibi_impact_override_missing_rationale",
24
+ ];
25
+ /**
26
+ * Staged Kibi impact contract for `kibi check --staged`.
27
+ *
28
+ * This is intentionally a small, stable contract for tests and future staged
29
+ * enforcement wiring:
30
+ * - `behavior_source_edit` is a supported source-file edit whose staged hunks
31
+ * intersect exported or other behavior-bearing/user-facing surfaces and whose
32
+ * changed lines are not comment-only or formatting-only.
33
+ * - `kibi_impact_evidence` is staged entity markdown, staged authored
34
+ * `documentation/symbols.yaml` metadata, refreshed
35
+ * `documentation/symbol-coordinates.yaml` when extraction output changes, or
36
+ * an explicit audited `Kibi-Impact: none` declaration with
37
+ * rationale for false positives/non-behavior-only edits.
38
+ * - `Kibi-Impact: none` never satisfies a genuine behavior change.
39
+ * - Test-only edits do not require new KB evidence unless they introduce
40
+ * executable test symbols that need traceability.
41
+ *
42
+ * This contract deliberately avoids broad semantic diffing and stays
43
+ * conservative so later staged-check enforcement can share exact diagnostic IDs
44
+ * and operator-facing remediation steps.
45
+ */
46
+ export const KIBI_IMPACT_DIAGNOSTICS = {
47
+ kibi_impact_evidence_missing: {
48
+ id: "kibi_impact_evidence_missing",
49
+ title: "Behavior edit requires staged Kibi impact evidence",
50
+ resolution: [
51
+ "Query Kibi via MCP first: use kb_search for discovery, then kb_query for exact follow-up.",
52
+ "Stage related KB entity markdown, stage authored documentation/symbols.yaml metadata, or refresh coordinates with kibi sync --refresh-symbol-coordinates and stage documentation/symbol-coordinates.yaml documentation/symbols.yaml.",
53
+ "Re-run or let the hook run kibi check --staged.",
54
+ ],
55
+ },
56
+ symbols_manifest_stale: {
57
+ id: "symbols_manifest_stale",
58
+ title: "Symbol coordinates evidence is stale for changed extraction output",
59
+ resolution: [
60
+ "Refresh symbol coordinates for the changed source file with kibi sync --refresh-symbol-coordinates.",
61
+ "Stage documentation/symbol-coordinates.yaml in the same change as the behavior edit, and stage documentation/symbols.yaml only if migration cleanup changed it.",
62
+ "Re-run or let the hook run kibi check --staged.",
63
+ ],
64
+ },
65
+ kibi_impact_override_missing_rationale: {
66
+ id: "kibi_impact_override_missing_rationale",
67
+ title: "Kibi no-impact override requires an explicit rationale",
68
+ resolution: [
69
+ "Use an audited declaration only for false positives or non-behavioral edits.",
70
+ "Include both 'Kibi-Impact: none' and a nearby 'Rationale:' line describing why the edit has no behavior impact.",
71
+ "Re-run or let the hook run kibi check --staged.",
72
+ ],
73
+ },
74
+ };
75
+ export function classifyKibiImpactEvidence(input) {
76
+ if (input.overrideDeclared && hasText(input.overrideRationale)) {
77
+ return "audited_no_impact";
78
+ }
79
+ const filePath = input.filePath ?? "";
80
+ if (!filePath) {
81
+ return null;
82
+ }
83
+ if (isEntityEvidenceMarkdown(filePath)) {
84
+ return "entity_markdown";
85
+ }
86
+ if (isSymbolsManifest(filePath, input.symbolsManifestPath) &&
87
+ input.extractionOutputChanged) {
88
+ return "symbols_manifest";
89
+ }
90
+ return null;
91
+ }
92
+ export function parseKibiImpactOverride(text) {
93
+ const declared = /^Kibi-Impact:\s*none\s*$/im.test(text);
94
+ const rationaleMatch = text.match(/^Rationale:\s*(.+)\s*$/im);
95
+ return {
96
+ declared,
97
+ rationale: hasText(rationaleMatch?.[1])
98
+ ? (rationaleMatch?.[1]?.trim() ?? null)
99
+ : null,
100
+ };
101
+ }
102
+ export function isAuditedNoImpactOverrideAllowed(input) {
103
+ return (input.override.declared &&
104
+ hasText(input.override.rationale) &&
105
+ !input.behaviorSourceEdit);
106
+ }
107
+ export function isBehaviorSourceEdit(input) {
108
+ if (!isSupportedBehaviorSourcePath(input.path)) {
109
+ return false;
110
+ }
111
+ if (!input.intersectsBehaviorBearingSymbol && !input.knownUserFacingSurface) {
112
+ return false;
113
+ }
114
+ const changes = extractChangedLines(input.diffText);
115
+ if (changes.length === 0) {
116
+ return false;
117
+ }
118
+ if (changes.every((line) => isIgnorableChangeLine(line))) {
119
+ return false;
120
+ }
121
+ const removed = normalizeChangedLines(changes.filter((line) => line.kind === "remove"));
122
+ const added = normalizeChangedLines(changes.filter((line) => line.kind === "add"));
123
+ if (removed.length > 0 && removed.join("\n") === added.join("\n")) {
124
+ return false;
125
+ }
126
+ return true;
127
+ }
128
+ export function isSupportedBehaviorSourcePath(filePath) {
129
+ for (const extension of SUPPORTED_BEHAVIOR_SOURCE_EXTENSIONS) {
130
+ if (filePath.endsWith(extension)) {
131
+ return true;
132
+ }
133
+ }
134
+ return false;
135
+ }
136
+ function isEntityEvidenceMarkdown(filePath) {
137
+ if (!filePath.endsWith(".md")) {
138
+ return false;
139
+ }
140
+ return ENTITY_EVIDENCE_SEGMENTS.some((segment) => filePath.includes(segment));
141
+ }
142
+ function isSymbolsManifest(filePath, symbolsManifestPath) {
143
+ const candidates = new Set([
144
+ "symbols.yaml",
145
+ "symbols.yml",
146
+ "documentation/symbols.yaml",
147
+ "documentation/symbols.yml",
148
+ ]);
149
+ if (symbolsManifestPath) {
150
+ candidates.add(symbolsManifestPath);
151
+ if (symbolsManifestPath.endsWith(".yaml")) {
152
+ candidates.add(`${symbolsManifestPath.slice(0, -5)}.yml`);
153
+ }
154
+ if (symbolsManifestPath.endsWith(".yml")) {
155
+ candidates.add(`${symbolsManifestPath.slice(0, -4)}.yaml`);
156
+ }
157
+ }
158
+ if (candidates.has(filePath)) {
159
+ return true;
160
+ }
161
+ return (filePath.endsWith("/symbols.yaml") ||
162
+ filePath.endsWith("/symbols.yml") ||
163
+ filePath === "symbols.yaml" ||
164
+ filePath === "symbols.yml");
165
+ }
166
+ function hasText(value) {
167
+ return typeof value === "string" && value.trim().length > 0;
168
+ }
169
+ function extractChangedLines(diffText) {
170
+ const lines = diffText.split(/\r?\n/);
171
+ const changes = [];
172
+ for (const line of lines) {
173
+ if (line.startsWith("+++") ||
174
+ line.startsWith("---") ||
175
+ line.startsWith("@@")) {
176
+ continue;
177
+ }
178
+ if (line.startsWith("+")) {
179
+ changes.push({ kind: "add", text: line.slice(1) });
180
+ continue;
181
+ }
182
+ if (line.startsWith("-")) {
183
+ changes.push({ kind: "remove", text: line.slice(1) });
184
+ }
185
+ }
186
+ return changes;
187
+ }
188
+ function isIgnorableChangeLine(line) {
189
+ const trimmed = line.text.trim();
190
+ if (!trimmed) {
191
+ return true;
192
+ }
193
+ return (trimmed.startsWith("//") ||
194
+ trimmed.startsWith("/*") ||
195
+ trimmed.startsWith("*/") ||
196
+ trimmed.startsWith("*"));
197
+ }
198
+ function normalizeChangedLines(lines) {
199
+ return lines
200
+ .map((line) => line.text.replace(/\s+/g, ""))
201
+ .filter((line) => line.length > 0);
202
+ }