kibi-cli 2.6.0 → 2.6.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 (131) hide show
  1. package/dist/cli-operation-metadata.d.ts +1 -1
  2. package/dist/cli-operation-metadata.js +1 -1
  3. package/dist/commands/check.d.ts.map +1 -1
  4. package/dist/commands/check.js +15 -0
  5. package/dist/commands/init-helpers.js +1 -1
  6. package/dist/commands/migrate.d.ts.map +1 -1
  7. package/dist/commands/migrate.js +43 -0
  8. package/dist/entity-body-context.d.ts +132 -0
  9. package/dist/entity-body-context.d.ts.map +1 -0
  10. package/dist/entity-body-context.js +382 -0
  11. package/dist/extractors/markdown.d.ts +13 -0
  12. package/dist/extractors/markdown.d.ts.map +1 -1
  13. package/dist/extractors/markdown.js +19 -2
  14. package/dist/intent-search.d.ts.map +1 -1
  15. package/dist/intent-search.js +4 -4
  16. package/dist/operations/bootstrap/candidate-helpers.d.ts +18 -0
  17. package/dist/operations/bootstrap/candidate-helpers.d.ts.map +1 -1
  18. package/dist/operations/bootstrap/candidate-helpers.js +35 -0
  19. package/dist/operations/bootstrap/candidates.d.ts.map +1 -1
  20. package/dist/operations/bootstrap/candidates.js +4 -2
  21. package/dist/operations/bootstrap/intent-claims.d.ts.map +1 -1
  22. package/dist/operations/bootstrap/intent-claims.js +59 -4
  23. package/dist/operations/bootstrap/markdown-candidates.d.ts.map +1 -1
  24. package/dist/operations/bootstrap/markdown-candidates.js +7 -3
  25. package/dist/operations/bootstrap/presentation.js +1 -1
  26. package/dist/operations/migration/entity-body-context.d.ts +57 -0
  27. package/dist/operations/migration/entity-body-context.d.ts.map +1 -0
  28. package/dist/operations/migration/entity-body-context.js +261 -0
  29. package/dist/operations/migration/polarity-values.d.ts.map +1 -1
  30. package/dist/operations/migration/polarity-values.js +5 -2
  31. package/dist/operations/migration/schema6.d.ts +2 -0
  32. package/dist/operations/migration/schema6.d.ts.map +1 -1
  33. package/dist/operations/migration/schema6.js +69 -0
  34. package/dist/operations/modeling/logic-modeling.d.ts.map +1 -1
  35. package/dist/operations/modeling/logic-modeling.js +3 -1
  36. package/dist/operations/modeling/model-requirement.d.ts.map +1 -1
  37. package/dist/operations/modeling/model-requirement.js +7 -9
  38. package/dist/operations/mutation/context-warning.d.ts +13 -0
  39. package/dist/operations/mutation/context-warning.d.ts.map +1 -0
  40. package/dist/operations/mutation/context-warning.js +59 -0
  41. package/dist/operations/mutation/origin.d.ts +2 -1
  42. package/dist/operations/mutation/origin.d.ts.map +1 -1
  43. package/dist/operations/mutation/origin.js +7 -18
  44. package/dist/operations/mutation/requirement-semantics.d.ts +16 -0
  45. package/dist/operations/mutation/requirement-semantics.d.ts.map +1 -0
  46. package/dist/operations/mutation/requirement-semantics.js +64 -0
  47. package/dist/operations/mutation/source-authoring.d.ts.map +1 -1
  48. package/dist/operations/mutation/source-authoring.js +10 -0
  49. package/dist/operations/mutation/stored-entity.d.ts +20 -0
  50. package/dist/operations/mutation/stored-entity.d.ts.map +1 -0
  51. package/dist/operations/mutation/stored-entity.js +51 -0
  52. package/dist/operations/mutation/upsert.d.ts +3 -2
  53. package/dist/operations/mutation/upsert.d.ts.map +1 -1
  54. package/dist/operations/mutation/upsert.js +19 -10
  55. package/dist/operations/mutation/validate-upsert.d.ts.map +1 -1
  56. package/dist/operations/mutation/validate-upsert.js +6 -1
  57. package/dist/operations/planning/compile-intent.d.ts +9 -0
  58. package/dist/operations/planning/compile-intent.d.ts.map +1 -1
  59. package/dist/operations/planning/compile-intent.js +49 -2
  60. package/dist/operations/semantic-advisor/analyze-prose.d.ts +3 -2
  61. package/dist/operations/semantic-advisor/analyze-prose.d.ts.map +1 -1
  62. package/dist/operations/semantic-advisor/analyze-prose.js +3 -41
  63. package/dist/operations/semantic-advisor/ingestion-boundary.d.ts.map +1 -1
  64. package/dist/operations/semantic-advisor/ingestion-boundary.js +10 -1
  65. package/dist/operations/semantic-advisor/proposition-role.d.ts +6 -0
  66. package/dist/operations/semantic-advisor/proposition-role.d.ts.map +1 -0
  67. package/dist/operations/semantic-advisor/proposition-role.js +76 -0
  68. package/dist/public/operations/catalog.d.ts +33 -6
  69. package/dist/public/operations/catalog.d.ts.map +1 -1
  70. package/dist/public/operations/check-executor.d.ts.map +1 -1
  71. package/dist/public/operations/check-executor.js +3 -0
  72. package/dist/public/operations/entity-context.d.ts +51 -0
  73. package/dist/public/operations/entity-context.d.ts.map +1 -0
  74. package/dist/public/operations/entity-context.js +235 -0
  75. package/dist/public/operations/origin-review.d.ts +1 -1
  76. package/dist/public/operations/origin-review.js +2 -2
  77. package/dist/public/operations/specs/bootstrap.d.ts +14 -2
  78. package/dist/public/operations/specs/bootstrap.d.ts.map +1 -1
  79. package/dist/public/operations/specs/bootstrap.js +8 -2
  80. package/dist/public/operations/specs/check-rules.generated.d.ts +1 -1
  81. package/dist/public/operations/specs/check-rules.generated.d.ts.map +1 -1
  82. package/dist/public/operations/specs/check-rules.generated.js +3 -1
  83. package/dist/public/operations/specs/check.d.ts +1 -1
  84. package/dist/public/operations/specs/mutation-schemas.d.ts +1 -1
  85. package/dist/public/operations/specs/mutation-schemas.d.ts.map +1 -1
  86. package/dist/public/operations/specs/mutation-schemas.js +10 -2
  87. package/dist/public/operations/specs/planning.d.ts +15 -0
  88. package/dist/public/operations/specs/planning.d.ts.map +1 -1
  89. package/dist/public/operations/specs/planning.js +15 -0
  90. package/dist/public/operations/specs/upsert.d.ts +3 -3
  91. package/dist/public/operations/specs/upsert.js +2 -2
  92. package/dist/public/schemas/entity.d.ts.map +1 -1
  93. package/dist/public/schemas/entity.js +7 -1
  94. package/dist/public/skills/kibi-bootstrap/SKILL.md +3 -3
  95. package/dist/public/skills/kibi-bootstrap/resources/bootstrap.md +5 -1
  96. package/dist/public/skills/kibi-usage/SKILL.md +56 -3
  97. package/dist/public/skills/kibi-usage/resources/source-authoring.md +5 -1
  98. package/dist/schemas/entity.schema.json +14 -1
  99. package/dist/search-ranking.d.ts.map +1 -1
  100. package/dist/search-ranking.js +7 -4
  101. package/dist/traceability/staged-consistency.d.ts +25 -0
  102. package/dist/traceability/staged-consistency.d.ts.map +1 -0
  103. package/dist/traceability/staged-consistency.js +92 -0
  104. package/dist/traceability/temp-kb.d.ts.map +1 -1
  105. package/dist/traceability/temp-kb.js +5 -0
  106. package/dist/utils/kb-manifest.d.ts +5 -0
  107. package/dist/utils/kb-manifest.d.ts.map +1 -1
  108. package/dist/utils/kb-manifest.js +6 -0
  109. package/dist/utils/rule-registry.generated.d.ts +11 -0
  110. package/dist/utils/rule-registry.generated.d.ts.map +1 -1
  111. package/dist/utils/rule-registry.generated.js +13 -0
  112. package/dist/utils/schema-version.d.ts +1 -1
  113. package/dist/utils/schema-version.d.ts.map +1 -1
  114. package/dist/utils/schema-version.js +3 -2
  115. package/package.json +2 -2
  116. package/schema/manifest.json +5 -0
  117. package/schema/validation.pl +14 -2
  118. package/src/public/operations/check-executor.ts +6 -0
  119. package/src/public/operations/entity-context.ts +304 -0
  120. package/src/public/operations/origin-review.ts +2 -2
  121. package/src/public/operations/specs/bootstrap.ts +9 -2
  122. package/src/public/operations/specs/check-rules.generated.ts +3 -1
  123. package/src/public/operations/specs/mutation-schemas.ts +10 -2
  124. package/src/public/operations/specs/planning.ts +18 -0
  125. package/src/public/operations/specs/upsert.ts +2 -2
  126. package/src/public/schemas/entity.ts +7 -1
  127. package/src/public/skills/kibi-bootstrap/SKILL.md +3 -3
  128. package/src/public/skills/kibi-bootstrap/resources/bootstrap.md +5 -1
  129. package/src/public/skills/kibi-usage/SKILL.md +56 -3
  130. package/src/public/skills/kibi-usage/resources/source-authoring.md +5 -1
  131. package/src/schemas/entity.schema.json +14 -1
