kibi-cli 0.17.0 → 0.18.1

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 (181) hide show
  1. package/dist/cli-json-command.d.ts.map +1 -1
  2. package/dist/cli-json-command.js +87 -11
  3. package/dist/cli-register-maintenance.d.ts.map +1 -1
  4. package/dist/cli-register-maintenance.js +8 -0
  5. package/dist/cli-register-reporting.d.ts.map +1 -1
  6. package/dist/cli-register-reporting.js +5 -0
  7. package/dist/cli.d.ts.map +1 -1
  8. package/dist/cli.js +2 -1
  9. package/dist/commands/aggregated-checks.d.ts.map +1 -1
  10. package/dist/commands/aggregated-checks.js +1 -0
  11. package/dist/commands/coverage.d.ts +5 -0
  12. package/dist/commands/coverage.d.ts.map +1 -1
  13. package/dist/commands/coverage.js +5 -0
  14. package/dist/commands/discovery-table.d.ts.map +1 -1
  15. package/dist/commands/discovery-table.js +96 -5
  16. package/dist/commands/sync/cache.d.ts +2 -0
  17. package/dist/commands/sync/cache.d.ts.map +1 -1
  18. package/dist/commands/sync/cache.js +8 -0
  19. package/dist/commands/sync/persistence.d.ts.map +1 -1
  20. package/dist/commands/sync/persistence.js +58 -1
  21. package/dist/commands/sync.d.ts.map +1 -1
  22. package/dist/commands/sync.js +72 -15
  23. package/dist/commands/usage-metrics.d.ts +66 -2
  24. package/dist/commands/usage-metrics.d.ts.map +1 -1
  25. package/dist/commands/usage-metrics.js +34 -24
  26. package/dist/commands/usage-remediation.d.ts +9 -0
  27. package/dist/commands/usage-remediation.d.ts.map +1 -0
  28. package/dist/commands/usage-remediation.js +52 -0
  29. package/dist/extractors/markdown.d.ts +8 -0
  30. package/dist/extractors/markdown.d.ts.map +1 -1
  31. package/dist/extractors/markdown.js +69 -2
  32. package/dist/operations/modeling/logic-modeling.d.ts.map +1 -1
  33. package/dist/operations/modeling/logic-modeling.js +14 -5
  34. package/dist/operations/modeling/model-requirement.d.ts.map +1 -1
  35. package/dist/operations/modeling/model-requirement.js +27 -2
  36. package/dist/operations/modeling/predicate-applyplan.d.ts +1 -1
  37. package/dist/operations/modeling/predicate-applyplan.d.ts.map +1 -1
  38. package/dist/operations/modeling/predicate-applyplan.js +18 -6
  39. package/dist/operations/modeling/predicate-inference.d.ts.map +1 -1
  40. package/dist/operations/modeling/predicate-inference.js +5 -17
  41. package/dist/operations/modeling/predicate-loader.js +1 -1
  42. package/dist/operations/modeling/predicate-types.d.ts +9 -1
  43. package/dist/operations/modeling/predicate-types.d.ts.map +1 -1
  44. package/dist/operations/modeling/suggest-predicates.d.ts.map +1 -1
  45. package/dist/operations/modeling/suggest-predicates.js +35 -11
  46. package/dist/operations/mutation/audit.js +1 -1
  47. package/dist/operations/mutation/contradictions.d.ts +1 -1
  48. package/dist/operations/mutation/contradictions.d.ts.map +1 -1
  49. package/dist/operations/mutation/contradictions.js +23 -18
  50. package/dist/operations/mutation/serialization.d.ts.map +1 -1
  51. package/dist/operations/mutation/serialization.js +6 -3
  52. package/dist/operations/mutation/upsert.d.ts +3 -1
  53. package/dist/operations/mutation/upsert.d.ts.map +1 -1
  54. package/dist/operations/mutation/upsert.js +51 -12
  55. package/dist/operations/mutation/validate-upsert.d.ts.map +1 -1
  56. package/dist/operations/mutation/validate-upsert.js +18 -2
  57. package/dist/operations/mutation/validation.d.ts.map +1 -1
  58. package/dist/operations/mutation/validation.js +8 -0
  59. package/dist/operations/semantic-advisor/analysis-receipt.d.ts.map +1 -1
  60. package/dist/operations/semantic-advisor/analysis-receipt.js +7 -1
  61. package/dist/operations/semantic-advisor/analyze-prose.d.ts.map +1 -1
  62. package/dist/operations/semantic-advisor/analyze-prose.js +76 -61
  63. package/dist/operations/semantic-advisor/clauses.d.ts +1 -0
  64. package/dist/operations/semantic-advisor/clauses.d.ts.map +1 -1
  65. package/dist/operations/semantic-advisor/clauses.js +7 -7
  66. package/dist/operations/semantic-advisor/ingestion-boundary.d.ts +18 -0
  67. package/dist/operations/semantic-advisor/ingestion-boundary.d.ts.map +1 -0
  68. package/dist/operations/semantic-advisor/ingestion-boundary.js +167 -0
  69. package/dist/operations/semantic-advisor/shared.d.ts +8 -0
  70. package/dist/operations/semantic-advisor/shared.d.ts.map +1 -1
  71. package/dist/operations/semantic-advisor/shared.js +37 -3
  72. package/dist/operations/semantic-advisor/types.d.ts +5 -0
  73. package/dist/operations/semantic-advisor/types.d.ts.map +1 -1
  74. package/dist/prolog/codec.d.ts.map +1 -1
  75. package/dist/prolog/codec.js +9 -2
  76. package/dist/prolog.d.ts +6 -0
  77. package/dist/prolog.d.ts.map +1 -1
  78. package/dist/prolog.js +240 -61
  79. package/dist/public/diagnostic-usage.d.ts +17 -0
  80. package/dist/public/diagnostic-usage.d.ts.map +1 -0
  81. package/dist/public/diagnostic-usage.js +152 -0
  82. package/dist/public/distribution-parity.d.ts +90 -0
  83. package/dist/public/distribution-parity.d.ts.map +1 -0
  84. package/dist/public/distribution-parity.js +367 -0
  85. package/dist/public/impact/full-kb-quality.d.ts +2 -0
  86. package/dist/public/impact/full-kb-quality.d.ts.map +1 -1
  87. package/dist/public/impact/full-kb-quality.js +53 -1
  88. package/dist/public/impact-diagnostics.d.ts +2 -0
  89. package/dist/public/impact-diagnostics.d.ts.map +1 -1
  90. package/dist/public/impact-diagnostics.js +1 -0
  91. package/dist/public/operations/catalog.d.ts +151 -6
  92. package/dist/public/operations/catalog.d.ts.map +1 -1
  93. package/dist/public/operations/check-executor.d.ts.map +1 -1
  94. package/dist/public/operations/check-executor.js +4 -0
  95. package/dist/public/operations/discovery-executors.d.ts +6 -0
  96. package/dist/public/operations/discovery-executors.d.ts.map +1 -1
  97. package/dist/public/operations/discovery-executors.js +18 -2
  98. package/dist/public/operations/index.d.ts +4 -0
  99. package/dist/public/operations/index.d.ts.map +1 -1
  100. package/dist/public/operations/index.js +4 -0
  101. package/dist/public/operations/legacy-migration-plan.d.ts +113 -0
  102. package/dist/public/operations/legacy-migration-plan.d.ts.map +1 -0
  103. package/dist/public/operations/legacy-migration-plan.js +409 -0
  104. package/dist/public/operations/node-ports.d.ts.map +1 -1
  105. package/dist/public/operations/node-ports.js +90 -0
  106. package/dist/public/operations/repair-plan.d.ts +184 -0
  107. package/dist/public/operations/repair-plan.d.ts.map +1 -0
  108. package/dist/public/operations/repair-plan.js +397 -0
  109. package/dist/public/operations/runtime-types.d.ts +7 -0
  110. package/dist/public/operations/runtime-types.d.ts.map +1 -1
  111. package/dist/public/operations/specs/check.d.ts +2 -2
  112. package/dist/public/operations/specs/check.js +2 -2
  113. package/dist/public/operations/specs/discovery.d.ts +1 -1
  114. package/dist/public/operations/specs/discovery.js +1 -1
  115. package/dist/public/operations/specs/modeling.d.ts +19 -1
  116. package/dist/public/operations/specs/modeling.d.ts.map +1 -1
  117. package/dist/public/operations/specs/modeling.js +16 -1
  118. package/dist/public/operations/specs/mutation-schemas.d.ts +96 -1
  119. package/dist/public/operations/specs/mutation-schemas.d.ts.map +1 -1
  120. package/dist/public/operations/specs/mutation-schemas.js +40 -1
  121. package/dist/public/operations/specs/reporting.d.ts +42 -1
  122. package/dist/public/operations/specs/reporting.d.ts.map +1 -1
  123. package/dist/public/operations/specs/reporting.js +70 -6
  124. package/dist/public/operations/specs/semantic.js +1 -1
  125. package/dist/public/operations/specs/upsert.d.ts +96 -1
  126. package/dist/public/operations/specs/upsert.d.ts.map +1 -1
  127. package/dist/public/operations/workspace-snapshot.d.ts +10 -0
  128. package/dist/public/operations/workspace-snapshot.d.ts.map +1 -0
  129. package/dist/public/operations/workspace-snapshot.js +20 -0
  130. package/dist/public/schemas/entity.d.ts.map +1 -1
  131. package/dist/public/schemas/entity.js +43 -1
  132. package/dist/public/skills/kibi-traceability/SKILL.md +7 -1
  133. package/dist/public/skills/kibi-usage/SKILL.md +10 -4
  134. package/dist/public/skills/kibi-usage/resources/fact-lanes.md +1 -1
  135. package/dist/public/skills/kibi-usage/resources/logic-ir.md +1 -1
  136. package/dist/public/skills/kibi-usage/resources/workflows.md +19 -2
  137. package/dist/public/telemetry-acceptance.d.ts +89 -0
  138. package/dist/public/telemetry-acceptance.d.ts.map +1 -0
  139. package/dist/public/telemetry-acceptance.js +597 -0
  140. package/dist/public/telemetry-remediation.d.ts +33 -0
  141. package/dist/public/telemetry-remediation.d.ts.map +1 -0
  142. package/dist/public/telemetry-remediation.js +257 -0
  143. package/dist/public/verification-receipt.d.ts +75 -0
  144. package/dist/public/verification-receipt.d.ts.map +1 -0
  145. package/dist/public/verification-receipt.js +129 -0
  146. package/dist/schemas/entity.schema.json +96 -2
  147. package/dist/traceability/temp-kb.d.ts.map +1 -1
  148. package/dist/traceability/temp-kb.js +36 -3
  149. package/dist/types/entities.d.ts +1 -0
  150. package/dist/types/entities.d.ts.map +1 -1
  151. package/dist/utils/rule-registry.d.ts +2 -0
  152. package/dist/utils/rule-registry.d.ts.map +1 -1
  153. package/package.json +30 -2
  154. package/src/public/diagnostic-usage.ts +206 -0
  155. package/src/public/distribution-parity.ts +580 -0
  156. package/src/public/impact/full-kb-quality.ts +74 -1
  157. package/src/public/impact-diagnostics.ts +16 -0
  158. package/src/public/operations/check-executor.ts +4 -0
  159. package/src/public/operations/discovery-executors.ts +24 -2
  160. package/src/public/operations/index.ts +4 -0
  161. package/src/public/operations/legacy-migration-plan.ts +688 -0
  162. package/src/public/operations/node-ports.ts +109 -0
  163. package/src/public/operations/repair-plan.ts +562 -0
  164. package/src/public/operations/runtime-types.ts +8 -0
  165. package/src/public/operations/specs/check.ts +2 -2
  166. package/src/public/operations/specs/discovery.ts +1 -1
  167. package/src/public/operations/specs/modeling.ts +19 -1
  168. package/src/public/operations/specs/mutation-schemas.ts +47 -1
  169. package/src/public/operations/specs/reporting.ts +91 -6
  170. package/src/public/operations/specs/semantic.ts +1 -1
  171. package/src/public/operations/workspace-snapshot.ts +28 -0
  172. package/src/public/schemas/entity.ts +44 -1
  173. package/src/public/skills/kibi-traceability/SKILL.md +7 -1
  174. package/src/public/skills/kibi-usage/SKILL.md +10 -4
  175. package/src/public/skills/kibi-usage/resources/fact-lanes.md +1 -1
  176. package/src/public/skills/kibi-usage/resources/logic-ir.md +1 -1
  177. package/src/public/skills/kibi-usage/resources/workflows.md +19 -2
  178. package/src/public/telemetry-acceptance.ts +859 -0
  179. package/src/public/telemetry-remediation.ts +462 -0
  180. package/src/public/verification-receipt.ts +170 -0
  181. package/src/schemas/entity.schema.json +96 -2
