kibi-cli 2.16.0 → 2.18.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 (83) hide show
  1. package/dist/cli-protocol.d.ts.map +1 -1
  2. package/dist/cli-protocol.js +13 -0
  3. package/dist/cli-register-proof.d.ts +6 -0
  4. package/dist/cli-register-proof.d.ts.map +1 -1
  5. package/dist/cli-register-proof.js +46 -2
  6. package/dist/commands/doctor.d.ts.map +1 -1
  7. package/dist/commands/doctor.js +9 -3
  8. package/dist/commands/sync/untracked-targets.d.ts.map +1 -1
  9. package/dist/commands/sync/untracked-targets.js +39 -9
  10. package/dist/commands/sync.d.ts.map +1 -1
  11. package/dist/commands/sync.js +26 -5
  12. package/dist/engine.d.ts +4 -0
  13. package/dist/engine.d.ts.map +1 -1
  14. package/dist/engine.js +40 -10
  15. package/dist/operations/modeling/predicate-applicability.d.ts.map +1 -1
  16. package/dist/operations/modeling/predicate-applicability.js +12 -3
  17. package/dist/operations/modeling/predicate-catalog-4.d.ts.map +1 -1
  18. package/dist/operations/modeling/predicate-catalog-4.js +4 -0
  19. package/dist/operations/modeling/predicate-loader.d.ts.map +1 -1
  20. package/dist/operations/modeling/predicate-loader.js +3 -0
  21. package/dist/operations/modeling/predicate-score-3.js +1 -1
  22. package/dist/operations/modeling/predicate-types.d.ts +5 -0
  23. package/dist/operations/modeling/predicate-types.d.ts.map +1 -1
  24. package/dist/operations/modeling/predicate-utils.d.ts.map +1 -1
  25. package/dist/operations/modeling/predicate-utils.js +2 -3
  26. package/dist/operations/mutation/source-authoring.d.ts +9 -0
  27. package/dist/operations/mutation/source-authoring.d.ts.map +1 -1
  28. package/dist/operations/mutation/source-authoring.js +38 -2
  29. package/dist/operations/planning/apply-plan.d.ts.map +1 -1
  30. package/dist/operations/planning/apply-plan.js +33 -8
  31. package/dist/operations/planning/migration-refusal.d.ts +14 -0
  32. package/dist/operations/planning/migration-refusal.d.ts.map +1 -0
  33. package/dist/operations/planning/migration-refusal.js +17 -0
  34. package/dist/operations/semantic-advisor/clauses.d.ts.map +1 -1
  35. package/dist/operations/semantic-advisor/clauses.js +7 -1
  36. package/dist/operations/semantic-advisor/shared.d.ts +7 -0
  37. package/dist/operations/semantic-advisor/shared.d.ts.map +1 -1
  38. package/dist/operations/semantic-advisor/shared.js +22 -3
  39. package/dist/prolog/store-lock.d.ts +22 -0
  40. package/dist/prolog/store-lock.d.ts.map +1 -1
  41. package/dist/prolog/store-lock.js +45 -1
  42. package/dist/prolog.d.ts +7 -1
  43. package/dist/prolog.d.ts.map +1 -1
  44. package/dist/prolog.js +21 -3
  45. package/dist/proof/inspect.d.ts +9 -0
  46. package/dist/proof/inspect.d.ts.map +1 -1
  47. package/dist/proof/inspect.js +10 -0
  48. package/dist/proof/integration-plan.d.ts +2 -1
  49. package/dist/proof/integration-plan.d.ts.map +1 -1
  50. package/dist/proof/integration-plan.js +30 -13
  51. package/dist/public/impact/coverage-depth-quality.d.ts.map +1 -1
  52. package/dist/public/impact/coverage-depth-quality.js +29 -1
  53. package/dist/public/operations/contracts.d.ts.map +1 -1
  54. package/dist/public/operations/contracts.js +3 -0
  55. package/dist/public/operations/discovery-executors.d.ts +14 -1
  56. package/dist/public/operations/discovery-executors.d.ts.map +1 -1
  57. package/dist/public/operations/discovery-executors.js +62 -12
  58. package/dist/public/operations/migration-plan.d.ts +2 -0
  59. package/dist/public/operations/migration-plan.d.ts.map +1 -1
  60. package/dist/public/operations/migration-plan.js +31 -0
  61. package/dist/public/operations/result-envelope.d.ts.map +1 -1
  62. package/dist/public/operations/result-envelope.js +23 -3
  63. package/dist/public/operations/source-relationship-parity.d.ts.map +1 -1
  64. package/dist/public/operations/source-relationship-parity.js +55 -1
  65. package/dist/public/skills/kibi-usage/SKILL.md +19 -4
  66. package/dist/public/skills/kibi-usage/resources/fact-lanes.md +3 -3
  67. package/dist/public/skills/kibi-usage/resources/proof.md +44 -3
  68. package/dist/utils/branch-store.d.ts +8 -0
  69. package/dist/utils/branch-store.d.ts.map +1 -1
  70. package/dist/utils/branch-store.js +27 -1
  71. package/dist/utils/content-freshness.d.ts +13 -0
  72. package/dist/utils/content-freshness.d.ts.map +1 -0
  73. package/dist/utils/content-freshness.js +161 -0
  74. package/package.json +2 -2
  75. package/src/public/impact/coverage-depth-quality.ts +46 -1
  76. package/src/public/operations/contracts.ts +3 -0
  77. package/src/public/operations/discovery-executors.ts +89 -11
  78. package/src/public/operations/migration-plan.ts +44 -0
  79. package/src/public/operations/result-envelope.ts +31 -3
  80. package/src/public/operations/source-relationship-parity.ts +60 -3
  81. package/src/public/skills/kibi-usage/SKILL.md +19 -4
  82. package/src/public/skills/kibi-usage/resources/fact-lanes.md +3 -3
  83. package/src/public/skills/kibi-usage/resources/proof.md +44 -3
@@ -1,6 +1,7 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync, } from "node:fs";
3
3
  import path from "node:path";
