kibi-cli 2.19.0 → 2.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli-operation-metadata.d.ts +1 -1
- package/dist/cli-operation-metadata.js +1 -1
- package/dist/cli-register-maintenance.js +1 -1
- package/dist/commands/engine.d.ts +2 -1
- package/dist/commands/engine.d.ts.map +1 -1
- package/dist/commands/engine.js +6 -1
- package/dist/commands/migrate.d.ts +2 -0
- package/dist/commands/migrate.d.ts.map +1 -1
- package/dist/commands/migrate.js +32 -6
- package/dist/commands/sync/discovery.d.ts.map +1 -1
- package/dist/commands/sync/discovery.js +14 -2
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +24 -6
- package/dist/extractors/markdown.d.ts.map +1 -1
- package/dist/extractors/markdown.js +2 -1
- package/dist/intent-search.d.ts +7 -0
- package/dist/intent-search.d.ts.map +1 -1
- package/dist/intent-search.js +66 -4
- package/dist/operations/migration/kb-sources.d.ts +5 -1
- package/dist/operations/migration/kb-sources.d.ts.map +1 -1
- package/dist/operations/migration/kb-sources.js +28 -1
- package/dist/operations/modeling/predicate-applicability.d.ts.map +1 -1
- package/dist/operations/modeling/predicate-applicability.js +10 -4
- package/dist/operations/modeling/predicate-applyplan.d.ts.map +1 -1
- package/dist/operations/modeling/predicate-applyplan.js +16 -5
- package/dist/operations/modeling/predicate-catalog-4.d.ts.map +1 -1
- package/dist/operations/modeling/predicate-catalog-4.js +3 -0
- package/dist/operations/modeling/predicate-inference-1.d.ts.map +1 -1
- package/dist/operations/modeling/predicate-inference-1.js +34 -7
- package/dist/operations/modeling/predicate-score-3.js +1 -1
- package/dist/operations/modeling/predicate-types.d.ts +6 -0
- package/dist/operations/modeling/predicate-types.d.ts.map +1 -1
- package/dist/operations/modeling/suggest-predicates.d.ts.map +1 -1
- package/dist/operations/modeling/suggest-predicates.js +111 -0
- package/dist/operations/mutation/source-authoring.d.ts +8 -0
- package/dist/operations/mutation/source-authoring.d.ts.map +1 -1
- package/dist/operations/mutation/source-authoring.js +33 -0
- package/dist/operations/mutation/types.d.ts +26 -0
- package/dist/operations/mutation/types.d.ts.map +1 -1
- package/dist/operations/mutation/upsert.d.ts.map +1 -1
- package/dist/operations/mutation/upsert.js +8 -2
- package/dist/operations/mutation/validate-upsert.d.ts.map +1 -1
- package/dist/operations/mutation/validate-upsert.js +116 -4
- package/dist/operations/mutation/validation.d.ts.map +1 -1
- package/dist/operations/mutation/validation.js +2 -1
- package/dist/operations/mutation/warnings.d.ts +10 -0
- package/dist/operations/mutation/warnings.d.ts.map +1 -1
- package/dist/operations/mutation/warnings.js +26 -0
- package/dist/operations/mutation/what-if.d.ts +25 -0
- package/dist/operations/mutation/what-if.d.ts.map +1 -0
- package/dist/operations/mutation/what-if.js +59 -0
- package/dist/operations/planning/compile-intent.d.ts +15 -20
- package/dist/operations/planning/compile-intent.d.ts.map +1 -1
- package/dist/operations/planning/compile-intent.js +64 -53
- package/dist/operations/semantic-advisor/clauses.d.ts +9 -0
- package/dist/operations/semantic-advisor/clauses.d.ts.map +1 -1
- package/dist/operations/semantic-advisor/clauses.js +32 -7
- package/dist/prolog/janitor.d.ts +26 -2
- package/dist/prolog/janitor.d.ts.map +1 -1
- package/dist/prolog/janitor.js +55 -3
- package/dist/prolog/store-lock.d.ts +28 -3
- package/dist/prolog/store-lock.d.ts.map +1 -1
- package/dist/prolog/store-lock.js +103 -12
- package/dist/public/operations/catalog.d.ts +49 -5
- package/dist/public/operations/catalog.d.ts.map +1 -1
- package/dist/public/operations/check-executor.d.ts +2 -2
- package/dist/public/operations/check-executor.d.ts.map +1 -1
- package/dist/public/operations/check-executor.js +35 -0
- package/dist/public/operations/check-format-shared.d.ts +16 -0
- package/dist/public/operations/check-format-shared.d.ts.map +1 -1
- package/dist/public/operations/check-format-shared.js +19 -0
- package/dist/public/operations/contracts.d.ts.map +1 -1
- package/dist/public/operations/contracts.js +10 -0
- package/dist/public/operations/discovery-executors.d.ts +3 -0
- package/dist/public/operations/discovery-executors.d.ts.map +1 -1
- package/dist/public/operations/discovery-executors.js +7 -2
- package/dist/public/operations/migration-plan.d.ts.map +1 -1
- package/dist/public/operations/migration-plan.js +37 -7
- package/dist/public/operations/specs/composite.d.ts +1 -1
- package/dist/public/operations/specs/composite.js +1 -1
- package/dist/public/operations/specs/discovery.d.ts +2 -2
- package/dist/public/operations/specs/discovery.d.ts.map +1 -1
- package/dist/public/operations/specs/discovery.js +2 -2
- package/dist/public/operations/specs/mutation-schemas.d.ts +2 -2
- package/dist/public/operations/specs/mutation-schemas.d.ts.map +1 -1
- package/dist/public/operations/specs/mutation-schemas.js +8 -17
- package/dist/public/operations/specs/upsert.d.ts +46 -2
- package/dist/public/operations/specs/upsert.d.ts.map +1 -1
- package/dist/public/operations/specs/upsert.js +14 -0
- package/dist/public/schemas/entity.d.ts.map +1 -1
- package/dist/public/schemas/entity.js +2 -13
- package/dist/public/skills/kibi-usage/SKILL.md +38 -1
- package/dist/public/skills/kibi-usage/resources/fact-lanes.md +5 -3
- package/dist/public/skills/kibi-usage/resources/ui-requirements.md +2 -2
- package/dist/public/skills/kibi-usage/resources/workflows.md +1 -1
- package/dist/schemas/entity.schema.json +2 -25
- package/dist/search-answer.d.ts +13 -0
- package/dist/search-answer.d.ts.map +1 -1
- package/dist/search-answer.js +45 -4
- package/dist/utils/branch-store.d.ts.map +1 -1
- package/dist/utils/branch-store.js +4 -2
- package/package.json +3 -3
- package/src/public/operations/check-executor.ts +44 -1
- package/src/public/operations/check-format-shared.ts +35 -1
- package/src/public/operations/contracts.ts +11 -0
- package/src/public/operations/discovery-executors.ts +12 -2
- package/src/public/operations/migration-plan.ts +41 -9
- package/src/public/operations/specs/composite.ts +1 -1
- package/src/public/operations/specs/discovery.ts +3 -2
- package/src/public/operations/specs/mutation-schemas.ts +8 -17
- package/src/public/operations/specs/upsert.ts +15 -0
- package/src/public/schemas/entity.ts +2 -13
- package/src/public/skills/kibi-usage/SKILL.md +38 -1
- package/src/public/skills/kibi-usage/resources/fact-lanes.md +5 -3
- package/src/public/skills/kibi-usage/resources/ui-requirements.md +2 -2
- package/src/public/skills/kibi-usage/resources/workflows.md +1 -1
- package/src/schemas/entity.schema.json +2 -25
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
-
// An explicit grant ("are allowed to", "is permitted to"
|
|
3
|
-
// permission just as "denied"/"forbidden"
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
// unmodeled normative
|
|
8
|
-
|
|
2
|
+
// An explicit grant ("are allowed to", "is permitted to", "have permission
|
|
3
|
+
// to", "are entitled to") asserts a permission just as "denied"/"forbidden"
|
|
4
|
+
// assert a prohibition. Bare "can", "may" and "are able to" are accepted by
|
|
5
|
+
// the predicate applicability gate but not here: stored clause roles are
|
|
6
|
+
// derived from this pattern, and "it can be restricted to …" style capability
|
|
7
|
+
// prose would turn existing descriptive inventories into unmodeled normative
|
|
8
|
+
// clauses ("must be able to" is already normative through "must").
|
|
9
|
+
const NORMATIVE_ASSERTION_PATTERN = /\b(?:must|shall|should|required|requires?|may\s+only|(?:is|are)\s+(?:not\s+)?(?:allowed|permitted|entitled)\s+to|ha(?:s|ve)\s+(?:no\s+)?permission\s+to|permitted|may\s+(?:not\s+)?(?:be\s+)?\w+\s+only\b|may\s+(?:have\s+)?(?:at\s+most|at\s+least|exactly|no\s+more\s+than|up\s+to)|only\s+.+?\s+(?:may|can)|must\s+not|shall\s+not|cannot|can't|denied|forbidden|prohibited|(?:is|are|be|become|becomes|remain|remains)\s+(?:invalid|rejected|prohibited|forbidden)|(?:reject|rejects|rejected|rejection)\s+(?:invalid|unresolved|ambiguous)|fail(?:s|ed)?\s+(?:clearly|explicitly|with)|expires?\s+(?:after|within|in)|failure\s+(?:behavior|policy|outcome)|error\s+(?:handling|behavior|policy|outcome)|required\s+outcome|defaults?\s+to)\b/i;
|
|
9
10
|
// Conditional/temporal cues help discover clauses but do not by themselves
|
|
10
11
|
// turn explanatory or subjective context into an asserted obligation.
|
|
11
12
|
const NORMATIVE_PATTERN = new RegExp(`${NORMATIVE_ASSERTION_PATTERN.source}|\\b(?:before|unless|when|if)\\b`, "i");
|
|
@@ -37,6 +38,30 @@ export function semanticClaimKey(text) {
|
|
|
37
38
|
const digest = createHash("sha256").update(normalized).digest("hex");
|
|
38
39
|
return `CLAIM-${digest.slice(0, 16).toUpperCase()}`;
|
|
39
40
|
}
|
|
41
|
+
/** Fact kinds that quote a claim as a review note and never ground it. */
|
|
42
|
+
const NON_GROUNDING_FACT_KINDS = new Set(["observation", "meta"]);
|
|
43
|
+
/**
|
|
44
|
+
* Fill `claim_key` from `claim_text` on a fact that may ground a claim.
|
|
45
|
+
*
|
|
46
|
+
* The key is a pure function of the text, so a caller that sends the text
|
|
47
|
+
* alone has given Kibi everything it needs; a supplied key is still checked
|
|
48
|
+
* against the derived one by the entity validators. Observation and meta
|
|
49
|
+
* facts quote a claim without owning it, so they stay keyless.
|
|
50
|
+
*/
|
|
51
|
+
// implements REQ-kibi-review-observation-claim-text-v2
|
|
52
|
+
export function deriveFactClaimKey(entity) {
|
|
53
|
+
if (entity.type !== "fact")
|
|
54
|
+
return;
|
|
55
|
+
if (entity.claim_key !== undefined)
|
|
56
|
+
return;
|
|
57
|
+
if (typeof entity.claim_text !== "string")
|
|
58
|
+
return;
|
|
59
|
+
if (typeof entity.fact_kind === "string" &&
|
|
60
|
+
NON_GROUNDING_FACT_KINDS.has(entity.fact_kind)) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
entity.claim_key = semanticClaimKey(entity.claim_text);
|
|
64
|
+
}
|
|
40
65
|
function detectedClauses(text) {
|
|
41
66
|
return text
|
|
42
67
|
.split(/(?:\r?\n)+|;|(?<=[.!?])\s+(?=[A-Z0-9])/)
|
package/dist/prolog/janitor.d.ts
CHANGED
|
@@ -25,7 +25,20 @@ export interface SocketFinding {
|
|
|
25
25
|
readonly holderState: StoreLockHolderState;
|
|
26
26
|
readonly action: "clean" | "keep";
|
|
27
27
|
}
|
|
28
|
-
|
|
28
|
+
/**
|
|
29
|
+
* A stale-lock takeover record past its visibility window: kb_status no
|
|
30
|
+
* longer reports it, so it is only clutter in the branch store.
|
|
31
|
+
*/
|
|
32
|
+
export interface TakeoverRecordFinding {
|
|
33
|
+
readonly kind: "takeover-record";
|
|
34
|
+
readonly storePath: string;
|
|
35
|
+
readonly recordPath: string;
|
|
36
|
+
/** When the takeover happened (the file's mtime for an unreadable record). */
|
|
37
|
+
readonly at: string;
|
|
38
|
+
readonly brokenPid?: number;
|
|
39
|
+
readonly action: "clean";
|
|
40
|
+
}
|
|
41
|
+
export type JanitorFinding = StoreLockFinding | SocketFinding | TakeoverRecordFinding;
|
|
29
42
|
export interface JanitorOptions {
|
|
30
43
|
/** Branch stores live under <workspaceRoot>/.kb/branches. */
|
|
31
44
|
readonly workspaceRoot: string;
|
|
@@ -35,16 +48,27 @@ export interface JanitorOptions {
|
|
|
35
48
|
readonly all?: boolean;
|
|
36
49
|
/** Execute cleanups; when false the scan only reports (dry run). */
|
|
37
50
|
readonly apply?: boolean;
|
|
51
|
+
/** Clock for the takeover-record age; defaults to the current time. */
|
|
52
|
+
readonly now?: Date;
|
|
38
53
|
}
|
|
39
54
|
/** Scan one branch store's ownership journal and clean stale artifacts. */
|
|
40
55
|
export declare function sweepStoreLock(storePath: string, apply: boolean): StoreLockFinding | null;
|
|
41
56
|
/** Scan all branch stores under <workspaceRoot>/.kb/branches. */
|
|
42
57
|
export declare function sweepWorkspaceStoreLocks(options: JanitorOptions): StoreLockFinding[];
|
|
58
|
+
/**
|
|
59
|
+
* Report, and with apply delete, the stale-lock takeover records under
|
|
60
|
+
* <workspaceRoot>/.kb/branches that are older than the window kb_status
|
|
61
|
+
* shows them for. Fresh records are kept and not reported.
|
|
62
|
+
*/
|
|
63
|
+
export declare function sweepStoreLockTakeoverRecords(options: JanitorOptions): TakeoverRecordFinding[];
|
|
43
64
|
/**
|
|
44
65
|
* Sweep runtime-directory daemon sockets. A socket is stale when its pid
|
|
45
66
|
* file records a dead process or a connect attempt is refused.
|
|
46
67
|
*/
|
|
47
68
|
export declare function sweepRuntimeSockets(options: JanitorOptions): SocketFinding[];
|
|
48
|
-
/**
|
|
69
|
+
/**
|
|
70
|
+
* Full janitor sweep across branch stores, expired takeover records and
|
|
71
|
+
* (optionally) runtime sockets.
|
|
72
|
+
*/
|
|
49
73
|
export declare function runJanitor(options: JanitorOptions): JanitorFinding[];
|
|
50
74
|
//# sourceMappingURL=janitor.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"janitor.d.ts","sourceRoot":"","sources":["../../src/prolog/janitor.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"janitor.d.ts","sourceRoot":"","sources":["../../src/prolog/janitor.ts"],"names":[],"mappings":"AA0BA,OAAO,EAGL,KAAK,oBAAoB,EAM1B,MAAM,iBAAiB,CAAC;AAEzB;;;;;;;;GAQG;AAGH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,WAAW,EAAE,oBAAoB,CAAC;IAC3C,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC;IAClC,QAAQ,CAAC,MAAM,EAAE,OAAO,GAAG,gBAAgB,GAAG,MAAM,CAAC;CACtD;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,EAAE,oBAAoB,CAAC;IAC3C,QAAQ,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,CAAC;CACnC;AAED;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC;IACjC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,MAAM,cAAc,GACtB,gBAAgB,GAChB,aAAa,GACb,qBAAqB,CAAC;AAE1B,MAAM,WAAW,cAAc;IAC7B,6DAA6D;IAC7D,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,8DAA8D;IAC9D,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,kEAAkE;IAClE,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC;IACvB,oEAAoE;IACpE,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB,uEAAuE;IACvE,QAAQ,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC;CACrB;AAED,2EAA2E;AAE3E,wBAAgB,cAAc,CAC5B,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,OAAO,GACb,gBAAgB,GAAG,IAAI,CA+CzB;AAED,iEAAiE;AAEjE,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,cAAc,GACtB,gBAAgB,EAAE,CAepB;AAED;;;;GAIG;AAEH,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,cAAc,GACtB,qBAAqB,EAAE,CAmCzB;AAED;;;GAGG;AAEH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,cAAc,GAAG,aAAa,EAAE,CA8C5E;AAED;;;GAGG;AAEH,wBAAgB,UAAU,CAAC,OAAO,EAAE,cAAc,GAAG,cAAc,EAAE,CAMpE"}
|
package/dist/prolog/janitor.js
CHANGED
|
@@ -15,9 +15,9 @@
|
|
|
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 { existsSync, readFileSync, readdirSync, rmSync } from "node:fs";
|
|
18
|
+
import { existsSync, readFileSync, readdirSync, rmSync, statSync, } from "node:fs";
|
|
19
19
|
import { join } from "node:path";
|
|
20
|
-
import { breakStoreLock, classifyStoreLockHolder, isProcessAlive, readStoreLockOwner, } from "./store-lock.js";
|
|
20
|
+
import { STORE_LOCK_TAKEOVER_FILE, STORE_LOCK_TAKEOVER_VISIBLE_MS, breakStoreLock, classifyStoreLockHolder, isProcessAlive, readStoreLockOwner, readStoreLockTakeover, } from "./store-lock.js";
|
|
21
21
|
/** Scan one branch store's ownership journal and clean stale artifacts. */
|
|
22
22
|
// implements REQ-core-journaled-engine-persistence
|
|
23
23
|
export function sweepStoreLock(storePath, apply) {
|
|
@@ -90,6 +90,54 @@ export function sweepWorkspaceStoreLocks(options) {
|
|
|
90
90
|
}
|
|
91
91
|
return findings;
|
|
92
92
|
}
|
|
93
|
+
/**
|
|
94
|
+
* Report, and with apply delete, the stale-lock takeover records under
|
|
95
|
+
* <workspaceRoot>/.kb/branches that are older than the window kb_status
|
|
96
|
+
* shows them for. Fresh records are kept and not reported.
|
|
97
|
+
*/
|
|
98
|
+
// implements REQ-core-journaled-engine-persistence
|
|
99
|
+
export function sweepStoreLockTakeoverRecords(options) {
|
|
100
|
+
const branchesDir = join(options.workspaceRoot, ".kb", "branches");
|
|
101
|
+
if (!existsSync(branchesDir))
|
|
102
|
+
return [];
|
|
103
|
+
const now = (options.now ?? new Date()).getTime();
|
|
104
|
+
const findings = [];
|
|
105
|
+
for (const entry of readdirSync(branchesDir)) {
|
|
106
|
+
const storePath = join(branchesDir, entry);
|
|
107
|
+
const recordPath = join(storePath, STORE_LOCK_TAKEOVER_FILE);
|
|
108
|
+
let at;
|
|
109
|
+
let brokenPid = null;
|
|
110
|
+
try {
|
|
111
|
+
const record = readStoreLockTakeover(storePath);
|
|
112
|
+
if (record !== null) {
|
|
113
|
+
at = record.at;
|
|
114
|
+
brokenPid = record.brokenPid;
|
|
115
|
+
}
|
|
116
|
+
else if (existsSync(recordPath)) {
|
|
117
|
+
at = statSync(recordPath).mtime.toISOString();
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
if (now - Date.parse(at) <= STORE_LOCK_TAKEOVER_VISIBLE_MS)
|
|
127
|
+
continue;
|
|
128
|
+
if (options.apply === true)
|
|
129
|
+
rmSync(recordPath, { force: true });
|
|
130
|
+
findings.push({
|
|
131
|
+
kind: "takeover-record",
|
|
132
|
+
storePath,
|
|
133
|
+
recordPath,
|
|
134
|
+
at,
|
|
135
|
+
...(brokenPid !== null ? { brokenPid } : {}),
|
|
136
|
+
action: "clean",
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
return findings;
|
|
140
|
+
}
|
|
93
141
|
/**
|
|
94
142
|
* Sweep runtime-directory daemon sockets. A socket is stale when its pid
|
|
95
143
|
* file records a dead process or a connect attempt is refused.
|
|
@@ -144,11 +192,15 @@ export function sweepRuntimeSockets(options) {
|
|
|
144
192
|
}
|
|
145
193
|
return findings;
|
|
146
194
|
}
|
|
147
|
-
/**
|
|
195
|
+
/**
|
|
196
|
+
* Full janitor sweep across branch stores, expired takeover records and
|
|
197
|
+
* (optionally) runtime sockets.
|
|
198
|
+
*/
|
|
148
199
|
// implements REQ-core-journaled-engine-persistence
|
|
149
200
|
export function runJanitor(options) {
|
|
150
201
|
return [
|
|
151
202
|
...sweepWorkspaceStoreLocks(options),
|
|
203
|
+
...sweepStoreLockTakeoverRecords(options),
|
|
152
204
|
...sweepRuntimeSockets(options),
|
|
153
205
|
];
|
|
154
206
|
}
|
|
@@ -66,12 +66,37 @@ export interface StoreLockTakeoverDecision {
|
|
|
66
66
|
readonly action: "break" | "surface";
|
|
67
67
|
readonly reason: string;
|
|
68
68
|
}
|
|
69
|
+
/** Reason prefix of a takeover that removed lock artifacts copied in. */
|
|
70
|
+
export declare const FOREIGN_STORE_LOCK_REASON_PREFIX = "journal belongs to another workspace";
|
|
71
|
+
/**
|
|
72
|
+
* The recorded root of an ownership journal that another workspace wrote,
|
|
73
|
+
* or null when the journal belongs to this store (or cannot be judged).
|
|
74
|
+
*
|
|
75
|
+
* kb.pl records the attached store directory as `workspaceRoot`; a journal
|
|
76
|
+
* may also name a workspace root. Either way it is foreign only when the
|
|
77
|
+
* workspace it names differs from the one that owns `storePath`, which
|
|
78
|
+
* happens when a `.kb` was copied (`cp -a`, a backup restore) while another
|
|
79
|
+
* workspace's engine held its store. An advisory lock is never inherited by
|
|
80
|
+
* a copied file, so nobody holds this store on the journal's behalf.
|
|
81
|
+
*
|
|
82
|
+
* The journal is judged only when that is safe: when the store's `rdf/lock`
|
|
83
|
+
* names a different pid than the journal, a process of this workspace has
|
|
84
|
+
* locked the store since the copy; when the recorded path no longer exists,
|
|
85
|
+
* the store may have been moved here while its holder still runs; and a
|
|
86
|
+
* recorded path that is this very directory (a bind mount) is not another
|
|
87
|
+
* workspace. Each of those returns null.
|
|
88
|
+
*/
|
|
89
|
+
export declare function foreignStoreLockJournalRoot(owner: PrologStoreLockOwner | null, storePath: string): string | null;
|
|
69
90
|
/**
|
|
70
91
|
* Decide whether a store-locked failure may be auto-healed. Only a provably
|
|
71
|
-
* dead holder (or a holder from a previous boot) is broken
|
|
72
|
-
*
|
|
92
|
+
* dead holder (or a holder from a previous boot) is broken, and, when the
|
|
93
|
+
* caller names the store being attached, a journal copied in from another
|
|
94
|
+
* workspace; live or unknown holders are surfaced so the operator can close
|
|
95
|
+
* the real session.
|
|
73
96
|
*/
|
|
74
|
-
export declare function decideStoreLockTakeover(owner: PrologStoreLockOwner | null
|
|
97
|
+
export declare function decideStoreLockTakeover(owner: PrologStoreLockOwner | null, options?: {
|
|
98
|
+
readonly storePath?: string;
|
|
99
|
+
}): StoreLockTakeoverDecision;
|
|
75
100
|
export interface StoreLockRetryContext {
|
|
76
101
|
readonly query: (goal: string) => Promise<QueryResult>;
|
|
77
102
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store-lock.d.ts","sourceRoot":"","sources":["../../src/prolog/store-lock.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"store-lock.d.ts","sourceRoot":"","sources":["../../src/prolog/store-lock.ts"],"names":[],"mappings":"AA2BA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,OAAO,KAAK,EAAqB,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAgBhF,8EAA8E;AAC9E,wBAAgB,aAAa,IAAI,MAAM,GAAG,IAAI,CAa7C;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAUnD;AAED,MAAM,MAAM,oBAAoB,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;AAEzE,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,oBAAoB,GAAG,IAAI,GACjC,oBAAoB,CAYtB;AAED;;;;;GAKG;AAEH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,MAAM,GAChB;IAAE,KAAK,EAAE,oBAAoB,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CA4B7D;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAWzD;AAED,qEAAqE;AACrE,eAAO,MAAM,wBAAwB,6BAA6B,CAAC;AAEnE;;;;;GAKG;AACH,eAAO,MAAM,8BAA8B,QAAsB,CAAC;AAElE,MAAM,MAAM,uBAAuB,GAAG,QAAQ,CAAC;IAC7C,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;CACd,CAAC,CAAC;AAEH;;;GAGG;AAEH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,MAAM,EAAE,MAAM,EACd,EAAE,GAAE,IAAiB,GACpB,IAAI,CAUN;AAED,iFAAiF;AAEjF,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,MAAM,GAChB,uBAAuB,GAAG,IAAI,CAmBhC;AAED,sEAAsE;AAEtE,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQ9D;AAED;;;;;;;;;;;;;;;GAeG;AAEH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,IAAI,CAerE;AAED,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,MAAM,EAAE,OAAO,GAAG,SAAS,CAAC;IACrC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,yEAAyE;AACzE,eAAO,MAAM,gCAAgC,yCACL,CAAC;AAoCzC;;;;;;;;;;;;;;;;;GAiBG;AAEH,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,oBAAoB,GAAG,IAAI,EAClC,SAAS,EAAE,MAAM,GAChB,MAAM,GAAG,IAAI,CAcf;AAED;;;;;;GAMG;AAEH,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,oBAAoB,GAAG,IAAI,EAClC,OAAO,GAAE;IAAE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GAC5C,yBAAyB,CA+B3B;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;CACxD;AAED;;;;;;GAMG;AAEH,wBAAsB,iCAAiC,CACrD,MAAM,EAAE,qBAAqB,EAC7B,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,WAAW,CAAC,CAmCtB"}
|
|
@@ -15,9 +15,9 @@
|
|
|
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 { existsSync, rmSync, writeFileSync } from "node:fs";
|
|
18
|
+
import { existsSync, realpathSync, rmSync, statSync, writeFileSync, } from "node:fs";
|
|
19
19
|
import { readFileSync } from "node:fs";
|
|
20
|
-
import { dirname, join } from "node:path";
|
|
20
|
+
import { basename, dirname, join } from "node:path";
|
|
21
21
|
import { escapeAtom } from "./codec.js";
|
|
22
22
|
/**
|
|
23
23
|
* Stewardship for the branch-store lock.
|
|
@@ -216,25 +216,114 @@ export function noteDeadHolderBeforeAttach(kbPath) {
|
|
|
216
216
|
: lockPid !== null
|
|
217
217
|
? { pid: lockPid }
|
|
218
218
|
: null;
|
|
219
|
-
const decision = decideStoreLockTakeover(owner);
|
|
219
|
+
const decision = decideStoreLockTakeover(owner, { storePath: kbPath });
|
|
220
220
|
if (decision.action !== "break")
|
|
221
221
|
return () => undefined;
|
|
222
222
|
const brokenPid = owner?.pid ?? null;
|
|
223
223
|
return () => recordStoreLockTakeover(kbPath, brokenPid, decision.reason);
|
|
224
224
|
}
|
|
225
|
+
/** Reason prefix of a takeover that removed lock artifacts copied in. */
|
|
226
|
+
export const FOREIGN_STORE_LOCK_REASON_PREFIX = "journal belongs to another workspace";
|
|
227
|
+
function existingRealPath(pathname) {
|
|
228
|
+
try {
|
|
229
|
+
return realpathSync(pathname);
|
|
230
|
+
}
|
|
231
|
+
catch {
|
|
232
|
+
return null;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
function sameDirectory(left, right) {
|
|
236
|
+
try {
|
|
237
|
+
const a = statSync(left);
|
|
238
|
+
const b = statSync(right);
|
|
239
|
+
return a.dev === b.dev && a.ino === b.ino;
|
|
240
|
+
}
|
|
241
|
+
catch {
|
|
242
|
+
return false;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* The workspace that owns a branch store: `<root>/.kb/branches/<key>` (a
|
|
247
|
+
* legacy key may span several segments) is owned by `<root>`. Null for a
|
|
248
|
+
* path outside that layout.
|
|
249
|
+
*/
|
|
250
|
+
function owningWorkspaceRoot(storePath) {
|
|
251
|
+
let current = storePath;
|
|
252
|
+
for (;;) {
|
|
253
|
+
const parent = dirname(current);
|
|
254
|
+
if (parent === current)
|
|
255
|
+
return null;
|
|
256
|
+
if (basename(parent) === "branches" && basename(dirname(parent)) === ".kb")
|
|
257
|
+
return dirname(dirname(parent));
|
|
258
|
+
current = parent;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* The recorded root of an ownership journal that another workspace wrote,
|
|
263
|
+
* or null when the journal belongs to this store (or cannot be judged).
|
|
264
|
+
*
|
|
265
|
+
* kb.pl records the attached store directory as `workspaceRoot`; a journal
|
|
266
|
+
* may also name a workspace root. Either way it is foreign only when the
|
|
267
|
+
* workspace it names differs from the one that owns `storePath`, which
|
|
268
|
+
* happens when a `.kb` was copied (`cp -a`, a backup restore) while another
|
|
269
|
+
* workspace's engine held its store. An advisory lock is never inherited by
|
|
270
|
+
* a copied file, so nobody holds this store on the journal's behalf.
|
|
271
|
+
*
|
|
272
|
+
* The journal is judged only when that is safe: when the store's `rdf/lock`
|
|
273
|
+
* names a different pid than the journal, a process of this workspace has
|
|
274
|
+
* locked the store since the copy; when the recorded path no longer exists,
|
|
275
|
+
* the store may have been moved here while its holder still runs; and a
|
|
276
|
+
* recorded path that is this very directory (a bind mount) is not another
|
|
277
|
+
* workspace. Each of those returns null.
|
|
278
|
+
*/
|
|
279
|
+
// implements REQ-core-journaled-engine-persistence
|
|
280
|
+
export function foreignStoreLockJournalRoot(owner, storePath) {
|
|
281
|
+
const recorded = owner?.workspaceRoot;
|
|
282
|
+
if (recorded === undefined || recorded === "")
|
|
283
|
+
return null;
|
|
284
|
+
const store = existingRealPath(storePath);
|
|
285
|
+
if (store === null)
|
|
286
|
+
return null;
|
|
287
|
+
const ownWorkspace = owningWorkspaceRoot(store);
|
|
288
|
+
if (ownWorkspace === null)
|
|
289
|
+
return null;
|
|
290
|
+
const lockPid = readRdfLockPid(join(storePath, "rdf", "lock"));
|
|
291
|
+
if (lockPid !== null && lockPid !== owner?.pid)
|
|
292
|
+
return null;
|
|
293
|
+
const recordedPath = existingRealPath(recorded);
|
|
294
|
+
if (recordedPath === null || recordedPath === store)
|
|
295
|
+
return null;
|
|
296
|
+
if (sameDirectory(recordedPath, store))
|
|
297
|
+
return null;
|
|
298
|
+
const recordedWorkspace = owningWorkspaceRoot(recordedPath) ?? recordedPath;
|
|
299
|
+
return recordedWorkspace === ownWorkspace ? null : recorded;
|
|
300
|
+
}
|
|
225
301
|
/**
|
|
226
302
|
* Decide whether a store-locked failure may be auto-healed. Only a provably
|
|
227
|
-
* dead holder (or a holder from a previous boot) is broken
|
|
228
|
-
*
|
|
303
|
+
* dead holder (or a holder from a previous boot) is broken, and, when the
|
|
304
|
+
* caller names the store being attached, a journal copied in from another
|
|
305
|
+
* workspace; live or unknown holders are surfaced so the operator can close
|
|
306
|
+
* the real session.
|
|
229
307
|
*/
|
|
230
|
-
|
|
308
|
+
// implements REQ-core-journaled-engine-persistence
|
|
309
|
+
export function decideStoreLockTakeover(owner, options = {}) {
|
|
231
310
|
const state = classifyStoreLockHolder(owner);
|
|
311
|
+
if (state === "dead") {
|
|
312
|
+
return {
|
|
313
|
+
action: "break",
|
|
314
|
+
reason: `recorded holder pid ${owner?.pid ?? "?"} is no longer running`,
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
const foreignRoot = options.storePath === undefined
|
|
318
|
+
? null
|
|
319
|
+
: foreignStoreLockJournalRoot(owner, options.storePath);
|
|
320
|
+
if (foreignRoot !== null) {
|
|
321
|
+
return {
|
|
322
|
+
action: "break",
|
|
323
|
+
reason: `${FOREIGN_STORE_LOCK_REASON_PREFIX} ${foreignRoot}`,
|
|
324
|
+
};
|
|
325
|
+
}
|
|
232
326
|
switch (state) {
|
|
233
|
-
case "dead":
|
|
234
|
-
return {
|
|
235
|
-
action: "break",
|
|
236
|
-
reason: `recorded holder pid ${owner?.pid ?? "?"} is no longer running`,
|
|
237
|
-
};
|
|
238
327
|
case "unknown":
|
|
239
328
|
return {
|
|
240
329
|
action: "surface",
|
|
@@ -261,7 +350,9 @@ export async function retryAttachAfterBreakingStaleLock(prolog, kbPath, failed)
|
|
|
261
350
|
const storeLocked = record?.storeLocked;
|
|
262
351
|
if (storeLocked === undefined)
|
|
263
352
|
return failed;
|
|
264
|
-
const decision = decideStoreLockTakeover(storeLocked.owner
|
|
353
|
+
const decision = decideStoreLockTakeover(storeLocked.owner, {
|
|
354
|
+
storePath: kbPath,
|
|
355
|
+
});
|
|
265
356
|
if (decision.action !== "break") {
|
|
266
357
|
const holderSummary = storeLocked.owner === null
|
|
267
358
|
? decision.reason
|
|
@@ -190,8 +190,8 @@ export declare const OPERATION_CATALOG: readonly [{
|
|
|
190
190
|
readonly limit: {
|
|
191
191
|
readonly type: "integer";
|
|
192
192
|
readonly minimum: 0;
|
|
193
|
-
readonly default:
|
|
194
|
-
readonly description: "Optional max rows to return after ranking. Default:
|
|
193
|
+
readonly default: 10;
|
|
194
|
+
readonly description: "Optional max rows to return after ranking. Default: 10; raise it or page with offset when the answer layer is not enough.";
|
|
195
195
|
};
|
|
196
196
|
readonly offset: {
|
|
197
197
|
readonly type: "integer";
|
|
@@ -718,7 +718,7 @@ export declare const OPERATION_CATALOG: readonly [{
|
|
|
718
718
|
}, {
|
|
719
719
|
readonly name: "kb_model";
|
|
720
720
|
readonly cliName: "model";
|
|
721
|
-
readonly description: "Turn requirement prose into checkable structure without writing the KB. mode:analyze returns the semantic advisor receipt: the clause ledger, what is grounded, what is ambiguous and suggested modeling (pass clauses for compound prose and optional typed kibi.logic.v1 interpretations). mode:requirement converts one claim (subjectKey, propertyKey, operator, value, or typed logic) into a strict-lane write set and applyPlan. mode:predicates ranks ontology predicate schemas and returns an applicable predicate-fact plan only for reviewed bindings, otherwise an ontology-gap observation.
|
|
721
|
+
readonly description: "Turn requirement prose into checkable structure without writing the KB. mode:analyze returns the semantic advisor receipt: the clause ledger, what is grounded, what is ambiguous and suggested modeling (pass clauses for compound prose and optional typed kibi.logic.v1 interpretations). mode:requirement converts one claim (subjectKey, propertyKey, operator, value, or typed logic) into a strict-lane write set and applyPlan. mode:predicates ranks ontology predicate schemas and returns an applicable predicate-fact plan only for reviewed bindings, otherwise an ontology-gap observation. With requirementId, mode:predicates also returns a hash-bound plan (fact write plus requires_predicate link) for kb_apply_plan, whose contradictionAnalysis is the what-if over the current KB; other returned plans apply with kb_upsert, and kb_upsert dryRun with plannedFacts previews a requirement before its facts exist.";
|
|
722
722
|
readonly businessInputSchema: {
|
|
723
723
|
readonly type: "object";
|
|
724
724
|
readonly required: readonly ["mode", "text"];
|
|
@@ -1521,11 +1521,11 @@ export declare const OPERATION_CATALOG: readonly [{
|
|
|
1521
1521
|
readonly claim_key: {
|
|
1522
1522
|
readonly type: "string";
|
|
1523
1523
|
readonly pattern: "^CLAIM-[A-F0-9]{16}$";
|
|
1524
|
-
readonly description: "Stable
|
|
1524
|
+
readonly description: "Stable key of the atomic prose clause grounded by this fact, derived from claim_text. Optional: when omitted, Kibi derives it; when sent, it must equal the derived key.";
|
|
1525
1525
|
};
|
|
1526
1526
|
readonly claim_text: {
|
|
1527
1527
|
readonly type: "string";
|
|
1528
|
-
readonly description: "Exact atomic requirement clause represented by this fact, retained for human audit.
|
|
1528
|
+
readonly description: "Exact atomic requirement clause represented by this fact, retained for human audit. On a grounding fact Kibi derives claim_key from it; an observation or meta fact quotes the clause it is about without a key.";
|
|
1529
1529
|
};
|
|
1530
1530
|
readonly predicate_name: {
|
|
1531
1531
|
readonly type: "string";
|
|
@@ -1689,6 +1689,50 @@ export declare const OPERATION_CATALOG: readonly [{
|
|
|
1689
1689
|
readonly default: false;
|
|
1690
1690
|
readonly description: "Validate the payload and return schema/modeling errors, a normalized preview and the semantic advisor receipt without writing the KB or workspace. Use it as the preflight before the real write.";
|
|
1691
1691
|
};
|
|
1692
|
+
readonly plannedFacts: {
|
|
1693
|
+
readonly type: "array";
|
|
1694
|
+
readonly description: "dryRun only. Fact upsert payloads (type, id, properties, optional relationships) that will be written before this payload, typically the applyPlan entries kb_model returned. They are validated in order and staged with the payload, so a requires_predicate or requires_property target that does not exist yet resolves, its claim_key is read from the plan, and the contradiction preview runs against the KB as it would be after the whole batch (result: stagedFacts, whatIf). A conflict the batch would introduce, such as an allow and a deny permission_rule on the same key, is refused as the commit would refuse it. Rejected without dryRun: write the facts first.";
|
|
1695
|
+
readonly items: {
|
|
1696
|
+
readonly type: "object";
|
|
1697
|
+
readonly required: readonly ["type", "id", "properties"];
|
|
1698
|
+
readonly properties: {
|
|
1699
|
+
readonly type: {
|
|
1700
|
+
readonly type: "string";
|
|
1701
|
+
readonly const: "fact";
|
|
1702
|
+
};
|
|
1703
|
+
readonly id: {
|
|
1704
|
+
readonly type: "string";
|
|
1705
|
+
readonly minLength: 1;
|
|
1706
|
+
};
|
|
1707
|
+
readonly properties: {
|
|
1708
|
+
readonly type: "object";
|
|
1709
|
+
};
|
|
1710
|
+
readonly relationships: {
|
|
1711
|
+
readonly type: "array";
|
|
1712
|
+
readonly description: "Optional relationship rows to create in the same call. For requirement encoding, prefer `constrains` + `requires_property` for strict property facts or `requires_predicate` for ontology predicate facts. Side effect: asserts edges in KB.";
|
|
1713
|
+
readonly items: {
|
|
1714
|
+
readonly type: "object";
|
|
1715
|
+
readonly required: readonly ["type", "from", "to"];
|
|
1716
|
+
readonly properties: {
|
|
1717
|
+
readonly type: {
|
|
1718
|
+
readonly type: "string";
|
|
1719
|
+
readonly enum: readonly ["depends_on", "specified_by", "verified_by", "validates", "implements", "covered_by", "executable_for", "constrained_by", "constrains", "requires_property", "requires_predicate", "requires_rule", "guards", "publishes", "consumes", "supersedes", "restates", "assumes", "exempts", "relates_to"];
|
|
1720
|
+
readonly description: "Relationship type enum. Use only supported values. Direction semantics follow KB model (e.g., implements symbol->req, verified_by req/scenario->test, executable_for symbol->test).";
|
|
1721
|
+
};
|
|
1722
|
+
readonly from: {
|
|
1723
|
+
readonly type: "string";
|
|
1724
|
+
readonly description: "Source entity ID (must exist). Example: 'SYM-login-handler'.";
|
|
1725
|
+
};
|
|
1726
|
+
readonly to: {
|
|
1727
|
+
readonly type: "string";
|
|
1728
|
+
readonly description: "Target entity ID (must exist). Example: 'REQ-cli-gc'.";
|
|
1729
|
+
};
|
|
1730
|
+
};
|
|
1731
|
+
};
|
|
1732
|
+
};
|
|
1733
|
+
};
|
|
1734
|
+
};
|
|
1735
|
+
};
|
|
1692
1736
|
readonly document: {
|
|
1693
1737
|
readonly type: "object";
|
|
1694
1738
|
readonly additionalProperties: false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../../../src/public/operations/catalog.ts"],"names":[],"mappings":"AA6BA,OAAO,KAAK,EACV,aAAa,EACb,aAAa,EACb,qBAAqB,EACtB,MAAM,YAAY,CAAC;AAEpB,eAAO,MAAM,iBAAiB
|
|
1
|
+
{"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../../../src/public/operations/catalog.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Violation } from "../check-types.js";
|
|
2
|
-
import { type CheckDiagnostic, type CheckStructuredContent, buildStructuredContent, buildSummary } from "./check-format-shared.js";
|
|
2
|
+
import { type CheckDiagnostic, type CheckEvaluated, type CheckStructuredContent, buildStructuredContent, buildSummary } from "./check-format-shared.js";
|
|
3
3
|
import { getEffectiveRules, resolveCheckRules } from "./check-helpers.js";
|
|
4
4
|
import type { OperationContext } from "./runtime-types.js";
|
|
5
5
|
import type { OperationResult } from "./types.js";
|
|
@@ -13,7 +13,7 @@ export type CheckInput = {
|
|
|
13
13
|
readonly maxDiagnostics?: number;
|
|
14
14
|
};
|
|
15
15
|
export type CheckPayload = CheckStructuredContent;
|
|
16
|
-
export type { CheckDiagnostic, CheckStructuredContent };
|
|
16
|
+
export type { CheckDiagnostic, CheckEvaluated, CheckStructuredContent };
|
|
17
17
|
export { buildStructuredContent, buildSummary, getEffectiveRules, resolveCheckRules, };
|
|
18
18
|
export type CheckExecutionOptions = {
|
|
19
19
|
readonly collectFullQualityDiagnosticsForExplicitRules?: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"check-executor.d.ts","sourceRoot":"","sources":["../../../src/public/operations/check-executor.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAEnD,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,sBAAsB,EAC3B,sBAAsB,EACtB,YAAY,EACb,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAGL,iBAAiB,EAGjB,iBAAiB,EAElB,MAAM,oBAAoB,CAAC;AAW5B,OAAO,KAAK,EAAE,gBAAgB,EAAc,MAAM,oBAAoB,CAAC;AAMvE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAIlD,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,sBAAsB,CAAC,EAAE,OAAO,CAAC;IAC1C,QAAQ,CAAC,wBAAwB,CAAC,EAAE,OAAO,CAAC;IAC5C,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;CAClC,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,sBAAsB,CAAC;AAClD,YAAY,EAAE,eAAe,EAAE,sBAAsB,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"check-executor.d.ts","sourceRoot":"","sources":["../../../src/public/operations/check-executor.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAEnD,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,sBAAsB,EAC3B,sBAAsB,EACtB,YAAY,EACb,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAGL,iBAAiB,EAGjB,iBAAiB,EAElB,MAAM,oBAAoB,CAAC;AAW5B,OAAO,KAAK,EAAE,gBAAgB,EAAc,MAAM,oBAAoB,CAAC;AAMvE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAIlD,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,sBAAsB,CAAC,EAAE,OAAO,CAAC;IAC1C,QAAQ,CAAC,wBAAwB,CAAC,EAAE,OAAO,CAAC;IAC5C,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;CAClC,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,sBAAsB,CAAC;AAClD,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,sBAAsB,EAAE,CAAC;AACxE,OAAO,EACL,sBAAsB,EACtB,YAAY,EACZ,iBAAiB,EACjB,iBAAiB,GAClB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,QAAQ,CAAC,6CAA6C,CAAC,EAAE,OAAO,CAAC;IACjE;;;;;;OAMG;IACH,QAAQ,CAAC,mBAAmB,CAAC,EAAE,OAAO,CAAC;CACxC,CAAC;AAoFF;;;;;GAKG;AAEH,wBAAgB,8BAA8B,CAC5C,OAAO,EAAE,gBAAgB,EACzB,aAAa,EAAE,MAAM,GACpB,SAAS,GAAG,IAAI,CAgClB;AAGD,wBAAsB,YAAY,CAChC,IAAI,EAAE,UAAU,EAChB,OAAO,EAAE,gBAAgB,EACzB,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC,CA0OxC"}
|
|
@@ -14,6 +14,31 @@ import { SOURCE_PATH_DANGLING_RULE, collectSourcePathDanglingViolations, } from
|
|
|
14
14
|
import { collectSourceRelationshipParityViolations } from "./source-relationship-parity.js";
|
|
15
15
|
import { readWorkspaceSnapshot } from "./workspace-snapshot.js";
|
|
16
16
|
export { buildStructuredContent, buildSummary, getEffectiveRules, resolveCheckRules, };
|
|
17
|
+
// implements REQ-search-answer-hygiene
|
|
18
|
+
/**
|
|
19
|
+
* What this run evaluated: the rules that ran, in registry order, and for
|
|
20
|
+
* `domain-contradictions` the number of requirement fact pairs the rule
|
|
21
|
+
* compared, read from the engine after the rules ran on the same store. A
|
|
22
|
+
* count the engine cannot give (an older engine) is left out rather than
|
|
23
|
+
* reported as zero.
|
|
24
|
+
*/
|
|
25
|
+
async function describeEvaluation(prolog, rules) {
|
|
26
|
+
const evaluated = {
|
|
27
|
+
rules: [...rules],
|
|
28
|
+
};
|
|
29
|
+
if (!rules.has("domain-contradictions"))
|
|
30
|
+
return evaluated;
|
|
31
|
+
try {
|
|
32
|
+
const result = await prolog.query("kb_domain_contradiction_pairs_examined(Count)");
|
|
33
|
+
const count = Number(result.bindings.Count);
|
|
34
|
+
if (result.success && Number.isInteger(count) && count >= 0)
|
|
35
|
+
evaluated.domainContradictions = { factPairsExamined: count };
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
// An engine without the predicate leaves the count out.
|
|
39
|
+
}
|
|
40
|
+
return evaluated;
|
|
41
|
+
}
|
|
17
42
|
function requireProlog(context) {
|
|
18
43
|
if (context.prolog === undefined) {
|
|
19
44
|
throw new Error("Check operation requires a Prolog runtime");
|
|
@@ -121,12 +146,15 @@ export async function executeCheck(args, context, options = {}) {
|
|
|
121
146
|
const violations = [uncompiled];
|
|
122
147
|
const statusPlan = await readStatusMigrationPlan(context);
|
|
123
148
|
const migrationPlan = await migrationPlanForCheck(context, violations, [], statusPlan);
|
|
149
|
+
// Every store-backed rule was skipped: only this one was evaluated.
|
|
150
|
+
const evaluated = { rules: [BRANCH_STORE_NOT_COMPILED_RULE] };
|
|
124
151
|
return {
|
|
125
152
|
content: [
|
|
126
153
|
{
|
|
127
154
|
type: "text",
|
|
128
155
|
text: buildSummary({
|
|
129
156
|
violations,
|
|
157
|
+
evaluated,
|
|
130
158
|
impactResult,
|
|
131
159
|
qualityDiagnostics: [],
|
|
132
160
|
}),
|
|
@@ -134,6 +162,7 @@ export async function executeCheck(args, context, options = {}) {
|
|
|
134
162
|
],
|
|
135
163
|
structuredContent: buildStructuredContent({
|
|
136
164
|
violations,
|
|
165
|
+
evaluated,
|
|
137
166
|
diagnostics: [
|
|
138
167
|
{
|
|
139
168
|
category: "SYNC_ERROR",
|
|
@@ -169,12 +198,14 @@ export async function executeCheck(args, context, options = {}) {
|
|
|
169
198
|
});
|
|
170
199
|
const statusPlan = await readStatusMigrationPlan(context);
|
|
171
200
|
const migrationPlan = await migrationPlanForCheck(context, [], qualityDiagnostics, statusPlan);
|
|
201
|
+
const evaluated = { rules: [] };
|
|
172
202
|
return {
|
|
173
203
|
content: [
|
|
174
204
|
{
|
|
175
205
|
type: "text",
|
|
176
206
|
text: buildSummary({
|
|
177
207
|
violations: [],
|
|
208
|
+
evaluated,
|
|
178
209
|
impactResult,
|
|
179
210
|
qualityDiagnostics,
|
|
180
211
|
}),
|
|
@@ -182,6 +213,7 @@ export async function executeCheck(args, context, options = {}) {
|
|
|
182
213
|
],
|
|
183
214
|
structuredContent: buildStructuredContent({
|
|
184
215
|
violations: [],
|
|
216
|
+
evaluated,
|
|
185
217
|
diagnostics: [],
|
|
186
218
|
qualityDiagnostics,
|
|
187
219
|
impactResult,
|
|
@@ -217,6 +249,7 @@ export async function executeCheck(args, context, options = {}) {
|
|
|
217
249
|
...checkPolicyFindings,
|
|
218
250
|
]);
|
|
219
251
|
const violations = partitioned.violations;
|
|
252
|
+
const evaluated = await describeEvaluation(prolog, rulesAllowlist);
|
|
220
253
|
const diagnostics = violations.map((v) => ({
|
|
221
254
|
category: "SYNC_ERROR",
|
|
222
255
|
severity: "error",
|
|
@@ -251,6 +284,7 @@ export async function executeCheck(args, context, options = {}) {
|
|
|
251
284
|
type: "text",
|
|
252
285
|
text: buildSummary({
|
|
253
286
|
violations,
|
|
287
|
+
evaluated,
|
|
254
288
|
impactResult,
|
|
255
289
|
qualityDiagnostics,
|
|
256
290
|
}),
|
|
@@ -258,6 +292,7 @@ export async function executeCheck(args, context, options = {}) {
|
|
|
258
292
|
],
|
|
259
293
|
structuredContent: buildStructuredContent({
|
|
260
294
|
violations,
|
|
295
|
+
evaluated,
|
|
261
296
|
diagnostics,
|
|
262
297
|
qualityDiagnostics,
|
|
263
298
|
impactResult,
|