@@ -0,0 +1,382 @@
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
+ /**
19
+ * Entity Markdown bodies carry human and agent context next to, not inside,
20
+ * the checked meaning. This module is the one place that knows which body
21
+ * text is context, so the extractor, the strict check, compile-intent,
22
+ * bootstrap, the migration and search all agree.
23
+ */
24
+ /** Heading words whose sections hold context rather than normative text. */
25
+ // implements REQ-kb-entity-body-context
26
+ export const CONTEXT_HEADING_WORDS = [
27
+ "context",
28
+ "rationale",
29
+ "why",
30
+ "background",
31
+ "source",
32
+ "notes",
33
+ "evidence",
34
+ ];
35
+ /** A context section needs at least this many words of prose. */
36
+ // implements REQ-kb-entity-body-context
37
+ export const MIN_CONTEXT_WORDS = 12;
38
+ /** Token-set Jaccard at or above this value counts as a restatement. */
39
+ // implements REQ-kb-entity-body-context
40
+ export const RESTATEMENT_JACCARD = 0.8;
41
+ /** Tag that marks legacy entities acknowledged as lacking context. */
42
+ // implements REQ-kb-entity-body-context
43
+ export const CONTEXT_MISSING_TAG = "review:context-missing";
44
+ const HEADING_LINE = /^\s{0,3}(#{1,6})(?:[ \t]+(.*?))?[ \t]*$/;
45
+ const CONTEXT_HEADING = new RegExp(`^(?:${CONTEXT_HEADING_WORDS.join("|")})\\b`, "i");
46
+ /** True when a heading's text starts with a context heading word. */
47
+ // implements REQ-kb-entity-body-context
48
+ export function isContextHeading(heading) {
49
+ return CONTEXT_HEADING.test(heading.trim().replace(/^[*_`\s]+/, ""));
50
+ }
51
+ /**
52
+ * Classify every line of a body. A line under a context heading stays in
53
+ * context until the next heading of the same or a higher level, so
54
+ * `### Constraints` below `## Context` is still context.
55
+ */
56
+ function classifyLines(body) {
57
+ const classified = [];
58
+ let contextLevel = null;
59
+ for (const line of body.replace(/\r\n?/g, "\n").split("\n")) {
60
+ const match = HEADING_LINE.exec(line);
61
+ if (match === null) {
62
+ classified.push({
63
+ line,
64
+ level: 0,
65
+ heading: "",
66
+ inContext: contextLevel !== null,
67
+ });
68
+ continue;
69
+ }
70
+ const level = match[1]?.length ?? 1;
71
+ const heading = (match[2] ?? "").replace(/[ \t]+#+$/, "").trim();
72
+ if (contextLevel !== null && level <= contextLevel)
73
+ contextLevel = null;
74
+ if (contextLevel === null && isContextHeading(heading)) {
75
+ contextLevel = level;
76
+ }
77
+ classified.push({ line, level, heading, inContext: contextLevel !== null });
78
+ }
79
+ return classified;
80
+ }
81
+ /** Split a Markdown body (front matter removed) into sections by ATX headings. */
82
+ // implements REQ-kb-entity-body-context
83
+ export function parseBodySections(body) {
84
+ const sections = [];
85
+ let current = {
86
+ level: 0,
87
+ heading: "",
88
+ isContext: false,
89
+ };
90
+ let lines = [];
91
+ const flush = () => {
92
+ const text = lines.join("\n").trim();
93
+ if (current.level > 0 || text !== "")
94
+ sections.push({ ...current, text });
95
+ lines = [];
96
+ };
97
+ for (const row of classifyLines(body)) {
98
+ if (row.level === 0) {
99
+ lines.push(row.line);
100
+ continue;
101
+ }
102
+ flush();
103
+ current = {
104
+ level: row.level,
105
+ heading: row.heading,
106
+ isContext: row.inContext,
107
+ };
108
+ }
109
+ flush();
110
+ return sections;
111
+ }
112
+ /**
113
+ * The body with every line of its context sections removed (other lines are
114
+ * untouched), for deriving the checked meaning.
115
+ */
116
+ // implements REQ-kb-entity-body-context
117
+ export function withoutContextSections(body) {
118
+ return classifyLines(body)
119
+ .filter((row) => !row.inContext)
120
+ .map((row) => row.line)
121
+ .join("\n");
122
+ }
123
+ /** Text of the context sections of a body, headings excluded. */
124
+ // implements REQ-kb-entity-body-context
125
+ export function contextSectionText(body) {
126
+ return parseBodySections(body)
127
+ .filter((section) => section.isContext && section.text !== "")
128
+ .map((section) => section.text)
129
+ .join("\n\n");
130
+ }
131
+ /** Types whose entities must carry body context. */
132
+ // implements REQ-kb-entity-body-context
133
+ export const CONTEXT_REQUIRED_TYPES = [
134
+ "req",
135
+ "scenario",
136
+ "test",
137
+ "adr",
138
+ "fact",
139
+ ];
140
+ /**
141
+ * True when the type needs no body context: symbols, flags and events, and
142
+ * facts of any fact_kind other than observation or meta (their front matter
143
+ * is the content).
144
+ */
145
+ // implements REQ-kb-entity-body-context
146
+ export function isContextExempt(type, entity) {
147
+ if (type === "fact") {
148
+ return entity.fact_kind !== "observation" && entity.fact_kind !== "meta";
149
+ }
150
+ return !CONTEXT_REQUIRED_TYPES.includes(type);
151
+ }
152
+ function proseWithoutHeadings(body) {
153
+ return parseBodySections(body)
154
+ .map((section) => section.text)
155
+ .filter((text) => text !== "")
156
+ .join("\n");
157
+ }
158
+ /**
159
+ * The body prose that counts as context. Requirements: only text under
160
+ * context headings. Scenarios, tests, ADRs and observation or meta facts:
161
+ * all body prose outside headings.
162
+ */
163
+ // implements REQ-kb-entity-body-context
164
+ export function contextProse(type, body, _entity = {}) {
165
+ return type === "req" ? contextSectionText(body) : proseWithoutHeadings(body);
166
+ }
167
+ function tokens(text) {
168
+ return text
169
+ .toLowerCase()
170
+ .split(/[^\p{L}\p{N}]+/u)
171
+ .filter((token) => token !== "");
172
+ }
173
+ /** Normalized token-set Jaccard similarity of two texts (0 when both empty). */
174
+ // implements REQ-kb-entity-body-context
175
+ export function tokenSetJaccard(left, right) {
176
+ const a = new Set(tokens(left));
177
+ const b = new Set(tokens(right));
178
+ if (a.size === 0 && b.size === 0)
179
+ return 0;
180
+ let shared = 0;
181
+ for (const token of a)
182
+ if (b.has(token))
183
+ shared += 1;
184
+ return shared / (a.size + b.size - shared);
185
+ }
186
+ /**
187
+ * Judge an entity's body context: at least MIN_CONTEXT_WORDS words of
188
+ * context prose that do not restate the title (or, for requirements, the
189
+ * semantic text). Exempt types always pass.
190
+ */
191
+ // implements REQ-kb-entity-body-context
192
+ export function assessContext(type, body, entity) {
193
+ if (isContextExempt(type, entity))
194
+ return { ok: true, words: 0 };
195
+ const prose = contextProse(type, body, entity);
196
+ const words = tokens(prose).length;
197
+ if (words === 0)
198
+ return { ok: false, reason: "none", words };
199
+ if (words < MIN_CONTEXT_WORDS)
200
+ return { ok: false, reason: "too_short", words };
201
+ const references = [
202
+ typeof entity.title === "string" ? entity.title : "",
203
+ type === "req" && typeof entity.semantic_text === "string"
204
+ ? entity.semantic_text
205
+ : "",
206
+ ].filter((text) => text.trim() !== "");
207
+ if (references.some((reference) => tokenSetJaccard(prose, reference) >= RESTATEMENT_JACCARD)) {
208
+ return { ok: false, reason: "restatement", words };
209
+ }
210
+ return { ok: true, words };
211
+ }
212
+ /** True when the entity's body states context that is not a restatement. */
213
+ // implements REQ-kb-entity-body-context
214
+ export function hasContext(type, body, entity) {
215
+ return assessContext(type, body, entity).ok;
216
+ }
217
+ const TYPE_LABEL = {
218
+ req: "requirement",
219
+ scenario: "scenario",
220
+ test: "test",
221
+ adr: "ADR",
222
+ fact: "observation fact",
223
+ };
224
+ /**
225
+ * The finding for an entity whose body lacks context, or null when it has
226
+ * context, is exempt, or is acknowledged by the schema 8 migration
227
+ * (`acknowledged`, true only for ids the migration recorded in the manifest;
228
+ * the tag alone never exempts). The strict check and the kb_upsert warning
229
+ * share it.
230
+ */
231
+ // implements REQ-kb-entity-body-context
232
+ export function contextFinding(type, id, body, entity, acknowledged = false) {
233
+ const assessment = assessContext(type, body, entity);
234
+ if (assessment.ok || assessment.reason === undefined)
235
+ return null;
236
+ if (acknowledged)
237
+ return null;
238
+ return {
239
+ type,
240
+ id,
241
+ reason: assessment.reason,
242
+ words: assessment.words,
243
+ description: `${TYPE_LABEL[type] ?? type} ${id} has no body context: ${missingContextDescription(type, assessment.reason)}`,
244
+ suggestion: CONTEXT_MISSING_HINT,
245
+ };
246
+ }
247
+ /** True when the entity's tags acknowledge missing context as legacy. */
248
+ // implements REQ-kb-entity-body-context
249
+ export function isContextAcknowledged(tags) {
250
+ return Array.isArray(tags) && tags.includes(CONTEXT_MISSING_TAG);
251
+ }
252
+ /** What is missing for a type, in the words the check and warnings use. */
253
+ // implements REQ-kb-entity-body-context
254
+ export function missingContextDescription(type, reason) {
255
+ const where = type === "req"
256
+ ? "a '## Context' (or Rationale, Why, Background, Source, Notes, Evidence) section"
257
+ : "body prose";
258
+ const what = reason === "restatement"
259
+ ? "only restates the title or statement"
260
+ : reason === "too_short"
261
+ ? `is shorter than ${MIN_CONTEXT_WORDS} words`
262
+ : "is missing";
263
+ return `${where} that states why this exists ${what}`;
264
+ }
265
+ /** Hint shared by the check finding and the kb_upsert warning. */
266
+ // implements REQ-kb-entity-body-context
267
+ export const CONTEXT_MISSING_HINT = "Add a '## Context' section (requirements) or a prose body (scenarios, tests, ADRs, observation facts) stating why this exists, who asked, the source and anything that does not fit the front matter. Never invent a reason the requester did not give: write who asked, the source and 'Reason not stated' in the Context section instead.";
268
+ /** Suggestion for a review:context-missing tag the schema 8 migration did not set. */
269
+ // implements REQ-kb-entity-body-context
270
+ export const RESERVED_TAG_HINT = "review:context-missing is reserved for entities acknowledged by the schema 8 migration; add context instead: write who asked, the source and 'Reason not stated' in the Context section, and remove the tag.";
271
+ function blockquote(text) {
272
+ return text
273
+ .replace(/\r\n?/g, "\n")
274
+ .trim()
275
+ .split("\n")
276
+ .map((line) => (line.trim() === "" ? ">" : `> ${line}`))
277
+ .join("\n");
278
+ }
279
+ function contextSectionBlock(context) {
280
+ return `## Context\n\n${context.trim()}`;
281
+ }
282
+ function sourceSectionBlock(source) {
283
+ const sourceLines = [];
284
+ const excerpt = source?.excerpt?.trim();
285
+ if (excerpt)
286
+ sourceLines.push(blockquote(excerpt));
287
+ const reference = [source?.title?.trim(), source?.reference?.trim()]
288
+ .filter((part) => part !== undefined && part !== "")
289
+ .join(" - ");
290
+ if (reference)
291
+ sourceLines.push(`Source: ${reference}`);
292
+ return sourceLines.length > 0
293
+ ? `## Source\n\n${sourceLines.join("\n\n")}`
294
+ : null;
295
+ }
296
+ /**
297
+ * Render a requirement body: the statement, then `## Context` and
298
+ * `## Source` when given. The statement stays the first, heading-free block
299
+ * so it remains the derived meaning when no `semantic_text` is pinned.
300
+ */
301
+ // implements REQ-kb-entity-body-context
302
+ export function renderRequirementBody(input) {
303
+ const blocks = [input.statement.trim()];
304
+ const context = input.context?.trim();
305
+ if (context)
306
+ blocks.push(contextSectionBlock(context));
307
+ const source = sourceSectionBlock(input.source);
308
+ if (source !== null)
309
+ blocks.push(source);
310
+ return `${blocks.join("\n\n")}\n`;
311
+ }
312
+ /**
313
+ * Revise a requirement body for a changed statement. The non-context part is
314
+ * replaced by the new statement; every context section is kept byte for byte,
315
+ * except that a supplied `context` replaces the `## Context` section and a
316
+ * supplied source replaces the `## Source` section (each is appended when the
317
+ * body had none).
318
+ */
319
+ // implements REQ-kb-entity-body-context
320
+ export function reviseRequirementBody(input) {
321
+ const replacements = new Map();
322
+ const context = input.context?.trim();
323
+ if (context)
324
+ replacements.set("context", contextSectionBlock(context));
325
+ const source = sourceSectionBlock(input.source);
326
+ if (source !== null)
327
+ replacements.set("source", source);
328
+ const blocks = [];
329
+ let open = null;
330
+ let openLevel = 0;
331
+ for (const row of classifyLines(input.existingBody)) {
332
+ if (!row.inContext) {
333
+ open = null;
334
+ continue;
335
+ }
336
+ const startsBlock = row.level > 0 &&
337
+ isContextHeading(row.heading) &&
338
+ (open === null || row.level <= openLevel);
339
+ if (startsBlock) {
340
+ const word = row.heading
341
+ .trim()
342
+ .replace(/^[*_`\s]+/, "")
343
+ .split(/\W+/, 1)[0];
344
+ open = { key: (word ?? "").toLowerCase(), lines: [] };
345
+ openLevel = row.level;
346
+ blocks.push(open);
347
+ }
348
+ open?.lines.push(row.line);
349
+ }
350
+ const used = new Set();
351
+ const parts = [input.statement.trim()];
352
+ for (const block of blocks) {
353
+ const replacement = replacements.get(block.key);
354
+ if (replacement !== undefined && !used.has(block.key)) {
355
+ used.add(block.key);
356
+ parts.push(replacement);
357
+ }
358
+ else if (replacement === undefined) {
359
+ parts.push(block.lines.join("\n").replace(/\n+$/, ""));
360
+ }
361
+ }
362
+ for (const [key, replacement] of replacements) {
363
+ if (!used.has(key))
364
+ parts.push(replacement);
365
+ }
366
+ return `${parts.join("\n\n")}\n`;
367
+ }
368
+ function firstLine(text) {
369
+ return text
370
+ .split(/\r?\n/)
371
+ .map((line) => line.trim())
372
+ .find(Boolean);
373
+ }
374
+ /**
375
+ * The line a search row shows for a body: the first line of the context
376
+ * prose when the body has any, else the first non-blank body line. With a
377
+ * statement-only body the first line would repeat the title.
378
+ */
379
+ // implements REQ-kb-entity-body-context
380
+ export function bodySnippetLine(type, body, entity = {}) {
381
+ return firstLine(contextProse(type, body, entity)) ?? firstLine(body);
382
+ }
@@ -101,6 +101,19 @@ export declare class FrontmatterError extends Error {
101
101
  });
102
102
  toString(): string;
103
103
  }
104
+ /**
105
+ * The checked meaning derived from a requirement body before schema 8: every
106
+ * line except headings, with list and quote markers removed. Context
107
+ * sections were part of it. Schema 8 pins this value as `semantic_text` for
108
+ * requirements that never stated one, so claim spans and hashes do not move.
109
+ */
110
+ export declare function legacyRequirementSemanticText(body: string): string;
111
+ /**
112
+ * The checked meaning derived from a requirement body: the legacy derivation
113
+ * over the body with its context sections (Context, Rationale, Why,
114
+ * Background, Source, Notes, Evidence) removed, so context never changes
115
+ * what a requirement means.
116
+ */
104
117
  export declare function requirementSemanticText(body: string): string;
105
118
  export declare function detectEmbeddedEntities(data: Record<string, unknown>, entityType: string): string[];
106
119
  export declare function extractFromMarkdownString(content: string, filePath: string): ExtractionResult;
@@ -1 +1 @@
1
- {"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/extractors/markdown.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/extractors/markdown.ts"],"names":[],"mappings":"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"}
@@ -19,6 +19,7 @@ import { createHash } from "node:crypto";
19
19
  import { readFileSync } from "node:fs";
20
20
  import Ajv from "ajv";
21
21
  import { load as yamlLoad } from "js-yaml";
22
+ import { withoutContextSections } from "../entity-body-context.js";
22
23
  import { semanticClaimKey } from "../operations/semantic-advisor/clauses.js";
23
24
  import { normalizeEntityOrigin, } from "../public/entity-origin.js";
24
25
  import { PROOF_BINDINGS_SCHEMA, PROOF_CONTRACT_SCHEMA, } from "../public/proof-protocol.js";
@@ -251,8 +252,14 @@ function parseFrontmatter(content) {
251
252
  content: parts.slice(2).join("---"),
252
253
  };
253
254
  }
254
- // implements REQ-kibi-legacy-migration-preview-v2
255
- export function requirementSemanticText(body) {
255
+ /**
256
+ * The checked meaning derived from a requirement body before schema 8: every
257
+ * line except headings, with list and quote markers removed. Context
258
+ * sections were part of it. Schema 8 pins this value as `semantic_text` for
259
+ * requirements that never stated one, so claim spans and hashes do not move.
260
+ */
261
+ // implements REQ-kibi-legacy-migration-preview-v2, REQ-kb-entity-body-context
262
+ export function legacyRequirementSemanticText(body) {
256
263
  return body
257
264
  .replace(/\r\n?/g, "\n")
258
265
  .split("\n")
@@ -261,6 +268,16 @@ export function requirementSemanticText(body) {
261
268
  .join("\n")
262
269
  .trim();
263
270
  }
271
+ /**
272
+ * The checked meaning derived from a requirement body: the legacy derivation
273
+ * over the body with its context sections (Context, Rationale, Why,
274
+ * Background, Source, Notes, Evidence) removed, so context never changes
275
+ * what a requirement means.
276
+ */
277
+ // implements REQ-kibi-legacy-migration-preview-v2, REQ-kb-entity-body-context
278
+ export function requirementSemanticText(body) {
279
+ return legacyRequirementSemanticText(withoutContextSections(body));
280
+ }
264
281
  function hasLikelyUnquotedColonInTitle(content) {
265
282
  if (!content.trim().startsWith("---")) {
266
283
  return false;
@@ -1 +1 @@
1
- {"version":3,"file":"intent-search.d.ts","sourceRoot":"","sources":["../src/intent-search.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"intent-search.d.ts","sourceRoot":"","sources":["../src/intent-search.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import path from "node:path";
2
+ import { bodySnippetLine } from "./entity-body-context.js";
2
3
  import { escapeAtom, normalizeEntityId, parseTriples } from "./prolog/codec.js";
3
4
  import { listSearchCandidates, loadEntityRows, loadSearchCandidates, } from "./public/operations/discovery-entities.js";
4
5
  import { loadMarkdownBody } from "./search-ranking.js";
@@ -418,10 +419,9 @@ export async function rankIntentEntities(entities, options, workspaceRoot, graph
418
419
  const scored = scoreEntity(entity, allTokens, facets, sourceEvidence, graphEvidence, documentFrequency, entities.length, body, supersededIds.has(entityId));
419
420
  if (scored.score < minScore)
420
421
  continue;
421
- const snippet = body
422
- ?.split(/\r?\n/)
423
- .map((line) => line.trim())
424
- .find(Boolean);
422
+ const snippet = body === null
423
+ ? undefined
424
+ : bodySnippetLine(String(entity.type ?? ""), body, entity);
425
425
  ranked.push({
426
426
  entity,
427
427
  score: scored.score,
@@ -10,4 +10,22 @@ export declare function upsert<T extends {
10
10
  readonly to: string;
11
11
  }[]): Readonly<Record<string, unknown>>;
12
12
  export declare function strictPlan(writeSet: StrictWriteSet): readonly Readonly<Record<string, unknown>>[];
13
+ /**
14
+ * Attach an authored body to an upsert step so the entity document carries
15
+ * more than its front matter.
16
+ */
17
+ export declare function withDocumentBody(step: Readonly<Record<string, unknown>>, body: string): Readonly<Record<string, unknown>>;
18
+ /**
19
+ * Where a deterministic bootstrap provider found an entry. No reason was
20
+ * stated in the source, so the sentence records provenance instead of
21
+ * inventing one; later schema versions and reviewers keep the origin.
22
+ */
23
+ export declare function bootstrapProvenance(provider: string, location: string, confidence: number): string;
24
+ /** Body for a non-requirement entity: its title, then its provenance. */
25
+ export declare function provenanceBody(title: string, provenance: string): string;
26
+ /**
27
+ * Body for a requirement found in prose: the statement, the provenance as
28
+ * its Context and the quoted statement with its location as its Source.
29
+ */
30
+ export declare function provenanceRequirementBody(statement: string, provenance: string, reference: string): string;
13
31
  //# sourceMappingURL=candidate-helpers.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"candidate-helpers.d.ts","sourceRoot":"","sources":["../../../src/operations/bootstrap/candidate-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAIrE,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,wBAAgB,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,MAAM,CAMtD;AAED,wBAAgB,MAAM,CACpB,CAAC,SAAS;IAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,OAAO,CAAA;CAAE,EAE5D,MAAM,EAAE,CAAC,EACT,aAAa,GAAE,SAAS;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;CACrB,EAAO,GACP,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAQnC;AAED,wBAAgB,UAAU,CACxB,QAAQ,EAAE,cAAc,GACvB,SAAS,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,CA0C9C"}
1
+ {"version":3,"file":"candidate-helpers.d.ts","sourceRoot":"","sources":["../../../src/operations/bootstrap/candidate-helpers.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAIrE,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,wBAAgB,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,MAAM,CAMtD;AAED,wBAAgB,MAAM,CACpB,CAAC,SAAS;IAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,OAAO,CAAA;CAAE,EAE5D,MAAM,EAAE,CAAC,EACT,aAAa,GAAE,SAAS;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;CACrB,EAAO,GACP,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAQnC;AAED,wBAAgB,UAAU,CACxB,QAAQ,EAAE,cAAc,GACvB,SAAS,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,CA0C9C;AAED;;;GAGG;AAEH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACvC,IAAI,EAAE,MAAM,GACX,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAEnC;AAED;;;;GAIG;AAEH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,MAAM,CAER;AAED,yEAAyE;AAEzE,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAExE;AAED;;;GAGG;AAEH,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,GAChB,MAAM,CAMR"}
@@ -1,3 +1,4 @@
1
+ import { renderRequirementBody } from "../../entity-body-context.js";
1
2
  import { annotateModelRequirementStep } from "../modeling/model-requirement.js";
2
3
  import { semanticClaimKey } from "../semantic-advisor/clauses.js";
3
4
  export function confidenceBand(value) {
@@ -60,3 +61,37 @@ export function strictPlan(writeSet) {
60
61
  logicClaims: [claimKey],
61
62
  }));
62
63
  }
64
+ /**
65
+ * Attach an authored body to an upsert step so the entity document carries
66
+ * more than its front matter.
67
+ */
68
+ // implements REQ-kb-entity-body-context
69
+ export function withDocumentBody(step, body) {
70
+ return { ...step, document: { body } };
71
+ }
72
+ /**
73
+ * Where a deterministic bootstrap provider found an entry. No reason was
74
+ * stated in the source, so the sentence records provenance instead of
75
+ * inventing one; later schema versions and reviewers keep the origin.
76
+ */
77
+ // implements REQ-kb-entity-body-context
78
+ export function bootstrapProvenance(provider, location, confidence) {
79
+ return `Recorded deterministically by the ${provider} bootstrap provider from ${location} (confidence ${confidence.toFixed(2)}). The source states no reason for this entry, so it preserves where the knowledge came from for later schema versions and reviewers.`;
80
+ }
81
+ /** Body for a non-requirement entity: its title, then its provenance. */
82
+ // implements REQ-kb-entity-body-context
83
+ export function provenanceBody(title, provenance) {
84
+ return `${title.trim()}\n\n${provenance}\n`;
85
+ }
86
+ /**
87
+ * Body for a requirement found in prose: the statement, the provenance as
88
+ * its Context and the quoted statement with its location as its Source.
89
+ */
90
+ // implements REQ-kb-entity-body-context
91
+ export function provenanceRequirementBody(statement, provenance, reference) {
92
+ return renderRequirementBody({
93
+ statement,
94
+ context: provenance,
95
+ source: { excerpt: statement, reference },
96
+ });
97
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"candidates.d.ts","sourceRoot":"","sources":["../../../src/operations/bootstrap/candidates.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,KAAK,oBAAoB,EAE1B,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EACV,iBAAiB,EAGlB,MAAM,YAAY,CAAC;AA+GpB,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,SAAS,iBAAiB,EAAE,EACtC,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,EAChC,aAAa,EAAE,MAAM,EACrB,sBAAsB,EAAE,OAAO,GAC9B,oBAAoB,CA4DtB"}
1
+ {"version":3,"file":"candidates.d.ts","sourceRoot":"","sources":["../../../src/operations/bootstrap/candidates.ts"],"names":[],"mappings":"AAYA,OAAO,EACL,KAAK,oBAAoB,EAE1B,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EACV,iBAAiB,EAGlB,MAAM,YAAY,CAAC;AAuHpB,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,SAAS,iBAAiB,EAAE,EACtC,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,EAChC,aAAa,EAAE,MAAM,EACrB,sBAAsB,EAAE,OAAO,GAC9B,oBAAoB,CA4DtB"}
@@ -1,7 +1,7 @@
1
1
  import path from "node:path";
2
2
  import { extractFromManifestString } from "../../extractors/manifest.js";
3
3
  import { extractFromMarkdownString } from "../../extractors/markdown.js";
4
- import { confidenceBand, slug, upsert } from "./candidate-helpers.js";
4
+ import { bootstrapProvenance, confidenceBand, provenanceBody, slug, upsert, withDocumentBody, } from "./candidate-helpers.js";
5
5
  import { markdownCandidates, } from "./markdown-candidates.js";
6
6
  function typedCandidates(item, existingIds) {
7
7
  const results = item.kind === "symbol_manifest"
@@ -82,7 +82,9 @@ function providerCandidate(item, existingIds, minConfidence) {
82
82
  confidenceBand: confidenceBand(confidence),
83
83
  evidence,
84
84
  relationships: [],
85
- applyPlan: [upsert(entity)],
85
+ applyPlan: [
86
+ withDocumentBody(upsert(entity), provenanceBody(title, `${bootstrapProvenance(item.provider, relativePath, confidence)}${evidence.length > 0 ? ` Evidence: ${evidence.join("; ")}.` : ""}`)),
87
+ ],
86
88
  },
87
89
  ];
88
90
  }
@@ -1 +1 @@
1
- {"version":3,"file":"intent-claims.d.ts","sourceRoot":"","sources":["../../../src/operations/bootstrap/intent-claims.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,wBAAwB,EAGxB,SAAS,EACT,gBAAgB,EACjB,MAAM,YAAY,CAAC;AAQpB,MAAM,MAAM,sBAAsB,GAAG;IACnC,QAAQ,CAAC,UAAU,EAAE,SAAS,SAAS,EAAE,CAAC;IAC1C,QAAQ,CAAC,iBAAiB,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACxD,QAAQ,CAAC,UAAU,EAAE,SAAS,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC;IAClE,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;CACzC,CAAC;AAuKF;;;;;;;GAOG;AAEH,wBAAgB,0BAA0B,CACxC,QAAQ,EAAE,wBAAwB,EAClC,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,EAChC,aAAa,EAAE,MAAM,GACpB,sBAAsB,CA8HxB"}
1
+ {"version":3,"file":"intent-claims.d.ts","sourceRoot":"","sources":["../../../src/operations/bootstrap/intent-claims.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,wBAAwB,EAGxB,SAAS,EACT,gBAAgB,EACjB,MAAM,YAAY,CAAC;AAQpB,MAAM,MAAM,sBAAsB,GAAG;IACnC,QAAQ,CAAC,UAAU,EAAE,SAAS,SAAS,EAAE,CAAC;IAC1C,QAAQ,CAAC,iBAAiB,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACxD,QAAQ,CAAC,UAAU,EAAE,SAAS,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC;IAClE,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;CACzC,CAAC;AA0NF;;;;;;;GAOG;AAEH,wBAAgB,0BAA0B,CACxC,QAAQ,EAAE,wBAAwB,EAClC,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,EAChC,aAAa,EAAE,MAAM,GACpB,sBAAsB,CAmJxB"}