4
+ import { MigrationActionRefusedError } from "../operations/planning/migration-refusal.js";
4
5
  import { buildMigrationPlan, migrationAction, } from "../public/operations/migration-plan.js";
5
6
  import { PROOF_CONTRACT_VERSION, PROOF_INTEGRATION_VERSION, } from "../public/proof-protocol.js";
6
7
  import { PROOF_INTEGRATIONS_PATH, integrationsPath, proofIntegrationErrors, } from "./integrations.js";
@@ -74,6 +75,16 @@ function packageTestCommand(root) {
74
75
  return ["yarn", "test"];
75
76
  return ["npm", "test"];
76
77
  }
78
+ const PACKAGE_TEST_SCRIPT_RUNNER = "package.json test script";
79
+ /**
80
+ * A command integration is judged as one run. When it runs the package's
81
+ * whole test script, say so: any failing test fails every obligation.
82
+ */
83
+ function wholeRunNote(proposal) {
84
+ if (!proposal.runner.startsWith(PACKAGE_TEST_SCRIPT_RUNNER))
85
+ return "";
86
+ return ` Kibi judges this run as a whole: a failing test anywhere in the package's test script fails every proof obligation that names '${proposal.integration.id}', so unrelated failures prove nothing. To narrow it, pass --command with a command that runs only the proof-bearing tests (kibi proof inspect --update ${proposal.integration.id} --command "<command>" --json once the file exists), or have the command write a kibi.proof-test-report.v1 to the path in KIBI_PROOF_TEST_REPORT so each test is judged by its own steps.`;
87
+ }
77
88
  /** Ordered: the first runner whose marker file exists wins. */
