kibi-cli 2.21.2 → 2.22.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-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 +108 -6
- package/dist/commands/init-helpers.d.ts +16 -2
- package/dist/commands/init-helpers.d.ts.map +1 -1
- package/dist/commands/init-helpers.js +52 -10
- package/dist/commands/init.d.ts +1 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +12 -1
- 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 +219 -9
- package/dist/commands/migrate.d.ts +37 -0
- package/dist/commands/migrate.d.ts.map +1 -1
- package/dist/commands/migrate.js +72 -188
- package/dist/commands/sync/manifest.d.ts.map +1 -1
- package/dist/commands/sync/manifest.js +9 -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 +25 -0
- package/dist/operations/migration/schema6.d.ts.map +1 -1
- package/dist/operations/migration/schema6.js +265 -7
- 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/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/source-authoring.d.ts.map +1 -1
- package/dist/operations/mutation/source-authoring.js +130 -35
- package/dist/operations/mutation/types.d.ts +2 -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 +28 -11
- package/dist/operations/mutation/validate-upsert.d.ts.map +1 -1
- package/dist/operations/mutation/validate-upsert.js +40 -8
- package/dist/operations/mutation/validation.d.ts.map +1 -1
- package/dist/operations/mutation/validation.js +43 -1
- package/dist/operations/planning/apply-plan.d.ts.map +1 -1
- package/dist/operations/planning/apply-plan.js +34 -10
- package/dist/operations/semantic-advisor/ingestion-boundary.d.ts.map +1 -1
- package/dist/operations/semantic-advisor/ingestion-boundary.js +25 -1
- package/dist/operations/semantic-advisor/stored-ledger-drift.d.ts +19 -0
- package/dist/operations/semantic-advisor/stored-ledger-drift.d.ts.map +1 -0
- package/dist/operations/semantic-advisor/stored-ledger-drift.js +78 -0
- 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 +3 -3
- package/dist/public/operations/check-executor.d.ts.map +1 -1
- package/dist/public/operations/check-executor.js +3 -0
- package/dist/public/operations/contracts.d.ts.map +1 -1
- package/dist/public/operations/contracts.js +6 -1
- package/dist/public/operations/decision-firmness.d.ts +3 -1
- package/dist/public/operations/decision-firmness.d.ts.map +1 -1
- package/dist/public/operations/decision-firmness.js +13 -3
- 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 +24 -2
- package/dist/public/operations/migration-plan.d.ts +15 -0
- package/dist/public/operations/migration-plan.d.ts.map +1 -1
- package/dist/public/operations/migration-plan.js +130 -17
- 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 +2 -1
- package/dist/public/operations/specs/check.d.ts +1 -1
- package/dist/public/operations/specs/planning.d.ts +2 -2
- package/dist/public/operations/specs/planning.js +2 -2
- package/dist/public/operations/specs/semantic.d.ts.map +1 -1
- package/dist/public/operations/specs/semantic.js +26 -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/skills/kibi-usage/SKILL.md +8 -3
- 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/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/utils/rule-registry.generated.d.ts +5 -0
- package/dist/utils/rule-registry.generated.d.ts.map +1 -1
- package/dist/utils/rule-registry.generated.js +6 -0
- package/package.json +3 -3
- package/src/public/impact/diagnostics.ts +29 -17
- package/src/public/operations/check-executor.ts +7 -0
- package/src/public/operations/contracts.ts +6 -1
- package/src/public/operations/decision-firmness.ts +18 -2
- package/src/public/operations/discovery-executors.ts +28 -2
- package/src/public/operations/migration-plan.ts +147 -20
- package/src/public/operations/result-envelope.ts +34 -1
- package/src/public/operations/specs/check-rules.generated.ts +2 -1
- package/src/public/operations/specs/planning.ts +2 -2
- package/src/public/operations/specs/semantic.ts +37 -2
- package/src/public/operations/symbol-granularity-check.ts +233 -0
- package/src/public/skills/kibi-usage/SKILL.md +8 -3
- package/src/public/symbol-granularity.ts +37 -0
|
@@ -138,7 +138,7 @@ function relationshipsFor(id, extracted, shards) {
|
|
|
138
138
|
for (const relationship of [...extracted, ...shards]) {
|
|
139
139
|
if (relationship.from !== id)
|
|
140
140
|
continue;
|
|
141
|
-
unique.set(
|
|
141
|
+
unique.set(relationshipKey(relationship), relationship);
|
|
142
142
|
}
|
|
143
143
|
return [...unique.values()];
|
|
144
144
|
}
|
|
@@ -267,20 +267,32 @@ function planOne(workspaceRoot, relativePath, entity, extracted, shards, facts)
|
|
|
267
267
|
for (const claimKey of modeledBecameContext) {
|
|
268
268
|
reasons.push(`modeled claim ${claimKey} is now classified as context (${inventory.find((entry) => entry.claim_key === claimKey)?.role ?? "context"}); its grounding cannot stay`);
|
|
269
269
|
}
|
|
270
|
+
const modeledKeys = inventory
|
|
271
|
+
.filter((entry) => entry.status === "modeled")
|
|
272
|
+
.map((entry) => entry.claim_key);
|
|
273
|
+
const declared = new Set(extracted
|
|
274
|
+
.filter((relationship) => relationship.from === entity.id)
|
|
275
|
+
.map(relationshipKey));
|
|
270
276
|
const groundingKeys = [];
|
|
277
|
+
const orphanedGrounding = [];
|
|
271
278
|
for (const relationship of relationships) {
|
|
272
279
|
if (!GROUNDING_RELATIONSHIPS.has(relationship.type))
|
|
273
280
|
continue;
|
|
274
281
|
const claimKey = facts.claimKey(relationship.to);
|
|
282
|
+
if (claimKey === undefined || !modeledKeys.includes(claimKey)) {
|
|
283
|
+
orphanedGrounding.push({
|
|
284
|
+
type: relationship.type,
|
|
285
|
+
target: relationship.to,
|
|
286
|
+
claimKey: claimKey ?? null,
|
|
287
|
+
inFrontMatter: declared.has(relationshipKey(relationship)),
|
|
288
|
+
});
|
|
289
|
+
}
|
|
275
290
|
if (claimKey === undefined) {
|
|
276
291
|
reasons.push(`grounding target ${relationship.to} (${relationship.type}) declares no claim_key`);
|
|
277
292
|
continue;
|
|
278
293
|
}
|
|
279
294
|
groundingKeys.push(claimKey);
|
|
280
295
|
}
|
|
281
|
-
const modeledKeys = inventory
|
|
282
|
-
.filter((entry) => entry.status === "modeled")
|
|
283
|
-
.map((entry) => entry.claim_key);
|
|
284
296
|
for (const claimKey of new Set(groundingKeys)) {
|
|
285
297
|
if (modeledKeys.includes(claimKey))
|
|
286
298
|
continue;
|
|
@@ -298,6 +310,14 @@ function planOne(workspaceRoot, relativePath, entity, extracted, shards, facts)
|
|
|
298
310
|
for (const error of after.errors) {
|
|
299
311
|
reasons.push(`re-derived inventory would still fail ingestion: ${error}`);
|
|
300
312
|
}
|
|
313
|
+
const orphaned = new Set(orphanedGrounding.map((link) => relationshipKey({ type: link.type, from: entity.id, to: link.target })));
|
|
314
|
+
const rederivableByDroppingGrounding = reasons.length > 0 &&
|
|
315
|
+
orphanedGrounding.length > 0 &&
|
|
316
|
+
// A target without claim_key may ground something else (a property
|
|
317
|
+
// value, for example); only links to a claim that is no longer modeled
|
|
318
|
+
// are dropped, and only from the requirement's own front matter.
|
|
319
|
+
orphanedGrounding.every((link) => link.inFrontMatter && link.claimKey !== null) &&
|
|
320
|
+
validateSemanticInventoryBoundary(nextPayload, relationships.filter((relationship) => !orphaned.has(relationshipKey(relationship))), analyzeSemanticAdvisorInput({ payload: nextPayload }).receipt).errors.length === 0;
|
|
301
321
|
return {
|
|
302
322
|
requirementId: entity.id,
|
|
303
323
|
path: relativePath,
|
|
@@ -310,8 +330,13 @@ function planOne(workspaceRoot, relativePath, entity, extracted, shards, facts)
|
|
|
310
330
|
contractHash: createHash("sha256")
|
|
311
331
|
.update(canonicalJson(contract))
|
|
312
332
|
.digest("hex"),
|
|
333
|
+
orphanedGrounding,
|
|
334
|
+
rederivableByDroppingGrounding,
|
|
313
335
|
};
|
|
314
336
|
}
|
|
337
|
+
function relationshipKey(relationship) {
|
|
338
|
+
return `${relationship.type}\u0000${relationship.from}\u0000${relationship.to}`;
|
|
339
|
+
}
|
|
315
340
|
function readShardRelationships(workspaceRoot) {
|
|
316
341
|
try {
|
|
317
342
|
return readAllShards(path.join(workspaceRoot, ".kb")).map(({ type, from, to }) => ({ type, from, to }));
|
|
@@ -328,7 +353,7 @@ function readShardRelationships(workspaceRoot) {
|
|
|
328
353
|
* scan to one requirement.
|
|
329
354
|
*/
|
|
330
355
|
// implements REQ-kibi-proposition-complete-ingestion, REQ-cli-schema-migration
|
|
331
|
-
export function planInventoryRederivation(workspaceRoot, onlyId) {
|
|
356
|
+
export function planInventoryRederivation(workspaceRoot, onlyId, options = {}) {
|
|
332
357
|
const shards = readShardRelationships(workspaceRoot);
|
|
333
358
|
const facts = new FactClaimIndex(workspaceRoot);
|
|
334
359
|
const plans = [];
|
|
@@ -347,7 +372,9 @@ export function planInventoryRederivation(workspaceRoot, onlyId) {
|
|
|
347
372
|
}
|
|
348
373
|
if (onlyId !== undefined && result.entity.id !== onlyId)
|
|
349
374
|
continue;
|
|
350
|
-
const plan = planOne(workspaceRoot, file.relativePath,
|
|
375
|
+
const plan = planOne(workspaceRoot, file.relativePath, options.status === undefined
|
|
376
|
+
? result.entity
|
|
377
|
+
: { ...result.entity, status: options.status }, result.relationships, shards, facts);
|
|
351
378
|
if (plan !== null)
|
|
352
379
|
plans.push(plan);
|
|
353
380
|
}
|
|
@@ -357,7 +384,7 @@ export function planInventoryRederivation(workspaceRoot, onlyId) {
|
|
|
357
384
|
* Rewrite the inventory contract keys of one requirement's frontmatter and
|
|
358
385
|
* confirm every other frontmatter field reads back unchanged.
|
|
359
386
|
*/
|
|
360
|
-
function rewriteContract(content, contract) {
|
|
387
|
+
function rewriteContract(content, contract, dropLinks = []) {
|
|
361
388
|
const slice = sliceFrontmatter(content);
|
|
362
389
|
if (slice === null)
|
|
363
390
|
return null;
|
|
@@ -365,6 +392,24 @@ function rewriteContract(content, contract) {
|
|
|
365
392
|
if (document.errors.length > 0)
|
|
366
393
|
return null;
|
|
367
394
|
const current = document.toJS();
|
|
395
|
+
const dropped = (link) => isRecord(link) &&
|
|
396
|
+
dropLinks.some((drop) => drop.type === link.type && drop.target === link.target);
|
|
397
|
+
const keptLinks = Array.isArray(current.links)
|
|
398
|
+
? current.links.filter((link) => !dropped(link))
|
|
399
|
+
: current.links;
|
|
400
|
+
if (dropLinks.length > 0) {
|
|
401
|
+
if (!Array.isArray(current.links))
|
|
402
|
+
return null;
|
|
403
|
+
if (current.links.length - keptLinks.length !==
|
|
404
|
+
dropLinks.length)
|
|
405
|
+
return null;
|
|
406
|
+
for (let index = current.links.length - 1; index >= 0; index--) {
|
|
407
|
+
if (dropped(current.links[index]))
|
|
408
|
+
document.deleteIn(["links", index]);
|
|
409
|
+
}
|
|
410
|
+
if (keptLinks.length === 0)
|
|
411
|
+
document.delete("links");
|
|
412
|
+
}
|
|
368
413
|
const flowSpan = (span) => {
|
|
369
414
|
const node = document.createNode(span);
|
|
370
415
|
node.flow = true;
|
|
@@ -425,7 +470,11 @@ function rewriteContract(content, contract) {
|
|
|
425
470
|
])) {
|
|
426
471
|
const expected = key in contract
|
|
427
472
|
? contract[key]
|
|
428
|
-
:
|
|
473
|
+
: key === "links" && dropLinks.length > 0
|
|
474
|
+
? keptLinks.length > 0
|
|
475
|
+
? keptLinks
|
|
476
|
+
: undefined
|
|
477
|
+
: before[key];
|
|
429
478
|
if (!isDeepStrictEqual(after[key], expected))
|
|
430
479
|
return null;
|
|
431
480
|
}
|
|
@@ -472,6 +521,48 @@ export function applyInventoryRederivation(workspaceRoot, requirementId, expecte
|
|
|
472
521
|
summary: plan.summary,
|
|
473
522
|
};
|
|
474
523
|
}
|
|
524
|
+
function linkKeys(links) {
|
|
525
|
+
return JSON.stringify(links.map((link) => `${link.type}\u0000${link.target}`).sort());
|
|
526
|
+
}
|
|
527
|
+
/**
|
|
528
|
+
* Apply an unsafe re-derivation a person approved: write the re-derived
|
|
529
|
+
* contract and remove exactly `expectedDrops`, the orphaned grounding links
|
|
530
|
+
* the plan listed, from the requirement's front matter. The current plan must
|
|
531
|
+
* still produce the approved contract hash and the same orphaned links, and
|
|
532
|
+
* the rewritten requirement must pass ingestion before anything is written;
|
|
533
|
+
* the grounding facts themselves are left alone.
|
|
534
|
+
*/
|
|
535
|
+
// implements REQ-kibi-proposition-complete-ingestion, REQ-cli-schema-migration
|
|
536
|
+
export function applyInventoryRederivationDroppingGrounding(workspaceRoot, requirementId, expectedContractHash, expectedDrops) {
|
|
537
|
+
const plan = planInventoryRederivation(workspaceRoot, requirementId).find((candidate) => candidate.requirementId === requirementId);
|
|
538
|
+
if (plan === undefined ||
|
|
539
|
+
!plan.rederivableByDroppingGrounding ||
|
|
540
|
+
plan.contractHash !== expectedContractHash ||
|
|
541
|
+
linkKeys(plan.orphanedGrounding) !== linkKeys(expectedDrops)) {
|
|
542
|
+
throw new Error(`Requirement ${requirementId} changed since planning; rerun kibi migrate and approve the new plan.`);
|
|
543
|
+
}
|
|
544
|
+
const absolute = path.join(workspaceRoot, plan.path);
|
|
545
|
+
const content = readText(absolute);
|
|
546
|
+
const next = content === null
|
|
547
|
+
? null
|
|
548
|
+
: rewriteContract(content, plan.contract, plan.orphanedGrounding);
|
|
549
|
+
if (next === null) {
|
|
550
|
+
throw new Error(`Requirement ${requirementId}: the re-derived inventory and the dropped grounding links could not be written without changing other frontmatter fields.`);
|
|
551
|
+
}
|
|
552
|
+
// Fail closed: the rewritten requirement must pass ingestion as sync sees it.
|
|
553
|
+
const reread = extractFromMarkdownString(next, absolute);
|
|
554
|
+
const remaining = planOne(workspaceRoot, plan.path, reread.entity, reread.relationships, readShardRelationships(workspaceRoot), new FactClaimIndex(workspaceRoot));
|
|
555
|
+
if (remaining !== null) {
|
|
556
|
+
throw new Error(`Requirement ${requirementId}: the rewrite would still fail ingestion (${remaining.errors.join("; ")}); nothing was written.`);
|
|
557
|
+
}
|
|
558
|
+
writeFileAtomically(absolute, next);
|
|
559
|
+
return {
|
|
560
|
+
requirementId,
|
|
561
|
+
path: plan.path,
|
|
562
|
+
outcome: "rederived",
|
|
563
|
+
summary: plan.summary,
|
|
564
|
+
};
|
|
565
|
+
}
|
|
475
566
|
/** Apply every safe re-derivation; unsafe ones are returned untouched. */
|
|
476
567
|
// implements REQ-kibi-proposition-complete-ingestion, REQ-cli-schema-migration
|
|
477
568
|
export function applySafeInventoryRederivations(workspaceRoot) {
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type InventoryRederivation } from "./inventory-rederive.js";
|
|
2
|
+
/**
|
|
3
|
+
* Suggested current status for ADR or lifecycle vocabulary found on
|
|
4
|
+
* requirements: decided or still-proposed intent stays `open`; retired
|
|
5
|
+
* intent is `closed`.
|
|
6
|
+
*/
|
|
7
|
+
export declare const SUGGESTED_REQUIREMENT_STATUS: Readonly<Record<string, string>>;
|
|
8
|
+
/** One requirement whose status is outside the vocabulary. */
|
|
9
|
+
export type RequirementStatusFinding = Readonly<{
|
|
10
|
+
requirementId: string;
|
|
11
|
+
path: string;
|
|
12
|
+
status: string;
|
|
13
|
+
/** The suggested current status; null when Kibi has no suggestion. */
|
|
14
|
+
suggestedStatus: string | null;
|
|
15
|
+
/** Inventory drift the requirement shows once it has the suggested status. */
|
|
16
|
+
latentDrift: InventoryRederivation | null;
|
|
17
|
+
}>;
|
|
18
|
+
/** Every requirement whose authored status is outside the vocabulary. */
|
|
19
|
+
export declare function planRequirementStatusMappings(workspaceRoot: string): RequirementStatusFinding[];
|
|
20
|
+
/**
|
|
21
|
+
* Set the status of one requirement from `from` to `to`, replacing only its
|
|
22
|
+
* `status` line. Refuses when the authored status is no longer `from`.
|
|
23
|
+
*/
|
|
24
|
+
export declare function applyRequirementStatusMapping(workspaceRoot: string, relativePath: string, from: string, to: string): void;
|
|
25
|
+
//# sourceMappingURL=requirement-status.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"requirement-status.d.ts","sourceRoot":"","sources":["../../../src/operations/migration/requirement-status.ts"],"names":[],"mappings":"AAmBA,OAAO,EACL,KAAK,qBAAqB,EAE3B,MAAM,yBAAyB,CAAC;AA8BjC;;;;GAIG;AAEH,eAAO,MAAM,4BAA4B,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAOzE,CAAC;AAEF,8DAA8D;AAE9D,MAAM,MAAM,wBAAwB,GAAG,QAAQ,CAAC;IAC9C,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,sEAAsE;IACtE,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,8EAA8E;IAC9E,WAAW,EAAE,qBAAqB,GAAG,IAAI,CAAC;CAC3C,CAAC,CAAC;AAYH,yEAAyE;AAEzE,wBAAgB,6BAA6B,CAC3C,aAAa,EAAE,MAAM,GACpB,wBAAwB,EAAE,CA8B5B;AAED;;;GAGG;AAEH,wBAAgB,6BAA6B,CAC3C,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,GACT,IAAI,CAaN"}
|
|
@@ -0,0 +1,105 @@
|
|
|
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 path from "node:path";
|
|
19
|
+
import { planInventoryRederivation, } from "./inventory-rederive.js";
|
|
20
|
+
import { listLaneMarkdownFiles, readText, readTopLevelField, sliceFrontmatter, withTopLevelField, writeFileAtomically, } from "./kb-sources.js";
|
|
21
|
+
/**
|
|
22
|
+
* Requirement statuses outside the current vocabulary (`req-status-vocabulary`).
|
|
23
|
+
*
|
|
24
|
+
* A requirement with ADR vocabulary such as `status: accepted` compiles, but
|
|
25
|
+
* it is not a current requirement: the proof ladder skips it and the
|
|
26
|
+
* ingestion boundary does not validate its semantic inventory, so inventory
|
|
27
|
+
* drift stays hidden until someone maps the status. Which current status a
|
|
28
|
+
* legacy one means is a semantic choice, so the mapping is only suggested;
|
|
29
|
+
* the latent drift is computed as if the suggestion were applied.
|
|
30
|
+
*/
|
|
31
|
+
/** Statuses `kibi check` accepts on a requirement (canonical and legacy). */
|
|
32
|
+
const REQUIREMENT_STATUSES = new Set([
|
|
33
|
+
"open",
|
|
34
|
+
"in_progress",
|
|
35
|
+
"closed",
|
|
36
|
+
"active",
|
|
37
|
+
"approved",
|
|
38
|
+
]);
|
|
39
|
+
/**
|
|
40
|
+
* Suggested current status for ADR or lifecycle vocabulary found on
|
|
41
|
+
* requirements: decided or still-proposed intent stays `open`; retired
|
|
42
|
+
* intent is `closed`.
|
|
43
|
+
*/
|
|
44
|
+
// implements REQ-cli-schema-migration
|
|
45
|
+
export const SUGGESTED_REQUIREMENT_STATUS = {
|
|
46
|
+
accepted: "open",
|
|
47
|
+
proposed: "open",
|
|
48
|
+
draft: "open",
|
|
49
|
+
deprecated: "closed",
|
|
50
|
+
superseded: "closed",
|
|
51
|
+
rejected: "closed",
|
|
52
|
+
};
|
|
53
|
+
function statusOf(content) {
|
|
54
|
+
const slice = sliceFrontmatter(content);
|
|
55
|
+
return slice === null ? undefined : readTopLevelField(slice.text, "status");
|
|
56
|
+
}
|
|
57
|
+
function idOf(content) {
|
|
58
|
+
const slice = sliceFrontmatter(content);
|
|
59
|
+
return slice === null ? undefined : readTopLevelField(slice.text, "id");
|
|
60
|
+
}
|
|
61
|
+
/** Every requirement whose authored status is outside the vocabulary. */
|
|
62
|
+
// implements REQ-cli-schema-migration
|
|
63
|
+
export function planRequirementStatusMappings(workspaceRoot) {
|
|
64
|
+
const findings = [];
|
|
65
|
+
for (const file of listLaneMarkdownFiles(workspaceRoot, ["requirements"])) {
|
|
66
|
+
const content = readText(file.absolutePath);
|
|
67
|
+
if (content === null)
|
|
68
|
+
continue;
|
|
69
|
+
const status = statusOf(content);
|
|
70
|
+
if (typeof status !== "string" || REQUIREMENT_STATUSES.has(status))
|
|
71
|
+
continue;
|
|
72
|
+
const id = idOf(content);
|
|
73
|
+
const requirementId = typeof id === "string" && id.length > 0
|
|
74
|
+
? id
|
|
75
|
+
: path.basename(file.relativePath, ".md");
|
|
76
|
+
const suggestedStatus = SUGGESTED_REQUIREMENT_STATUS[status] ?? null;
|
|
77
|
+
findings.push({
|
|
78
|
+
requirementId,
|
|
79
|
+
path: file.relativePath,
|
|
80
|
+
status,
|
|
81
|
+
suggestedStatus,
|
|
82
|
+
latentDrift: suggestedStatus === null
|
|
83
|
+
? null
|
|
84
|
+
: (planInventoryRederivation(workspaceRoot, requirementId, {
|
|
85
|
+
status: suggestedStatus,
|
|
86
|
+
}).find((plan) => plan.requirementId === requirementId) ?? null),
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
return findings.sort((left, right) => left.requirementId.localeCompare(right.requirementId));
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Set the status of one requirement from `from` to `to`, replacing only its
|
|
93
|
+
* `status` line. Refuses when the authored status is no longer `from`.
|
|
94
|
+
*/
|
|
95
|
+
// implements REQ-cli-schema-migration
|
|
96
|
+
export function applyRequirementStatusMapping(workspaceRoot, relativePath, from, to) {
|
|
97
|
+
const absolute = path.join(workspaceRoot, relativePath);
|
|
98
|
+
const content = readText(absolute);
|
|
99
|
+
if (content === null || statusOf(content) !== from)
|
|
100
|
+
throw new Error(`${relativePath} no longer has status ${from}; rerun kibi migrate and approve the new plan.`);
|
|
101
|
+
const next = withTopLevelField(content, "status", to);
|
|
102
|
+
if (next === null)
|
|
103
|
+
throw new Error(`${relativePath}: status could not be set to ${to} without changing other frontmatter fields; set it by hand.`);
|
|
104
|
+
writeFileAtomically(absolute, next);
|
|
105
|
+
}
|
|
@@ -10,10 +10,25 @@ export declare const DECISION_FIRMNESS_SCHEMA_VERSION = 9;
|
|
|
10
10
|
export declare const SEMANTIC_INVENTORY_REDERIVE_CODE = "semantic_inventory_rederive";
|
|
11
11
|
/** Review: a drifted inventory Kibi cannot re-derive safely. */
|
|
12
12
|
export declare const SEMANTIC_INVENTORY_REVIEW_CODE = "semantic_inventory_review";
|
|
13
|
+
/**
|
|
14
|
+
* Review, applied only when approved by id: re-derive a drifted inventory and
|
|
15
|
+
* drop the grounding links that no longer ground a modeled claim.
|
|
16
|
+
*/
|
|
17
|
+
export declare const SEMANTIC_INVENTORY_REDERIVE_DROP_GROUNDING_CODE = "semantic_inventory_rederive_drop_grounding";
|
|
18
|
+
/** Review, applied only when approved by id: map a legacy requirement status. */
|
|
19
|
+
export declare const REQ_STATUS_VOCABULARY_MAP_CODE = "req_status_vocabulary_map";
|
|
13
20
|
/** Automatic: stamp `origin: {kind: migration}` on authored entities. */
|
|
14
21
|
export declare const ENTITY_ORIGIN_BACKFILL_CODE = "entity_origin_backfill";
|
|
15
22
|
export declare const ENTITY_ORIGIN_BACKFILL_ACTION_ID = "entity-origin-backfill";
|
|
16
23
|
export { CLOSE_SUPERSEDED_REQUIREMENTS_CODE, MIGRATION_SYNC_ACTION_ID, MIGRATION_SYNC_CODE, SOURCE_PATH_REWRITE_CODE, };
|
|
24
|
+
/**
|
|
25
|
+
* One action per requirement whose status is outside the vocabulary: a
|
|
26
|
+
* review (the target status is a semantic choice) carrying the suggested
|
|
27
|
+
* mapping and the inventory drift the requirement shows once mapped. With a
|
|
28
|
+
* suggestion it is executable when approved by id; the re-derivation of the
|
|
29
|
+
* latent drift depends on it.
|
|
30
|
+
*/
|
|
31
|
+
export declare function requirementStatusActions(workspaceRoot: string): MigrationAction[];
|
|
17
32
|
/**
|
|
18
33
|
* Exceptions without approved_by, read from authored sources so the list is
|
|
19
34
|
* available before the KB compiles.
|
|
@@ -51,6 +66,11 @@ export declare function buildLifecycleRepairActions(workspaceRoot: string): {
|
|
|
51
66
|
actions: MigrationAction[];
|
|
52
67
|
sourceRewriteActionIds: string[];
|
|
53
68
|
};
|
|
69
|
+
/**
|
|
70
|
+
* The automatic legacy-link pass over `.kb/symbols.yaml`, bound to the
|
|
71
|
+
* manifest bytes it was planned from; null when no link needs a mark.
|
|
72
|
+
*/
|
|
73
|
+
export declare function symbolLegacyLinkAction(workspaceRoot: string): MigrationAction | null;
|
|
54
74
|
/** The sync that recompiles sources rewritten by earlier actions. */
|
|
55
75
|
export declare function migrationSyncAction(dependsOn: readonly string[]): MigrationAction;
|
|
56
76
|
type ApplyContext = Readonly<{
|
|
@@ -59,5 +79,10 @@ type ApplyContext = Readonly<{
|
|
|
59
79
|
}>;
|
|
60
80
|
/** Execute one automatic action produced by this module. */
|
|
61
81
|
export declare function applySchema6MigrationAction(action: MigrationAction, context: ApplyContext): Promise<void>;
|
|
82
|
+
/**
|
|
83
|
+
* Review actions Kibi can execute, but only when a person approves them by
|
|
84
|
+
* id (`--approved-action`): `--apply-safe` selects automatic actions alone.
|
|
85
|
+
*/
|
|
86
|
+
export declare const SCHEMA6_APPROVABLE_REVIEW_CODES: ReadonlySet<string>;
|
|
62
87
|
export declare const SCHEMA6_AUTOMATIC_CODES: ReadonlySet<string>;
|
|
63
88
|
//# sourceMappingURL=schema6.d.ts.map
|
|
@@ -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;AAoD1D,gEAAgE;AAEhE,eAAO,MAAM,qBAAqB,IAAI,CAAC;AAEvC,+EAA+E;AAE/E,eAAO,MAAM,2BAA2B,IAAI,CAAC;AAE7C,4DAA4D;AAE5D,eAAO,MAAM,gCAAgC,IAAI,CAAC;AAElD,yEAAyE;AAEzE,eAAO,MAAM,gCAAgC,gCAAgC,CAAC;AAC9E,gEAAgE;AAEhE,eAAO,MAAM,8BAA8B,8BAA8B,CAAC;AAC1E;;;GAGG;AAEH,eAAO,MAAM,+CAA+C,+CACd,CAAC;AAC/C,iFAAiF;AAEjF,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;AAgLF;;;;;;GAMG;AAEH,wBAAgB,wBAAwB,CACtC,aAAa,EAAE,MAAM,GACpB,eAAe,EAAE,CAqEnB;AAyBD;;;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,CAgN3B;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;;;GAGG;AAEH,wBAAgB,sBAAsB,CACpC,aAAa,EAAE,MAAM,GACpB,eAAe,GAAG,IAAI,CAqBxB;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,CAgHf;AAED;;;GAGG;AAEH,eAAO,MAAM,+BAA+B,EAAE,WAAW,CAAC,MAAM,CAK9D,CAAC;AAGH,eAAO,MAAM,uBAAuB,EAAE,WAAW,CAAC,MAAM,CAWtD,CAAC"}
|