kibi-cli 2.2.0 → 2.4.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 (230) hide show
  1. package/dist/cli-json-command.d.ts.map +1 -1
  2. package/dist/cli-json-command.js +2 -2
  3. package/dist/cli-operation-loader.d.ts.map +1 -1
  4. package/dist/cli-operation-loader.js +3 -0
  5. package/dist/cli-operation-metadata.d.ts +5 -1
  6. package/dist/cli-operation-metadata.d.ts.map +1 -1
  7. package/dist/cli-operation-metadata.js +6 -1
  8. package/dist/cli-register-maintenance.d.ts.map +1 -1
  9. package/dist/cli-register-maintenance.js +7 -0
  10. package/dist/cli-register-reporting.d.ts.map +1 -1
  11. package/dist/cli-register-reporting.js +4 -0
  12. package/dist/commands/check-diff.d.ts +5 -0
  13. package/dist/commands/check-diff.d.ts.map +1 -0
  14. package/dist/commands/check-diff.js +62 -0
  15. package/dist/commands/check-generated.d.ts.map +1 -1
  16. package/dist/commands/check-generated.js +41 -18
  17. package/dist/commands/check.d.ts.map +1 -1
  18. package/dist/commands/check.js +210 -73
  19. package/dist/commands/doctor.d.ts.map +1 -1
  20. package/dist/commands/doctor.js +63 -29
  21. package/dist/commands/github-init.d.ts.map +1 -1
  22. package/dist/commands/github-init.js +9 -2
  23. package/dist/commands/merge-driver.d.ts +31 -0
  24. package/dist/commands/merge-driver.d.ts.map +1 -0
  25. package/dist/commands/merge-driver.js +268 -0
  26. package/dist/commands/sync/manifest.d.ts.map +1 -1
  27. package/dist/commands/sync/manifest.js +3 -1
  28. package/dist/engine.d.ts +15 -1
  29. package/dist/engine.d.ts.map +1 -1
  30. package/dist/engine.js +252 -52
  31. package/dist/extractors/symbols-coordinator.d.ts +7 -0
  32. package/dist/extractors/symbols-coordinator.d.ts.map +1 -1
  33. package/dist/extractors/symbols-coordinator.js +75 -39
  34. package/dist/operations/bootstrap/candidates.js +1 -1
  35. package/dist/operations/bootstrap/discovery.js +1 -1
  36. package/dist/operations/bootstrap/generate.d.ts.map +1 -1
  37. package/dist/operations/bootstrap/generate.js +21 -5
  38. package/dist/operations/bootstrap/guidance-actions.d.ts.map +1 -1
  39. package/dist/operations/bootstrap/guidance-actions.js +3 -0
  40. package/dist/operations/bootstrap/guidance.d.ts.map +1 -1
  41. package/dist/operations/bootstrap/guidance.js +7 -1
  42. package/dist/operations/bootstrap/intent-claims.d.ts +17 -0
  43. package/dist/operations/bootstrap/intent-claims.d.ts.map +1 -0
  44. package/dist/operations/bootstrap/intent-claims.js +95 -0
  45. package/dist/operations/bootstrap/presentation.d.ts +2 -0
  46. package/dist/operations/bootstrap/presentation.d.ts.map +1 -1
  47. package/dist/operations/bootstrap/presentation.js +60 -1
  48. package/dist/operations/bootstrap/types.d.ts +28 -0
  49. package/dist/operations/bootstrap/types.d.ts.map +1 -1
  50. package/dist/operations/bootstrap/types.js +16 -0
  51. package/dist/operations/modeling/predicate-inference-1.js +1 -1
  52. package/dist/operations/mutation/source-authoring.d.ts.map +1 -1
  53. package/dist/operations/mutation/source-authoring.js +175 -53
  54. package/dist/operations/mutation/symbol-refresh.d.ts.map +1 -1
  55. package/dist/operations/mutation/symbol-refresh.js +4 -1
  56. package/dist/operations/mutation/upsert.d.ts.map +1 -1
  57. package/dist/operations/mutation/upsert.js +5 -7
  58. package/dist/operations/planning/apply-plan.d.ts.map +1 -1
  59. package/dist/operations/planning/apply-plan.js +5 -9
  60. package/dist/operations/proof/ingest-proof.d.ts.map +1 -1
  61. package/dist/operations/proof/ingest-proof.js +1 -0
  62. package/dist/operations/semantic-advisor/analysis-receipt.d.ts.map +1 -1
  63. package/dist/operations/semantic-advisor/analysis-receipt.js +7 -1
  64. package/dist/operations/semantic-advisor/analyze-prose.d.ts.map +1 -1
  65. package/dist/operations/semantic-advisor/analyze-prose.js +26 -4
  66. package/dist/operations/semantic-advisor/clauses.d.ts +1 -0
  67. package/dist/operations/semantic-advisor/clauses.d.ts.map +1 -1
  68. package/dist/operations/semantic-advisor/clauses.js +7 -1
  69. package/dist/performance-trace.d.ts +17 -0
  70. package/dist/performance-trace.d.ts.map +1 -0
  71. package/dist/performance-trace.js +134 -0
  72. package/dist/plugins/approved-source-analyzers.d.ts +13 -0
  73. package/dist/plugins/approved-source-analyzers.d.ts.map +1 -0
  74. package/dist/plugins/approved-source-analyzers.generated.d.ts +71 -0
  75. package/dist/plugins/approved-source-analyzers.generated.d.ts.map +1 -0
  76. package/dist/plugins/approved-source-analyzers.generated.js +77 -0
  77. package/dist/plugins/approved-source-analyzers.js +3 -0
  78. package/dist/plugins/maintenance-source-analysis.d.ts +14 -0
  79. package/dist/plugins/maintenance-source-analysis.d.ts.map +1 -0
  80. package/dist/plugins/maintenance-source-analysis.js +191 -0
  81. package/dist/plugins/registry.d.ts +2 -1
  82. package/dist/plugins/registry.d.ts.map +1 -1
  83. package/dist/plugins/registry.js +6 -1
  84. package/dist/plugins/source-analysis-service.d.ts +36 -1
  85. package/dist/plugins/source-analysis-service.d.ts.map +1 -1
  86. package/dist/plugins/source-analysis-service.js +184 -27
  87. package/dist/plugins/source-change-analysis.d.ts +15 -0
  88. package/dist/plugins/source-change-analysis.d.ts.map +1 -0
  89. package/dist/plugins/source-change-analysis.js +54 -0
  90. package/dist/plugins/source-classification.d.ts +41 -0
  91. package/dist/plugins/source-classification.d.ts.map +1 -0
  92. package/dist/plugins/source-classification.js +490 -0
  93. package/dist/prolog/swipl-resolver.d.ts +88 -0
  94. package/dist/prolog/swipl-resolver.d.ts.map +1 -0
  95. package/dist/prolog/swipl-resolver.js +446 -0
  96. package/dist/prolog.d.ts +15 -1
  97. package/dist/prolog.d.ts.map +1 -1
  98. package/dist/prolog.js +67 -6
  99. package/dist/public/diagnostic-usage.d.ts +14 -0
  100. package/dist/public/diagnostic-usage.d.ts.map +1 -1
  101. package/dist/public/diagnostic-usage.js +55 -1
  102. package/dist/public/impact/analyzer.d.ts.map +1 -1
  103. package/dist/public/impact/analyzer.js +56 -5
  104. package/dist/public/impact/diagnostics.d.ts.map +1 -1
  105. package/dist/public/impact/diagnostics.js +3 -1
  106. package/dist/public/impact/manifest.d.ts.map +1 -1
  107. package/dist/public/impact/manifest.js +15 -1
  108. package/dist/public/impact/source-changes.d.ts.map +1 -1
  109. package/dist/public/impact/source-changes.js +35 -27
  110. package/dist/public/impact/types.d.ts +2 -0
  111. package/dist/public/impact/types.d.ts.map +1 -1
  112. package/dist/public/operations/catalog.d.ts +117 -1
  113. package/dist/public/operations/catalog.d.ts.map +1 -1
  114. package/dist/public/operations/catalog.js +2 -0
  115. package/dist/public/operations/contracts.d.ts.map +1 -1
  116. package/dist/public/operations/contracts.js +309 -8
  117. package/dist/public/operations/impact-review-preparation.d.ts +14 -0
  118. package/dist/public/operations/impact-review-preparation.d.ts.map +1 -0
  119. package/dist/public/operations/impact-review-preparation.js +379 -0
  120. package/dist/public/operations/index.d.ts +2 -0
  121. package/dist/public/operations/index.d.ts.map +1 -1
  122. package/dist/public/operations/index.js +2 -0
  123. package/dist/public/operations/node-ports.d.ts.map +1 -1
  124. package/dist/public/operations/node-ports.js +1 -35
  125. package/dist/public/operations/proof-receipt-projection.d.ts +5 -0
  126. package/dist/public/operations/proof-receipt-projection.d.ts.map +1 -0
  127. package/dist/public/operations/proof-receipt-projection.js +36 -0
  128. package/dist/public/operations/specs/bootstrap.d.ts +73 -1
  129. package/dist/public/operations/specs/bootstrap.d.ts.map +1 -1
  130. package/dist/public/operations/specs/bootstrap.js +66 -1
  131. package/dist/public/operations/specs/impact-review-preparation.d.ts +47 -0
  132. package/dist/public/operations/specs/impact-review-preparation.d.ts.map +1 -0
  133. package/dist/public/operations/specs/impact-review-preparation.js +43 -0
  134. package/dist/public/operations/symbol-repair-plan.d.ts.map +1 -1
  135. package/dist/public/operations/symbol-repair-plan.js +3 -1
  136. package/dist/public/operations/types.d.ts +1 -1
  137. package/dist/public/operations/types.d.ts.map +1 -1
  138. package/dist/public/skills/kibi-bootstrap/SKILL.md +47 -11
  139. package/dist/public/skills/kibi-bootstrap/resources/bootstrap.md +6 -1
  140. package/dist/public/skills/kibi-usage/SKILL.md +14 -0
  141. package/dist/public/skills/kibi-usage/resources/operation-access.md +5 -0
  142. package/dist/public/telemetry-acceptance.d.ts +8 -0
  143. package/dist/public/telemetry-acceptance.d.ts.map +1 -1
  144. package/dist/public/telemetry-acceptance.js +10 -0
  145. package/dist/traceability/analysis-gate.d.ts +39 -0
  146. package/dist/traceability/analysis-gate.d.ts.map +1 -0
  147. package/dist/traceability/analysis-gate.js +51 -0
  148. package/dist/traceability/git-change-snapshot.d.ts +27 -0
  149. package/dist/traceability/git-change-snapshot.d.ts.map +1 -0
  150. package/dist/traceability/git-change-snapshot.js +411 -0
  151. package/dist/traceability/git-staged.d.ts +5 -1
  152. package/dist/traceability/git-staged.d.ts.map +1 -1
  153. package/dist/traceability/git-staged.js +16 -11
  154. package/dist/traceability/impact-evaluator.d.ts +54 -0
  155. package/dist/traceability/impact-evaluator.d.ts.map +1 -0
  156. package/dist/traceability/impact-evaluator.js +270 -0
  157. package/dist/traceability/impact-git-tree.d.ts +12 -0
  158. package/dist/traceability/impact-git-tree.d.ts.map +1 -0
  159. package/dist/traceability/impact-git-tree.js +46 -0
  160. package/dist/traceability/impact-knowledge.d.ts +16 -0
  161. package/dist/traceability/impact-knowledge.d.ts.map +1 -0
  162. package/dist/traceability/impact-knowledge.js +165 -0
  163. package/dist/traceability/impact-policy.d.ts +15 -0
  164. package/dist/traceability/impact-policy.d.ts.map +1 -0
  165. package/dist/traceability/impact-policy.js +48 -0
  166. package/dist/traceability/impact-policy.v1.schema.json +48 -0
  167. package/dist/traceability/impact-pr-diff.d.ts +5 -0
  168. package/dist/traceability/impact-pr-diff.d.ts.map +1 -0
  169. package/dist/traceability/impact-pr-diff.js +83 -0
  170. package/dist/traceability/impact-record-validation.d.ts +9 -0
  171. package/dist/traceability/impact-record-validation.d.ts.map +1 -0
  172. package/dist/traceability/impact-record-validation.js +113 -0
  173. package/dist/traceability/impact-review.d.ts +148 -0
  174. package/dist/traceability/impact-review.d.ts.map +1 -0
  175. package/dist/traceability/impact-review.js +494 -0
  176. package/dist/traceability/impact-review.schema.json +365 -0
  177. package/dist/traceability/impact-side-evidence.d.ts +13 -0
  178. package/dist/traceability/impact-side-evidence.d.ts.map +1 -0
  179. package/dist/traceability/impact-side-evidence.js +240 -0
  180. package/dist/traceability/reviewed-coordinate-refresh.d.ts +10 -0
  181. package/dist/traceability/reviewed-coordinate-refresh.d.ts.map +1 -0
  182. package/dist/traceability/reviewed-coordinate-refresh.js +49 -0
  183. package/dist/traceability/snapshot-knowledge.d.ts +4 -0
  184. package/dist/traceability/snapshot-knowledge.d.ts.map +1 -0
  185. package/dist/traceability/snapshot-knowledge.js +98 -0
  186. package/dist/traceability/staged-file-coverage.d.ts +23 -0
  187. package/dist/traceability/staged-file-coverage.d.ts.map +1 -1
  188. package/dist/traceability/staged-impact-contract.d.ts.map +1 -1
  189. package/dist/traceability/staged-impact-contract.js +2 -16
  190. package/dist/traceability/staged-symbols-manifest.d.ts +4 -0
  191. package/dist/traceability/staged-symbols-manifest.d.ts.map +1 -1
  192. package/dist/traceability/staged-symbols-manifest.js +17 -6
  193. package/dist/traceability/symbol-extract.d.ts +3 -5
  194. package/dist/traceability/symbol-extract.d.ts.map +1 -1
  195. package/dist/traceability/symbol-extract.js +49 -34
  196. package/dist/traceability/temp-kb.d.ts +1 -1
  197. package/dist/traceability/temp-kb.d.ts.map +1 -1
  198. package/dist/traceability/temp-kb.js +49 -13
  199. package/dist/traceability/trusted-pr-event.d.ts +13 -0
  200. package/dist/traceability/trusted-pr-event.d.ts.map +1 -0
  201. package/dist/traceability/trusted-pr-event.js +105 -0
  202. package/dist/utils/canonical-path.d.ts +3 -0
  203. package/dist/utils/canonical-path.d.ts.map +1 -0
  204. package/dist/utils/canonical-path.js +33 -0
  205. package/package.json +14 -5
  206. package/src/public/diagnostic-usage.ts +59 -1
  207. package/src/public/impact/analyzer.ts +88 -5
  208. package/src/public/impact/diagnostics.ts +7 -5
  209. package/src/public/impact/manifest.ts +14 -1
  210. package/src/public/impact/source-changes.ts +39 -34
  211. package/src/public/impact/types.ts +5 -0
  212. package/src/public/operations/catalog.ts +2 -0
  213. package/src/public/operations/contracts.ts +385 -9
  214. package/src/public/operations/impact-review-preparation.ts +548 -0
  215. package/src/public/operations/index.ts +2 -0
  216. package/src/public/operations/node-ports.ts +1 -39
  217. package/src/public/operations/proof-receipt-projection.ts +39 -0
  218. package/src/public/operations/specs/bootstrap.ts +78 -4
  219. package/src/public/operations/specs/impact-review-preparation.ts +46 -0
  220. package/src/public/operations/symbol-repair-plan.ts +3 -1
  221. package/src/public/operations/types.ts +1 -0
  222. package/src/public/skills/kibi-bootstrap/SKILL.md +47 -11
  223. package/src/public/skills/kibi-bootstrap/resources/bootstrap.md +6 -1
  224. package/src/public/skills/kibi-usage/SKILL.md +14 -0
  225. package/src/public/skills/kibi-usage/resources/operation-access.md +5 -0
  226. package/src/public/telemetry-acceptance.ts +9 -0
  227. package/src/traceability/impact-policy.v1.schema.json +48 -0
  228. package/src/traceability/impact-review.schema.json +365 -0
  229. package/templates/github/kibi-badge.yml +0 -4
  230. package/templates/github/kibi-report.yml +0 -4
