kibi-cli 2.12.0 → 2.13.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.
@@ -1 +1 @@
1
- {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AA+EA,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CAC3B;AAGD,wBAAsB,aAAa,CACjC,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAgG/B;AAED,wBAAsB,4BAA4B,CAChD,IAAI,GAAE,MAAM,OAAO,CAAC;IAAE,gBAAgB,CAAC,EAAE,OAAO,CAAA;CAAE,CACT,GACxC,OAAO,CAAC,OAAO,CAAC,CAOlB;AAED,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;;;;;;;;;;;;;;;;MAkE3C;AAkGD,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAGzE;AAED,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,GACX,MAAM,GAAG,SAAS,CAepB"}
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAiFA,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CAC3B;AAGD,wBAAsB,aAAa,CACjC,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAoG/B;AAED,wBAAsB,4BAA4B,CAChD,IAAI,GAAE,MAAM,OAAO,CAAC;IAAE,gBAAgB,CAAC,EAAE,OAAO,CAAA;CAAE,CACT,GACxC,OAAO,CAAC,OAAO,CAAC,CAOlB;AAED,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;;;;;;;;;;;;;;;;MAkE3C;AAkGD,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAGzE;AAED,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,GACX,MAAM,GAAG,SAAS,CAepB"}
@@ -21,9 +21,11 @@ import { createRequire } from "node:module";
21
21
  import * as path from "node:path";
22
22
  import { fileURLToPath } from "node:url";
23
23
  import { bootstrapKibiEnvironment, secretSourceFromBootstrap, } from "../env/bootstrap.js";
24
+ import { kibiPackageVersions } from "../package-versions.js";
24
25
  import { describeConfiguredCapabilityPlugins, readProjectKibiConfig, } from "../plugins/project-config.js";
25
26
  import { SwiplResolutionError, inspectSwiplBundle, probeRequiredLibraries, resolveSwipl, } from "../prolog/swipl-resolver.js";
26
27
  import { buildMigrationPlan, migrationAction, } from "../public/operations/migration-plan.js";
28
+ import { resolveReadBranchAttachment } from "../utils/branch-resolver.js";
27
29
  import { resolveGitRepository, } from "../utils/git-repository-context.js";
28
30
  import { readKbManifestStatus } from "../utils/kb-manifest.js";
29
31
  import { hasManagedHooks, outdatedManagedHooks } from "./init-helpers.js";
@@ -86,6 +88,10 @@ export async function doctorCommand(options = {}) {
86
88
  name: "Capability plugins",
87
89
  check: checkCapabilityPlugins,
88
90
  },
91
+ {
92
+ name: "Engine daemon",
93
+ check: checkEngineDaemon,
94
+ },
89
95
  ];
90
96
  const results = [];
