kibi-cli 2.5.2 → 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 (138) 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/generate.d.ts.map +1 -1
  22. package/dist/operations/bootstrap/generate.js +24 -15
  23. package/dist/operations/bootstrap/intent-claims.d.ts.map +1 -1
  24. package/dist/operations/bootstrap/intent-claims.js +210 -5
  25. package/dist/operations/bootstrap/markdown-candidates.d.ts.map +1 -1
  26. package/dist/operations/bootstrap/markdown-candidates.js +7 -3
  27. package/dist/operations/bootstrap/presentation.d.ts +8 -0
  28. package/dist/operations/bootstrap/presentation.d.ts.map +1 -1
  29. package/dist/operations/bootstrap/presentation.js +66 -8
  30. package/dist/operations/bootstrap/types.d.ts +21 -0
  31. package/dist/operations/bootstrap/types.d.ts.map +1 -1
  32. package/dist/operations/bootstrap/types.js +10 -0
  33. package/dist/operations/migration/entity-body-context.d.ts +57 -0
  34. package/dist/operations/migration/entity-body-context.d.ts.map +1 -0
  35. package/dist/operations/migration/entity-body-context.js +261 -0
  36. package/dist/operations/migration/polarity-values.d.ts.map +1 -1
  37. package/dist/operations/migration/polarity-values.js +5 -2
  38. package/dist/operations/migration/schema6.d.ts +2 -0
  39. package/dist/operations/migration/schema6.d.ts.map +1 -1
  40. package/dist/operations/migration/schema6.js +69 -0
  41. package/dist/operations/modeling/logic-modeling.d.ts.map +1 -1
  42. package/dist/operations/modeling/logic-modeling.js +3 -1
  43. package/dist/operations/modeling/model-requirement.d.ts.map +1 -1
  44. package/dist/operations/modeling/model-requirement.js +7 -9
  45. package/dist/operations/mutation/context-warning.d.ts +13 -0
  46. package/dist/operations/mutation/context-warning.d.ts.map +1 -0
  47. package/dist/operations/mutation/context-warning.js +59 -0
  48. package/dist/operations/mutation/origin.d.ts +2 -1
  49. package/dist/operations/mutation/origin.d.ts.map +1 -1
  50. package/dist/operations/mutation/origin.js +7 -18
  51. package/dist/operations/mutation/requirement-semantics.d.ts +16 -0
  52. package/dist/operations/mutation/requirement-semantics.d.ts.map +1 -0
  53. package/dist/operations/mutation/requirement-semantics.js +64 -0
  54. package/dist/operations/mutation/source-authoring.d.ts.map +1 -1
  55. package/dist/operations/mutation/source-authoring.js +10 -0
  56. package/dist/operations/mutation/stored-entity.d.ts +20 -0
  57. package/dist/operations/mutation/stored-entity.d.ts.map +1 -0
  58. package/dist/operations/mutation/stored-entity.js +51 -0
  59. package/dist/operations/mutation/upsert.d.ts +3 -2
  60. package/dist/operations/mutation/upsert.d.ts.map +1 -1
  61. package/dist/operations/mutation/upsert.js +19 -10
  62. package/dist/operations/mutation/validate-upsert.d.ts.map +1 -1
  63. package/dist/operations/mutation/validate-upsert.js +6 -1
  64. package/dist/operations/planning/compile-intent.d.ts +9 -0
  65. package/dist/operations/planning/compile-intent.d.ts.map +1 -1
  66. package/dist/operations/planning/compile-intent.js +49 -2
  67. package/dist/operations/semantic-advisor/analyze-prose.d.ts +3 -2
  68. package/dist/operations/semantic-advisor/analyze-prose.d.ts.map +1 -1
  69. package/dist/operations/semantic-advisor/analyze-prose.js +3 -41
  70. package/dist/operations/semantic-advisor/ingestion-boundary.d.ts.map +1 -1
  71. package/dist/operations/semantic-advisor/ingestion-boundary.js +10 -1
  72. package/dist/operations/semantic-advisor/proposition-role.d.ts +6 -0
  73. package/dist/operations/semantic-advisor/proposition-role.d.ts.map +1 -0
  74. package/dist/operations/semantic-advisor/proposition-role.js +76 -0
  75. package/dist/public/operations/catalog.d.ts +78 -9
  76. package/dist/public/operations/catalog.d.ts.map +1 -1
  77. package/dist/public/operations/check-executor.d.ts.map +1 -1
  78. package/dist/public/operations/check-executor.js +3 -0
  79. package/dist/public/operations/entity-context.d.ts +51 -0
  80. package/dist/public/operations/entity-context.d.ts.map +1 -0
  81. package/dist/public/operations/entity-context.js +235 -0
  82. package/dist/public/operations/origin-review.d.ts +1 -1
  83. package/dist/public/operations/origin-review.js +2 -2
  84. package/dist/public/operations/specs/bootstrap.d.ts +59 -5
  85. package/dist/public/operations/specs/bootstrap.d.ts.map +1 -1
  86. package/dist/public/operations/specs/bootstrap.js +48 -6
  87. package/dist/public/operations/specs/check-rules.generated.d.ts +1 -1
  88. package/dist/public/operations/specs/check-rules.generated.d.ts.map +1 -1
  89. package/dist/public/operations/specs/check-rules.generated.js +3 -1
  90. package/dist/public/operations/specs/check.d.ts +1 -1
  91. package/dist/public/operations/specs/mutation-schemas.d.ts +1 -1
  92. package/dist/public/operations/specs/mutation-schemas.d.ts.map +1 -1
  93. package/dist/public/operations/specs/mutation-schemas.js +10 -2
  94. package/dist/public/operations/specs/planning.d.ts +15 -0
  95. package/dist/public/operations/specs/planning.d.ts.map +1 -1
  96. package/dist/public/operations/specs/planning.js +15 -0
  97. package/dist/public/operations/specs/upsert.d.ts +3 -3
  98. package/dist/public/operations/specs/upsert.js +2 -2
  99. package/dist/public/schemas/entity.d.ts.map +1 -1
  100. package/dist/public/schemas/entity.js +7 -1
  101. package/dist/public/skills/kibi-bootstrap/SKILL.md +13 -7
  102. package/dist/public/skills/kibi-bootstrap/resources/bootstrap.md +9 -2
  103. package/dist/public/skills/kibi-usage/SKILL.md +56 -3
  104. package/dist/public/skills/kibi-usage/resources/source-authoring.md +5 -1
  105. package/dist/schemas/entity.schema.json +14 -1
  106. package/dist/search-ranking.d.ts.map +1 -1
  107. package/dist/search-ranking.js +7 -4
  108. package/dist/traceability/staged-consistency.d.ts +25 -0
  109. package/dist/traceability/staged-consistency.d.ts.map +1 -0
  110. package/dist/traceability/staged-consistency.js +92 -0
  111. package/dist/traceability/temp-kb.d.ts.map +1 -1
  112. package/dist/traceability/temp-kb.js +5 -0
  113. package/dist/utils/kb-manifest.d.ts +5 -0
  114. package/dist/utils/kb-manifest.d.ts.map +1 -1
  115. package/dist/utils/kb-manifest.js +6 -0
  116. package/dist/utils/rule-registry.generated.d.ts +11 -0
  117. package/dist/utils/rule-registry.generated.d.ts.map +1 -1
  118. package/dist/utils/rule-registry.generated.js +13 -0
  119. package/dist/utils/schema-version.d.ts +1 -1
  120. package/dist/utils/schema-version.d.ts.map +1 -1
  121. package/dist/utils/schema-version.js +3 -2
  122. package/package.json +2 -2
  123. package/schema/manifest.json +5 -0
  124. package/schema/validation.pl +14 -2
  125. package/src/public/operations/check-executor.ts +6 -0
  126. package/src/public/operations/entity-context.ts +304 -0
  127. package/src/public/operations/origin-review.ts +2 -2
  128. package/src/public/operations/specs/bootstrap.ts +52 -5
  129. package/src/public/operations/specs/check-rules.generated.ts +3 -1
  130. package/src/public/operations/specs/mutation-schemas.ts +10 -2
  131. package/src/public/operations/specs/planning.ts +18 -0
  132. package/src/public/operations/specs/upsert.ts +2 -2
  133. package/src/public/schemas/entity.ts +7 -1
  134. package/src/public/skills/kibi-bootstrap/SKILL.md +13 -7
  135. package/src/public/skills/kibi-bootstrap/resources/bootstrap.md +9 -2
  136. package/src/public/skills/kibi-usage/SKILL.md +56 -3
  137. package/src/public/skills/kibi-usage/resources/source-authoring.md +5 -1
  138. package/src/schemas/entity.schema.json +14 -1