package/dist/engine.js CHANGED
@@ -6,21 +6,34 @@
6
6
  * the local socket; Prolog itself never crosses the process boundary.
7
7
  */
8
8
  import { spawn } from "node:child_process";
9
- import { createHash } from "node:crypto";
10
- import { chmodSync, closeSync, existsSync, fsyncSync, mkdirSync, openSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync, } from "node:fs";
9
+ import { createHash, randomUUID } from "node:crypto";
10
+ import { chmodSync, closeSync, existsSync, fsyncSync, lstatSync, mkdirSync, openSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync, } from "node:fs";
11
11
  import * as net from "node:net";
12
12
  import * as os from "node:os";
13
13
  import * as path from "node:path";
14
+ import { performance } from "node:perf_hooks";
14
15
  import { fileURLToPath } from "node:url";
16
+ import { writePerformanceTraceEvent } from "./performance-trace.js";
15
17
  import { PrologProcess, resolveKbPlPath } from "./prolog.js";
16
18
  import { parseEntityFromList, parseListOfLists } from "./prolog/codec.js";
17
19
  import { retryAttachAfterBreakingStaleLock } from "./prolog/store-lock.js";
20
+ import { resolveSwipl, swiplIdentity } from "./prolog/swipl-resolver.js";
18
21
  import { queryEntityChunks } from "./public/operations/discovery-entities.js";
