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.
- package/dist/cli-operation-metadata.d.ts +1 -1
- package/dist/cli-operation-metadata.js +1 -1
- package/dist/commands/check.d.ts.map +1 -1
- package/dist/commands/check.js +15 -0
- package/dist/commands/init-helpers.js +1 -1
- package/dist/commands/migrate.d.ts.map +1 -1
- package/dist/commands/migrate.js +43 -0
- package/dist/entity-body-context.d.ts +132 -0
- package/dist/entity-body-context.d.ts.map +1 -0
- package/dist/entity-body-context.js +382 -0
- package/dist/extractors/markdown.d.ts +13 -0
- package/dist/extractors/markdown.d.ts.map +1 -1
- package/dist/extractors/markdown.js +19 -2
- package/dist/intent-search.d.ts.map +1 -1
- package/dist/intent-search.js +4 -4
- package/dist/operations/bootstrap/candidate-helpers.d.ts +18 -0
- package/dist/operations/bootstrap/candidate-helpers.d.ts.map +1 -1
- package/dist/operations/bootstrap/candidate-helpers.js +35 -0
- package/dist/operations/bootstrap/candidates.d.ts.map +1 -1
- package/dist/operations/bootstrap/candidates.js +4 -2
- package/dist/operations/bootstrap/intent-claims.d.ts.map +1 -1
- package/dist/operations/bootstrap/intent-claims.js +59 -4
- package/dist/operations/bootstrap/markdown-candidates.d.ts.map +1 -1
- package/dist/operations/bootstrap/markdown-candidates.js +7 -3
- package/dist/operations/bootstrap/presentation.js +1 -1
- package/dist/operations/migration/entity-body-context.d.ts +57 -0
- package/dist/operations/migration/entity-body-context.d.ts.map +1 -0
- package/dist/operations/migration/entity-body-context.js +261 -0
- package/dist/operations/migration/polarity-values.d.ts.map +1 -1
- package/dist/operations/migration/polarity-values.js +5 -2
- package/dist/operations/migration/schema6.d.ts +2 -0
- package/dist/operations/migration/schema6.d.ts.map +1 -1
- package/dist/operations/migration/schema6.js +69 -0
- package/dist/operations/modeling/logic-modeling.d.ts.map +1 -1
- package/dist/operations/modeling/logic-modeling.js +3 -1
- package/dist/operations/modeling/model-requirement.d.ts.map +1 -1
- package/dist/operations/modeling/model-requirement.js +7 -9
- package/dist/operations/mutation/context-warning.d.ts +13 -0
- package/dist/operations/mutation/context-warning.d.ts.map +1 -0
- package/dist/operations/mutation/context-warning.js +59 -0
- package/dist/operations/mutation/origin.d.ts +2 -1
- package/dist/operations/mutation/origin.d.ts.map +1 -1
- package/dist/operations/mutation/origin.js +7 -18
- package/dist/operations/mutation/requirement-semantics.d.ts +16 -0
- package/dist/operations/mutation/requirement-semantics.d.ts.map +1 -0
- package/dist/operations/mutation/requirement-semantics.js +64 -0
- package/dist/operations/mutation/source-authoring.d.ts.map +1 -1
- package/dist/operations/mutation/source-authoring.js +10 -0
- package/dist/operations/mutation/stored-entity.d.ts +20 -0
- package/dist/operations/mutation/stored-entity.d.ts.map +1 -0
- package/dist/operations/mutation/stored-entity.js +51 -0
- package/dist/operations/mutation/upsert.d.ts +3 -2
- package/dist/operations/mutation/upsert.d.ts.map +1 -1
- package/dist/operations/mutation/upsert.js +19 -10
- package/dist/operations/mutation/validate-upsert.d.ts.map +1 -1
- package/dist/operations/mutation/validate-upsert.js +6 -1
- package/dist/operations/planning/compile-intent.d.ts +9 -0
- package/dist/operations/planning/compile-intent.d.ts.map +1 -1
- package/dist/operations/planning/compile-intent.js +49 -2
- package/dist/operations/semantic-advisor/analyze-prose.d.ts +3 -2
- package/dist/operations/semantic-advisor/analyze-prose.d.ts.map +1 -1
- package/dist/operations/semantic-advisor/analyze-prose.js +3 -41
- package/dist/operations/semantic-advisor/ingestion-boundary.d.ts.map +1 -1
- package/dist/operations/semantic-advisor/ingestion-boundary.js +10 -1
- package/dist/operations/semantic-advisor/proposition-role.d.ts +6 -0
- package/dist/operations/semantic-advisor/proposition-role.d.ts.map +1 -0
- package/dist/operations/semantic-advisor/proposition-role.js +76 -0
- package/dist/public/operations/catalog.d.ts +33 -6
- package/dist/public/operations/catalog.d.ts.map +1 -1
- package/dist/public/operations/check-executor.d.ts.map +1 -1
- package/dist/public/operations/check-executor.js +3 -0
- package/dist/public/operations/entity-context.d.ts +51 -0
- package/dist/public/operations/entity-context.d.ts.map +1 -0
- package/dist/public/operations/entity-context.js +235 -0
- package/dist/public/operations/origin-review.d.ts +1 -1
- package/dist/public/operations/origin-review.js +2 -2
- package/dist/public/operations/specs/bootstrap.d.ts +14 -2
- package/dist/public/operations/specs/bootstrap.d.ts.map +1 -1
- package/dist/public/operations/specs/bootstrap.js +8 -2
- package/dist/public/operations/specs/check-rules.generated.d.ts +1 -1
- package/dist/public/operations/specs/check-rules.generated.d.ts.map +1 -1
- package/dist/public/operations/specs/check-rules.generated.js +3 -1
- package/dist/public/operations/specs/check.d.ts +1 -1
- package/dist/public/operations/specs/mutation-schemas.d.ts +1 -1
- package/dist/public/operations/specs/mutation-schemas.d.ts.map +1 -1
- package/dist/public/operations/specs/mutation-schemas.js +10 -2
- package/dist/public/operations/specs/planning.d.ts +15 -0
- package/dist/public/operations/specs/planning.d.ts.map +1 -1
- package/dist/public/operations/specs/planning.js +15 -0
- package/dist/public/operations/specs/upsert.d.ts +3 -3
- package/dist/public/operations/specs/upsert.js +2 -2
- package/dist/public/schemas/entity.d.ts.map +1 -1
- package/dist/public/schemas/entity.js +7 -1
- package/dist/public/skills/kibi-bootstrap/SKILL.md +3 -3
- package/dist/public/skills/kibi-bootstrap/resources/bootstrap.md +5 -1
- package/dist/public/skills/kibi-usage/SKILL.md +56 -3
- package/dist/public/skills/kibi-usage/resources/source-authoring.md +5 -1
- package/dist/schemas/entity.schema.json +14 -1
- package/dist/search-ranking.d.ts.map +1 -1
- package/dist/search-ranking.js +7 -4
- package/dist/traceability/staged-consistency.d.ts +25 -0
- package/dist/traceability/staged-consistency.d.ts.map +1 -0
- package/dist/traceability/staged-consistency.js +92 -0
- package/dist/traceability/temp-kb.d.ts.map +1 -1
- package/dist/traceability/temp-kb.js +5 -0
- package/dist/utils/kb-manifest.d.ts +5 -0
- package/dist/utils/kb-manifest.d.ts.map +1 -1
- package/dist/utils/kb-manifest.js +6 -0
- package/dist/utils/rule-registry.generated.d.ts +11 -0
- package/dist/utils/rule-registry.generated.d.ts.map +1 -1
- package/dist/utils/rule-registry.generated.js +13 -0
- package/dist/utils/schema-version.d.ts +1 -1
- package/dist/utils/schema-version.d.ts.map +1 -1
- package/dist/utils/schema-version.js +3 -2
- package/package.json +2 -2
- package/schema/manifest.json +5 -0
- package/schema/validation.pl +14 -2
- package/src/public/operations/check-executor.ts +6 -0
- package/src/public/operations/entity-context.ts +304 -0
- package/src/public/operations/origin-review.ts +2 -2
- package/src/public/operations/specs/bootstrap.ts +9 -2
- package/src/public/operations/specs/check-rules.generated.ts +3 -1
- package/src/public/operations/specs/mutation-schemas.ts +10 -2
- package/src/public/operations/specs/planning.ts +18 -0
- package/src/public/operations/specs/upsert.ts +2 -2
- package/src/public/schemas/entity.ts +7 -1
- package/src/public/skills/kibi-bootstrap/SKILL.md +3 -3
- package/src/public/skills/kibi-bootstrap/resources/bootstrap.md +5 -1
- package/src/public/skills/kibi-usage/SKILL.md +56 -3
- package/src/public/skills/kibi-usage/resources/source-authoring.md +5 -1
- package/src/schemas/entity.schema.json +14 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
+
import { renderRequirementBody } from "../../entity-body-context.js";
|
|
2
3
|
import { buildStrictWriteSet } from "../../utils/strict-modeling.js";
|
|
3
4
|
import { confidenceBand, strictPlan, upsert } from "./candidate-helpers.js";
|
|
4
5
|
import { claimFor } from "./requirement-claims.js";
|
|
@@ -22,6 +23,32 @@ function digest(...parts) {
|
|
|
22
23
|
.slice(0, 16)
|
|
23
24
|
.toUpperCase();
|
|
24
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* The entity body a claim persists: the statement, then a `## Source`
|
|
28
|
+
* section with the verbatim excerpt, the knowledge source title and the
|
|
29
|
+
* claim's reference. The external source (a ticket, a page) may be gone by the
|
|
30
|
+
* next migration; the body is what remains.
|
|
31
|
+
*/
|
|
32
|
+
// implements REQ-kb-entity-body-context
|
|
33
|
+
function claimBody(source, claim) {
|
|
34
|
+
return renderRequirementBody({
|
|
35
|
+
statement: claim.statement,
|
|
36
|
+
source: {
|
|
37
|
+
excerpt: claim.excerpt,
|
|
38
|
+
title: source.title,
|
|
39
|
+
reference: claim.reference,
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Attach the claim body to an upsert step. The body is the statement plus the
|
|
45
|
+
* cited source; no context tag is added, so a claim whose source states no
|
|
46
|
+
* reason is reported by entity-context-missing instead of being acknowledged.
|
|
47
|
+
*/
|
|
48
|
+
// implements REQ-kb-entity-body-context
|
|
49
|
+
function withClaimBody(step, body) {
|
|
50
|
+
return { ...step, document: { body } };
|
|
51
|
+
}
|
|
25
52
|
/**
|
|
26
53
|
* An observation or open question from a declared source is evidence for the
|
|
27
54
|
* human, not a requirement: it becomes a cited, non-blocking observation fact
|
|
@@ -58,7 +85,7 @@ function reviewClaimCandidate(source, claim, kind, confidence) {
|
|
|
58
85
|
...(claim.excerpt ? [`excerpt:${claim.excerpt}`] : []),
|
|
59
86
|
],
|
|
60
87
|
relationships: [],
|
|
61
|
-
applyPlan: [upsert(entity)],
|
|
88
|
+
applyPlan: [withClaimBody(upsert(entity), claimBody(source, claim))],
|
|
62
89
|
};
|
|
63
90
|
}
|
|
64
91
|
/**
|
|
@@ -101,6 +128,17 @@ function conflictCandidates(declared, sources, existingIds, minConfidence) {
|
|
|
101
128
|
continue;
|
|
102
129
|
}
|
|
103
130
|
const title = `Conflict between ${refs.join(" and ")}: ${conflict.note}`;
|
|
131
|
+
const evidenceLines = conflict.claimReferences.map((ref) => {
|
|
132
|
+
const source = sources.get(ref.sourceId);
|
|
133
|
+
const claim = (declared.intentClaims ?? []).find((row) => row.sourceId === ref.sourceId && row.reference === ref.reference);
|
|
134
|
+
return [
|
|
135
|
+
`- ${[source?.title, ref.reference].filter(Boolean).join(" - ")}${claim ? `: ${claim.statement}` : ""}`,
|
|
136
|
+
...(claim?.excerpt
|
|
137
|
+
? [` > ${claim.excerpt.replace(/\s*\n\s*/g, " ")}`]
|
|
138
|
+
: []),
|
|
139
|
+
].join("\n");
|
|
140
|
+
});
|
|
141
|
+
const conflictBody = `${conflict.note}\n\n## Evidence\n\n${evidenceLines.join("\n")}\n`;
|
|
104
142
|
candidates.push({
|
|
105
143
|
candidateId,
|
|
106
144
|
entityType: "fact",
|
|
@@ -120,7 +158,7 @@ function conflictCandidates(declared, sources, existingIds, minConfidence) {
|
|
|
120
158
|
}),
|
|
121
159
|
relationships: [],
|
|
122
160
|
applyPlan: [
|
|
123
|
-
upsert({
|
|
161
|
+
withClaimBody(upsert({
|
|
124
162
|
type: "fact",
|
|
125
163
|
id,
|
|
126
164
|
title,
|
|
@@ -135,7 +173,7 @@ function conflictCandidates(declared, sources, existingIds, minConfidence) {
|
|
|
135
173
|
...new Set(conflict.claimReferences.map((ref) => `knowledge-source:${ref.sourceId}`)),
|
|
136
174
|
],
|
|
137
175
|
],
|
|
138
|
-
}),
|
|
176
|
+
}), conflictBody),
|
|
139
177
|
],
|
|
140
178
|
});
|
|
141
179
|
}
|
|
@@ -174,6 +212,21 @@ export function buildIntentClaimCandidates(declared, existingIds, minConfidence)
|
|
|
174
212
|
});
|
|
175
213
|
continue;
|
|
176
214
|
}
|
|
215
|
+
// The excerpt is the only verbatim quote from the source; without it an
|
|
216
|
+
// intent or observation would persist as a bare sentence. Only an open
|
|
217
|
+
// question may omit it.
|
|
218
|
+
if (kind !== "open_question" && !claim.excerpt) {
|
|
219
|
+
suppressed.push({
|
|
220
|
+
candidateId: "",
|
|
221
|
+
reason: "missing_excerpt",
|
|
222
|
+
sourcePath: claim.reference,
|
|
223
|
+
entityType: kind === "intent" ? "req" : "fact",
|
|
224
|
+
statement: claim.statement,
|
|
225
|
+
sourceId: source.id,
|
|
226
|
+
});
|
|
227
|
+
diagnostics.push(`Claim at ${source.id}:${claim.reference} is an ${kind === "intent" ? "intent" : "observation"} claim without an excerpt; quote the passage it came from in excerpt so the entity keeps it, then re-plan.`);
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
177
230
|
const confidence = AUTHORITY_CONFIDENCE[source.authority];
|
|
178
231
|
if (kind !== "intent") {
|
|
179
232
|
const review = reviewClaimCandidate(source, claim, kind, confidence);
|
|
@@ -222,7 +275,9 @@ export function buildIntentClaimCandidates(declared, existingIds, minConfidence)
|
|
|
222
275
|
from,
|
|
223
276
|
to,
|
|
224
277
|
})),
|
|
225
|
-
applyPlan: strictPlan(writeSet)
|
|
278
|
+
applyPlan: strictPlan(writeSet).map((step) => step.type === "req"
|
|
279
|
+
? withClaimBody(step, claimBody(source, claim))
|
|
280
|
+
: step),
|
|
226
281
|
});
|
|
227
282
|
continue;
|
|
228
283
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"markdown-candidates.d.ts","sourceRoot":"","sources":["../../../src/operations/bootstrap/markdown-candidates.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"markdown-candidates.d.ts","sourceRoot":"","sources":["../../../src/operations/bootstrap/markdown-candidates.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EACV,iBAAiB,EACjB,SAAS,EACT,gBAAgB,EACjB,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,oBAAoB,GAAG;IACjC,QAAQ,CAAC,UAAU,EAAE,SAAS,SAAS,EAAE,CAAC;IAC1C,QAAQ,CAAC,iBAAiB,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACxD,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,QAAQ,CAAC,UAAU,EAAE,SAAS,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC;CACnE,CAAC;AAuJF,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,iBAAiB,EACvB,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,EAChC,aAAa,EAAE,MAAM,GACpB,oBAAoB,CAkFtB"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { buildStrictWriteSet } from "../../utils/strict-modeling.js";
|
|
3
|
-
import { confidenceBand, slug, strictPlan, upsert, } from "./candidate-helpers.js";
|
|
3
|
+
import { bootstrapProvenance, confidenceBand, provenanceBody, provenanceRequirementBody, slug, strictPlan, upsert, withDocumentBody, } from "./candidate-helpers.js";
|
|
4
4
|
import { claimFor, normalizeClaimStatement } from "./requirement-claims.js";
|
|
5
5
|
function headingSignals(heading, sourcePath, textRef, minConfidence) {
|
|
6
6
|
const result = [];
|
|
@@ -53,7 +53,9 @@ function genericHeadingCandidate(item, heading, line, existingIds, minConfidence
|
|
|
53
53
|
confidenceBand: confidence >= 0.95 ? "high" : confidence >= 0.8 ? "medium" : "low",
|
|
54
54
|
evidence: [`generic_heading:${relativePath}#L${line}`],
|
|
55
55
|
relationships: [],
|
|
56
|
-
applyPlan: [
|
|
56
|
+
applyPlan: [
|
|
57
|
+
withDocumentBody(upsert(entity), provenanceBody(heading, bootstrapProvenance("generic markdown", `${relativePath} line ${line}`, confidence))),
|
|
58
|
+
],
|
|
57
59
|
};
|
|
58
60
|
}
|
|
59
61
|
function requirementCandidate(item, statement, line, heading, headingLine, existingIds, minConfidence) {
|
|
@@ -93,7 +95,9 @@ function requirementCandidate(item, statement, line, heading, headingLine, exist
|
|
|
93
95
|
from,
|
|
94
96
|
to,
|
|
95
97
|
})),
|
|
96
|
-
applyPlan: strictPlan(writeSet)
|
|
98
|
+
applyPlan: strictPlan(writeSet).map((step) => step.type === "req"
|
|
99
|
+
? withDocumentBody(step, provenanceRequirementBody(statement, bootstrapProvenance("generic markdown", `${relativePath} line ${line}${heading ? ` under the heading "${heading}"` : ""}`, confidence), `${relativePath}#L${line}`))
|
|
100
|
+
: step),
|
|
97
101
|
};
|
|
98
102
|
}
|
|
99
103
|
// implements REQ-KIBI-BOOTSTRAP-PLAN
|
|
@@ -234,7 +234,7 @@ export function presentBootstrap(input) {
|
|
|
234
234
|
const contextQuestions = [];
|
|
235
235
|
if (status === "needs_context") {
|
|
236
236
|
if (droppedAuthoritative.length > 0)
|
|
237
|
-
contextQuestions.push(`No declared claim from authoritative source(s) ${droppedAuthoritative.map((row) => `"${row.source.title}"`).join(", ")} could be planned; how should those claims be restated or authored before bootstrap applies
|
|
237
|
+
contextQuestions.push(`No declared claim from authoritative source(s) ${droppedAuthoritative.map((row) => `"${row.source.title}"`).join(", ")} could be planned; how should those claims be restated or authored before bootstrap applies? Intent and observation claims also need an excerpt (the verbatim source passage), which Kibi keeps in the entity's Source section.`);
|
|
238
238
|
if (!declaredContext.projectSummary)
|
|
239
239
|
contextQuestions.push("What is the one-sentence purpose of this repository?");
|
|
240
240
|
if (!declaredContext.knowledgeSources)
|
|
@@ -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,
|
|
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
|
|
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;
|
|
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;
|
|
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"}
|