91
97
  for (const { name, check } of checks) {
@@ -227,7 +233,7 @@ async function runtimeProvenance() {
227
233
  mcpCliRange: mcp.dependencies?.["kibi-cli"] ?? "unknown",
228
234
  executeApplyPlanExported,
229
235
  entrypoint: process.argv[1] ?? "unknown",
230
- packageVersions: process.env.KIBI_PACKAGE_VERSIONS ?? "unknown",
236
+ packageVersions: kibiPackageVersions(),
231
237
  locations: {
232
238
  cli: packagePath,
233
239
  cliEntrypoint: process.argv[1] ?? "unknown",
@@ -494,6 +500,75 @@ function formatJevStaticConfigParts(env = process.env) {
494
500
  }
495
501
  return [`jev.model=${model}`, `jev.timeoutMs=${String(timeoutMs)}`];
496
502
  }
503
+ /**
504
+ * The package versions and SWI-Prolog of the engine daemon serving this
505
+ * workspace and branch, read through its handshake without starting one. A
506
+ * daemon with other versions is replaced by the next Kibi command, so it is
507
+ * reported, not failed.
508
+ */
509
+ // implements REQ-engine-daemon-package-versions
510
+ async function checkEngineDaemon() {
511
+ const workspaceRoot = path.resolve(process.env.KIBI_WORKSPACE ??
512
+ process.env.KIBI_PROJECT_ROOT ??
513
+ process.env.KIBI_ROOT ??
514
+ process.cwd());
515
+ const expected = kibiPackageVersions();
516
+ const attachment = resolveReadBranchAttachment(workspaceRoot);
517
+ if ("error" in attachment) {
518
+ return {
519
+ passed: true,
520
+ message: "Not checked: no branch to address the engine daemon",
521
+ details: { running: false, expectedPackageVersions: expected },
522
+ };
523
+ }
524
+ const { EngineClient } = await import("../engine.js");
525
+ const client = new EngineClient({
526
+ workspaceRoot,
527
+ branch: attachment.kbBranch,
528
+ });
529
+ let daemon = null;
530
+ try {
531
+ daemon = await client.inspectLiveDaemon();
532
+ }
533
+ catch (error) {
534
+ return {
535
+ passed: true,
536
+ message: `Not reachable: ${error instanceof Error ? error.message : String(error)}`,
537
+ details: { running: false, expectedPackageVersions: expected },
538
+ };
539
+ }
540
+ finally {
541
+ await client.terminate();
542
+ }
543
+ if (daemon === null) {
544
+ return {
545
+ passed: true,
546
+ message: "Not running",
547
+ details: { running: false, expectedPackageVersions: expected },
548
+ };
549
+ }
550
+ const details = {
551
+ running: true,
552
+ pid: client.getPid(),
553
+ branch: attachment.kbBranch,
554
+ packageVersions: daemon.packageVersions,
555
+ prologIdentity: daemon.prologIdentity,
556
+ expectedPackageVersions: expected,
557
+ };
558
+ if (daemon.packageVersions === expected) {
559
+ return {
560
+ passed: true,
561
+ message: `Running ${daemon.packageVersions}`,
562
+ details,
563
+ };
564
+ }
565
+ return {
566
+ passed: true,
567
+ message: `Running ${daemon.packageVersions ?? "a daemon that reports no package versions"}, not this CLI's ${expected}; the next Kibi command replaces it`,
568
+ remediation: "Run: kibi engine stop",
569
+ details,
570
+ };
571
+ }
497
572
  function checkKbDirectory() {
498
573
  const kbDir = path.join(process.cwd(), ".kb");
499
574
  if (!existsSync(kbDir)) {
package/dist/engine.d.ts CHANGED
@@ -8,6 +8,14 @@ export { EngineQueryLimitError, QUERY_LIMIT_EXCEEDED_CODE, queryLimitExceededOf,
8
8
  export type { EngineLimitExceeded, EngineQueryLimits, } from "./engine-limits.js";
9
9
  export declare const ENGINE_PROTOCOL_VERSION = 1;
10
10
  export declare const ENGINE_IDLE_TIMEOUT_MS: number;
11
+ /**
12
+ * Package versions this engine build carries (KIBI_PACKAGE_VERSIONS when
13
+ * set). The client sends them on every request and the daemon reports its
14
+ * own in the handshake; a daemon with other versions is replaced, never
15
+ * reused.
16
+ */
17
+ export declare function enginePackageVersions(): string;
18
+ /** @deprecated The versions at module load; call enginePackageVersions(). */
11
19
  export declare const ENGINE_PACKAGE_VERSIONS: string;
12
20
  /**
13
21
  * Identity of the SWI-Prolog this process would launch (`<bin>@<version>`).
@@ -43,6 +51,11 @@ export type EnginePublicationLease = Readonly<{
43
51
  readonly release: () => void;
44
52
  }>;
45
53
  export declare function acquireEnginePublicationLease(workspaceRoot: string, branch: string): EnginePublicationLease;
54
+ /** What a live daemon reports in its handshake. */
55
+ export type EngineDaemonIdentity = Readonly<{
56
+ prologIdentity: string | null;
57
+ packageVersions: string | null;
58
+ }>;
46
59
  export type EngineClientOptions = {
47
60
  readonly workspaceRoot: string;
48
61
  readonly branch: string;
@@ -99,11 +112,21 @@ export declare class EngineClient {
99
112
  invalidateCache(): void;
100
113
  isRunning(): boolean;
101
114
  private readAttachedIdentity;
102
- private daemonRuntimeMatches;
115
+ /** The live daemon's handshake: its SWI-Prolog and package versions. */
116
+ private daemonHandshake;
117
+ /**
118
+ * The identity a live daemon reports, without starting one; null when no
119
+ * daemon serves this workspace and branch. The connection is closed again.
120
+ */
121
+ inspectLiveDaemon(): Promise<EngineDaemonIdentity | null>;
122
+ /** Why the live daemon may not serve this client, or null when it may. */
123
+ private daemonRuntimeMismatch;
103
124
  /**
104
- * A live daemon keeps the SWI-Prolog it was started with. When this client
105
- * resolves a different executable or version (KIBI_SWIPL changed, the
106
- * bundled package was upgraded, a pre-handshake daemon), the daemon is
125
+ * A live daemon keeps the SWI-Prolog and the package versions it was
126
+ * started with. When this client resolves a different executable or
127
+ * version (KIBI_SWIPL changed, the bundled package was upgraded, a
128
+ * pre-handshake daemon) or carries other package versions (a daemon left
129
+ * by another install, for example one a git hook started), the daemon is
107
130
  * stopped and replaced; it is never reused.
108
131
  */
109
132
  private reconcileRuntime;
@@ -1 +1 @@
1
- {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"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"}
package/dist/engine.js CHANGED
@@ -14,6 +14,7 @@ import * as path from "node:path";
14
14
  import { performance } from "node:perf_hooks";
15
15
  import { fileURLToPath } from "node:url";
16
16
  import { BOUNDED_READ_HELPER_DEFINITION, assertWithinQueryLimits, boundedReadGoal, normalizeQueryLimits, queryLimitsFromEnv, settleBoundedRead, } from "./engine-limits.js";
17
+ import { kibiPackageVersions } from "./package-versions.js";
17
18
  import { writePerformanceTraceEvent } from "./performance-trace.js";
18
19
  import { PrologProcess, resolveKbPlPath } from "./prolog.js";
19
20
  import { parseEntityFromList, parseListOfLists } from "./prolog/codec.js";
@@ -33,7 +34,18 @@ const READ_LIMITED_METHODS = new Set([
33
34
  ]);
34
35
  export const ENGINE_PROTOCOL_VERSION = 1;
35
36
  export const ENGINE_IDLE_TIMEOUT_MS = 10 * 60 * 1000;
36
- export const ENGINE_PACKAGE_VERSIONS = process.env.KIBI_PACKAGE_VERSIONS ?? "unknown";
37
+ /**
38
+ * Package versions this engine build carries (KIBI_PACKAGE_VERSIONS when
39
+ * set). The client sends them on every request and the daemon reports its
40
+ * own in the handshake; a daemon with other versions is replaced, never
41
+ * reused.
42
+ */
43
+ // implements REQ-engine-daemon-package-versions
44
+ export function enginePackageVersions() {
45
+ return kibiPackageVersions();
46
+ }
47
+ /** @deprecated The versions at module load; call enginePackageVersions(). */
48
+ export const ENGINE_PACKAGE_VERSIONS = kibiPackageVersions();
37
49
  /**
38
50
  * Identity of the SWI-Prolog this process would launch (`<bin>@<version>`).
39
51
  * The daemon and every client compare it; a daemon running a different
@@ -864,6 +876,10 @@ export class EngineClient {
864
876
  env: {
865
877
  ...process.env,
866
878
  KIBI_ENGINE_PROTOCOL: String(ENGINE_PROTOCOL_VERSION),
879
+ // The daemon reports the versions of the client that
880
+ // started it, so this client and its own daemon agree even
881
+ // when the daemon entry is resolved from a bundled host.
882
+ KIBI_PACKAGE_VERSIONS: enginePackageVersions(),
867
883
  },
868
884
  });
869
885
  await new Promise((resolve, reject) => {
@@ -978,7 +994,7 @@ export class EngineClient {
978
994
  ...limits,
979
995
  id,
980
996
  protocolVersion: ENGINE_PROTOCOL_VERSION,
981
- packageVersions: ENGINE_PACKAGE_VERSIONS,
997
+ packageVersions: enginePackageVersions(),
982
998
  prologIdentity: engineSwiplIdentity(),
983
999
  workspaceRoot: this.workspaceRoot,
984
1000
  branch: this.branch,
@@ -1092,7 +1108,7 @@ export class EngineClient {
1092
1108
  method: "cancel",
1093
1109
  cancelOf: requestId,
1094
1110
  protocolVersion: ENGINE_PROTOCOL_VERSION,
1095
- packageVersions: ENGINE_PACKAGE_VERSIONS,
1111
+ packageVersions: enginePackageVersions(),
1096
1112
  prologIdentity: engineSwiplIdentity(),
1097
1113
  workspaceRoot: this.workspaceRoot,
1098
1114
  branch: this.branch,
@@ -1136,30 +1152,68 @@ export class EngineClient {
1136
1152
  return null;
1137
1153
  return parseEngineAttachmentIdentity(status.bindings.JsonString);
1138
1154
  }
1139
- async daemonRuntimeMatches() {
1155
+ /** The live daemon's handshake: its SWI-Prolog and package versions. */
1156
+ async daemonHandshake() {
1140
1157
  const reply = await this.request({
1141
1158
  method: "handshake",
1142
1159
  });
1143
- return reply?.prologIdentity === engineSwiplIdentity();
1160
+ return {
1161
+ prologIdentity: typeof reply?.prologIdentity === "string" ? reply.prologIdentity : null,
1162
+ packageVersions: typeof reply?.packageVersions === "string"
1163
+ ? reply.packageVersions
1164
+ : null,
1165
+ };
1166
+ }
1167
+ /**
1168
+ * The identity a live daemon reports, without starting one; null when no
1169
+ * daemon serves this workspace and branch. The connection is closed again.
1170
+ */
1171
+ // implements REQ-engine-daemon-package-versions
1172
+ async inspectLiveDaemon() {
1173
+ const wasConnected = this.isRunning();
1174
+ if (!wasConnected)
1175
+ await this.connect(false);
1176
+ if (!this.isRunning())
1177
+ return null;
1178
+ try {
1179
+ return await this.daemonHandshake();
1180
+ }
1181
+ finally {
1182
+ if (!wasConnected)
1183
+ await this.terminate();
1184
+ }
1185
+ }
1186
+ /** Why the live daemon may not serve this client, or null when it may. */
1187
+ async daemonRuntimeMismatch() {
1188
+ const daemon = await this.daemonHandshake();
1189
+ const packageVersions = enginePackageVersions();
1190
+ if (daemon.packageVersions !== packageVersions)
1191
+ return `Kibi engine is running other package versions (${daemon.packageVersions ?? "not reported"}) than this client (${packageVersions})`;
1192
+ if (daemon.prologIdentity !== engineSwiplIdentity())
1193
+ return `Kibi engine is running a different SWI-Prolog than this client resolved (${engineSwiplIdentity()})`;
1194
+ return null;
1144
1195
  }
1145
1196
  /**
1146
- * A live daemon keeps the SWI-Prolog it was started with. When this client
1147
- * resolves a different executable or version (KIBI_SWIPL changed, the
1148
- * bundled package was upgraded, a pre-handshake daemon), the daemon is
1197
+ * A live daemon keeps the SWI-Prolog and the package versions it was
1198
+ * started with. When this client resolves a different executable or
1199
+ * version (KIBI_SWIPL changed, the bundled package was upgraded, a
1200
+ * pre-handshake daemon) or carries other package versions (a daemon left
1201
+ * by another install, for example one a git hook started), the daemon is
1149
1202
  * stopped and replaced; it is never reused.
1150
1203
  */
1151
- // implements REQ-prolog-daemon-runtime-identity
1204
+ // implements REQ-prolog-daemon-runtime-identity, REQ-engine-daemon-package-versions
1152
1205
  async reconcileRuntime() {
1153
1206
  if (this.replacingStaleDaemon || this.socket === null)
1154
1207
  return;
1155
- if (await this.daemonRuntimeMatches())
1208
+ if ((await this.daemonRuntimeMismatch()) === null)
1156
1209
  return;
1157
1210
  this.replacingStaleDaemon = true;
1158
1211
  try {
1159
1212
  await this.shutdownConnectedDaemon();
1160
1213
  await this.connect(true);
1161
- if (!(await this.daemonRuntimeMatches())) {
1162
- throw new Error(`Kibi engine is running a different SWI-Prolog than this client resolved (${engineSwiplIdentity()}); run 'kibi engine stop' and retry`);
1214
+ const mismatch = await this.daemonRuntimeMismatch();
1215
+ if (mismatch !== null) {
1216
+ throw new Error(`${mismatch} after replacing it; run 'kibi engine stop' and retry`);
1163
1217
  }
1164
1218
  }
1165
1219
  finally {
@@ -1577,6 +1631,7 @@ export async function runEngineDaemon(requestedOptions) {
1577
1631
  await session.boot();
1578
1632
  let attachedIdentity = readEngineAttachmentIdentity(branchPath);
1579
1633
  const serverPrologIdentity = engineSwiplIdentity();
1634
+ const serverPackageVersions = enginePackageVersions();
1580
1635
  mkdirSync(path.dirname(options.socketPath), { recursive: true, mode: 0o700 });
1581
1636
  if (existsSync(options.socketPath)) {
1582
1637
  const isLivePeerSignal = (error) => {
@@ -1739,23 +1794,22 @@ export async function runEngineDaemon(requestedOptions) {
1739
1794
  if (request.protocolVersion !== ENGINE_PROTOCOL_VERSION) {
1740
1795
  throw new Error(`Kibi engine protocol mismatch: client=${request.protocolVersion ?? "missing"}, server=${ENGINE_PROTOCOL_VERSION}`);
1741
1796
  }
1742
- const expectedPackages = process.env.KIBI_PACKAGE_VERSIONS;
1743
- if (expectedPackages !== undefined &&
1744
- request.packageVersions !== expectedPackages) {
1745
- throw new Error(`Kibi engine package-version mismatch: client=${request.packageVersions ?? "missing"}, server=${expectedPackages}`);
1746
- }
1747
1797
  if (canonicalFilesystemPath(request.workspaceRoot ?? "") !==
1748
1798
  options.workspaceRoot ||
1749
1799
  request.branch !== options.branch) {
1750
1800
  throw new Error("Kibi engine workspace identity mismatch");
1751
1801
  }
1752
- // A client that resolved a different Prolog must not be served by this
1753
- // daemon. Handshake reports the identity and stop must still work so the
1802
+ // A client from another install (other package versions) or one that
1803
+ // resolved a different Prolog must not be served by this daemon.
1804
+ // Handshake reports both identities and stop must still work so the
1754
1805
  // client can replace the daemon.
1755
- if (request.method !== "handshake" &&
1756
- request.method !== "stop" &&
1757
- request.prologIdentity !== serverPrologIdentity) {
1758
- throw new Error(`Kibi engine SWI-Prolog mismatch: client=${request.prologIdentity ?? "missing"}, server=${serverPrologIdentity}`);
1806
+ if (request.method !== "handshake" && request.method !== "stop") {
1807
+ if (request.packageVersions !== serverPackageVersions) {
1808
+ throw new Error(`Kibi engine package-version mismatch: client=${request.packageVersions ?? "missing"}, server=${serverPackageVersions}`);
1809
+ }
1810
+ if (request.prologIdentity !== serverPrologIdentity) {
1811
+ throw new Error(`Kibi engine SWI-Prolog mismatch: client=${request.prologIdentity ?? "missing"}, server=${serverPrologIdentity}`);
1812
+ }
1759
1813
  }
1760
1814
  if (!isEngineLifecycleRequest(request) && (await session.ensureLive())) {
1761
1815
  // A recycled session re-read the store; nothing cached from the lost
@@ -2037,7 +2091,10 @@ export async function runEngineDaemon(requestedOptions) {
2037
2091
  throw new Error("export.targetDirectory is required");
2038
2092
  return prolog.query(`kb_storage_export('${quoteProlog(request.targetDirectory)}')`);
2039
2093
  case "handshake":
2040
- return { prologIdentity: serverPrologIdentity };
2094
+ return {
2095
+ prologIdentity: serverPrologIdentity,
2096
+ packageVersions: serverPackageVersions,
2097
+ };
2041
2098
  case "stop":
2042
2099
  setImmediate(() => void shutdown());
2043
2100
  return { stopped: true };
@@ -2134,7 +2191,7 @@ export async function runEngineDaemon(requestedOptions) {
2134
2191
  id: request.id,
2135
2192
  ok: false,
2136
2193
  error: "Kibi engine is shutting down; request was not executed",
2137
- serverPackageVersions: ENGINE_PACKAGE_VERSIONS,
2194
+ serverPackageVersions,
2138
2195
  });
2139
2196
  return;
2140
2197
  }
@@ -2149,7 +2206,7 @@ export async function runEngineDaemon(requestedOptions) {
2149
2206
  id: request.id,
2150
2207
  ok: false,
2151
2208
  error: "Kibi engine request cancelled",
2152
- serverPackageVersions: ENGINE_PACKAGE_VERSIONS,
2209
+ serverPackageVersions,
2153
2210
  });
2154
2211
  return;
2155
2212
  }
@@ -2159,7 +2216,7 @@ export async function runEngineDaemon(requestedOptions) {
2159
2216
  id: request.id,
2160
2217
  ok: true,
2161
2218
  result,
2162
- serverPackageVersions: ENGINE_PACKAGE_VERSIONS,
2219
+ serverPackageVersions,
2163
2220
  });
2164
2221
  }
2165
2222
  catch (error) {
@@ -2167,7 +2224,7 @@ export async function runEngineDaemon(requestedOptions) {
2167
2224
  id: request.id,
2168
2225
  ok: false,
2169
2226
  error: error instanceof Error ? error.message : String(error),
2170
- serverPackageVersions: ENGINE_PACKAGE_VERSIONS,
2227
+ serverPackageVersions,
2171
2228
  });
2172
2229
  }
2173
2230
  finally {
@@ -11,6 +11,13 @@ export declare function buildSuggestion(schema: PredicateSchemaCandidate, text:
11
11
  * the caller bound that argument or passed subjectHint.
12
12
  */
13
13
  requirementSubject?: string;
14
+ /**
15
+ * Every subject_key the requirement constrains. When there are any, the
16
+ * predicate must be about one of them (its `subject` argument or, for a
17
+ * schema without one, its subject_key) or kb_check reports
18
+ * strict-req-fact-pairing; an unpaired candidate stays incomplete.
19
+ */
20
+ constrainedSubjects?: readonly string[];
14
21
  }): PredicateSuggestion;
15
22
  export declare function buildPredicateApplyPlan(suggestion: PredicateSuggestion, args: SuggestPredicatesArgs): Array<Record<string, unknown>>;
16
23
  export declare function buildRelationshipPlan(factId: string | undefined, requirementId: string | undefined, claimText?: string, existingLogicClaims?: readonly string[]): Record<string, unknown> | null;
@@ -1 +1 @@
1
- {"version":3,"file":"predicate-applyplan.d.ts","sourceRoot":"","sources":["../../../src/operations/modeling/predicate-applyplan.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAEV,wBAAwB,EACxB,wBAAwB,EACxB,mBAAmB,EACnB,0BAA0B,EAC1B,qBAAqB,EACtB,MAAM,sBAAsB,CAAC;AAQ9B,wBAAgB,eAAe,CAC7B,MAAM,EAAE,wBAAwB,EAChC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,gBAAgB,GAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAM,EACvD,YAAY,CAAC,EAAE,QAAQ,GAAG,MAAM,EAChC,WAAW,CAAC,EAAE;IACZ,WAAW,CAAC,EAAE,UAAU,GAAG,UAAU,CAAC;IACtC,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,eAAe,CAAC,EAAE,wBAAwB,CAAC;IAC3C,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B,GACA,mBAAmB,CAsHrB;AAGD,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,mBAAmB,EAC/B,IAAI,EAAE,qBAAqB,GAC1B,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAqChC;AAGD,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,aAAa,EAAE,MAAM,GAAG,SAAS,EACjC,SAAS,CAAC,EAAE,MAAM,EAClB,mBAAmB,GAAE,SAAS,MAAM,EAAO,GAC1C,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAuBhC;AAoBD;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,qBAAqB,GAC1B,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAwBhC;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,GACd,0BAA0B,CAoE5B"}
1
+ {"version":3,"file":"predicate-applyplan.d.ts","sourceRoot":"","sources":["../../../src/operations/modeling/predicate-applyplan.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAEV,wBAAwB,EACxB,wBAAwB,EACxB,mBAAmB,EACnB,0BAA0B,EAC1B,qBAAqB,EACtB,MAAM,sBAAsB,CAAC;AAQ9B,wBAAgB,eAAe,CAC7B,MAAM,EAAE,wBAAwB,EAChC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,gBAAgB,GAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAM,EACvD,YAAY,CAAC,EAAE,QAAQ,GAAG,MAAM,EAChC,WAAW,CAAC,EAAE;IACZ,WAAW,CAAC,EAAE,UAAU,GAAG,UAAU,CAAC;IACtC,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,eAAe,CAAC,EAAE,wBAAwB,CAAC;IAC3C,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACzC,GACA,mBAAmB,CA4JrB;AAGD,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,mBAAmB,EAC/B,IAAI,EAAE,qBAAqB,GAC1B,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CA0ChC;AAGD,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,aAAa,EAAE,MAAM,GAAG,SAAS,EACjC,SAAS,CAAC,EAAE,MAAM,EAClB,mBAAmB,GAAE,SAAS,MAAM,EAAO,GAC1C,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAuBhC;AAoBD;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,qBAAqB,GAC1B,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAwBhC;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,GACd,0BAA0B,CAoE5B"}
@@ -5,21 +5,28 @@ import { inferArgs } from "./predicate-inference.js";
5
5
  import { schemaForCandidate } from "./predicate-loader.js";
6
6
  import { hashId } from "./predicate-utils.js";
7
7
  import { applyArgumentRewrites, predicateArgumentConformance, } from "./predicate-vocabulary.js";
8
- // implements REQ-mcp-suggest-predicates
8
+ // implements REQ-mcp-suggest-predicates, REQ-model-predicates-requirement-subject-v2, REQ-model-predicates-binding-clauses
9
9
  export function buildSuggestion(schema, text, subject, score, argumentBindings = {}, polarityHint, diagnostics) {
10
10
  const inferredArgs = inferArgs(schema, text, subject);
11
11
  const canonicalLauncherArgs = exactLauncherPredicateArgs(schema.predicate_name, text);
12
12
  const hasExactBinding = (name) => typeof argumentBindings[name] === "string" &&
13
13
  argumentBindings[name].trim().length > 0;
14
- const requirementSubjectArgument = diagnostics?.requirementSubject &&
15
- diagnostics.explicitSubject !== true &&
16
- !hasExactBinding("subject")
17
- ? schema.argument_names.indexOf("subject")
14
+ // The argument the schema names `subject`, wherever it sits; -1 when the
15
+ // schema names no subject (permission_rule(actor, action, resource, ...)).
16
+ const subjectArgument = schema.argument_names.indexOf("subject");
17
+ const explicitSubject = diagnostics?.explicitSubject === true;
18
+ // The reviewed subject: subjectHint, else the requirement's constrained
19
+ // subject. It binds the `subject` argument unless that argument is bound.
20
+ const reviewedSubject = explicitSubject
21
+ ? subject
22
+ : diagnostics?.requirementSubject;
23
+ const reviewedSubjectArgument = reviewedSubject !== undefined && !hasExactBinding("subject")
24
+ ? subjectArgument
18
25
  : -1;
19
26
  const boundArgs = schema.argument_names.map((name, index) => {
20
27
  const exactBinding = argumentBindings[name];
21
- if (index === requirementSubjectArgument)
22
- return diagnostics?.requirementSubject ?? "unknown";
28
+ if (index === reviewedSubjectArgument)
29
+ return reviewedSubject ?? "unknown";
23
30
  return typeof exactBinding === "string" && exactBinding.trim().length > 0
24
31
  ? exactBinding.trim()
25
32
  : (inferredArgs[index] ?? "unknown");
@@ -34,32 +41,59 @@ export function buildSuggestion(schema, text, subject, score, argumentBindings =
34
41
  const conformance = predicateArgumentConformance(schema.argument_names, boundArgs, vocabulary);
35
42
  const predicateArgs = applyArgumentRewrites(boundArgs, conformance.rewrites);
36
43
  const undeclaredArguments = new Set(conformance.undeclared.map((value) => value.argumentName));
44
+ // A schema without a `subject` argument may still lead with the hinted
45
+ // subject (inference put it there): that value is the agent's reviewed
46
+ // value, even when the schema names its first argument after it.
47
+ const hintedFirstArgument = explicitSubject &&
48
+ subjectArgument < 0 &&
49
+ !hasExactBinding(schema.argument_names[0] ?? "") &&
50
+ predicateArgs[0] === subject
51
+ ? 0
52
+ : -1;
37
53
  const bindingProvenanceByArgument = Object.fromEntries(schema.argument_names.map((name, index) => [
38
54
  name,
39
- index === requirementSubjectArgument && !undeclaredArguments.has(name)
40
- ? "requirement"
41
- : classifyBinding(predicateArgs[index] ?? "unknown", text, (typeof argumentBindings[name] === "string" &&
42
- argumentBindings[name].trim().length > 0) ||
43
- (diagnostics?.explicitSubject === true && index === 0), canonicalLauncherArgs?.[index] === predicateArgs[index] &&
55
+ index === reviewedSubjectArgument && !undeclaredArguments.has(name)
56
+ ? explicitSubject
57
+ ? classifyBinding(predicateArgs[index] ?? "unknown", text, true)
58
+ : "requirement"
59
+ : classifyBinding(predicateArgs[index] ?? "unknown", text, hasExactBinding(name) || index === hintedFirstArgument, canonicalLauncherArgs?.[index] === predicateArgs[index] &&
44
60
  !(index === 0 &&
45
61
  predicateArgs[index] === "launcher" &&
46
- diagnostics?.explicitSubject !== true &&
47
- typeof argumentBindings[name] !== "string"),
48
- // A subject named through subjectHint is the agent's reviewed
49
- // subject, even when the schema names its first argument after it.
50
- index === 0 &&
51
- diagnostics?.explicitSubject === true &&
52
- typeof argumentBindings[name] !== "string"
62
+ !explicitSubject &&
63
+ typeof argumentBindings[name] !== "string"), index === hintedFirstArgument
53
64
  ? { constants: schema.argument_constants?.[name] }
54
65
  : {
55
66
  argumentName: name,
56
67
  argumentNames: schema.argument_names,
68
+ argumentType: schema.argument_types[index],
57
69
  constants: schema.argument_constants?.[name],
58
70
  }),
59
71
  ]));
72
+ // The subject the planned predicate fact is about, when the requirement
73
+ // constrains subjects: the `subject` argument's value, or for a schema
74
+ // without one the reviewed subject, recorded as the fact's subject_key.
75
+ const constrainedSubjects = diagnostics?.constrainedSubjects ?? [];
76
+ const subjectKey = constrainedSubjects.length === 0
77
+ ? null
78
+ : subjectArgument >= 0
79
+ ? (predicateArgs[subjectArgument] ?? null)
80
+ : (reviewedSubject ?? null);
81
+ const subjectPairing = constrainedSubjects.length === 0
82
+ ? "not_required"
83
+ : subjectKey !== null && constrainedSubjects.includes(subjectKey)
84
+ ? "paired"
85
+ : "unpaired";
60
86
  const bindingProvenance = aggregateBindingProvenance(Object.values(bindingProvenanceByArgument));
61
87
  const unboundArguments = schema.argument_names.filter((name) => undeclaredArguments.has(name) ||
62
88
  !bindingCanBeApplied(bindingProvenanceByArgument[name] ?? "placeholder"));
89
+ // An unpaired predicate would leave kb_check's strict-req-fact-pairing on
90
+ // the requirement, so the subject still needs a binding: the `subject`
91
+ // argument, or the fact's subject_key for a schema without one.
92
+ if (subjectPairing === "unpaired") {
93
+ const missing = subjectArgument >= 0 ? "subject" : "subject_key";
94
+ if (!unboundArguments.includes(missing))
95
+ unboundArguments.push(missing);
96
+ }
63
97
  const canonicalKey = `${schema.predicate_name}(${predicateArgs.join(",")})`;
64
98
  // Permission-style inference carries the deontic decision as its final
65
99
  // argument. Preserve that polarity in the typed suggestion instead of
@@ -79,6 +113,8 @@ export function buildSuggestion(schema, text, subject, score, argumentBindings =
79
113
  unbound_arguments: unboundArguments,
80
114
  binding_provenance: bindingProvenance,
81
115
  binding_provenance_by_argument: bindingProvenanceByArgument,
116
+ subject_key: subjectKey,
117
+ subject_pairing: subjectPairing,
82
118
  eligibility: diagnostics?.eligibility ?? "eligible",
83
119
  rejection_reasons: [...(diagnostics?.rejectionReasons ?? [])],
84
120
  applicability_score: diagnostics?.applicabilityScore ?? score,
@@ -97,7 +133,7 @@ export function buildSuggestion(schema, text, subject, score, argumentBindings =
97
133
  schema: schemaForCandidate(schema),
98
134
  };
99
135
  }
100
- // implements REQ-mcp-suggest-predicates
136
+ // implements REQ-mcp-suggest-predicates, REQ-model-predicates-requirement-subject-v2
101
137
  export function buildPredicateApplyPlan(suggestion, args) {
102
138
  if (suggestion.binding_status !== "complete" ||
103
139
  suggestion.eligibility !== "eligible")
@@ -123,6 +159,11 @@ export function buildPredicateApplyPlan(suggestion, args) {
123
159
  ...suggestion.schema.tags.map((tag) => `predicate:${tag}`),
124
160
  ],
125
161
  fact_kind: "predicate",
162
+ // The subject the predicate is about, so kb_check pairs it with the
163
+ // requirement's subject fact whatever argument holds the subject.
164
+ ...(suggestion.subject_key
165
+ ? { subject_key: suggestion.subject_key }
166
+ : {}),
126
167
  predicate_name: suggestion.predicate_name,
127
168
  predicate_args: suggestion.predicate_args,
128
169
  canonical_key: suggestion.canonical_key,
@@ -1 +1 @@
1
- {"version":3,"file":"predicate-binding-hints.d.ts","sourceRoot":"","sources":["../../../src/operations/modeling/predicate-binding-hints.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAoD7E;;;;;GAKG;AAEH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,mBAAmB,EAC9B,IAAI,EAAE,MAAM,EACZ,mBAAmB,GAAE,SAAS,MAAM,EAAO,GAC1C,WAAW,EAAE,CAiCf;AAED,wEAAwE;AACxE,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,SAAS,WAAW,EAAE,GAAG,MAAM,CAW1E"}
1
+ {"version":3,"file":"predicate-binding-hints.d.ts","sourceRoot":"","sources":["../../../src/operations/modeling/predicate-binding-hints.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AA0D7E;;;;;GAKG;AAEH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,mBAAmB,EAC9B,IAAI,EAAE,MAAM,EACZ,mBAAmB,GAAE,SAAS,MAAM,EAAO,GAC1C,WAAW,EAAE,CA6Df;AAED,wEAAwE;AACxE,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,SAAS,WAAW,EAAE,GAAG,MAAM,CAW1E"}
@@ -1,4 +1,4 @@
1
- import { isGenericPlaceholder, nameOrStopWordReason, } from "./predicate-bindings.js";
1
+ import { bindingCanBeApplied, clauseBindingReason, isGenericPlaceholder, nameOrStopWordReason, } from "./predicate-bindings.js";
2
2
  const MAX_EXAMPLES = 5;
3
3
  /** Split `name(a, b(c), d)` into its top-level arguments, or [] when it is not a call. */
4
4
  function exampleArguments(example) {
@@ -36,6 +36,12 @@ function unboundReason(candidate, name, value, text) {
36
36
  });
37
37
  if (nameReason !== null)
38
38
  return `The value "${value}" is not a binding: ${nameReason}.`;
39
+ const clauseReason = clauseBindingReason(value, {
40
+ argumentType: schema.argument_types[schema.argument_names.indexOf(name)],
41
+ constants: schema.argument_constants?.[name],
42
+ });
43
+ if (clauseReason !== null)
44
+ return `The value "${value}" is not a binding: ${clauseReason}. Bind a noun of at most 3 words, or the requirement's subject key.`;
39
45
  if (!value.trim() || isGenericPlaceholder(value))
40
46
  return "The claim text names no value for this argument.";
41
47
  if (provenance === "inferred")
@@ -50,11 +56,25 @@ function unboundReason(candidate, name, value, text) {
50
56
  * current value was not accepted, so the agent binds from the claim text
51
57
  * instead of guessing.
52
58
  */
53
- // implements REQ-model-predicates-binding-placeholders, REQ-model-predicates-requirement-subject
59
+ // implements REQ-model-predicates-binding-placeholders, REQ-model-predicates-requirement-subject-v2, REQ-model-predicates-binding-clauses
54
60
  export function buildBindingHints(candidate, text, requirementSubjects = []) {
55
61
  const schema = candidate.schema;
56
62
  const parsedExamples = schema.examples.map(exampleArguments);
63
+ const namesSubject = schema.argument_names.includes("subject");
57
64
  return candidate.unbound_arguments.map((name) => {
65
+ // A schema without a subject argument records the requirement's subject
66
+ // as the predicate fact's subject_key instead.
67
+ if (name === "subject_key" && !namesSubject)
68
+ return {
69
+ argument: name,
70
+ position: -1,
71
+ type: "subject_key",
72
+ description: "The subject the predicate fact is about; recorded as its subject_key because the schema names no subject argument.",
73
+ examples: requirementSubjects.slice(0, MAX_EXAMPLES),
74
+ currentValue: candidate.subject_key ?? "",
75
+ provenance: "placeholder",
76
+ reason: `The ${schema.predicate_name} schema does not name the requirement's subject, so kb_check pairs the predicate with the subject fact only through subject_key. Pass subjectHint with one of the subjects the requirement constrains.`,
77
+ };
58
78
  const position = schema.argument_names.indexOf(name);
59
79
  const constants = schema.argument_constants?.[name];
60
80
  const exampleValues = parsedExamples
@@ -63,7 +83,13 @@ export function buildBindingHints(candidate, text, requirementSubjects = []) {
63
83
  // The subject keys the requirement already constrains come first, so
64
84
  // the predicate and the subject fact use one identifier for the subject.
65
85
  const examples = Array.from(new Set([
66
- ...(name === "subject" ? requirementSubjects : []),
86
+ ...(name === "subject" ||
87
+ (!namesSubject &&
88
+ clauseBindingReason(candidate.predicate_args[position] ?? "", {
89
+ argumentType: schema.argument_types[position],
90
+ }) !== null)
91
+ ? requirementSubjects
92
+ : []),
67
93
  ...(constants ?? []),
68
94
  ...exampleValues,
69
95
  ])).slice(0, MAX_EXAMPLES);
@@ -78,7 +104,11 @@ export function buildBindingHints(candidate, text, requirementSubjects = []) {
78
104
  examples,
79
105
  currentValue: current,
80
106
  provenance: candidate.binding_provenance_by_argument[name] ?? "placeholder",
81
- reason: unboundReason(candidate, name, current, text),
107
+ reason: name === "subject" &&
108
+ candidate.subject_pairing === "unpaired" &&
109
+ bindingCanBeApplied(candidate.binding_provenance_by_argument[name] ?? "placeholder")
110
+ ? `The value "${current}" is not a subject the requirement constrains (${requirementSubjects.join(", ")}), so kb_check would not pair the predicate with the subject fact. Bind one of them.`
111
+ : unboundReason(candidate, name, current, text),
82
112
  };
83
113
  });
84
114
  }
@@ -10,6 +10,8 @@ export type BindingContext = Readonly<{
10
10
  argumentNames?: readonly string[];
11
11
  /** Declared constants of this argument: always valid when matched. */
12
12
  constants?: readonly string[] | undefined;
13
+ /** The argument's declared type (`entity`, `actor`, `resource`, ...). */
14
+ argumentType?: string | undefined;
13
15
  /**
14
16
  * The claim text. A value that repeats an argument name is still a real
15
17
  * binding when the claim itself names it (a `launcher` argument bound to
@@ -23,6 +25,17 @@ export type BindingContext = Readonly<{
23
25
  * word. Declared constants and the booleans `true`/`false` always pass.
24
26
  */
25
27
  export declare function nameOrStopWordReason(value: string, context?: BindingContext): string | null;
28
+ /** The most words a value of a naming argument may have. */
29
+ export declare const MAX_NAMING_BINDING_WORDS = 3;
30
+ /**
31
+ * Why a value taken from the claim text cannot name a participant, or null
32
+ * when it can: a value of an entity-, actor- or resource-like argument with
33
+ * more than MAX_NAMING_BINDING_WORDS words is a clause of the claim (for
34
+ * example everything before the modal verb), not the participant's name.
35
+ * Explicit bindings, requirement subjects and declared constants are not
36
+ * judged here.
37
+ */
38
+ export declare function clauseBindingReason(value: string, context?: BindingContext): string | null;
26
39
  export declare function classifyBinding(value: string, text: string, explicit: boolean, canonical?: boolean, context?: BindingContext): BindingProvenance;
27
40
  export declare function aggregateBindingProvenance(values: readonly BindingProvenance[]): BindingProvenance;
28
41
  export declare function bindingCanBeApplied(value: BindingProvenance): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"predicate-bindings.d.ts","sourceRoot":"","sources":["../../../src/operations/modeling/predicate-bindings.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAgH9D,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAW3D;AAgED,iEAAiE;AACjE,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMlD;AAED,sDAAsD;AACtD,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC;IACpC,qCAAqC;IACrC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,yCAAyC;IACzC,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,sEAAsE;IACtE,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IAC1C;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3B,CAAC,CAAC;AAiBH;;;;GAIG;AAEH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,cAAmB,GAC3B,MAAM,GAAG,IAAI,CAYf;AAGD,wBAAgB,eAAe,CAC7B,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,OAAO,EACjB,SAAS,UAAQ,EACjB,OAAO,GAAE,cAAmB,GAC3B,iBAAiB,CAmBnB;AAUD,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,SAAS,iBAAiB,EAAE,GACnC,iBAAiB,CAQnB;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAIrE"}
1
+ {"version":3,"file":"predicate-bindings.d.ts","sourceRoot":"","sources":["../../../src/operations/modeling/predicate-bindings.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAgH9D,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAW3D;AAgED,iEAAiE;AACjE,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMlD;AAED,sDAAsD;AACtD,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC;IACpC,qCAAqC;IACrC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,yCAAyC;IACzC,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,sEAAsE;IACtE,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IAC1C,yEAAyE;IACzE,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3B,CAAC,CAAC;AAiBH;;;;GAIG;AAEH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,cAAmB,GAC3B,MAAM,GAAG,IAAI,CAYf;AAgBD,4DAA4D;AAC5D,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAE1C;;;;;;;GAOG;AAEH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,cAAmB,GAC3B,MAAM,GAAG,IAAI,CAOf;AAGD,wBAAgB,eAAe,CAC7B,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,OAAO,EACjB,SAAS,UAAQ,EACjB,OAAO,GAAE,cAAmB,GAC3B,iBAAiB,CAsBnB;AAUD,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,SAAS,iBAAiB,EAAE,GACnC,iBAAiB,CAQnB;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAIrE"}
@@ -209,7 +209,42 @@ export function nameOrStopWordReason(value, context = {}) {
209
209
  return `it repeats the argument name ${token} and the claim does not name it`;
210
210
  return null;
211
211
  }
212
- // implements REQ-mcp-suggest-predicates, REQ-model-predicates-binding-placeholders
212
+ /**
213
+ * Argument types that name a participant (who or what), so a value is a
214
+ * short noun or a subject key, never a clause of the claim.
215
+ */
216
+ const NAMING_ARGUMENT_TYPES = new Set([
217
+ "entity",
218
+ "actor",
219
+ "actor_scope",
220
+ "resource",
221
+ "owner",
222
+ "role",
223
+ "component",
224
+ ]);
225
+ /** The most words a value of a naming argument may have. */
226
+ export const MAX_NAMING_BINDING_WORDS = 3;
227
+ /**
228
+ * Why a value taken from the claim text cannot name a participant, or null
229
+ * when it can: a value of an entity-, actor- or resource-like argument with
230
+ * more than MAX_NAMING_BINDING_WORDS words is a clause of the claim (for
231
+ * example everything before the modal verb), not the participant's name.
232
+ * Explicit bindings, requirement subjects and declared constants are not
233
+ * judged here.
234
+ */
235
+ // implements REQ-model-predicates-binding-clauses
236
+ export function clauseBindingReason(value, context = {}) {
237
+ const type = context.argumentType ? bindingToken(context.argumentType) : "";
238
+ if (!NAMING_ARGUMENT_TYPES.has(type))
239
+ return null;
240
+ if (matchesConstant(value, context))
241
+ return null;
242
+ const words = bindingToken(value).split("_").filter(Boolean);
243
+ if (words.length <= MAX_NAMING_BINDING_WORDS)
244
+ return null;
245
+ return `it is a ${words.length}-word clause of the claim, not a short name for this ${type}`;
246
+ }
247
+ // implements REQ-mcp-suggest-predicates, REQ-model-predicates-binding-placeholders, REQ-model-predicates-binding-clauses
213
248
  export function classifyBinding(value, text, explicit, canonical = false, context = {}) {
214
249
  const normalized = value.trim();
215
250
  // A value that only repeats an argument name or a stop word is unbound
@@ -226,6 +261,10 @@ export function classifyBinding(value, text, explicit, canonical = false, contex
226
261
  return "explicit";
227
262
  if (!normalized || isGenericPlaceholder(normalized))
228
263
  return "placeholder";
264
+ // A clause lifted from the claim names no participant: it stays unbound
265
+ // like a placeholder so the agent binds a short noun or the subject key.
266
+ if (clauseBindingReason(normalized, context) !== null)
267
+ return "placeholder";
229
268
  if (textContainsValue(text, normalized))
230
269
  return "extracted";
231
270
  return "inferred";
@@ -53,6 +53,18 @@ export interface PredicateSuggestion {
53
53
  binding_provenance: BindingProvenance;
54
54
  /** Per-argument provenance retained for review and deterministic diagnostics. */
55
55
  binding_provenance_by_argument: Record<string, BindingProvenance>;
56
+ /**
57
+ * The subject_key the planned predicate fact is about when the requirement
58
+ * constrains subjects: the value of the argument named `subject`, or for a
59
+ * schema without one the requirement's subject. Null otherwise.
60
+ */
61
+ subject_key: string | null;
62
+ /**
63
+ * Whether the predicate is about a subject the requirement constrains, so
64
+ * kb_check pairs it with the subject fact. `unpaired` keeps the candidate
65
+ * incomplete; `not_required` when the requirement constrains no subject.
66
+ */
67
+ subject_pairing: "paired" | "unpaired" | "not_required";
56
68
  eligibility: "eligible" | "rejected";
57
69
  rejection_reasons: string[];
58
70
  applicability_score: number;
@@ -1 +1 @@
1
- {"version":3,"file":"predicate-types.d.ts","sourceRoot":"","sources":["../../../src/operations/modeling/predicate-types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"predicate-types.d.ts","sourceRoot":"","sources":["../../../src/operations/modeling/predicate-types.ts"],"names":[],"mappings":"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"}
@@ -49,7 +49,7 @@ export function hashId(prefix, parts) {
49
49
  * requirement without a subject fact the subject stays a placeholder, so the
50
50
  * agent binds it instead of getting a demo subject such as editor.annotation.
51
51
  */
52
- // implements REQ-mcp-suggest-predicates, REQ-model-predicates-requirement-subject
52
+ // implements REQ-mcp-suggest-predicates, REQ-model-predicates-requirement-subject-v2
53
53
  export function inferSubject(text, subjectHint, requirement) {
54
54
  const explicit = normalizeOptionalString(subjectHint);
55
55
  if (explicit)
@@ -1 +1 @@
1
- {"version":3,"file":"suggest-predicates.d.ts","sourceRoot":"","sources":["../../../src/operations/modeling/suggest-predicates.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,gBAAgB,EAChB,UAAU,EACX,MAAM,0CAA0C,CAAC;AAyBlD,OAAO,KAAK,EAGV,mBAAmB,EACnB,qBAAqB,EACrB,uBAAuB,EACxB,MAAM,sBAAsB,CAAC;AAG9B,YAAY,EACV,iBAAiB,EACjB,wBAAwB,EACxB,mBAAmB,EACnB,0BAA0B,EAC1B,qBAAqB,EACrB,uBAAuB,GACxB,MAAM,sBAAsB,CAAC;AA6H9B,wBAAgB,sCAAsC,CACpD,IAAI,EAAE,IAAI,CAAC,mBAAmB,EAAE,qBAAqB,GAAG,gBAAgB,CAAC,EACzE,KAAK,EAAE,IAAI,CAAC,mBAAmB,EAAE,qBAAqB,GAAG,gBAAgB,CAAC,GACzE,MAAM,CAIR;AAED,wBAAgB,2CAA2C,CACzD,IAAI,EAAE,IAAI,CACR,mBAAmB,EACnB,qBAAqB,GAAG,OAAO,GAAG,gBAAgB,CACnD,EACD,KAAK,EAAE,IAAI,CACT,mBAAmB,EACnB,qBAAqB,GAAG,OAAO,GAAG,gBAAgB,CACnD,GACA,MAAM,CAKR;AA+HD,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,UAAU,GAAG,IAAI,EACzB,IAAI,EAAE,qBAAqB,EAC3B,OAAO,CAAC,EAAE,gBAAgB,GACzB,OAAO,CAAC,uBAAuB,CAAC,CA8QlC;AA8GD,wBAAsB,wBAAwB,CAC5C,IAAI,EAAE,qBAAqB,EAC3B,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,uBAAuB,CAAC,CAElC"}
1
+ {"version":3,"file":"suggest-predicates.d.ts","sourceRoot":"","sources":["../../../src/operations/modeling/suggest-predicates.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,gBAAgB,EAChB,UAAU,EACX,MAAM,0CAA0C,CAAC;AAyBlD,OAAO,KAAK,EAGV,mBAAmB,EACnB,qBAAqB,EACrB,uBAAuB,EACxB,MAAM,sBAAsB,CAAC;AAG9B,YAAY,EACV,iBAAiB,EACjB,wBAAwB,EACxB,mBAAmB,EACnB,0BAA0B,EAC1B,qBAAqB,EACrB,uBAAuB,GACxB,MAAM,sBAAsB,CAAC;AA6H9B,wBAAgB,sCAAsC,CACpD,IAAI,EAAE,IAAI,CAAC,mBAAmB,EAAE,qBAAqB,GAAG,gBAAgB,CAAC,EACzE,KAAK,EAAE,IAAI,CAAC,mBAAmB,EAAE,qBAAqB,GAAG,gBAAgB,CAAC,GACzE,MAAM,CAIR;AAED,wBAAgB,2CAA2C,CACzD,IAAI,EAAE,IAAI,CACR,mBAAmB,EACnB,qBAAqB,GAAG,OAAO,GAAG,gBAAgB,CACnD,EACD,KAAK,EAAE,IAAI,CACT,mBAAmB,EACnB,qBAAqB,GAAG,OAAO,GAAG,gBAAgB,CACnD,GACA,MAAM,CAKR;AA+HD,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,UAAU,GAAG,IAAI,EACzB,IAAI,EAAE,qBAAqB,EAC3B,OAAO,CAAC,EAAE,gBAAgB,GACzB,OAAO,CAAC,uBAAuB,CAAC,CAwRlC;AAkID,wBAAsB,wBAAwB,CAC5C,IAAI,EAAE,qBAAqB,EAC3B,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,uBAAuB,CAAC,CAElC"}
@@ -200,7 +200,7 @@ function hasSubjectHint(value) {
200
200
  * contradiction checks by subject see the predicate and the subject fact as
201
201
  * one subject.
202
202
  */
203
- // implements REQ-model-predicates-requirement-subject
203
+ // implements REQ-model-predicates-requirement-subject-v2
204
204
  async function constrainedSubjectKeys(prolog, requirementId, warnings) {
205
205
  if (prolog === null || !requirementId?.trim())
206
206
  return [];
@@ -221,12 +221,12 @@ async function constrainedSubjectKeys(prolog, requirementId, warnings) {
221
221
  export async function handleKbSuggestPredicates(prolog, args, context) {
222
222
  const text = normalizeText(args.text);
223
223
  const warnings = [];
224
- const requirementSubjects = hasSubjectHint(args.subjectHint)
225
- ? []
226
- : await constrainedSubjectKeys(prolog, args.requirementId, warnings);
224
+ const requirementSubjects = await constrainedSubjectKeys(prolog, args.requirementId, warnings);
227
225
  // One constrained subject is the requirement's subject; with several the
228
- // agent picks one, so they are offered as binding examples instead.
229
- const requirementSubject = requirementSubjects.length === 1 ? requirementSubjects[0] : undefined;
226
+ // agent picks one (subjectHint), so they are offered as binding examples.
227
+ const requirementSubject = !hasSubjectHint(args.subjectHint) && requirementSubjects.length === 1
228
+ ? requirementSubjects[0]
229
+ : undefined;
230
230
  const subject = inferSubject(text, args.subjectHint, {
231
231
  requirementId: args.requirementId,
232
232
  subjectKey: requirementSubject,
@@ -289,6 +289,7 @@ export async function handleKbSuggestPredicates(prolog, args, context) {
289
289
  scoreComponents: ranked.components,
290
290
  explicitSubject: Boolean(args.subjectHint?.trim()),
291
291
  ...(requirementSubject ? { requirementSubject } : {}),
292
+ constrainedSubjects: requirementSubjects,
292
293
  });
293
294
  });
294
295
  const evaluatedCandidates = withMarginRejection(initialCandidates)
@@ -370,6 +371,9 @@ export async function handleKbSuggestPredicates(prolog, args, context) {
370
371
  const bindingHints = recommendedAction === "provide_argument_bindings" && recommendedCandidate
371
372
  ? buildBindingHints(recommendedCandidate, text, requirementSubjects)
372
373
  : [];
374
+ if (recommendedCandidate?.subject_pairing === "unpaired") {
375
+ warnings.push(unpairedSubjectWarning(recommendedCandidate, args, requirementSubjects));
376
+ }
373
377
  const recommendedPredicateSchema = !recommendedCandidate && !unavailableSchema
374
378
  ? buildPredicateSchemaDraft(text, subject)
375
379
  : null;
@@ -412,6 +416,20 @@ export async function handleKbSuggestPredicates(prolog, args, context) {
412
416
  applyPlan,
413
417
  };
414
418
  }
419
+ /**
420
+ * Why the recommended predicate is not offered for grounding: it is not about
421
+ * a subject the requirement constrains, so kb_check would keep reporting
422
+ * strict-req-fact-pairing after the link.
423
+ */
424
+ // implements REQ-model-predicates-requirement-subject-v2
425
+ function unpairedSubjectWarning(candidate, args, constrainedSubjects) {
426
+ const subjects = constrainedSubjects.join(", ");
427
+ const schemaNamesSubject = candidate.schema.argument_names.includes("subject");
428
+ const cause = schemaNamesSubject
429
+ ? `its subject argument is ${candidate.subject_key ?? "unbound"}, not a subject ${args.requirementId} constrains (${subjects})`
430
+ : `the ${candidate.predicate_name} schema does not name the requirement's subject (its arguments are ${candidate.schema.argument_names.join(", ")}) and its subject_key ${candidate.subject_key === null ? "cannot be chosen" : `${candidate.subject_key} is not`} one of the subjects ${args.requirementId} constrains (${subjects})`;
431
+ return `${candidate.predicate_name} is not offered for grounding because ${cause}, so kb_check would report strict-req-fact-pairing after the link. Pass subjectHint with one of ${subjects} and retry.`;
432
+ }
415
433
  /** Stored requirement fields a relationship-only update must restate. */
416
434
  const RESTATED_REQUIREMENT_FIELDS = [
417
435
  "title",
@@ -0,0 +1,10 @@
1
+ /**
2
+ * The package versions this build of the engine and its Prolog core carry,
3
+ * for example `kibi-cli@3.6.0,kibi-core@0.18.0`. The engine client and the
4
+ * daemon compare them, so a daemon left running by another install is
5
+ * replaced instead of serving this client.
6
+ */
7
+ export declare const KIBI_BUILT_PACKAGE_VERSIONS: string;
8
+ /** KIBI_PACKAGE_VERSIONS when set (an explicit override), else the built versions. */
9
+ export declare function kibiPackageVersions(): string;
10
+ //# sourceMappingURL=package-versions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-versions.d.ts","sourceRoot":"","sources":["../src/package-versions.ts"],"names":[],"mappings":"AAiFA;;;;;GAKG;AAEH,eAAO,MAAM,2BAA2B,QAAwD,CAAC;AAEjG,sFAAsF;AAEtF,wBAAgB,mBAAmB,IAAI,MAAM,CAK5C"}
@@ -0,0 +1,68 @@
1
+ /*
2
+ Kibi — repo-local, per-branch, queryable long-term memory for software projects
3
+ Copyright (C) 2026 Piotr Franczyk
4
+
5
+ This program is free software: you can redistribute it and/or modify
6
+ it under the terms of the GNU Affero General Public License as published by
7
+ the Free Software Foundation, either version 3 of the License, or
8
+ (at your option) any later version.
9
+
10
+ This program is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU Affero General Public License for more details.
14
+
15
+ You should have received a copy of the GNU Affero General Public License
16
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
17
+ */
18
+ import { readFileSync } from "node:fs";
19
+ import { createRequire } from "node:module";
20
+ import path from "node:path";
21
+ import { fileURLToPath } from "node:url";
22
+ const require = createRequire(import.meta.url);
23
+ const moduleDirectory = path.dirname(fileURLToPath(import.meta.url));
24
+ function manifestVersion(manifestPath, expectedName) {
25
+ try {
26
+ const manifest = JSON.parse(readFileSync(manifestPath, "utf8"));
27
+ return manifest.name === expectedName &&
28
+ typeof manifest.version === "string"
29
+ ? manifest.version
30
+ : undefined;
31
+ }
32
+ catch {
33
+ return undefined;
34
+ }
35
+ }
36
+ function cliVersion() {
37
+ if (typeof __KIBI_CLI_VERSION__ === "string")
38
+ return __KIBI_CLI_VERSION__;
39
+ // src/ and dist/ both sit directly under the package root.
40
+ return (manifestVersion(path.join(moduleDirectory, "..", "package.json"), "kibi-cli") ?? "unknown");
41
+ }
42
+ function coreVersion() {
43
+ try {
44
+ const resolved = manifestVersion(require.resolve("kibi-core/package.json"), "kibi-core");
45
+ if (resolved)
46
+ return resolved;
47
+ }
48
+ catch {
49
+ // Fall back to the monorepo layout below.
50
+ }
51
+ return (manifestVersion(path.join(moduleDirectory, "..", "..", "core", "package.json"), "kibi-core") ?? "unknown");
52
+ }
53
+ /**
54
+ * The package versions this build of the engine and its Prolog core carry,
55
+ * for example `kibi-cli@3.6.0,kibi-core@0.18.0`. The engine client and the
56
+ * daemon compare them, so a daemon left running by another install is
57
+ * replaced instead of serving this client.
58
+ */
59
+ // implements REQ-engine-daemon-package-versions
60
+ export const KIBI_BUILT_PACKAGE_VERSIONS = `kibi-cli@${cliVersion()},kibi-core@${coreVersion()}`;
61
+ /** KIBI_PACKAGE_VERSIONS when set (an explicit override), else the built versions. */
62
+ // implements REQ-engine-daemon-package-versions
63
+ export function kibiPackageVersions() {
64
+ const override = process.env.KIBI_PACKAGE_VERSIONS;
65
+ return override !== undefined && override.length > 0
66
+ ? override
67
+ : KIBI_BUILT_PACKAGE_VERSIONS;
68
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"prolog.d.ts","sourceRoot":"","sources":["../src/prolog.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"prolog.d.ts","sourceRoot":"","sources":["../src/prolog.ts"],"names":[],"mappings":"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"}
package/dist/prolog.js CHANGED
@@ -22,6 +22,7 @@ import path from "node:path";
22
22
  import { performance } from "node:perf_hooks";
23
23
  import { fileURLToPath } from "node:url";
24
24
  import { getKbPlPathOverride, isPrologDebugEnabled } from "./env.js";
25
+ import { kibiPackageVersions } from "./package-versions.js";
25
26
  import { writePerformanceTraceEvent } from "./performance-trace.js";
26
27
  import { extractPrologErrorRecord, } from "./prolog/error-terms.js";
27
28
  import { resolveSwipl, swiplChildEnv, } from "./prolog/swipl-resolver.js";
@@ -30,22 +31,6 @@ const DEFAULT_PROLOG_OUTPUT_MAX_BUFFER_BYTES = 8 * 1024 * 1024;
30
31
  const PROLOG_OUTPUT_OVERFLOW_ERROR = "Query exceeded bounded Prolog output capacity (ENOBUFS); narrow the operation or reduce stored entity size";
31
32
  const INTERACTIVE_QUERY_FRAME_END = "__KIBI_QUERY_FRAME_END__";
32
33
  const require = createRequire(import.meta.url);
33
- function packageVersion(packagePath) {
34
- try {
35
- const packageJson = require(packagePath);
36
- return typeof packageJson.version === "string"
37
- ? packageJson.version
38
- : "unknown";
39
- }
40
- catch {
41
- return "unknown";
42
- }
43
- }
44
- const KIBI_PACKAGE_VERSIONS = [
45
- `kibi-cli@${packageVersion(path.join(importMetaDir, "..", "package.json"))}`,
46
- `kibi-core@${packageVersion(path.join(importMetaDir, "..", "..", "core", "package.json"))}`,
47
- `kibi-mcp@${packageVersion(path.join(importMetaDir, "..", "..", "mcp", "package.json"))}`,
48
- ].join(",");
49
34
  export function resolveKbPlPath() {
50
35
  // implements REQ-009
51
36
  const overrideKbPath = getKbPlPathOverride();
@@ -207,7 +192,7 @@ export class PrologProcess {
207
192
  ...launch.env,
208
193
  KIBI_RUNTIME_NAME: process.versions.bun !== undefined ? "bun" : "node",
209
194
  KIBI_RUNTIME_VERSION: process.versions.bun ?? process.versions.node ?? "unknown",
210
- KIBI_PACKAGE_VERSIONS: process.env.KIBI_PACKAGE_VERSIONS ?? KIBI_PACKAGE_VERSIONS,
195
+ KIBI_PACKAGE_VERSIONS: kibiPackageVersions(),
211
196
  },
212
197
  });
213
198
  this.clearQueryBuffers();
@@ -363,7 +348,7 @@ export class PrologProcess {
363
348
  const runtime = this.errorBuffer
364
349
  .split("\n")
365
350
  .find((line) => line.includes("__KIBI_RUNTIME__"));
366
- console.error(`[prolog debug] runtime=${runtime ?? "unknown"} packages=${process.env.KIBI_PACKAGE_VERSIONS ?? KIBI_PACKAGE_VERSIONS}`);
351
+ console.error(`[prolog debug] runtime=${runtime ?? "unknown"} packages=${kibiPackageVersions()}`);
367
352
  }
368
353
  settle();
369
354
  this.terminationReason = `query timeout: ${goalLabel}`;
@@ -604,7 +589,7 @@ export class PrologProcess {
604
589
  ].join(", ");
605
590
  const runtimeName = process.versions.bun !== undefined ? "bun" : "node";
606
591
  const runtimeVersion = process.versions.bun ?? process.versions.node ?? "unknown";
607
- const packageVersions = process.env.KIBI_PACKAGE_VERSIONS ?? KIBI_PACKAGE_VERSIONS;
592
+ const packageVersions = kibiPackageVersions();
608
593
  let child;
609
594
  try {
610
595
  const launch = this.launchTarget();
@@ -2,7 +2,7 @@
2
2
  id: kibi-usage
3
3
  name: Kibi Usage
4
4
  description: Use Kibi's source-first, exact-Git, migration-aware, proof-aware operations safely across MCP or the trusted local CLI, including partial completion repair.
5
- version: 2.8.0
5
+ version: 2.9.0
6
6
  kibiCompatibility: ">=1.0.0"
7
7
  tags:
8
8
  - kibi
@@ -260,7 +260,11 @@ constants) or `examples`, and why the current value was refused. With a
260
260
  `requirementId` whose requirement `constrains` one subject fact, the `subject`
261
261
  argument is already bound to that fact's `subject_key` (provenance
262
262
  `requirement`); keep it, so the predicate and the subject fact name one
263
- subject. Bind them
263
+ subject. A schema without a `subject` argument (`permission_rule`) records
264
+ that key as the planned fact's `subject_key` instead; when the requirement
265
+ constrains several subjects, an unbound `subject_key` asks you to pass
266
+ `subjectHint` with one of them. A participant (`actor`, `resource`, entity)
267
+ is a short noun, never a clause of the claim. Bind them
264
268
  from the claim's own words and call again with the same `text` and
265
269
  `requirementId`, plus `schemaId` and `argumentBindings` keyed by
266
270
  `argument_names` (reuse `argument_constants` values when the schema has them).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kibi-cli",
3
- "version": "2.12.0",
3
+ "version": "2.13.0",
4
4
  "type": "module",
5
5
  "description": "Kibi CLI for knowledge base management",
6
6
  "engines": {
@@ -235,7 +235,7 @@
235
235
  "fast-glob": "^3.2.12",
236
236
  "gray-matter": "^4.0.3",
237
237
  "js-yaml": "^4.1.0",
238
- "kibi-core": "^0.17.1",
238
+ "kibi-core": "^0.17.2",
239
239
  "kibi-plugin-builtin": "^0.4.2",
240
240
  "kibi-plugin-sdk": "^0.4.1",
241
241
  "kibi-swipl": "^1.0.1",
@@ -2,7 +2,7 @@
2
2
  id: kibi-usage
3
3
  name: Kibi Usage
4
4
  description: Use Kibi's source-first, exact-Git, migration-aware, proof-aware operations safely across MCP or the trusted local CLI, including partial completion repair.
5
- version: 2.8.0
5
+ version: 2.9.0
6
6
  kibiCompatibility: ">=1.0.0"
7
7
  tags:
8
8
  - kibi
@@ -260,7 +260,11 @@ constants) or `examples`, and why the current value was refused. With a
260
260
  `requirementId` whose requirement `constrains` one subject fact, the `subject`
261
261
  argument is already bound to that fact's `subject_key` (provenance
262
262
  `requirement`); keep it, so the predicate and the subject fact name one
263
- subject. Bind them
263
+ subject. A schema without a `subject` argument (`permission_rule`) records
264
+ that key as the planned fact's `subject_key` instead; when the requirement
265
+ constrains several subjects, an unbound `subject_key` asks you to pass
266
+ `subjectHint` with one of them. A participant (`actor`, `resource`, entity)
267
+ is a short noun, never a clause of the claim. Bind them
264
268
  from the claim's own words and call again with the same `text` and
265
269
  `requirementId`, plus `schemaId` and `argumentBindings` keyed by
266
270
  `argument_names` (reuse `argument_constants` values when the schema has them).