kibi-cli 2.2.0 → 2.3.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-loader.d.ts.map +1 -1
- package/dist/cli-operation-loader.js +3 -0
- package/dist/cli-operation-metadata.d.ts +4 -0
- package/dist/cli-operation-metadata.d.ts.map +1 -1
- package/dist/cli-operation-metadata.js +5 -0
- package/dist/cli-register-reporting.d.ts.map +1 -1
- package/dist/cli-register-reporting.js +4 -0
- package/dist/commands/check-diff.d.ts +5 -0
- package/dist/commands/check-diff.d.ts.map +1 -0
- package/dist/commands/check-diff.js +62 -0
- package/dist/commands/check-generated.d.ts.map +1 -1
- package/dist/commands/check-generated.js +41 -18
- package/dist/commands/check.d.ts.map +1 -1
- package/dist/commands/check.js +210 -73
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +63 -29
- package/dist/commands/github-init.d.ts.map +1 -1
- package/dist/commands/github-init.js +9 -2
- package/dist/commands/sync/manifest.d.ts.map +1 -1
- package/dist/commands/sync/manifest.js +3 -1
- package/dist/engine.d.ts +15 -1
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +252 -52
- package/dist/extractors/symbols-coordinator.d.ts +7 -0
- package/dist/extractors/symbols-coordinator.d.ts.map +1 -1
- package/dist/extractors/symbols-coordinator.js +75 -39
- package/dist/operations/modeling/predicate-inference-1.js +1 -1
- package/dist/operations/mutation/source-authoring.d.ts.map +1 -1
- package/dist/operations/mutation/source-authoring.js +175 -53
- package/dist/operations/mutation/upsert.d.ts.map +1 -1
- package/dist/operations/mutation/upsert.js +5 -7
- package/dist/operations/planning/apply-plan.d.ts.map +1 -1
- package/dist/operations/planning/apply-plan.js +5 -9
- package/dist/operations/proof/ingest-proof.d.ts.map +1 -1
- package/dist/operations/proof/ingest-proof.js +1 -0
- package/dist/operations/semantic-advisor/analysis-receipt.d.ts.map +1 -1
- package/dist/operations/semantic-advisor/analysis-receipt.js +7 -1
- package/dist/operations/semantic-advisor/analyze-prose.d.ts.map +1 -1
- package/dist/operations/semantic-advisor/analyze-prose.js +26 -4
- package/dist/operations/semantic-advisor/clauses.d.ts +1 -0
- package/dist/operations/semantic-advisor/clauses.d.ts.map +1 -1
- package/dist/operations/semantic-advisor/clauses.js +7 -1
- package/dist/performance-trace.d.ts +17 -0
- package/dist/performance-trace.d.ts.map +1 -0
- package/dist/performance-trace.js +134 -0
- package/dist/plugins/approved-source-analyzers.d.ts +13 -0
- package/dist/plugins/approved-source-analyzers.d.ts.map +1 -0
- package/dist/plugins/approved-source-analyzers.generated.d.ts +71 -0
- package/dist/plugins/approved-source-analyzers.generated.d.ts.map +1 -0
- package/dist/plugins/approved-source-analyzers.generated.js +77 -0
- package/dist/plugins/approved-source-analyzers.js +3 -0
- package/dist/plugins/maintenance-source-analysis.d.ts +14 -0
- package/dist/plugins/maintenance-source-analysis.d.ts.map +1 -0
- package/dist/plugins/maintenance-source-analysis.js +191 -0
- package/dist/plugins/registry.d.ts +2 -1
- package/dist/plugins/registry.d.ts.map +1 -1
- package/dist/plugins/registry.js +6 -1
- package/dist/plugins/source-analysis-service.d.ts +36 -1
- package/dist/plugins/source-analysis-service.d.ts.map +1 -1
- package/dist/plugins/source-analysis-service.js +184 -27
- package/dist/plugins/source-change-analysis.d.ts +15 -0
- package/dist/plugins/source-change-analysis.d.ts.map +1 -0
- package/dist/plugins/source-change-analysis.js +54 -0
- package/dist/plugins/source-classification.d.ts +41 -0
- package/dist/plugins/source-classification.d.ts.map +1 -0
- package/dist/plugins/source-classification.js +490 -0
- package/dist/prolog/swipl-resolver.d.ts +88 -0
- package/dist/prolog/swipl-resolver.d.ts.map +1 -0
- package/dist/prolog/swipl-resolver.js +446 -0
- package/dist/prolog.d.ts +15 -1
- package/dist/prolog.d.ts.map +1 -1
- package/dist/prolog.js +67 -6
- package/dist/public/impact/analyzer.d.ts.map +1 -1
- package/dist/public/impact/analyzer.js +56 -5
- package/dist/public/impact/diagnostics.d.ts.map +1 -1
- package/dist/public/impact/diagnostics.js +3 -1
- package/dist/public/impact/manifest.d.ts.map +1 -1
- package/dist/public/impact/manifest.js +15 -1
- package/dist/public/impact/source-changes.d.ts.map +1 -1
- package/dist/public/impact/source-changes.js +35 -27
- package/dist/public/impact/types.d.ts +2 -0
- package/dist/public/impact/types.d.ts.map +1 -1
- package/dist/public/operations/catalog.d.ts +44 -0
- package/dist/public/operations/catalog.d.ts.map +1 -1
- package/dist/public/operations/catalog.js +2 -0
- package/dist/public/operations/contracts.d.ts.map +1 -1
- package/dist/public/operations/contracts.js +309 -8
- package/dist/public/operations/impact-review-preparation.d.ts +14 -0
- package/dist/public/operations/impact-review-preparation.d.ts.map +1 -0
- package/dist/public/operations/impact-review-preparation.js +379 -0
- package/dist/public/operations/index.d.ts +2 -0
- package/dist/public/operations/index.d.ts.map +1 -1
- package/dist/public/operations/index.js +2 -0
- package/dist/public/operations/node-ports.d.ts.map +1 -1
- package/dist/public/operations/node-ports.js +1 -35
- package/dist/public/operations/proof-receipt-projection.d.ts +5 -0
- package/dist/public/operations/proof-receipt-projection.d.ts.map +1 -0
- package/dist/public/operations/proof-receipt-projection.js +36 -0
- package/dist/public/operations/specs/impact-review-preparation.d.ts +47 -0
- package/dist/public/operations/specs/impact-review-preparation.d.ts.map +1 -0
- package/dist/public/operations/specs/impact-review-preparation.js +43 -0
- package/dist/public/operations/types.d.ts +1 -1
- package/dist/public/operations/types.d.ts.map +1 -1
- package/dist/public/skills/kibi-usage/resources/operation-access.md +1 -0
- package/dist/traceability/analysis-gate.d.ts +39 -0
- package/dist/traceability/analysis-gate.d.ts.map +1 -0
- package/dist/traceability/analysis-gate.js +51 -0
- package/dist/traceability/git-change-snapshot.d.ts +27 -0
- package/dist/traceability/git-change-snapshot.d.ts.map +1 -0
- package/dist/traceability/git-change-snapshot.js +411 -0
- package/dist/traceability/git-staged.d.ts +5 -1
- package/dist/traceability/git-staged.d.ts.map +1 -1
- package/dist/traceability/git-staged.js +16 -11
- package/dist/traceability/impact-evaluator.d.ts +54 -0
- package/dist/traceability/impact-evaluator.d.ts.map +1 -0
- package/dist/traceability/impact-evaluator.js +270 -0
- package/dist/traceability/impact-git-tree.d.ts +12 -0
- package/dist/traceability/impact-git-tree.d.ts.map +1 -0
- package/dist/traceability/impact-git-tree.js +46 -0
- package/dist/traceability/impact-knowledge.d.ts +16 -0
- package/dist/traceability/impact-knowledge.d.ts.map +1 -0
- package/dist/traceability/impact-knowledge.js +165 -0
- package/dist/traceability/impact-policy.d.ts +15 -0
- package/dist/traceability/impact-policy.d.ts.map +1 -0
- package/dist/traceability/impact-policy.js +48 -0
- package/dist/traceability/impact-policy.v1.schema.json +48 -0
- package/dist/traceability/impact-pr-diff.d.ts +5 -0
- package/dist/traceability/impact-pr-diff.d.ts.map +1 -0
- package/dist/traceability/impact-pr-diff.js +83 -0
- package/dist/traceability/impact-record-validation.d.ts +9 -0
- package/dist/traceability/impact-record-validation.d.ts.map +1 -0
- package/dist/traceability/impact-record-validation.js +113 -0
- package/dist/traceability/impact-review.d.ts +148 -0
- package/dist/traceability/impact-review.d.ts.map +1 -0
- package/dist/traceability/impact-review.js +494 -0
- package/dist/traceability/impact-review.schema.json +365 -0
- package/dist/traceability/impact-side-evidence.d.ts +13 -0
- package/dist/traceability/impact-side-evidence.d.ts.map +1 -0
- package/dist/traceability/impact-side-evidence.js +240 -0
- package/dist/traceability/reviewed-coordinate-refresh.d.ts +10 -0
- package/dist/traceability/reviewed-coordinate-refresh.d.ts.map +1 -0
- package/dist/traceability/reviewed-coordinate-refresh.js +49 -0
- package/dist/traceability/snapshot-knowledge.d.ts +4 -0
- package/dist/traceability/snapshot-knowledge.d.ts.map +1 -0
- package/dist/traceability/snapshot-knowledge.js +98 -0
- package/dist/traceability/staged-file-coverage.d.ts +23 -0
- package/dist/traceability/staged-file-coverage.d.ts.map +1 -1
- package/dist/traceability/staged-impact-contract.d.ts.map +1 -1
- package/dist/traceability/staged-impact-contract.js +2 -16
- package/dist/traceability/staged-symbols-manifest.d.ts +4 -0
- package/dist/traceability/staged-symbols-manifest.d.ts.map +1 -1
- package/dist/traceability/staged-symbols-manifest.js +17 -6
- package/dist/traceability/symbol-extract.d.ts +3 -5
- package/dist/traceability/symbol-extract.d.ts.map +1 -1
- package/dist/traceability/symbol-extract.js +49 -34
- package/dist/traceability/temp-kb.d.ts +1 -1
- package/dist/traceability/temp-kb.d.ts.map +1 -1
- package/dist/traceability/temp-kb.js +49 -13
- package/dist/traceability/trusted-pr-event.d.ts +13 -0
- package/dist/traceability/trusted-pr-event.d.ts.map +1 -0
- package/dist/traceability/trusted-pr-event.js +105 -0
- package/dist/utils/canonical-path.d.ts +3 -0
- package/dist/utils/canonical-path.d.ts.map +1 -0
- package/dist/utils/canonical-path.js +33 -0
- package/package.json +14 -5
- package/src/public/impact/analyzer.ts +88 -5
- package/src/public/impact/diagnostics.ts +7 -5
- package/src/public/impact/manifest.ts +14 -1
- package/src/public/impact/source-changes.ts +39 -34
- package/src/public/impact/types.ts +5 -0
- package/src/public/operations/catalog.ts +2 -0
- package/src/public/operations/contracts.ts +385 -9
- package/src/public/operations/impact-review-preparation.ts +548 -0
- package/src/public/operations/index.ts +2 -0
- package/src/public/operations/node-ports.ts +1 -39
- package/src/public/operations/proof-receipt-projection.ts +39 -0
- package/src/public/operations/specs/impact-review-preparation.ts +46 -0
- package/src/public/operations/types.ts +1 -0
- package/src/public/skills/kibi-usage/resources/operation-access.md +1 -0
- package/src/traceability/impact-policy.v1.schema.json +48 -0
- package/src/traceability/impact-review.schema.json +365 -0
- package/templates/github/kibi-badge.yml +0 -4
- package/templates/github/kibi-report.yml +0 -4
|
@@ -17,42 +17,10 @@
|
|
|
17
17
|
*/
|
|
18
18
|
import * as fs from "node:fs";
|
|
19
19
|
import * as path from "node:path";
|
|
20
|
+
import { createMaintenanceSourceAnalysisService } from "../plugins/maintenance-source-analysis.js";
|
|
20
21
|
import { createSourceAnalysisService, } from "../plugins/source-analysis-service.js";
|
|
22
|
+
import { extensionLanguage, isTsJsSourcePath, } from "../plugins/source-classification.js";
|
|
21
23
|
import { createTsMorphSourceAnalysisProvider, enrichSymbolCoordinatesWithTsMorph, } from "./symbols-ts.js";
|
|
22
|
-
const TS_JS_EXTENSIONS = new Set([
|
|
23
|
-
".ts",
|
|
24
|
-
".tsx",
|
|
25
|
-
".js",
|
|
26
|
-
".jsx",
|
|
27
|
-
".mts",
|
|
28
|
-
".cts",
|
|
29
|
-
".mjs",
|
|
30
|
-
".cjs",
|
|
31
|
-
]);
|
|
32
|
-
const SOURCE_LANGUAGE_EXTENSIONS = {
|
|
33
|
-
".c": "c",
|
|
34
|
-
".cc": "cpp",
|
|
35
|
-
".cjs": "javascript",
|
|
36
|
-
".cpp": "cpp",
|
|
37
|
-
".cs": "csharp",
|
|
38
|
-
".cts": "typescript",
|
|
39
|
-
".go": "go",
|
|
40
|
-
".h": "c",
|
|
41
|
-
".hpp": "cpp",
|
|
42
|
-
".java": "java",
|
|
43
|
-
".js": "javascript",
|
|
44
|
-
".jsx": "javascript",
|
|
45
|
-
".kt": "kotlin",
|
|
46
|
-
".mjs": "javascript",
|
|
47
|
-
".mts": "typescript",
|
|
48
|
-
".php": "php",
|
|
49
|
-
".py": "python",
|
|
50
|
-
".rb": "ruby",
|
|
51
|
-
".rs": "rust",
|
|
52
|
-
".swift": "swift",
|
|
53
|
-
".ts": "typescript",
|
|
54
|
-
".tsx": "typescript",
|
|
55
|
-
};
|
|
56
24
|
const DEFAULT_SOURCE_ANALYSIS_PROVIDERS = [
|
|
57
25
|
createTsMorphSourceAnalysisProvider(),
|
|
58
26
|
];
|
|
@@ -114,10 +82,40 @@ export async function analyzeSourceTextWithRegistry(filePath, content, registry)
|
|
|
114
82
|
return analyzeSourceText(filePath, content);
|
|
115
83
|
}
|
|
116
84
|
}
|
|
85
|
+
function isCoordinateOnlyDecoratorPartial(analysis) {
|
|
86
|
+
if (analysis.status !== "partial" ||
|
|
87
|
+
analysis.language !== "python" ||
|
|
88
|
+
analysis.module.analysisMode !== "parser" ||
|
|
89
|
+
analysis.providerId !== "kibi-plugin-treesitter.tree-sitter.v2" ||
|
|
90
|
+
analysis.stamp?.pluginId !== "kibi-plugin-treesitter" ||
|
|
91
|
+
analysis.diagnostics.length === 0 ||
|
|
92
|
+
analysis.uncoveredRanges.length !== analysis.diagnostics.length)
|
|
93
|
+
return false;
|
|
94
|
+
return (analysis.diagnostics.every((diagnostic) => {
|
|
95
|
+
if (diagnostic.code !== "TREESITTER_DECORATOR_EXPANSION_UNAVAILABLE" ||
|
|
96
|
+
diagnostic.range === undefined)
|
|
97
|
+
return false;
|
|
98
|
+
const range = diagnostic.range;
|
|
99
|
+
return analysis.uncoveredRanges.some((uncovered) => uncovered.reason === "decorator-may-alter-or-create-declarations" &&
|
|
100
|
+
uncovered.startLine === range.startLine &&
|
|
101
|
+
uncovered.startColumn === range.startColumn &&
|
|
102
|
+
uncovered.endLine === range.endLine &&
|
|
103
|
+
uncovered.endColumn === range.endColumn);
|
|
104
|
+
}) &&
|
|
105
|
+
analysis.uncoveredRanges.every((uncovered) => uncovered.reason === "decorator-may-alter-or-create-declarations" &&
|
|
106
|
+
analysis.diagnostics.some(({ range }) => range !== undefined &&
|
|
107
|
+
uncovered.startLine === range.startLine &&
|
|
108
|
+
uncovered.startColumn === range.startColumn &&
|
|
109
|
+
uncovered.endLine === range.endLine &&
|
|
110
|
+
uncovered.endColumn === range.endColumn)));
|
|
111
|
+
}
|
|
117
112
|
export async function enrichSymbolCoordinates(entries, workspaceRoot, deps) {
|
|
118
113
|
// implements REQ-vscode-traceability
|
|
119
114
|
const enrichTsCoordinates = deps?.enrichTsCoordinates ?? enrichSymbolCoordinatesWithTsMorph;
|
|
120
115
|
const output = entries.map((entry) => withoutGeneratedCoordinates(entry));
|
|
116
|
+
const service = deps?.sourceAnalysisService ??
|
|
117
|
+
createMaintenanceSourceAnalysisService(workspaceRoot);
|
|
118
|
+
const analyses = new Map();
|
|
121
119
|
const tsIndices = [];
|
|
122
120
|
const tsEntries = [];
|
|
123
121
|
for (let index = 0; index < output.length; index++) {
|
|
@@ -125,15 +123,54 @@ export async function enrichSymbolCoordinates(entries, workspaceRoot, deps) {
|
|
|
125
123
|
if (!entry)
|
|
126
124
|
continue;
|
|
127
125
|
const resolved = resolveSourcePath(entry.sourceFile, workspaceRoot);
|
|
128
|
-
if (!resolved)
|
|
126
|
+
if (!resolved || !fs.statSync(resolved.absolutePath).isFile())
|
|
129
127
|
continue;
|
|
130
128
|
const ext = path.extname(resolved.absolutePath).toLowerCase();
|
|
131
|
-
if (
|
|
129
|
+
if (isTsJsSourcePath(resolved.absolutePath)) {
|
|
132
130
|
tsIndices.push(index);
|
|
133
131
|
tsEntries.push(entry);
|
|
134
132
|
continue;
|
|
135
133
|
}
|
|
136
|
-
|
|
134
|
+
const logicalPath = path
|
|
135
|
+
.relative(workspaceRoot, resolved.absolutePath)
|
|
136
|
+
.replaceAll("\\", "/");
|
|
137
|
+
let analysis = analyses.get(logicalPath);
|
|
138
|
+
const firstAnalysis = analysis === undefined;
|
|
139
|
+
if (!analysis) {
|
|
140
|
+
analysis = await service.analyzeTextV2(logicalPath, fs.readFileSync(resolved.absolutePath, "utf8"));
|
|
141
|
+
analyses.set(logicalPath, analysis);
|
|
142
|
+
}
|
|
143
|
+
const coordinateOnlyPartial = deps?.allowPythonDecoratorCoordinates === true &&
|
|
144
|
+
isCoordinateOnlyDecoratorPartial(analysis);
|
|
145
|
+
if (analysis.status === "failed" ||
|
|
146
|
+
(analysis.status === "partial" && !coordinateOnlyPartial))
|
|
147
|
+
throw new Error(`Cannot refresh incomplete source analysis for ${logicalPath}: ${analysis.diagnostics.map((d) => d.message).join("; ")}`);
|
|
148
|
+
if (coordinateOnlyPartial && firstAnalysis) {
|
|
149
|
+
await deps?.verifyPythonDecoratorCoordinates?.(logicalPath, analysis);
|
|
150
|
+
console.warn(`[kibi] Coordinate-only refresh for ${logicalPath}; source analysis remains partial: ${analysis.diagnostics.map((diagnostic) => diagnostic.message).join("; ")}`);
|
|
151
|
+
}
|
|
152
|
+
if (analysis.status === "unsupported") {
|
|
153
|
+
// Preserve the legacy coarse heuristic until the file-level migration;
|
|
154
|
+
// it is never exposed as parser-backed symbol evidence.
|
|
155
|
+
output[index] = enrichWithRegexHeuristic(entry, resolved.absolutePath);
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
const exact = analysis.symbols.filter((symbol) => (symbol.qualifiedName ?? symbol.name) === entry.title);
|
|
159
|
+
const candidates = exact.length
|
|
160
|
+
? exact
|
|
161
|
+
: analysis.symbols.filter((symbol) => symbol.name === entry.title);
|
|
162
|
+
if (candidates.length !== 1)
|
|
163
|
+
continue;
|
|
164
|
+
const symbol = candidates[0];
|
|
165
|
+
if (!symbol)
|
|
166
|
+
continue;
|
|
167
|
+
output[index] = {
|
|
168
|
+
...entry,
|
|
169
|
+
sourceLine: symbol.startLine,
|
|
170
|
+
sourceColumn: symbol.startColumn,
|
|
171
|
+
sourceEndLine: symbol.endLine,
|
|
172
|
+
sourceEndColumn: symbol.endColumn,
|
|
173
|
+
};
|
|
137
174
|
}
|
|
138
175
|
if (tsEntries.length > 0) {
|
|
139
176
|
const enrichedTs = await enrichTsCoordinates(tsEntries, workspaceRoot);
|
|
@@ -218,8 +255,7 @@ function createFallbackAnalysis(filePath, fallbackReason) {
|
|
|
218
255
|
};
|
|
219
256
|
}
|
|
220
257
|
function detectSourceLanguage(filePath) {
|
|
221
|
-
return (
|
|
222
|
-
"unknown");
|
|
258
|
+
return extensionLanguage(filePath);
|
|
223
259
|
}
|
|
224
260
|
function inferModuleTitle(filePath) {
|
|
225
261
|
const extension = path.extname(filePath);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { normalizePredicateToken, normalizeSubjectKey, singularize, slug, } from "./predicate-utils.js";
|
|
2
2
|
// implements REQ-mcp-suggest-predicates
|
|
3
3
|
export function inferPermissionRuleArgs(text) {
|
|
4
|
-
const prohibition = text.match(/^(?<actor>[a-z][a-z\s_-]*?)\s+(?:must\s+not|cannot|can't|is\s+forbidden\s+to)\s+(?<action>[a-z][a-z_-]*)\s+(?<resource>.+?)\.?$/i);
|
|
4
|
+
const prohibition = text.match(/^(?<actor>[a-z][a-z\s_-]*?)\s+(?:must\s+not|must\s+never|never|cannot|can't|is\s+forbidden\s+to)\s+(?<action>[a-z][a-z_-]*)\s+(?<resource>.+?)\.?$/i);
|
|
5
5
|
if (prohibition?.groups) {
|
|
6
6
|
return [
|
|
7
7
|
singularize(slug(prohibition.groups.actor ?? "actor")),
|
|
@@ -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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"}
|
|
@@ -2,9 +2,11 @@ import { createHash } from "node:crypto";
|
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
3
|
import fs from "node:fs";
|
|
4
4
|
import path from "node:path";
|
|
5
|
+
import { isDeepStrictEqual } from "node:util";
|
|
5
6
|
import { dump as dumpYaml, load as loadYaml } from "js-yaml";
|
|
6
7
|
import { parseDocument, stringify } from "yaml";
|
|
7
8
|
import { OperationError } from "../../cli-errors.js";
|
|
9
|
+
import { canonicalFilesystemPath } from "../../utils/canonical-path.js";
|
|
8
10
|
import { CANONICAL_ENTITY_PATHS, isDerivedKbPath, } from "../../utils/kb-paths.js";
|
|
9
11
|
function digest(value) {
|
|
10
12
|
return createHash("sha256").update(value).digest("hex");
|
|
@@ -69,21 +71,24 @@ export function resolveContainedSourcePath(workspaceRoot, relative) {
|
|
|
69
71
|
throw new OperationError("SOURCE_PATH_INVALID", `document.path cannot target Kibi's derived state under ${workspaceRelative}: ${relative}`);
|
|
70
72
|
}
|
|
71
73
|
// A symlinked existing file or parent could otherwise escape the workspace.
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
}
|
|
76
|
-
const real = fs.realpathSync.native(existing);
|
|
77
|
-
if (real !== root && !real.startsWith(`${root}${path.sep}`)) {
|
|
74
|
+
const realRoot = canonicalFilesystemPath(root);
|
|
75
|
+
const real = canonicalFilesystemPath(absolute);
|
|
76
|
+
if (real !== realRoot && !real.startsWith(`${realRoot}${path.sep}`)) {
|
|
78
77
|
throw new OperationError("SOURCE_PATH_INVALID", `document.path resolves outside the workspace: ${relative}`);
|
|
79
78
|
}
|
|
80
79
|
return absolute;
|
|
81
80
|
}
|
|
82
81
|
export function normalizeAuthoredSourcePath(workspaceRoot, source) {
|
|
83
82
|
const normalized = source.replaceAll("\\", "/");
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
83
|
+
const root = path.resolve(workspaceRoot);
|
|
84
|
+
let relative = normalized;
|
|
85
|
+
if (path.isAbsolute(normalized)) {
|
|
86
|
+
const absolute = path.resolve(normalized);
|
|
87
|
+
relative =
|
|
88
|
+
absolute === root || absolute.startsWith(`${root}${path.sep}`)
|
|
89
|
+
? path.relative(root, absolute)
|
|
90
|
+
: path.relative(canonicalFilesystemPath(root), canonicalFilesystemPath(absolute));
|
|
91
|
+
}
|
|
87
92
|
return path
|
|
88
93
|
.relative(path.resolve(workspaceRoot), resolveContainedSourcePath(workspaceRoot, relative))
|
|
89
94
|
.replaceAll(path.sep, "/");
|
|
@@ -246,13 +251,97 @@ export function manifestRelationships(item) {
|
|
|
246
251
|
: [];
|
|
247
252
|
});
|
|
248
253
|
}
|
|
249
|
-
|
|
254
|
+
// implements REQ-source-analysis-v2
|
|
255
|
+
function manifestRecord(item) {
|
|
256
|
+
if (item === null ||
|
|
257
|
+
typeof item !== "object" ||
|
|
258
|
+
!("toJSON" in item) ||
|
|
259
|
+
typeof item.toJSON !== "function") {
|
|
260
|
+
return undefined;
|
|
261
|
+
}
|
|
262
|
+
const value = item.toJSON();
|
|
263
|
+
return value !== null && typeof value === "object" && !Array.isArray(value)
|
|
264
|
+
? value
|
|
265
|
+
: undefined;
|
|
266
|
+
}
|
|
267
|
+
// implements REQ-source-analysis-v2
|
|
268
|
+
function failDuplicateConflict(entityId, field) {
|
|
269
|
+
throw new OperationError("SOURCE_DUPLICATE_CONFLICT", `Duplicate symbol ${entityId} has conflicting authored field "${field}"; no source was written`, false);
|
|
270
|
+
}
|
|
271
|
+
// implements REQ-source-analysis-v2
|
|
272
|
+
function mergeCompatibleManifestField(target, field, value, entityId, conflictField = field) {
|
|
273
|
+
if (Object.hasOwn(target, field)) {
|
|
274
|
+
if (!isDeepStrictEqual(target[field], value)) {
|
|
275
|
+
failDuplicateConflict(entityId, conflictField);
|
|
276
|
+
}
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
Object.defineProperty(target, field, {
|
|
280
|
+
configurable: true,
|
|
281
|
+
enumerable: true,
|
|
282
|
+
value,
|
|
283
|
+
writable: true,
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
// implements REQ-source-analysis-v2
|
|
287
|
+
function mergeDuplicateManifestFields(records, entityId) {
|
|
288
|
+
const merged = Object.create(null);
|
|
289
|
+
for (const record of records) {
|
|
290
|
+
// Links and typed relationships are collections, so merge them separately
|
|
291
|
+
// instead of treating a difference as conflicting scalar metadata.
|
|
292
|
+
const authored = Object.fromEntries(Object.entries(symbolManifestRecord(record)).filter(([key]) => key !== "links"));
|
|
293
|
+
for (const [key, value] of Object.entries(authored)) {
|
|
294
|
+
mergeCompatibleManifestField(merged, key, value, entityId);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
return merged;
|
|
298
|
+
}
|
|
299
|
+
// implements REQ-source-analysis-v2
|
|
300
|
+
function manifestRelationshipRecords(record, entityId) {
|
|
301
|
+
if (record.relationships === undefined)
|
|
302
|
+
return [];
|
|
303
|
+
if (!Array.isArray(record.relationships)) {
|
|
304
|
+
failDuplicateConflict(entityId, "relationships");
|
|
305
|
+
}
|
|
306
|
+
return record.relationships;
|
|
307
|
+
}
|
|
308
|
+
// implements REQ-source-analysis-v2
|
|
309
|
+
function mergeManifestRelationshipRecords(records, incoming, entityId) {
|
|
250
310
|
const merged = new Map();
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
311
|
+
const untyped = [];
|
|
312
|
+
for (const record of records) {
|
|
313
|
+
for (const row of manifestRelationshipRecords(record, entityId)) {
|
|
314
|
+
if (row === null || typeof row !== "object" || Array.isArray(row)) {
|
|
315
|
+
if (!untyped.some((value) => isDeepStrictEqual(value, row))) {
|
|
316
|
+
untyped.push(row);
|
|
317
|
+
}
|
|
318
|
+
continue;
|
|
319
|
+
}
|
|
320
|
+
const candidate = row;
|
|
321
|
+
const type = candidate.type;
|
|
322
|
+
const target = candidate.target ?? candidate.to;
|
|
323
|
+
if (typeof type !== "string" || typeof target !== "string") {
|
|
324
|
+
if (!untyped.some((value) => isDeepStrictEqual(value, row))) {
|
|
325
|
+
untyped.push(row);
|
|
326
|
+
}
|
|
327
|
+
continue;
|
|
328
|
+
}
|
|
329
|
+
const key = `${type}\u0000${target}`;
|
|
330
|
+
const normalized = {
|
|
331
|
+
...Object.fromEntries(Object.entries(candidate).filter(([key]) => key !== "to")),
|
|
332
|
+
type,
|
|
333
|
+
target,
|
|
334
|
+
};
|
|
335
|
+
const previous = merged.get(key);
|
|
336
|
+
if (previous) {
|
|
337
|
+
for (const [field, value] of Object.entries(normalized)) {
|
|
338
|
+
mergeCompatibleManifestField(previous, field, value, entityId, `relationship ${type} -> ${target}.${field}`);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
else {
|
|
342
|
+
merged.set(key, normalized);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
256
345
|
}
|
|
257
346
|
for (const relationship of incoming) {
|
|
258
347
|
if (relationship.from !== entityId ||
|
|
@@ -260,10 +349,45 @@ function mergeManifestRelationships(existing, incoming, entityId) {
|
|
|
260
349
|
typeof relationship.to !== "string") {
|
|
261
350
|
continue;
|
|
262
351
|
}
|
|
263
|
-
const
|
|
264
|
-
|
|
352
|
+
const key = `${relationship.type}\u0000${relationship.to}`;
|
|
353
|
+
const normalized = {
|
|
354
|
+
...Object.fromEntries(Object.entries(relationship).filter(([key]) => key !== "from" && key !== "to")),
|
|
355
|
+
type: relationship.type,
|
|
356
|
+
target: relationship.to,
|
|
357
|
+
};
|
|
358
|
+
const previous = merged.get(key);
|
|
359
|
+
if (previous) {
|
|
360
|
+
for (const [field, value] of Object.entries(normalized)) {
|
|
361
|
+
mergeCompatibleManifestField(previous, field, value, entityId, `relationship ${relationship.type} -> ${relationship.to}.${field}`);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
else {
|
|
365
|
+
merged.set(key, normalized);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
return [
|
|
369
|
+
...[...merged.values()].sort((left, right) => `${String(left.type)}\u0000${String(left.target)}`.localeCompare(`${String(right.type)}\u0000${String(right.target)}`)),
|
|
370
|
+
...untyped,
|
|
371
|
+
];
|
|
372
|
+
}
|
|
373
|
+
// implements REQ-source-analysis-v2
|
|
374
|
+
function mergeManifestLinks(records, entity) {
|
|
375
|
+
const values = [
|
|
376
|
+
...records.map((record) => record.links),
|
|
377
|
+
entity.links,
|
|
378
|
+
].filter((value) => value !== undefined);
|
|
379
|
+
if (values.length === 0)
|
|
380
|
+
return undefined;
|
|
381
|
+
const links = [];
|
|
382
|
+
for (const value of values) {
|
|
383
|
+
const entries = Array.isArray(value) ? value : [value];
|
|
384
|
+
for (const entry of entries) {
|
|
385
|
+
if (!links.some((existing) => isDeepStrictEqual(existing, entry))) {
|
|
386
|
+
links.push(entry);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
265
389
|
}
|
|
266
|
-
return
|
|
390
|
+
return links;
|
|
267
391
|
}
|
|
268
392
|
/** Indexes of every manifest entry whose `id` equals `id`, in file order. */
|
|
269
393
|
function symbolManifestIndexes(items, id) {
|
|
@@ -276,11 +400,11 @@ function symbolManifestIndexes(items, id) {
|
|
|
276
400
|
}
|
|
277
401
|
function renderSymbolManifest(entity, relationships, existingContent) {
|
|
278
402
|
if (existingContent === undefined) {
|
|
279
|
-
const
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
}));
|
|
403
|
+
const created = symbolManifestRecord(entity);
|
|
404
|
+
const rows = mergeManifestRelationshipRecords([], relationships, String(entity.id));
|
|
405
|
+
if (rows.length > 0)
|
|
406
|
+
created.relationships = rows;
|
|
407
|
+
const doc = parseDocument(stringify({ symbols: [created] }));
|
|
284
408
|
return doc.toString(AUTHORED_YAML_OPTIONS);
|
|
285
409
|
}
|
|
286
410
|
const doc = parseDocument(existingContent);
|
|
@@ -290,36 +414,34 @@ function renderSymbolManifest(entity, relationships, existingContent) {
|
|
|
290
414
|
}
|
|
291
415
|
const items = symbols.items;
|
|
292
416
|
const id = String(entity.id);
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
for (const duplicate of matches.slice(1).reverse()) {
|
|
322
|
-
doc.deleteIn(["symbols", duplicate]);
|
|
417
|
+
const indices = items.flatMap((item, index) => {
|
|
418
|
+
if (!item || typeof item !== "object" || !("get" in item))
|
|
419
|
+
return [];
|
|
420
|
+
return String(item.get("id")) === id
|
|
421
|
+
? [index]
|
|
422
|
+
: [];
|
|
423
|
+
});
|
|
424
|
+
const existingRecords = indices
|
|
425
|
+
.map((index) => manifestRecord(items[index]))
|
|
426
|
+
.filter((record) => record !== undefined);
|
|
427
|
+
if (existingRecords.length !== indices.length) {
|
|
428
|
+
failDuplicateConflict(id, "record");
|
|
429
|
+
}
|
|
430
|
+
const previous = mergeDuplicateManifestFields(existingRecords, id);
|
|
431
|
+
const next = { ...previous, ...symbolManifestRecord(entity) };
|
|
432
|
+
const mergedRelationships = mergeManifestRelationshipRecords(existingRecords, relationships, id);
|
|
433
|
+
if (mergedRelationships.length > 0) {
|
|
434
|
+
next.relationships = mergedRelationships;
|
|
435
|
+
}
|
|
436
|
+
const mergedLinks = mergeManifestLinks(existingRecords, entity);
|
|
437
|
+
if (mergedLinks !== undefined)
|
|
438
|
+
next.links = mergedLinks;
|
|
439
|
+
if (indices.length > 0) {
|
|
440
|
+
// Patch one canonical row and remove all redundant copies only after
|
|
441
|
+
// compatible authored fields and all links have been merged successfully.
|
|
442
|
+
doc.setIn(["symbols", indices[0]], next);
|
|
443
|
+
for (const duplicateIndex of indices.slice(1).reverse()) {
|
|
444
|
+
items.splice(duplicateIndex, 1);
|
|
323
445
|
}
|
|
324
446
|
}
|
|
325
447
|
else {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upsert.d.ts","sourceRoot":"","sources":["../../../src/operations/mutation/upsert.ts"],"names":[],"mappings":"
|
|
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;AAqCxE,OAAO,KAAK,EAAE,iBAAiB,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAoGhF,wBAAsB,+BAA+B,CACnD,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACzC,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,IAAI,CAAC,CAaf;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,GACxB,OAAO,CAAC,SAAS,iBAAiB,EAAE,CAAC,CAuBvC;AAmCD,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;AAEH,wBAAsB,aAAa,CACjC,KAAK,EAAE,WAAW,EAClB,OAAO,EAAE,gBAAgB,EACzB,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,eAAe,CAAC,aAAa,CAAC,CAAC,CAshBzC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
-
import { existsSync, readFileSync,
|
|
2
|
+
import { existsSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { OperationError } from "../../cli-errors.js";
|
|
5
5
|
import { readManifestWithCoordinateOverlay } from "../../extractors/manifest.js";
|
|
@@ -9,6 +9,7 @@ import { loadEntities } from "../../public/operations/discovery-entities.js";
|
|
|
9
9
|
import { appendOnlyProofReceiptHistoryErrors } from "../../public/proof-receipt.js";
|
|
10
10
|
import { appendRelationship, computeShardPath, } from "../../relationships/shards.js";
|
|
11
11
|
import { resolveBranchAttachment } from "../../utils/branch-resolver.js";
|
|
12
|
+
import { canonicalFilesystemPath } from "../../utils/canonical-path.js";
|
|
12
13
|
import { entityIdStyleWarnings } from "../../utils/entity-id-style.js";
|
|
13
14
|
import { analyzeSemanticAdvisorInput } from "../semantic-advisor/analyze-prose.js";
|
|
14
15
|
import { assertLogicalGroundingClaimKeys, assertSemanticInventoryBoundary, } from "../semantic-advisor/ingestion-boundary.js";
|
|
@@ -57,12 +58,9 @@ function assertRelationshipShardContained(workspaceRoot, shardPath) {
|
|
|
57
58
|
if (!absolute.startsWith(`${relationshipRoot}${path.sep}`)) {
|
|
58
59
|
throw new OperationError("SOURCE_PATH_INVALID", `Relationship shard escapes the canonical workspace lane: ${shardPath}`);
|
|
59
60
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
}
|
|
64
|
-
const real = realpathSync.native(existing);
|
|
65
|
-
if (real !== root && !real.startsWith(`${root}${path.sep}`)) {
|
|
61
|
+
const realRoot = canonicalFilesystemPath(root);
|
|
62
|
+
const real = canonicalFilesystemPath(absolute);
|
|
63
|
+
if (real !== realRoot && !real.startsWith(`${realRoot}${path.sep}`)) {
|
|
66
64
|
throw new OperationError("SOURCE_PATH_INVALID", `Relationship shard follows a symlink outside the workspace: ${shardPath}`);
|
|
67
65
|
}
|
|
68
66
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apply-plan.d.ts","sourceRoot":"","sources":["../../../src/operations/planning/apply-plan.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"apply-plan.d.ts","sourceRoot":"","sources":["../../../src/operations/planning/apply-plan.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AAIjF,OAAO,EACL,KAAK,eAAe,EAIrB,MAAM,uBAAuB,CAAC;AAwB/B,OAAO,KAAK,EACV,aAAa,EACb,eAAe,EAGhB,MAAM,uBAAuB,CAAC;AAE/B,YAAY,EACV,aAAa,EACb,eAAe,EACf,kBAAkB,GACnB,MAAM,uBAAuB,CAAC;AAG/B,eAAO,MAAM,yBAAyB,EAAG,2BAAoC,CAAC;AAmI9E,wBAAgB,iCAAiC,CAC/C,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,GAChB,IAAI,CAMN;AAED,wBAAgB,mCAAmC,CACjD,SAAS,EAAE,SAAS;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,EAAE,EACnE,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,GAC3B,IAAI,CAaN;AAED,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,SAAS,eAAe,EAAE,EACnC,SAAS,cAAoB,GAC5B,eAAe,EAAE,CA2CnB;AAm+CD,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,aAAa,EACnB,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC;IACT,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C,iBAAiB,EAAE,eAAe,CAAC;CACpC,CAAC,CA2BD"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
-
import { existsSync, realpathSync } from "node:fs";
|
|
3
2
|
import path from "node:path";
|
|
4
3
|
import { OperationError } from "../../cli-errors.js";
|
|
5
4
|
import { branchEnsureCommand, branchMigrateCommand, branchRecoverCommand, } from "../../commands/branch.js";
|
|
@@ -10,6 +9,7 @@ import { executeStatus } from "../../public/operations/discovery-executors.js";
|
|
|
10
9
|
import { PREDICATE_SCHEMA_ALIGNMENT_CODE, migrationPlanHash, } from "../../public/operations/migration-plan.js";
|
|
11
10
|
import { readMigrationConfigStatus } from "../../public/operations/migration-plan.js";
|
|
12
11
|
import { readWorkspaceSnapshot } from "../../public/operations/workspace-snapshot.js";
|
|
12
|
+
import { canonicalFilesystemPath } from "../../utils/canonical-path.js";
|
|
13
13
|
import { isDerivedKbPath } from "../../utils/kb-paths.js";
|
|
14
14
|
import { bootstrapEmptyKbSnapshotId, bootstrapPlanHash, } from "../bootstrap/types.js";
|
|
15
15
|
import { executeDelete } from "../mutation/delete.js";
|
|
@@ -427,14 +427,10 @@ async function applySourceWrites(context, writes, planHash, allowReplay = false,
|
|
|
427
427
|
if (workspaceRelative === ".kb" || isDerivedKbPath(workspaceRelative)) {
|
|
428
428
|
throw new Error("Apply plan failed: sourceWrites.path cannot target Kibi's derived .kb runtime trees");
|
|
429
429
|
}
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
}
|
|
435
|
-
const realExisting = realpathSync.native(existingPath);
|
|
436
|
-
if (realExisting !== root &&
|
|
437
|
-
!realExisting.startsWith(`${root}${path.sep}`)) {
|
|
430
|
+
const realRoot = canonicalFilesystemPath(root);
|
|
431
|
+
const realExisting = canonicalFilesystemPath(absolute);
|
|
432
|
+
if (realExisting !== realRoot &&
|
|
433
|
+
!realExisting.startsWith(`${realRoot}${path.sep}`)) {
|
|
438
434
|
throw new Error(`Apply plan failed: sourceWrites.path follows a symlink outside the workspace: ${write.path}`);
|
|
439
435
|
}
|
|
440
436
|
const existing = await context.fs
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ingest-proof.d.ts","sourceRoot":"","sources":["../../../src/operations/proof/ingest-proof.ts"],"names":[],"mappings":"AAMA,OAAO,EACL,KAAK,QAAQ,EAEd,MAAM,yBAAyB,CAAC;AAOjC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AAkBjF,OAAO,EAEL,KAAK,YAAY,EAGlB,MAAM,+BAA+B,CAAC;AAqBvC,MAAM,MAAM,eAAe,GAAG,QAAQ,CAAC;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC5C,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC7B,CAAC,CAAC;AAEH,MAAM,MAAM,qBAAqB,GAAG,QAAQ,CAAC;IAC3C,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,YAAY,CAAC,SAAS,CAAC,CAAC;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,SAAS,QAAQ,EAAE,CAAC;CAC3B,CAAC,CAAC;AAGH,MAAM,MAAM,iBAAiB,GAAG,QAAQ,CAAC;IACvC,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,SAAS,qBAAqB,EAAE,CAAC;CAC3C,CAAC,CAAC;AAEH,KAAK,iBAAiB,GAAG;IACvB,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C,iBAAiB,EAAE,iBAAiB,CAAC;CACtC,CAAC;
|
|
1
|
+
{"version":3,"file":"ingest-proof.d.ts","sourceRoot":"","sources":["../../../src/operations/proof/ingest-proof.ts"],"names":[],"mappings":"AAMA,OAAO,EACL,KAAK,QAAQ,EAEd,MAAM,yBAAyB,CAAC;AAOjC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AAkBjF,OAAO,EAEL,KAAK,YAAY,EAGlB,MAAM,+BAA+B,CAAC;AAqBvC,MAAM,MAAM,eAAe,GAAG,QAAQ,CAAC;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC5C,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC7B,CAAC,CAAC;AAEH,MAAM,MAAM,qBAAqB,GAAG,QAAQ,CAAC;IAC3C,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,YAAY,CAAC,SAAS,CAAC,CAAC;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,SAAS,QAAQ,EAAE,CAAC;CAC3B,CAAC,CAAC;AAGH,MAAM,MAAM,iBAAiB,GAAG,QAAQ,CAAC;IACvC,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,SAAS,qBAAqB,EAAE,CAAC;CAC3C,CAAC,CAAC;AAEH,KAAK,iBAAiB,GAAG;IACvB,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C,iBAAiB,EAAE,iBAAiB,CAAC;CACtC,CAAC;AAqkBF,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,eAAe,EACrB,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,iBAAiB,CAAC,CAuC5B"}
|
|
@@ -446,6 +446,7 @@ async function executeIngestProofUnlocked(args, context, lifecycle) {
|
|
|
446
446
|
},
|
|
447
447
|
};
|
|
448
448
|
}
|
|
449
|
+
// implements REQ-kibi-verification-evidence-contract
|
|
449
450
|
export async function executeIngestProof(args, context) {
|
|
450
451
|
if (!context.fs ||
|
|
451
452
|
context.sourceFirst === false ||
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analysis-receipt.d.ts","sourceRoot":"","sources":["../../../src/operations/semantic-advisor/analysis-receipt.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EACL,KAAK,OAAO,EAMb,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EACV,6BAA6B,EAI7B,4BAA4B,EAC5B,0BAA0B,EAC1B,mBAAmB,EACnB,iBAAiB,EACjB,cAAc,EACf,MAAM,YAAY,CAAC;AAyBpB,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,SAAS,cAAc,EAAE,EAClC,OAAO,EAAE,OAAO,EAChB,WAAW,EAAE,SAAS,0BAA0B,EAAE,EAClD,OAAO,EAAE,SAAS,cAAc,EAAE,EAClC,YAAY,EAAE,SAAS,mBAAmB,EAAE,EAC5C,eAAe,EAAE,SAAS,4BAA4B,EAAE,EACxD,cAAc,EAAE,SAAS,iBAAiB,EAAE,GAC3C,6BAA6B,
|
|
1
|
+
{"version":3,"file":"analysis-receipt.d.ts","sourceRoot":"","sources":["../../../src/operations/semantic-advisor/analysis-receipt.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EACL,KAAK,OAAO,EAMb,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EACV,6BAA6B,EAI7B,4BAA4B,EAC5B,0BAA0B,EAC1B,mBAAmB,EACnB,iBAAiB,EACjB,cAAc,EACf,MAAM,YAAY,CAAC;AAyBpB,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,SAAS,cAAc,EAAE,EAClC,OAAO,EAAE,OAAO,EAChB,WAAW,EAAE,SAAS,0BAA0B,EAAE,EAClD,OAAO,EAAE,SAAS,cAAc,EAAE,EAClC,YAAY,EAAE,SAAS,mBAAmB,EAAE,EAC5C,eAAe,EAAE,SAAS,4BAA4B,EAAE,EACxD,cAAc,EAAE,SAAS,iBAAiB,EAAE,GAC3C,6BAA6B,CA2H/B"}
|
|
@@ -27,9 +27,15 @@ export function buildAdvisorResult(payload, signals, modeled, suggestions, claus
|
|
|
27
27
|
: suggestions.some(({ kind }) => kind === "predicate")
|
|
28
28
|
? "predicate"
|
|
29
29
|
: null;
|
|
30
|
+
const signalLane = chooseLane(signals);
|
|
31
|
+
const unresolvedNormative = propositions.some(({ role, status }) => role === "normative" &&
|
|
32
|
+
["missing", "ambiguous", "ontology_gap"].includes(status));
|
|
30
33
|
const candidateLane = modeled
|
|
31
34
|
? "none"
|
|
32
|
-
: (suggestionLane ??
|
|
35
|
+
: (suggestionLane ??
|
|
36
|
+
(signalLane === "none" && unresolvedNormative
|
|
37
|
+
? "observation_review"
|
|
38
|
+
: signalLane));
|
|
33
39
|
const readiness = modeled
|
|
34
40
|
? "modeled"
|
|
35
41
|
: candidateLane === "none"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analyze-prose.d.ts","sourceRoot":"","sources":["../../../src/operations/semantic-advisor/analyze-prose.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"analyze-prose.d.ts","sourceRoot":"","sources":["../../../src/operations/semantic-advisor/analyze-prose.ts"],"names":[],"mappings":"AAmCA,OAAO,KAAK,EACV,6BAA6B,EAC7B,oBAAoB,EAWrB,MAAM,YAAY,CAAC;AAEpB,eAAO,MAAM,wBAAwB,wBAAwB,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEhD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,EAAE,CAI1D;AAk2BD,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,oBAAoB,GAC1B,6BAA6B,CA+D/B"}
|
|
@@ -2,7 +2,7 @@ import { createBuiltinOntologyPack, detectSignals as detectBuiltinSignals, } fro
|
|
|
2
2
|
import { utf8Span, validateLogicIr, } from "../../logic/ir.js";
|
|
3
3
|
import { logicRuleFactId } from "../modeling/logic-modeling.js";
|
|
4
4
|
import { buildAdvisorResult } from "./analysis-receipt.js";
|
|
5
|
-
import { extractSemanticClauses, semanticClaimKey, } from "./clauses.js";
|
|
5
|
+
import { extractSemanticClauses, hasNormativeAssertion, semanticClaimKey, } from "./clauses.js";
|
|
6
6
|
import { observationPlan } from "./observation-plan.js";
|
|
7
7
|
import { predicateSuggestion as buildPredicateSuggestion, isRecord, payloadHash, propertiesOf, relationship, semanticClausesOf, semanticSourceHash, semanticSourceOf, sourceOf, statementOf, stringValue, } from "./shared.js";
|
|
8
8
|
import { detectStrictSuggestion } from "./strict-rules.js";
|
|
@@ -371,11 +371,33 @@ function unmatchedClauseSuggestion(payload, clause, clauses, expectedClaimKeys)
|
|
|
371
371
|
}, clause, clauses, expectedClaimKeys, statementOf(payload), semanticSourceOf(payload).field);
|
|
372
372
|
}
|
|
373
373
|
function propositionRole(statement, normative) {
|
|
374
|
-
|
|
374
|
+
// Explicit context labels may quote obligations. Incidental explanatory
|
|
375
|
+
// words within an asserted obligation must not exempt it from grounding.
|
|
376
|
+
const assertedNormative = normative && hasNormativeAssertion(statement);
|
|
377
|
+
// A bare desired impression is subjective, even when phrased with should.
|
|
378
|
+
// Keep concrete actions, quantitative conditions and any independent
|
|
379
|
+
// obligation assertive instead of exempting them through subjective words.
|
|
380
|
+
const impression = /\bshould\s+(?:feel\s+(?:welcoming|comfortable|energetic)(?:\s+and\s+(?:welcoming|comfortable|energetic))*|(?:look|seem)\s+complete)\b/i.exec(statement);
|
|
381
|
+
const impressionTail = impression
|
|
382
|
+
? statement.slice(impression.index + impression[0].length).trim()
|
|
383
|
+
: "";
|
|
384
|
+
const subjectiveAspiration = impression !== null &&
|
|
385
|
+
(impressionTail.length === 0 ||
|
|
386
|
+
/^(?:to|for)\s+[^,;.!?]+$/i.test(impressionTail)) &&
|
|
387
|
+
!/\b(?:and|or)\b/i.test(impressionTail) &&
|
|
388
|
+
!/\d|\b(?:at least|at most|exactly|within|no more than)\b/i.test(statement) &&
|
|
389
|
+
!hasNormativeAssertion(statement.replace(impression[0], ""));
|
|
390
|
+
if (/^\s*(?:for example\b|e\.g\.|(?:example|illustrative(?: example)?)\s*:)/i.test(statement) ||
|
|
391
|
+
(!assertedNormative &&
|
|
392
|
+
/\b(?:for example|e\.g\.|such as|illustrative)\b/i.test(statement)))
|
|
375
393
|
return "example";
|
|
376
|
-
if (
|
|
394
|
+
if (/^\s*rationale\s*:/i.test(statement) ||
|
|
395
|
+
(!assertedNormative &&
|
|
396
|
+
/\b(?:because|so that|in order to| rationale|therefore)\b/i.test(statement)))
|
|
377
397
|
return "rationale";
|
|
378
|
-
if (
|
|
398
|
+
if (subjectiveAspiration ||
|
|
399
|
+
(!assertedNormative &&
|
|
400
|
+
/\b(?:feel|comfortable|looks complete|seems complete|subjective|prefer)\b/i.test(statement)))
|
|
379
401
|
return "subjective";
|
|
380
402
|
if (/\b(?:means|defined as|refers to|is called)\b/i.test(statement))
|
|
381
403
|
return "definition";
|