kibi-cli 2.5.2 → 2.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli-operation-metadata.d.ts +1 -1
- package/dist/cli-operation-metadata.js +1 -1
- package/dist/commands/check.d.ts.map +1 -1
- package/dist/commands/check.js +15 -0
- package/dist/commands/init-helpers.js +1 -1
- package/dist/commands/migrate.d.ts.map +1 -1
- package/dist/commands/migrate.js +43 -0
- package/dist/entity-body-context.d.ts +132 -0
- package/dist/entity-body-context.d.ts.map +1 -0
- package/dist/entity-body-context.js +382 -0
- package/dist/extractors/markdown.d.ts +13 -0
- package/dist/extractors/markdown.d.ts.map +1 -1
- package/dist/extractors/markdown.js +19 -2
- package/dist/intent-search.d.ts.map +1 -1
- package/dist/intent-search.js +4 -4
- package/dist/operations/bootstrap/candidate-helpers.d.ts +18 -0
- package/dist/operations/bootstrap/candidate-helpers.d.ts.map +1 -1
- package/dist/operations/bootstrap/candidate-helpers.js +35 -0
- package/dist/operations/bootstrap/candidates.d.ts.map +1 -1
- package/dist/operations/bootstrap/candidates.js +4 -2
- package/dist/operations/bootstrap/generate.d.ts.map +1 -1
- package/dist/operations/bootstrap/generate.js +24 -15
- package/dist/operations/bootstrap/intent-claims.d.ts.map +1 -1
- package/dist/operations/bootstrap/intent-claims.js +210 -5
- package/dist/operations/bootstrap/markdown-candidates.d.ts.map +1 -1
- package/dist/operations/bootstrap/markdown-candidates.js +7 -3
- package/dist/operations/bootstrap/presentation.d.ts +8 -0
- package/dist/operations/bootstrap/presentation.d.ts.map +1 -1
- package/dist/operations/bootstrap/presentation.js +66 -8
- package/dist/operations/bootstrap/types.d.ts +21 -0
- package/dist/operations/bootstrap/types.d.ts.map +1 -1
- package/dist/operations/bootstrap/types.js +10 -0
- package/dist/operations/migration/entity-body-context.d.ts +57 -0
- package/dist/operations/migration/entity-body-context.d.ts.map +1 -0
- package/dist/operations/migration/entity-body-context.js +261 -0
- package/dist/operations/migration/polarity-values.d.ts.map +1 -1
- package/dist/operations/migration/polarity-values.js +5 -2
- package/dist/operations/migration/schema6.d.ts +2 -0
- package/dist/operations/migration/schema6.d.ts.map +1 -1
- package/dist/operations/migration/schema6.js +69 -0
- package/dist/operations/modeling/logic-modeling.d.ts.map +1 -1
- package/dist/operations/modeling/logic-modeling.js +3 -1
- package/dist/operations/modeling/model-requirement.d.ts.map +1 -1
- package/dist/operations/modeling/model-requirement.js +7 -9
- package/dist/operations/mutation/context-warning.d.ts +13 -0
- package/dist/operations/mutation/context-warning.d.ts.map +1 -0
- package/dist/operations/mutation/context-warning.js +59 -0
- package/dist/operations/mutation/origin.d.ts +2 -1
- package/dist/operations/mutation/origin.d.ts.map +1 -1
- package/dist/operations/mutation/origin.js +7 -18
- package/dist/operations/mutation/requirement-semantics.d.ts +16 -0
- package/dist/operations/mutation/requirement-semantics.d.ts.map +1 -0
- package/dist/operations/mutation/requirement-semantics.js +64 -0
- package/dist/operations/mutation/source-authoring.d.ts.map +1 -1
- package/dist/operations/mutation/source-authoring.js +10 -0
- package/dist/operations/mutation/stored-entity.d.ts +20 -0
- package/dist/operations/mutation/stored-entity.d.ts.map +1 -0
- package/dist/operations/mutation/stored-entity.js +51 -0
- package/dist/operations/mutation/upsert.d.ts +3 -2
- package/dist/operations/mutation/upsert.d.ts.map +1 -1
- package/dist/operations/mutation/upsert.js +19 -10
- package/dist/operations/mutation/validate-upsert.d.ts.map +1 -1
- package/dist/operations/mutation/validate-upsert.js +6 -1
- package/dist/operations/planning/compile-intent.d.ts +9 -0
- package/dist/operations/planning/compile-intent.d.ts.map +1 -1
- package/dist/operations/planning/compile-intent.js +49 -2
- package/dist/operations/semantic-advisor/analyze-prose.d.ts +3 -2
- package/dist/operations/semantic-advisor/analyze-prose.d.ts.map +1 -1
- package/dist/operations/semantic-advisor/analyze-prose.js +3 -41
- package/dist/operations/semantic-advisor/ingestion-boundary.d.ts.map +1 -1
- package/dist/operations/semantic-advisor/ingestion-boundary.js +10 -1
- package/dist/operations/semantic-advisor/proposition-role.d.ts +6 -0
- package/dist/operations/semantic-advisor/proposition-role.d.ts.map +1 -0
- package/dist/operations/semantic-advisor/proposition-role.js +76 -0
- package/dist/public/operations/catalog.d.ts +78 -9
- package/dist/public/operations/catalog.d.ts.map +1 -1
- package/dist/public/operations/check-executor.d.ts.map +1 -1
- package/dist/public/operations/check-executor.js +3 -0
- package/dist/public/operations/entity-context.d.ts +51 -0
- package/dist/public/operations/entity-context.d.ts.map +1 -0
- package/dist/public/operations/entity-context.js +235 -0
- package/dist/public/operations/origin-review.d.ts +1 -1
- package/dist/public/operations/origin-review.js +2 -2
- package/dist/public/operations/specs/bootstrap.d.ts +59 -5
- package/dist/public/operations/specs/bootstrap.d.ts.map +1 -1
- package/dist/public/operations/specs/bootstrap.js +48 -6
- package/dist/public/operations/specs/check-rules.generated.d.ts +1 -1
- package/dist/public/operations/specs/check-rules.generated.d.ts.map +1 -1
- package/dist/public/operations/specs/check-rules.generated.js +3 -1
- package/dist/public/operations/specs/check.d.ts +1 -1
- package/dist/public/operations/specs/mutation-schemas.d.ts +1 -1
- package/dist/public/operations/specs/mutation-schemas.d.ts.map +1 -1
- package/dist/public/operations/specs/mutation-schemas.js +10 -2
- package/dist/public/operations/specs/planning.d.ts +15 -0
- package/dist/public/operations/specs/planning.d.ts.map +1 -1
- package/dist/public/operations/specs/planning.js +15 -0
- package/dist/public/operations/specs/upsert.d.ts +3 -3
- package/dist/public/operations/specs/upsert.js +2 -2
- package/dist/public/schemas/entity.d.ts.map +1 -1
- package/dist/public/schemas/entity.js +7 -1
- package/dist/public/skills/kibi-bootstrap/SKILL.md +13 -7
- package/dist/public/skills/kibi-bootstrap/resources/bootstrap.md +9 -2
- package/dist/public/skills/kibi-usage/SKILL.md +56 -3
- package/dist/public/skills/kibi-usage/resources/source-authoring.md +5 -1
- package/dist/schemas/entity.schema.json +14 -1
- package/dist/search-ranking.d.ts.map +1 -1
- package/dist/search-ranking.js +7 -4
- package/dist/traceability/staged-consistency.d.ts +25 -0
- package/dist/traceability/staged-consistency.d.ts.map +1 -0
- package/dist/traceability/staged-consistency.js +92 -0
- package/dist/traceability/temp-kb.d.ts.map +1 -1
- package/dist/traceability/temp-kb.js +5 -0
- package/dist/utils/kb-manifest.d.ts +5 -0
- package/dist/utils/kb-manifest.d.ts.map +1 -1
- package/dist/utils/kb-manifest.js +6 -0
- package/dist/utils/rule-registry.generated.d.ts +11 -0
- package/dist/utils/rule-registry.generated.d.ts.map +1 -1
- package/dist/utils/rule-registry.generated.js +13 -0
- package/dist/utils/schema-version.d.ts +1 -1
- package/dist/utils/schema-version.d.ts.map +1 -1
- package/dist/utils/schema-version.js +3 -2
- package/package.json +2 -2
- package/schema/manifest.json +5 -0
- package/schema/validation.pl +14 -2
- package/src/public/operations/check-executor.ts +6 -0
- package/src/public/operations/entity-context.ts +304 -0
- package/src/public/operations/origin-review.ts +2 -2
- package/src/public/operations/specs/bootstrap.ts +52 -5
- package/src/public/operations/specs/check-rules.generated.ts +3 -1
- package/src/public/operations/specs/mutation-schemas.ts +10 -2
- package/src/public/operations/specs/planning.ts +18 -0
- package/src/public/operations/specs/upsert.ts +2 -2
- package/src/public/schemas/entity.ts +7 -1
- package/src/public/skills/kibi-bootstrap/SKILL.md +13 -7
- package/src/public/skills/kibi-bootstrap/resources/bootstrap.md +9 -2
- package/src/public/skills/kibi-usage/SKILL.md +56 -3
- package/src/public/skills/kibi-usage/resources/source-authoring.md +5 -1
- package/src/schemas/entity.schema.json +14 -1
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { contextFinding } from "../../entity-body-context.js";
|
|
4
|
+
import { requirementSemanticText } from "../../extractors/markdown.js";
|
|
5
|
+
import { readAuthoredEntity } from "../../public/operations/entity-context.js";
|
|
6
|
+
import { readKbManifest } from "../../utils/kb-manifest.js";
|
|
7
|
+
function readBody(workspaceRoot, source) {
|
|
8
|
+
if (typeof source !== "string" || !source.endsWith(".md"))
|
|
9
|
+
return undefined;
|
|
10
|
+
try {
|
|
11
|
+
return (readAuthoredEntity(readFileSync(path.resolve(workspaceRoot, source), "utf8"), source)?.body ?? undefined);
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* The body the authored document has, or will have, after this upsert: the
|
|
19
|
+
* written file when there is one, the supplied body, the preserved body of
|
|
20
|
+
* the entity's existing document, or the default a new requirement gets.
|
|
21
|
+
*/
|
|
22
|
+
// implements REQ-kb-entity-body-context
|
|
23
|
+
export function upsertDocumentBody(input, entity, workspaceRoot, writtenPath) {
|
|
24
|
+
if (writtenPath !== undefined) {
|
|
25
|
+
const written = readBody(workspaceRoot, writtenPath);
|
|
26
|
+
if (written !== undefined)
|
|
27
|
+
return written;
|
|
28
|
+
}
|
|
29
|
+
if (input.document?.body !== undefined)
|
|
30
|
+
return input.document.body;
|
|
31
|
+
const existing = readBody(workspaceRoot, input.document?.path ?? entity.source);
|
|
32
|
+
if (existing !== undefined)
|
|
33
|
+
return existing;
|
|
34
|
+
return input.type === "req" ? `${String(entity.semantic_text ?? "")}\n` : "";
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* kb_upsert warning for a written entity whose body lacks context. The same
|
|
38
|
+
* finding blocks `kb_check` as entity-context-missing, so agents see it first.
|
|
39
|
+
*/
|
|
40
|
+
// implements REQ-kb-entity-body-context
|
|
41
|
+
export function entityContextWarnings(input, entity, workspaceRoot, writtenPath) {
|
|
42
|
+
const body = upsertDocumentBody(input, entity, workspaceRoot, writtenPath);
|
|
43
|
+
const semanticText = typeof entity.semantic_text === "string" && entity.semantic_text.trim()
|
|
44
|
+
? entity.semantic_text
|
|
45
|
+
: input.type === "req"
|
|
46
|
+
? requirementSemanticText(body)
|
|
47
|
+
: undefined;
|
|
48
|
+
const acknowledged = (readKbManifest(workspaceRoot)?.contextAcknowledged ?? []).includes(input.id);
|
|
49
|
+
const finding = contextFinding(input.type, input.id, body, {
|
|
50
|
+
title: entity.title,
|
|
51
|
+
semantic_text: semanticText,
|
|
52
|
+
fact_kind: entity.fact_kind,
|
|
53
|
+
}, acknowledged);
|
|
54
|
+
return finding === null
|
|
55
|
+
? []
|
|
56
|
+
: [
|
|
57
|
+
`${finding.description}. kb_check blocks it under entity-context-missing. ${finding.suggestion}`,
|
|
58
|
+
];
|
|
59
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { PrologPort } from "../../public/operations/runtime-types.js";
|
|
2
|
+
import { type StoredEntityLookup } from "./stored-entity.js";
|
|
2
3
|
import type { StagedUpsertState, UpsertInput } from "./types.js";
|
|
3
4
|
/**
|
|
4
5
|
* Resolve the provenance an upsert writes. kb_upsert never overwrites who
|
|
@@ -17,5 +18,5 @@ import type { StagedUpsertState, UpsertInput } from "./types.js";
|
|
|
17
18
|
* Without a Prolog runtime the existing entity cannot be read, so only rule 1
|
|
18
19
|
* applies.
|
|
19
20
|
*/
|
|
20
|
-
export declare function resolveUpsertOrigin(input: UpsertInput, prolog: Pick<PrologPort, "query"> | undefined, now: Date, staged?: StagedUpsertState): Promise<UpsertInput>;
|
|
21
|
+
export declare function resolveUpsertOrigin(input: UpsertInput, prolog: Pick<PrologPort, "query"> | undefined, now: Date, staged?: StagedUpsertState, lookup?: StoredEntityLookup): Promise<UpsertInput>;
|
|
21
22
|
//# sourceMappingURL=origin.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"origin.d.ts","sourceRoot":"","sources":["../../../src/operations/mutation/origin.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"origin.d.ts","sourceRoot":"","sources":["../../../src/operations/mutation/origin.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0CAA0C,CAAC;AAC3E,OAAO,EACL,KAAK,kBAAkB,EAExB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAUjE;;;;;;;;;;;;;;;;GAgBG;AAEH,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,GAAG,SAAS,EAC7C,GAAG,EAAE,IAAI,EACT,MAAM,CAAC,EAAE,iBAAiB,EAC1B,MAAM,CAAC,EAAE,kBAAkB,GAC1B,OAAO,CAAC,WAAW,CAAC,CAwBtB"}
|
|
@@ -15,9 +15,8 @@
|
|
|
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 { escapeAtom } from "../../prolog/codec.js";
|
|
19
18
|
import { readEntityOrigin } from "../../public/entity-origin.js";
|
|
20
|
-
import {
|
|
19
|
+
import { storedEntityLookup, } from "./stored-entity.js";
|
|
21
20
|
function isRecord(value) {
|
|
22
21
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
23
22
|
}
|
|
@@ -42,7 +41,7 @@ function withOrigin(input, origin) {
|
|
|
42
41
|
* applies.
|
|
43
42
|
*/
|
|
44
43
|
// implements REQ-kibi-entity-origin
|
|
45
|
-
export async function resolveUpsertOrigin(input, prolog, now, staged) {
|
|
44
|
+
export async function resolveUpsertOrigin(input, prolog, now, staged, lookup) {
|
|
46
45
|
const supplied = input.properties.origin;
|
|
47
46
|
if (supplied !== undefined) {
|
|
48
47
|
return isRecord(supplied) && supplied.recorded_at === undefined
|
|
@@ -57,22 +56,12 @@ export async function resolveUpsertOrigin(input, prolog, now, staged) {
|
|
|
57
56
|
const stored = readEntityOrigin(planned.origin);
|
|
58
57
|
return stored === null ? input : withOrigin(input, stored);
|
|
59
58
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
if (!exists.success) {
|
|
59
|
+
const existing = await (lookup ?? storedEntityLookup(prolog, input.id, input.type)).entity();
|
|
60
|
+
if (existing === undefined) {
|
|
63
61
|
return withOrigin(input, { kind: "agent", recorded_at: now.toISOString() });
|
|
64
62
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
id: input.id,
|
|
69
|
-
type: input.type,
|
|
70
|
-
});
|
|
71
|
-
stored = readEntityOrigin(existing?.origin);
|
|
72
|
-
}
|
|
73
|
-
catch {
|
|
74
|
-
// Unreadable: leave origin out. The source-first write merges the
|
|
75
|
-
// authored frontmatter, so a stored origin there survives either way.
|
|
76
|
-
}
|
|
63
|
+
// Unreadable (null): leave origin out. The source-first write merges the
|
|
64
|
+
// authored frontmatter, so a stored origin there survives either way.
|
|
65
|
+
const stored = readEntityOrigin(existing?.origin);
|
|
77
66
|
return stored === null ? input : withOrigin(input, stored);
|
|
78
67
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { PrologPort } from "../../public/operations/runtime-types.js";
|
|
2
|
+
import { type StoredEntityLookup } from "./stored-entity.js";
|
|
3
|
+
import type { StagedUpsertState, UpsertInput } from "./types.js";
|
|
4
|
+
/**
|
|
5
|
+
* kb_upsert on an existing requirement that changes neither its prose nor its
|
|
6
|
+
* proposition ledger keeps the stored ledger. A payload that adds a
|
|
7
|
+
* relationship (for example `specified_by`) and carries no `semantic_*` or
|
|
8
|
+
* `logic_claims` field, and no `title` or `text_ref` that differs from the
|
|
9
|
+
* stored value, is merged over the stored semantic contract (and the stored
|
|
10
|
+
* `text_ref` it omits) before validation. The
|
|
11
|
+
* proposition-complete check then runs against the merged requirement, which
|
|
12
|
+
* is also what the write records. A payload that supplies any ledger field or
|
|
13
|
+
* changes the prose is validated exactly as given.
|
|
14
|
+
*/
|
|
15
|
+
export declare function withStoredRequirementSemantics(input: UpsertInput, prolog: Pick<PrologPort, "query">, staged?: StagedUpsertState, lookup?: StoredEntityLookup): Promise<UpsertInput>;
|
|
16
|
+
//# sourceMappingURL=requirement-semantics.d.ts.map
|
|
@@ -0,0 +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;AAC3E,OAAO,EACL,KAAK,kBAAkB,EAExB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAwCjE;;;;;;;;;;GAUG;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,CA6BtB"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { storedEntityLookup, } from "./stored-entity.js";
|
|
2
|
+
/** The fields that make up a requirement's proposition ledger. */
|
|
3
|
+
const SEMANTIC_CONTRACT_FIELDS = [
|
|
4
|
+
"semantic_text",
|
|
5
|
+
"semantic_clauses",
|
|
6
|
+
"semantic_inventory",
|
|
7
|
+
"semantic_inventory_version",
|
|
8
|
+
"semantic_source_field",
|
|
9
|
+
"semantic_source_hash",
|
|
10
|
+
"logic_claims",
|
|
11
|
+
];
|
|
12
|
+
/** Prose a requirement's semantic source can be read from besides semantic_text. */
|
|
13
|
+
const PROSE_FIELDS = ["title", "text_ref"];
|
|
14
|
+
/** Stored prose a relationship-only update may leave out. */
|
|
15
|
+
const PRESERVED_PROSE_FIELDS = ["text_ref"];
|
|
16
|
+
function suppliesSemanticContract(properties) {
|
|
17
|
+
return Object.keys(properties).some((key) => key.startsWith("semantic_") || key === "logic_claims");
|
|
18
|
+
}
|
|
19
|
+
async function storedRequirement(id, lookup, staged) {
|
|
20
|
+
// An earlier step of the same plan that writes this entity is its history.
|
|
21
|
+
const planned = staged?.entities.get(id);
|
|
22
|
+
if (planned !== undefined)
|
|
23
|
+
return planned.type === "req" ? planned : undefined;
|
|
24
|
+
return (await lookup.entity()) ?? undefined;
|
|
25
|
+
}
|
|
26
|
+
// implements REQ-kibi-upsert-preserves-requirement-semantics
|
|
27
|
+
/**
|
|
28
|
+
* kb_upsert on an existing requirement that changes neither its prose nor its
|
|
29
|
+
* proposition ledger keeps the stored ledger. A payload that adds a
|
|
30
|
+
* relationship (for example `specified_by`) and carries no `semantic_*` or
|
|
31
|
+
* `logic_claims` field, and no `title` or `text_ref` that differs from the
|
|
32
|
+
* stored value, is merged over the stored semantic contract (and the stored
|
|
33
|
+
* `text_ref` it omits) before validation. The
|
|
34
|
+
* proposition-complete check then runs against the merged requirement, which
|
|
35
|
+
* is also what the write records. A payload that supplies any ledger field or
|
|
36
|
+
* changes the prose is validated exactly as given.
|
|
37
|
+
*/
|
|
38
|
+
export async function withStoredRequirementSemantics(input, prolog, staged, lookup = storedEntityLookup(prolog, input.id, input.type)) {
|
|
39
|
+
if (input.type !== "req")
|
|
40
|
+
return input;
|
|
41
|
+
const properties = input.properties ?? {};
|
|
42
|
+
if (suppliesSemanticContract(properties))
|
|
43
|
+
return input;
|
|
44
|
+
const stored = await storedRequirement(input.id, lookup, staged);
|
|
45
|
+
if (stored === undefined)
|
|
46
|
+
return input;
|
|
47
|
+
if (PROSE_FIELDS.some((field) => properties[field] !== undefined && properties[field] !== stored[field]))
|
|
48
|
+
return input;
|
|
49
|
+
const preserved = {};
|
|
50
|
+
for (const field of [
|
|
51
|
+
...SEMANTIC_CONTRACT_FIELDS,
|
|
52
|
+
...PRESERVED_PROSE_FIELDS,
|
|
53
|
+
]) {
|
|
54
|
+
if (stored[field] !== undefined)
|
|
55
|
+
preserved[field] = stored[field];
|
|
56
|
+
}
|
|
57
|
+
// Only a recorded ledger is kept. A stored `semantic_text` alone (derived
|
|
58
|
+
// from the body at sync) is not one, and merging it would turn a payload
|
|
59
|
+
// that is valid as sent into one the ingestion boundary rejects.
|
|
60
|
+
if (stored.semantic_inventory_version === undefined ||
|
|
61
|
+
!Array.isArray(stored.semantic_inventory))
|
|
62
|
+
return input;
|
|
63
|
+
return { ...input, properties: { ...preserved, ...properties } };
|
|
64
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"source-authoring.d.ts","sourceRoot":"","sources":["../../../src/operations/mutation/source-authoring.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"source-authoring.d.ts","sourceRoot":"","sources":["../../../src/operations/mutation/source-authoring.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,6 +6,7 @@ import { isDeepStrictEqual } from "node:util";
|
|
|
6
6
|
import { dump as dumpYaml, load as loadYaml } from "js-yaml";
|
|
7
7
|
import { parseDocument, stringify } from "yaml";
|
|
8
8
|
import { OperationError } from "../../cli-errors.js";
|
|
9
|
+
import { requirementSemanticText } from "../../extractors/markdown.js";
|
|
9
10
|
import { canonicalFilesystemPath } from "../../utils/canonical-path.js";
|
|
10
11
|
import { CANONICAL_ENTITY_PATHS, isDerivedKbPath, } from "../../utils/kb-paths.js";
|
|
11
12
|
function digest(value) {
|
|
@@ -192,6 +193,15 @@ function renderEntityDocument(input, entity, existingContent) {
|
|
|
192
193
|
frontmatter.id = entity.id;
|
|
193
194
|
frontmatter.title ??= entity.id;
|
|
194
195
|
frontmatter.type = entity.type;
|
|
196
|
+
// The checked meaning is always stated, never derived from a body that now
|
|
197
|
+
// also carries context sections.
|
|
198
|
+
if (entity.type === "req" &&
|
|
199
|
+
(typeof frontmatter.semantic_text !== "string" ||
|
|
200
|
+
frontmatter.semantic_text.trim() === "")) {
|
|
201
|
+
const derived = requirementSemanticText(body);
|
|
202
|
+
if (derived !== "")
|
|
203
|
+
frontmatter.semantic_text = derived;
|
|
204
|
+
}
|
|
195
205
|
return `---\n${dumpYaml(frontmatter, { noRefs: true, lineWidth: -1, sortKeys: false })}---${body.startsWith("\n") ? "" : "\n"}${body}`;
|
|
196
206
|
}
|
|
197
207
|
/** Generated coordinate fields belong exclusively to `.kb/symbol-coordinates.yaml`. */
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { PrologPort } from "../../public/operations/runtime-types.js";
|
|
2
|
+
/**
|
|
3
|
+
* The stored entity an upsert replaces: `undefined` when no entity has the
|
|
4
|
+
* id, `null` when one exists but cannot be read.
|
|
5
|
+
*/
|
|
6
|
+
export type StoredEntity = Readonly<Record<string, unknown>> | null | undefined;
|
|
7
|
+
export type StoredEntityLookup = {
|
|
8
|
+
/** Whether an entity with the id is stored. */
|
|
9
|
+
readonly exists: () => Promise<boolean>;
|
|
10
|
+
/** The stored entity, loaded only when one exists. */
|
|
11
|
+
readonly entity: () => Promise<StoredEntity>;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* One read of the entity an upsert replaces, shared by every step of the
|
|
15
|
+
* upsert that needs it (the requirement ledger merge, the stored
|
|
16
|
+
* relationships and the stored origin), so the store is probed and loaded at
|
|
17
|
+
* most once per upsert.
|
|
18
|
+
*/
|
|
19
|
+
export declare function storedEntityLookup(prolog: Pick<PrologPort, "query">, id: string, type: string): StoredEntityLookup;
|
|
20
|
+
//# sourceMappingURL=stored-entity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stored-entity.d.ts","sourceRoot":"","sources":["../../../src/operations/mutation/stored-entity.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0CAA0C,CAAC;AAE3E;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,IAAI,GAAG,SAAS,CAAC;AAEhF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,+CAA+C;IAC/C,QAAQ,CAAC,MAAM,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IACxC,sDAAsD;IACtD,QAAQ,CAAC,MAAM,EAAE,MAAM,OAAO,CAAC,YAAY,CAAC,CAAC;CAC9C,CAAC;AAGF;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,EACjC,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,MAAM,GACX,kBAAkB,CAsBpB"}
|
|
@@ -0,0 +1,51 @@
|
|
|
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 { escapeAtom } from "../../prolog/codec.js";
|
|
19
|
+
import { loadEntities } from "../../public/operations/discovery-entities.js";
|
|
20
|
+
// implements REQ-kibi-upsert-preserves-requirement-semantics, REQ-kibi-entity-origin
|
|
21
|
+
/**
|
|
22
|
+
* One read of the entity an upsert replaces, shared by every step of the
|
|
23
|
+
* upsert that needs it (the requirement ledger merge, the stored
|
|
24
|
+
* relationships and the stored origin), so the store is probed and loaded at
|
|
25
|
+
* most once per upsert.
|
|
26
|
+
*/
|
|
27
|
+
export function storedEntityLookup(prolog, id, type) {
|
|
28
|
+
let probe;
|
|
29
|
+
let read;
|
|
30
|
+
const exists = () => {
|
|
31
|
+
probe ??= prolog
|
|
32
|
+
.query(`once(kb_entity('${escapeAtom(id)}', _, _))`)
|
|
33
|
+
.then((result) => result.success);
|
|
34
|
+
return probe;
|
|
35
|
+
};
|
|
36
|
+
const entity = () => {
|
|
37
|
+
read ??= (async () => {
|
|
38
|
+
if (!(await exists()))
|
|
39
|
+
return undefined;
|
|
40
|
+
try {
|
|
41
|
+
const [existing] = await loadEntities(prolog, { id, type });
|
|
42
|
+
return existing ?? null;
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
})();
|
|
48
|
+
return read;
|
|
49
|
+
};
|
|
50
|
+
return { exists, entity };
|
|
51
|
+
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import type { OperationContext } from "../../public/operations/runtime-types.js";
|
|
2
2
|
import type { OperationResult } from "../../public/operations/types.js";
|
|
3
3
|
import { analyzeSemanticAdvisorInput } from "../semantic-advisor/analyze-prose.js";
|
|
4
|
+
import { type StoredEntityLookup } from "./stored-entity.js";
|
|
4
5
|
import type { RelationshipInput, StagedUpsertState, UpsertInput, UpsertPayload, ValidatedUpsert } from "./types.js";
|
|
5
6
|
export declare function assertRelationshipShardContained(workspaceRoot: string, shardPath: string): void;
|
|
6
7
|
export declare function validateAppendOnlyProofReceipts(entity: Readonly<Record<string, unknown>>, context: OperationContext, staged?: StagedUpsertState): Promise<void>;
|
|
7
|
-
export declare function effectiveRelationships(input: UpsertInput, entity: Readonly<Record<string, unknown>>, relationships: readonly RelationshipInput[], context: OperationContext, staged?: StagedUpsertState): Promise<readonly RelationshipInput[]>;
|
|
8
|
+
export declare function effectiveRelationships(input: UpsertInput, entity: Readonly<Record<string, unknown>>, relationships: readonly RelationshipInput[], context: OperationContext, staged?: StagedUpsertState, lookup?: StoredEntityLookup): Promise<readonly RelationshipInput[]>;
|
|
8
9
|
export type UpsertValidationOptions = Readonly<{
|
|
9
10
|
/** Skip the append-only receipt check (kibi proof prune only). */
|
|
10
11
|
readonly allowReceiptsPrune?: boolean;
|
|
@@ -29,7 +30,7 @@ export type UpsertValidation = Readonly<{
|
|
|
29
30
|
* kb_apply_plan runs it for every plan step before the plan's first write,
|
|
30
31
|
* passing the earlier steps' writes as `staged`.
|
|
31
32
|
*/
|
|
32
|
-
export declare function validateUpsertForCommit(
|
|
33
|
+
export declare function validateUpsertForCommit(payload: UpsertInput, context: OperationContext, options?: UpsertValidationOptions): Promise<UpsertValidation>;
|
|
33
34
|
export type UpsertExecutionOptions = Readonly<{
|
|
34
35
|
/**
|
|
35
36
|
* Internal escape hatch for proof-receipt ingest: when provided, the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upsert.d.ts","sourceRoot":"","sources":["../../../src/operations/mutation/upsert.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AACjF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAUxE,OAAO,EAAE,2BAA2B,EAAE,MAAM,sCAAsC,CAAC;
|
|
1
|
+
{"version":3,"file":"upsert.d.ts","sourceRoot":"","sources":["../../../src/operations/mutation/upsert.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AACjF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAUxE,OAAO,EAAE,2BAA2B,EAAE,MAAM,sCAAsC,CAAC;AA4BnF,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;AA6CpB,wBAAgB,gCAAgC,CAC9C,aAAa,EAAE,MAAM,EACrB,SAAS,EAAE,MAAM,GAChB,IAAI,CAkBN;AAmCD,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,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,UAAU,CAAC,OAAO,2BAA2B,CAAC,CAAC;CACnE,CAAC,CAAC;AAGH;;;;;;;;GAQG;AACH,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,WAAW,EACpB,OAAO,EAAE,gBAAgB,EACzB,OAAO,GAAE,uBAA4B,GACpC,OAAO,CAAC,gBAAgB,CAAC,CAgF3B;AAGD,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,CAsgBzC"}
|
|
@@ -4,7 +4,6 @@ import path from "node:path";
|
|
|
4
4
|
import { OperationError } from "../../cli-errors.js";
|
|
5
5
|
import { readManifestWithCoordinateOverlay } from "../../extractors/manifest.js";
|
|
6
6
|
import { extractManifestSymbolRecords } from "../../extractors/manifest.js";
|
|
7
|
-
import { escapeAtom } from "../../prolog/codec.js";
|
|
8
7
|
import { loadEntities } from "../../public/operations/discovery-entities.js";
|
|
9
8
|
import { appendOnlyProofReceiptHistoryErrors } from "../../public/proof-receipt.js";
|
|
10
9
|
import { appendRelationship, computeShardPath, } from "../../relationships/shards.js";
|
|
@@ -13,13 +12,16 @@ import { canonicalFilesystemPath } from "../../utils/canonical-path.js";
|
|
|
13
12
|
import { entityIdStyleWarnings } from "../../utils/entity-id-style.js";
|
|
14
13
|
import { analyzeSemanticAdvisorInput } from "../semantic-advisor/analyze-prose.js";
|
|
15
14
|
import { assertLogicalGroundingClaimKeys, assertSemanticInventoryBoundary, } from "../semantic-advisor/ingestion-boundary.js";
|
|
15
|
+
import { entityContextWarnings } from "./context-warning.js";
|
|
16
16
|
import { buildUpsertCommitGoal, formatUpsertError } from "./contradictions.js";
|
|
17
17
|
import { resolveUpsertOrigin } from "./origin.js";
|
|
18
18
|
import { planRecoveryNotes, settlePendingPlanApplyJournals, withPlanRecoveryNotes, } from "./plan-apply-journal.js";
|
|
19
19
|
import { assertPredicateArgumentVocabulary } from "./predicate-vocabulary-guard.js";
|
|
20
20
|
import { existingRelationships, validateLiveRelationshipTargets, validateRelationshipSources, validateStrictLanePairing, validateSupersedesSourceHistory, } from "./relationships.js";
|
|
21
|
+
import { withStoredRequirementSemantics } from "./requirement-semantics.js";
|
|
21
22
|
import { MutationRollbackFailureError, MutationSaga } from "./saga.js";
|
|
22
23
|
import { writePendingSourceReceipt, writeSourceForUpsert, } from "./source-authoring.js";
|
|
24
|
+
import { storedEntityLookup, } from "./stored-entity.js";
|
|
23
25
|
import { acquireSymbolCompilerLock, releaseSymbolCompilerLock, } from "./symbol-compiler-lock.js";
|
|
24
26
|
import { validateSymbolGranularity } from "./symbol-granularity.js";
|
|
25
27
|
import { refreshSymbolCoordinatesForManifest } from "./symbol-refresh.js";
|
|
@@ -118,16 +120,16 @@ export async function validateAppendOnlyProofReceipts(entity, context, staged) {
|
|
|
118
120
|
throw new Error(`Entity validation failed: ${errors.join("; ")}`);
|
|
119
121
|
}
|
|
120
122
|
}
|
|
121
|
-
export async function effectiveRelationships(input, entity, relationships, context, staged) {
|
|
123
|
+
export async function effectiveRelationships(input, entity, relationships, context, staged, lookup) {
|
|
122
124
|
const prolog = requireProlog(context);
|
|
123
125
|
// Relationships an earlier plan step adds from this entity will exist when
|
|
124
126
|
// this upsert runs.
|
|
125
127
|
const plannedOwn = (staged?.relationships ?? []).filter((relationship) => relationship.from === input.id);
|
|
126
|
-
const exists = await
|
|
127
|
-
if (!exists
|
|
128
|
+
const exists = await (lookup ?? storedEntityLookup(prolog, input.id, input.type)).exists();
|
|
129
|
+
if (!exists && plannedOwn.length === 0)
|
|
128
130
|
return relationships;
|
|
129
131
|
try {
|
|
130
|
-
const current = exists
|
|
132
|
+
const current = exists
|
|
131
133
|
? (await existingRelationships(prolog, String(entity.id)))
|
|
132
134
|
// An upsert owns only relationships whose source is the upserted
|
|
133
135
|
// entity. Incoming relationships must not be copied into its
|
|
@@ -186,16 +188,22 @@ function reextractCanonicalSymbolEntity(symbolId, authoredRelativePath, workspac
|
|
|
186
188
|
* kb_apply_plan runs it for every plan step before the plan's first write,
|
|
187
189
|
* passing the earlier steps' writes as `staged`.
|
|
188
190
|
*/
|
|
189
|
-
export async function validateUpsertForCommit(
|
|
191
|
+
export async function validateUpsertForCommit(payload, context, options = {}) {
|
|
190
192
|
const prolog = requireProlog(context);
|
|
191
193
|
const staged = options.staged;
|
|
192
|
-
|
|
194
|
+
// The payload must be valid on its own before the store is read.
|
|
195
|
+
const checked = validateUpsertInput(payload, context.clock());
|
|
196
|
+
validateRelationshipSources(payload.id, checked.relationships);
|
|
197
|
+
// One read of the entity this upsert replaces, shared by the ledger merge
|
|
198
|
+
// and the stored origin below.
|
|
199
|
+
const lookup = storedEntityLookup(prolog, payload.id, payload.type);
|
|
200
|
+
const input = await withStoredRequirementSemantics(payload, prolog, staged, lookup);
|
|
201
|
+
const validated = input === payload ? checked : validateUpsertInput(input, context.clock());
|
|
193
202
|
if (options.allowReceiptsPrune !== true) {
|
|
194
203
|
await validateAppendOnlyProofReceipts(validated.entity, context, staged);
|
|
195
204
|
}
|
|
196
|
-
validateRelationshipSources(input.id, validated.relationships);
|
|
197
205
|
await validateSymbolGranularity(validated.entity, validated.relationships, context);
|
|
198
|
-
const relationships = await effectiveRelationships(input, validated.entity, validated.relationships, context, staged);
|
|
206
|
+
const relationships = await effectiveRelationships(input, validated.entity, validated.relationships, context, staged, lookup);
|
|
199
207
|
await validateStrictLanePairing(prolog, validated.relationships, staged);
|
|
200
208
|
await validateLiveRelationshipTargets(prolog, validated.entity, validated.relationships, staged);
|
|
201
209
|
await validateSupersedesSourceHistory(prolog, validated.entity, validated.relationships, context.workspaceRoot, undefined, staged);
|
|
@@ -207,7 +215,7 @@ export async function validateUpsertForCommit(input, context, options = {}) {
|
|
|
207
215
|
await assertPredicateArgumentVocabulary(prolog, validated.entity, staged);
|
|
208
216
|
// The origin the write records is added last: none of the checks above
|
|
209
217
|
// reads it, and a rejected payload never pays for the stored-origin read.
|
|
210
|
-
const recorded = await resolveUpsertOrigin(input, prolog, context.clock(), staged);
|
|
218
|
+
const recorded = await resolveUpsertOrigin(input, prolog, context.clock(), staged, lookup);
|
|
211
219
|
return {
|
|
212
220
|
validated: recorded === input
|
|
213
221
|
? validated
|
|
@@ -516,6 +524,7 @@ export async function executeUpsert(input, context, options = {}) {
|
|
|
516
524
|
...semantic.warnings,
|
|
517
525
|
...coverage,
|
|
518
526
|
...idStyleWarnings,
|
|
527
|
+
...entityContextWarnings(input, commitEntity ?? validated.entity, context.workspaceRoot, sourceWrite?.receipt.path),
|
|
519
528
|
...shardWarnings,
|
|
520
529
|
],
|
|
521
530
|
semanticAdvisor: semantic.receipt,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate-upsert.d.ts","sourceRoot":"","sources":["../../../src/operations/mutation/validate-upsert.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,gBAAgB,EAEjB,MAAM,0CAA0C,CAAC;AAClD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;
|
|
1
|
+
{"version":3,"file":"validate-upsert.d.ts","sourceRoot":"","sources":["../../../src/operations/mutation/validate-upsert.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,gBAAgB,EAEjB,MAAM,0CAA0C,CAAC;AAClD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAOxE,OAAO,KAAK,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AA+CrE;;;;;GAKG;AACH,wBAAsB,qBAAqB,CACzC,KAAK,EAAE,WAAW,EAClB,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,eAAe,CAAC,qBAAqB,CAAC,CAAC,CA4DjD"}
|
|
@@ -3,6 +3,7 @@ import { escapeAtom } from "../../prolog/codec.js";
|
|
|
3
3
|
import { entityIdStyleWarnings } from "../../utils/entity-id-style.js";
|
|
4
4
|
import { analyzeSemanticAdvisorInput } from "../semantic-advisor/analyze-prose.js";
|
|
5
5
|
import { assertSemanticInventoryBoundary } from "../semantic-advisor/ingestion-boundary.js";
|
|
6
|
+
import { entityContextWarnings } from "./context-warning.js";
|
|
6
7
|
import { validateRelationshipSources } from "./relationships.js";
|
|
7
8
|
import { validateSymbolGranularity } from "./symbol-granularity.js";
|
|
8
9
|
import { validateAppendOnlyProofReceipts, validateUpsertForCommit, } from "./upsert.js";
|
|
@@ -57,7 +58,11 @@ export async function executeValidateUpsert(input, context) {
|
|
|
57
58
|
const payload = {
|
|
58
59
|
valid: true,
|
|
59
60
|
errors: [],
|
|
60
|
-
warnings: [
|
|
61
|
+
warnings: [
|
|
62
|
+
...semantic.warnings,
|
|
63
|
+
...idStyleWarnings,
|
|
64
|
+
...entityContextWarnings(input, entity, context.workspaceRoot),
|
|
65
|
+
],
|
|
61
66
|
semanticAdvisor: semantic.receipt,
|
|
62
67
|
normalizedPreview: entity,
|
|
63
68
|
};
|
|
@@ -14,6 +14,15 @@ export type CompileIntentArgs = Readonly<{
|
|
|
14
14
|
scenarioDrafts?: readonly ScenarioDraft[];
|
|
15
15
|
testDrafts?: readonly TestDraft[];
|
|
16
16
|
proposalDecisions?: readonly ProposalDecision[];
|
|
17
|
+
/**
|
|
18
|
+
* Why the requirement exists, who asked and what does not fit its checked
|
|
19
|
+
* meaning. Required when mode is create; rendered as `## Context`.
|
|
20
|
+
*/
|
|
21
|
+
context?: string;
|
|
22
|
+
/** Verbatim text the intent came from; rendered as a blockquote in `## Source`. */
|
|
23
|
+
sourceExcerpt?: string;
|
|
24
|
+
/** Locator of that text (ticket, URL, path); rendered in `## Source`. */
|
|
25
|
+
sourceReference?: string;
|
|
17
26
|
}>;
|
|
18
27
|
export type ScenarioDraft = Readonly<{
|
|
19
28
|
id?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compile-intent.d.ts","sourceRoot":"","sources":["../../../src/operations/planning/compile-intent.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"compile-intent.d.ts","sourceRoot":"","sources":["../../../src/operations/planning/compile-intent.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import path from "node:path";
|
|
3
|
+
import { renderRequirementBody, reviseRequirementBody, } from "../../entity-body-context.js";
|
|
3
4
|
import { executeIntentSearch, } from "../../intent-search.js";
|
|
4
5
|
import { publicCapabilityStamp } from "../../plugins/compose-semantic-classifier.js";
|
|
5
6
|
import { normalizeEntityId } from "../../prolog/codec.js";
|
|
6
7
|
import { loadEntities } from "../../public/operations/discovery-entities.js";
|
|
7
8
|
import { executeStatus } from "../../public/operations/discovery-executors.js";
|
|
9
|
+
import { readAuthoredEntity } from "../../public/operations/entity-context.js";
|
|
8
10
|
import { buildWhatIfAnalysisGoal } from "../mutation/contradictions.js";
|
|
9
11
|
import { canonicalSourcePath } from "../mutation/source-authoring.js";
|
|
10
12
|
import { validateUpsertInput } from "../mutation/validation.js";
|
|
@@ -48,6 +50,13 @@ function requiredIntent(args) {
|
|
|
48
50
|
!text(args.requirementId)) {
|
|
49
51
|
throw new Error("Compile intent failed: requirementId must be non-empty when supplied");
|
|
50
52
|
}
|
|
53
|
+
if (args.mode === "create" && !text(args.context)) {
|
|
54
|
+
throw new Error("Compile intent failed: context must be non-empty when mode is create; state why the requirement exists, who asked and the source, or write 'Reason not stated' when the requester gave no reason");
|
|
55
|
+
}
|
|
56
|
+
if (!text(args.context) &&
|
|
57
|
+
(text(args.sourceExcerpt) !== "" || text(args.sourceReference) !== "")) {
|
|
58
|
+
throw new Error("Compile intent failed: sourceExcerpt and sourceReference need context; supply context or drop them");
|
|
59
|
+
}
|
|
51
60
|
return intent;
|
|
52
61
|
}
|
|
53
62
|
function validateLocation(location) {
|
|
@@ -251,7 +260,9 @@ async function withDocumentTargets(context, prolog, steps, requirement, now) {
|
|
|
251
260
|
const stepDocument = isRecord(step.document) ? step.document : {};
|
|
252
261
|
const document = type === "req" && id === requirement.id
|
|
253
262
|
? {
|
|
254
|
-
|
|
263
|
+
...(requirement.body !== undefined
|
|
264
|
+
? { body: requirement.body }
|
|
265
|
+
: {}),
|
|
255
266
|
...(requirement.path !== undefined
|
|
256
267
|
? { path: requirement.path }
|
|
257
268
|
: {}),
|
|
@@ -283,6 +294,18 @@ async function withDocumentTargets(context, prolog, steps, requirement, now) {
|
|
|
283
294
|
}
|
|
284
295
|
return targeted;
|
|
285
296
|
}
|
|
297
|
+
/** Body of the requirement's existing authored document, when readable. */
|
|
298
|
+
async function existingRequirementBody(context, source) {
|
|
299
|
+
if (!context.fs || !source.endsWith(".md"))
|
|
300
|
+
return undefined;
|
|
301
|
+
try {
|
|
302
|
+
const raw = await context.fs.readFile(path.join(context.workspaceRoot, source));
|
|
303
|
+
return readAuthoredEntity(String(raw), source)?.body ?? undefined;
|
|
304
|
+
}
|
|
305
|
+
catch {
|
|
306
|
+
return undefined;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
286
309
|
function generatedRequirementId(intent) {
|
|
287
310
|
return `REQ-${slug(intent)}-${shortHash(intent).toUpperCase()}`;
|
|
288
311
|
}
|
|
@@ -841,11 +864,35 @@ export async function executeCompileIntent(args, context) {
|
|
|
841
864
|
// A step whose entity or document cannot be rendered would fail the apply,
|
|
842
865
|
// so it makes the plan need resolution instead of reporting it ready.
|
|
843
866
|
let planSteps = stepsWithAcceptedProposals;
|
|
867
|
+
// A create always carries context. An update replaces the non-context part
|
|
868
|
+
// of the existing body with the new intent and keeps its context sections
|
|
869
|
+
// byte for byte; supplied context or source replaces those sections too.
|
|
870
|
+
const sourceInput = {
|
|
871
|
+
excerpt: args.sourceExcerpt,
|
|
872
|
+
reference: args.sourceReference,
|
|
873
|
+
};
|
|
874
|
+
const existingBody = args.mode === "update"
|
|
875
|
+
? await existingRequirementBody(context, requirementDocument ?? text(existingEntity.source))
|
|
876
|
+
: undefined;
|
|
877
|
+
const requirementBody = existingBody !== undefined
|
|
878
|
+
? reviseRequirementBody({
|
|
879
|
+
existingBody,
|
|
880
|
+
statement: intent,
|
|
881
|
+
context: args.context,
|
|
882
|
+
source: sourceInput,
|
|
883
|
+
})
|
|
884
|
+
: text(args.context) !== ""
|
|
885
|
+
? renderRequirementBody({
|
|
886
|
+
statement: intent,
|
|
887
|
+
context: args.context,
|
|
888
|
+
source: sourceInput,
|
|
889
|
+
})
|
|
890
|
+
: undefined;
|
|
844
891
|
if (statusValue === "ready") {
|
|
845
892
|
try {
|
|
846
893
|
planSteps = await withDocumentTargets(context, prolog, stepsWithAcceptedProposals, {
|
|
847
894
|
id: requirementId,
|
|
848
|
-
body:
|
|
895
|
+
...(requirementBody !== undefined ? { body: requirementBody } : {}),
|
|
849
896
|
...(requirementDocument !== undefined
|
|
850
897
|
? { path: requirementDocument }
|
|
851
898
|
: {}),
|