78
89
  const RUNNER_COMMANDS = [
79
90
  {
@@ -144,15 +155,21 @@ const RUNNER_COMMANDS = [
144
155
  * reporter; a native producer can replace it later through an update plan.
145
156
  */
146
157
  // implements REQ-kibi-verification-evidence-contract
147
- export function proposeProofIntegration(root, overrideId) {
158
+ export function proposeProofIntegration(root, overrideId, overrideCommand) {
148
159
  const npmCommand = packageTestCommand(root);
149
- const detected = npmCommand !== null
160
+ const detected = overrideCommand !== undefined && overrideCommand.length > 0
150
161
  ? {
151
- runner: `package.json test script (${npmCommand.join(" ")})`,
162
+ runner: `--command (${overrideCommand.join(" ")})`,
152
163
  id: "unit",
153
- command: npmCommand,
164
+ command: overrideCommand,
154
165
  }
155
- : RUNNER_COMMANDS.find((entry) => entry.files.some((file) => existsSync(path.join(root, file))));
166
+ : npmCommand !== null
167
+ ? {
168
+ runner: `${PACKAGE_TEST_SCRIPT_RUNNER} (${npmCommand.join(" ")})`,
169
+ id: "unit",
170
+ command: npmCommand,
171
+ }
172
+ : RUNNER_COMMANDS.find((entry) => entry.files.some((file) => existsSync(path.join(root, file))));
156
173
  if (detected === undefined)
157
174
  return null;
158
175
  const id = overrideId ?? detected.id;
@@ -235,7 +252,7 @@ export function buildProofIntegrationPlan(root, options = {}) {
235
252
  proposal: null,
236
253
  reason: `${PROOF_INTEGRATIONS_PATH} is not a valid ${PROOF_INTEGRATION_VERSION} file, so Kibi cannot update one integration in it. Run kibi prove for the validation error.`,
237
254
  };
238
- const proposal = proposeProofIntegration(root, update);
255
+ const proposal = proposeProofIntegration(root, update, options.command);
239
256
  if (proposal === null) {
240
257
  return {
241
258
  plan: null,
@@ -273,7 +290,7 @@ export function buildProofIntegrationPlan(root, options = {}) {
273
290
  actions: [action],
274
291
  }),
275
292
  proposal,
276
- reason: `Applying the plan ${update === undefined ? "creates" : "updates"} ${PROOF_INTEGRATIONS_PATH} with the ${proposal.integration.producer} integration '${proposal.integration.id}' (${proposal.integration.command.join(" ")}). Proof-bearing tests then name it in proof_contract.integration and kibi prove runs it.`,
293
+ reason: `Applying the plan ${update === undefined ? "creates" : "updates"} ${PROOF_INTEGRATIONS_PATH} with the ${proposal.integration.producer} integration '${proposal.integration.id}' (${proposal.integration.command.join(" ")}). Proof-bearing tests then name it in proof_contract.integration and kibi prove runs it.${wholeRunNote(proposal)}`,
277
294
  };
278
295
  }
279
296
  function isRecord(value) {
@@ -295,27 +312,27 @@ export function applyProofIntegrationAction(action, root) {
295
312
  (evidence.mode !== "create" && evidence.mode !== "update") ||
296
313
  !isRecord(integration) ||
297
314
  typeof integration.id !== "string")
298
- throw new Error(`Proof integration action '${action.id}' is malformed; rerun kibi proof inspect for a new plan.`);
315
+ throw new MigrationActionRefusedError(`Proof integration action '${action.id}' is malformed; rerun kibi proof inspect for a new plan.`);
299
316
  const planned = isRecord(evidence.sourceHashes) ? evidence.sourceHashes : {};
300
317
  const live = sourceHashes(root);
301
318
  const changed = [
302
319
  ...new Set([...Object.keys(planned), ...Object.keys(live)]),
303
320
  ].filter((file) => planned[file] !== live[file]);
304
321
  if (changed.length > 0)
305
- throw new Error(`Proof integration plan refused: ${changed.join(", ")} changed since planning; rerun kibi proof inspect and review the new plan.`);
322
+ throw new MigrationActionRefusedError(`Proof integration plan refused: ${changed.join(", ")} changed since planning; rerun kibi proof inspect and review the new plan.`);
306
323
  const filePath = integrationsPath(root);
307
324
  let integrations;
308
325
  if (evidence.mode === "create") {
309
326
  if (existsSync(filePath))
310
- throw new Error(`Proof integration plan refused: ${PROOF_INTEGRATIONS_PATH} already exists and this plan only creates it. Run kibi proof inspect --update <integration id> for a plan that adds or replaces one named integration.`);
327
+ throw new MigrationActionRefusedError(`Proof integration plan refused: ${PROOF_INTEGRATIONS_PATH} already exists and this plan only creates it. Run kibi proof inspect --update <integration id> for a plan that adds or replaces one named integration.`);
311
328
  integrations = [integration];
312
329
  }
313
330
  else {
314
331
  if (fileHash(filePath) !== evidence.previousFileHash)
315
- throw new Error(`Proof integration plan refused: ${PROOF_INTEGRATIONS_PATH} changed since planning; rerun kibi proof inspect --update ${integration.id}.`);
332
+ throw new MigrationActionRefusedError(`Proof integration plan refused: ${PROOF_INTEGRATIONS_PATH} changed since planning; rerun kibi proof inspect --update ${integration.id}.`);
316
333
  const current = readIntegrationsFile(root);
317
334
  if (current === null)
318
- throw new Error(`Proof integration plan refused: ${PROOF_INTEGRATIONS_PATH} is not a valid ${PROOF_INTEGRATION_VERSION} file.`);
335
+ throw new MigrationActionRefusedError(`Proof integration plan refused: ${PROOF_INTEGRATIONS_PATH} is not a valid ${PROOF_INTEGRATION_VERSION} file.`);
319
336
  integrations = current.integrations.some((entry) => entry.id === integration.id)
320
337
  ? current.integrations.map((entry) => entry.id === integration.id ? integration : entry)
321
338
  : [...current.integrations, integration];
@@ -323,7 +340,7 @@ export function applyProofIntegrationAction(action, root) {
323
340
  const file = { version: PROOF_INTEGRATION_VERSION, integrations };
324
341
  const errors = proofIntegrationErrors(file);
325
342
  if (errors.length > 0)
326
- throw new Error(`Proof integration plan refused: the result would be invalid (${errors.join("; ")}).`);
343
+ throw new MigrationActionRefusedError(`Proof integration plan refused: the result would be invalid (${errors.join("; ")}).`);
327
344
  mkdirSync(path.dirname(filePath), { recursive: true });
328
345
  const temporary = `${filePath}.${process.pid}.tmp`;
329
346
  writeFileSync(temporary, `${JSON.stringify(file, null, 2)}\n`, "utf8");
@@ -1 +1 @@
1
- {"version":3,"file":"coverage-depth-quality.d.ts","sourceRoot":"","sources":["../../../src/public/impact/coverage-depth-quality.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,gBAAgB,EACjB,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAsIpD,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,MAAM,EAAE,CAI1E;AAwID,wBAAgB,qCAAqC,CACnD,eAAe,EAAE,SAAS,gBAAgB,EAAE,EAC5C,kBAAkB,GAAE,WAAW,CAC7B,MAAM,EACN,QAAQ,CAAC;IACP,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7C,QAAQ,CAAC,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC9C,CAAC,CACS,GACZ,SAAS,iBAAiB,EAAE,CAc9B"}
1
+ {"version":3,"file":"coverage-depth-quality.d.ts","sourceRoot":"","sources":["../../../src/public/impact/coverage-depth-quality.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,gBAAgB,EACjB,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAsIpD,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,MAAM,EAAE,CAI1E;AAgLD,wBAAgB,qCAAqC,CACnD,eAAe,EAAE,SAAS,gBAAgB,EAAE,EAC5C,kBAAkB,GAAE,WAAW,CAC7B,MAAM,EACN,QAAQ,CAAC;IACP,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7C,QAAQ,CAAC,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC9C,CAAC,CACS,GACZ,SAAS,iBAAiB,EAAE,CAmB9B"}
@@ -185,10 +185,38 @@ function coverageForRequirement(result, manifestResults, entities) {
185
185
  scenarioTests,
186
186
  };
187
187
  }
188
+ /**
189
+ * Requirement statuses that keep a requirement in the coverage-depth review.
190
+ * `closed` is reviewed only when tagged `implemented` (the documented
191
+ * "done, with evidence" shape); a plain closed, deprecated or superseded
192
+ * requirement is retired history, not a coverage gap.
193
+ */
194
+ const REVIEWED_REQUIREMENT_STATUSES = new Set([
195
+ "open",
196
+ "in_progress",
197
+ "active",
198
+ "approved",
199
+ ]);
200
+ function supersededRequirementIds(manifestResults) {
201
+ return new Set(manifestResults.flatMap((result) => result.entity.type === "req"
202
+ ? result.relationships.flatMap((relationship) => relationship.type === "supersedes" ? [relationship.to] : [])
203
+ : []));
204
+ }
205
+ // implements REQ-audit-quality-diagnostics-v1
206
+ function isReviewableRequirement(requirement, superseded) {
207
+ if (superseded.has(requirement.id))
208
+ return false;
209
+ const status = requirement.status.trim().toLowerCase();
210
+ if (REVIEWED_REQUIREMENT_STATUSES.has(status))
211
+ return true;
212
+ return (status === "closed" && (requirement.tags ?? []).includes("implemented"));
213
+ }
188
214
  export function createCoverageDepthQualityDiagnostics(manifestResults, proofByRequirement = new Map()) {
189
215
  const entities = entitiesById(manifestResults);
216
+ const superseded = supersededRequirementIds(manifestResults);
190
217
  return manifestResults
191
- .filter((result) => result.entity.type === "req")
218
+ .filter((result) => result.entity.type === "req" &&
219
+ isReviewableRequirement(result.entity, superseded))
192
220
  .flatMap((result) => {
193
221
  const diagnostic = createDiagnostic(coverageForRequirement(result, manifestResults, entities), proofByRequirement.get(result.entity.id));
194
222
  return diagnostic === undefined ? [] : [diagnostic];
@@ -1 +1 @@
1
- {"version":3,"file":"contracts.d.ts","sourceRoot":"","sources":["../../../src/public/operations/contracts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,0BAA0B,EAC1B,aAAa,EACd,MAAM,YAAY,CAAC;AAEpB,oEAAoE;AACpE,MAAM,MAAM,mBAAmB,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAsZpE;;uEAEuE;AACvE,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,mBAAmB,GAC1B,mBAAmB,CAMrB;AAiXD,eAAO,MAAM,sBAAsB,EAAE,QAAQ,CAC3C,MAAM,CAAC,aAAa,EAAE,mBAAmB,CAAC,CAa3C,CAAC;AAmDF,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,SAAS;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,EAClD,YAAY,EAAE,MAAM,GACnB,IAAI,CAIN;AAED,wBAAgB,eAAe,CAC7B,SAAS,EAAE,aAAa,EACxB,OAAO,EAAE,SAAS,eAAe,EAAE,GAClC,SAAS,0BAA0B,EAAE,CAoBvC"}
1
+ {"version":3,"file":"contracts.d.ts","sourceRoot":"","sources":["../../../src/public/operations/contracts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,0BAA0B,EAC1B,aAAa,EACd,MAAM,YAAY,CAAC;AAEpB,oEAAoE;AACpE,MAAM,MAAM,mBAAmB,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAsZpE;;uEAEuE;AACvE,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,mBAAmB,GAC1B,mBAAmB,CAMrB;AAoXD,eAAO,MAAM,sBAAsB,EAAE,QAAQ,CAC3C,MAAM,CAAC,aAAa,EAAE,mBAAmB,CAAC,CAa3C,CAAC;AAmDF,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,SAAS;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,EAClD,YAAY,EAAE,MAAM,GACnB,IAAI,CAIN;AAED,wBAAgB,eAAe,CAC7B,SAAS,EAAE,aAAa,EACxB,OAAO,EAAE,SAAS,eAAe,EAAE,GAClC,SAAS,0BAA0B,EAAE,CAoBvC"}
@@ -355,6 +355,8 @@ const BASE_DATA_SCHEMAS = {
355
355
  truncated: booleanValue,
356
356
  queryAnalysis: recordValue,
357
357
  answer: recordValue,
358
+ branch: { type: ["string", "null"] },
359
+ branchStore: recordValue,
358
360
  }, ["results", "count"]),
359
361
  kb_status: objectData({
360
362
  branch: stringValue,
@@ -377,6 +379,7 @@ const BASE_DATA_SCHEMAS = {
377
379
  staleReasons: recordArray,
378
380
  staleReasonCount: integerValue,
379
381
  staleReasonsTruncated: booleanValue,
382
+ notices: recordArray,
380
383
  branchAttachment: recordValue,
381
384
  proofSnapshotChanges: recordArray,
382
385
  proofSnapshotChangeCount: integerValue,
@@ -1,7 +1,7 @@
1
1
  import { type IntentSearchAnalysis, type IntentSearchFacets, type IntentSearchMatch, type SourceLocation } from "../../intent-search.js";
2
2
  import { type SearchAnswer } from "../../search-answer.js";
3
3
  import type { SearchMatch } from "../../search-ranking.js";
4
- import { type BranchStoreInspection } from "../../utils/branch-store.js";
4
+ import { BRANCH_STORE_NOT_COMPILED, type BranchStoreInspection } from "../../utils/branch-store.js";
5
5
  import { type MigrationConfigStatus, type MigrationPlan } from "./migration-plan.js";
6
6
  import type { OperationContext } from "./runtime-types.js";
7
7
  import type { OperationResult } from "./types.js";
@@ -35,6 +35,17 @@ export type SearchPayload = {
35
35
  readonly truncated?: boolean;
36
36
  readonly queryAnalysis?: IntentSearchAnalysis;
37
37
  readonly answer?: SearchAnswer;
38
+ /** The Kibi branch whose store was searched, when the runtime attached one. */
39
+ readonly branch?: string | null;
40
+ /** Present when the searched store was never compiled for this branch. */
41
+ readonly branchStore?: SearchBranchStoreNotice;
42
+ };
43
+ export type SearchBranchStoreNotice = {
44
+ readonly state: "not_compiled";
45
+ readonly code: typeof BRANCH_STORE_NOT_COMPILED;
46
+ readonly path: string;
47
+ readonly detail: string;
48
+ readonly remediation: Readonly<Record<string, unknown>>;
38
49
  };
39
50
  export type StatusInput = Readonly<Record<string, never>>;
40
51
  export type StatusPayload = {
@@ -54,6 +65,8 @@ export type StatusPayload = {
54
65
  readonly staleReasons?: readonly Record<string, unknown>[];
55
66
  readonly staleReasonCount?: number;
56
67
  readonly staleReasonsTruncated?: boolean;
68
+ /** Informational, non-blocking observations (never make the KB stale). */
69
+ readonly notices?: readonly Record<string, unknown>[];
57
70
  readonly branchAttachment?: {
58
71
  readonly gitBranch: string;
59
72
  readonly kbBranch: string;
@@ -1 +1 @@
1
- {"version":3,"file":"discovery-executors.d.ts","sourceRoot":"","sources":["../../../src/public/operations/discovery-executors.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"discovery-executors.d.ts","sourceRoot":"","sources":["../../../src/public/operations/discovery-executors.ts"],"names":[],"mappings":"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"}
@@ -7,11 +7,34 @@ import { SwiplResolutionError } from "../../prolog/swipl-resolver.js";
7
7
  import { buildSearchAnswer } from "../../search-answer.js";
8
8
  import { rankEntities } from "../../search-ranking.js";
9
9
  import { resolveBranchAttachment } from "../../utils/branch-resolver.js";
10
- import { BRANCH_STORE_NOT_COMPILED, branchStoreReason, inspectBranchStore, storeLockJournalReason, uncompiledBranchStoreReason, } from "../../utils/branch-store.js";
10
+ import { BRANCH_STORE_NOT_COMPILED, branchStoreReason, inspectBranchStore, storeLockJournalReason, storeLockTakeoverReason, uncompiledBranchStoreReason, } from "../../utils/branch-store.js";
11
+ import { confirmSourceNewerReasons } from "../../utils/content-freshness.js";
11
12
  import { loadSearchCandidates, paginateResults, queryEntitiesViaQuery, reloadFullEntities, validateEntityType, } from "./discovery-entities.js";
12
13
  import { buildActionsFromStatus, readMigrationConfigStatus, } from "./migration-plan.js";
13
14
  import { OperationJsonDecodeError, runOperationJsonQuery, } from "./prolog-json.js";
14
15
  import { readWorkspaceSnapshot } from "./workspace-snapshot.js";
16
+ /**
17
+ * An empty result from a store that was never compiled says nothing about
18
+ * the authored requirements, so search reports the store state itself (the
19
+ * same reason kb_status and kb_check use) instead of a bare "no results".
20
+ */
21
+ // implements REQ-cli-status-pre-first-sync, REQ-mcp-search-discovery
22
+ function uncompiledSearchNotice(context) {
23
+ const attachment = context.branchAttachment;
24
+ if (attachment === undefined)
25
+ return null;
26
+ const store = inspectBranchStore(context.workspaceRoot, attachment.kbBranch);
27
+ const reason = uncompiledBranchStoreReason(context.workspaceRoot, store, attachment.kbBranch);
28
+ if (reason === null)
29
+ return null;
30
+ return {
31
+ state: "not_compiled",
32
+ code: BRANCH_STORE_NOT_COMPILED,
33
+ path: store.path,
34
+ detail: String(reason.detail),
35
+ remediation: reason.remediation,
36
+ };
37
+ }
15
38
  function requireProlog(context) {
16
39
  if (!context.prolog) {
17
40
  throw new Error("Discovery operation requires a Prolog context");
@@ -118,6 +141,15 @@ export async function executeSearch(input, context) {
118
141
  validateEntityType(type);
119
142
  try {
120
143
  const prolog = requireProlog(context);
144
+ const branch = context.branchAttachment?.kbBranch ?? null;
145
+ const storeNotice = uncompiledSearchNotice(context);
146
+ const branchFields = {
147
+ branch,
148
+ ...(storeNotice ? { branchStore: storeNotice } : {}),
149
+ };
150
+ const storeNote = storeNotice
151
+ ? ` Note: ${storeNotice.detail} Run kibi sync before relying on search results.`
152
+ : "";
121
153
  const intentMode = rankingMode === "intent-v1" ||
122
154
  semanticFacets !== undefined ||
123
155
  sourceLocations !== undefined;
@@ -142,12 +174,12 @@ export async function executeSearch(input, context) {
142
174
  : undefined;
143
175
  // The structured payload carries every row; the text is a short
144
176
  // human-readable digest instead of a second copy of the results.
145
- const text = intentResult.matches.length === 0
177
+ const text = `${intentResult.matches.length === 0
146
178
  ? `No intent search results for '${trimmedQuery}' (abstained).`
147
179
  : `Found ${intentResult.matches.length} intent search results for '${trimmedQuery}'${intentResult.analysis.ambiguous ? " (top matches are close; confirm before relying on one)" : ""}. Top: ${paginated
148
180
  .slice(0, 5)
149
181
  .map((match) => String(match.entity.id ?? ""))
150
- .join(", ")}${answerLayer ? `. Governing: ${answerLayer.governing.map((req) => req.id).join(", ") || "none found"}` : ""}.`;
182
+ .join(", ")}${answerLayer ? `. Governing: ${answerLayer.governing.map((req) => req.id).join(", ") || "none found"}` : ""}.`}${storeNote}`;
151
183
  return {
152
184
  content: [{ type: "text", text }],
153
185
  structuredContent: {
@@ -156,6 +188,7 @@ export async function executeSearch(input, context) {
156
188
  truncated: offset + paginated.length < intentResult.matches.length,
157
189
  queryAnalysis: intentResult.analysis,
158
190
  ...(answerLayer ? { answer: answerLayer } : {}),
191
+ ...branchFields,
159
192
  },
160
193
  };
161
194
  }
@@ -168,17 +201,18 @@ export async function executeSearch(input, context) {
168
201
  }, context.signal);
169
202
  const matches = await rankEntities(entities, trimmedQuery, context.workspaceRoot);
170
203
  const paginated = paginateResults(matches, limit, offset);
171
- const text = matches.length === 0
204
+ const text = `${matches.length === 0
172
205
  ? `No search results for '${trimmedQuery}'.`
173
206
  : `Found ${matches.length} search results for '${trimmedQuery}'. Showing ${paginated.length} (offset ${offset}, limit ${limit}): ${paginated
174
207
  .map((match) => `${String(match.entity.id ?? "")} [${match.reasons.join(", ")}]`)
175
- .join(", ")}`;
208
+ .join(", ")}`}${storeNote}`;
176
209
  return {
177
210
  content: [{ type: "text", text }],
178
211
  structuredContent: {
179
212
  results: await projectMatches(prolog, paginated, fields),
180
213
  count: matches.length,
181
214
  truncated: offset + paginated.length < matches.length,
215
+ ...branchFields,
182
216
  },
183
217
  };
184
218
  }
@@ -272,7 +306,19 @@ export async function executeStatus(_input, context) {
272
306
  await ownedEngine?.terminate();
273
307
  }
274
308
  const snapshotEvidence = await readWorkspaceSnapshot(context);
275
- const existingReasons = payload.staleReasons ?? [];
309
+ // implements REQ-cli-status-pre-first-sync
310
+ // Prolog compares file times only. A fresh clone or a checkout rewrites
311
+ // every mtime without changing a byte, so confirm each "newer" source
312
+ // against the content hashes the last compilation recorded.
313
+ const prologReasons = payload.staleReasons ?? [];
314
+ const confirmed = confirmSourceNewerReasons(context.workspaceRoot, store.path, prologReasons);
315
+ const existingReasons = confirmed.kept;
316
+ if (confirmed.dropped.length > 0 &&
317
+ confirmed.kept.length === 0 &&
318
+ payload.staleReasonsTruncated !== true &&
319
+ payload.syncState === "stale") {
320
+ payload = { ...payload, syncState: "fresh", dirty: false };
321
+ }
276
322
  // implements REQ-cli-status-pre-first-sync
277
323
  // A missing or empty store beside authored sources gets the one reason
278
324
  // whose remediation works (kibi sync); `kibi branch ensure` alone would
@@ -280,6 +326,9 @@ export async function executeStatus(_input, context) {
280
326
  const storeReason = uncompiledBranchStoreReason(context.workspaceRoot, store, attachment.kbBranch) ?? branchStoreReason(store);
281
327
  const storeUncompiled = storeReason?.code === BRANCH_STORE_NOT_COMPILED;
282
328
  const lockReason = storeLockJournalReason(store.path);
329
+ // implements REQ-core-journaled-engine-persistence
330
+ // A stale-lock takeover heals itself; report it without making the KB stale.
331
+ const takeoverNotice = storeLockTakeoverReason(store.path);
283
332
  const compilerReason = compilerFingerprintReason(store.path);
284
333
  const engineReason = engineStatus
285
334
  ? {
@@ -311,13 +360,14 @@ export async function executeStatus(_input, context) {
311
360
  // Source hashes can all match while the compilation itself is lossy, so
312
361
  // a compiler contract change alone makes the store stale.
313
362
  ...(compilerReason ? { syncState: "stale", dirty: true } : {}),
314
- // An empty store has no stale file to report, yet nothing in it is
315
- // current: the authored sources were never compiled.
316
- ...(storeUncompiled && store.state === "healthy"
317
- ? { syncState: "stale", dirty: true }
318
- : {}),
363
+ // A missing or empty store has no stale file to report, yet nothing in
364
+ // it is current: the authored sources were never compiled. (A missing
365
+ // store without authored sources, and an unreadable or incomplete one,
366
+ // stay "unknown".)
367
+ ...(storeUncompiled ? { syncState: "stale", dirty: true } : {}),
319
368
  branchAttachment: attachment,
320
369
  branchStore: store,
370
+ ...(takeoverNotice ? { notices: [takeoverNotice] } : {}),
321
371
  ...(engineStatus ? { engineStatus } : {}),
322
372
  staleReasons,
323
373
  staleReasonCount: staleReasons.length,
@@ -447,7 +497,7 @@ export async function executeStatus(_input, context) {
447
497
  content: [
448
498
  {
449
499
  type: "text",
450
- text: `Branch ${payload.branch} is ${enrichedPayload.syncState} (snapshot ${payload.snapshotId}, dirty=${enrichedPayload.dirty}, proofSnapshot=${enrichedPayload.proofSnapshot})${storeUncompiled ? `. Blocking: ${String(storeReason?.detail)} Run kibi sync.` : ""}`,
500
+ text: `Branch ${payload.branch} is ${enrichedPayload.syncState} (snapshot ${payload.snapshotId}, dirty=${enrichedPayload.dirty}, proofSnapshot=${enrichedPayload.proofSnapshot})${storeUncompiled ? `. Blocking: ${String(storeReason?.detail)} Run kibi sync.` : ""}${takeoverNotice ? `. Note: ${String(takeoverNotice.detail)}` : ""}`,
451
501
  },
452
502
  ],
453
503
  structuredContent: statusWithPlan,
@@ -94,6 +94,8 @@ export type MigrationConfigStatus = Readonly<{
94
94
  configHash: string | null;
95
95
  }>;
96
96
  export declare function readMigrationConfigStatus(workspaceRoot: string): MigrationConfigStatus;
97
+ /** Migration action code of the automatic recompile of changed sources. */
98
+ export declare const FRESHNESS_RESYNC = "freshness_resync";
97
99
  export declare function buildActionsFromStatus(input: {
98
100
  workspaceRoot: string;
99
101
  branchAttachment?: Readonly<Record<string, unknown>>;
@@ -1 +1 @@
1
- {"version":3,"file":"migration-plan.d.ts","sourceRoot":"","sources":["../../../src/public/operations/migration-plan.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"migration-plan.d.ts","sourceRoot":"","sources":["../../../src/public/operations/migration-plan.ts"],"names":[],"mappings":"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"}
@@ -3,6 +3,7 @@ import { existsSync, readFileSync } from "node:fs";
3
3
  import * as path from "node:path";
4
4
  import { BRANCH_STORE_NOT_COMPILED } from "../../utils/branch-store.js";
5
5
  import { legacyConfigExists } from "../../utils/config.js";
6
+ import { MTIME_SOURCE_REASON_CODES } from "../../utils/content-freshness.js";
6
7
  import { readKbManifestStatus } from "../../utils/kb-manifest.js";
7
8
  import { getSchemaVersionStatus, normalizeSchemaVersion, } from "../../utils/schema-version.js";
8
9
  import { lifecycleActionsFromViolations, schema6ReviewActionsFromCheck, } from "./schema6-check-actions.js";
@@ -438,6 +439,8 @@ function readLegacySchemaVersion(workspaceRoot) {
438
439
  }
439
440
  }
440
441
  // implements REQ-agent-guided-migration-orchestration
442
+ /** Migration action code of the automatic recompile of changed sources. */
443
+ export const FRESHNESS_RESYNC = "freshness_resync";
441
444
  export function buildActionsFromStatus(input) {
442
445
  const actions = [];
443
446
  const attachment = input.branchAttachment;
@@ -562,11 +565,39 @@ export function buildActionsFromStatus(input) {
562
565
  autoApplicable: true,
563
566
  }));
564
567
  }
568
+ // implements REQ-cli-status-pre-first-sync
569
+ // Sources whose content changed since the last compilation (kb_status has
570
+ // already dropped mtime-only reasons) are fixed by recompiling them: one
571
+ // automatic `kibi sync`, not a review per file. An uncompiled store is
572
+ // compiled by the step above, which also covers these files.
573
+ const resyncReasons = (input.staleReasons ?? []).filter((reason) => typeof reason.code === "string" &&
574
+ MTIME_SOURCE_REASON_CODES.has(reason.code));
575
+ if (resyncReasons.length > 0 && uncompiled === undefined) {
576
+ actions.push(migrationAction({
577
+ id: "freshness-resync",
578
+ code: FRESHNESS_RESYNC,
579
+ category: "freshness",
580
+ safety: "automatic",
581
+ invocation: { kind: "cli", command_argv: ["kibi", "sync"] },
582
+ affectedFiles: [
583
+ ...new Set(resyncReasons.flatMap((reason) => typeof reason.path === "string" ? [reason.path] : [])),
584
+ ].sort(),
585
+ evidence: { reasons: resyncReasons },
586
+ dependsOn: actions
587
+ .map((action) => action.id)
588
+ .filter((id) => id === "branch-store-ensure" || id === "schema-config-upgrade"),
589
+ postconditions: [{ syncState: "fresh" }],
590
+ autoApplicable: true,
591
+ }));
592
+ }
565
593
  for (const reason of input.staleReasons ?? []) {
566
594
  const code = typeof reason.code === "string" ? reason.code : "stale_source";
567
595
  // Planned above as an automatic compile step, not a review.
568
596
  if (code === BRANCH_STORE_NOT_COMPILED)
569
597
  continue;
598
+ // Planned above as one automatic resync (or covered by the compile).
599
+ if (MTIME_SOURCE_REASON_CODES.has(code))
600
+ continue;
570
601
  const file = typeof reason.path === "string" ? reason.path : "";
571
602
  actions.push(migrationAction({
572
603
  id: `freshness-${code}-${file}`,
@@ -1 +1 @@
1
- {"version":3,"file":"result-envelope.d.ts","sourceRoot":"","sources":["../../../src/public/operations/result-envelope.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE7E,eAAO,MAAM,qBAAqB,EAAG,CAAU,CAAC;AAoChD,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,eAAe,EACvB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,UAAU,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAS/B;AAoFD,wBAAgB,aAAa,CAAC,IAAI,EAAE;IAClC,QAAQ,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,CAAC;IACtC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;CACjC,GAAG,MAAM,CAET;AAED,wBAAgB,YAAY,CAAC,CAAC,EAC5B,IAAI,EAAE;IACJ,QAAQ,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,CAAC;IACtC,QAAQ,CAAC,OAAO,EAAE,SAAS,eAAe,EAAE,CAAC;IAC7C,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;CACjC,EACD,IAAI,EAAE,CAAC,EACP,OAAO,GAAE,OAAO,CACd,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,QAAQ,GAAG,aAAa,GAAG,aAAa,GAAG,OAAO,CAAC,CACxE,GAAG;IACF;;;;OAIG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;CACzB,GACL,UAAU,CAAC,CAAC,CAAC,CAkCf;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAKrD;AAGD,MAAM,WAAW,uBAAuB;IACtC,sEAAsE;IACtE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC5C,2EAA2E;IAC3E,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACzC;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,OAAO,GACd,uBAAuB,CAYzB;AAaD;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAC3C,IAAI,CAKN"}
1
+ {"version":3,"file":"result-envelope.d.ts","sourceRoot":"","sources":["../../../src/public/operations/result-envelope.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE7E,eAAO,MAAM,qBAAqB,EAAG,CAAU,CAAC;AAoChD,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,eAAe,EACvB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,UAAU,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAS/B;AAoFD,wBAAgB,aAAa,CAAC,IAAI,EAAE;IAClC,QAAQ,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,CAAC;IACtC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;CACjC,GAAG,MAAM,CAET;AAYD,wBAAgB,YAAY,CAAC,CAAC,EAC5B,IAAI,EAAE;IACJ,QAAQ,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,CAAC;IACtC,QAAQ,CAAC,OAAO,EAAE,SAAS,eAAe,EAAE,CAAC;IAC7C,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;CACjC,EACD,IAAI,EAAE,CAAC,EACP,OAAO,GAAE,OAAO,CACd,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,QAAQ,GAAG,aAAa,GAAG,aAAa,GAAG,OAAO,CAAC,CACxE,GAAG;IACF;;;;OAIG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;CACzB,GACL,UAAU,CAAC,CAAC,CAAC,CAmDf;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAKrD;AAGD,MAAM,WAAW,uBAAuB;IACtC,sEAAsE;IACtE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC5C,2EAA2E;IAC3E,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACzC;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,OAAO,GACd,uBAAuB,CAYzB;AAaD;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAC3C,IAAI,CAKN"}
@@ -1,3 +1,4 @@
1
+ import { MIGRATION_PLAN_REFUSED } from "../../operations/planning/migration-refusal.js";
1
2
  export const KIBI_PROTOCOL_VERSION = 1;
2
3
  function record(value) {
3
4
  return value !== null && typeof value === "object" && !Array.isArray(value);
@@ -103,14 +104,25 @@ function extraFailedEffects(declared, data) {
103
104
  export function resultVersion(spec) {
104
105
  return spec.resultVersion ?? `kibi.${spec.name}.v1`;
105
106
  }
107
+ function refusalDetail(row) {
108
+ const results = Array.isArray(row.actionResults) ? row.actionResults : [];
109
+ const failure = results.find((entry) => record(entry) && entry.outcome === "failed");
110
+ return record(failure) && typeof failure.detail === "string"
111
+ ? failure.detail
112
+ : "";
113
+ }
106
114
  export function toKibiResult(spec, data, options = {}) {
107
115
  const row = record(data) ? data : undefined;
116
+ // A migration plan whose actions were all refused changed nothing: it is
117
+ // an error, not a success that needs reconciliation.
118
+ const migrationRefused = row?.version === "kibi.migration-apply-result.v1" &&
119
+ row.outcome === "refused";
108
120
  let status = options.status;
109
121
  if (!status) {
110
122
  status = "success";
111
123
  if (row?.status === "committed_with_repairs")
112
124
  status = "committed_with_repairs";
113
- if (row?.status === "rejected")
125
+ if (row?.status === "rejected" || migrationRefused)
114
126
  status = "error";
115
127
  }
116
128
  const terminalError = row?.status === "rejected"
@@ -119,9 +131,17 @@ export function toKibiResult(spec, data, options = {}) {
119
131
  message: "Bootstrap stopped at a deterministic failure. Inspect actionResults for committed actions and re-plan from the current state.",
120
132
  retryable: false,
121
133
  }
122
- : undefined;
134
+ : migrationRefused
135
+ ? {
136
+ code: MIGRATION_PLAN_REFUSED,
137
+ message: `Migration plan refused; nothing was changed. ${refusalDetail(row)}`.trim(),
138
+ retryable: false,
139
+ }
140
+ : undefined;
123
141
  const resultError = options.error ?? terminalError;
124
- const outcome = effectOutcome(status, options);
142
+ const outcome = effectOutcome(status, migrationRefused && options.attempted === undefined
143
+ ? { ...options, attempted: false }
144
+ : options);
125
145
  return {
126
146
  kibiProtocol: KIBI_PROTOCOL_VERSION,
127
147
  operation: spec.name,
@@ -1 +1 @@
1
- {"version":3,"file":"source-relationship-parity.d.ts","sourceRoot":"","sources":["../../../src/public/operations/source-relationship-parity.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD,MAAM,MAAM,wBAAwB,GAAG,QAAQ,CAAC;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;CACpC,CAAC,CAAC;AAaH,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,SAAS,wBAAwB,EAAE,EAC7C,QAAQ,EAAE,SAAS,wBAAwB,EAAE,GAC5C,SAAS,EAAE,CAwDb;AAuCD,wBAAgB,6BAA6B,CAC3C,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,GACX,wBAAwB,EAAE,CAmB5B;AA6BD,wBAAsB,yCAAyC,CAC7D,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC,SAAS,EAAE,CAAC,CA0DtB"}
1
+ {"version":3,"file":"source-relationship-parity.d.ts","sourceRoot":"","sources":["../../../src/public/operations/source-relationship-parity.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD,MAAM,MAAM,wBAAwB,GAAG,QAAQ,CAAC;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;CACpC,CAAC,CAAC;AAaH,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,SAAS,wBAAwB,EAAE,EAC7C,QAAQ,EAAE,SAAS,wBAAwB,EAAE,GAC5C,SAAS,EAAE,CAwDb;AAuCD,wBAAgB,6BAA6B,CAC3C,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,GACX,wBAAwB,EAAE,CAmB5B;AA6BD,wBAAsB,yCAAyC,CAC7D,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC,SAAS,EAAE,CAAC,CA0DtB"}
@@ -2,6 +2,7 @@ import { execFileSync } from "node:child_process";
2
2
  import path from "node:path";
3
3
  import { discoverSourceFiles } from "../../commands/sync/discovery.js";
4
4
  import { processExtractions } from "../../commands/sync/extraction.js";
5
+ import { findUntrackedDocumentMatches } from "../../commands/sync/untracked-targets.js";
5
6
  import { RELATIONSHIP_TYPES } from "../../operations/mutation/relationships.js";
6
7
  import { parseListOfLists, parsePrologValue } from "../../prolog/codec.js";
7
8
  import { readAllShards } from "../../relationships/shards.js";
@@ -173,5 +174,58 @@ export async function collectSourceRelationshipParityViolations(workspaceRoot, p
173
174
  source: ".kb/relationships",
174
175
  });
175
176
  }
176
- return compareRelationshipParity(authored, await compiledRelationships(prolog));
177
+ return explainUntrackedEndpoints(workspaceRoot, compareRelationshipParity(authored, await compiledRelationships(prolog)));
178
+ }
179
+ /**
180
+ * An authored relationship is missing from the compiled KB most often
181
+ * because an endpoint is declared in a file sync cannot see: one Git does not
182
+ * track and no pending-source receipt covers (for example a `.kb/symbols.yaml`
183
+ * that `kibi init` created and kb_upsert appended to before receipts covered
184
+ * existing untracked files). Name that file and the fix.
185
+ */
186
+ // implements REQ-kibi-source-relationship-parity
187
+ function explainUntrackedEndpoints(workspaceRoot, violations) {
188
+ const endpoints = new Set();
189
+ for (const violation of violations) {
190
+ const relationship = authoredToCompiledRelationship(violation);
191
+ if (relationship === null)
192
+ continue;
193
+ endpoints.add(relationship.from);
194
+ endpoints.add(relationship.to);
195
+ }
196
+ if (endpoints.size === 0)
197
+ return violations;
198
+ const untracked = findUntrackedDocumentMatches(workspaceRoot, [...endpoints]);
199
+ if (untracked.size === 0)
200
+ return violations;
201
+ return violations.map((violation) => {
202
+ const relationship = authoredToCompiledRelationship(violation);
203
+ if (relationship === null)
204
+ return violation;
205
+ const sources = [relationship.from, relationship.to].flatMap((id) => {
206
+ const file = untracked.get(id);
207
+ return file === undefined ? [] : [{ entityId: id, file }];
208
+ });
209
+ if (sources.length === 0)
210
+ return violation;
211
+ const files = [...new Set(sources.map((source) => source.file))];
212
+ return {
213
+ ...violation,
214
+ suggestion: `${sources.map((source) => source.entityId).join(" and ")} ${sources.length === 1 ? "is" : "are"} declared in ${files.join(", ")}, which Git does not track and no pending-source receipt covers, so sync never compiles it. Run 'git add ${files.join(" ")}' (staging is enough) or rewrite the entity with kb_upsert, then run kibi sync and rerun kb_check.`,
215
+ evidence: {
216
+ ...(violation.evidence ?? {}),
217
+ untrackedSources: sources,
218
+ },
219
+ };
220
+ });
221
+ }
222
+ function authoredToCompiledRelationship(violation) {
223
+ const evidence = violation.evidence;
224
+ if (evidence?.direction !== "authored_to_compiled")
225
+ return null;
226
+ const from = evidence.relationship?.from;
227
+ const to = evidence.relationship?.to;
228
+ return typeof from === "string" && typeof to === "string"
229
+ ? { from, to }
230
+ : null;
177
231
  }