kibi-cli 2.23.0 → 2.25.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/commands/migrate.d.ts.map +1 -1
- package/dist/commands/migrate.js +23 -0
- package/dist/decision-firmness.d.ts +16 -4
- package/dist/decision-firmness.d.ts.map +1 -1
- package/dist/decision-firmness.js +29 -6
- package/dist/extractors/markdown.d.ts.map +1 -1
- package/dist/extractors/markdown.js +2 -1
- package/dist/firm-decision-edit.d.ts +30 -0
- package/dist/firm-decision-edit.d.ts.map +1 -0
- package/dist/firm-decision-edit.js +90 -0
- package/dist/intent-search.d.ts +2 -0
- package/dist/intent-search.d.ts.map +1 -1
- package/dist/intent-search.js +16 -5
- package/dist/operations/bootstrap/candidate-helpers.d.ts +6 -0
- package/dist/operations/bootstrap/candidate-helpers.d.ts.map +1 -1
- package/dist/operations/bootstrap/candidate-helpers.js +19 -0
- package/dist/operations/bootstrap/intent-claims.d.ts.map +1 -1
- package/dist/operations/bootstrap/intent-claims.js +2 -2
- package/dist/operations/bootstrap/markdown-candidates.d.ts.map +1 -1
- package/dist/operations/bootstrap/markdown-candidates.js +2 -2
- package/dist/operations/migration/firm-supersede.d.ts +19 -0
- package/dist/operations/migration/firm-supersede.d.ts.map +1 -0
- package/dist/operations/migration/firm-supersede.js +60 -0
- package/dist/operations/migration/schema6.d.ts.map +1 -1
- package/dist/operations/migration/schema6.js +41 -0
- package/dist/operations/mutation/firm-decision-guard.d.ts +10 -0
- package/dist/operations/mutation/firm-decision-guard.d.ts.map +1 -0
- package/dist/operations/mutation/firm-decision-guard.js +71 -0
- package/dist/operations/mutation/requirement-semantics.d.ts +3 -1
- package/dist/operations/mutation/requirement-semantics.d.ts.map +1 -1
- package/dist/operations/mutation/requirement-semantics.js +13 -2
- package/dist/operations/mutation/upsert.d.ts.map +1 -1
- package/dist/operations/mutation/upsert.js +2 -0
- package/dist/public/operations/catalog.d.ts +3 -3
- package/dist/public/operations/decision-firmness.d.ts +25 -1
- package/dist/public/operations/decision-firmness.d.ts.map +1 -1
- package/dist/public/operations/decision-firmness.js +134 -8
- package/dist/public/operations/discovery-executors.d.ts.map +1 -1
- package/dist/public/operations/discovery-executors.js +19 -6
- package/dist/public/operations/source-path-dangling.js +1 -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/mutation-schemas.d.ts +1 -1
- package/dist/public/operations/specs/mutation-schemas.js +1 -1
- package/dist/public/operations/specs/upsert.d.ts +2 -2
- package/dist/public/operations/specs/upsert.js +1 -1
- package/dist/public/schemas/entity.js +1 -1
- package/dist/public/skills/kibi-bootstrap/SKILL.md +3 -3
- package/dist/public/skills/kibi-usage/SKILL.md +36 -14
- package/dist/schemas/entity.schema.json +1 -1
- package/dist/search-answer.d.ts.map +1 -1
- package/dist/search-answer.js +9 -1
- package/dist/types/entities.d.ts +2 -2
- package/dist/types/entities.d.ts.map +1 -1
- package/dist/utils/kb-manifest.d.ts +7 -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 +5 -0
- package/dist/utils/rule-registry.generated.d.ts.map +1 -1
- package/dist/utils/rule-registry.generated.js +6 -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 +1 -1
- package/src/public/operations/decision-firmness.ts +187 -17
- package/src/public/operations/discovery-executors.ts +28 -5
- package/src/public/operations/source-path-dangling.ts +1 -1
- package/src/public/operations/specs/check-rules.generated.ts +2 -1
- package/src/public/operations/specs/mutation-schemas.ts +1 -1
- package/src/public/operations/specs/upsert.ts +1 -1
- package/src/public/schemas/entity.ts +1 -1
- package/src/public/skills/kibi-bootstrap/SKILL.md +3 -3
- package/src/public/skills/kibi-usage/SKILL.md +36 -14
- package/src/schemas/entity.schema.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema6.d.ts","sourceRoot":"","sources":["../../../src/operations/migration/schema6.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"schema6.d.ts","sourceRoot":"","sources":["../../../src/operations/migration/schema6.ts"],"names":[],"mappings":"AAwBA,OAAO,EACL,KAAK,eAAe,EAErB,MAAM,2CAA2C,CAAC;AACnD,OAAO,EAEL,kCAAkC,EAClC,wBAAwB,EACxB,mBAAmB,EAEnB,wBAAwB,EAOzB,MAAM,kDAAkD,CAAC;AAyD1D,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,CAuP3B;AAED;;;;;;GAMG;AAEH,wBAAgB,2BAA2B,CAAC,aAAa,EAAE,MAAM,GAAG;IAClE,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,sBAAsB,EAAE,MAAM,EAAE,CAAC;CAClC,CAuCA;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;AAgDD,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,CAoHf;AAED;;;GAGG;AAEH,eAAO,MAAM,+BAA+B,EAAE,WAAW,CAAC,MAAM,CAK9D,CAAC;AAGH,eAAO,MAAM,uBAAuB,EAAE,WAAW,CAAC,MAAM,CAYtD,CAAC"}
|
|
@@ -17,10 +17,12 @@
|
|
|
17
17
|
*/
|
|
18
18
|
import path from "node:path";
|
|
19
19
|
import { extractFromMarkdown, } from "../../extractors/markdown.js";
|
|
20
|
+
import { FIRMNESS_FROM_ORIGIN_SCHEMA_VERSION } from "../../public/operations/decision-firmness.js";
|
|
20
21
|
import { migrationAction, } from "../../public/operations/migration-plan.js";
|
|
21
22
|
import { CLOSE_SUPERSEDED_REQUIREMENTS_ACTION_ID, CLOSE_SUPERSEDED_REQUIREMENTS_CODE, MIGRATION_SYNC_ACTION_ID, MIGRATION_SYNC_CODE, SOURCE_PATH_REWRITE_ACTION_ID, SOURCE_PATH_REWRITE_CODE, closeSupersededRequirementsActionInput, exceptionUnapprovedActionInput, migrationSyncActionInput, sourcePathReviewActionInput, sourcePathRewriteActionInput, supersessionCycleReviewActionInput, } from "../../public/operations/schema6-check-actions.js";
|
|
22
23
|
import { readAllShards } from "../../relationships/shards.js";
|
|
23
24
|
import { CONTEXT_MISSING_TAG_CODE, SEMANTIC_TEXT_PIN_CODE, applyContextMissingTags, applySemanticTextPins, countByType, planContextMissingTags, planSemanticTextPins, } from "./entity-body-context.js";
|
|
25
|
+
import { FIRM_SUPERSEDE_ACKNOWLEDGE_CODE, applyFirmSupersedeAcknowledgement, planFirmSupersedeAcknowledgement, } from "./firm-supersede.js";
|
|
24
26
|
import { applyInventoryRederivation, applyInventoryRederivationDroppingGrounding, planInventoryRederivation, } from "./inventory-rederive.js";
|
|
25
27
|
import { listLaneMarkdownFiles } from "./kb-sources.js";
|
|
26
28
|
import { applyOriginBackfill, planOriginBackfill } from "./origin-backfill.js";
|
|
@@ -470,6 +472,40 @@ export function buildSchema6MigrationFragment(input) {
|
|
|
470
472
|
}));
|
|
471
473
|
}
|
|
472
474
|
}
|
|
475
|
+
// Schema 10: a decision without firmness that an agent did not write now
|
|
476
|
+
// reads as firm. Acknowledge supersedes of such decisions recorded before
|
|
477
|
+
// that, so history does not block; new ones must come from a person.
|
|
478
|
+
if (input.currentSchemaVersion === null ||
|
|
479
|
+
input.currentSchemaVersion < FIRMNESS_FROM_ORIGIN_SCHEMA_VERSION) {
|
|
480
|
+
const edges = planFirmSupersedeAcknowledgement(input.workspaceRoot);
|
|
481
|
+
if (edges.length > 0) {
|
|
482
|
+
const id = "firm-supersede-acknowledge";
|
|
483
|
+
// Manifest only, but the bumped schema blocks without it.
|
|
484
|
+
sourceRewriteActionIds.push(id);
|
|
485
|
+
actions.push(migrationAction({
|
|
486
|
+
id,
|
|
487
|
+
code: FIRM_SUPERSEDE_ACKNOWLEDGE_CODE,
|
|
488
|
+
category: "schema",
|
|
489
|
+
safety: "automatic",
|
|
490
|
+
autoApplicable: true,
|
|
491
|
+
invocation: {
|
|
492
|
+
kind: "cli",
|
|
493
|
+
command_argv: ["kibi", "migrate", "--yes"],
|
|
494
|
+
},
|
|
495
|
+
affectedEntityIds: [
|
|
496
|
+
...new Set(edges.map((edge) => edge.split(" -> ")[0] ?? edge)),
|
|
497
|
+
].sort(),
|
|
498
|
+
affectedFiles: [".kb/manifest.json"],
|
|
499
|
+
postconditions: [{ rule: "decision-firm-superseded", findings: 0 }],
|
|
500
|
+
evidence: {
|
|
501
|
+
reason: "Schema 10 reads a requirement or ADR without firmness as firm unless an agent wrote it, and blocks a replacement of a firm decision that is not itself firm. Supersedes recorded before that are acknowledged in the manifest; no firmness is written.",
|
|
502
|
+
count: edges.length,
|
|
503
|
+
edges,
|
|
504
|
+
preserves: "every authored source file",
|
|
505
|
+
},
|
|
506
|
+
}));
|
|
507
|
+
}
|
|
508
|
+
}
|
|
473
509
|
const drift = planInventoryRederivation(input.workspaceRoot);
|
|
474
510
|
for (const plan of drift) {
|
|
475
511
|
const action = plan.safe ? rederiveAction(plan) : reviewAction(plan);
|
|
@@ -670,6 +706,10 @@ export async function applySchema6MigrationAction(action, context) {
|
|
|
670
706
|
applySupersedesReasonAcknowledgement(context.workspaceRoot);
|
|
671
707
|
return;
|
|
672
708
|
}
|
|
709
|
+
case FIRM_SUPERSEDE_ACKNOWLEDGE_CODE: {
|
|
710
|
+
applyFirmSupersedeAcknowledgement(context.workspaceRoot);
|
|
711
|
+
return;
|
|
712
|
+
}
|
|
673
713
|
case SEMANTIC_INVENTORY_REDERIVE_CODE: {
|
|
674
714
|
const requirementId = action.affectedEntityIds[0];
|
|
675
715
|
if (requirementId === undefined)
|
|
@@ -749,6 +789,7 @@ export const SCHEMA6_AUTOMATIC_CODES = new Set([
|
|
|
749
789
|
SEMANTIC_TEXT_PIN_CODE,
|
|
750
790
|
CONTEXT_MISSING_TAG_CODE,
|
|
751
791
|
SUPERSEDES_REASON_ACKNOWLEDGE_CODE,
|
|
792
|
+
FIRM_SUPERSEDE_ACKNOWLEDGE_CODE,
|
|
752
793
|
SEMANTIC_INVENTORY_REDERIVE_CODE,
|
|
753
794
|
ENTITY_ORIGIN_BACKFILL_CODE,
|
|
754
795
|
CLOSE_SUPERSEDED_REQUIREMENTS_CODE,
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { StoredEntityLookup } from "./stored-entity.js";
|
|
2
|
+
import type { UpsertInput } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Refuse an upsert that changes a current firm requirement's or ADR's claim
|
|
5
|
+
* in place unless it cites new human words for the change. The decision is
|
|
6
|
+
* judged as authored before the write, so dropping its firmness or origin in
|
|
7
|
+
* the same write does not make it editable.
|
|
8
|
+
*/
|
|
9
|
+
export declare function assertFirmDecisionUnchanged(input: UpsertInput, workspaceRoot: string, lookup: StoredEntityLookup): Promise<void>;
|
|
10
|
+
//# sourceMappingURL=firm-decision-guard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"firm-decision-guard.d.ts","sourceRoot":"","sources":["../../../src/operations/mutation/firm-decision-guard.ts"],"names":[],"mappings":"AA8BA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAwB9C;;;;;GAKG;AAEH,wBAAsB,2BAA2B,CAC/C,KAAK,EAAE,WAAW,EAClB,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,kBAAkB,GACzB,OAAO,CAAC,IAAI,CAAC,CA2Bf"}
|
|
@@ -0,0 +1,71 @@
|
|
|
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 { readFileSync } from "node:fs";
|
|
19
|
+
import path from "node:path";
|
|
20
|
+
import { carriesFirmness } from "../../decision-firmness.js";
|
|
21
|
+
import { firmEditGuidance, unapprovedFirmEdit, } from "../../firm-decision-edit.js";
|
|
22
|
+
import { isCurrentAuthoredEntity, readAuthoredEntity, } from "../../public/operations/entity-context.js";
|
|
23
|
+
function readStoredDocument(workspaceRoot, stored) {
|
|
24
|
+
const source = stored.source;
|
|
25
|
+
if (typeof source !== "string" || !source.endsWith(".md"))
|
|
26
|
+
return undefined;
|
|
27
|
+
try {
|
|
28
|
+
const authored = readAuthoredEntity(readFileSync(path.resolve(workspaceRoot, source), "utf8"), source);
|
|
29
|
+
if (authored === null)
|
|
30
|
+
return undefined;
|
|
31
|
+
return {
|
|
32
|
+
type: authored.type,
|
|
33
|
+
data: authored.data,
|
|
34
|
+
body: authored.body,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Refuse an upsert that changes a current firm requirement's or ADR's claim
|
|
43
|
+
* in place unless it cites new human words for the change. The decision is
|
|
44
|
+
* judged as authored before the write, so dropping its firmness or origin in
|
|
45
|
+
* the same write does not make it editable.
|
|
46
|
+
*/
|
|
47
|
+
// implements REQ-kb-firm-decision-edit
|
|
48
|
+
export async function assertFirmDecisionUnchanged(input, workspaceRoot, lookup) {
|
|
49
|
+
if (!carriesFirmness(input.type))
|
|
50
|
+
return;
|
|
51
|
+
const stored = await lookup.entity();
|
|
52
|
+
if (stored === undefined || stored === null)
|
|
53
|
+
return;
|
|
54
|
+
const authored = readStoredDocument(workspaceRoot, stored);
|
|
55
|
+
const before = authored ?? {
|
|
56
|
+
type: input.type,
|
|
57
|
+
data: stored,
|
|
58
|
+
body: input.document?.body ?? "",
|
|
59
|
+
};
|
|
60
|
+
if (!isCurrentAuthoredEntity({ id: input.id, path: "", ...before, data: { ...before.data } }, new Set()))
|
|
61
|
+
return;
|
|
62
|
+
const after = {
|
|
63
|
+
type: input.type,
|
|
64
|
+
data: { ...before.data, ...input.properties },
|
|
65
|
+
body: input.document?.body ?? before.body,
|
|
66
|
+
};
|
|
67
|
+
const changed = unapprovedFirmEdit(before, after);
|
|
68
|
+
if (changed.length === 0)
|
|
69
|
+
return;
|
|
70
|
+
throw new Error(`Entity validation failed: ${input.id} is a firm decision, so kb_upsert does not change its ${changed.join(", ")} in place. ${firmEditGuidance(input.type)}.`);
|
|
71
|
+
}
|
|
@@ -8,7 +8,9 @@ import type { StagedUpsertState, UpsertInput } from "./types.js";
|
|
|
8
8
|
* relationship (for example `specified_by`) and carries no `semantic_*` or
|
|
9
9
|
* `logic_claims` field, and no `title` or `text_ref` that differs from the
|
|
10
10
|
* stored value, is merged over the stored semantic contract (and the stored
|
|
11
|
-
* `text_ref` it omits) before validation.
|
|
11
|
+
* `text_ref` it omits) before validation. When the stored ledger reads its
|
|
12
|
+
* prose from `semantic_text`, a changed `text_ref` is merged the same way,
|
|
13
|
+
* since it is not the prose. The
|
|
12
14
|
* proposition-complete check then runs against the merged requirement, which
|
|
13
15
|
* is also what the write records. A payload that supplies any ledger field or
|
|
14
16
|
* changes the prose is validated exactly as given.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"requirement-semantics.d.ts","sourceRoot":"","sources":["../../../src/operations/mutation/requirement-semantics.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0CAA0C,CAAC;AAE3E,OAAO,EAEL,KAAK,oBAAoB,EAE1B,MAAM,2CAA2C,CAAC;
|
|
1
|
+
{"version":3,"file":"requirement-semantics.d.ts","sourceRoot":"","sources":["../../../src/operations/mutation/requirement-semantics.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0CAA0C,CAAC;AAE3E,OAAO,EAEL,KAAK,oBAAoB,EAE1B,MAAM,2CAA2C,CAAC;AAEnD,OAAO,EACL,KAAK,kBAAkB,EAExB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAwCjE;;;;;;;;;;;;GAYG;AACH,wBAAsB,8BAA8B,CAClD,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,EACjC,MAAM,CAAC,EAAE,iBAAiB,EAC1B,MAAM,GAAE,kBAAqE,GAC5E,OAAO,CAAC,WAAW,CAAC,CAsCtB;AAuBD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,+BAA+B,CACnD,KAAK,EAAE,WAAW,EAClB,aAAa,EAAE,SAAS,oBAAoB,EAAE,EAC9C,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,EACjC,MAAM,CAAC,EAAE,iBAAiB,EAC1B,MAAM,GAAE,kBAAqE,GAC5E,OAAO,CAAC,IAAI,CAAC,CAmBf"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { analyzeSemanticAdvisorInput } from "../semantic-advisor/analyze-prose.js";
|
|
2
2
|
import { validateSemanticInventoryBoundary, } from "../semantic-advisor/ingestion-boundary.js";
|
|
3
|
+
import { stringValue } from "../semantic-advisor/shared.js";
|
|
3
4
|
import { storedEntityLookup, } from "./stored-entity.js";
|
|
4
5
|
/** The fields that make up a requirement's proposition ledger. */
|
|
5
6
|
const SEMANTIC_CONTRACT_FIELDS = [
|
|
@@ -32,7 +33,9 @@ async function storedRequirement(id, lookup, staged) {
|
|
|
32
33
|
* relationship (for example `specified_by`) and carries no `semantic_*` or
|
|
33
34
|
* `logic_claims` field, and no `title` or `text_ref` that differs from the
|
|
34
35
|
* stored value, is merged over the stored semantic contract (and the stored
|
|
35
|
-
* `text_ref` it omits) before validation.
|
|
36
|
+
* `text_ref` it omits) before validation. When the stored ledger reads its
|
|
37
|
+
* prose from `semantic_text`, a changed `text_ref` is merged the same way,
|
|
38
|
+
* since it is not the prose. The
|
|
36
39
|
* proposition-complete check then runs against the merged requirement, which
|
|
37
40
|
* is also what the write records. A payload that supplies any ledger field or
|
|
38
41
|
* changes the prose is validated exactly as given.
|
|
@@ -46,7 +49,15 @@ export async function withStoredRequirementSemantics(input, prolog, staged, look
|
|
|
46
49
|
const stored = await storedRequirement(input.id, lookup, staged);
|
|
47
50
|
if (stored === undefined)
|
|
48
51
|
return input;
|
|
49
|
-
|
|
52
|
+
// text_ref is prose only while it is the semantic source. Once the stored
|
|
53
|
+
// ledger reads semantic_text, changing it (for example clearing a text_ref
|
|
54
|
+
// whose file is gone) changes no proposition. A changed title stays a
|
|
55
|
+
// prose change: it is what a reader takes the requirement to say.
|
|
56
|
+
const readsSemanticText = stored.semantic_source_field === "semantic_text" &&
|
|
57
|
+
stringValue(stored.semantic_text).length > 0;
|
|
58
|
+
if (PROSE_FIELDS.some((field) => !(field === "text_ref" && readsSemanticText) &&
|
|
59
|
+
properties[field] !== undefined &&
|
|
60
|
+
properties[field] !== stored[field]))
|
|
50
61
|
return input;
|
|
51
62
|
const preserved = {};
|
|
52
63
|
for (const field of [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upsert.d.ts","sourceRoot":"","sources":["../../../src/operations/mutation/upsert.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AACjF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAexE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"upsert.d.ts","sourceRoot":"","sources":["../../../src/operations/mutation/upsert.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AACjF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAexE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AA6B3E,OAAO,EACL,KAAK,kBAAkB,EAExB,MAAM,oBAAoB,CAAC;AAQ5B,OAAO,KAAK,EACV,iBAAiB,EACjB,iBAAiB,EACjB,WAAW,EACX,aAAa,EACb,eAAe,EAChB,MAAM,YAAY,CAAC;AAsEpB,wBAAgB,gCAAgC,CAC9C,aAAa,EAAE,MAAM,EACrB,SAAS,EAAE,MAAM,GAChB,IAAI,CAkBN;AAwCD,wBAAsB,+BAA+B,CACnD,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACzC,OAAO,EAAE,gBAAgB,EACzB,MAAM,CAAC,EAAE,iBAAiB,GACzB,OAAO,CAAC,IAAI,CAAC,CAqBf;AAED,wBAAsB,sBAAsB,CAC1C,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACzC,aAAa,EAAE,SAAS,iBAAiB,EAAE,EAC3C,OAAO,EAAE,gBAAgB,EACzB,MAAM,CAAC,EAAE,iBAAiB,EAC1B,MAAM,CAAC,EAAE,kBAAkB,GAC1B,OAAO,CAAC,SAAS,iBAAiB,EAAE,CAAC,CA8BvC;AAmCD,MAAM,MAAM,uBAAuB,GAAG,QAAQ,CAAC;IAC7C,kEAAkE;IAClE,QAAQ,CAAC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IACtC;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,iBAAiB,CAAC;CACrC,CAAC,CAAC;AAGH,uFAAuF;AACvF,MAAM,MAAM,sBAAsB,GAAG,QAAQ,CAAC;IAC5C,QAAQ,CAAC,OAAO,EAAE,sBAAsB,GAAG,IAAI,CAAC;IAChD,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;CACtC,CAAC,CAAC;AAGH;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,WAAW,GAAG;IACrB,QAAQ,CAAC,aAAa,EAAE,SAAS,iBAAiB,EAAE,CAAC;CACtD,GACA,sBAAsB,CASxB;AAGD,MAAM,MAAM,gBAAgB,GAAG,QAAQ,CAAC;IACtC,QAAQ,CAAC,SAAS,EAAE,eAAe,CAAC;IACpC,yEAAyE;IACzE,QAAQ,CAAC,aAAa,EAAE,SAAS,iBAAiB,EAAE,CAAC;IACrD,QAAQ,CAAC,QAAQ,EAAE,sBAAsB,CAAC;CAC3C,CAAC,CAAC;AAGH;;;;;;;;GAQG;AACH,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,WAAW,EACpB,OAAO,EAAE,gBAAgB,EACzB,OAAO,GAAE,uBAA4B,GACpC,OAAO,CAAC,gBAAgB,CAAC,CAkF3B;AAgDD,MAAM,MAAM,sBAAsB,GAAG,QAAQ,CAAC;IAC5C;;;;;;OAMG;IAEH,QAAQ,CAAC,sBAAsB,CAAC,EAAE,MAAM,CAAC;IACzC;;;;OAIG;IACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IACtC;;;;OAIG;IACH,QAAQ,CAAC,mBAAmB,CAAC,EAAE,OAAO,CAAC;CACxC,CAAC,CAAC;AAyBH,wBAAsB,aAAa,CACjC,KAAK,EAAE,WAAW,EAClB,OAAO,EAAE,gBAAgB,EACzB,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,eAAe,CAAC,aAAa,CAAC,CAAC,CA2hBzC"}
|
|
@@ -15,6 +15,7 @@ import { analyzeSemanticAdvisorInput } from "../semantic-advisor/analyze-prose.j
|
|
|
15
15
|
import { assertLogicalGroundingClaimKeys, assertSemanticInventoryBoundary, } from "../semantic-advisor/ingestion-boundary.js";
|
|
16
16
|
import { entityContextWarnings } from "./context-warning.js";
|
|
17
17
|
import { buildUpsertCommitGoal, formatUpsertError } from "./contradictions.js";
|
|
18
|
+
import { assertFirmDecisionUnchanged } from "./firm-decision-guard.js";
|
|
18
19
|
import { resolveUpsertOrigin } from "./origin.js";
|
|
19
20
|
import { planRecoveryNotes, settlePendingPlanApplyJournals, withPlanRecoveryNotes, } from "./plan-apply-journal.js";
|
|
20
21
|
import { assertPredicateArgumentVocabulary } from "./predicate-vocabulary-guard.js";
|
|
@@ -247,6 +248,7 @@ export async function validateUpsertForCommit(payload, context, options = {}) {
|
|
|
247
248
|
await assertStoredRequirementBoundary(input, relationships, prolog, staged, lookup);
|
|
248
249
|
await assertLogicalGroundingClaimKeys(prolog, { ...input, relationships }, relationships, staged);
|
|
249
250
|
await assertPredicateArgumentVocabulary(prolog, validated.entity, staged);
|
|
251
|
+
await assertFirmDecisionUnchanged(payload, context.workspaceRoot, lookup);
|
|
250
252
|
// The origin the write records is added last: none of the checks above
|
|
251
253
|
// reads it, and a rejected payload never pays for the stored-origin read.
|
|
252
254
|
const recorded = await resolveUpsertOrigin(input, prolog, context.clock(), staged, lookup);
|
|
@@ -989,7 +989,7 @@ export declare const OPERATION_CATALOG: readonly [{
|
|
|
989
989
|
}, {
|
|
990
990
|
readonly name: "kb_upsert";
|
|
991
991
|
readonly cliName: "upsert";
|
|
992
|
-
readonly description: "Create or update one entity and optional relationships. Use for KB mutations after validating intent; prefer a dryRun:true call first because it validates without writing and returns semantic advisor receipts for prose-heavy requirements. Use kb_model (mode requirement) before hand-writing strict property facts from prose, and kb_model (mode predicates) before hand-writing ontology predicate facts. Use the `relationships` array for batch creation of multiple links in a single call (e.g., linking a requirement to multiple tests or facts). Prefer modeling requirements as reusable fact links (`constrains`, `requires_property`, or `requires_predicate`) so consistency and contradiction checks remain queryable. Relationship endpoints must already exist in KB. For requirements, the write will be rejected if it contradicts existing current requirements that constrain the same subject with incompatible properties. To replace a conflicting requirement, include a `supersedes` relationship from the new requirement to the old one in the same request, then upsert the old requirement with status closed (kb_check blocks a superseded requirement that is not closed). Successful writes may return non-blocking semantic advisor warnings; inspect and repair those warnings before treating prose as contradiction-checkable. Pass a sectioned `document.body` when creating a requirement (the statement, then `## Context` stating why it exists, who asked and the source, then `## Source` with the verbatim excerpt) and a prose body for scenarios, tests, ADRs and observation facts; a result warning reports an entity whose body lacks context, and kb_check blocks it under entity-context-missing. Never invent a reason the requester did not give: write 'Reason not stated'. Do not use for read-only inspection. Side effects: writes KB, may refresh symbol coordinates; dryRun:true writes nothing.";
|
|
992
|
+
readonly description: "Create or update one entity and optional relationships. Use for KB mutations after validating intent; prefer a dryRun:true call first because it validates without writing and returns semantic advisor receipts for prose-heavy requirements. Use kb_model (mode requirement) before hand-writing strict property facts from prose, and kb_model (mode predicates) before hand-writing ontology predicate facts. Use the `relationships` array for batch creation of multiple links in a single call (e.g., linking a requirement to multiple tests or facts). An update keeps the properties and relationships it leaves out: send the fields that change (with title and status) and only the links to add. Prefer modeling requirements as reusable fact links (`constrains`, `requires_property`, or `requires_predicate`) so consistency and contradiction checks remain queryable. Relationship endpoints must already exist in KB. For requirements, the write will be rejected if it contradicts existing current requirements that constrain the same subject with incompatible properties. To replace a conflicting requirement, include a `supersedes` relationship from the new requirement to the old one in the same request, then upsert the old requirement with status closed (kb_check blocks a superseded requirement that is not closed). Successful writes may return non-blocking semantic advisor warnings; inspect and repair those warnings before treating prose as contradiction-checkable. Pass a sectioned `document.body` when creating a requirement (the statement, then `## Context` stating why it exists, who asked and the source, then `## Source` with the verbatim excerpt) and a prose body for scenarios, tests, ADRs and observation facts; a result warning reports an entity whose body lacks context, and kb_check blocks it under entity-context-missing. Never invent a reason the requester did not give: write 'Reason not stated'. Do not use for read-only inspection. Side effects: writes KB, may refresh symbol coordinates; dryRun:true writes nothing.";
|
|
993
993
|
readonly businessInputSchema: {
|
|
994
994
|
readonly type: "object";
|
|
995
995
|
readonly required: readonly ["type", "id", "properties"];
|
|
@@ -1125,7 +1125,7 @@ export declare const OPERATION_CATALOG: readonly [{
|
|
|
1125
1125
|
readonly firmness: {
|
|
1126
1126
|
readonly type: "string";
|
|
1127
1127
|
readonly enum: readonly ["firm", "default", "exploratory"];
|
|
1128
|
-
readonly description: "req/adr only. firm = a human stated it as a rule (needs origin.ref to their words);
|
|
1128
|
+
readonly description: "req/adr only. firm = a human stated it as a rule (needs origin.ref to their words); its title, meaning or firmness changes only with new human words (a new origin.ref) or by supersede. default = delegated or agent choice; exploratory = flagged guess. Absent = default if an agent wrote it, else firm.";
|
|
1129
1129
|
};
|
|
1130
1130
|
readonly rationale: {
|
|
1131
1131
|
readonly type: "string";
|
|
@@ -1839,7 +1839,7 @@ export declare const OPERATION_CATALOG: readonly [{
|
|
|
1839
1839
|
readonly type: "string";
|
|
1840
1840
|
readonly enum: readonly string[];
|
|
1841
1841
|
};
|
|
1842
|
-
readonly description: "Optional rule subset. Allowed: must-priority-coverage, symbol-coverage, symbol-traceability, symbol-granularity, no-dangling-refs, source-relationship-parity, branch-store-not-compiled, source-path-dangling, no-cycles, required-fields, deprecated-adr-no-successor, superseded-requirement-open, scenario-feasibility, scenario-feasibility-unknown, exception-claim-keys, numeric-string-value, rule-key-arguments-missing, domain-contradictions, logic-coverage, rule-safety, rule-verifiability, query-plan-safety, req-status-vocabulary, strict-fact-shape, strict-req-fact-pairing, predicate-verifiability, strict-readiness, semantic-completeness, related-requirement-unmodeled, proof-contract-symbols, entity-id-style, domain-redundancy, domain-implication, subject-key-identity, subject-key-shape, ontology-quality, exception-unapproved, exception-approval-self-attested, agent-requirement-unapproved, requirement-rationale-missing, symbol-owner-superseded, adr-unlinked, adr-proposed, predicate-schema-conformance, entity-context-missing, entity-context-acknowledged, decision-firm-unreferenced, decision-firm-superseded, supersedes-reason-missing, supersedes-reason-acknowledged, policy-ownership, policy-markers. If omitted, server runs canonical and advisory rules plus the full-KB qualityDiagnostics audit scan, including usage telemetry acceptance when evidence exists; migration rules run only when explicitly selected. Advisory and migration findings are non-blocking qualityDiagnostics. If supplied, server preserves scoped validation and skips the full-KB advisory scan.";
|
|
1842
|
+
readonly description: "Optional rule subset. Allowed: must-priority-coverage, symbol-coverage, symbol-traceability, symbol-granularity, no-dangling-refs, source-relationship-parity, branch-store-not-compiled, source-path-dangling, no-cycles, required-fields, deprecated-adr-no-successor, superseded-requirement-open, scenario-feasibility, scenario-feasibility-unknown, exception-claim-keys, numeric-string-value, rule-key-arguments-missing, domain-contradictions, logic-coverage, rule-safety, rule-verifiability, query-plan-safety, req-status-vocabulary, strict-fact-shape, strict-req-fact-pairing, predicate-verifiability, strict-readiness, semantic-completeness, related-requirement-unmodeled, proof-contract-symbols, entity-id-style, domain-redundancy, domain-implication, subject-key-identity, subject-key-shape, ontology-quality, exception-unapproved, exception-approval-self-attested, agent-requirement-unapproved, requirement-rationale-missing, symbol-owner-superseded, adr-unlinked, adr-proposed, predicate-schema-conformance, entity-context-missing, entity-context-acknowledged, decision-firm-unreferenced, decision-firm-superseded, decision-firm-edited, supersedes-reason-missing, supersedes-reason-acknowledged, policy-ownership, policy-markers. If omitted, server runs canonical and advisory rules plus the full-KB qualityDiagnostics audit scan, including usage telemetry acceptance when evidence exists; migration rules run only when explicitly selected. Advisory and migration findings are non-blocking qualityDiagnostics. If supplied, server preserves scoped validation and skips the full-KB advisory scan.";
|
|
1843
1843
|
};
|
|
1844
1844
|
readonly sourceFiles: {
|
|
1845
1845
|
readonly type: "array";
|
|
@@ -4,11 +4,18 @@ import { type AuthoredEntity } from "./entity-context.js";
|
|
|
4
4
|
export declare const DECISION_FIRM_UNREFERENCED_RULE = "decision-firm-unreferenced";
|
|
5
5
|
/** Only a firm decision may supersede a firm decision (blocking). */
|
|
6
6
|
export declare const DECISION_FIRM_SUPERSEDED_RULE = "decision-firm-superseded";
|
|
7
|
+
/** A firm decision's claim must not change in place without new human words (blocking). */
|
|
8
|
+
export declare const DECISION_FIRM_EDITED_RULE = "decision-firm-edited";
|
|
7
9
|
/** A supersede must say why under "Why this changed" (blocking). */
|
|
8
10
|
export declare const SUPERSEDES_REASON_MISSING_RULE = "supersedes-reason-missing";
|
|
9
11
|
/** How many legacy supersedes the schema 9 migration acknowledged (info). */
|
|
10
12
|
export declare const SUPERSEDES_REASON_ACKNOWLEDGED_RULE = "supersedes-reason-acknowledged";
|
|
11
|
-
export declare const DECISION_FIRMNESS_RULES: readonly ["decision-firm-unreferenced", "decision-firm-superseded", "supersedes-reason-missing", "supersedes-reason-acknowledged"];
|
|
13
|
+
export declare const DECISION_FIRMNESS_RULES: readonly ["decision-firm-unreferenced", "decision-firm-superseded", "decision-firm-edited", "supersedes-reason-missing", "supersedes-reason-acknowledged"];
|
|
14
|
+
/**
|
|
15
|
+
* The schema version from which a decision without `firmness` reads its
|
|
16
|
+
* firmness from its origin, so a person's or imported rule is firm.
|
|
17
|
+
*/
|
|
18
|
+
export declare const FIRMNESS_FROM_ORIGIN_SCHEMA_VERSION = 10;
|
|
12
19
|
/** Every authored requirement and ADR. */
|
|
13
20
|
export declare function listDecisionEntities(workspaceRoot: string): AuthoredEntity[];
|
|
14
21
|
/**
|
|
@@ -27,10 +34,27 @@ export declare function authoredSupersedes(workspaceRoot: string, entities: read
|
|
|
27
34
|
export declare function unexplainedSupersedes(entities: readonly AuthoredEntity[], edges: ReadonlyMap<string, Set<string>>): AuthoredEntity[];
|
|
28
35
|
/** The supersede edges of an entity, as the manifest acknowledges them. */
|
|
29
36
|
export declare function supersedeAcknowledgements(id: string, edges: ReadonlyMap<string, Set<string>>): string[];
|
|
37
|
+
/**
|
|
38
|
+
* Supersede edges (`FROM -> TO`) whose target reads as firm only because
|
|
39
|
+
* firmness follows origin (it has no `firmness` and an agent did not write
|
|
40
|
+
* it) and whose superseder is not firm, retired entities included. These
|
|
41
|
+
* were allowed before schema 10; the migration acknowledges them once.
|
|
42
|
+
*/
|
|
43
|
+
export declare function implicitFirmSupersedes(entities: readonly AuthoredEntity[], edges: ReadonlyMap<string, Set<string>>): string[];
|
|
30
44
|
/** Evaluate the firmness rules over authored requirements and ADRs. */
|
|
31
45
|
export declare function evaluateDecisionFirmness(entities: readonly AuthoredEntity[], edges: ReadonlyMap<string, Set<string>>, rules?: ReadonlySet<string>, acknowledged?: ReadonlySet<string>, options?: Readonly<{
|
|
32
46
|
schemaVersion?: number | null;
|
|
47
|
+
/** Edges the schema 10 migration recorded (`FROM -> TO`). */
|
|
48
|
+
firmSupersedeAcknowledged?: ReadonlySet<string>;
|
|
33
49
|
}>): Violation[];
|
|
50
|
+
/** Reads a workspace-relative file as committed at HEAD; null when absent. */
|
|
51
|
+
export type CommittedFileReader = (relativePath: string) => string | null;
|
|
52
|
+
/**
|
|
53
|
+
* Current firm requirements and ADRs whose claim changed since HEAD without
|
|
54
|
+
* citing new human words: an in-place edit that bypassed kb_upsert's guard.
|
|
55
|
+
* A decision new since HEAD, or one that was not firm there, is not judged.
|
|
56
|
+
*/
|
|
57
|
+
export declare function evaluateFirmDecisionEdits(entities: readonly AuthoredEntity[], edges: ReadonlyMap<string, Set<string>>, changed: ReadonlySet<string>, readCommitted: CommittedFileReader): Violation[];
|
|
34
58
|
/** Read the authored decisions once and evaluate the selected rules. */
|
|
35
59
|
export declare function collectDecisionFirmnessViolations(rules: ReadonlySet<string>, workspaceRoot: string): Violation[];
|
|
36
60
|
//# sourceMappingURL=decision-firmness.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"decision-firmness.d.ts","sourceRoot":"","sources":["../../../src/public/operations/decision-firmness.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"decision-firmness.d.ts","sourceRoot":"","sources":["../../../src/public/operations/decision-firmness.ts"],"names":[],"mappings":"AAwCA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EACL,KAAK,cAAc,EAGpB,MAAM,qBAAqB,CAAC;AAE7B,wEAAwE;AAExE,eAAO,MAAM,+BAA+B,+BAA+B,CAAC;AAC5E,qEAAqE;AAErE,eAAO,MAAM,6BAA6B,6BAA6B,CAAC;AACxE,2FAA2F;AAE3F,eAAO,MAAM,yBAAyB,yBAAyB,CAAC;AAChE,oEAAoE;AAEpE,eAAO,MAAM,8BAA8B,8BAA8B,CAAC;AAC1E,6EAA6E;AAE7E,eAAO,MAAM,mCAAmC,mCACd,CAAC;AAGnC,eAAO,MAAM,uBAAuB,4JAM1B,CAAC;AAOX;;;GAGG;AAEH,eAAO,MAAM,mCAAmC,KAAK,CAAC;AAiBtD,0CAA0C;AAE1C,wBAAgB,oBAAoB,CAAC,aAAa,EAAE,MAAM,GAAG,cAAc,EAAE,CAS5E;AAED;;;;;GAKG;AAEH,wBAAgB,kBAAkB,CAChC,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,SAAS,cAAc,EAAE,GAClC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CA+B1B;AASD;;;;;GAKG;AAEH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,SAAS,cAAc,EAAE,EACnC,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,GACtC,cAAc,EAAE,CAQlB;AAED,2EAA2E;AAE3E,wBAAgB,yBAAyB,CACvC,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,GACtC,MAAM,EAAE,CAIV;AAED;;;;;GAKG;AAEH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,SAAS,cAAc,EAAE,EACnC,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,GACtC,MAAM,EAAE,CAyBV;AAED,uEAAuE;AAEvE,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,SAAS,cAAc,EAAE,EACnC,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,EACvC,KAAK,GAAE,WAAW,CAAC,MAAM,CAAoC,EAC7D,YAAY,GAAE,WAAW,CAAC,MAAM,CAAa,EAC7C,OAAO,GAAE,QAAQ,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,6DAA6D;IAC7D,yBAAyB,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CACjD,CAAM,GACN,SAAS,EAAE,CA+Gb;AAED,8EAA8E;AAE9E,MAAM,MAAM,mBAAmB,GAAG,CAAC,YAAY,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;AAkC1E;;;;GAIG;AAEH,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,SAAS,cAAc,EAAE,EACnC,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,EACvC,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,EAC5B,aAAa,EAAE,mBAAmB,GACjC,SAAS,EAAE,CAwBb;AAED,wEAAwE;AAExE,wBAAgB,iCAAiC,CAC/C,KAAK,EAAE,WAAW,CAAC,MAAM,CAAC,EAC1B,aAAa,EAAE,MAAM,GACpB,SAAS,EAAE,CA+Bb"}
|
|
@@ -15,8 +15,10 @@
|
|
|
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 { execFileSync } from "node:child_process";
|
|
18
19
|
import path from "node:path";
|
|
19
|
-
import { MIN_WHY_CHANGED_WORDS, WHY_THIS_CHANGED_HEADING, carriesFirmness, effectiveFirmness, firmnessRef, supersedeAcknowledgement, whyThisChangedWords, } from "../../decision-firmness.js";
|
|
20
|
+
import { MIN_WHY_CHANGED_WORDS, WHY_THIS_CHANGED_HEADING, carriesFirmness, effectiveFirmness, firmnessIsImplicit, firmnessRef, supersedeAcknowledgement, whyThisChangedWords, } from "../../decision-firmness.js";
|
|
21
|
+
import { firmEditGuidance, unapprovedFirmEdit, } from "../../firm-decision-edit.js";
|
|
20
22
|
import { listLaneMarkdownFiles, readText, } from "../../operations/migration/kb-sources.js";
|
|
21
23
|
import { readAllShards } from "../../relationships/shards.js";
|
|
22
24
|
import { readKbManifest } from "../../utils/kb-manifest.js";
|
|
@@ -27,6 +29,9 @@ export const DECISION_FIRM_UNREFERENCED_RULE = "decision-firm-unreferenced";
|
|
|
27
29
|
/** Only a firm decision may supersede a firm decision (blocking). */
|
|
28
30
|
// implements REQ-kb-decision-firmness
|
|
29
31
|
export const DECISION_FIRM_SUPERSEDED_RULE = "decision-firm-superseded";
|
|
32
|
+
/** A firm decision's claim must not change in place without new human words (blocking). */
|
|
33
|
+
// implements REQ-kb-firm-decision-edit
|
|
34
|
+
export const DECISION_FIRM_EDITED_RULE = "decision-firm-edited";
|
|
30
35
|
/** A supersede must say why under "Why this changed" (blocking). */
|
|
31
36
|
// implements REQ-kb-decision-firmness
|
|
32
37
|
export const SUPERSEDES_REASON_MISSING_RULE = "supersedes-reason-missing";
|
|
@@ -37,12 +42,25 @@ export const SUPERSEDES_REASON_ACKNOWLEDGED_RULE = "supersedes-reason-acknowledg
|
|
|
37
42
|
export const DECISION_FIRMNESS_RULES = [
|
|
38
43
|
DECISION_FIRM_UNREFERENCED_RULE,
|
|
39
44
|
DECISION_FIRM_SUPERSEDED_RULE,
|
|
45
|
+
DECISION_FIRM_EDITED_RULE,
|
|
40
46
|
SUPERSEDES_REASON_MISSING_RULE,
|
|
41
47
|
SUPERSEDES_REASON_ACKNOWLEDGED_RULE,
|
|
42
48
|
];
|
|
43
49
|
const DECISION_LANES = ["requirements", "adr"];
|
|
44
50
|
/** The schema version from which a supersede must explain itself. */
|
|
45
51
|
const SUPERSEDES_REASON_SCHEMA_VERSION = 9;
|
|
52
|
+
/**
|
|
53
|
+
* The schema version from which a decision without `firmness` reads its
|
|
54
|
+
* firmness from its origin, so a person's or imported rule is firm.
|
|
55
|
+
*/
|
|
56
|
+
// implements REQ-kb-decision-firmness-from-origin
|
|
57
|
+
export const FIRMNESS_FROM_ORIGIN_SCHEMA_VERSION = 10;
|
|
58
|
+
/**
|
|
59
|
+
* Told on a KB older than schema 10: the pending schema upgrade acknowledges
|
|
60
|
+
* supersedes of decisions that only became firm when firmness started to
|
|
61
|
+
* follow origin.
|
|
62
|
+
*/
|
|
63
|
+
const PRE_SCHEMA10_FIRM_NOTE = " This decision has no firmness and was not written by an agent, so it reads as firm from schema 10; supersedes recorded before schema 10 are acknowledged by the plan's schema-config-upgrade (kibi migrate --yes).";
|
|
46
64
|
/**
|
|
47
65
|
* Told on a KB older than schema 9: the pending schema upgrade acknowledges
|
|
48
66
|
* supersedes recorded before the rule existed, so no edit is required now.
|
|
@@ -128,21 +146,51 @@ export function supersedeAcknowledgements(id, edges) {
|
|
|
128
146
|
.sort()
|
|
129
147
|
.map((target) => supersedeAcknowledgement(id, target));
|
|
130
148
|
}
|
|
149
|
+
/**
|
|
150
|
+
* Supersede edges (`FROM -> TO`) whose target reads as firm only because
|
|
151
|
+
* firmness follows origin (it has no `firmness` and an agent did not write
|
|
152
|
+
* it) and whose superseder is not firm, retired entities included. These
|
|
153
|
+
* were allowed before schema 10; the migration acknowledges them once.
|
|
154
|
+
*/
|
|
155
|
+
// implements REQ-kb-decision-firmness-from-origin
|
|
156
|
+
export function implicitFirmSupersedes(entities, edges) {
|
|
157
|
+
const byId = new Map(entities.map((entity) => [entity.id, entity]));
|
|
158
|
+
const found = [];
|
|
159
|
+
for (const [from, targets] of edges) {
|
|
160
|
+
const source = byId.get(from);
|
|
161
|
+
if (source === undefined ||
|
|
162
|
+
effectiveFirmness(source.type, source.data.firmness, source.data.origin) === "firm")
|
|
163
|
+
continue;
|
|
164
|
+
for (const to of targets) {
|
|
165
|
+
const target = byId.get(to);
|
|
166
|
+
if (target !== undefined &&
|
|
167
|
+
firmnessIsImplicit(target.type, target.data.firmness) &&
|
|
168
|
+
effectiveFirmness(target.type, undefined, target.data.origin) === "firm")
|
|
169
|
+
found.push(supersedeAcknowledgement(from, to));
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return found.sort();
|
|
173
|
+
}
|
|
131
174
|
/** Evaluate the firmness rules over authored requirements and ADRs. */
|
|
132
175
|
// implements REQ-kb-decision-firmness
|
|
133
176
|
export function evaluateDecisionFirmness(entities, edges, rules = new Set(DECISION_FIRMNESS_RULES), acknowledged = new Set(), options = {}) {
|
|
134
177
|
const preSchema9 = typeof options.schemaVersion === "number" &&
|
|
135
178
|
options.schemaVersion < SUPERSEDES_REASON_SCHEMA_VERSION;
|
|
179
|
+
const preSchema10 = typeof options.schemaVersion === "number" &&
|
|
180
|
+
options.schemaVersion < FIRMNESS_FROM_ORIGIN_SCHEMA_VERSION;
|
|
181
|
+
const firmAcknowledged = options.firmSupersedeAcknowledged ?? new Set();
|
|
136
182
|
const findings = [];
|
|
137
183
|
const superseded = supersededIds(edges);
|
|
138
184
|
const byId = new Map(entities.map((entity) => [entity.id, entity]));
|
|
139
185
|
const current = entities
|
|
140
186
|
.filter((entity) => isCurrentAuthoredEntity(entity, superseded))
|
|
141
187
|
.sort((left, right) => left.id.localeCompare(right.id));
|
|
142
|
-
const firmnessOf = (entity) => effectiveFirmness(entity.type, entity.data.firmness);
|
|
188
|
+
const firmnessOf = (entity) => effectiveFirmness(entity.type, entity.data.firmness, entity.data.origin);
|
|
189
|
+
// Only an authored `firmness: firm` must cite the person's words: a
|
|
190
|
+
// decision that reads as firm from its origin already names its author.
|
|
143
191
|
if (rules.has(DECISION_FIRM_UNREFERENCED_RULE)) {
|
|
144
192
|
for (const entity of current) {
|
|
145
|
-
if (
|
|
193
|
+
if (entity.data.firmness !== "firm")
|
|
146
194
|
continue;
|
|
147
195
|
if (firmnessRef({ type: entity.type, ...entity.data }) !== undefined)
|
|
148
196
|
continue;
|
|
@@ -162,11 +210,19 @@ export function evaluateDecisionFirmness(entities, edges, rules = new Set(DECISI
|
|
|
162
210
|
for (const entity of [...entities].sort((left, right) => left.id.localeCompare(right.id))) {
|
|
163
211
|
if (firmnessOf(entity) === "firm")
|
|
164
212
|
continue;
|
|
213
|
+
const implicit = new Set();
|
|
165
214
|
const firmTargets = [...(edges.get(entity.id) ?? [])]
|
|
166
215
|
.filter((id) => {
|
|
167
216
|
const target = byId.get(id);
|
|
168
|
-
|
|
169
|
-
|
|
217
|
+
if (target === undefined || firmnessOf(target) !== "firm")
|
|
218
|
+
return false;
|
|
219
|
+
if (!firmnessIsImplicit(target.type, target.data.firmness))
|
|
220
|
+
return true;
|
|
221
|
+
// Recorded before firmness followed origin: acknowledged once.
|
|
222
|
+
if (firmAcknowledged.has(supersedeAcknowledgement(entity.id, id)))
|
|
223
|
+
return false;
|
|
224
|
+
implicit.add(id);
|
|
225
|
+
return true;
|
|
170
226
|
})
|
|
171
227
|
.sort();
|
|
172
228
|
if (firmTargets.length === 0)
|
|
@@ -175,7 +231,7 @@ export function evaluateDecisionFirmness(entities, edges, rules = new Set(DECISI
|
|
|
175
231
|
rule: DECISION_FIRM_SUPERSEDED_RULE,
|
|
176
232
|
entityId: entity.id,
|
|
177
233
|
description: `${entity.id} (firmness: ${firmnessOf(entity)}) supersedes the firm decision${firmTargets.length === 1 ? "" : "s"} ${firmTargets.join(", ")}; only a human may change a firm decision`,
|
|
178
|
-
suggestion:
|
|
234
|
+
suggestion: `Ask the person who stated the firm decision; if they agree, mark the replacement firmness: firm with origin.ref to their words, otherwise remove the supersedes link and propose the change instead${preSchema10 && implicit.size > 0 ? `.${PRE_SCHEMA10_FIRM_NOTE}` : ""}`,
|
|
179
235
|
source: entity.path,
|
|
180
236
|
evidence: { firmness: firmnessOf(entity), firmTargets },
|
|
181
237
|
});
|
|
@@ -215,12 +271,82 @@ export function evaluateDecisionFirmness(entities, edges, rules = new Set(DECISI
|
|
|
215
271
|
}
|
|
216
272
|
return findings;
|
|
217
273
|
}
|
|
274
|
+
/**
|
|
275
|
+
* The decision files whose working copy differs from HEAD, with a reader for
|
|
276
|
+
* their committed content; undefined outside a Git checkout or before the
|
|
277
|
+
* first commit, where there is nothing to compare against.
|
|
278
|
+
*/
|
|
279
|
+
function committedDecisionChanges(workspaceRoot) {
|
|
280
|
+
try {
|
|
281
|
+
const listed = execFileSync("git", ["-C", workspaceRoot, "diff", "--name-only", "--relative", "-z", "HEAD"], { encoding: "utf8", maxBuffer: 64 * 1024 * 1024, stdio: "pipe" });
|
|
282
|
+
const changed = new Set(listed.split("\0").filter((name) => name !== ""));
|
|
283
|
+
const read = (relativePath) => {
|
|
284
|
+
try {
|
|
285
|
+
return execFileSync("git", ["-C", workspaceRoot, "show", `HEAD:./${relativePath}`], { encoding: "utf8", maxBuffer: 64 * 1024 * 1024, stdio: "pipe" });
|
|
286
|
+
}
|
|
287
|
+
catch {
|
|
288
|
+
return null;
|
|
289
|
+
}
|
|
290
|
+
};
|
|
291
|
+
return { changed, read };
|
|
292
|
+
}
|
|
293
|
+
catch {
|
|
294
|
+
return undefined;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Current firm requirements and ADRs whose claim changed since HEAD without
|
|
299
|
+
* citing new human words: an in-place edit that bypassed kb_upsert's guard.
|
|
300
|
+
* A decision new since HEAD, or one that was not firm there, is not judged.
|
|
301
|
+
*/
|
|
302
|
+
// implements REQ-kb-firm-decision-edit
|
|
303
|
+
export function evaluateFirmDecisionEdits(entities, edges, changed, readCommitted) {
|
|
304
|
+
const superseded = supersededIds(edges);
|
|
305
|
+
const findings = [];
|
|
306
|
+
for (const entity of [...entities].sort((left, right) => left.id.localeCompare(right.id))) {
|
|
307
|
+
if (!changed.has(entity.path))
|
|
308
|
+
continue;
|
|
309
|
+
if (!isCurrentAuthoredEntity(entity, superseded))
|
|
310
|
+
continue;
|
|
311
|
+
const committed = readCommitted(entity.path);
|
|
312
|
+
if (committed === null)
|
|
313
|
+
continue;
|
|
314
|
+
const before = readAuthoredEntity(committed, entity.path);
|
|
315
|
+
if (before === null || before.type !== entity.type)
|
|
316
|
+
continue;
|
|
317
|
+
const fields = unapprovedFirmEdit(before, entity);
|
|
318
|
+
if (fields.length === 0)
|
|
319
|
+
continue;
|
|
320
|
+
findings.push({
|
|
321
|
+
rule: DECISION_FIRM_EDITED_RULE,
|
|
322
|
+
entityId: entity.id,
|
|
323
|
+
description: `${entity.id} is a firm decision whose ${fields.join(", ")} changed since HEAD without citing new human words`,
|
|
324
|
+
suggestion: `${firmEditGuidance(entity.type)}. To undo the edit, restore ${entity.path} from HEAD`,
|
|
325
|
+
source: entity.path,
|
|
326
|
+
evidence: { type: entity.type, changed: fields },
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
return findings;
|
|
330
|
+
}
|
|
218
331
|
/** Read the authored decisions once and evaluate the selected rules. */
|
|
219
|
-
// implements REQ-kb-decision-firmness
|
|
332
|
+
// implements REQ-kb-decision-firmness, REQ-kb-firm-decision-edit
|
|
220
333
|
export function collectDecisionFirmnessViolations(rules, workspaceRoot) {
|
|
221
334
|
if (!DECISION_FIRMNESS_RULES.some((rule) => rules.has(rule)))
|
|
222
335
|
return [];
|
|
223
336
|
const entities = listDecisionEntities(workspaceRoot);
|
|
224
337
|
const manifest = readKbManifest(workspaceRoot);
|
|
225
|
-
|
|
338
|
+
const edges = authoredSupersedes(workspaceRoot, entities);
|
|
339
|
+
const committed = rules.has(DECISION_FIRM_EDITED_RULE)
|
|
340
|
+
? committedDecisionChanges(workspaceRoot)
|
|
341
|
+
: undefined;
|
|
342
|
+
const edited = committed
|
|
343
|
+
? evaluateFirmDecisionEdits(entities, edges, committed.changed, committed.read)
|
|
344
|
+
: [];
|
|
345
|
+
return [
|
|
346
|
+
...edited,
|
|
347
|
+
...evaluateDecisionFirmness(entities, edges, rules, new Set(manifest?.supersedesReasonAcknowledged ?? []), {
|
|
348
|
+
schemaVersion: manifest?.schemaVersion ?? null,
|
|
349
|
+
firmSupersedeAcknowledged: new Set(manifest?.firmSupersedeAcknowledged ?? []),
|
|
350
|
+
}),
|
|
351
|
+
];
|
|
226
352
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discovery-executors.d.ts","sourceRoot":"","sources":["../../../src/public/operations/discovery-executors.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,cAAc,
|
|
1
|
+
{"version":3,"file":"discovery-executors.d.ts","sourceRoot":"","sources":["../../../src/public/operations/discovery-executors.ts"],"names":[],"mappings":"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"}
|