kibi-cli 2.19.0 → 2.21.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 (117) hide show
  1. package/dist/cli-operation-metadata.d.ts +1 -1
  2. package/dist/cli-operation-metadata.js +1 -1
  3. package/dist/cli-register-maintenance.js +1 -1
  4. package/dist/commands/engine.d.ts +2 -1
  5. package/dist/commands/engine.d.ts.map +1 -1
  6. package/dist/commands/engine.js +6 -1
  7. package/dist/commands/migrate.d.ts +2 -0
  8. package/dist/commands/migrate.d.ts.map +1 -1
  9. package/dist/commands/migrate.js +32 -6
  10. package/dist/commands/sync/discovery.d.ts.map +1 -1
  11. package/dist/commands/sync/discovery.js +14 -2
  12. package/dist/engine.d.ts.map +1 -1
  13. package/dist/engine.js +24 -6
  14. package/dist/extractors/markdown.d.ts.map +1 -1
  15. package/dist/extractors/markdown.js +2 -1
  16. package/dist/intent-search.d.ts +7 -0
  17. package/dist/intent-search.d.ts.map +1 -1
  18. package/dist/intent-search.js +66 -4
  19. package/dist/operations/migration/kb-sources.d.ts +5 -1
  20. package/dist/operations/migration/kb-sources.d.ts.map +1 -1
  21. package/dist/operations/migration/kb-sources.js +28 -1
  22. package/dist/operations/modeling/predicate-applicability.d.ts.map +1 -1
  23. package/dist/operations/modeling/predicate-applicability.js +10 -4
  24. package/dist/operations/modeling/predicate-applyplan.d.ts.map +1 -1
  25. package/dist/operations/modeling/predicate-applyplan.js +16 -5
  26. package/dist/operations/modeling/predicate-catalog-4.d.ts.map +1 -1
  27. package/dist/operations/modeling/predicate-catalog-4.js +3 -0
  28. package/dist/operations/modeling/predicate-inference-1.d.ts.map +1 -1
  29. package/dist/operations/modeling/predicate-inference-1.js +34 -7
  30. package/dist/operations/modeling/predicate-score-3.js +1 -1
  31. package/dist/operations/modeling/predicate-types.d.ts +6 -0
  32. package/dist/operations/modeling/predicate-types.d.ts.map +1 -1
  33. package/dist/operations/modeling/suggest-predicates.d.ts.map +1 -1
  34. package/dist/operations/modeling/suggest-predicates.js +111 -0
  35. package/dist/operations/mutation/source-authoring.d.ts +8 -0
  36. package/dist/operations/mutation/source-authoring.d.ts.map +1 -1
  37. package/dist/operations/mutation/source-authoring.js +33 -0
  38. package/dist/operations/mutation/types.d.ts +26 -0
  39. package/dist/operations/mutation/types.d.ts.map +1 -1
  40. package/dist/operations/mutation/upsert.d.ts.map +1 -1
  41. package/dist/operations/mutation/upsert.js +8 -2
  42. package/dist/operations/mutation/validate-upsert.d.ts.map +1 -1
  43. package/dist/operations/mutation/validate-upsert.js +116 -4
  44. package/dist/operations/mutation/validation.d.ts.map +1 -1
  45. package/dist/operations/mutation/validation.js +2 -1
  46. package/dist/operations/mutation/warnings.d.ts +10 -0
  47. package/dist/operations/mutation/warnings.d.ts.map +1 -1
  48. package/dist/operations/mutation/warnings.js +26 -0
  49. package/dist/operations/mutation/what-if.d.ts +25 -0
  50. package/dist/operations/mutation/what-if.d.ts.map +1 -0
  51. package/dist/operations/mutation/what-if.js +59 -0
  52. package/dist/operations/planning/compile-intent.d.ts +15 -20
  53. package/dist/operations/planning/compile-intent.d.ts.map +1 -1
  54. package/dist/operations/planning/compile-intent.js +64 -53
  55. package/dist/operations/semantic-advisor/clauses.d.ts +9 -0
  56. package/dist/operations/semantic-advisor/clauses.d.ts.map +1 -1
  57. package/dist/operations/semantic-advisor/clauses.js +32 -7
  58. package/dist/prolog/janitor.d.ts +26 -2
  59. package/dist/prolog/janitor.d.ts.map +1 -1
  60. package/dist/prolog/janitor.js +55 -3
  61. package/dist/prolog/store-lock.d.ts +28 -3
  62. package/dist/prolog/store-lock.d.ts.map +1 -1
  63. package/dist/prolog/store-lock.js +103 -12
  64. package/dist/public/operations/catalog.d.ts +49 -5
  65. package/dist/public/operations/catalog.d.ts.map +1 -1
  66. package/dist/public/operations/check-executor.d.ts +2 -2
  67. package/dist/public/operations/check-executor.d.ts.map +1 -1
  68. package/dist/public/operations/check-executor.js +35 -0
  69. package/dist/public/operations/check-format-shared.d.ts +16 -0
  70. package/dist/public/operations/check-format-shared.d.ts.map +1 -1
  71. package/dist/public/operations/check-format-shared.js +19 -0
  72. package/dist/public/operations/contracts.d.ts.map +1 -1
  73. package/dist/public/operations/contracts.js +10 -0
  74. package/dist/public/operations/discovery-executors.d.ts +3 -0
  75. package/dist/public/operations/discovery-executors.d.ts.map +1 -1
  76. package/dist/public/operations/discovery-executors.js +7 -2
  77. package/dist/public/operations/migration-plan.d.ts.map +1 -1
  78. package/dist/public/operations/migration-plan.js +37 -7
  79. package/dist/public/operations/specs/composite.d.ts +1 -1
  80. package/dist/public/operations/specs/composite.js +1 -1
  81. package/dist/public/operations/specs/discovery.d.ts +2 -2
  82. package/dist/public/operations/specs/discovery.d.ts.map +1 -1
  83. package/dist/public/operations/specs/discovery.js +2 -2
  84. package/dist/public/operations/specs/mutation-schemas.d.ts +2 -2
  85. package/dist/public/operations/specs/mutation-schemas.d.ts.map +1 -1
  86. package/dist/public/operations/specs/mutation-schemas.js +8 -17
  87. package/dist/public/operations/specs/upsert.d.ts +46 -2
  88. package/dist/public/operations/specs/upsert.d.ts.map +1 -1
  89. package/dist/public/operations/specs/upsert.js +14 -0
  90. package/dist/public/schemas/entity.d.ts.map +1 -1
  91. package/dist/public/schemas/entity.js +2 -13
  92. package/dist/public/skills/kibi-usage/SKILL.md +38 -1
  93. package/dist/public/skills/kibi-usage/resources/fact-lanes.md +5 -3
  94. package/dist/public/skills/kibi-usage/resources/ui-requirements.md +2 -2
  95. package/dist/public/skills/kibi-usage/resources/workflows.md +1 -1
  96. package/dist/schemas/entity.schema.json +2 -25
  97. package/dist/search-answer.d.ts +13 -0
  98. package/dist/search-answer.d.ts.map +1 -1
  99. package/dist/search-answer.js +45 -4
  100. package/dist/utils/branch-store.d.ts.map +1 -1
  101. package/dist/utils/branch-store.js +4 -2
  102. package/package.json +3 -3
  103. package/src/public/operations/check-executor.ts +44 -1
  104. package/src/public/operations/check-format-shared.ts +35 -1
  105. package/src/public/operations/contracts.ts +11 -0
  106. package/src/public/operations/discovery-executors.ts +12 -2
  107. package/src/public/operations/migration-plan.ts +41 -9
  108. package/src/public/operations/specs/composite.ts +1 -1
  109. package/src/public/operations/specs/discovery.ts +3 -2
  110. package/src/public/operations/specs/mutation-schemas.ts +8 -17
  111. package/src/public/operations/specs/upsert.ts +15 -0
  112. package/src/public/schemas/entity.ts +2 -13
  113. package/src/public/skills/kibi-usage/SKILL.md +38 -1
  114. package/src/public/skills/kibi-usage/resources/fact-lanes.md +5 -3
  115. package/src/public/skills/kibi-usage/resources/ui-requirements.md +2 -2
  116. package/src/public/skills/kibi-usage/resources/workflows.md +1 -1
  117. package/src/schemas/entity.schema.json +2 -25