@@ -1,4 +1,4 @@
1
- import { payloadHash, propertiesOf } from "./shared.js";
1
+ import { SEMANTIC_INVENTORY_VERSION, payloadHash, propertiesOf, semanticSourceHash, semanticSourceOf, } from "./shared.js";
2
2
  function chooseLane(signals) {
3
3
  if (signals.some(({ kind }) => kind === "numeric_cardinality" || kind === "numeric_threshold"))
4
4
  return "strict_property";
@@ -25,6 +25,7 @@ function summary(readiness, lane) {
25
25
  }
26
26
  // implements REQ-mcp-semantic-advisor-preflight
27
27
  export function buildAdvisorResult(payload, signals, modeled, suggestions, clauses, propositions, interpretations, shadowAnalysis) {
28
+ const semanticSource = semanticSourceOf(payload);
28
29
  const suggestionLane = suggestions.some(({ kind }) => kind === "strict_property")
29
30
  ? "strict_property"
30
31
  : suggestions.some(({ kind }) => kind === "rule")
@@ -72,6 +73,11 @@ export function buildAdvisorResult(payload, signals, modeled, suggestions, claus
72
73
  const receipt = {
73
74
  version: "semantic-advisor-v2",
74
75
  payload_hash: payloadHash(payload),
76
+ inventory_contract: {
77
+ version: SEMANTIC_INVENTORY_VERSION,
78
+ source_field: semanticSource.field,
79
+ source_hash: semanticSourceHash(semanticSource.text),
80
+ },
75
81
  logic_readiness: readiness,
76
82
  candidate_lane: candidateLane,
77
83
  signals,
@@ -1 +1 @@
1
- {"version":3,"file":"analyze-prose.d.ts","sourceRoot":"","sources":["../../../src/operations/semantic-advisor/analyze-prose.ts"],"names":[],"mappings":"AA8BA,OAAO,KAAK,EACV,6BAA6B,EAC7B,oBAAoB,EAWrB,MAAM,YAAY,CAAC;AAEpB,eAAO,MAAM,wBAAwB,wBAAwB,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AA6zBhD,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,oBAAoB,GAC1B,6BAA6B,CAuD/B"}
1
+ {"version":3,"file":"analyze-prose.d.ts","sourceRoot":"","sources":["../../../src/operations/semantic-advisor/analyze-prose.ts"],"names":[],"mappings":"AAkCA,OAAO,KAAK,EACV,6BAA6B,EAC7B,oBAAoB,EAWrB,MAAM,YAAY,CAAC;AAEpB,eAAO,MAAM,wBAAwB,wBAAwB,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AA01BhD,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,oBAAoB,GAC1B,6BAA6B,CA+D/B"}
@@ -8,7 +8,7 @@ import { CORE_PREDICATE_RULES } from "./predicate-rules-core.js";
8
8
  import { POLICY_PREDICATE_RULES } from "./predicate-rules-policy.js";
9
9
  import { PRODUCT_TAIL_PREDICATE_RULES } from "./predicate-rules-product-tail.js";
10
10
  import { PRODUCT_PREDICATE_RULES } from "./predicate-rules-product.js";
11
- import { isRecord, payloadHash, propertiesOf, relationship, sourceOf, statementOf, stringValue, } from "./shared.js";
11
+ import { isRecord, payloadHash, propertiesOf, relationship, semanticClausesOf, semanticSourceHash, semanticSourceOf, sourceOf, statementOf, stringValue, } from "./shared.js";
12
12
  import { detectStrictSuggestion } from "./strict-rules.js";
13
13
  export const SEMANTIC_ADVISOR_VERSION = "semantic-advisor-v2";
14
14
  export { semanticClaimKey } from "./clauses.js";
@@ -52,7 +52,12 @@ const SIGNAL_PATTERNS = [
52
52
  ];
53
53
  function proseOf(payload) {
54
54
  const properties = propertiesOf(payload);
55
- return [properties.title, properties.text_ref, properties.description]
55
+ return [
56
+ properties.title,
57
+ properties.semantic_text,
58
+ properties.text_ref,
59
+ properties.description,
60
+ ]
56
61
  .map(stringValue)
57
62
  .filter(Boolean)
58
63
  .join("\n");
@@ -69,8 +74,8 @@ function logicalGroundingSlots(payload) {
69
74
  return relationships.filter((relationship) => isRecord(relationship) &&
70
75
  ["requires_property", "requires_predicate", "requires_rule"].includes(stringValue(relationship.type))).length;
71
76
  }
72
- function isModeled(payload, expectedClaimCount) {
73
- if (expectedClaimCount === 0)
77
+ function isModeled(payload, expectedClaimKeys) {
78
+ if (expectedClaimKeys.length === 0)
74
79
  return false;
75
80
  const relationships = Array.isArray(payload.relationships)
76
81
  ? payload.relationships
@@ -79,7 +84,16 @@ function isModeled(payload, expectedClaimCount) {
79
84
  .filter(isRecord)
80
85
  .map((relationship) => stringValue(relationship.type))
81
86
  .filter(Boolean));
82
- return (logicalGroundingSlots(payload) >= expectedClaimCount &&
87
+ const rawInventory = propertiesOf(payload).semantic_inventory;
88
+ const inventory = Array.isArray(rawInventory)
89
+ ? rawInventory.filter(isRecord)
90
+ : [];
91
+ const modeledClaimKeys = inventory
92
+ .filter(({ status }) => status === "modeled")
93
+ .map(({ claim_key }) => stringValue(claim_key));
94
+ return (logicalGroundingSlots(payload) === expectedClaimKeys.length &&
95
+ modeledClaimKeys.length === expectedClaimKeys.length &&
96
+ expectedClaimKeys.every((claimKey) => modeledClaimKeys.includes(claimKey)) &&
83
97
  ((types.has("constrains") && types.has("requires_property")) ||
84
98
  types.has("requires_predicate") ||
85
99
  types.has("requires_rule")));
@@ -231,13 +245,8 @@ function modelingSuggestions(payload, modeled, clauses, interpretations) {
231
245
  const suggestions = [];
232
246
  const seen = new Set();
233
247
  const expectedClaimKeys = clauses
234
- .filter((clause) => clause.normative)
248
+ .filter((clause) => !["rationale", "example", "subjective"].includes(propositionRole(clause.text, clause.normative)))
235
249
  .map((clause) => clause.claim_key);
236
- const rawDeclaredClaimKeys = propertiesOf(payload).logic_claims;
237
- const declaredClaimKeys = Array.isArray(rawDeclaredClaimKeys)
238
- ? rawDeclaredClaimKeys.filter((value) => typeof value === "string")
239
- : [];
240
- const mergedClaimKeys = Array.from(new Set([...declaredClaimKeys, ...expectedClaimKeys]));
241
250
  for (const clause of clauses) {
242
251
  const candidate = clause.text;
243
252
  const rawSuggestion = predicateSuggestion(payload, candidate) ??
@@ -245,9 +254,9 @@ function modelingSuggestions(payload, modeled, clauses, interpretations) {
245
254
  ambiguitySuggestion(payload, candidate) ??
246
255
  detectStrictSuggestion(payload, candidate);
247
256
  const suggestion = rawSuggestion
248
- ? withClauseProvenance(rawSuggestion, clause, mergedClaimKeys, statementOf(payload))
257
+ ? withClauseProvenance(rawSuggestion, clause, clauses, expectedClaimKeys, statementOf(payload), semanticSourceOf(payload).field)
249
258
  : clause.normative
250
- ? unmatchedClauseSuggestion(payload, clause, mergedClaimKeys)
259
+ ? unmatchedClauseSuggestion(payload, clause, clauses, expectedClaimKeys)
251
260
  : null;
252
261
  if (!suggestion)
253
262
  continue;
@@ -264,7 +273,7 @@ function modelingSuggestions(payload, modeled, clauses, interpretations) {
264
273
  const suggestion = ruleSuggestion(payload, interpretation);
265
274
  if (!suggestion)
266
275
  continue;
267
- const withProvenance = withClauseProvenance(suggestion, clause, mergedClaimKeys, statementOf(payload));
276
+ const withProvenance = withClauseProvenance(suggestion, clause, clauses, expectedClaimKeys, statementOf(payload), semanticSourceOf(payload).field);
268
277
  const key = withProvenance.kind === "rule"
269
278
  ? `${withProvenance.claim_key}:rule:${withProvenance.semantic_key}`
270
279
  : `${withProvenance.claim_key}:${withProvenance.kind}`;
@@ -275,9 +284,45 @@ function modelingSuggestions(payload, modeled, clauses, interpretations) {
275
284
  }
276
285
  return suggestions;
277
286
  }
278
- function withClauseProvenance(suggestion, clause, expectedClaimKeys, statement) {
287
+ function withClauseProvenance(suggestion, clause, clauses, expectedClaimKeys, statement, sourceField) {
279
288
  const clauseOffset = statement.indexOf(clause.text);
280
289
  const clauseSpan = utf8Span(statement || clause.text, clauseOffset >= 0 ? clauseOffset : 0, clauseOffset >= 0 ? clauseOffset + clause.text.length : clause.text.length);
290
+ const status = suggestion.kind === "ambiguity_observation"
291
+ ? "ambiguous"
292
+ : suggestion.kind === "ontology_gap"
293
+ ? "ontology_gap"
294
+ : "modeled";
295
+ let inventoryCursor = 0;
296
+ const semanticInventory = clauses.map((entry) => {
297
+ const located = propositionSpan(statement, entry, inventoryCursor);
298
+ inventoryCursor = located.next;
299
+ const role = propositionRole(entry.text, entry.normative);
300
+ const context = ["rationale", "example", "subjective"].includes(role);
301
+ const entryStatus = entry.index === clause.index
302
+ ? status
303
+ : context
304
+ ? "nonlogical"
305
+ : "missing";
306
+ return {
307
+ claim_key: entry.claim_key,
308
+ claim_text: entry.text,
309
+ role,
310
+ status: entryStatus,
311
+ span: located.span,
312
+ reason: entry.index === clause.index
313
+ ? status === "modeled"
314
+ ? "Draft apply plan contains a typed grounding for this proposition."
315
+ : suggestion.rationale
316
+ : context
317
+ ? "Prose is retained for human context and is not a verifiable domain proposition."
318
+ : "No typed grounding is included for this proposition in the current draft plan.",
319
+ };
320
+ });
321
+ const inventoryContract = {
322
+ version: "kibi.semantic-inventory.v1",
323
+ source_field: sourceField,
324
+ source_hash: semanticSourceHash(statement),
325
+ };
281
326
  const applyPlan = suggestion.applyPlan.map((step) => {
282
327
  if (!isRecord(step))
283
328
  return step;
@@ -288,32 +333,16 @@ function withClauseProvenance(suggestion, clause, expectedClaimKeys, statement)
288
333
  const existing = Array.isArray(properties.logic_claims)
289
334
  ? properties.logic_claims.filter((value) => typeof value === "string")
290
335
  : [];
291
- const inventory = Array.isArray(properties.semantic_inventory)
292
- ? properties.semantic_inventory.filter(isRecord)
293
- : [];
294
- const status = suggestion.kind === "ambiguity_observation"
295
- ? "ambiguous"
296
- : suggestion.kind === "ontology_gap"
297
- ? "ontology_gap"
298
- : "modeled";
299
336
  return {
300
337
  ...step,
301
338
  properties: {
302
339
  ...properties,
303
340
  logic_claims: Array.from(new Set([...existing, ...expectedClaimKeys])),
304
- semantic_inventory: [
305
- ...inventory.filter((entry) => entry.claim_key !== clause.claim_key),
306
- {
307
- claim_key: clause.claim_key,
308
- claim_text: clause.text,
309
- role: clause.normative ? "normative" : "descriptive",
310
- status,
311
- span: clauseSpan,
312
- reason: status === "modeled"
313
- ? "Draft apply plan contains a typed grounding for this proposition."
314
- : suggestion.rationale,
315
- },
316
- ],
341
+ semantic_clauses: clauses.map(({ text }) => text),
342
+ semantic_inventory_version: inventoryContract.version,
343
+ semantic_source_field: inventoryContract.source_field,
344
+ semantic_source_hash: inventoryContract.source_hash,
345
+ semantic_inventory: semanticInventory,
317
346
  },
318
347
  };
319
348
  }
@@ -342,16 +371,9 @@ function withClauseProvenance(suggestion, clause, expectedClaimKeys, statement)
342
371
  claimKey: clause.claim_key,
343
372
  claimText: clause.text,
344
373
  logicClaims: expectedClaimKeys,
345
- semanticInventory: [
346
- {
347
- claim_key: clause.claim_key,
348
- claim_text: clause.text,
349
- role: clause.normative ? "normative" : "descriptive",
350
- status: "modeled",
351
- span: clauseSpan,
352
- reason: "The returned typed fact grounds this proposition.",
353
- },
354
- ],
374
+ semanticClauses: clauses.map(({ text }) => text),
375
+ semanticInventory,
376
+ inventoryContract,
355
377
  instructions: "Create the predicate fact, merge the returned logicClaims into the requirement logic_claims manifest, then add requires_predicate without overwriting other requirement metadata.",
356
378
  },
357
379
  }
@@ -363,23 +385,16 @@ function withClauseProvenance(suggestion, clause, expectedClaimKeys, statement)
363
385
  claimKey: clause.claim_key,
364
386
  claimText: clause.text,
365
387
  logicClaims: expectedClaimKeys,
366
- semanticInventory: [
367
- {
368
- claim_key: clause.claim_key,
369
- claim_text: clause.text,
370
- role: clause.normative ? "normative" : "descriptive",
371
- status: "modeled",
372
- span: clauseSpan,
373
- reason: "The returned typed rule grounds this proposition.",
374
- },
375
- ],
388
+ semanticClauses: clauses.map(({ text }) => text),
389
+ semanticInventory,
390
+ inventoryContract,
376
391
  instructions: "Create the rule_schema and rule facts, merge the returned logicClaims into the requirement logic_claims manifest, then add requires_rule without overwriting other requirement metadata.",
377
392
  },
378
393
  }
379
394
  : {}),
380
395
  };
381
396
  }
382
- function unmatchedClauseSuggestion(payload, clause, expectedClaimKeys) {
397
+ function unmatchedClauseSuggestion(payload, clause, clauses, expectedClaimKeys) {
383
398
  return withClauseProvenance({
384
399
  kind: "ontology_gap",
385
400
  claim_key: clause.claim_key,
@@ -394,7 +409,7 @@ function unmatchedClauseSuggestion(payload, clause, expectedClaimKeys) {
394
409
  "review:ontology-gap",
395
410
  "needs_schema_extension",
396
411
  ]),
397
- }, clause, expectedClaimKeys, statementOf(payload));
412
+ }, clause, clauses, expectedClaimKeys, statementOf(payload), semanticSourceOf(payload).field);
398
413
  }
399
414
  function propositionRole(statement, normative) {
400
415
  if (/\b(?:for example|e\.g\.|such as|illustrative)\b/i.test(statement))
@@ -668,17 +683,17 @@ export function analyzeSemanticAdvisorInput(input) {
668
683
  const statement = statementOf(payload) || proseOf(payload);
669
684
  const signals = requirement ? detectSignals(proseOf(payload)) : [];
670
685
  const clauses = statement
671
- ? extractSemanticClauses(statement, input.clauses)
686
+ ? extractSemanticClauses(statement, input.clauses ?? semanticClausesOf(payload))
672
687
  : [];
673
688
  const rawDeclaredClaims = propertiesOf(payload).logic_claims;
674
689
  const declaredClaims = Array.isArray(rawDeclaredClaims)
675
690
  ? rawDeclaredClaims.filter((value) => typeof value === "string")
676
691
  : [];
677
692
  const expectedClaims = clauses
678
- .filter((clause) => clause.normative)
693
+ .filter((clause) => !["rationale", "example", "subjective"].includes(propositionRole(clause.text, clause.normative)))
679
694
  .map((clause) => clause.claim_key);
680
695
  const modeled = requirement &&
681
- isModeled(payload, expectedClaims.length) &&
696
+ isModeled(payload, expectedClaims) &&
682
697
  expectedClaims.length > 0 &&
683
698
  expectedClaims.every((claimKey) => declaredClaims.includes(claimKey));
684
699
  const suggestions = modelingSuggestions(payload, modeled, clauses, input.interpretations);
@@ -5,6 +5,7 @@ export type SemanticClause = Readonly<{
5
5
  normative: boolean;
6
6
  source: "detected" | "supplied";
7
7
  }>;
8
+ export declare function normalizeSemanticClause(value: string): string;
8
9
  export declare function semanticClaimKey(text: string): string;
9
10
  export declare function extractSemanticClauses(text: string, suppliedClauses?: readonly string[]): readonly SemanticClause[];
10
11
  //# sourceMappingURL=clauses.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"clauses.d.ts","sourceRoot":"","sources":["../../../src/operations/semantic-advisor/clauses.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,UAAU,GAAG,UAAU,CAAC;CACjC,CAAC,CAAC;AAkBH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAIrD;AAeD,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,MAAM,EACZ,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,GAClC,SAAS,cAAc,EAAE,CAgB3B"}
1
+ {"version":3,"file":"clauses.d.ts","sourceRoot":"","sources":["../../../src/operations/semantic-advisor/clauses.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,UAAU,GAAG,UAAU,CAAC;CACjC,CAAC,CAAC;AAKH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAW7D;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAIrD;AAeD,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,MAAM,EACZ,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,GAClC,SAAS,cAAc,EAAE,CAgB3B"}
@@ -1,6 +1,6 @@
1
1
  import { createHash } from "node:crypto";
2
2
  const NORMATIVE_PATTERN = /\b(?:must|shall|should|required|requires?|may\s+only|only\s+.+?\s+(?:may|can)|must\s+not|shall\s+not|cannot|can't|forbidden|denied|defaults?\s+to|before|unless|when|if)\b/i;
3
- function normalizeClause(value) {
3
+ export function normalizeSemanticClause(value) {
4
4
  return (value
5
5
  .replace(/^\s*(?:[-*+]\s+|\d+[.)]\s+)/, "")
6
6
  .replace(/\s+/g, " ")
@@ -11,7 +11,7 @@ function normalizeClause(value) {
11
11
  .trim());
12
12
  }
13
13
  export function semanticClaimKey(text) {
14
- const normalized = normalizeClause(text).toLowerCase();
14
+ const normalized = normalizeSemanticClause(text).toLowerCase();
15
15
  const digest = createHash("sha256").update(normalized).digest("hex");
16
16
  return `CLAIM-${digest.slice(0, 16).toUpperCase()}`;
17
17
  }
@@ -23,21 +23,21 @@ function detectedClauses(text) {
23
23
  return [sentence];
24
24
  return sentence.split(/\s+(?:,\s*)?and\s+(?=(?:the\s+)?[a-z][^.!?]{0,100}\b(?:must|shall|should|requires?|cannot|can't|expire|default|transition|states?\s+are)\b)/i);
25
25
  })
26
- .map(normalizeClause)
26
+ .map(normalizeSemanticClause)
27
27
  .filter(Boolean);
28
28
  }
29
29
  export function extractSemanticClauses(text, suppliedClauses) {
30
30
  const source = suppliedClauses === undefined ? "detected" : "supplied";
31
31
  const raw = suppliedClauses ?? detectedClauses(text);
32
- const unique = Array.from(new Set(raw.map(normalizeClause).filter(Boolean)));
33
- if (suppliedClauses !== undefined && unique.length === 0) {
32
+ const normalized = raw.map(normalizeSemanticClause).filter(Boolean);
33
+ if (suppliedClauses !== undefined && normalized.length === 0) {
34
34
  throw new Error("Semantic advisor clauses must contain at least one non-empty atomic claim");
35
35
  }
36
- return unique.map((clause, index) => ({
36
+ return normalized.map((clause, index) => ({
37
37
  claim_key: semanticClaimKey(clause),
38
38
  text: clause,
39
39
  index,
40
- normative: source === "supplied" || NORMATIVE_PATTERN.test(clause),
40
+ normative: NORMATIVE_PATTERN.test(clause),
41
41
  source,
42
42
  }));
43
43
  }
@@ -0,0 +1,18 @@
1
+ import type { PrologPort } from "../../public/operations/runtime-types.js";
2
+ import { type Payload } from "./shared.js";
3
+ import type { SemanticAdvisorReceipt } from "./types.js";
4
+ export interface SemanticInventoryBoundaryResult {
5
+ readonly applicable: boolean;
6
+ readonly errors: readonly string[];
7
+ readonly sourceHash: string;
8
+ }
9
+ type SemanticRelationship = Readonly<{
10
+ type?: unknown;
11
+ from?: unknown;
12
+ to?: unknown;
13
+ }>;
14
+ export declare function validateSemanticInventoryBoundary(payload: Payload, relationships: readonly SemanticRelationship[], receipt: SemanticAdvisorReceipt): SemanticInventoryBoundaryResult;
15
+ export declare function assertSemanticInventoryBoundary(payload: Payload, relationships: readonly SemanticRelationship[], receipt: SemanticAdvisorReceipt): void;
16
+ export declare function assertLogicalGroundingClaimKeys(prolog: PrologPort, payload: Payload, relationships: readonly SemanticRelationship[]): Promise<void>;
17
+ export {};
18
+ //# sourceMappingURL=ingestion-boundary.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ingestion-boundary.d.ts","sourceRoot":"","sources":["../../../src/operations/semantic-advisor/ingestion-boundary.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0CAA0C,CAAC;AAE3E,OAAO,EACL,KAAK,OAAO,EAOb,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,sBAAsB,EAAuB,MAAM,YAAY,CAAC;AAgB9E,MAAM,WAAW,+BAA+B;IAC9C,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED,KAAK,oBAAoB,GAAG,QAAQ,CAAC;IACnC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,EAAE,CAAC,EAAE,OAAO,CAAC;CACd,CAAC,CAAC;AAgCH,wBAAgB,iCAAiC,CAC/C,OAAO,EAAE,OAAO,EAChB,aAAa,EAAE,SAAS,oBAAoB,EAAE,EAC9C,OAAO,EAAE,sBAAsB,GAC9B,+BAA+B,CAmIjC;AAED,wBAAgB,+BAA+B,CAC7C,OAAO,EAAE,OAAO,EAChB,aAAa,EAAE,SAAS,oBAAoB,EAAE,EAC9C,OAAO,EAAE,sBAAsB,GAC9B,IAAI,CAWN;AAGD,wBAAsB,+BAA+B,CACnD,MAAM,EAAE,UAAU,EAClB,OAAO,EAAE,OAAO,EAChB,aAAa,EAAE,SAAS,oBAAoB,EAAE,GAC7C,OAAO,CAAC,IAAI,CAAC,CA+Cf"}
@@ -0,0 +1,167 @@
1
+ import { escapeAtom } from "../../prolog/codec.js";
2
+ import { semanticClaimKey } from "./clauses.js";
3
+ import { SEMANTIC_INVENTORY_VERSION, isRecord, propertiesOf, semanticSourceHash, semanticSourceOf, stringValue, } from "./shared.js";
4
+ const CURRENT_REQUIREMENT_STATUSES = new Set([
5
+ "open",
6
+ "in_progress",
7
+ "closed",
8
+ "active",
9
+ "approved",
10
+ ]);
11
+ const CONTEXT_ROLES = new Set(["rationale", "example", "subjective"]);
12
+ const LOGICAL_RELATIONSHIPS = new Set([
13
+ "requires_property",
14
+ "requires_predicate",
15
+ "requires_rule",
16
+ ]);
17
+ function inventoryOf(payload) {
18
+ const raw = propertiesOf(payload).semantic_inventory;
19
+ return Array.isArray(raw) ? raw.filter(isRecord) : [];
20
+ }
21
+ function exactSpanText(source, span) {
22
+ const start = span.start;
23
+ const end = span.end;
24
+ if (typeof start !== "number" ||
25
+ typeof end !== "number" ||
26
+ !Number.isInteger(start) ||
27
+ !Number.isInteger(end) ||
28
+ start < 0 ||
29
+ end <= start)
30
+ return null;
31
+ const bytes = Buffer.from(source, "utf8");
32
+ if (end > bytes.length)
33
+ return null;
34
+ return bytes.subarray(start, end).toString("utf8");
35
+ }
36
+ function propositionIsAssertive(proposition) {
37
+ return !CONTEXT_ROLES.has(proposition.role);
38
+ }
39
+ // implements REQ-kibi-proposition-complete-ingestion
40
+ export function validateSemanticInventoryBoundary(payload, relationships, receipt) {
41
+ const properties = propertiesOf(payload);
42
+ const semanticSource = semanticSourceOf(payload);
43
+ const sourceHash = semanticSourceHash(semanticSource.text);
44
+ const currentRequirement = stringValue(payload.type) === "req" &&
45
+ CURRENT_REQUIREMENT_STATUSES.has(stringValue(properties.status));
46
+ const assertive = receipt.propositions.filter(propositionIsAssertive);
47
+ const applicable = currentRequirement &&
48
+ semanticSource.text.length > 0 &&
49
+ (semanticSource.field !== "title" ||
50
+ assertive.some(({ role }) => role === "normative"));
51
+ if (!applicable)
52
+ return { applicable, errors: [], sourceHash };
53
+ const errors = [];
54
+ if (properties.semantic_inventory_version !== SEMANTIC_INVENTORY_VERSION) {
55
+ errors.push(`semantic_inventory_version must be '${SEMANTIC_INVENTORY_VERSION}'`);
56
+ }
57
+ if (properties.semantic_source_field !== semanticSource.field) {
58
+ errors.push(`semantic_source_field must be '${semanticSource.field}' for the current requirement prose`);
59
+ }
60
+ if (properties.semantic_source_hash !== sourceHash) {
61
+ errors.push(`semantic_source_hash must equal the SHA-256 hash of ${semanticSource.field} (expected '${sourceHash}')`);
62
+ }
63
+ const inventory = inventoryOf(payload);
64
+ if (!Array.isArray(properties.semantic_inventory)) {
65
+ errors.push("semantic_inventory must contain one entry for every advisor proposition");
66
+ }
67
+ if (inventory.length !== receipt.propositions.length) {
68
+ errors.push(`semantic_inventory must contain exactly ${receipt.propositions.length} proposition(s); received ${inventory.length}`);
69
+ }
70
+ const seenKeys = new Set();
71
+ const seenSpans = new Set();
72
+ for (const [index, entry] of inventory.entries()) {
73
+ const expected = receipt.propositions[index];
74
+ const claimKey = stringValue(entry.claim_key);
75
+ const claimText = stringValue(entry.claim_text);
76
+ const role = stringValue(entry.role);
77
+ const status = stringValue(entry.status);
78
+ const span = isRecord(entry.span) ? entry.span : {};
79
+ const start = span.start;
80
+ const end = span.end;
81
+ const spanKey = `${String(start)}:${String(end)}`;
82
+ if (seenKeys.has(claimKey))
83
+ errors.push(`semantic_inventory has duplicate claim_key '${claimKey}'`);
84
+ seenKeys.add(claimKey);
85
+ if (seenSpans.has(spanKey))
86
+ errors.push(`semantic_inventory has duplicate span '${spanKey}'`);
87
+ seenSpans.add(spanKey);
88
+ const derivedKey = semanticClaimKey(claimText);
89
+ if (claimKey !== derivedKey) {
90
+ errors.push(`semantic_inventory[${index}].claim_key must match claim_text (expected '${derivedKey}')`);
91
+ }
92
+ const sliced = exactSpanText(semanticSource.text, span);
93
+ if (sliced !== claimText) {
94
+ errors.push(`semantic_inventory[${index}].span must select its exact claim_text from ${semanticSource.field}`);
95
+ }
96
+ if (expected &&
97
+ (claimKey !== expected.claim_key ||
98
+ claimText !== expected.claim_text ||
99
+ role !== expected.role ||
100
+ start !== expected.span.start ||
101
+ end !== expected.span.end)) {
102
+ errors.push(`semantic_inventory[${index}] does not match advisor proposition '${expected.claim_key}'`);
103
+ }
104
+ const contextRole = CONTEXT_ROLES.has(role);
105
+ if (contextRole && status !== "nonlogical") {
106
+ errors.push(`semantic_inventory[${index}] role '${role}' must use status 'nonlogical'`);
107
+ }
108
+ if (!contextRole && status === "nonlogical") {
109
+ errors.push(`semantic_inventory[${index}] assertive role '${role}' cannot use status 'nonlogical'`);
110
+ }
111
+ }
112
+ const declaredClaims = Array.isArray(properties.logic_claims)
113
+ ? properties.logic_claims.filter((value) => typeof value === "string")
114
+ : [];
115
+ const expectedClaims = assertive.map(({ claim_key }) => claim_key);
116
+ if (declaredClaims.length !== expectedClaims.length ||
117
+ expectedClaims.some((claimKey) => !declaredClaims.includes(claimKey))) {
118
+ errors.push("logic_claims must contain exactly every assertive semantic_inventory claim_key");
119
+ }
120
+ const modeledCount = inventory.filter(({ status }) => status === "modeled").length;
121
+ const groundingCount = relationships.filter((relationship) => relationship.from === payload.id &&
122
+ LOGICAL_RELATIONSHIPS.has(stringValue(relationship.type))).length;
123
+ if (modeledCount !== groundingCount) {
124
+ errors.push(`modeled semantic_inventory entries (${modeledCount}) must equal logical grounding relationships (${groundingCount})`);
125
+ }
126
+ return { applicable, errors, sourceHash };
127
+ }
128
+ export function assertSemanticInventoryBoundary(payload, relationships, receipt) {
129
+ const result = validateSemanticInventoryBoundary(payload, relationships, receipt);
130
+ if (result.errors.length > 0) {
131
+ throw new Error(`Proposition-complete ingestion failed: ${result.errors.join("; ")}. Run kb_semantic_advisor with the complete prose and preserve its inventory contract before retrying.`);
132
+ }
133
+ }
134
+ // implements REQ-kibi-proposition-complete-ingestion
135
+ export async function assertLogicalGroundingClaimKeys(prolog, payload, relationships) {
136
+ if (stringValue(payload.type) !== "req")
137
+ return;
138
+ if (propertiesOf(payload).semantic_inventory_version !==
139
+ SEMANTIC_INVENTORY_VERSION)
140
+ return;
141
+ const modeledClaimKeys = inventoryOf(payload)
142
+ .filter(({ status }) => status === "modeled")
143
+ .map(({ claim_key }) => stringValue(claim_key));
144
+ const groundedClaimKeys = [];
145
+ for (const relationship of relationships) {
146
+ if (relationship.from !== payload.id ||
147
+ !LOGICAL_RELATIONSHIPS.has(stringValue(relationship.type)))
148
+ continue;
149
+ const target = stringValue(relationship.to);
150
+ const result = await prolog.query(`once((kb_entity('${escapeAtom(target)}', fact, _SemanticGroundProps), memberchk(claim_key=_SemanticGroundRaw, _SemanticGroundProps), normalize_term_atom(_SemanticGroundRaw, ClaimKey)))`);
151
+ const claimKey = result.success
152
+ ? stringValue(result.bindings.ClaimKey).replace(/^['"]|['"]$/g, "")
153
+ : "";
154
+ if (!claimKey) {
155
+ throw new Error(`Proposition-complete ingestion failed: logical grounding target '${target}' must declare a claim_key.`);
156
+ }
157
+ groundedClaimKeys.push(claimKey);
158
+ }
159
+ const duplicate = groundedClaimKeys.find((claimKey, index) => groundedClaimKeys.indexOf(claimKey) !== index);
160
+ if (duplicate) {
161
+ throw new Error(`Proposition-complete ingestion failed: claim '${duplicate}' has more than one logical grounding relationship.`);
162
+ }
163
+ if (groundedClaimKeys.length !== modeledClaimKeys.length ||
164
+ modeledClaimKeys.some((claimKey) => !groundedClaimKeys.includes(claimKey))) {
165
+ throw new Error("Proposition-complete ingestion failed: modeled proposition claim_keys must match logical grounding target claim_keys exactly.");
166
+ }
167
+ }
@@ -1,10 +1,18 @@
1
1
  import type { SemanticModelingSuggestion, SemanticStrictPropertyClaim } from "./types.js";
2
2
  export type Payload = Readonly<Record<string, unknown>>;
3
3
  export type MatchGroups = Readonly<Record<string, string | undefined>>;
4
+ export declare const SEMANTIC_INVENTORY_VERSION = "kibi.semantic-inventory.v1";
5
+ export type SemanticSourceField = "semantic_text" | "text_ref" | "title";
4
6
  export declare function isRecord(value: unknown): value is Record<string, unknown>;
5
7
  export declare function stringValue(value: unknown): string;
6
8
  export declare function canonicalize(value: unknown): string;
7
9
  export declare function payloadHash(payload: Payload): string;
10
+ export declare function semanticSourceOf(payload: Payload): {
11
+ readonly field: SemanticSourceField;
12
+ readonly text: string;
13
+ };
14
+ export declare function semanticSourceHash(text: string): string;
15
+ export declare function semanticClausesOf(payload: Payload): readonly string[] | undefined;
8
16
  export declare function shortHash(value: string): string;
9
17
  export declare function propertiesOf(payload: Payload): Record<string, unknown>;
10
18
  export declare function statementOf(payload: Payload): string;
@@ -1 +1 @@
1
- {"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../../src/operations/semantic-advisor/shared.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,0BAA0B,EAE1B,2BAA2B,EAC5B,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AACxD,MAAM,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;AAGvE,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEzE;AAGD,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAElD;AAGD,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CASnD;AAGD,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAKpD;AAGD,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE/C;AAGD,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEtE;AAGD,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAGpD;AAGD,wBAAgB,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAIjD;AAGD,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAOlD;AAGD,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAQ7D;AAGD,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGjD;AAGD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,MAAM,GACX,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEzB;AAGD,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,2BAA2B,EAClC,SAAS,EAAE,MAAM,EACjB,UAAU,SAAM,GACf,0BAA0B,CAqF5B;AAGD,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,SAAS,EAAE,MAAM,EACjB,QAAQ,GAAE,QAAQ,GAAG,MAAiB,GACrC,0BAA0B,CA+C5B"}
1
+ {"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../../src/operations/semantic-advisor/shared.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,0BAA0B,EAE1B,2BAA2B,EAC5B,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AACxD,MAAM,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;AACvE,eAAO,MAAM,0BAA0B,+BAA+B,CAAC;AACvE,MAAM,MAAM,mBAAmB,GAAG,eAAe,GAAG,UAAU,GAAG,OAAO,CAAC;AAGzE,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEzE;AAGD,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAElD;AAGD,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CASnD;AAGD,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAKpD;AAGD,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG;IAClD,QAAQ,CAAC,KAAK,EAAE,mBAAmB,CAAC;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB,CAmBA;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,OAAO,GACf,SAAS,MAAM,EAAE,GAAG,SAAS,CAO/B;AAGD,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE/C;AAGD,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEtE;AAGD,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAEpD;AAGD,wBAAgB,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAIjD;AAGD,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAOlD;AAGD,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAQ7D;AAGD,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGjD;AAGD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,MAAM,GACX,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEzB;AAGD,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,2BAA2B,EAClC,SAAS,EAAE,MAAM,EACjB,UAAU,SAAM,GACf,0BAA0B,CA0F5B;AAGD,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,SAAS,EAAE,MAAM,EACjB,QAAQ,GAAE,QAAQ,GAAG,MAAiB,GACrC,0BAA0B,CA+C5B"}
@@ -1,5 +1,6 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import { semanticClaimKey } from "./clauses.js";
3
+ export const SEMANTIC_INVENTORY_VERSION = "kibi.semantic-inventory.v1";
3
4
  // implements REQ-mcp-semantic-advisor-preflight
4
5
  export function isRecord(value) {
5
6
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -25,6 +26,35 @@ export function payloadHash(payload) {
25
26
  const stable = Object.fromEntries(Object.entries(payload).filter(([key]) => !key.startsWith("_")));
26
27
  return createHash("sha256").update(canonicalize(stable)).digest("hex");
27
28
  }
29
+ // implements REQ-kibi-legacy-migration-preview-v2
30
+ export function semanticSourceOf(payload) {
31
+ const properties = propertiesOf(payload);
32
+ const declaredField = stringValue(properties.semantic_source_field);
33
+ if (declaredField === "semantic_text" ||
34
+ declaredField === "text_ref" ||
35
+ declaredField === "title") {
36
+ return {
37
+ field: declaredField,
38
+ text: stringValue(properties[declaredField]),
39
+ };
40
+ }
41
+ const semanticText = stringValue(properties.semantic_text);
42
+ if (semanticText)
43
+ return { field: "semantic_text", text: semanticText };
44
+ const textRef = stringValue(properties.text_ref);
45
+ return textRef
46
+ ? { field: "text_ref", text: textRef }
47
+ : { field: "title", text: stringValue(properties.title) };
48
+ }
49
+ export function semanticSourceHash(text) {
50
+ return createHash("sha256").update(text).digest("hex");
51
+ }
52
+ export function semanticClausesOf(payload) {
53
+ const value = propertiesOf(payload).semantic_clauses;
54
+ if (!Array.isArray(value))
55
+ return undefined;
56
+ return value.filter((clause) => typeof clause === "string" && clause.trim().length > 0);
57
+ }
28
58
  // implements REQ-mcp-semantic-advisor-preflight
29
59
  export function shortHash(value) {
30
60
  return createHash("sha256").update(value).digest("hex").slice(0, 12);
@@ -35,8 +65,7 @@ export function propertiesOf(payload) {
35
65
  }
36
66
  // implements REQ-mcp-semantic-advisor-preflight
37
67
  export function statementOf(payload) {
38
- const properties = propertiesOf(payload);
39
- return stringValue(properties.text_ref) || stringValue(properties.title);
68
+ return semanticSourceOf(payload).text;
40
69
  }
41
70
  // implements REQ-mcp-semantic-advisor-preflight
42
71
  export function sourceOf(payload) {
@@ -77,6 +106,7 @@ export function relationship(from, to, type) {
77
106
  // implements REQ-mcp-semantic-advisor-preflight
78
107
  export function strictSuggestion(payload, evidence, claim, rationale, confidence = 0.9) {
79
108
  const claimText = statementOf(payload);
109
+ const semanticSource = semanticSourceOf(payload);
80
110
  const reqId = stringValue(payload.id) || `REQ-SEMANTIC-${shortHash(claim.subject_key)}`;
81
111
  const subjectId = `FACT-SUBJECT-${shortHash(claim.subject_key)}`;
82
112
  const propertyId = `FACT-PROP-${shortHash(`${claim.subject_key}.${claim.property_key}.${claim.operator}.${canonicalize(claim)}`)}`;
@@ -147,7 +177,11 @@ export function strictSuggestion(payload, evidence, claim, rationale, confidence
147
177
  "Semantic advisor requirement suggestion",
148
178
  status: "open",
149
179
  source,
150
- text_ref: statementOf(payload),
180
+ ...(semanticSource.field === "semantic_text"
181
+ ? { semantic_text: statementOf(payload) }
182
+ : semanticSource.field === "text_ref"
183
+ ? { text_ref: statementOf(payload) }
184
+ : {}),
151
185
  tags: ["semantic-advisor-suggestion"],
152
186
  },
153
187
  relationships: [
@@ -137,6 +137,11 @@ export type SemanticModelingSuggestion = {
137
137
  export interface SemanticAdvisorReceipt {
138
138
  readonly version: string;
139
139
  readonly payload_hash: string;
140
+ readonly inventory_contract: {
141
+ readonly version: "kibi.semantic-inventory.v1";
142
+ readonly source_field: "semantic_text" | "text_ref" | "title";
143
+ readonly source_hash: string;
144
+ };
140
145
  readonly logic_readiness: SemanticAdvisorReadiness;
141
146
  readonly candidate_lane: SemanticAdvisorLane;
142
147
  readonly signals: readonly SemanticSignal[];