@@ -31,6 +31,16 @@ export const KNOWLEDGE_SOURCE_AUTHORITIES = [
31
31
  "supporting",
32
32
  "stale",
33
33
  ];
34
+ /**
35
+ * What a harvested claim is: intended behavior, an observation about how
36
+ * things are today, or a question the sources leave open. Only intent can
37
+ * become a requirement; the others stay explicit review facts.
38
+ */
39
+ export const INTENT_CLAIM_KINDS = [
40
+ "intent",
41
+ "observation",
42
+ "open_question",
43
+ ];
34
44
  export const BOOTSTRAP_PROVIDER_ORDER = [
35
45
  "typed_kibi_docs",
36
46
  "generic_repo_docs",
@@ -0,0 +1,57 @@
1
+ /** Schema 8: pin the checked meaning of requirements that never stated one. */
2
+ export declare const SEMANTIC_TEXT_PIN_CODE = "semantic_text_pin";
3
+ /** Schema 8: acknowledge current entities that lack body context. */
4
+ export declare const CONTEXT_MISSING_TAG_CODE = "context_missing_tag";
5
+ /** One authored file the schema 8 migration rewrites (front matter only). */
6
+ export type BodyContextTarget = Readonly<{
7
+ id: string;
8
+ type: string;
9
+ path: string;
10
+ before: string;
11
+ after: string;
12
+ }>;
13
+ export type BodyContextPlan = Readonly<{
14
+ targets: readonly BodyContextTarget[];
15
+ /** Files Kibi cannot edit safely, with the reason. */
16
+ skipped: readonly Readonly<{
17
+ id: string;
18
+ path: string;
19
+ reason: string;
20
+ }>[];
21
+ /** Context-less entities that already carried the tag before migration. */
22
+ alreadyTagged?: readonly string[];
23
+ }>;
24
+ /**
25
+ * Ids the schema 8 migration acknowledges: every context-less entity it tags
26
+ * plus those that already carried the tag. Recorded in the manifest, which is
27
+ * the only thing that makes the tag honored by `entity-context-missing`.
28
+ */
29
+ export declare function acknowledgedContextIds(plan: BodyContextPlan): string[];
30
+ /**
31
+ * Requirements without a front-matter `semantic_text`, pinned to the value
32
+ * the pre-schema-8 derivation produces from the body (context sections
33
+ * included), so claim spans and hashes do not move when the extractor stops
34
+ * reading context sections. Read-only.
35
+ */
36
+ export declare function planSemanticTextPins(workspaceRoot: string): BodyContextPlan;
37
+ /**
38
+ * Add one tag to a document's front matter, leaving every other byte
39
+ * unchanged. Handles an absent key, a one-line flow list and a block list of
40
+ * plain items; returns null for anything else or when the edit would not read
41
+ * back as exactly that one added tag.
42
+ */
43
+ export declare function withAddedTag(content: string, tag: string): string | null;
44
+ /**
45
+ * Current requirements, scenarios, tests, ADRs and observation facts whose
46
+ * body fails the context check and that are not yet tagged, to be tagged
47
+ * `review:context-missing`. No prose is written: the tag only acknowledges the
48
+ * gap. Read-only.
49
+ */
50
+ export declare function planContextMissingTags(workspaceRoot: string): BodyContextPlan;
51
+ /** Count targets by entity type, sorted by type. */
52
+ export declare function countByType(targets: readonly Pick<BodyContextTarget, "type">[]): Record<string, number>;
53
+ /** Pin semantic_text, then return how many requirements were rewritten. */
54
+ export declare function applySemanticTextPins(workspaceRoot: string): number;
55
+ /** Tag entities that lack context, then return how many were rewritten. */
56
+ export declare function applyContextMissingTags(workspaceRoot: string): number;
57
+ //# sourceMappingURL=entity-body-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entity-body-context.d.ts","sourceRoot":"","sources":["../../../src/operations/migration/entity-body-context.ts"],"names":[],"mappings":"AA0CA,+EAA+E;AAE/E,eAAO,MAAM,sBAAsB,sBAAsB,CAAC;AAC1D,qEAAqE;AAErE,eAAO,MAAM,wBAAwB,wBAAwB,CAAC;AAE9D,6EAA6E;AAE7E,MAAM,MAAM,iBAAiB,GAAG,QAAQ,CAAC;IACvC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf,CAAC,CAAC;AAGH,MAAM,MAAM,eAAe,GAAG,QAAQ,CAAC;IACrC,OAAO,EAAE,SAAS,iBAAiB,EAAE,CAAC;IACtC,sDAAsD;IACtD,OAAO,EAAE,SAAS,QAAQ,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,EAAE,CAAC;IAC3E,2EAA2E;IAC3E,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC,CAAC,CAAC;AAEH;;;;GAIG;AAEH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,eAAe,GAAG,MAAM,EAAE,CAOtE;AAED;;;;;GAKG;AAEH,wBAAgB,oBAAoB,CAAC,aAAa,EAAE,MAAM,GAAG,eAAe,CA8B3E;AAMD;;;;;GAKG;AAEH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAmExE;AAED;;;;;GAKG;AAEH,wBAAgB,sBAAsB,CAAC,aAAa,EAAE,MAAM,GAAG,eAAe,CAkC7E;AAED,oDAAoD;AAEpD,wBAAgB,WAAW,CACzB,OAAO,EAAE,SAAS,IAAI,CAAC,iBAAiB,EAAE,MAAM,CAAC,EAAE,GAClD,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAQxB;AASD,2EAA2E;AAE3E,wBAAgB,qBAAqB,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAEnE;AAED,2EAA2E;AAE3E,wBAAgB,uBAAuB,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAKrE"}
@@ -0,0 +1,261 @@
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 { isDeepStrictEqual } from "node:util";
19
+ import { load as loadYaml } from "js-yaml";
20
+ import { CONTEXT_MISSING_TAG, assessContext, isContextAcknowledged, } from "../../entity-body-context.js";
21
+ import { legacyRequirementSemanticText } from "../../extractors/markdown.js";
22
+ import { authoredSupersededIds, contextEntityOf, isCurrentAuthoredEntity, listContextAuthoredEntities, readAuthoredEntity, } from "../../public/operations/entity-context.js";
23
+ import { readKbManifest, writeKbManifest } from "../../utils/kb-manifest.js";
24
+ import { listLaneMarkdownFiles, readText, sliceFrontmatter, withTopLevelField, writeFileAtomically, } from "./kb-sources.js";
25
+ /** Schema 8: pin the checked meaning of requirements that never stated one. */
26
+ // implements REQ-kb-entity-body-context, REQ-cli-schema-migration
27
+ export const SEMANTIC_TEXT_PIN_CODE = "semantic_text_pin";
28
+ /** Schema 8: acknowledge current entities that lack body context. */
29
+ // implements REQ-kb-entity-body-context, REQ-cli-schema-migration
30
+ export const CONTEXT_MISSING_TAG_CODE = "context_missing_tag";
31
+ /**
32
+ * Ids the schema 8 migration acknowledges: every context-less entity it tags
33
+ * plus those that already carried the tag. Recorded in the manifest, which is
34
+ * the only thing that makes the tag honored by `entity-context-missing`.
35
+ */
36
+ // implements REQ-kb-entity-body-context, REQ-cli-schema-migration
37
+ export function acknowledgedContextIds(plan) {
38
+ return [
39
+ ...new Set([
40
+ ...plan.targets.map((target) => target.id),
41
+ ...(plan.alreadyTagged ?? []),
42
+ ]),
43
+ ].sort();
44
+ }
45
+ /**
46
+ * Requirements without a front-matter `semantic_text`, pinned to the value
47
+ * the pre-schema-8 derivation produces from the body (context sections
48
+ * included), so claim spans and hashes do not move when the extractor stops
49
+ * reading context sections. Read-only.
50
+ */
51
+ // implements REQ-kb-entity-body-context, REQ-cli-schema-migration
52
+ export function planSemanticTextPins(workspaceRoot) {
53
+ const targets = [];
54
+ const skipped = [];
55
+ for (const file of listLaneMarkdownFiles(workspaceRoot, ["requirements"])) {
56
+ const before = readText(file.absolutePath);
57
+ if (before === null)
58
+ continue;
59
+ const entity = readAuthoredEntity(before, file.relativePath);
60
+ if (entity === null || entity.type !== "req")
61
+ continue;
62
+ const pinned = entity.data.semantic_text;
63
+ if (typeof pinned === "string" && pinned.trim() !== "")
64
+ continue;
65
+ const derived = legacyRequirementSemanticText(entity.body);
66
+ if (derived === "")
67
+ continue;
68
+ const after = withTopLevelField(before, "semantic_text", derived);
69
+ if (after === null) {
70
+ skipped.push({
71
+ id: entity.id,
72
+ path: file.relativePath,
73
+ reason: "semantic_text could not be edited safely",
74
+ });
75
+ continue;
76
+ }
77
+ targets.push({
78
+ id: entity.id,
79
+ type: entity.type,
80
+ path: file.relativePath,
81
+ before,
82
+ after,
83
+ });
84
+ }
85
+ return { targets, skipped };
86
+ }
87
+ function isRecord(value) {
88
+ return value !== null && typeof value === "object" && !Array.isArray(value);
89
+ }
90
+ /**
91
+ * Add one tag to a document's front matter, leaving every other byte
92
+ * unchanged. Handles an absent key, a one-line flow list and a block list of
93
+ * plain items; returns null for anything else or when the edit would not read
94
+ * back as exactly that one added tag.
95
+ */
96
+ // implements REQ-kb-entity-body-context, REQ-cli-schema-migration
97
+ export function withAddedTag(content, tag) {
98
+ const slice = sliceFrontmatter(content);
99
+ if (slice === null)
100
+ return null;
101
+ let before;
102
+ try {
103
+ before = loadYaml(slice.text);
104
+ }
105
+ catch {
106
+ return null;
107
+ }
108
+ if (!isRecord(before))
109
+ return null;
110
+ const existing = before.tags;
111
+ if (existing !== undefined && existing !== null && !Array.isArray(existing))
112
+ return null;
113
+ const eol = slice.eol;
114
+ const lines = slice.text.split(/\r?\n/);
115
+ // The text ends with a line break, so the last element is empty.
116
+ const body = lines.slice(0, -1);
117
+ const keyIndex = body.findIndex((line) => /^tags[ \t]*:/.test(line));
118
+ let next;
119
+ if (keyIndex < 0) {
120
+ next = [...body, "tags:", ` - ${tag}`];
121
+ }
122
+ else {
123
+ const line = body[keyIndex] ?? "";
124
+ const rest = line.slice(line.indexOf(":") + 1).trim();
125
+ if (rest.startsWith("[") && rest.endsWith("]")) {
126
+ const inner = rest.slice(1, -1).trim();
127
+ const edited = `${line.slice(0, line.indexOf(":") + 1)} [${inner === "" ? tag : `${inner}, ${tag}`}]`;
128
+ next = [...body.slice(0, keyIndex), edited, ...body.slice(keyIndex + 1)];
129
+ }
130
+ else if (rest === "" || rest === "null" || rest === "~") {
131
+ let end = keyIndex + 1;
132
+ let indent = " ";
133
+ while (end < body.length) {
134
+ const item = /^([ \t]*)-[ \t]+\S/.exec(body[end] ?? "");
135
+ if (item === null)
136
+ break;
137
+ if (end === keyIndex + 1)
138
+ indent = item[1] ?? "";
139
+ end += 1;
140
+ }
141
+ const head = rest === "" ? line : `${line.slice(0, line.indexOf(":") + 1)}`;
142
+ next = [
143
+ ...body.slice(0, keyIndex),
144
+ head,
145
+ ...body.slice(keyIndex + 1, end),
146
+ `${indent}- ${tag}`,
147
+ ...body.slice(end),
148
+ ];
149
+ }
150
+ else {
151
+ return null;
152
+ }
153
+ }
154
+ const text = `${next.join(eol)}${eol}`;
155
+ try {
156
+ const after = loadYaml(text);
157
+ if (!isRecord(after))
158
+ return null;
159
+ const { tags: beforeTags, ...beforeRest } = before;
160
+ const { tags: afterTags, ...afterRest } = after;
161
+ const expected = [...(Array.isArray(beforeTags) ? beforeTags : []), tag];
162
+ if (!isDeepStrictEqual(afterTags, expected) ||
163
+ !isDeepStrictEqual(beforeRest, afterRest)) {
164
+ return null;
165
+ }
166
+ }
167
+ catch {
168
+ return null;
169
+ }
170
+ return `${slice.prefix}${text}${slice.suffix}`;
171
+ }
172
+ /**
173
+ * Current requirements, scenarios, tests, ADRs and observation facts whose
174
+ * body fails the context check and that are not yet tagged, to be tagged
175
+ * `review:context-missing`. No prose is written: the tag only acknowledges the
176
+ * gap. Read-only.
177
+ */
178
+ // implements REQ-kb-entity-body-context, REQ-cli-schema-migration
179
+ export function planContextMissingTags(workspaceRoot) {
180
+ const entities = listContextAuthoredEntities(workspaceRoot);
181
+ const superseded = authoredSupersededIds(workspaceRoot, entities);
182
+ const targets = [];
183
+ const skipped = [];
184
+ const alreadyTagged = [];
185
+ for (const entity of entities) {
186
+ if (!isCurrentAuthoredEntity(entity, superseded))
187
+ continue;
188
+ const view = contextEntityOf(entity);
189
+ if (assessContext(entity.type, entity.body, view).ok)
190
+ continue;
191
+ if (isContextAcknowledged(view.tags)) {
192
+ alreadyTagged.push(entity.id);
193
+ continue;
194
+ }
195
+ const before = readText(`${workspaceRoot}/${entity.path}`);
196
+ if (before === null)
197
+ continue;
198
+ const after = withAddedTag(before, CONTEXT_MISSING_TAG);
199
+ if (after === null) {
200
+ skipped.push({
201
+ id: entity.id,
202
+ path: entity.path,
203
+ reason: "tags could not be edited safely",
204
+ });
205
+ continue;
206
+ }
207
+ targets.push({
208
+ id: entity.id,
209
+ type: entity.type,
210
+ path: entity.path,
211
+ before,
212
+ after,
213
+ });
214
+ }
215
+ return { targets, skipped, alreadyTagged };
216
+ }
217
+ /** Count targets by entity type, sorted by type. */
218
+ // implements REQ-kb-entity-body-context, REQ-cli-schema-migration
219
+ export function countByType(targets) {
220
+ const counts = {};
221
+ for (const target of targets) {
222
+ counts[target.type] = (counts[target.type] ?? 0) + 1;
223
+ }
224
+ return Object.fromEntries(Object.entries(counts).sort(([left], [right]) => left.localeCompare(right)));
225
+ }
226
+ function applyPlan(workspaceRoot, plan) {
227
+ for (const target of plan.targets) {
228
+ writeFileAtomically(`${workspaceRoot}/${target.path}`, target.after);
229
+ }
230
+ return plan.targets.length;
231
+ }
232
+ /** Pin semantic_text, then return how many requirements were rewritten. */
233
+ // implements REQ-kb-entity-body-context, REQ-cli-schema-migration
234
+ export function applySemanticTextPins(workspaceRoot) {
235
+ return applyPlan(workspaceRoot, planSemanticTextPins(workspaceRoot));
236
+ }
237
+ /** Tag entities that lack context, then return how many were rewritten. */
238
+ // implements REQ-kb-entity-body-context, REQ-cli-schema-migration
239
+ export function applyContextMissingTags(workspaceRoot) {
240
+ const plan = planContextMissingTags(workspaceRoot);
241
+ const count = applyPlan(workspaceRoot, plan);
242
+ recordContextAcknowledged(workspaceRoot, acknowledgedContextIds(plan));
243
+ return count;
244
+ }
245
+ /**
246
+ * Record the acknowledged ids in the manifest. The tag alone is never honored
247
+ * by `entity-context-missing`; the manifest is what the migration vouches with.
248
+ */
249
+ function recordContextAcknowledged(workspaceRoot, ids) {
250
+ if (ids.length === 0)
251
+ return;
252
+ const manifest = readKbManifest(workspaceRoot);
253
+ if (manifest === null)
254
+ return;
255
+ writeKbManifest(workspaceRoot, {
256
+ ...manifest,
257
+ contextAcknowledged: [
258
+ ...new Set([...(manifest.contextAcknowledged ?? []), ...ids]),
259
+ ].sort(),
260
+ });
261
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"polarity-values.d.ts","sourceRoot":"","sources":["../../../src/operations/migration/polarity-values.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,4BAA4B,4BAA4B,CAAC;AAEtE,6EAA6E;AAE7E,wBAAgB,yBAAyB,CACvC,aAAa,EAAE,MAAM,GACpB,SAAS;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAAE,CA+DxE;AAGD,wBAAgB,0BAA0B,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAKxE"}
1
+ {"version":3,"file":"polarity-values.d.ts","sourceRoot":"","sources":["../../../src/operations/migration/polarity-values.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,4BAA4B,4BAA4B,CAAC;AAEtE,6EAA6E;AAE7E,wBAAgB,yBAAyB,CACvC,aAAa,EAAE,MAAM,GACpB,SAAS;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAAE,CAiExE;AAGD,wBAAgB,0BAA0B,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAKxE"}
@@ -35,7 +35,10 @@ export function planPolarityValueBackfill(workspaceRoot) {
35
35
  typeof data.property_key !== "string")
36
36
  throw new Error(`Cannot migrate polarity fact ${file.relativePath}: subject_key and property_key are required`);
37
37
  const after = `${slice.prefix}${slice.text}operator: eq${slice.eol}value_type: bool${slice.eol}value_bool: true${slice.eol}${slice.suffix}`;
38
- const parsed = loadYaml(sliceFrontmatter(after).text);
38
+ const afterFrontmatter = sliceFrontmatter(after);
39
+ if (!afterFrontmatter)
40
+ throw new Error(`Polarity migration could not verify ${file.relativePath}`);
41
+ const parsed = loadYaml(afterFrontmatter.text);
39
42
  if (parsed.operator !== "eq" ||
40
43
  parsed.value_type !== "bool" ||
41
44
  parsed.value_bool !== true)
@@ -43,7 +46,7 @@ export function planPolarityValueBackfill(workspaceRoot) {
43
46
  targets.push({
44
47
  id: typeof data.id === "string"
45
48
  ? data.id
46
- : file.relativePath.split("/").at(-1).slice(0, -3),
49
+ : (file.relativePath.split("/").at(-1) ?? "").slice(0, -3),
47
50
  path: file.relativePath,
48
51
  before,
49
52
  after,
@@ -2,6 +2,8 @@ import { type MigrationAction } from "../../public/operations/migration-plan.js"
2
2
  import { CLOSE_SUPERSEDED_REQUIREMENTS_CODE, MIGRATION_SYNC_ACTION_ID, MIGRATION_SYNC_CODE, SOURCE_PATH_REWRITE_CODE } from "../../public/operations/schema6-check-actions.js";
3
3
  /** The KB schema generation that introduced entity `origin`. */
4
4
  export declare const ORIGIN_SCHEMA_VERSION = 6;
5
+ /** The KB schema generation that requires body context on current entities. */
6
+ export declare const BODY_CONTEXT_SCHEMA_VERSION = 8;
5
7
  /** Automatic: re-derive a drifted inventory with the current advisor. */
6
8
  export declare const SEMANTIC_INVENTORY_REDERIVE_CODE = "semantic_inventory_rederive";
7
9
  /** Review: a drifted inventory Kibi cannot re-derive safely. */
@@ -1 +1 @@
1
- {"version":3,"file":"schema6.d.ts","sourceRoot":"","sources":["../../../src/operations/migration/schema6.ts"],"names":[],"mappings":"AAuBA,OAAO,EACL,KAAK,eAAe,EAErB,MAAM,2CAA2C,CAAC;AACnD,OAAO,EAEL,kCAAkC,EAClC,wBAAwB,EACxB,mBAAmB,EAEnB,wBAAwB,EAOzB,MAAM,kDAAkD,CAAC;AA2B1D,gEAAgE;AAEhE,eAAO,MAAM,qBAAqB,IAAI,CAAC;AAEvC,yEAAyE;AAEzE,eAAO,MAAM,gCAAgC,gCAAgC,CAAC;AAC9E,gEAAgE;AAEhE,eAAO,MAAM,8BAA8B,8BAA8B,CAAC;AAC1E,yEAAyE;AAEzE,eAAO,MAAM,2BAA2B,2BAA2B,CAAC;AAEpE,eAAO,MAAM,gCAAgC,2BAA2B,CAAC;AACzE,OAAO,EACL,kCAAkC,EAClC,wBAAwB,EACxB,mBAAmB,EACnB,wBAAwB,GACzB,CAAC;AAsEF;;;GAGG;AAEH,wBAAgB,+BAA+B,CAC7C,aAAa,EAAE,MAAM,GACpB,KAAK,CAAC;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAsDnE;AAGD,MAAM,MAAM,wBAAwB,GAAG,QAAQ,CAAC;IAC9C,OAAO,EAAE,SAAS,eAAe,EAAE,CAAC;IACpC,uDAAuD;IACvD,sBAAsB,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1C,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;CAChC,CAAC,CAAC;AAEH;;;;;;GAMG;AAEH,wBAAgB,6BAA6B,CAAC,KAAK,EAAE;IACnD,aAAa,EAAE,MAAM,CAAC;IACtB,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;CACrC,GAAG,wBAAwB,CA8F3B;AAED;;;;;;GAMG;AAEH,wBAAgB,2BAA2B,CAAC,aAAa,EAAE,MAAM,GAAG;IAClE,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,sBAAsB,EAAE,MAAM,EAAE,CAAC;CAClC,CAoCA;AAED,qEAAqE;AAErE,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,SAAS,MAAM,EAAE,GAC3B,eAAe,CAEjB;AA0CD,KAAK,YAAY,GAAG,QAAQ,CAAC;IAC3B,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB,CAAC,CAAC;AAEH,4DAA4D;AAE5D,wBAAsB,2BAA2B,CAC/C,MAAM,EAAE,eAAe,EACvB,OAAO,EAAE,YAAY,GACpB,OAAO,CAAC,IAAI,CAAC,CA8Df;AAGD,eAAO,MAAM,uBAAuB,EAAE,WAAW,CAAC,MAAM,CAOtD,CAAC"}
1
+ {"version":3,"file":"schema6.d.ts","sourceRoot":"","sources":["../../../src/operations/migration/schema6.ts"],"names":[],"mappings":"AAuBA,OAAO,EACL,KAAK,eAAe,EAErB,MAAM,2CAA2C,CAAC;AACnD,OAAO,EAEL,kCAAkC,EAClC,wBAAwB,EACxB,mBAAmB,EAEnB,wBAAwB,EAOzB,MAAM,kDAAkD,CAAC;AAoC1D,gEAAgE;AAEhE,eAAO,MAAM,qBAAqB,IAAI,CAAC;AAEvC,+EAA+E;AAE/E,eAAO,MAAM,2BAA2B,IAAI,CAAC;AAE7C,yEAAyE;AAEzE,eAAO,MAAM,gCAAgC,gCAAgC,CAAC;AAC9E,gEAAgE;AAEhE,eAAO,MAAM,8BAA8B,8BAA8B,CAAC;AAC1E,yEAAyE;AAEzE,eAAO,MAAM,2BAA2B,2BAA2B,CAAC;AAEpE,eAAO,MAAM,gCAAgC,2BAA2B,CAAC;AACzE,OAAO,EACL,kCAAkC,EAClC,wBAAwB,EACxB,mBAAmB,EACnB,wBAAwB,GACzB,CAAC;AAsEF;;;GAGG;AAEH,wBAAgB,+BAA+B,CAC7C,aAAa,EAAE,MAAM,GACpB,KAAK,CAAC;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAsDnE;AAGD,MAAM,MAAM,wBAAwB,GAAG,QAAQ,CAAC;IAC9C,OAAO,EAAE,SAAS,eAAe,EAAE,CAAC;IACpC,uDAAuD;IACvD,sBAAsB,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1C,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;CAChC,CAAC,CAAC;AAEH;;;;;;GAMG;AAEH,wBAAgB,6BAA6B,CAAC,KAAK,EAAE;IACnD,aAAa,EAAE,MAAM,CAAC;IACtB,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;CACrC,GAAG,wBAAwB,CA6J3B;AAED;;;;;;GAMG;AAEH,wBAAgB,2BAA2B,CAAC,aAAa,EAAE,MAAM,GAAG;IAClE,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,sBAAsB,EAAE,MAAM,EAAE,CAAC;CAClC,CAoCA;AAED,qEAAqE;AAErE,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,SAAS,MAAM,EAAE,GAC3B,eAAe,CAEjB;AA0CD,KAAK,YAAY,GAAG,QAAQ,CAAC;IAC3B,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB,CAAC,CAAC;AAEH,4DAA4D;AAE5D,wBAAsB,2BAA2B,CAC/C,MAAM,EAAE,eAAe,EACvB,OAAO,EAAE,YAAY,GACpB,OAAO,CAAC,IAAI,CAAC,CAsEf;AAGD,eAAO,MAAM,uBAAuB,EAAE,WAAW,CAAC,MAAM,CAStD,CAAC"}
@@ -20,6 +20,7 @@ import { extractFromMarkdown, } from "../../extractors/markdown.js";
20
20
  import { migrationAction, } from "../../public/operations/migration-plan.js";
21
21
  import { CLOSE_SUPERSEDED_REQUIREMENTS_ACTION_ID, CLOSE_SUPERSEDED_REQUIREMENTS_CODE, MIGRATION_SYNC_ACTION_ID, MIGRATION_SYNC_CODE, SOURCE_PATH_REWRITE_ACTION_ID, SOURCE_PATH_REWRITE_CODE, closeSupersededRequirementsActionInput, exceptionUnapprovedActionInput, migrationSyncActionInput, sourcePathReviewActionInput, sourcePathRewriteActionInput, supersessionCycleReviewActionInput, } from "../../public/operations/schema6-check-actions.js";
22
22
  import { readAllShards } from "../../relationships/shards.js";
23
+ import { CONTEXT_MISSING_TAG_CODE, SEMANTIC_TEXT_PIN_CODE, applyContextMissingTags, applySemanticTextPins, countByType, planContextMissingTags, planSemanticTextPins, } from "./entity-body-context.js";
23
24
  import { applyInventoryRederivation, planInventoryRederivation, } from "./inventory-rederive.js";
24
25
  import { listLaneMarkdownFiles } from "./kb-sources.js";
25
26
  import { applyOriginBackfill, planOriginBackfill } from "./origin-backfill.js";
@@ -29,6 +30,9 @@ import { applySupersededClosures, planSupersededClosures, } from "./superseded-c
29
30
  /** The KB schema generation that introduced entity `origin`. */
30
31
  // implements REQ-kibi-schema6-migration, REQ-cli-schema-migration
31
32
  export const ORIGIN_SCHEMA_VERSION = 6;
33
+ /** The KB schema generation that requires body context on current entities. */
34
+ // implements REQ-kb-entity-body-context, REQ-cli-schema-migration
35
+ export const BODY_CONTEXT_SCHEMA_VERSION = 8;
32
36
  /** Automatic: re-derive a drifted inventory with the current advisor. */
33
37
  // implements REQ-kibi-schema6-migration, REQ-cli-schema-migration
34
38
  export const SEMANTIC_INVENTORY_REDERIVE_CODE = "semantic_inventory_rederive";
@@ -190,6 +194,61 @@ export function buildSchema6MigrationFragment(input) {
190
194
  },
191
195
  }));
192
196
  }
197
+ // Schema 8: pin the checked meaning, then acknowledge missing context. A
198
+ // missing or invalid version upgrades through every step, so it is planned.
199
+ if (input.currentSchemaVersion === null ||
200
+ input.currentSchemaVersion < BODY_CONTEXT_SCHEMA_VERSION) {
201
+ const pins = planSemanticTextPins(input.workspaceRoot);
202
+ if (pins.targets.length > 0) {
203
+ const id = "semantic-text-pin";
204
+ sourceRewriteActionIds.push(id);
205
+ actions.push(migrationAction({
206
+ id,
207
+ code: SEMANTIC_TEXT_PIN_CODE,
208
+ category: "schema",
209
+ safety: "automatic",
210
+ autoApplicable: true,
211
+ invocation: {
212
+ kind: "cli",
213
+ command_argv: ["kibi", "migrate", "--yes"],
214
+ },
215
+ affectedEntityIds: pins.targets.map((row) => row.id),
216
+ affectedFiles: pins.targets.map((row) => row.path),
217
+ postconditions: [{ requirementsWithoutSemanticText: 0 }],
218
+ evidence: {
219
+ reason: "Schema 8 stops reading context sections (Context, Rationale, Why, Background, Source, Notes, Evidence) as part of a requirement's meaning. Requirements that never stated semantic_text get the value the old derivation produced, so claim spans and hashes do not move.",
220
+ count: pins.targets.length,
221
+ preserves: "every other front matter key and the body bytes",
222
+ },
223
+ }));
224
+ }
225
+ const tags = planContextMissingTags(input.workspaceRoot);
226
+ if (tags.targets.length > 0) {
227
+ const id = "context-missing-tag";
228
+ sourceRewriteActionIds.push(id);
229
+ actions.push(migrationAction({
230
+ id,
231
+ code: CONTEXT_MISSING_TAG_CODE,
232
+ category: "schema",
233
+ safety: "automatic",
234
+ autoApplicable: true,
235
+ invocation: {
236
+ kind: "cli",
237
+ command_argv: ["kibi", "migrate", "--yes"],
238
+ },
239
+ dependsOn: pins.targets.length > 0 ? ["semantic-text-pin"] : [],
240
+ affectedEntityIds: tags.targets.map((row) => row.id),
241
+ affectedFiles: tags.targets.map((row) => row.path),
242
+ postconditions: [{ rule: "entity-context-missing", findings: 0 }],
243
+ evidence: {
244
+ reason: "Schema 8 blocks current requirements, scenarios, tests, ADRs and observation facts whose body states no context. Existing ones are tagged review:context-missing (acknowledged legacy, counted by entity-context-acknowledged); no prose is written and no reason is invented.",
245
+ count: tags.targets.length,
246
+ byType: countByType(tags.targets),
247
+ preserves: "every other front matter key and the body bytes",
248
+ },
249
+ }));
250
+ }
251
+ }
193
252
  const drift = planInventoryRederivation(input.workspaceRoot);
194
253
  for (const plan of drift) {
195
254
  const action = plan.safe ? rederiveAction(plan) : reviewAction(plan);
@@ -330,6 +389,14 @@ export async function applySchema6MigrationAction(action, context) {
330
389
  applyPolarityValueBackfill(context.workspaceRoot);
331
390
  return;
332
391
  }
392
+ case SEMANTIC_TEXT_PIN_CODE: {
393
+ applySemanticTextPins(context.workspaceRoot);
394
+ return;
395
+ }
396
+ case CONTEXT_MISSING_TAG_CODE: {
397
+ applyContextMissingTags(context.workspaceRoot);
398
+ return;
399
+ }
333
400
  case SEMANTIC_INVENTORY_REDERIVE_CODE: {
334
401
  const requirementId = action.affectedEntityIds[0];
335
402
  if (requirementId === undefined)
@@ -371,6 +438,8 @@ export async function applySchema6MigrationAction(action, context) {
371
438
  // implements REQ-kibi-schema6-migration, REQ-cli-schema-migration
372
439
  export const SCHEMA6_AUTOMATIC_CODES = new Set([
373
440
  POLARITY_VALUE_BACKFILL_CODE,
441
+ SEMANTIC_TEXT_PIN_CODE,
442
+ CONTEXT_MISSING_TAG_CODE,
374
443
  SEMANTIC_INVENTORY_REDERIVE_CODE,
375
444
  ENTITY_ORIGIN_BACKFILL_CODE,
376
445
  CLOSE_SUPERSEDED_REQUIREMENTS_CODE,
@@ -1 +1 @@
1
- {"version":3,"file":"logic-modeling.d.ts","sourceRoot":"","sources":["../../../src/operations/modeling/logic-modeling.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,WAAW,EAIjB,MAAM,mBAAmB,CAAC;AAQ3B,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACjD,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,UAAU,EAAE,WAAW,CAAC;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,SAAS,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACpD;AAUD,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,mBAAmB,GACzB,oBAAoB,CAkHtB"}
1
+ {"version":3,"file":"logic-modeling.d.ts","sourceRoot":"","sources":["../../../src/operations/modeling/logic-modeling.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,WAAW,EAIjB,MAAM,mBAAmB,CAAC;AAS3B,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACjD,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,UAAU,EAAE,WAAW,CAAC;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,SAAS,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACpD;AAUD,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,mBAAmB,GACzB,oBAAoB,CAoHtB"}
@@ -1,6 +1,7 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import { logicSemanticKey, utf8Span, validateLogicIr, } from "../../logic/ir.js";
3
3
  import { modeledClaimRole, normalizeSemanticClause, semanticClaimKey, } from "../semantic-advisor/clauses.js";
4
+ import { advisorPropositionRole } from "../semantic-advisor/proposition-role.js";
4
5
  import { semanticSourceHash } from "../semantic-advisor/shared.js";
5
6
  function shortId(value) {
6
7
  return createHash("sha256")
@@ -98,7 +99,8 @@ export function buildLogicApplyPlan(input) {
98
99
  {
99
100
  claim_key: claimKey,
100
101
  claim_text: claimText,
101
- role: modeledClaimRole(claimText, validation.normalized.modality),
102
+ role: advisorPropositionRole(input.text.trim(), claimKey) ??
103
+ modeledClaimRole(claimText, validation.normalized.modality),
102
104
  status: "modeled",
103
105
  span,
104
106
  semantic_key: semanticKey,
@@ -1 +1 @@
1
- {"version":3,"file":"model-requirement.d.ts","sourceRoot":"","sources":["../../../src/operations/modeling/model-requirement.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AAgBjF,OAAO,EACL,yBAAyB,EACzB,uBAAuB,EACxB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,iCAAiC,EACjC,uBAAuB,EACxB,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EACV,oBAAoB,EACpB,sBAAsB,EACvB,MAAM,wBAAwB,CAAC;AAUhC,YAAY,EACV,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,wBAAwB,CAAC;AAkNhC,OAAO,EACL,iCAAiC,EACjC,uBAAuB,EACvB,yBAAyB,EACzB,uBAAuB,GACxB,CAAC;AAIF,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,EAAE;IACP,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB,GACA,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CA4CzB;AA+OD,wBAAsB,4BAA4B,CAChD,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAIxB;AAED,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,oBAAoB,EAC1B,aAAa,EAAE,MAAM,EACrB,OAAO,CAAC,EAAE,gBAAgB,GACzB,OAAO,CAAC,sBAAsB,CAAC,CAgHjC;AAED,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,oBAAoB,EAC1B,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,sBAAsB,CAAC,CAajC"}
1
+ {"version":3,"file":"model-requirement.d.ts","sourceRoot":"","sources":["../../../src/operations/modeling/model-requirement.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AAgBjF,OAAO,EACL,yBAAyB,EACzB,uBAAuB,EACxB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,iCAAiC,EACjC,uBAAuB,EACxB,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EACV,oBAAoB,EACpB,sBAAsB,EACvB,MAAM,wBAAwB,CAAC;AAUhC,YAAY,EACV,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,wBAAwB,CAAC;AAkNhC,OAAO,EACL,iCAAiC,EACjC,uBAAuB,EACvB,yBAAyB,EACzB,uBAAuB,GACxB,CAAC;AAIF,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,EAAE;IACP,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB,GACA,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CA+CzB;AAwOD,wBAAsB,4BAA4B,CAChD,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAIxB;AAED,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,oBAAoB,EAC1B,aAAa,EAAE,MAAM,EACrB,OAAO,CAAC,EAAE,gBAAgB,GACzB,OAAO,CAAC,sBAAsB,CAAC,CAgHjC;AAED,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,oBAAoB,EAC1B,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,sBAAsB,CAAC,CAajC"}
@@ -1,9 +1,9 @@
1
1
  import { buildStrictWriteSet, } from "../../public/check-types.js";
2
2
  import { readKbManifestStatus } from "../../utils/kb-manifest.js";
3
3
  import { isConventionalSubjectKey, normalizeSubjectKey, } from "../../utils/strict-modeling.js";
4
- import { propositionRole } from "../semantic-advisor/analyze-prose.js";
5
- import { extractSemanticClauses, modeledClaimRole, normalizeSemanticClause, semanticClaimKey, } from "../semantic-advisor/clauses.js";
4
+ import { modeledClaimRole, normalizeSemanticClause, semanticClaimKey, } from "../semantic-advisor/clauses.js";
6
5
  import { detectConditionalRule } from "../semantic-advisor/conditional-rules.js";
6
+ import { advisorPropositionRole } from "../semantic-advisor/proposition-role.js";
7
7
  import { semanticSourceHash } from "../semantic-advisor/shared.js";
8
8
  import { buildLogicApplyPlan } from "./logic-modeling.js";
9
9
  import { strictWriteSetToApplyPlan, writeSetPrimaryEntityId, } from "./requirement-applyplan.js";
@@ -198,7 +198,9 @@ export function annotateModelRequirementStep(step, context) {
198
198
  {
199
199
  claim_key: context.claimKey,
200
200
  claim_text: normalizedClaimText,
201
- role: modeledClaimRole(claimText),
201
+ role: advisorPropositionRole(claimText, context.claimKey, [
202
+ claimText,
203
+ ]) ?? modeledClaimRole(claimText),
202
204
  status: "modeled",
203
205
  span: {
204
206
  start: 0,
@@ -235,10 +237,6 @@ function unresolvedObservationStep(step) {
235
237
  // ingestion compares the persisted inventory with it. A rule modality alone
236
238
  // would call "X must not happen unless C" normative where the advisor reads an
237
239
  // exception, so the role comes from the advisor's own clause analysis.
238
- function advisorRole(semanticText, claimKey) {
239
- const clause = extractSemanticClauses(semanticText).find((entry) => entry.claim_key === claimKey);
240
- return clause ? propositionRole(clause.text, clause.normative) : null;
241
- }
242
240
  function withAdvisorRoles(plan) {
243
241
  return plan.map((step) => {
244
242
  if (step.type !== "req")
@@ -257,7 +255,7 @@ function withAdvisorRoles(plan) {
257
255
  return entry;
258
256
  const row = entry;
259
257
  const role = typeof row.claim_key === "string"
260
- ? advisorRole(semanticText, row.claim_key)
258
+ ? advisorPropositionRole(semanticText, row.claim_key)
261
259
  : null;
262
260
  return role === null ? row : { ...row, role };
263
261
  }),
@@ -351,7 +349,7 @@ async function unresolvedConditionalResult(args, extracted, reason, workspaceRoo
351
349
  {
352
350
  claim_key: claimKey,
353
351
  claim_text: claimText,
354
- role: advisorRole(semanticText, claimKey) ??
352
+ role: advisorPropositionRole(semanticText, claimKey) ??
355
353
  modeledClaimRole(claimText),
356
354
  status: "ontology_gap",
357
355
  span: {
@@ -0,0 +1,13 @@
1
+ import type { UpsertInput } from "./types.js";
2
+ /**
3
+ * The body the authored document has, or will have, after this upsert: the
4
+ * written file when there is one, the supplied body, the preserved body of
5
+ * the entity's existing document, or the default a new requirement gets.
6
+ */
7
+ export declare function upsertDocumentBody(input: UpsertInput, entity: Readonly<Record<string, unknown>>, workspaceRoot: string, writtenPath?: string): string;
8
+ /**
9
+ * kb_upsert warning for a written entity whose body lacks context. The same
10
+ * finding blocks `kb_check` as entity-context-missing, so agents see it first.
11
+ */
12
+ export declare function entityContextWarnings(input: UpsertInput, entity: Readonly<Record<string, unknown>>, workspaceRoot: string, writtenPath?: string): readonly string[];
13
+ //# sourceMappingURL=context-warning.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-warning.d.ts","sourceRoot":"","sources":["../../../src/operations/mutation/context-warning.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAgB9C;;;;GAIG;AAEH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACzC,aAAa,EAAE,MAAM,EACrB,WAAW,CAAC,EAAE,MAAM,GACnB,MAAM,CAYR;AAED;;;GAGG;AAEH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACzC,aAAa,EAAE,MAAM,EACrB,WAAW,CAAC,EAAE,MAAM,GACnB,SAAS,MAAM,EAAE,CA2BnB"}