@@ -1,11 +1,12 @@
1
1
  import { createHash } from "node:crypto";
2
- // An explicit grant ("are allowed to", "is permitted to") asserts a
3
- // permission just as "denied"/"forbidden" assert a prohibition. Bare "can" and
4
- // "may" are accepted by the predicate applicability gate but not here: stored
5
- // clause roles are derived from this pattern, and "it can be restricted to …"
6
- // style capability prose would turn existing descriptive inventories into
7
- // unmodeled normative clauses.
8
- const NORMATIVE_ASSERTION_PATTERN = /\b(?:must|shall|should|required|requires?|may\s+only|(?:is|are)\s+(?:not\s+)?(?:allowed|permitted)\s+to|permitted|may\s+(?:not\s+)?(?:be\s+)?\w+\s+only\b|may\s+(?:have\s+)?(?:at\s+most|at\s+least|exactly|no\s+more\s+than|up\s+to)|only\s+.+?\s+(?:may|can)|must\s+not|shall\s+not|cannot|can't|denied|forbidden|prohibited|(?:is|are|be|become|becomes|remain|remains)\s+(?:invalid|rejected|prohibited|forbidden)|(?:reject|rejects|rejected|rejection)\s+(?:invalid|unresolved|ambiguous)|fail(?:s|ed)?\s+(?:clearly|explicitly|with)|expires?\s+(?:after|within|in)|failure\s+(?:behavior|policy|outcome)|error\s+(?:handling|behavior|policy|outcome)|required\s+outcome|defaults?\s+to)\b/i;
2
+ // An explicit grant ("are allowed to", "is permitted to", "have permission
3
+ // to", "are entitled to") asserts a permission just as "denied"/"forbidden"
4
+ // assert a prohibition. Bare "can", "may" and "are able to" are accepted by
5
+ // the predicate applicability gate but not here: stored clause roles are
6
+ // derived from this pattern, and "it can be restricted to …" style capability
7
+ // prose would turn existing descriptive inventories into unmodeled normative
8
+ // clauses ("must be able to" is already normative through "must").
9
+ const NORMATIVE_ASSERTION_PATTERN = /\b(?:must|shall|should|required|requires?|may\s+only|(?:is|are)\s+(?:not\s+)?(?:allowed|permitted|entitled)\s+to|ha(?:s|ve)\s+(?:no\s+)?permission\s+to|permitted|may\s+(?:not\s+)?(?:be\s+)?\w+\s+only\b|may\s+(?:have\s+)?(?:at\s+most|at\s+least|exactly|no\s+more\s+than|up\s+to)|only\s+.+?\s+(?:may|can)|must\s+not|shall\s+not|cannot|can't|denied|forbidden|prohibited|(?:is|are|be|become|becomes|remain|remains)\s+(?:invalid|rejected|prohibited|forbidden)|(?:reject|rejects|rejected|rejection)\s+(?:invalid|unresolved|ambiguous)|fail(?:s|ed)?\s+(?:clearly|explicitly|with)|expires?\s+(?:after|within|in)|failure\s+(?:behavior|policy|outcome)|error\s+(?:handling|behavior|policy|outcome)|required\s+outcome|defaults?\s+to)\b/i;
9
10
  // Conditional/temporal cues help discover clauses but do not by themselves
10
11
  // turn explanatory or subjective context into an asserted obligation.
11
12
  const NORMATIVE_PATTERN = new RegExp(`${NORMATIVE_ASSERTION_PATTERN.source}|\\b(?:before|unless|when|if)\\b`, "i");
@@ -37,6 +38,30 @@ export function semanticClaimKey(text) {
37
38
  const digest = createHash("sha256").update(normalized).digest("hex");
38
39
  return `CLAIM-${digest.slice(0, 16).toUpperCase()}`;
39
40
  }
41
+ /** Fact kinds that quote a claim as a review note and never ground it. */
42
+ const NON_GROUNDING_FACT_KINDS = new Set(["observation", "meta"]);
43
+ /**
44
+ * Fill `claim_key` from `claim_text` on a fact that may ground a claim.
45
+ *
46
+ * The key is a pure function of the text, so a caller that sends the text
47
+ * alone has given Kibi everything it needs; a supplied key is still checked
48
+ * against the derived one by the entity validators. Observation and meta
49
+ * facts quote a claim without owning it, so they stay keyless.
50
+ */
51
+ // implements REQ-kibi-review-observation-claim-text-v2
52
+ export function deriveFactClaimKey(entity) {
53
+ if (entity.type !== "fact")
54
+ return;
55
+ if (entity.claim_key !== undefined)
56
+ return;
57
+ if (typeof entity.claim_text !== "string")
58
+ return;
59
+ if (typeof entity.fact_kind === "string" &&
60
+ NON_GROUNDING_FACT_KINDS.has(entity.fact_kind)) {
61
+ return;
62
+ }
63
+ entity.claim_key = semanticClaimKey(entity.claim_text);
64
+ }
40
65
  function detectedClauses(text) {
41
66
  return text
42
67
  .split(/(?:\r?\n)+|;|(?<=[.!?])\s+(?=[A-Z0-9])/)
@@ -25,7 +25,20 @@ export interface SocketFinding {
25
25
  readonly holderState: StoreLockHolderState;
26
26
  readonly action: "clean" | "keep";
27
27
  }
28
- export type JanitorFinding = StoreLockFinding | SocketFinding;
28
+ /**
29
+ * A stale-lock takeover record past its visibility window: kb_status no
30
+ * longer reports it, so it is only clutter in the branch store.
31
+ */
32
+ export interface TakeoverRecordFinding {
33
+ readonly kind: "takeover-record";
34
+ readonly storePath: string;
35
+ readonly recordPath: string;
36
+ /** When the takeover happened (the file's mtime for an unreadable record). */
37
+ readonly at: string;
38
+ readonly brokenPid?: number;
39
+ readonly action: "clean";
40
+ }
41
+ export type JanitorFinding = StoreLockFinding | SocketFinding | TakeoverRecordFinding;
29
42
  export interface JanitorOptions {
30
43
  /** Branch stores live under <workspaceRoot>/.kb/branches. */
31
44
  readonly workspaceRoot: string;
@@ -35,16 +48,27 @@ export interface JanitorOptions {
35
48
  readonly all?: boolean;
36
49
  /** Execute cleanups; when false the scan only reports (dry run). */
37
50
  readonly apply?: boolean;
51
+ /** Clock for the takeover-record age; defaults to the current time. */
52
+ readonly now?: Date;
38
53
  }
39
54
  /** Scan one branch store's ownership journal and clean stale artifacts. */
40
55
  export declare function sweepStoreLock(storePath: string, apply: boolean): StoreLockFinding | null;
41
56
  /** Scan all branch stores under <workspaceRoot>/.kb/branches. */
42
57
  export declare function sweepWorkspaceStoreLocks(options: JanitorOptions): StoreLockFinding[];
58
+ /**
59
+ * Report, and with apply delete, the stale-lock takeover records under
60
+ * <workspaceRoot>/.kb/branches that are older than the window kb_status
61
+ * shows them for. Fresh records are kept and not reported.
62
+ */
63
+ export declare function sweepStoreLockTakeoverRecords(options: JanitorOptions): TakeoverRecordFinding[];
43
64
  /**
44
65
  * Sweep runtime-directory daemon sockets. A socket is stale when its pid
45
66
  * file records a dead process or a connect attempt is refused.
46
67
  */
47
68
  export declare function sweepRuntimeSockets(options: JanitorOptions): SocketFinding[];
48
- /** Full janitor sweep across branch stores and (optionally) runtime sockets. */
69
+ /**
70
+ * Full janitor sweep across branch stores, expired takeover records and
71
+ * (optionally) runtime sockets.
72
+ */
49
73
  export declare function runJanitor(options: JanitorOptions): JanitorFinding[];
50
74
  //# sourceMappingURL=janitor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"janitor.d.ts","sourceRoot":"","sources":["../../src/prolog/janitor.ts"],"names":[],"mappings":"AAoBA,OAAO,EACL,KAAK,oBAAoB,EAK1B,MAAM,iBAAiB,CAAC;AAEzB;;;;;;;;GAQG;AAGH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,WAAW,EAAE,oBAAoB,CAAC;IAC3C,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC;IAClC,QAAQ,CAAC,MAAM,EAAE,OAAO,GAAG,gBAAgB,GAAG,MAAM,CAAC;CACtD;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,EAAE,oBAAoB,CAAC;IAC3C,QAAQ,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,CAAC;CACnC;AAED,MAAM,MAAM,cAAc,GAAG,gBAAgB,GAAG,aAAa,CAAC;AAE9D,MAAM,WAAW,cAAc;IAC7B,6DAA6D;IAC7D,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,8DAA8D;IAC9D,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,kEAAkE;IAClE,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC;IACvB,oEAAoE;IACpE,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,2EAA2E;AAE3E,wBAAgB,cAAc,CAC5B,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,OAAO,GACb,gBAAgB,GAAG,IAAI,CA+CzB;AAED,iEAAiE;AAEjE,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,cAAc,GACtB,gBAAgB,EAAE,CAepB;AAED;;;GAGG;AAEH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,cAAc,GAAG,aAAa,EAAE,CA8C5E;AAED,gFAAgF;AAEhF,wBAAgB,UAAU,CAAC,OAAO,EAAE,cAAc,GAAG,cAAc,EAAE,CAKpE"}
1
+ {"version":3,"file":"janitor.d.ts","sourceRoot":"","sources":["../../src/prolog/janitor.ts"],"names":[],"mappings":"AA0BA,OAAO,EAGL,KAAK,oBAAoB,EAM1B,MAAM,iBAAiB,CAAC;AAEzB;;;;;;;;GAQG;AAGH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,WAAW,EAAE,oBAAoB,CAAC;IAC3C,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC;IAClC,QAAQ,CAAC,MAAM,EAAE,OAAO,GAAG,gBAAgB,GAAG,MAAM,CAAC;CACtD;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,EAAE,oBAAoB,CAAC;IAC3C,QAAQ,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,CAAC;CACnC;AAED;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC;IACjC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,MAAM,cAAc,GACtB,gBAAgB,GAChB,aAAa,GACb,qBAAqB,CAAC;AAE1B,MAAM,WAAW,cAAc;IAC7B,6DAA6D;IAC7D,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,8DAA8D;IAC9D,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,kEAAkE;IAClE,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC;IACvB,oEAAoE;IACpE,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB,uEAAuE;IACvE,QAAQ,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC;CACrB;AAED,2EAA2E;AAE3E,wBAAgB,cAAc,CAC5B,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,OAAO,GACb,gBAAgB,GAAG,IAAI,CA+CzB;AAED,iEAAiE;AAEjE,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,cAAc,GACtB,gBAAgB,EAAE,CAepB;AAED;;;;GAIG;AAEH,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,cAAc,GACtB,qBAAqB,EAAE,CAmCzB;AAED;;;GAGG;AAEH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,cAAc,GAAG,aAAa,EAAE,CA8C5E;AAED;;;GAGG;AAEH,wBAAgB,UAAU,CAAC,OAAO,EAAE,cAAc,GAAG,cAAc,EAAE,CAMpE"}
@@ -15,9 +15,9 @@
15
15
  You should have received a copy of the GNU Affero General Public License
16
16
  along with this program. If not, see <https://www.gnu.org/licenses/>.
17
17
  */
18
- import { existsSync, readFileSync, readdirSync, rmSync } from "node:fs";
18
+ import { existsSync, readFileSync, readdirSync, rmSync, statSync, } from "node:fs";
19
19
  import { join } from "node:path";
20
- import { breakStoreLock, classifyStoreLockHolder, isProcessAlive, readStoreLockOwner, } from "./store-lock.js";
20
+ import { STORE_LOCK_TAKEOVER_FILE, STORE_LOCK_TAKEOVER_VISIBLE_MS, breakStoreLock, classifyStoreLockHolder, isProcessAlive, readStoreLockOwner, readStoreLockTakeover, } from "./store-lock.js";
21
21
  /** Scan one branch store's ownership journal and clean stale artifacts. */
22
22
  // implements REQ-core-journaled-engine-persistence
23
23
  export function sweepStoreLock(storePath, apply) {
@@ -90,6 +90,54 @@ export function sweepWorkspaceStoreLocks(options) {
90
90
  }
91
91
  return findings;
92
92
  }
93
+ /**
94
+ * Report, and with apply delete, the stale-lock takeover records under
95
+ * <workspaceRoot>/.kb/branches that are older than the window kb_status
96
+ * shows them for. Fresh records are kept and not reported.
97
+ */
98
+ // implements REQ-core-journaled-engine-persistence
99
+ export function sweepStoreLockTakeoverRecords(options) {
100
+ const branchesDir = join(options.workspaceRoot, ".kb", "branches");
101
+ if (!existsSync(branchesDir))
102
+ return [];
103
+ const now = (options.now ?? new Date()).getTime();
104
+ const findings = [];
105
+ for (const entry of readdirSync(branchesDir)) {
106
+ const storePath = join(branchesDir, entry);
107
+ const recordPath = join(storePath, STORE_LOCK_TAKEOVER_FILE);
108
+ let at;
109
+ let brokenPid = null;
110
+ try {
111
+ const record = readStoreLockTakeover(storePath);
112
+ if (record !== null) {
113
+ at = record.at;
114
+ brokenPid = record.brokenPid;
115
+ }
116
+ else if (existsSync(recordPath)) {
117
+ at = statSync(recordPath).mtime.toISOString();
118
+ }
119
+ else {
120
+ continue;
121
+ }
122
+ }
123
+ catch {
124
+ continue;
125
+ }
126
+ if (now - Date.parse(at) <= STORE_LOCK_TAKEOVER_VISIBLE_MS)
127
+ continue;
128
+ if (options.apply === true)
129
+ rmSync(recordPath, { force: true });
130
+ findings.push({
131
+ kind: "takeover-record",
132
+ storePath,
133
+ recordPath,
134
+ at,
135
+ ...(brokenPid !== null ? { brokenPid } : {}),
136
+ action: "clean",
137
+ });
138
+ }
139
+ return findings;
140
+ }
93
141
  /**
94
142
  * Sweep runtime-directory daemon sockets. A socket is stale when its pid
95
143
  * file records a dead process or a connect attempt is refused.
@@ -144,11 +192,15 @@ export function sweepRuntimeSockets(options) {
144
192
  }
145
193
  return findings;
146
194
  }
147
- /** Full janitor sweep across branch stores and (optionally) runtime sockets. */
195
+ /**
196
+ * Full janitor sweep across branch stores, expired takeover records and
197
+ * (optionally) runtime sockets.
198
+ */
148
199
  // implements REQ-core-journaled-engine-persistence
149
200
  export function runJanitor(options) {
150
201
  return [
151
202
  ...sweepWorkspaceStoreLocks(options),
203
+ ...sweepStoreLockTakeoverRecords(options),
152
204
  ...sweepRuntimeSockets(options),
153
205
  ];
154
206
  }
@@ -66,12 +66,37 @@ export interface StoreLockTakeoverDecision {
66
66
  readonly action: "break" | "surface";
67
67
  readonly reason: string;
68
68
  }
69
+ /** Reason prefix of a takeover that removed lock artifacts copied in. */
70
+ export declare const FOREIGN_STORE_LOCK_REASON_PREFIX = "journal belongs to another workspace";
71
+ /**
72
+ * The recorded root of an ownership journal that another workspace wrote,
73
+ * or null when the journal belongs to this store (or cannot be judged).
74
+ *
75
+ * kb.pl records the attached store directory as `workspaceRoot`; a journal
76
+ * may also name a workspace root. Either way it is foreign only when the
77
+ * workspace it names differs from the one that owns `storePath`, which
78
+ * happens when a `.kb` was copied (`cp -a`, a backup restore) while another
79
+ * workspace's engine held its store. An advisory lock is never inherited by
80
+ * a copied file, so nobody holds this store on the journal's behalf.
81
+ *
82
+ * The journal is judged only when that is safe: when the store's `rdf/lock`
83
+ * names a different pid than the journal, a process of this workspace has
84
+ * locked the store since the copy; when the recorded path no longer exists,
85
+ * the store may have been moved here while its holder still runs; and a
86
+ * recorded path that is this very directory (a bind mount) is not another
87
+ * workspace. Each of those returns null.
88
+ */
89
+ export declare function foreignStoreLockJournalRoot(owner: PrologStoreLockOwner | null, storePath: string): string | null;
69
90
  /**
70
91
  * Decide whether a store-locked failure may be auto-healed. Only a provably
71
- * dead holder (or a holder from a previous boot) is broken; live or unknown
72
- * holders are surfaced so the operator can close the real session.
92
+ * dead holder (or a holder from a previous boot) is broken, and, when the
93
+ * caller names the store being attached, a journal copied in from another
94
+ * workspace; live or unknown holders are surfaced so the operator can close
95
+ * the real session.
73
96
  */
74
- export declare function decideStoreLockTakeover(owner: PrologStoreLockOwner | null): StoreLockTakeoverDecision;
97
+ export declare function decideStoreLockTakeover(owner: PrologStoreLockOwner | null, options?: {
98
+ readonly storePath?: string;
99
+ }): StoreLockTakeoverDecision;
75
100
  export interface StoreLockRetryContext {
76
101
  readonly query: (goal: string) => Promise<QueryResult>;
77
102
  }
@@ -1 +1 @@
1
- {"version":3,"file":"store-lock.d.ts","sourceRoot":"","sources":["../../src/prolog/store-lock.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,OAAO,KAAK,EAAqB,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAgBhF,8EAA8E;AAC9E,wBAAgB,aAAa,IAAI,MAAM,GAAG,IAAI,CAa7C;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAUnD;AAED,MAAM,MAAM,oBAAoB,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;AAEzE,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,oBAAoB,GAAG,IAAI,GACjC,oBAAoB,CAYtB;AAED;;;;;GAKG;AAEH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,MAAM,GAChB;IAAE,KAAK,EAAE,oBAAoB,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CA4B7D;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAWzD;AAED,qEAAqE;AACrE,eAAO,MAAM,wBAAwB,6BAA6B,CAAC;AAEnE;;;;;GAKG;AACH,eAAO,MAAM,8BAA8B,QAAsB,CAAC;AAElE,MAAM,MAAM,uBAAuB,GAAG,QAAQ,CAAC;IAC7C,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;CACd,CAAC,CAAC;AAEH;;;GAGG;AAEH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,MAAM,EAAE,MAAM,EACd,EAAE,GAAE,IAAiB,GACpB,IAAI,CAUN;AAED,iFAAiF;AAEjF,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,MAAM,GAChB,uBAAuB,GAAG,IAAI,CAmBhC;AAED,sEAAsE;AAEtE,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQ9D;AAED;;;;;;;;;;;;;;;GAeG;AAEH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,IAAI,CAerE;AAED,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,MAAM,EAAE,OAAO,GAAG,SAAS,CAAC;IACrC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,oBAAoB,GAAG,IAAI,GACjC,yBAAyB,CAoB3B;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;CACxD;AAED;;;;;;GAMG;AAEH,wBAAsB,iCAAiC,CACrD,MAAM,EAAE,qBAAqB,EAC7B,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,WAAW,CAAC,CAiCtB"}
1
+ {"version":3,"file":"store-lock.d.ts","sourceRoot":"","sources":["../../src/prolog/store-lock.ts"],"names":[],"mappings":"AA2BA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,OAAO,KAAK,EAAqB,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAgBhF,8EAA8E;AAC9E,wBAAgB,aAAa,IAAI,MAAM,GAAG,IAAI,CAa7C;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAUnD;AAED,MAAM,MAAM,oBAAoB,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;AAEzE,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,oBAAoB,GAAG,IAAI,GACjC,oBAAoB,CAYtB;AAED;;;;;GAKG;AAEH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,MAAM,GAChB;IAAE,KAAK,EAAE,oBAAoB,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CA4B7D;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAWzD;AAED,qEAAqE;AACrE,eAAO,MAAM,wBAAwB,6BAA6B,CAAC;AAEnE;;;;;GAKG;AACH,eAAO,MAAM,8BAA8B,QAAsB,CAAC;AAElE,MAAM,MAAM,uBAAuB,GAAG,QAAQ,CAAC;IAC7C,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;CACd,CAAC,CAAC;AAEH;;;GAGG;AAEH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,MAAM,EAAE,MAAM,EACd,EAAE,GAAE,IAAiB,GACpB,IAAI,CAUN;AAED,iFAAiF;AAEjF,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,MAAM,GAChB,uBAAuB,GAAG,IAAI,CAmBhC;AAED,sEAAsE;AAEtE,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQ9D;AAED;;;;;;;;;;;;;;;GAeG;AAEH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,IAAI,CAerE;AAED,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,MAAM,EAAE,OAAO,GAAG,SAAS,CAAC;IACrC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,yEAAyE;AACzE,eAAO,MAAM,gCAAgC,yCACL,CAAC;AAoCzC;;;;;;;;;;;;;;;;;GAiBG;AAEH,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,oBAAoB,GAAG,IAAI,EAClC,SAAS,EAAE,MAAM,GAChB,MAAM,GAAG,IAAI,CAcf;AAED;;;;;;GAMG;AAEH,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,oBAAoB,GAAG,IAAI,EAClC,OAAO,GAAE;IAAE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GAC5C,yBAAyB,CA+B3B;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;CACxD;AAED;;;;;;GAMG;AAEH,wBAAsB,iCAAiC,CACrD,MAAM,EAAE,qBAAqB,EAC7B,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,WAAW,CAAC,CAmCtB"}
@@ -15,9 +15,9 @@
15
15
  You should have received a copy of the GNU Affero General Public License
16
16
  along with this program. If not, see <https://www.gnu.org/licenses/>.
17
17
  */
18
- import { existsSync, rmSync, writeFileSync } from "node:fs";
18
+ import { existsSync, realpathSync, rmSync, statSync, writeFileSync, } from "node:fs";
19
19
  import { readFileSync } from "node:fs";
20
- import { dirname, join } from "node:path";
20
+ import { basename, dirname, join } from "node:path";
21
21
  import { escapeAtom } from "./codec.js";
22
22
  /**
23
23
  * Stewardship for the branch-store lock.
@@ -216,25 +216,114 @@ export function noteDeadHolderBeforeAttach(kbPath) {
216
216
  : lockPid !== null
217
217
  ? { pid: lockPid }
218
218
  : null;
219
- const decision = decideStoreLockTakeover(owner);
219
+ const decision = decideStoreLockTakeover(owner, { storePath: kbPath });
220
220
  if (decision.action !== "break")
221
221
  return () => undefined;
222
222
  const brokenPid = owner?.pid ?? null;
223
223
  return () => recordStoreLockTakeover(kbPath, brokenPid, decision.reason);
224
224
  }
225
+ /** Reason prefix of a takeover that removed lock artifacts copied in. */
226
+ export const FOREIGN_STORE_LOCK_REASON_PREFIX = "journal belongs to another workspace";
227
+ function existingRealPath(pathname) {
228
+ try {
229
+ return realpathSync(pathname);
230
+ }
231
+ catch {
232
+ return null;
233
+ }
234
+ }
235
+ function sameDirectory(left, right) {
236
+ try {
237
+ const a = statSync(left);
238
+ const b = statSync(right);
239
+ return a.dev === b.dev && a.ino === b.ino;
240
+ }
241
+ catch {
242
+ return false;
243
+ }
244
+ }
245
+ /**
246
+ * The workspace that owns a branch store: `<root>/.kb/branches/<key>` (a
247
+ * legacy key may span several segments) is owned by `<root>`. Null for a
248
+ * path outside that layout.
249
+ */
250
+ function owningWorkspaceRoot(storePath) {
251
+ let current = storePath;
252
+ for (;;) {
253
+ const parent = dirname(current);
254
+ if (parent === current)
255
+ return null;
256
+ if (basename(parent) === "branches" && basename(dirname(parent)) === ".kb")
257
+ return dirname(dirname(parent));
258
+ current = parent;
259
+ }
260
+ }
261
+ /**
262
+ * The recorded root of an ownership journal that another workspace wrote,
263
+ * or null when the journal belongs to this store (or cannot be judged).
264
+ *
265
+ * kb.pl records the attached store directory as `workspaceRoot`; a journal
266
+ * may also name a workspace root. Either way it is foreign only when the
267
+ * workspace it names differs from the one that owns `storePath`, which
268
+ * happens when a `.kb` was copied (`cp -a`, a backup restore) while another
269
+ * workspace's engine held its store. An advisory lock is never inherited by
270
+ * a copied file, so nobody holds this store on the journal's behalf.
271
+ *
272
+ * The journal is judged only when that is safe: when the store's `rdf/lock`
273
+ * names a different pid than the journal, a process of this workspace has
274
+ * locked the store since the copy; when the recorded path no longer exists,
275
+ * the store may have been moved here while its holder still runs; and a
276
+ * recorded path that is this very directory (a bind mount) is not another
277
+ * workspace. Each of those returns null.
278
+ */
279
+ // implements REQ-core-journaled-engine-persistence
280
+ export function foreignStoreLockJournalRoot(owner, storePath) {
281
+ const recorded = owner?.workspaceRoot;
282
+ if (recorded === undefined || recorded === "")
283
+ return null;
284
+ const store = existingRealPath(storePath);
285
+ if (store === null)
286
+ return null;
287
+ const ownWorkspace = owningWorkspaceRoot(store);
288
+ if (ownWorkspace === null)
289
+ return null;
290
+ const lockPid = readRdfLockPid(join(storePath, "rdf", "lock"));
291
+ if (lockPid !== null && lockPid !== owner?.pid)
292
+ return null;
293
+ const recordedPath = existingRealPath(recorded);
294
+ if (recordedPath === null || recordedPath === store)
295
+ return null;
296
+ if (sameDirectory(recordedPath, store))
297
+ return null;
298
+ const recordedWorkspace = owningWorkspaceRoot(recordedPath) ?? recordedPath;
299
+ return recordedWorkspace === ownWorkspace ? null : recorded;
300
+ }
225
301
  /**
226
302
  * Decide whether a store-locked failure may be auto-healed. Only a provably
227
- * dead holder (or a holder from a previous boot) is broken; live or unknown
228
- * holders are surfaced so the operator can close the real session.
303
+ * dead holder (or a holder from a previous boot) is broken, and, when the
304
+ * caller names the store being attached, a journal copied in from another
305
+ * workspace; live or unknown holders are surfaced so the operator can close
306
+ * the real session.
229
307
  */
230
- export function decideStoreLockTakeover(owner) {
308
+ // implements REQ-core-journaled-engine-persistence
309
+ export function decideStoreLockTakeover(owner, options = {}) {
231
310
  const state = classifyStoreLockHolder(owner);
311
+ if (state === "dead") {
312
+ return {
313
+ action: "break",
314
+ reason: `recorded holder pid ${owner?.pid ?? "?"} is no longer running`,
315
+ };
316
+ }
317
+ const foreignRoot = options.storePath === undefined
318
+ ? null
319
+ : foreignStoreLockJournalRoot(owner, options.storePath);
320
+ if (foreignRoot !== null) {
321
+ return {
322
+ action: "break",
323
+ reason: `${FOREIGN_STORE_LOCK_REASON_PREFIX} ${foreignRoot}`,
324
+ };
325
+ }
232
326
  switch (state) {
233
- case "dead":
234
- return {
235
- action: "break",
236
- reason: `recorded holder pid ${owner?.pid ?? "?"} is no longer running`,
237
- };
238
327
  case "unknown":
239
328
  return {
240
329
  action: "surface",
@@ -261,7 +350,9 @@ export async function retryAttachAfterBreakingStaleLock(prolog, kbPath, failed)
261
350
  const storeLocked = record?.storeLocked;
262
351
  if (storeLocked === undefined)
263
352
  return failed;
264
- const decision = decideStoreLockTakeover(storeLocked.owner);
353
+ const decision = decideStoreLockTakeover(storeLocked.owner, {
354
+ storePath: kbPath,
355
+ });
265
356
  if (decision.action !== "break") {
266
357
  const holderSummary = storeLocked.owner === null
267
358
  ? decision.reason
@@ -190,8 +190,8 @@ export declare const OPERATION_CATALOG: readonly [{
190
190
  readonly limit: {
191
191
  readonly type: "integer";
192
192
  readonly minimum: 0;
193
- readonly default: 20;
194
- readonly description: "Optional max rows to return after ranking. Default: 20.";
193
+ readonly default: 10;
194
+ readonly description: "Optional max rows to return after ranking. Default: 10; raise it or page with offset when the answer layer is not enough.";
195
195
  };
196
196
  readonly offset: {
197
197
  readonly type: "integer";
@@ -718,7 +718,7 @@ export declare const OPERATION_CATALOG: readonly [{
718
718
  }, {
719
719
  readonly name: "kb_model";
720
720
  readonly cliName: "model";
721
- readonly description: "Turn requirement prose into checkable structure without writing the KB. mode:analyze returns the semantic advisor receipt: the clause ledger, what is grounded, what is ambiguous and suggested modeling (pass clauses for compound prose and optional typed kibi.logic.v1 interpretations). mode:requirement converts one claim (subjectKey, propertyKey, operator, value, or typed logic) into a strict-lane write set and applyPlan. mode:predicates ranks ontology predicate schemas and returns an applicable predicate-fact plan only for reviewed bindings, otherwise an ontology-gap observation. Apply returned plans with kb_upsert.";
721
+ readonly description: "Turn requirement prose into checkable structure without writing the KB. mode:analyze returns the semantic advisor receipt: the clause ledger, what is grounded, what is ambiguous and suggested modeling (pass clauses for compound prose and optional typed kibi.logic.v1 interpretations). mode:requirement converts one claim (subjectKey, propertyKey, operator, value, or typed logic) into a strict-lane write set and applyPlan. mode:predicates ranks ontology predicate schemas and returns an applicable predicate-fact plan only for reviewed bindings, otherwise an ontology-gap observation. With requirementId, mode:predicates also returns a hash-bound plan (fact write plus requires_predicate link) for kb_apply_plan, whose contradictionAnalysis is the what-if over the current KB; other returned plans apply with kb_upsert, and kb_upsert dryRun with plannedFacts previews a requirement before its facts exist.";
722
722
  readonly businessInputSchema: {
723
723
  readonly type: "object";
724
724
  readonly required: readonly ["mode", "text"];
@@ -1521,11 +1521,11 @@ export declare const OPERATION_CATALOG: readonly [{
1521
1521
  readonly claim_key: {
1522
1522
  readonly type: "string";
1523
1523
  readonly pattern: "^CLAIM-[A-F0-9]{16}$";
1524
- readonly description: "Stable semantic-advisor key for the atomic prose clause grounded by this fact.";
1524
+ readonly description: "Stable key of the atomic prose clause grounded by this fact, derived from claim_text. Optional: when omitted, Kibi derives it; when sent, it must equal the derived key.";
1525
1525
  };
1526
1526
  readonly claim_text: {
1527
1527
  readonly type: "string";
1528
- readonly description: "Exact atomic requirement clause represented by this fact, retained for human audit. Requires claim_key, except on an observation or meta fact, which may quote the clause it is about without claim_key.";
1528
+ readonly description: "Exact atomic requirement clause represented by this fact, retained for human audit. On a grounding fact Kibi derives claim_key from it; an observation or meta fact quotes the clause it is about without a key.";
1529
1529
  };
1530
1530
  readonly predicate_name: {
1531
1531
  readonly type: "string";
@@ -1689,6 +1689,50 @@ export declare const OPERATION_CATALOG: readonly [{
1689
1689
  readonly default: false;
1690
1690
  readonly description: "Validate the payload and return schema/modeling errors, a normalized preview and the semantic advisor receipt without writing the KB or workspace. Use it as the preflight before the real write.";
1691
1691
  };
1692
+ readonly plannedFacts: {
1693
+ readonly type: "array";
1694
+ readonly description: "dryRun only. Fact upsert payloads (type, id, properties, optional relationships) that will be written before this payload, typically the applyPlan entries kb_model returned. They are validated in order and staged with the payload, so a requires_predicate or requires_property target that does not exist yet resolves, its claim_key is read from the plan, and the contradiction preview runs against the KB as it would be after the whole batch (result: stagedFacts, whatIf). A conflict the batch would introduce, such as an allow and a deny permission_rule on the same key, is refused as the commit would refuse it. Rejected without dryRun: write the facts first.";
1695
+ readonly items: {
1696
+ readonly type: "object";
1697
+ readonly required: readonly ["type", "id", "properties"];
1698
+ readonly properties: {
1699
+ readonly type: {
1700
+ readonly type: "string";
1701
+ readonly const: "fact";
1702
+ };
1703
+ readonly id: {
1704
+ readonly type: "string";
1705
+ readonly minLength: 1;
1706
+ };
1707
+ readonly properties: {
1708
+ readonly type: "object";
1709
+ };
1710
+ readonly relationships: {
1711
+ readonly type: "array";
1712
+ readonly description: "Optional relationship rows to create in the same call. For requirement encoding, prefer `constrains` + `requires_property` for strict property facts or `requires_predicate` for ontology predicate facts. Side effect: asserts edges in KB.";
1713
+ readonly items: {
1714
+ readonly type: "object";
1715
+ readonly required: readonly ["type", "from", "to"];
1716
+ readonly properties: {
1717
+ readonly type: {
1718
+ readonly type: "string";
1719
+ readonly enum: readonly ["depends_on", "specified_by", "verified_by", "validates", "implements", "covered_by", "executable_for", "constrained_by", "constrains", "requires_property", "requires_predicate", "requires_rule", "guards", "publishes", "consumes", "supersedes", "restates", "assumes", "exempts", "relates_to"];
1720
+ readonly description: "Relationship type enum. Use only supported values. Direction semantics follow KB model (e.g., implements symbol->req, verified_by req/scenario->test, executable_for symbol->test).";
1721
+ };
1722
+ readonly from: {
1723
+ readonly type: "string";
1724
+ readonly description: "Source entity ID (must exist). Example: 'SYM-login-handler'.";
1725
+ };
1726
+ readonly to: {
1727
+ readonly type: "string";
1728
+ readonly description: "Target entity ID (must exist). Example: 'REQ-cli-gc'.";
1729
+ };
1730
+ };
1731
+ };
1732
+ };
1733
+ };
1734
+ };
1735
+ };
1692
1736
  readonly document: {
1693
1737
  readonly type: "object";
1694
1738
  readonly additionalProperties: false;
@@ -1 +1 @@
1
- {"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../../../src/public/operations/catalog.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../../../src/public/operations/catalog.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import type { Violation } from "../check-types.js";
2
- import { type CheckDiagnostic, type CheckStructuredContent, buildStructuredContent, buildSummary } from "./check-format-shared.js";
2
+ import { type CheckDiagnostic, type CheckEvaluated, type CheckStructuredContent, buildStructuredContent, buildSummary } from "./check-format-shared.js";
3
3
  import { getEffectiveRules, resolveCheckRules } from "./check-helpers.js";
4
4
  import type { OperationContext } from "./runtime-types.js";
5
5
  import type { OperationResult } from "./types.js";
@@ -13,7 +13,7 @@ export type CheckInput = {
13
13
  readonly maxDiagnostics?: number;
14
14
  };
15
15
  export type CheckPayload = CheckStructuredContent;
16
- export type { CheckDiagnostic, CheckStructuredContent };
16
+ export type { CheckDiagnostic, CheckEvaluated, CheckStructuredContent };
17
17
  export { buildStructuredContent, buildSummary, getEffectiveRules, resolveCheckRules, };
18
18
  export type CheckExecutionOptions = {
19
19
  readonly collectFullQualityDiagnosticsForExplicitRules?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"check-executor.d.ts","sourceRoot":"","sources":["../../../src/public/operations/check-executor.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAEnD,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,sBAAsB,EAC3B,sBAAsB,EACtB,YAAY,EACb,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAGL,iBAAiB,EAGjB,iBAAiB,EAElB,MAAM,oBAAoB,CAAC;AAW5B,OAAO,KAAK,EAAE,gBAAgB,EAAc,MAAM,oBAAoB,CAAC;AAMvE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAIlD,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,sBAAsB,CAAC,EAAE,OAAO,CAAC;IAC1C,QAAQ,CAAC,wBAAwB,CAAC,EAAE,OAAO,CAAC;IAC5C,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;CAClC,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,sBAAsB,CAAC;AAClD,YAAY,EAAE,eAAe,EAAE,sBAAsB,EAAE,CAAC;AACxD,OAAO,EACL,sBAAsB,EACtB,YAAY,EACZ,iBAAiB,EACjB,iBAAiB,GAClB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,QAAQ,CAAC,6CAA6C,CAAC,EAAE,OAAO,CAAC;IACjE;;;;;;OAMG;IACH,QAAQ,CAAC,mBAAmB,CAAC,EAAE,OAAO,CAAC;CACxC,CAAC;AAoDF;;;;;GAKG;AAEH,wBAAgB,8BAA8B,CAC5C,OAAO,EAAE,gBAAgB,EACzB,aAAa,EAAE,MAAM,GACpB,SAAS,GAAG,IAAI,CAgClB;AAGD,wBAAsB,YAAY,CAChC,IAAI,EAAE,UAAU,EAChB,OAAO,EAAE,gBAAgB,EACzB,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC,CAgOxC"}
1
+ {"version":3,"file":"check-executor.d.ts","sourceRoot":"","sources":["../../../src/public/operations/check-executor.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAEnD,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,sBAAsB,EAC3B,sBAAsB,EACtB,YAAY,EACb,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAGL,iBAAiB,EAGjB,iBAAiB,EAElB,MAAM,oBAAoB,CAAC;AAW5B,OAAO,KAAK,EAAE,gBAAgB,EAAc,MAAM,oBAAoB,CAAC;AAMvE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAIlD,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,sBAAsB,CAAC,EAAE,OAAO,CAAC;IAC1C,QAAQ,CAAC,wBAAwB,CAAC,EAAE,OAAO,CAAC;IAC5C,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;CAClC,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,sBAAsB,CAAC;AAClD,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,sBAAsB,EAAE,CAAC;AACxE,OAAO,EACL,sBAAsB,EACtB,YAAY,EACZ,iBAAiB,EACjB,iBAAiB,GAClB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,QAAQ,CAAC,6CAA6C,CAAC,EAAE,OAAO,CAAC;IACjE;;;;;;OAMG;IACH,QAAQ,CAAC,mBAAmB,CAAC,EAAE,OAAO,CAAC;CACxC,CAAC;AAoFF;;;;;GAKG;AAEH,wBAAgB,8BAA8B,CAC5C,OAAO,EAAE,gBAAgB,EACzB,aAAa,EAAE,MAAM,GACpB,SAAS,GAAG,IAAI,CAgClB;AAGD,wBAAsB,YAAY,CAChC,IAAI,EAAE,UAAU,EAChB,OAAO,EAAE,gBAAgB,EACzB,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC,CA0OxC"}
@@ -14,6 +14,31 @@ import { SOURCE_PATH_DANGLING_RULE, collectSourcePathDanglingViolations, } from
14
14
  import { collectSourceRelationshipParityViolations } from "./source-relationship-parity.js";
15
15
  import { readWorkspaceSnapshot } from "./workspace-snapshot.js";
16
16
  export { buildStructuredContent, buildSummary, getEffectiveRules, resolveCheckRules, };
17
+ // implements REQ-search-answer-hygiene
18
+ /**
19
+ * What this run evaluated: the rules that ran, in registry order, and for
20
+ * `domain-contradictions` the number of requirement fact pairs the rule
21
+ * compared, read from the engine after the rules ran on the same store. A
22
+ * count the engine cannot give (an older engine) is left out rather than
23
+ * reported as zero.
24
+ */
25
+ async function describeEvaluation(prolog, rules) {
26
+ const evaluated = {
27
+ rules: [...rules],
28
+ };
29
+ if (!rules.has("domain-contradictions"))
30
+ return evaluated;
31
+ try {
32
+ const result = await prolog.query("kb_domain_contradiction_pairs_examined(Count)");
33
+ const count = Number(result.bindings.Count);
34
+ if (result.success && Number.isInteger(count) && count >= 0)
35
+ evaluated.domainContradictions = { factPairsExamined: count };
36
+ }
37
+ catch {
38
+ // An engine without the predicate leaves the count out.
39
+ }
40
+ return evaluated;
41
+ }
17
42
  function requireProlog(context) {
18
43
  if (context.prolog === undefined) {
19
44
  throw new Error("Check operation requires a Prolog runtime");
@@ -121,12 +146,15 @@ export async function executeCheck(args, context, options = {}) {
121
146
  const violations = [uncompiled];
122
147
  const statusPlan = await readStatusMigrationPlan(context);
123
148
  const migrationPlan = await migrationPlanForCheck(context, violations, [], statusPlan);
149
+ // Every store-backed rule was skipped: only this one was evaluated.
150
+ const evaluated = { rules: [BRANCH_STORE_NOT_COMPILED_RULE] };
124
151
  return {
125
152
  content: [
126
153
  {
127
154
  type: "text",
128
155
  text: buildSummary({
129
156
  violations,
157
+ evaluated,
130
158
  impactResult,
131
159
  qualityDiagnostics: [],
132
160
  }),
@@ -134,6 +162,7 @@ export async function executeCheck(args, context, options = {}) {
134
162
  ],
135
163
  structuredContent: buildStructuredContent({
136
164
  violations,
165
+ evaluated,
137
166
  diagnostics: [
138
167
  {
139
168
  category: "SYNC_ERROR",
@@ -169,12 +198,14 @@ export async function executeCheck(args, context, options = {}) {
169
198
  });
170
199
  const statusPlan = await readStatusMigrationPlan(context);
171
200
  const migrationPlan = await migrationPlanForCheck(context, [], qualityDiagnostics, statusPlan);
201
+ const evaluated = { rules: [] };
172
202
  return {
173
203
  content: [
174
204
  {
175
205
  type: "text",
176
206
  text: buildSummary({
177
207
  violations: [],
208
+ evaluated,
178
209
  impactResult,
179
210
  qualityDiagnostics,
180
211
  }),
@@ -182,6 +213,7 @@ export async function executeCheck(args, context, options = {}) {
182
213
  ],
183
214
  structuredContent: buildStructuredContent({
184
215
  violations: [],
216
+ evaluated,
185
217
  diagnostics: [],
186
218
  qualityDiagnostics,
187
219
  impactResult,
@@ -217,6 +249,7 @@ export async function executeCheck(args, context, options = {}) {
217
249
  ...checkPolicyFindings,
218
250
  ]);
219
251
  const violations = partitioned.violations;
252
+ const evaluated = await describeEvaluation(prolog, rulesAllowlist);
220
253
  const diagnostics = violations.map((v) => ({
221
254
  category: "SYNC_ERROR",
222
255
  severity: "error",
@@ -251,6 +284,7 @@ export async function executeCheck(args, context, options = {}) {
251
284
  type: "text",
252
285
  text: buildSummary({
253
286
  violations,
287
+ evaluated,
254
288
  impactResult,
255
289
  qualityDiagnostics,
256
290
  }),
@@ -258,6 +292,7 @@ export async function executeCheck(args, context, options = {}) {
258
292
  ],
259
293
  structuredContent: buildStructuredContent({
260
294
  violations,
295
+ evaluated,
261
296
  diagnostics,
262
297
  qualityDiagnostics,
263
298
  impactResult,