kibi-cli 2.20.0 → 2.21.2
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/doctor.js +13 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +15 -3
- package/dist/commands/legacy-storage-migration.d.ts.map +1 -1
- package/dist/commands/legacy-storage-migration.js +26 -1
- package/dist/commands/migrate.d.ts +2 -0
- package/dist/commands/migrate.d.ts.map +1 -1
- package/dist/commands/migrate.js +155 -11
- package/dist/commands/sync/discovery.d.ts.map +1 -1
- package/dist/commands/sync/discovery.js +14 -2
- 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 +16 -1
- package/dist/operations/migration/kb-sources.d.ts +5 -1
- package/dist/operations/migration/kb-sources.d.ts.map +1 -1
- package/dist/operations/migration/kb-sources.js +28 -1
- 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 +44 -1
- 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/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/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 +8 -0
- package/dist/operations/mutation/source-authoring.d.ts.map +1 -1
- package/dist/operations/mutation/source-authoring.js +33 -0
- package/dist/operations/mutation/types.d.ts +37 -0
- package/dist/operations/mutation/types.d.ts.map +1 -1
- package/dist/operations/mutation/upsert.d.ts.map +1 -1
- package/dist/operations/mutation/upsert.js +54 -2
- package/dist/operations/mutation/validation.d.ts.map +1 -1
- package/dist/operations/mutation/validation.js +2 -1
- 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 +8 -2
- package/dist/operations/semantic-advisor/clauses.d.ts +9 -0
- package/dist/operations/semantic-advisor/clauses.d.ts.map +1 -1
- package/dist/operations/semantic-advisor/clauses.js +24 -0
- 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 +3 -0
- package/dist/public/operations/contracts.d.ts.map +1 -1
- package/dist/public/operations/contracts.js +29 -1
- 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.map +1 -1
- package/dist/public/operations/discovery-executors.js +16 -2
- package/dist/public/operations/migration-plan.d.ts.map +1 -1
- package/dist/public/operations/migration-plan.js +37 -7
- 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 +5 -1
- package/dist/public/operations/specs/check.d.ts +1 -1
- package/dist/public/operations/specs/mutation-schemas.d.ts +7 -2
- package/dist/public/operations/specs/mutation-schemas.d.ts.map +1 -1
- package/dist/public/operations/specs/mutation-schemas.js +13 -17
- 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/upsert.d.ts +7 -2
- package/dist/public/operations/specs/upsert.d.ts.map +1 -1
- package/dist/public/schemas/entity.d.ts.map +1 -1
- package/dist/public/schemas/entity.js +13 -13
- package/dist/public/skills/kibi-traceability/SKILL.md +6 -4
- package/dist/public/skills/kibi-usage/SKILL.md +52 -10
- package/dist/public/skills/kibi-usage/resources/fact-lanes.md +1 -1
- package/dist/public/skills/kibi-usage/resources/source-authoring.md +4 -2
- package/dist/public/skills/kibi-usage/resources/ui-requirements.md +2 -2
- package/dist/public/skills/kibi-usage/resources/workflows.md +1 -1
- 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 +30 -25
- 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/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 +21 -0
- package/dist/utils/rule-registry.generated.d.ts.map +1 -1
- package/dist/utils/rule-registry.generated.js +25 -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 +2 -2
- package/schema/entities.pl +6 -0
- package/src/public/operations/check-executor.ts +6 -0
- package/src/public/operations/contracts.ts +33 -1
- package/src/public/operations/decision-firmness.ts +280 -0
- package/src/public/operations/discovery-executors.ts +17 -2
- package/src/public/operations/migration-plan.ts +41 -9
- package/src/public/operations/specs/check-rules.generated.ts +5 -1
- package/src/public/operations/specs/mutation-schemas.ts +14 -17
- package/src/public/operations/specs/mutation.ts +7 -2
- package/src/public/schemas/entity.ts +14 -13
- package/src/public/skills/kibi-traceability/SKILL.md +6 -4
- package/src/public/skills/kibi-usage/SKILL.md +52 -10
- package/src/public/skills/kibi-usage/resources/fact-lanes.md +1 -1
- package/src/public/skills/kibi-usage/resources/source-authoring.md +4 -2
- package/src/public/skills/kibi-usage/resources/ui-requirements.md +2 -2
- package/src/public/skills/kibi-usage/resources/workflows.md +1 -1
- package/src/schemas/entity.schema.json +30 -25
|
@@ -0,0 +1,115 @@
|
|
|
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
|
+
* Decision firmness: how firmly a requirement or ADR was decided, which tells
|
|
20
|
+
* a later agent whether it may supersede the decision on evidence or must ask
|
|
21
|
+
* a human first. This module is the one place that knows the values, the
|
|
22
|
+
* default and what a supersede must explain, so extraction, checks, search,
|
|
23
|
+
* query and migration agree.
|
|
24
|
+
*/
|
|
25
|
+
import { parseBodySections } from "./entity-body-context.js";
|
|
26
|
+
/** Firmness values, firmest first. */
|
|
27
|
+
// implements REQ-kb-decision-firmness
|
|
28
|
+
export const FIRMNESS_VALUES = ["firm", "default", "exploratory"];
|
|
29
|
+
/** The firmness of a decision that does not state one. */
|
|
30
|
+
// implements REQ-kb-decision-firmness
|
|
31
|
+
export const DEFAULT_FIRMNESS = "default";
|
|
32
|
+
/** Entity types that carry firmness. */
|
|
33
|
+
// implements REQ-kb-decision-firmness
|
|
34
|
+
export const FIRMNESS_TYPES = ["req", "adr"];
|
|
35
|
+
/** A supersede must explain itself under a heading starting with this. */
|
|
36
|
+
// implements REQ-kb-decision-firmness
|
|
37
|
+
export const WHY_THIS_CHANGED_HEADING = "Why this changed";
|
|
38
|
+
/** The explanation needs at least this many words of prose. */
|
|
39
|
+
// implements REQ-kb-decision-firmness
|
|
40
|
+
export const MIN_WHY_CHANGED_WORDS = 12;
|
|
41
|
+
const WHY_THIS_CHANGED = /^why\s+this\s+changed\b/i;
|
|
42
|
+
/**
|
|
43
|
+
* How the manifest records one acknowledged supersede edge. Edges, not ids,
|
|
44
|
+
* are acknowledged, so a supersede added later to the same entity still has
|
|
45
|
+
* to explain itself.
|
|
46
|
+
*/
|
|
47
|
+
// implements REQ-kb-decision-firmness
|
|
48
|
+
export function supersedeAcknowledgement(from, to) {
|
|
49
|
+
return `${from} -> ${to}`;
|
|
50
|
+
}
|
|
51
|
+
// implements REQ-kb-decision-firmness
|
|
52
|
+
export function isFirmness(value) {
|
|
53
|
+
return (typeof value === "string" &&
|
|
54
|
+
FIRMNESS_VALUES.includes(value));
|
|
55
|
+
}
|
|
56
|
+
// implements REQ-kb-decision-firmness
|
|
57
|
+
export function carriesFirmness(type) {
|
|
58
|
+
return (typeof type === "string" &&
|
|
59
|
+
FIRMNESS_TYPES.includes(type));
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* The firmness a decision is read with: the authored value, else `default`.
|
|
63
|
+
* Undefined for types that carry no firmness.
|
|
64
|
+
*/
|
|
65
|
+
// implements REQ-kb-decision-firmness
|
|
66
|
+
export function effectiveFirmness(type, value) {
|
|
67
|
+
if (!carriesFirmness(type))
|
|
68
|
+
return undefined;
|
|
69
|
+
return isFirmness(value) ? value : DEFAULT_FIRMNESS;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* The reference that makes a firm decision traceable to a human's words:
|
|
73
|
+
* `origin.ref`, or `approval_ref` on a requirement.
|
|
74
|
+
*/
|
|
75
|
+
// implements REQ-kb-decision-firmness
|
|
76
|
+
export function firmnessRef(entity) {
|
|
77
|
+
const origin = entity.origin;
|
|
78
|
+
if (origin !== null && typeof origin === "object") {
|
|
79
|
+
const ref = origin.ref;
|
|
80
|
+
if (typeof ref === "string" && ref.trim() !== "")
|
|
81
|
+
return ref.trim();
|
|
82
|
+
}
|
|
83
|
+
if (entity.type === "req" &&
|
|
84
|
+
typeof entity.approval_ref === "string" &&
|
|
85
|
+
entity.approval_ref.trim() !== "") {
|
|
86
|
+
return entity.approval_ref.trim();
|
|
87
|
+
}
|
|
88
|
+
return undefined;
|
|
89
|
+
}
|
|
90
|
+
function wordCount(text) {
|
|
91
|
+
return text.split(/\s+/).filter((word) => /[\p{L}\p{N}]/u.test(word)).length;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Words of prose under the body's "Why this changed" heading (nested
|
|
95
|
+
* headings included), or 0 when the body has no such section.
|
|
96
|
+
*/
|
|
97
|
+
// implements REQ-kb-decision-firmness
|
|
98
|
+
export function whyThisChangedWords(body) {
|
|
99
|
+
const sections = parseBodySections(body);
|
|
100
|
+
let level = null;
|
|
101
|
+
let words = 0;
|
|
102
|
+
for (const section of sections) {
|
|
103
|
+
if (level !== null && section.level > 0 && section.level <= level) {
|
|
104
|
+
level = null;
|
|
105
|
+
}
|
|
106
|
+
if (level === null &&
|
|
107
|
+
section.level > 0 &&
|
|
108
|
+
WHY_THIS_CHANGED.test(section.heading.replace(/^[*_`\s]+/, ""))) {
|
|
109
|
+
level = section.level;
|
|
110
|
+
}
|
|
111
|
+
if (level !== null)
|
|
112
|
+
words += wordCount(section.text);
|
|
113
|
+
}
|
|
114
|
+
return words;
|
|
115
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type Firmness } from "../decision-firmness.js";
|
|
1
2
|
import { type EntityOrigin } from "../public/entity-origin.js";
|
|
2
3
|
import { type ProofBinding, type ProofContract } from "../public/proof-protocol.js";
|
|
3
4
|
import { type ProofReceipt } from "../public/proof-receipt.js";
|
|
@@ -15,6 +16,7 @@ export interface ExtractedEntity {
|
|
|
15
16
|
severity?: string;
|
|
16
17
|
text_ref?: string;
|
|
17
18
|
origin?: EntityOrigin;
|
|
19
|
+
firmness?: Firmness;
|
|
18
20
|
semantic_text?: string;
|
|
19
21
|
logic_claims?: string[];
|
|
20
22
|
semantic_clauses?: string[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/extractors/markdown.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/extractors/markdown.ts"],"names":[],"mappings":"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"}
|
|
@@ -19,8 +19,9 @@ import { createHash } from "node:crypto";
|
|
|
19
19
|
import { readFileSync } from "node:fs";
|
|
20
20
|
import Ajv from "ajv";
|
|
21
21
|
import { load as yamlLoad } from "js-yaml";
|
|
22
|
+
import { FIRMNESS_VALUES, carriesFirmness, isFirmness, } from "../decision-firmness.js";
|
|
22
23
|
import { withoutContextSections } from "../entity-body-context.js";
|
|
23
|
-
import { semanticClaimKey } from "../operations/semantic-advisor/clauses.js";
|
|
24
|
+
import { deriveFactClaimKey, semanticClaimKey, } from "../operations/semantic-advisor/clauses.js";
|
|
24
25
|
import { normalizeEntityOrigin, } from "../public/entity-origin.js";
|
|
25
26
|
import { PROOF_BINDINGS_SCHEMA, PROOF_CONTRACT_SCHEMA, } from "../public/proof-protocol.js";
|
|
26
27
|
import { proofReceiptHistoryErrors, } from "../public/proof-receipt.js";
|
|
@@ -511,6 +512,19 @@ function extractFromMarkdownContent(content, filePath) {
|
|
|
511
512
|
}
|
|
512
513
|
entity.rationale = data.rationale;
|
|
513
514
|
}
|
|
515
|
+
// implements REQ-kb-decision-firmness
|
|
516
|
+
// How firmly a requirement or ADR was decided; absent reads as default.
|
|
517
|
+
if (data.firmness !== undefined) {
|
|
518
|
+
if (!carriesFirmness(type) || !isFirmness(data.firmness)) {
|
|
519
|
+
throw new FrontmatterError(carriesFirmness(type)
|
|
520
|
+
? `Invalid firmness; expected one of ${FIRMNESS_VALUES.join(", ")}`
|
|
521
|
+
: "firmness is only allowed on type: req or adr", filePath, {
|
|
522
|
+
classification: "Invalid Firmness",
|
|
523
|
+
hint: "Use firm only for a rule a human stated (with origin.ref to their words), default for a delegated or agent choice, exploratory for a flagged guess; remove the field from other entity types.",
|
|
524
|
+
});
|
|
525
|
+
}
|
|
526
|
+
entity.firmness = data.firmness;
|
|
527
|
+
}
|
|
514
528
|
if (type === "req" && Array.isArray(data.exempts_claims)) {
|
|
515
529
|
entity.exempts_claims = data.exempts_claims.filter((value) => typeof value === "string");
|
|
516
530
|
}
|
|
@@ -671,6 +685,7 @@ function extractFromMarkdownContent(content, filePath) {
|
|
|
671
685
|
hint: "Fix the entity fields so they match the public schema.",
|
|
672
686
|
});
|
|
673
687
|
}
|
|
688
|
+
deriveFactClaimKey(entity);
|
|
674
689
|
if (entity.type === "fact" &&
|
|
675
690
|
entity.claim_key !== undefined &&
|
|
676
691
|
entity.claim_text !== undefined) {
|
|
@@ -47,7 +47,11 @@ export declare function withTopLevelField(content: string, key: string, value: s
|
|
|
47
47
|
* change (the key gone, every other key parsing identically).
|
|
48
48
|
*/
|
|
49
49
|
export declare function withoutTopLevelField(content: string, key: string): string | null;
|
|
50
|
-
/**
|
|
50
|
+
/**
|
|
51
|
+
* Replace a file's bytes atomically. A migration rewrite of an untracked
|
|
52
|
+
* `.kb/` source also rebinds its pending-source receipt, so the next sync
|
|
53
|
+
* reads the rewritten file instead of refusing it as hash drift.
|
|
54
|
+
*/
|
|
51
55
|
export declare function writeFileAtomically(filePath: string, content: string): void;
|
|
52
56
|
export declare function readText(filePath: string): string | null;
|
|
53
57
|
//# sourceMappingURL=kb-sources.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kb-sources.d.ts","sourceRoot":"","sources":["../../../src/operations/migration/kb-sources.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"kb-sources.d.ts","sourceRoot":"","sources":["../../../src/operations/migration/kb-sources.ts"],"names":[],"mappings":"AA+BA,OAAO,EAEL,KAAK,UAAU,EAEhB,MAAM,yBAAyB,CAAC;AAGjC,yEAAyE;AAEzE,MAAM,MAAM,gBAAgB,GAAG,QAAQ,CAAC;IACtC,IAAI,EAAE,UAAU,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,yCAAyC;IACzC,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC,CAAC;AAuBH,0EAA0E;AAE1E,wBAAgB,qBAAqB,CACnC,aAAa,EAAE,MAAM,EACrB,KAAK,GAAE,SAAS,UAAU,EAAiB,GAC1C,gBAAgB,EAAE,CAkBpB;AAED,6DAA6D;AAE7D,MAAM,MAAM,gBAAgB,GAAG,QAAQ,CAAC;IACtC,6DAA6D;IAC7D,MAAM,EAAE,MAAM,CAAC;IACf,sDAAsD;IACtD,IAAI,EAAE,MAAM,CAAC;IACb,2CAA2C;IAC3C,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,IAAI,GAAG,MAAM,CAAC;CACpB,CAAC,CAAC;AAEH;;;;;GAKG;AAEH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAczE;AAUD;;;;;GAKG;AAEH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAe3E;AAeD;;;;;GAKG;AAEH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,GACZ,MAAM,GAAG,IAAI,CAyBf;AAQD;;;;;;GAMG;AAEH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,GACV,MAAM,GAAG,IAAI,CAsBf;AAID;;;;GAIG;AAEH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAY3E;AAqBD,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAMxD"}
|
|
@@ -15,11 +15,13 @@
|
|
|
15
15
|
You should have received a copy of the GNU Affero General Public License
|
|
16
16
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
17
|
*/
|
|
18
|
+
import { createHash } from "node:crypto";
|
|
18
19
|
import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, writeFileSync, } from "node:fs";
|
|
19
20
|
import path from "node:path";
|
|
20
21
|
import { isDeepStrictEqual } from "node:util";
|
|
21
22
|
import { load as loadYaml } from "js-yaml";
|
|
22
23
|
import { ENTITY_LANES, KB_PATHS, } from "../../utils/kb-paths.js";
|
|
24
|
+
import { republishPendingSourceReceipt } from "../mutation/source-authoring.js";
|
|
23
25
|
function walkMarkdown(directory, files) {
|
|
24
26
|
let entries;
|
|
25
27
|
try {
|
|
@@ -214,13 +216,38 @@ export function withoutTopLevelField(content, key) {
|
|
|
214
216
|
}
|
|
215
217
|
return match === null ? content : `${slice.prefix}${text}${slice.suffix}`;
|
|
216
218
|
}
|
|
217
|
-
|
|
219
|
+
const KB_ROOT_DIRNAME = ".kb";
|
|
220
|
+
/**
|
|
221
|
+
* Replace a file's bytes atomically. A migration rewrite of an untracked
|
|
222
|
+
* `.kb/` source also rebinds its pending-source receipt, so the next sync
|
|
223
|
+
* reads the rewritten file instead of refusing it as hash drift.
|
|
224
|
+
*/
|
|
218
225
|
// implements REQ-cli-schema-migration
|
|
219
226
|
export function writeFileAtomically(filePath, content) {
|
|
220
227
|
mkdirSync(path.dirname(filePath), { recursive: true });
|
|
221
228
|
const tempPath = `${filePath}.kibi-migrate-${process.pid}-${Date.now()}`;
|
|
222
229
|
writeFileSync(tempPath, content, "utf8");
|
|
223
230
|
renameSync(tempPath, filePath);
|
|
231
|
+
const source = kbSourceLocation(filePath);
|
|
232
|
+
if (source === null)
|
|
233
|
+
return;
|
|
234
|
+
republishPendingSourceReceipt(source.workspaceRoot, source.relativePath, createHash("sha256").update(content, "utf8").digest("hex"));
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* The workspace root and workspace-relative path of a file under `.kb/`, or
|
|
238
|
+
* `null` for a file outside any knowledge root.
|
|
239
|
+
*/
|
|
240
|
+
function kbSourceLocation(filePath) {
|
|
241
|
+
const absolute = path.resolve(filePath);
|
|
242
|
+
const segments = absolute.split(path.sep);
|
|
243
|
+
const index = segments.lastIndexOf(KB_ROOT_DIRNAME);
|
|
244
|
+
if (index <= 0)
|
|
245
|
+
return null;
|
|
246
|
+
const workspaceRoot = segments.slice(0, index).join(path.sep) || path.sep;
|
|
247
|
+
return {
|
|
248
|
+
workspaceRoot,
|
|
249
|
+
relativePath: segments.slice(index).join("/"),
|
|
250
|
+
};
|
|
224
251
|
}
|
|
225
252
|
// implements REQ-cli-schema-migration
|
|
226
253
|
export function readText(filePath) {
|
|
@@ -4,6 +4,8 @@ import { CLOSE_SUPERSEDED_REQUIREMENTS_CODE, MIGRATION_SYNC_ACTION_ID, MIGRATION
|
|
|
4
4
|
export declare const ORIGIN_SCHEMA_VERSION = 6;
|
|
5
5
|
/** The KB schema generation that requires body context on current entities. */
|
|
6
6
|
export declare const BODY_CONTEXT_SCHEMA_VERSION = 8;
|
|
7
|
+
/** The KB schema generation that adds decision firmness. */
|
|
8
|
+
export declare const DECISION_FIRMNESS_SCHEMA_VERSION = 9;
|
|
7
9
|
/** Automatic: re-derive a drifted inventory with the current advisor. */
|
|
8
10
|
export declare const SEMANTIC_INVENTORY_REDERIVE_CODE = "semantic_inventory_rederive";
|
|
9
11
|
/** 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;AAyC1D,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,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;AAwEF;;;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,CAoM3B;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,CA0Ef;AAGD,eAAO,MAAM,uBAAuB,EAAE,WAAW,CAAC,MAAM,CAUtD,CAAC"}
|
|
@@ -27,12 +27,16 @@ import { applyOriginBackfill, planOriginBackfill } from "./origin-backfill.js";
|
|
|
27
27
|
import { POLARITY_VALUE_BACKFILL_CODE, applyPolarityValueBackfill, planPolarityValueBackfill, } from "./polarity-values.js";
|
|
28
28
|
import { applySourcePathRepairs, findSourceRepairs, plannedSourcePathRepairs, } from "./source-paths.js";
|
|
29
29
|
import { applySupersededClosures, planSupersededClosures, } from "./superseded-closure.js";
|
|
30
|
+
import { SUPERSEDES_REASON_ACKNOWLEDGE_CODE, applySupersedesReasonAcknowledgement, planSupersedesReasonAcknowledgement, } from "./supersedes-reason.js";
|
|
30
31
|
/** The KB schema generation that introduced entity `origin`. */
|
|
31
32
|
// implements REQ-kibi-schema6-migration, REQ-cli-schema-migration
|
|
32
33
|
export const ORIGIN_SCHEMA_VERSION = 6;
|
|
33
34
|
/** The KB schema generation that requires body context on current entities. */
|
|
34
35
|
// implements REQ-kb-entity-body-context, REQ-cli-schema-migration
|
|
35
36
|
export const BODY_CONTEXT_SCHEMA_VERSION = 8;
|
|
37
|
+
/** The KB schema generation that adds decision firmness. */
|
|
38
|
+
// implements REQ-kb-decision-firmness, REQ-cli-schema-migration
|
|
39
|
+
export const DECISION_FIRMNESS_SCHEMA_VERSION = 9;
|
|
36
40
|
/** Automatic: re-derive a drifted inventory with the current advisor. */
|
|
37
41
|
// implements REQ-kibi-schema6-migration, REQ-cli-schema-migration
|
|
38
42
|
export const SEMANTIC_INVENTORY_REDERIVE_CODE = "semantic_inventory_rederive";
|
|
@@ -88,7 +92,7 @@ function reviewAction(plan) {
|
|
|
88
92
|
safety: "review",
|
|
89
93
|
invocation: {
|
|
90
94
|
kind: "review",
|
|
91
|
-
instruction: `${plan.requirementId} (${plan.path}) no longer matches the current semantic advisor and cannot be re-derived automatically: ${plan.reasons.join("; ")}. Fix it
|
|
95
|
+
instruction: `${plan.requirementId} (${plan.path}) no longer matches the current semantic advisor and cannot be re-derived automatically: ${plan.reasons.join("; ")}. Fix it in ${plan.path} itself: kibi sync rejects this requirement, so store-backed tools (kb_upsert, kb_delete) cannot see it until it compiles. In its front matter, write the re-derived contract from this action's evidence.contract (semantic_inventory, logic_claims, semantic_source_hash and their version fields), then make modeled claims and requires_* links match one to one: re-ground or remove each listed grounding link, and keep a claim modeled only while a grounding fact with the same claim_key remains. Run kibi sync to confirm. To see how the advisor reads the prose, run \`kibi model --input -\` with {"mode":"analyze","type":"req","id":"${plan.requirementId}","text":<the requirement's semantic_text, or its statement when it has none>}.`,
|
|
92
96
|
},
|
|
93
97
|
affectedEntityIds: [plan.requirementId],
|
|
94
98
|
affectedFiles: [plan.path],
|
|
@@ -99,6 +103,8 @@ function reviewAction(plan) {
|
|
|
99
103
|
reasons: plan.reasons,
|
|
100
104
|
summary: plan.summary,
|
|
101
105
|
changes: plan.changes.filter((change) => change.change !== "kept"),
|
|
106
|
+
contract: plan.contract,
|
|
107
|
+
contractHash: plan.contractHash,
|
|
102
108
|
},
|
|
103
109
|
});
|
|
104
110
|
}
|
|
@@ -249,6 +255,38 @@ export function buildSchema6MigrationFragment(input) {
|
|
|
249
255
|
}));
|
|
250
256
|
}
|
|
251
257
|
}
|
|
258
|
+
// Schema 9: acknowledge supersedes recorded before they had to explain
|
|
259
|
+
// themselves. Manifest only; no source changes and no reason is written.
|
|
260
|
+
if (input.currentSchemaVersion === null ||
|
|
261
|
+
input.currentSchemaVersion < DECISION_FIRMNESS_SCHEMA_VERSION) {
|
|
262
|
+
const unexplained = planSupersedesReasonAcknowledgement(input.workspaceRoot);
|
|
263
|
+
if (unexplained.length > 0) {
|
|
264
|
+
const id = "supersedes-reason-acknowledge";
|
|
265
|
+
// Not a source rewrite, but the schema upgrade and the store sync
|
|
266
|
+
// must wait for it like one: the bumped schema blocks without it.
|
|
267
|
+
sourceRewriteActionIds.push(id);
|
|
268
|
+
actions.push(migrationAction({
|
|
269
|
+
id,
|
|
270
|
+
code: SUPERSEDES_REASON_ACKNOWLEDGE_CODE,
|
|
271
|
+
category: "schema",
|
|
272
|
+
safety: "automatic",
|
|
273
|
+
autoApplicable: true,
|
|
274
|
+
invocation: {
|
|
275
|
+
kind: "cli",
|
|
276
|
+
command_argv: ["kibi", "migrate", "--yes"],
|
|
277
|
+
},
|
|
278
|
+
affectedEntityIds: unexplained.map((row) => row.id),
|
|
279
|
+
affectedFiles: [".kb/manifest.json"],
|
|
280
|
+
postconditions: [{ rule: "supersedes-reason-missing", findings: 0 }],
|
|
281
|
+
evidence: {
|
|
282
|
+
reason: "Schema 9 blocks a current requirement or ADR that supersedes another without a 'Why this changed' section. Existing ones are acknowledged in the manifest (counted by supersedes-reason-acknowledged); no reason is invented.",
|
|
283
|
+
count: unexplained.length,
|
|
284
|
+
byType: countByType(unexplained),
|
|
285
|
+
preserves: "every authored source file",
|
|
286
|
+
},
|
|
287
|
+
}));
|
|
288
|
+
}
|
|
289
|
+
}
|
|
252
290
|
const drift = planInventoryRederivation(input.workspaceRoot);
|
|
253
291
|
for (const plan of drift) {
|
|
254
292
|
const action = plan.safe ? rederiveAction(plan) : reviewAction(plan);
|
|
@@ -397,6 +435,10 @@ export async function applySchema6MigrationAction(action, context) {
|
|
|
397
435
|
applyContextMissingTags(context.workspaceRoot);
|
|
398
436
|
return;
|
|
399
437
|
}
|
|
438
|
+
case SUPERSEDES_REASON_ACKNOWLEDGE_CODE: {
|
|
439
|
+
applySupersedesReasonAcknowledgement(context.workspaceRoot);
|
|
440
|
+
return;
|
|
441
|
+
}
|
|
400
442
|
case SEMANTIC_INVENTORY_REDERIVE_CODE: {
|
|
401
443
|
const requirementId = action.affectedEntityIds[0];
|
|
402
444
|
if (requirementId === undefined)
|
|
@@ -440,6 +482,7 @@ export const SCHEMA6_AUTOMATIC_CODES = new Set([
|
|
|
440
482
|
POLARITY_VALUE_BACKFILL_CODE,
|
|
441
483
|
SEMANTIC_TEXT_PIN_CODE,
|
|
442
484
|
CONTEXT_MISSING_TAG_CODE,
|
|
485
|
+
SUPERSEDES_REASON_ACKNOWLEDGE_CODE,
|
|
443
486
|
SEMANTIC_INVENTORY_REDERIVE_CODE,
|
|
444
487
|
ENTITY_ORIGIN_BACKFILL_CODE,
|
|
445
488
|
CLOSE_SUPERSEDED_REQUIREMENTS_CODE,
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/** Migration action code for the schema 9 acknowledgement. */
|
|
2
|
+
export declare const SUPERSEDES_REASON_ACKNOWLEDGE_CODE = "supersedes_reason_acknowledge";
|
|
3
|
+
/** One superseding decision the migration acknowledges. */
|
|
4
|
+
export type SupersedesReasonTarget = Readonly<{
|
|
5
|
+
id: string;
|
|
6
|
+
type: string;
|
|
7
|
+
path: string;
|
|
8
|
+
/** The supersede edges to acknowledge, as the manifest records them. */
|
|
9
|
+
edges: readonly string[];
|
|
10
|
+
}>;
|
|
11
|
+
/**
|
|
12
|
+
* Superseding requirements and ADRs without a "Why this changed" section
|
|
13
|
+
* whose supersede edges the manifest does not acknowledge yet, retired ones
|
|
14
|
+
* included. Nothing in the sources changes: no reason is written, the
|
|
15
|
+
* manifest only records that these edges predate the rule. Read-only.
|
|
16
|
+
*/
|
|
17
|
+
export declare function planSupersedesReasonAcknowledgement(workspaceRoot: string): SupersedesReasonTarget[];
|
|
18
|
+
/** The manifest list with the targets' edges added, sorted and unique. */
|
|
19
|
+
export declare function mergeSupersedesAcknowledgements(existing: readonly string[] | undefined, targets: readonly SupersedesReasonTarget[]): string[];
|
|
20
|
+
/**
|
|
21
|
+
* Record the acknowledged edges in the manifest; returns how many entities
|
|
22
|
+
* were acknowledged. Without a manifest there is no schema to upgrade from,
|
|
23
|
+
* so it refuses rather than report an acknowledgement it did not write.
|
|
24
|
+
*/
|
|
25
|
+
export declare function applySupersedesReasonAcknowledgement(workspaceRoot: string): number;
|
|
26
|
+
//# sourceMappingURL=supersedes-reason.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"supersedes-reason.d.ts","sourceRoot":"","sources":["../../../src/operations/migration/supersedes-reason.ts"],"names":[],"mappings":"AA0BA,8DAA8D;AAE9D,eAAO,MAAM,kCAAkC,kCACd,CAAC;AAElC,2DAA2D;AAE3D,MAAM,MAAM,sBAAsB,GAAG,QAAQ,CAAC;IAC5C,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,wEAAwE;IACxE,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1B,CAAC,CAAC;AAEH;;;;;GAKG;AAEH,wBAAgB,mCAAmC,CACjD,aAAa,EAAE,MAAM,GACpB,sBAAsB,EAAE,CAgB1B;AAED,0EAA0E;AAE1E,wBAAgB,+BAA+B,CAC7C,QAAQ,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,EACvC,OAAO,EAAE,SAAS,sBAAsB,EAAE,GACzC,MAAM,EAAE,CAIV;AAED;;;;GAIG;AAEH,wBAAgB,oCAAoC,CAClD,aAAa,EAAE,MAAM,GACpB,MAAM,CAiBR"}
|
|
@@ -0,0 +1,69 @@
|
|
|
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 { authoredSupersedes, listDecisionEntities, supersedeAcknowledgements, unexplainedSupersedes, } from "../../public/operations/decision-firmness.js";
|
|
19
|
+
import { readKbManifest, writeKbManifest } from "../../utils/kb-manifest.js";
|
|
20
|
+
/** Migration action code for the schema 9 acknowledgement. */
|
|
21
|
+
// implements REQ-kb-decision-firmness, REQ-cli-schema-migration
|
|
22
|
+
export const SUPERSEDES_REASON_ACKNOWLEDGE_CODE = "supersedes_reason_acknowledge";
|
|
23
|
+
/**
|
|
24
|
+
* Superseding requirements and ADRs without a "Why this changed" section
|
|
25
|
+
* whose supersede edges the manifest does not acknowledge yet, retired ones
|
|
26
|
+
* included. Nothing in the sources changes: no reason is written, the
|
|
27
|
+
* manifest only records that these edges predate the rule. Read-only.
|
|
28
|
+
*/
|
|
29
|
+
// implements REQ-kb-decision-firmness, REQ-cli-schema-migration
|
|
30
|
+
export function planSupersedesReasonAcknowledgement(workspaceRoot) {
|
|
31
|
+
const entities = listDecisionEntities(workspaceRoot);
|
|
32
|
+
const known = new Set(readKbManifest(workspaceRoot)?.supersedesReasonAcknowledged ?? []);
|
|
33
|
+
const edges = authoredSupersedes(workspaceRoot, entities);
|
|
34
|
+
return unexplainedSupersedes(entities, edges)
|
|
35
|
+
.map((entity) => ({
|
|
36
|
+
id: entity.id,
|
|
37
|
+
type: entity.type,
|
|
38
|
+
path: entity.path,
|
|
39
|
+
edges: supersedeAcknowledgements(entity.id, edges).filter((edge) => !known.has(edge)),
|
|
40
|
+
}))
|
|
41
|
+
.filter((target) => target.edges.length > 0);
|
|
42
|
+
}
|
|
43
|
+
/** The manifest list with the targets' edges added, sorted and unique. */
|
|
44
|
+
// implements REQ-kb-decision-firmness
|
|
45
|
+
export function mergeSupersedesAcknowledgements(existing, targets) {
|
|
46
|
+
return [
|
|
47
|
+
...new Set([...(existing ?? []), ...targets.flatMap((t) => t.edges)]),
|
|
48
|
+
].sort();
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Record the acknowledged edges in the manifest; returns how many entities
|
|
52
|
+
* were acknowledged. Without a manifest there is no schema to upgrade from,
|
|
53
|
+
* so it refuses rather than report an acknowledgement it did not write.
|
|
54
|
+
*/
|
|
55
|
+
// implements REQ-kb-decision-firmness, REQ-cli-schema-migration
|
|
56
|
+
export function applySupersedesReasonAcknowledgement(workspaceRoot) {
|
|
57
|
+
const targets = planSupersedesReasonAcknowledgement(workspaceRoot);
|
|
58
|
+
if (targets.length === 0)
|
|
59
|
+
return 0;
|
|
60
|
+
const manifest = readKbManifest(workspaceRoot);
|
|
61
|
+
if (manifest === null) {
|
|
62
|
+
throw new Error("Cannot acknowledge existing supersedes without .kb/manifest.json; run 'kibi migrate --yes', which writes the manifest and the acknowledgement together.");
|
|
63
|
+
}
|
|
64
|
+
writeKbManifest(workspaceRoot, {
|
|
65
|
+
...manifest,
|
|
66
|
+
supersedesReasonAcknowledged: mergeSupersedesAcknowledgements(manifest.supersedesReasonAcknowledged, targets),
|
|
67
|
+
});
|
|
68
|
+
return targets.length;
|
|
69
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"predicate-applyplan.d.ts","sourceRoot":"","sources":["../../../src/operations/modeling/predicate-applyplan.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"predicate-applyplan.d.ts","sourceRoot":"","sources":["../../../src/operations/modeling/predicate-applyplan.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAEV,wBAAwB,EACxB,wBAAwB,EACxB,mBAAmB,EACnB,0BAA0B,EAC1B,qBAAqB,EACtB,MAAM,sBAAsB,CAAC;AAQ9B,wBAAgB,eAAe,CAC7B,MAAM,EAAE,wBAAwB,EAChC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,gBAAgB,GAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAM,EACvD,YAAY,CAAC,EAAE,QAAQ,GAAG,MAAM,EAChC,WAAW,CAAC,EAAE;IACZ,WAAW,CAAC,EAAE,UAAU,GAAG,UAAU,CAAC;IACtC,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,eAAe,CAAC,EAAE,wBAAwB,CAAC;IAC3C,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACzC,GACA,mBAAmB,CAuLrB;AAGD,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,mBAAmB,EAC/B,IAAI,EAAE,qBAAqB,GAC1B,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAkDhC;AAGD,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,aAAa,EAAE,MAAM,GAAG,SAAS,EACjC,SAAS,CAAC,EAAE,MAAM,EAClB,mBAAmB,GAAE,SAAS,MAAM,EAAO,GAC1C,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAuBhC;AAoBD;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,qBAAqB,GAC1B,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAwBhC;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,GACd,0BAA0B,CAoE5B"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { semanticClaimKey } from "../semantic-advisor/clauses.js";
|
|
1
|
+
import { normalizeSemanticClause, semanticClaimKey, } from "../semantic-advisor/clauses.js";
|
|
2
2
|
import { exactLauncherPredicateArgs } from "../semantic-advisor/predicate-rules-launcher.js";
|
|
3
3
|
import { aggregateBindingProvenance, bindingCanBeApplied, classifyBinding, isGenericPlaceholder, isParticipantArgumentType, } from "./predicate-bindings.js";
|
|
4
4
|
import { inferArgs } from "./predicate-inference.js";
|
|
@@ -190,11 +190,19 @@ export function buildPredicateApplyPlan(suggestion, args) {
|
|
|
190
190
|
? { subject_key: suggestion.subject_key }
|
|
191
191
|
: {}),
|
|
192
192
|
predicate_name: suggestion.predicate_name,
|
|
193
|
+
// The schema's namespace, so the fact conforms to the project
|
|
194
|
+
// schema it was planned from rather than to default:<name>.
|
|
195
|
+
...(suggestion.schema.predicate_namespace
|
|
196
|
+
? { predicate_namespace: suggestion.schema.predicate_namespace }
|
|
197
|
+
: {}),
|
|
193
198
|
predicate_args: suggestion.predicate_args,
|
|
194
199
|
canonical_key: suggestion.canonical_key,
|
|
195
200
|
polarity: suggestion.polarity,
|
|
196
201
|
claim_key: claimKey,
|
|
197
|
-
|
|
202
|
+
// The ledger stores the clause without its sentence punctuation, and
|
|
203
|
+
// the proof compares the fact's claim_text with the ledger entry
|
|
204
|
+
// verbatim, so the fact quotes the same normalised clause.
|
|
205
|
+
claim_text: normalizeSemanticClause(args.text),
|
|
198
206
|
},
|
|
199
207
|
relationships: [],
|
|
200
208
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"predicate-loader.d.ts","sourceRoot":"","sources":["../../../src/operations/modeling/predicate-loader.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0CAA0C,CAAC;AAK3E,OAAO,KAAK,EACV,wBAAwB,EACxB,mBAAmB,EACpB,MAAM,sBAAsB,CAAC;AAI9B,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAExE;AAGD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,wBAAwB,GAAG,IAAI,CACxE,wBAAwB,EACxB,UAAU,CACX,GAAG;IACF,WAAW,EAAE,mBAAmB,CAAC;CAClC,
|
|
1
|
+
{"version":3,"file":"predicate-loader.d.ts","sourceRoot":"","sources":["../../../src/operations/modeling/predicate-loader.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0CAA0C,CAAC;AAK3E,OAAO,KAAK,EACV,wBAAwB,EACxB,mBAAmB,EACpB,MAAM,sBAAsB,CAAC;AAI9B,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAExE;AAGD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,wBAAwB,GAAG,IAAI,CACxE,wBAAwB,EACxB,UAAU,CACX,GAAG;IACF,WAAW,EAAE,mBAAmB,CAAC;CAClC,CAgCA;AAGD,wBAAsB,4BAA4B,CAChD,MAAM,EAAE,UAAU,GAAG,IAAI,EACzB,sBAAsB,EAAE,OAAO,EAC/B,QAAQ,EAAE,MAAM,EAAE,GACjB,OAAO,CAAC,wBAAwB,EAAE,CAAC,CAwBrC;AAGD,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,wBAAwB,EAAE,CAoE5B;AAGD,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,mBAAmB,GAAG,SAAS,CAOjC;AAGD,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,EAAE,CAQpD"}
|
|
@@ -10,6 +10,9 @@ export function schemaForCandidate(schema) {
|
|
|
10
10
|
return {
|
|
11
11
|
id: schema.id,
|
|
12
12
|
predicate_name: schema.predicate_name,
|
|
13
|
+
...(schema.predicate_namespace
|
|
14
|
+
? { predicate_namespace: schema.predicate_namespace }
|
|
15
|
+
: {}),
|
|
13
16
|
title: schema.title,
|
|
14
17
|
description: schema.description,
|
|
15
18
|
argument_names: schema.argument_names,
|
|
@@ -67,10 +70,18 @@ export function predicateSchemaFromEntity(entity) {
|
|
|
67
70
|
const argumentDescriptions = stringArray(entity.argument_descriptions);
|
|
68
71
|
const keyArguments = stringArray(entity.key_arguments);
|
|
69
72
|
const vocabulary = predicateVocabularyFromEntity(entity);
|
|
73
|
+
// A project schema's namespace is part of the predicate signature the
|
|
74
|
+
// conformance rule checks, so a planned fact has to carry it.
|
|
75
|
+
const predicateNamespace = normalizeOptionalString(typeof entity.predicate_namespace === "string"
|
|
76
|
+
? entity.predicate_namespace
|
|
77
|
+
: undefined);
|
|
70
78
|
return [
|
|
71
79
|
{
|
|
72
80
|
id: String(entity.id ?? hashId("FACT-SCHEMA", [predicateName])),
|
|
73
81
|
predicate_name: predicateName,
|
|
82
|
+
...(predicateNamespace && predicateNamespace !== "default"
|
|
83
|
+
? { predicate_namespace: predicateNamespace }
|
|
84
|
+
: {}),
|
|
74
85
|
title: String(entity.title ?? predicateName),
|
|
75
86
|
description: String(entity.description ??
|
|
76
87
|
`Project-local ${predicateName} predicate schema.`),
|
|
@@ -6,6 +6,8 @@ export interface PredicateUsageHints {
|
|
|
6
6
|
export interface PredicateSchemaCandidate {
|
|
7
7
|
id: string;
|
|
8
8
|
predicate_name: string;
|
|
9
|
+
/** The schema's predicate_namespace; absent for the default namespace. */
|
|
10
|
+
predicate_namespace?: string;
|
|
9
11
|
title: string;
|
|
10
12
|
description: string;
|
|
11
13
|
argument_names: string[];
|
|
@@ -128,7 +130,30 @@ export interface ExistingClaimGrounding {
|
|
|
128
130
|
};
|
|
129
131
|
factId: string;
|
|
130
132
|
factKind: string | null;
|
|
133
|
+
/** The stored claim_key of the grounding fact. */
|
|
131
134
|
claimKey: string;
|
|
135
|
+
/** The stored canonical_key of the grounding fact (predicate facts), else null. */
|
|
136
|
+
canonicalKey: string | null;
|
|
137
|
+
/**
|
|
138
|
+
* How the fact was recognised as grounding this claim: the same claim_key
|
|
139
|
+
* (the same proposition text), or the same canonical_key as the recommended
|
|
140
|
+
* candidate (the same predicate tuple stated in other words).
|
|
141
|
+
*/
|
|
142
|
+
matchedBy: "claim_key" | "canonical_key";
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* A stored decision-predicate fact of a current requirement that agrees with
|
|
146
|
+
* the recommended candidate on every key argument and decides the opposite,
|
|
147
|
+
* found when no hash-bound plan carried the contradiction analysis.
|
|
148
|
+
*/
|
|
149
|
+
export interface CandidateDecisionConflict {
|
|
150
|
+
requirementId: string;
|
|
151
|
+
factId: string;
|
|
152
|
+
/** The stored fact's effective decision. */
|
|
153
|
+
effect: string;
|
|
154
|
+
/** The candidate's effective decision. */
|
|
155
|
+
proposedEffect: string;
|
|
156
|
+
canonicalKey: string;
|
|
132
157
|
}
|
|
133
158
|
export interface SuggestPredicatesResult {
|
|
134
159
|
content: Array<{
|
|
@@ -143,7 +168,7 @@ export interface SuggestPredicatesResult {
|
|
|
143
168
|
requirementId: string | null;
|
|
144
169
|
subject: string;
|
|
145
170
|
candidates: PredicateSuggestion[];
|
|
146
|
-
recommendedAction: "apply_requires_predicate" | "provide_argument_bindings" | "resolve_schema_reference" | "record_ontology_gap" | "review_nonlogical" | "replace_grounding";
|
|
171
|
+
recommendedAction: "apply_requires_predicate" | "provide_argument_bindings" | "resolve_schema_reference" | "record_ontology_gap" | "review_nonlogical" | "replace_grounding" | "extend_requirement" | "keep_existing_grounding";
|
|
147
172
|
recommendedPredicateSchema: RecommendedPredicateSchema | null;
|
|
148
173
|
applyPlan: Array<Record<string, unknown>>;
|
|
149
174
|
relationshipPlan: Record<string, unknown> | null;
|
|
@@ -156,6 +181,12 @@ export interface SuggestPredicatesResult {
|
|
|
156
181
|
/** The planned predicate fact id a requires_predicate link must target (never a candidate id). */
|
|
157
182
|
relationshipTarget?: string | null;
|
|
158
183
|
existingGrounding?: ExistingClaimGrounding[];
|
|
184
|
+
/**
|
|
185
|
+
* Stored decision facts of current requirements that contradict the
|
|
186
|
+
* recommended candidate on its key arguments; empty when a plan carried
|
|
187
|
+
* the contradiction analysis or no complete candidate was found.
|
|
188
|
+
*/
|
|
189
|
+
decisionConflicts?: CandidateDecisionConflict[];
|
|
159
190
|
replacementPlan?: Record<string, unknown> | null;
|
|
160
191
|
/** On provide_argument_bindings: one hint per unbound argument of the recommended candidate. */
|
|
161
192
|
bindingHints?: BindingHint[];
|