kibi-cli 2.21.0 → 2.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli-operation-metadata.d.ts +1 -1
- package/dist/cli-operation-metadata.js +1 -1
- package/dist/cli-register-foundation.d.ts.map +1 -1
- package/dist/cli-register-foundation.js +1 -0
- package/dist/commands/check.d.ts +0 -1
- package/dist/commands/check.d.ts.map +1 -1
- package/dist/commands/check.js +47 -111
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +107 -5
- package/dist/commands/init-helpers.d.ts +14 -1
- package/dist/commands/init-helpers.d.ts.map +1 -1
- package/dist/commands/init-helpers.js +49 -10
- package/dist/commands/init.d.ts +1 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +27 -4
- package/dist/commands/legacy-storage-migration.d.ts +46 -1
- package/dist/commands/legacy-storage-migration.d.ts.map +1 -1
- package/dist/commands/legacy-storage-migration.js +244 -9
- package/dist/commands/migrate.d.ts.map +1 -1
- package/dist/commands/migrate.js +150 -166
- package/dist/commands/sync/manifest.d.ts.map +1 -1
- package/dist/commands/sync/manifest.js +9 -0
- package/dist/commands/sync/persistence.d.ts.map +1 -1
- package/dist/commands/sync/persistence.js +4 -0
- package/dist/decision-firmness.d.ts +39 -0
- package/dist/decision-firmness.d.ts.map +1 -0
- package/dist/decision-firmness.js +115 -0
- package/dist/extractors/markdown.d.ts +2 -0
- package/dist/extractors/markdown.d.ts.map +1 -1
- package/dist/extractors/markdown.js +14 -0
- package/dist/extractors/symbols-coordinator.js +1 -0
- package/dist/intent-search.d.ts.map +1 -1
- package/dist/intent-search.js +28 -6
- package/dist/operations/migration/inventory-rederive.d.ts +40 -1
- package/dist/operations/migration/inventory-rederive.d.ts.map +1 -1
- package/dist/operations/migration/inventory-rederive.js +99 -8
- package/dist/operations/migration/requirement-status.d.ts +25 -0
- package/dist/operations/migration/requirement-status.d.ts.map +1 -0
- package/dist/operations/migration/requirement-status.js +105 -0
- package/dist/operations/migration/schema6.d.ts +27 -0
- package/dist/operations/migration/schema6.d.ts.map +1 -1
- package/dist/operations/migration/schema6.js +308 -7
- package/dist/operations/migration/supersedes-reason.d.ts +26 -0
- package/dist/operations/migration/supersedes-reason.d.ts.map +1 -0
- package/dist/operations/migration/supersedes-reason.js +69 -0
- package/dist/operations/migration/symbol-legacy-links.d.ts +51 -0
- package/dist/operations/migration/symbol-legacy-links.d.ts.map +1 -0
- package/dist/operations/migration/symbol-legacy-links.js +319 -0
- package/dist/operations/modeling/predicate-applyplan.d.ts.map +1 -1
- package/dist/operations/modeling/predicate-applyplan.js +10 -2
- package/dist/operations/modeling/predicate-loader.d.ts.map +1 -1
- package/dist/operations/modeling/predicate-loader.js +11 -0
- package/dist/operations/modeling/predicate-types.d.ts +32 -1
- package/dist/operations/modeling/predicate-types.d.ts.map +1 -1
- package/dist/operations/modeling/suggest-predicates.d.ts.map +1 -1
- package/dist/operations/modeling/suggest-predicates.js +175 -35
- package/dist/operations/mutation/context-warning.d.ts +12 -2
- package/dist/operations/mutation/context-warning.d.ts.map +1 -1
- package/dist/operations/mutation/context-warning.js +6 -6
- package/dist/operations/mutation/delete.d.ts +5 -1
- package/dist/operations/mutation/delete.d.ts.map +1 -1
- package/dist/operations/mutation/delete.js +223 -17
- package/dist/operations/mutation/serialization.d.ts.map +1 -1
- package/dist/operations/mutation/serialization.js +1 -0
- package/dist/operations/mutation/source-authoring.d.ts.map +1 -1
- package/dist/operations/mutation/source-authoring.js +130 -35
- package/dist/operations/mutation/types.d.ts +39 -1
- package/dist/operations/mutation/types.d.ts.map +1 -1
- package/dist/operations/mutation/upsert.d.ts +17 -2
- package/dist/operations/mutation/upsert.d.ts.map +1 -1
- package/dist/operations/mutation/upsert.js +82 -13
- package/dist/operations/mutation/validate-upsert.d.ts.map +1 -1
- package/dist/operations/mutation/validate-upsert.js +40 -8
- package/dist/operations/planning/apply-plan.d.ts +6 -1
- package/dist/operations/planning/apply-plan.d.ts.map +1 -1
- package/dist/operations/planning/apply-plan.js +26 -5
- package/dist/public/impact/diagnostics.d.ts.map +1 -1
- package/dist/public/impact/diagnostics.js +24 -14
- package/dist/public/operations/catalog.d.ts +14 -5
- 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 +6 -0
- package/dist/public/operations/contracts.d.ts.map +1 -1
- package/dist/public/operations/contracts.js +35 -2
- package/dist/public/operations/decision-firmness.d.ts +34 -0
- package/dist/public/operations/decision-firmness.d.ts.map +1 -0
- package/dist/public/operations/decision-firmness.js +216 -0
- package/dist/public/operations/discovery-executors.d.ts +2 -0
- package/dist/public/operations/discovery-executors.d.ts.map +1 -1
- package/dist/public/operations/discovery-executors.js +25 -4
- package/dist/public/operations/migration-plan.d.ts +2 -0
- package/dist/public/operations/migration-plan.d.ts.map +1 -1
- package/dist/public/operations/migration-plan.js +101 -16
- package/dist/public/operations/result-envelope.d.ts.map +1 -1
- package/dist/public/operations/result-envelope.js +27 -1
- 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 +6 -1
- package/dist/public/operations/specs/check.d.ts +1 -1
- package/dist/public/operations/specs/mutation-schemas.d.ts +5 -0
- package/dist/public/operations/specs/mutation-schemas.d.ts.map +1 -1
- package/dist/public/operations/specs/mutation-schemas.js +5 -0
- package/dist/public/operations/specs/mutation.d.ts +6 -2
- package/dist/public/operations/specs/mutation.d.ts.map +1 -1
- package/dist/public/operations/specs/mutation.js +6 -2
- package/dist/public/operations/specs/planning.d.ts +2 -2
- package/dist/public/operations/specs/planning.js +2 -2
- package/dist/public/operations/specs/upsert.d.ts +5 -0
- package/dist/public/operations/specs/upsert.d.ts.map +1 -1
- package/dist/public/operations/symbol-granularity-check.d.ts +18 -0
- package/dist/public/operations/symbol-granularity-check.d.ts.map +1 -0
- package/dist/public/operations/symbol-granularity-check.js +175 -0
- package/dist/public/schemas/entity.d.ts.map +1 -1
- package/dist/public/schemas/entity.js +11 -0
- package/dist/public/skills/kibi-traceability/SKILL.md +6 -4
- package/dist/public/skills/kibi-usage/SKILL.md +50 -10
- package/dist/public/skills/kibi-usage/resources/source-authoring.md +4 -2
- package/dist/public/symbol-granularity.d.ts +17 -0
- package/dist/public/symbol-granularity.d.ts.map +1 -1
- package/dist/public/symbol-granularity.js +21 -0
- package/dist/relationships/shards.d.ts +10 -0
- package/dist/relationships/shards.d.ts.map +1 -1
- package/dist/relationships/shards.js +27 -11
- package/dist/schemas/entity.schema.json +28 -0
- package/dist/search-answer.d.ts +31 -2
- package/dist/search-answer.d.ts.map +1 -1
- package/dist/search-answer.js +115 -17
- package/dist/traceability/evidence-model.d.ts +7 -3
- package/dist/traceability/evidence-model.d.ts.map +1 -1
- package/dist/traceability/staged-symbols-manifest.js +6 -5
- package/dist/traceability/validate.d.ts +14 -1
- package/dist/traceability/validate.d.ts.map +1 -1
- package/dist/traceability/validate.js +41 -0
- package/dist/types/entities.d.ts +4 -0
- package/dist/types/entities.d.ts.map +1 -1
- package/dist/utils/kb-manifest.d.ts +6 -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 +26 -0
- package/dist/utils/rule-registry.generated.d.ts.map +1 -1
- package/dist/utils/rule-registry.generated.js +31 -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 -1
- package/package.json +3 -3
- package/schema/entities.pl +6 -0
- package/src/public/impact/diagnostics.ts +29 -17
- package/src/public/operations/check-executor.ts +13 -0
- package/src/public/operations/contracts.ts +39 -2
- package/src/public/operations/decision-firmness.ts +280 -0
- package/src/public/operations/discovery-executors.ts +29 -4
- package/src/public/operations/migration-plan.ts +100 -19
- package/src/public/operations/result-envelope.ts +34 -1
- package/src/public/operations/specs/check-rules.generated.ts +6 -1
- package/src/public/operations/specs/mutation-schemas.ts +6 -0
- package/src/public/operations/specs/mutation.ts +7 -2
- package/src/public/operations/specs/planning.ts +2 -2
- package/src/public/operations/symbol-granularity-check.ts +233 -0
- package/src/public/schemas/entity.ts +12 -0
- package/src/public/skills/kibi-traceability/SKILL.md +6 -4
- package/src/public/skills/kibi-usage/SKILL.md +50 -10
- package/src/public/skills/kibi-usage/resources/source-authoring.md +4 -2
- package/src/public/symbol-granularity.ts +37 -0
- package/src/schemas/entity.schema.json +28 -0
|
@@ -0,0 +1,233 @@
|
|
|
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
|
+
import { readFileSync, statSync } from "node:fs";
|
|
20
|
+
import * as path from "node:path";
|
|
21
|
+
import type { ExtractionResult } from "../../extractors/markdown.js";
|
|
22
|
+
import { createMaintenanceSourceAnalysisService } from "../../plugins/maintenance-source-analysis.js";
|
|
23
|
+
import {
|
|
24
|
+
normalizeEntityId,
|
|
25
|
+
parseEntityFromList,
|
|
26
|
+
parseListOfLists,
|
|
27
|
+
parseTriples,
|
|
28
|
+
} from "../../prolog/codec.js";
|
|
29
|
+
import {
|
|
30
|
+
type ExtractedSymbol,
|
|
31
|
+
extractSymbolsFromStagedFileAsync,
|
|
32
|
+
} from "../../traceability/symbol-extract.js";
|
|
33
|
+
import type { Violation } from "../../utils/rule-registry.js";
|
|
34
|
+
import { createSymbolGranularityDiagnostics } from "../impact/diagnostics.js";
|
|
35
|
+
import { createImpactManifestLookup } from "../impact/manifest.js";
|
|
36
|
+
import { normalizeSourceFile } from "../impact/source-changes.js";
|
|
37
|
+
import {
|
|
38
|
+
isAllowedGranularityReason,
|
|
39
|
+
isTraceabilityRelationshipType,
|
|
40
|
+
} from "../symbol-granularity.js";
|
|
41
|
+
import type { PrologPort } from "./runtime-types.js";
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Full-check form of the staged gate's `symbol_granularity_violation`: a
|
|
45
|
+
* symbol with traceability relationships must not link its source file
|
|
46
|
+
* coarsely while narrower behavioral symbols are available, unless it carries
|
|
47
|
+
* an allowed granularity_reason.
|
|
48
|
+
*/
|
|
49
|
+
// implements REQ-cli-check, REQ-cli-staged-impact-enforcement
|
|
50
|
+
export const SYMBOL_GRANULARITY_RULE = "symbol-granularity";
|
|
51
|
+
|
|
52
|
+
const SYMBOL_ROWS_QUERY =
|
|
53
|
+
"findall([Id,symbol,Fields], (kb_entity(Id, symbol, Props), include([Key=_]>>memberchk(Key, [title,status,source,sourceFile,granularity_reason]), Props, Fields)), Rows)";
|
|
54
|
+
const SYMBOL_RELATIONSHIPS_QUERY =
|
|
55
|
+
"findall([From,To,Type], (member(Type, [implements,covered_by,executable_for]), kb_relationship(Type, From, To), kb_entity(From, symbol, _)), Rels)";
|
|
56
|
+
|
|
57
|
+
function stringField(
|
|
58
|
+
entity: Record<string, unknown>,
|
|
59
|
+
key: string,
|
|
60
|
+
): string | undefined {
|
|
61
|
+
const value = entity[key];
|
|
62
|
+
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// implements REQ-cli-check
|
|
66
|
+
async function loadSymbolResults(
|
|
67
|
+
prolog: Pick<PrologPort, "query">,
|
|
68
|
+
workspaceRoot: string,
|
|
69
|
+
): Promise<ExtractionResult[]> {
|
|
70
|
+
const rows = await prolog.query(SYMBOL_ROWS_QUERY);
|
|
71
|
+
if (!rows.success) {
|
|
72
|
+
throw new Error(
|
|
73
|
+
`symbol-granularity symbol projection failed: ${rows.error ?? "unknown error"}`,
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
const rels = await prolog.query(SYMBOL_RELATIONSHIPS_QUERY);
|
|
77
|
+
if (!rels.success) {
|
|
78
|
+
throw new Error(
|
|
79
|
+
`symbol-granularity relationship projection failed: ${rels.error ?? "unknown error"}`,
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const relationships = new Map<string, ExtractionResult["relationships"]>();
|
|
84
|
+
for (const [rawFrom, rawTo, type] of parseTriples(
|
|
85
|
+
rels.bindings.Rels ?? "[]",
|
|
86
|
+
)) {
|
|
87
|
+
const from = normalizeEntityId(rawFrom);
|
|
88
|
+
const current = relationships.get(from) ?? [];
|
|
89
|
+
current.push({ from, to: normalizeEntityId(rawTo), type });
|
|
90
|
+
relationships.set(from, current);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const results: ExtractionResult[] = [];
|
|
94
|
+
for (const row of parseListOfLists(rows.bindings.Rows ?? "[]")) {
|
|
95
|
+
const entity = parseEntityFromList(row);
|
|
96
|
+
const id = stringField(entity, "id");
|
|
97
|
+
const sourceFile = stringField(entity, "sourceFile");
|
|
98
|
+
if (id === undefined || sourceFile === undefined) continue;
|
|
99
|
+
const granularityReason = stringField(entity, "granularity_reason");
|
|
100
|
+
results.push({
|
|
101
|
+
entity: {
|
|
102
|
+
id,
|
|
103
|
+
type: "symbol",
|
|
104
|
+
title: stringField(entity, "title") ?? "",
|
|
105
|
+
status: stringField(entity, "status") ?? "",
|
|
106
|
+
created_at: "",
|
|
107
|
+
updated_at: "",
|
|
108
|
+
source: stringField(entity, "source") ?? "",
|
|
109
|
+
...(granularityReason !== undefined
|
|
110
|
+
? { granularity_reason: granularityReason }
|
|
111
|
+
: {}),
|
|
112
|
+
},
|
|
113
|
+
relationships: relationships.get(id) ?? [],
|
|
114
|
+
sourceFile: normalizeSourceFile(workspaceRoot, sourceFile),
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
return results;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* The symbols the staged gate would judge: they carry a traceability
|
|
122
|
+
* relationship and no allowed granularity_reason. Other symbols are exempt,
|
|
123
|
+
* so their source files need no analysis.
|
|
124
|
+
*/
|
|
125
|
+
// implements REQ-cli-check
|
|
126
|
+
function granularityCandidates(
|
|
127
|
+
results: readonly ExtractionResult[],
|
|
128
|
+
): ExtractionResult[] {
|
|
129
|
+
return results.filter(
|
|
130
|
+
(result) =>
|
|
131
|
+
result.relationships.some((relationship) =>
|
|
132
|
+
isTraceabilityRelationshipType(relationship.type),
|
|
133
|
+
) && !isAllowedGranularityReason(result.entity.granularity_reason),
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function readRegularFile(absolutePath: string): string | null {
|
|
138
|
+
try {
|
|
139
|
+
if (!statSync(absolutePath).isFile()) return null;
|
|
140
|
+
return readFileSync(absolutePath, "utf8");
|
|
141
|
+
} catch {
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// implements REQ-cli-check
|
|
147
|
+
async function analyzeFiles(
|
|
148
|
+
files: readonly string[],
|
|
149
|
+
results: readonly ExtractionResult[],
|
|
150
|
+
workspaceRoot: string,
|
|
151
|
+
): Promise<Map<string, readonly ExtractedSymbol[]>> {
|
|
152
|
+
const manifestLookup = createImpactManifestLookup(results);
|
|
153
|
+
const service = createMaintenanceSourceAnalysisService(workspaceRoot);
|
|
154
|
+
const analyses = new Map<string, readonly ExtractedSymbol[]>();
|
|
155
|
+
for (const file of files) {
|
|
156
|
+
const content = readRegularFile(path.resolve(workspaceRoot, file));
|
|
157
|
+
if (content === null) continue;
|
|
158
|
+
try {
|
|
159
|
+
const analysis = await service.analyzeTextV2(file, content);
|
|
160
|
+
// Only a complete parser-backed analysis decides; the staged gate
|
|
161
|
+
// reports an incomplete one itself when the file is touched.
|
|
162
|
+
if (analysis.status !== "ok") continue;
|
|
163
|
+
const symbols = await extractSymbolsFromStagedFileAsync(
|
|
164
|
+
{
|
|
165
|
+
path: file,
|
|
166
|
+
status: "M",
|
|
167
|
+
content,
|
|
168
|
+
hunkRanges: [{ start: 1, end: Number.MAX_SAFE_INTEGER }],
|
|
169
|
+
},
|
|
170
|
+
manifestLookup,
|
|
171
|
+
{ analyzeText: async () => analysis },
|
|
172
|
+
);
|
|
173
|
+
analyses.set(file, symbols);
|
|
174
|
+
} catch {
|
|
175
|
+
// An analysis failure cannot decide anything for this file.
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return analyses;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// implements REQ-cli-check
|
|
182
|
+
function granularityViolations(
|
|
183
|
+
candidates: readonly ExtractionResult[],
|
|
184
|
+
sourceSymbolsByFile: ReadonlyMap<string, readonly ExtractedSymbol[]>,
|
|
185
|
+
workspaceRoot: string,
|
|
186
|
+
): Violation[] {
|
|
187
|
+
return createSymbolGranularityDiagnostics({
|
|
188
|
+
manifestResults: candidates.filter(
|
|
189
|
+
(result) =>
|
|
190
|
+
result.sourceFile !== undefined &&
|
|
191
|
+
sourceSymbolsByFile.has(result.sourceFile),
|
|
192
|
+
),
|
|
193
|
+
symbolsByFile: new Map(),
|
|
194
|
+
sourceSymbolsByFile,
|
|
195
|
+
workspaceRoot,
|
|
196
|
+
}).map((diagnostic) => ({
|
|
197
|
+
rule: SYMBOL_GRANULARITY_RULE,
|
|
198
|
+
entityId: diagnostic.entityId ?? "",
|
|
199
|
+
description: diagnostic.message,
|
|
200
|
+
suggestion: diagnostic.suggestion,
|
|
201
|
+
...(diagnostic.source !== undefined ? { source: diagnostic.source } : {}),
|
|
202
|
+
evidence: {
|
|
203
|
+
diagnosticId: diagnostic.id,
|
|
204
|
+
...(diagnostic.evidence ?? {}),
|
|
205
|
+
},
|
|
206
|
+
}));
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* `symbol-granularity`: the staged gate's granularity predicate, evaluated
|
|
211
|
+
* for every symbol against its whole working-tree file, every declaration a
|
|
212
|
+
* candidate as if the file were fully staged. Only files of symbols the gate
|
|
213
|
+
* would judge are analyzed; a file the source analyzers cannot fully analyze
|
|
214
|
+
* is skipped.
|
|
215
|
+
*/
|
|
216
|
+
// implements REQ-cli-check, REQ-cli-staged-impact-enforcement
|
|
217
|
+
export async function collectSymbolGranularityViolations(
|
|
218
|
+
prolog: Pick<PrologPort, "query">,
|
|
219
|
+
workspaceRoot: string,
|
|
220
|
+
rules: ReadonlySet<string>,
|
|
221
|
+
): Promise<Violation[]> {
|
|
222
|
+
if (!rules.has(SYMBOL_GRANULARITY_RULE)) return [];
|
|
223
|
+
const results = await loadSymbolResults(prolog, workspaceRoot);
|
|
224
|
+
const candidates = granularityCandidates(results);
|
|
225
|
+
const files = [
|
|
226
|
+
...new Set(candidates.map((result) => result.sourceFile ?? "")),
|
|
227
|
+
]
|
|
228
|
+
.filter((file) => file.length > 0)
|
|
229
|
+
.sort();
|
|
230
|
+
if (files.length === 0) return [];
|
|
231
|
+
const analyses = await analyzeFiles(files, results, workspaceRoot);
|
|
232
|
+
return granularityViolations(candidates, analyses, workspaceRoot);
|
|
233
|
+
}
|
|
@@ -358,6 +358,12 @@ const entitySchema: Record<string, unknown> = {
|
|
|
358
358
|
text_ref: { type: "string" },
|
|
359
359
|
// Provenance of any authored entity: who wrote it and on what authority.
|
|
360
360
|
origin: ENTITY_ORIGIN_SCHEMA,
|
|
361
|
+
firmness: {
|
|
362
|
+
type: "string",
|
|
363
|
+
enum: ["firm", "default", "exploratory"],
|
|
364
|
+
description:
|
|
365
|
+
"Requirement and ADR only. How firmly the decision was made. firm: a human stated it as a rule; it needs a ref (origin.ref, or approval_ref on a requirement) to their words, and only a human may change it. default (assumed when absent): a delegated or agent choice; a later agent may supersede it with evidence. exploratory: a flagged guess, expected to be revisited.",
|
|
366
|
+
},
|
|
361
367
|
expects: {
|
|
362
368
|
type: "string",
|
|
363
369
|
enum: ["success", "rejection", "error"],
|
|
@@ -713,6 +719,12 @@ const entitySchema: Record<string, unknown> = {
|
|
|
713
719
|
},
|
|
714
720
|
},
|
|
715
721
|
},
|
|
722
|
+
{
|
|
723
|
+
if: {
|
|
724
|
+
properties: { type: { enum: ["req", "adr"] } },
|
|
725
|
+
},
|
|
726
|
+
else: { not: { required: ["firmness"] } },
|
|
727
|
+
},
|
|
716
728
|
{
|
|
717
729
|
if: {
|
|
718
730
|
properties: { type: { const: "scenario" } },
|
|
@@ -43,10 +43,12 @@ sequential `kb_upsert`, then run final check and coverage. Kibi authors tracked
|
|
|
43
43
|
files transactionally but never Git-stages or commits them. Do not read or edit
|
|
44
44
|
`.kb` directly.
|
|
45
45
|
|
|
46
|
-
Use `kb_delete` only for intentional cleanup
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
46
|
+
Use `kb_delete` only for intentional cleanup; `dryRun: true` previews any
|
|
47
|
+
delete without writing. Authored entity deletion returns `outcome:
|
|
48
|
+
plan_returned` with a hash-bound plan whose `nextActions[0].input` is the exact
|
|
49
|
+
`kb_apply_plan` input; requirements return `supersession_required` and evolve
|
|
50
|
+
through a new requirement linked with `supersedes`. Relationship deletes patch
|
|
51
|
+
shards while preserving unrelated records.
|
|
50
52
|
|
|
51
53
|
## Typed recovery and proof
|
|
52
54
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
id: kibi-usage
|
|
3
3
|
name: Kibi Usage
|
|
4
4
|
description: Use Kibi's source-first, exact-Git, migration-aware, proof-aware operations safely across MCP or the trusted local CLI, including partial completion repair.
|
|
5
|
-
version: 2.
|
|
5
|
+
version: 2.16.0
|
|
6
6
|
kibiCompatibility: ">=1.0.0"
|
|
7
7
|
tags:
|
|
8
8
|
- kibi
|
|
@@ -188,8 +188,9 @@ returns `status: error`, `MIGRATION_PLAN_REFUSED` and `data.outcome:
|
|
|
188
188
|
refused`: nothing changed, so read the action `detail` and get a new plan.
|
|
189
189
|
`data.outcome: reconciliation_required` (status success) means an action
|
|
190
190
|
failed mid-way: inspect its effect before retrying. `kb_delete` of an
|
|
191
|
-
authored entity returns status success with `deleted: 0
|
|
192
|
-
|
|
191
|
+
authored entity returns status success with `deleted: 0` and `outcome:
|
|
192
|
+
plan_returned` (or `supersession_required` for a requirement): nothing was
|
|
193
|
+
deleted yet, and `nextActions` names the call that does it. If the status is
|
|
193
194
|
`committed_with_repairs`, the mutation already committed: inspect failed effects,
|
|
194
195
|
execute each required repair action in order, and never retry the original
|
|
195
196
|
operation. Record effect failures, followed actions, and unsafe retries in
|
|
@@ -302,12 +303,18 @@ authored. Each one is the order the write path accepts.
|
|
|
302
303
|
between the two writes `kb_check` reports the requirement until the
|
|
303
304
|
second lands.
|
|
304
305
|
3. **Deleting authored entities.** `kb_delete` on an authored entity that
|
|
305
|
-
is not a requirement (scenario, test, fact, ADR, …)
|
|
306
|
-
`
|
|
307
|
-
`
|
|
308
|
-
|
|
309
|
-
`
|
|
310
|
-
|
|
306
|
+
is not a requirement (scenario, test, fact, ADR, …) writes nothing and
|
|
307
|
+
returns `outcome: plan_returned` with a hash-bound
|
|
308
|
+
`kibi.entity-deletion-plan.v1` in `deletionPlan`. After review, run
|
|
309
|
+
`nextActions[0]` unchanged: `kb_apply_plan` with its `input` (`plan` plus
|
|
310
|
+
`approvedPlanHash: plan.planHash`), or repeat the `kb_delete` call with
|
|
311
|
+
`approvedPlanHash` to apply the freshly computed plan in one step (a
|
|
312
|
+
changed source fails with `DELETE_PLAN_HASH_MISMATCH`). `dryRun: true`
|
|
313
|
+
previews relationship and direct deletes without writing. For an
|
|
314
|
+
authored requirement the result is `outcome: supersession_required`, the
|
|
315
|
+
plan carries `supersessionRequired: true` and both routes refuse it
|
|
316
|
+
(`REQUIREMENT_SUPERSESSION_REQUIRED`): Kibi never deletes an authored
|
|
317
|
+
requirement. Evolve it instead with a new
|
|
311
318
|
requirement linked by `supersedes` and close the old one, or, for an
|
|
312
319
|
agent-origin requirement nobody approved and nothing links to, upsert it
|
|
313
320
|
with `status: closed` (keep its `title`); it stays on disk as history. A
|
|
@@ -342,6 +349,29 @@ human sets `approved_by`; `kb_check` flags approvals an agent recorded without
|
|
|
342
349
|
corroboration. Never fill in an approval yourself. Record why a requirement
|
|
343
350
|
exists in `rationale`, or link the ADR that explains it.
|
|
344
351
|
|
|
352
|
+
## Decision firmness
|
|
353
|
+
|
|
354
|
+
Requirements and ADRs carry `firmness`, which says what you may do with them.
|
|
355
|
+
Search answers, `kb_query` rows and hook snippets show it (snippets label only
|
|
356
|
+
`[firm]` and `[exploratory]`; an unlabeled decision is `default`).
|
|
357
|
+
|
|
358
|
+
- `firm`: a human stated it as a rule. Follow it; to change it, ask first.
|
|
359
|
+
`kb_check` blocks a firm decision without `origin.ref` to their words, and
|
|
360
|
+
a replacement of a firm decision that is not itself firm.
|
|
361
|
+
- `default` (when absent): a delegated or agent choice. Follow it unless the
|
|
362
|
+
task gives evidence against it; then supersede it in the same change and
|
|
363
|
+
list it under "Decisions I changed" for review, without asking first.
|
|
364
|
+
- `exploratory`: a flagged guess; revisit it when you touch the area.
|
|
365
|
+
|
|
366
|
+
Set `firmness` from what a human actually said: only their stated rule is
|
|
367
|
+
`firm` (with `origin.ref`); "do whatever" or your own pick is `default`; a
|
|
368
|
+
guess is `exploratory`. A supersede needs `## Why this changed` in the new
|
|
369
|
+
entity's body (at least 12 words): name the evidence (a failing test, a
|
|
370
|
+
measured cost, a constraint the old decision missed, a new requirement) and
|
|
371
|
+
answer the old decision's reasoning; `kb_check` blocks it otherwise. A
|
|
372
|
+
preference is not evidence: propose it instead of superseding. Kibi checks
|
|
373
|
+
only that a firm decision has a reference; never cite words nobody said.
|
|
374
|
+
|
|
345
375
|
Conditional clauses ("only when", "only if", "must not ... unless") compile
|
|
346
376
|
into typed `forbid` rules linked by `requires_rule`, not property facts; one
|
|
347
377
|
`kb_model` or `kb_compile_intent` cannot translate stays an `ontology_gap`.
|
|
@@ -421,7 +451,17 @@ a second grounding link would fail, so keep the existing link or apply the
|
|
|
421
451
|
`kb_delete` of the old link, requirement link; between the last two `kb_check`
|
|
422
452
|
reports both `logic-coverage` and `strict-req-fact-pairing` for the
|
|
423
453
|
requirement, as `expected.kbCheckAfterStep` states; run `kb_check` after the
|
|
424
|
-
last step and apply `rollback` if it is not clean)
|
|
454
|
+
last step and apply `rollback` if it is not clean). `keep_existing_grounding`
|
|
455
|
+
means the requirement already links a predicate fact with the candidate's
|
|
456
|
+
`canonical_key` (`existingGrounding[].matchedBy` is `canonical_key` when the
|
|
457
|
+
claim was worded differently), so write nothing. `extend_requirement` means
|
|
458
|
+
the requirement's proposition ledger has no entry for this text, so a link
|
|
459
|
+
cannot be made and no fact is planned: add the clause to the requirement's
|
|
460
|
+
prose (`mode: "requirement"`, or `kb_upsert` with the extended `semantic_text`
|
|
461
|
+
and the ledger `mode: "analyze"` returns) and call `mode: "predicates"` again.
|
|
462
|
+
Read `decisionConflicts` and its warnings whenever `plan` is null: they name
|
|
463
|
+
the stored decision facts the candidate would contradict and the requirements
|
|
464
|
+
that own them. `provide_argument_bindings` and `record_ontology_gap` mean
|
|
425
465
|
the same as for an ungrounded claim, and the gap observation is not a grounding
|
|
426
466
|
link, so write it exactly as returned (tags, `claim_text`, `document.body`, no
|
|
427
467
|
`claim_key`, no relationships). Record an ontology gap only when no returned schema fits the
|
|
@@ -23,8 +23,10 @@ drift diagnostic. Unresolved Git index conflicts are likewise blocking; Kibi
|
|
|
23
23
|
never chooses a merge winner.
|
|
24
24
|
|
|
25
25
|
Relationship upserts and relationship deletes patch only the canonical shard,
|
|
26
|
-
preserving unrelated records. Authored entity deletion
|
|
27
|
-
|
|
26
|
+
preserving unrelated records. Authored entity deletion writes nothing and
|
|
27
|
+
returns a hash-bound plan (`outcome: plan_returned`); approve it by running the
|
|
28
|
+
returned `nextActions[0]` (`kb_apply_plan` with `{plan, approvedPlanHash}`)
|
|
29
|
+
unchanged, or by repeating `kb_delete` with `approvedPlanHash`. Evolve requirements with a new
|
|
28
30
|
requirement and `supersedes`, rather than deleting the old semantic claim.
|
|
29
31
|
|
|
30
32
|
On `committed_with_repairs`, inspect `effects` and execute the typed required
|
|
@@ -117,6 +117,43 @@ export function getBehavioralSymbolNames(
|
|
|
117
117
|
].sort();
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
+
/**
|
|
121
|
+
* The candidates that are narrower than a manifest symbol: members of it
|
|
122
|
+
* (`Title.member`), or, when the source declares no symbol named like it,
|
|
123
|
+
* every other declaration in the file.
|
|
124
|
+
*/
|
|
125
|
+
// implements REQ-symbol-behavioral-anchors, REQ-cli-schema-migration
|
|
126
|
+
export function narrowerSymbols<T extends { name: string }>(
|
|
127
|
+
manifestSymbolName: string,
|
|
128
|
+
candidates: readonly T[],
|
|
129
|
+
sourceSymbols: readonly { name: string }[],
|
|
130
|
+
): T[] {
|
|
131
|
+
const declared = sourceSymbols.some(
|
|
132
|
+
(symbol) => symbol.name === manifestSymbolName,
|
|
133
|
+
);
|
|
134
|
+
return candidates.filter(
|
|
135
|
+
(candidate) =>
|
|
136
|
+
candidate.name !== manifestSymbolName &&
|
|
137
|
+
(candidate.name.startsWith(`${manifestSymbolName}.`) || !declared),
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* The behavioral symbols that make a traceability link on
|
|
143
|
+
* `manifestSymbolName` coarse: the staged granularity gate blocks such a
|
|
144
|
+
* link unless it carries a granularity_reason, and `kibi migrate` marks
|
|
145
|
+
* exactly these links legacy-link. Empty when the link is narrow enough.
|
|
146
|
+
*/
|
|
147
|
+
// implements REQ-symbol-behavioral-anchors, REQ-cli-schema-migration
|
|
148
|
+
export function coarseLinkBehavioralNames(
|
|
149
|
+
manifestSymbolName: string,
|
|
150
|
+
sourceSymbols: readonly GranularSymbolCandidate[],
|
|
151
|
+
): string[] {
|
|
152
|
+
return getBehavioralSymbolNames(
|
|
153
|
+
narrowerSymbols(manifestSymbolName, sourceSymbols, sourceSymbols),
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
|
|
120
157
|
export function getNonBehavioralSymbolNames(
|
|
121
158
|
candidates: GranularSymbolCandidate[],
|
|
122
159
|
): string[] {
|
|
@@ -514,6 +514,15 @@
|
|
|
514
514
|
},
|
|
515
515
|
"additionalProperties": false
|
|
516
516
|
},
|
|
517
|
+
"firmness": {
|
|
518
|
+
"type": "string",
|
|
519
|
+
"enum": [
|
|
520
|
+
"firm",
|
|
521
|
+
"default",
|
|
522
|
+
"exploratory"
|
|
523
|
+
],
|
|
524
|
+
"description": "Requirement and ADR only. How firmly the decision was made. firm: a human stated it as a rule; it needs a ref (origin.ref, or approval_ref on a requirement) to their words, and only a human may change it. default (assumed when absent): a delegated or agent choice; a later agent may supersede it with evidence. exploratory: a flagged guess, expected to be revisited."
|
|
525
|
+
},
|
|
517
526
|
"expects": {
|
|
518
527
|
"type": "string",
|
|
519
528
|
"enum": [
|
|
@@ -1657,6 +1666,25 @@
|
|
|
1657
1666
|
}
|
|
1658
1667
|
}
|
|
1659
1668
|
},
|
|
1669
|
+
{
|
|
1670
|
+
"if": {
|
|
1671
|
+
"properties": {
|
|
1672
|
+
"type": {
|
|
1673
|
+
"enum": [
|
|
1674
|
+
"req",
|
|
1675
|
+
"adr"
|
|
1676
|
+
]
|
|
1677
|
+
}
|
|
1678
|
+
}
|
|
1679
|
+
},
|
|
1680
|
+
"else": {
|
|
1681
|
+
"not": {
|
|
1682
|
+
"required": [
|
|
1683
|
+
"firmness"
|
|
1684
|
+
]
|
|
1685
|
+
}
|
|
1686
|
+
}
|
|
1687
|
+
},
|
|
1660
1688
|
{
|
|
1661
1689
|
"if": {
|
|
1662
1690
|
"properties": {
|