19
22
  import { isValidBranchName } from "./utils/branch-resolver.js";
20
23
  import { branchStorePath, ensureBranchStoreManifest, } from "./utils/branch-store-locator.js";
24
+ import { canonicalFilesystemPath } from "./utils/canonical-path.js";
21
25
  export const ENGINE_PROTOCOL_VERSION = 1;
22
26
  export const ENGINE_IDLE_TIMEOUT_MS = 10 * 60 * 1000;
23
27
  export const ENGINE_PACKAGE_VERSIONS = process.env.KIBI_PACKAGE_VERSIONS ?? "unknown";
28
+ /**
29
+ * Identity of the SWI-Prolog this process would launch (`<bin>@<version>`).
30
+ * The daemon and every client compare it; a daemon running a different
31
+ * resolved Prolog is replaced, never reused.
32
+ */
33
+ // implements REQ-prolog-daemon-runtime-identity
34
+ export function engineSwiplIdentity() {
35
+ return swiplIdentity(resolveSwipl());
36
+ }
24
37
  const ENGINE_QUERY_CACHE_MAX_ENTRIES = 128;
25
38
  const ENGINE_QUERY_CACHE_MAX_RESULT_BYTES = 8 * 1024 * 1024;
26
39
  const ENGINE_FRESHNESS_CACHE_MS = 100;
@@ -259,17 +272,75 @@ export function runtimeDirectory() {
259
272
  const configured = process.env.KIBI_RUNTIME_DIR ??
260
273
  process.env.XDG_RUNTIME_DIR ??
261
274
  path.join(os.tmpdir(), "kibi-runtime");
262
- const candidates = [configured, path.join(os.tmpdir(), "kibi-runtime")];
275
+ // Windows named pipes have no Unix socket pathname budget. Preserve its
276
+ // filesystem location policy for the associated pid files.
277
+ if (process.platform === "win32") {
278
+ for (const candidate of [
279
+ configured,
280
+ path.join(os.tmpdir(), "kibi-runtime"),
281
+ ]) {
282
+ try {
283
+ mkdirSync(candidate, { recursive: true, mode: 0o700 });
284
+ const probe = path.join(candidate, `.kibi-write-${process.pid}`);
285
+ writeFileSync(probe, "", { mode: 0o600 });
286
+ unlinkSync(probe);
287
+ return candidate;
288
+ }
289
+ catch {
290
+ // Try the existing system-temp fallback.
291
+ }
292
+ }
293
+ throw new Error("Unable to create a writable Kibi engine runtime directory");
294
+ }
295
+ const euid = process.geteuid?.();
296
+ if (euid === undefined)
297
+ throw new Error("Kibi engine runtime euid unavailable");
298
+ let configuredIdentity;
299
+ try {
300
+ configuredIdentity = canonicalFilesystemPath(configured);
301
+ }
302
+ catch {
303
+ // An inaccessible or dangling configured path remains a distinct identity;
304
+ // it is never accepted as the socket directory below.
305
+ configuredIdentity = path.resolve(configured);
306
+ }
307
+ const configuredKey = createHash("sha256")
308
+ .update(configuredIdentity)
309
+ .digest("hex")
310
+ .slice(0, 32);
311
+ const candidates = [
312
+ configured,
313
+ path.join("/tmp", `kb-${euid}-${configuredKey}`),
314
+ ];
315
+ const maximumBytes = process.platform === "linux" ? 107 : 103;
316
+ const socketName = `kibi-${"0".repeat(32)}.sock`;
263
317
  for (const candidate of candidates) {
264
318
  try {
319
+ try {
320
+ if (lstatSync(candidate).isSymbolicLink())
321
+ continue;
322
+ }
323
+ catch (error) {
324
+ if (error.code !== "ENOENT")
325
+ throw error;
326
+ }
265
327
  mkdirSync(candidate, { recursive: true, mode: 0o700 });
328
+ const directory = lstatSync(candidate);
329
+ if (!directory.isDirectory() ||
330
+ directory.uid !== euid ||
331
+ (directory.mode & 0o077) !== 0)
332
+ continue;
333
+ const canonical = canonicalFilesystemPath(candidate);
334
+ if (Buffer.byteLength(path.join(canonical, socketName), "utf8") >
335
+ maximumBytes)
336
+ continue;
266
337
  // XDG_RUNTIME_DIR can exist but be mounted read-only (for example in a
267
338
  // constrained container). Probe the directory before using it for the
268
339
  // socket, start lock, and pid files so auto-start fails over cleanly.
269
- const probe = path.join(candidate, `.kibi-write-${process.pid}`);
270
- writeFileSync(probe, "", { mode: 0o600 });
340
+ const probe = path.join(canonical, `.kibi-write-${randomUUID()}`);
341
+ writeFileSync(probe, "", { mode: 0o600, flag: "wx" });
271
342
  unlinkSync(probe);
272
- return candidate;
343
+ return canonical;
273
344
  }
274
345
  catch {
275
346
  // Try the private system-temp fallback below.
@@ -327,18 +398,11 @@ export function fsyncJournaledBranchStore(branchPath) {
327
398
  }
328
399
  // implements REQ-core-journaled-engine-persistence
329
400
  export function engineSocketPath(workspaceRoot, branch) {
330
- const canonicalRoot = (() => {
331
- try {
332
- return realpathSync(workspaceRoot);
333
- }
334
- catch {
335
- return path.resolve(workspaceRoot);
336
- }
337
- })();
401
+ const canonicalRoot = canonicalFilesystemPath(workspaceRoot);
338
402
  const key = createHash("sha256")
339
403
  .update(`${canonicalRoot}\0${branch}`)
340
- // 128 bits keeps collision risk negligible while staying below the
341
- // roughly 108-byte sockaddr_un limit even in a nested XDG runtime path.
404
+ // Retain 128 bits of workspace/branch identity; runtimeDirectory budgets
405
+ // the complete pathname rather than shortening this identity.
342
406
  .digest("hex")
343
407
  .slice(0, 32);
344
408
  if (process.platform === "win32") {
@@ -675,22 +739,36 @@ export class EngineClient {
675
739
  if (!isValidBranchName(options.branch)) {
676
740
  throw new Error(`Invalid Kibi engine branch name: ${options.branch}`);
677
741
  }
678
- const resolvedWorkspaceRoot = path.resolve(options.workspaceRoot);
679
- try {
680
- this.workspaceRoot = realpathSync(resolvedWorkspaceRoot);
681
- }
682
- catch {
683
- this.workspaceRoot = resolvedWorkspaceRoot;
684
- }
742
+ this.workspaceRoot = canonicalFilesystemPath(options.workspaceRoot);
685
743
  this.branch = options.branch;
686
744
  this.timeout = options.timeout ?? 120_000;
687
745
  this.allowPublicationLock = options.allowPublicationLock ?? false;
688
746
  }
689
747
  async start(allowSpawn = true) {
690
748
  const wasConnected = this.socket !== null && !this.socket.destroyed;
691
- await this.connect(allowSpawn);
692
- if (!wasConnected && this.socket !== null) {
693
- await this.reconcileAttachment();
749
+ for (let attempt = 0;; attempt += 1) {
750
+ await this.connect(allowSpawn);
751
+ if (wasConnected || this.socket === null)
752
+ return;
753
+ try {
754
+ await this.reconcileRuntime();
755
+ await this.reconcileAttachment();
756
+ return;
757
+ }
758
+ catch (error) {
759
+ // A listener can begin draining after the kernel accepts a connection
760
+ // but before the read-only runtime and attachment handshakes finish.
761
+ // Retry those handshakes once; request() never retries an application
762
+ // RPC.
763
+ if (attempt > 0 ||
764
+ !allowSpawn ||
765
+ !(error instanceof Error) ||
766
+ error.message !== "Kibi engine connection closed" ||
767
+ (this.socket !== null && !this.socket.destroyed))
768
+ throw error;
769
+ this.socket?.destroy();
770
+ this.socket = null;
771
+ }
694
772
  }
695
773
  }
696
774
  async connect(allowSpawn = true) {
@@ -729,6 +807,22 @@ export class EngineClient {
729
807
  }
730
808
  }
731
809
  if (this.socket === null) {
810
+ // A draining daemon removes its listener before saving, but retains
811
+ // its PID until the branch lock is released. Do not start a second
812
+ // writer while that process is still completing shutdown.
813
+ const existingPid = this.getPid();
814
+ if (existingPid > 0) {
815
+ let alive = false;
816
+ try {
817
+ process.kill(existingPid, 0);
818
+ alive = true;
819
+ }
820
+ catch { }
821
+ if (alive) {
822
+ await new Promise((resolve) => setTimeout(resolve, 50));
823
+ continue;
824
+ }
825
+ }
732
826
  lock = tryAcquireStartLock(lockPath);
733
827
  if (lock === null) {
734
828
  await new Promise((resolve) => setTimeout(resolve, 50));
@@ -780,7 +874,10 @@ export class EngineClient {
780
874
  this.attachSocket(this.socket);
781
875
  }
782
876
  attachSocket(socket) {
877
+ this.inputBuffer = Buffer.alloc(0);
783
878
  socket.on("data", (chunk) => {
879
+ if (this.socket !== socket)
880
+ return;
784
881
  try {
785
882
  const bytes = typeof chunk === "string" ? Buffer.from(chunk) : chunk;
786
883
  this.inputBuffer = parseFrames(Buffer.concat([this.inputBuffer, bytes]), (value) => this.handleResponse(value));
@@ -790,6 +887,8 @@ export class EngineClient {
790
887
  }
791
888
  });
792
889
  socket.on("close", () => {
890
+ if (this.socket !== socket)
891
+ return;
793
892
  this.socket = null;
794
893
  const error = new Error("Kibi engine connection closed");
795
894
  for (const pending of this.pending.values()) {
@@ -798,6 +897,8 @@ export class EngineClient {
798
897
  this.pending.clear();
799
898
  });
800
899
  socket.on("error", (error) => {
900
+ if (this.socket !== socket)
901
+ return;
801
902
  for (const pending of this.pending.values()) {
802
903
  this.settlePending(pending, () => pending.reject(error));
803
904
  }
@@ -859,6 +960,7 @@ export class EngineClient {
859
960
  id,
860
961
  protocolVersion: ENGINE_PROTOCOL_VERSION,
861
962
  packageVersions: ENGINE_PACKAGE_VERSIONS,
963
+ prologIdentity: engineSwiplIdentity(),
862
964
  workspaceRoot: this.workspaceRoot,
863
965
  branch: this.branch,
864
966
  }), ignoreWriteFailure);
@@ -968,6 +1070,7 @@ export class EngineClient {
968
1070
  cancelOf: requestId,
969
1071
  protocolVersion: ENGINE_PROTOCOL_VERSION,
970
1072
  packageVersions: ENGINE_PACKAGE_VERSIONS,
1073
+ prologIdentity: engineSwiplIdentity(),
971
1074
  workspaceRoot: this.workspaceRoot,
972
1075
  branch: this.branch,
973
1076
  }), ignoreWriteFailure);
@@ -1010,6 +1113,36 @@ export class EngineClient {
1010
1113
  return null;
1011
1114
  return parseEngineAttachmentIdentity(status.bindings.JsonString);
1012
1115
  }
1116
+ async daemonRuntimeMatches() {
1117
+ const reply = await this.request({
1118
+ method: "handshake",
1119
+ });
1120
+ return reply?.prologIdentity === engineSwiplIdentity();
1121
+ }
1122
+ /**
1123
+ * A live daemon keeps the SWI-Prolog it was started with. When this client
1124
+ * resolves a different executable or version (KIBI_SWIPL changed, the
1125
+ * bundled package was upgraded, a pre-handshake daemon), the daemon is
1126
+ * stopped and replaced; it is never reused.
1127
+ */
1128
+ // implements REQ-prolog-daemon-runtime-identity
1129
+ async reconcileRuntime() {
1130
+ if (this.replacingStaleDaemon || this.socket === null)
1131
+ return;
1132
+ if (await this.daemonRuntimeMatches())
1133
+ return;
1134
+ this.replacingStaleDaemon = true;
1135
+ try {
1136
+ await this.shutdownConnectedDaemon();
1137
+ await this.connect(true);
1138
+ if (!(await this.daemonRuntimeMatches())) {
1139
+ throw new Error(`Kibi engine is running a different SWI-Prolog than this client resolved (${engineSwiplIdentity()}); run 'kibi engine stop' and retry`);
1140
+ }
1141
+ }
1142
+ finally {
1143
+ this.replacingStaleDaemon = false;
1144
+ }
1145
+ }
1013
1146
  async reconcileAttachment() {
1014
1147
  if (this.replacingStaleDaemon || this.socket === null)
1015
1148
  return;
@@ -1034,26 +1167,40 @@ export class EngineClient {
1034
1167
  }
1035
1168
  async shutdownConnectedDaemon() {
1036
1169
  const socketPath = engineSocketPath(this.workspaceRoot, this.branch);
1170
+ let requestError;
1037
1171
  if (!this.isRunning()) {
1038
1172
  if (existsSync(socketPath)) {
1039
1173
  throw new Error(`Kibi engine socket remains present but is not reachable: ${socketPath}`);
1040
1174
  }
1041
- return;
1042
- }
1043
- let requestError;
1044
- try {
1045
- await this.request({ method: "stop" });
1175
+ const existingPid = this.getPid();
1176
+ if (existingPid <= 0)
1177
+ return;
1178
+ try {
1179
+ process.kill(existingPid, 0);
1180
+ }
1181
+ catch {
1182
+ return;
1183
+ }
1184
+ // An already-draining daemon can have no listener while its durability
1185
+ // save still owns the store. A stop caller must wait for that handoff.
1046
1186
  }
1047
- catch (error) {
1048
- requestError = error;
1187
+ else {
1188
+ try {
1189
+ await this.request({ method: "stop" });
1190
+ }
1191
+ catch (error) {
1192
+ requestError = error;
1193
+ }
1194
+ this.socket?.destroy();
1195
+ this.socket = null;
1049
1196
  }
1050
- this.socket?.destroy();
1051
- this.socket = null;
1197
+ const pidPath = enginePidPath(this.workspaceRoot, this.branch);
1052
1198
  const deadline = Date.now() + 5_000;
1053
- while (existsSync(socketPath) && Date.now() < deadline) {
1199
+ while ((existsSync(socketPath) || existsSync(pidPath)) &&
1200
+ Date.now() < deadline) {
1054
1201
  await new Promise((resolve) => setTimeout(resolve, 25));
1055
1202
  }
1056
- if (existsSync(socketPath)) {
1203
+ if (existsSync(socketPath) || existsSync(pidPath)) {
1057
1204
  const detail = requestError instanceof Error ? `: ${requestError.message}` : "";
1058
1205
  throw new Error(`Kibi engine did not stop within 5 seconds${detail}`);
1059
1206
  }
@@ -1079,11 +1226,8 @@ export class EngineClient {
1079
1226
  throw new Error("Unable to start Kibi engine for stop request");
1080
1227
  }
1081
1228
  }
1082
- if (!this.isRunning()) {
1083
- if (existsSync(socketPath)) {
1084
- throw new Error(`Kibi engine socket remains present but is not reachable: ${socketPath}`);
1085
- }
1086
- return;
1229
+ if (!this.isRunning() && existsSync(socketPath)) {
1230
+ throw new Error(`Kibi engine socket remains present but is not reachable: ${socketPath}`);
1087
1231
  }
1088
1232
  await this.shutdownConnectedDaemon();
1089
1233
  }
@@ -1301,7 +1445,9 @@ function recoverInterruptedGeneration(branchPath) {
1301
1445
  }
1302
1446
  }
1303
1447
  function isEngineLifecycleRequest(request) {
1304
- if (request.method === "stop" || request.method === "cancel")
1448
+ if (request.method === "stop" ||
1449
+ request.method === "cancel" ||
1450
+ request.method === "handshake")
1305
1451
  return true;
1306
1452
  const kind = request.command?.kind;
1307
1453
  return (request.method === "command" &&
@@ -1386,11 +1532,15 @@ export class EngineSession {
1386
1532
  return true;
1387
1533
  }
1388
1534
  }
1389
- // implements REQ-core-journaled-engine-lifecycle
1390
- export async function runEngineDaemon(options) {
1391
- if (!isValidBranchName(options.branch)) {
1392
- throw new Error(`Invalid Kibi engine branch name: ${options.branch}`);
1535
+ // implements REQ-core-journaled-engine-persistence
1536
+ export async function runEngineDaemon(requestedOptions) {
1537
+ if (!isValidBranchName(requestedOptions.branch)) {
1538
+ throw new Error(`Invalid Kibi engine branch name: ${requestedOptions.branch}`);
1393
1539
  }
1540
+ const options = {
1541
+ ...requestedOptions,
1542
+ workspaceRoot: canonicalFilesystemPath(requestedOptions.workspaceRoot),
1543
+ };
1394
1544
  const branchPath = ensureBranchStoreManifest(options.workspaceRoot, options.branch);
1395
1545
  await ensureJournaledBranchStoreAsync(branchPath);
1396
1546
  const prolog = new PrologProcess({
@@ -1403,6 +1553,7 @@ export async function runEngineDaemon(options) {
1403
1553
  const session = new EngineSession(prolog, branchPath);
1404
1554
  await session.boot();
1405
1555
  let attachedIdentity = readEngineAttachmentIdentity(branchPath);
1556
+ const serverPrologIdentity = engineSwiplIdentity();
1406
1557
  mkdirSync(path.dirname(options.socketPath), { recursive: true, mode: 0o700 });
1407
1558
  if (existsSync(options.socketPath)) {
1408
1559
  const isLivePeerSignal = (error) => {
@@ -1473,6 +1624,10 @@ export async function runEngineDaemon(options) {
1473
1624
  let freshnessCache = null;
1474
1625
  const clients = new Set();
1475
1626
  let shuttingDown = false;
1627
+ let finishShutdown;
1628
+ const shutdownFinished = new Promise((resolve) => {
1629
+ finishShutdown = resolve;
1630
+ });
1476
1631
  const exactBranchStatus = (result) => {
1477
1632
  if (!result.success || typeof result.bindings.JsonString !== "string") {
1478
1633
  return result;
@@ -1520,7 +1675,7 @@ export async function runEngineDaemon(options) {
1520
1675
  }, engineWorkspaceWatchdogMs());
1521
1676
  workspaceWatchdog.unref();
1522
1677
  const scheduleIdleExit = () => {
1523
- if (activeClients > 0)
1678
+ if (shuttingDown || activeClients > 0)
1524
1679
  return;
1525
1680
  if (!idleCompactionQueued) {
1526
1681
  idleCompactionQueued = true;
@@ -1552,11 +1707,19 @@ export async function runEngineDaemon(options) {
1552
1707
  request.packageVersions !== expectedPackages) {
1553
1708
  throw new Error(`Kibi engine package-version mismatch: client=${request.packageVersions ?? "missing"}, server=${expectedPackages}`);
1554
1709
  }
1555
- if (path.resolve(request.workspaceRoot ?? "") !==
1556
- path.resolve(options.workspaceRoot) ||
1710
+ if (canonicalFilesystemPath(request.workspaceRoot ?? "") !==
1711
+ options.workspaceRoot ||
1557
1712
  request.branch !== options.branch) {
1558
1713
  throw new Error("Kibi engine workspace identity mismatch");
1559
1714
  }
1715
+ // A client that resolved a different Prolog must not be served by this
1716
+ // daemon. Handshake reports the identity and stop must still work so the
1717
+ // client can replace the daemon.
1718
+ if (request.method !== "handshake" &&
1719
+ request.method !== "stop" &&
1720
+ request.prologIdentity !== serverPrologIdentity) {
1721
+ throw new Error(`Kibi engine SWI-Prolog mismatch: client=${request.prologIdentity ?? "missing"}, server=${serverPrologIdentity}`);
1722
+ }
1560
1723
  if (!isEngineLifecycleRequest(request) && (await session.ensureLive())) {
1561
1724
  // A recycled session re-read the store; nothing cached from the lost
1562
1725
  // session may be served, and the attachment identity may have moved.
@@ -1747,8 +1910,15 @@ export async function runEngineDaemon(options) {
1747
1910
  }
1748
1911
  }
1749
1912
  case "kbStatus": {
1913
+ const freshnessCacheLookupStartedAt = process.env.KIBI_PERF_TIMINGS === "1" ? performance.now() : null;
1750
1914
  if (freshnessCache !== null &&
1751
1915
  Date.now() - freshnessCache.capturedAt <= ENGINE_FRESHNESS_CACHE_MS) {
1916
+ if (freshnessCacheLookupStartedAt !== null) {
1917
+ writePerformanceTraceEvent({
1918
+ kind: "engine-freshness-cache-hit",
1919
+ durationMs: performance.now() - freshnessCacheLookupStartedAt,
1920
+ });
1921
+ }
1752
1922
  return freshnessCache.result;
1753
1923
  }
1754
1924
  const result = exactBranchStatus(await prolog.query("status:kb_status_json(JsonString)"));
@@ -1768,9 +1938,17 @@ export async function runEngineDaemon(options) {
1768
1938
  freshnessCache = null;
1769
1939
  }
1770
1940
  if (cacheableEngineGoal(request.goal)) {
1941
+ const queryCacheLookupStartedAt = process.env.KIBI_PERF_TIMINGS === "1" ? performance.now() : null;
1771
1942
  const cached = queryCache.get(request.goal);
1772
- if (cached !== undefined)
1943
+ if (cached !== undefined) {
1944
+ if (queryCacheLookupStartedAt !== null) {
1945
+ writePerformanceTraceEvent({
1946
+ kind: "engine-query-cache-hit",
1947
+ durationMs: performance.now() - queryCacheLookupStartedAt,
1948
+ });
1949
+ }
1773
1950
  return cached;
1951
+ }
1774
1952
  }
1775
1953
  const result = await prolog.query(request.goal);
1776
1954
  session.recordModuleLoad(request.goal, result);
@@ -1810,6 +1988,8 @@ export async function runEngineDaemon(options) {
1810
1988
  if (typeof request.targetDirectory !== "string")
1811
1989
  throw new Error("export.targetDirectory is required");
1812
1990
  return prolog.query(`kb_storage_export('${quoteProlog(request.targetDirectory)}')`);
1991
+ case "handshake":
1992
+ return { prologIdentity: serverPrologIdentity };
1813
1993
  case "stop":
1814
1994
  setImmediate(() => void shutdown());
1815
1995
  return { stopped: true };
@@ -1836,6 +2016,10 @@ export async function runEngineDaemon(options) {
1836
2016
  if (idleTimer)
1837
2017
  clearTimeout(idleTimer);
1838
2018
  clearInterval(workspaceWatchdog);
2019
+ // Stop accepting clients before the first asynchronous durability step.
2020
+ // Keep the PID published until Prolog releases the branch-store lock.
2021
+ server.close();
2022
+ await queue.catch(() => undefined);
1839
2023
  const saved = session.needsRecycle()
1840
2024
  ? null
1841
2025
  : await prolog.query("kb_save").catch(() => null);
@@ -1851,7 +2035,6 @@ export async function runEngineDaemon(options) {
1851
2035
  await prolog.terminate().catch(() => undefined);
1852
2036
  for (const client of clients)
1853
2037
  client.destroy();
1854
- server.close();
1855
2038
  // A close callback can remain pending on older Node releases when a
1856
2039
  // client disconnects during `server.close()`. The daemon has already
1857
2040
  // removed its socket/pid and has no useful work left, so do not keep the
@@ -1872,6 +2055,7 @@ export async function runEngineDaemon(options) {
1872
2055
  // gone, force the final event-loop exit rather than retaining a stale
1873
2056
  // detached Node process on platform-specific server bookkeeping.
1874
2057
  setTimeout(() => process.exit(0), 50).unref();
2058
+ finishShutdown();
1875
2059
  };
1876
2060
  // Detached engines must cross the same durability boundary when a service
1877
2061
  // manager or a test harness terminates them as they do for an RPC stop.
@@ -1880,6 +2064,12 @@ export async function runEngineDaemon(options) {
1880
2064
  process.once("SIGTERM", requestSignalShutdown);
1881
2065
  process.once("SIGINT", requestSignalShutdown);
1882
2066
  server.on("connection", (socket) => {
2067
+ // A peer may disappear while the daemon refuses or drains its socket.
2068
+ socket.on("error", () => undefined);
2069
+ if (shuttingDown) {
2070
+ socket.destroy();
2071
+ return;
2072
+ }
1883
2073
  clients.add(socket);
1884
2074
  activeClients += 1;
1885
2075
  // Request ids are per-connection. Cancel marks must not be daemon-global
@@ -1891,6 +2081,15 @@ export async function runEngineDaemon(options) {
1891
2081
  const bytes = typeof chunk === "string" ? Buffer.from(chunk) : chunk;
1892
2082
  buffer = parseFrames(Buffer.concat([buffer, bytes]), (value) => {
1893
2083
  const request = value;
2084
+ if (shuttingDown) {
2085
+ writeSocketFrame(socket, {
2086
+ id: request.id,
2087
+ ok: false,
2088
+ error: "Kibi engine is shutting down; request was not executed",
2089
+ serverPackageVersions: ENGINE_PACKAGE_VERSIONS,
2090
+ });
2091
+ return;
2092
+ }
1894
2093
  if (request.method === "cancel" &&
1895
2094
  typeof request.cancelOf === "number") {
1896
2095
  cancelledRequests.add(request.cancelOf);
@@ -1959,4 +2158,5 @@ export async function runEngineDaemon(options) {
1959
2158
  await new Promise((resolve) => {
1960
2159
  server.once("close", resolve);
1961
2160
  });
2161
+ await shutdownFinished;
1962
2162
  }
@@ -1,4 +1,5 @@
1
1
  import type { CapabilityRegistry } from "../plugins/registry.js";
2
+ import type { SourceAnalysisService } from "../plugins/source-analysis-service.js";
2
3
  import { type ManifestSymbolEntry, enrichSymbolCoordinatesWithTsMorph } from "./symbols-ts.js";
3
4
  export type { ManifestSymbolEntry };
4
5
  export type SourceAnalysisMode = "parser" | "fallback";
@@ -36,7 +37,13 @@ export interface AnalyzeSourceTextOptions {
36
37
  registry?: CapabilityRegistry;
37
38
  }
38
39
  interface EnrichSymbolCoordinatesDeps {
40
+ sourceAnalysisService: SourceAnalysisService;
39
41
  enrichTsCoordinates: typeof enrichSymbolCoordinatesWithTsMorph;
42
+ /** Coordinate-only sync may locate explicit declarations in decorated Python.
43
+ * Completeness-sensitive callers must also verify the captured policy/review. */
44
+ allowPythonDecoratorCoordinates?: boolean;
45
+ /** Additional snapshot/policy authorization for completeness-sensitive gates. */
46
+ verifyPythonDecoratorCoordinates?: (logicalPath: string, analysis: Awaited<ReturnType<SourceAnalysisService["analyzeTextV2"]>>) => Promise<void>;
40
47
  }
41
48
  export declare function analyzeSourceText(entries: ManifestSymbolEntry[], workspaceRoot: string, deps?: Partial<EnrichSymbolCoordinatesDeps>): Promise<ManifestSymbolEntry[]>;
42
49
  export declare function analyzeSourceText(filePath: string, content: string, options?: AnalyzeSourceTextOptions): SourceAnalysisResult;
@@ -1 +1 @@
1
- {"version":3,"file":"symbols-coordinator.d.ts","sourceRoot":"","sources":["../../src/extractors/symbols-coordinator.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAKjE,OAAO,EACL,KAAK,mBAAmB,EAExB,kCAAkC,EACnC,MAAM,iBAAiB,CAAC;AAazB,YAAY,EAAE,mBAAmB,EAAE,CAAC;AAEpC,MAAM,MAAM,kBAAkB,GAAG,QAAQ,GAAG,UAAU,CAAC;AAEvD,MAAM,MAAM,gBAAgB,GACxB,UAAU,GACV,OAAO,GACP,QAAQ,GACR,UAAU,GACV,UAAU,GACV,WAAW,GACX,MAAM,GACN,MAAM,GACN,UAAU,GACV,SAAS,CAAC;AAEd,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,gBAAgB,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,kBAAkB,CAAC;IACjC,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,MAAM,EAAE,oBAAoB,CAAC;IAC7B,OAAO,EAAE,oBAAoB,EAAE,CAAC;CACjC;AAED,MAAM,WAAW,sBAAsB;IACrC,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;IACxC,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,oBAAoB,CAAC;CACtE;AAED,MAAM,WAAW,wBAAwB;IACvC,SAAS,CAAC,EAAE,sBAAsB,EAAE,CAAC;IACrC,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,kBAAkB,CAAC;CAC/B;AAED,UAAU,2BAA2B;IACnC,mBAAmB,EAAE,OAAO,kCAAkC,CAAC;CAChE;AA+BD,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,mBAAmB,EAAE,EAC9B,aAAa,EAAE,MAAM,EACrB,IAAI,CAAC,EAAE,OAAO,CAAC,2BAA2B,CAAC,GAC1C,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAAC;AAClC,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,wBAAwB,GACjC,oBAAoB,CAAC;AA8DxB;;;GAGG;AAEH,wBAAsB,6BAA6B,CACjD,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,kBAAkB,GAC3B,OAAO,CAAC,oBAAoB,CAAC,CAO/B;AAED,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,mBAAmB,EAAE,EAC9B,aAAa,EAAE,MAAM,EACrB,IAAI,CAAC,EAAE,OAAO,CAAC,2BAA2B,CAAC,GAC1C,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAqChC"}
1
+ {"version":3,"file":"symbols-coordinator.d.ts","sourceRoot":"","sources":["../../src/extractors/symbols-coordinator.ts"],"names":[],"mappings":"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"}