kibi-cli 0.16.1 → 0.18.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-json-command.d.ts.map +1 -1
- package/dist/cli-json-command.js +87 -11
- package/dist/cli-register-maintenance.d.ts.map +1 -1
- package/dist/cli-register-maintenance.js +8 -0
- package/dist/cli-register-reporting.d.ts.map +1 -1
- package/dist/cli-register-reporting.js +5 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +2 -1
- package/dist/commands/aggregated-checks.d.ts.map +1 -1
- package/dist/commands/aggregated-checks.js +1 -0
- package/dist/commands/check.d.ts.map +1 -1
- package/dist/commands/check.js +1 -1
- package/dist/commands/coverage.d.ts +5 -0
- package/dist/commands/coverage.d.ts.map +1 -1
- package/dist/commands/coverage.js +5 -0
- package/dist/commands/discovery-table.d.ts.map +1 -1
- package/dist/commands/discovery-table.js +96 -5
- package/dist/commands/sync/cache.d.ts +2 -0
- package/dist/commands/sync/cache.d.ts.map +1 -1
- package/dist/commands/sync/cache.js +8 -0
- package/dist/commands/sync/manifest.d.ts +12 -1
- package/dist/commands/sync/manifest.d.ts.map +1 -1
- package/dist/commands/sync/manifest.js +22 -5
- package/dist/commands/sync/persistence.d.ts.map +1 -1
- package/dist/commands/sync/persistence.js +76 -2
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +72 -15
- package/dist/commands/usage-metrics.d.ts +66 -2
- package/dist/commands/usage-metrics.d.ts.map +1 -1
- package/dist/commands/usage-metrics.js +34 -24
- package/dist/commands/usage-remediation.d.ts +9 -0
- package/dist/commands/usage-remediation.d.ts.map +1 -0
- package/dist/commands/usage-remediation.js +52 -0
- package/dist/extractors/markdown.d.ts +17 -1
- package/dist/extractors/markdown.d.ts.map +1 -1
- package/dist/extractors/markdown.js +81 -2
- package/dist/logic/ir.d.ts +112 -0
- package/dist/logic/ir.d.ts.map +1 -0
- package/dist/logic/ir.js +729 -0
- package/dist/operations/modeling/logic-modeling.d.ts +22 -0
- package/dist/operations/modeling/logic-modeling.d.ts.map +1 -0
- package/dist/operations/modeling/logic-modeling.js +120 -0
- package/dist/operations/modeling/model-requirement.d.ts.map +1 -1
- package/dist/operations/modeling/model-requirement.js +83 -2
- package/dist/operations/modeling/predicate-applyplan.d.ts +1 -1
- package/dist/operations/modeling/predicate-applyplan.d.ts.map +1 -1
- package/dist/operations/modeling/predicate-applyplan.js +29 -4
- package/dist/operations/modeling/predicate-inference.d.ts.map +1 -1
- package/dist/operations/modeling/predicate-inference.js +3 -0
- package/dist/operations/modeling/predicate-loader.d.ts.map +1 -1
- package/dist/operations/modeling/predicate-loader.js +7 -1
- package/dist/operations/modeling/predicate-ranker.d.ts.map +1 -1
- package/dist/operations/modeling/predicate-ranker.js +40 -2
- package/dist/operations/modeling/predicate-types.d.ts +12 -1
- package/dist/operations/modeling/predicate-types.d.ts.map +1 -1
- package/dist/operations/modeling/requirement-types.d.ts +12 -0
- package/dist/operations/modeling/requirement-types.d.ts.map +1 -1
- package/dist/operations/modeling/suggest-predicates.d.ts.map +1 -1
- package/dist/operations/modeling/suggest-predicates.js +35 -11
- package/dist/operations/mutation/audit.js +1 -1
- package/dist/operations/mutation/contradictions.d.ts +1 -1
- package/dist/operations/mutation/contradictions.d.ts.map +1 -1
- package/dist/operations/mutation/contradictions.js +23 -18
- package/dist/operations/mutation/relationships.d.ts.map +1 -1
- package/dist/operations/mutation/relationships.js +8 -0
- package/dist/operations/mutation/serialization.d.ts.map +1 -1
- package/dist/operations/mutation/serialization.js +6 -0
- package/dist/operations/mutation/strict-fact.d.ts.map +1 -1
- package/dist/operations/mutation/strict-fact.js +68 -3
- package/dist/operations/mutation/upsert.d.ts +3 -1
- package/dist/operations/mutation/upsert.d.ts.map +1 -1
- package/dist/operations/mutation/upsert.js +51 -12
- package/dist/operations/mutation/validate-upsert.d.ts.map +1 -1
- package/dist/operations/mutation/validate-upsert.js +18 -2
- package/dist/operations/mutation/validation.d.ts.map +1 -1
- package/dist/operations/mutation/validation.js +8 -0
- package/dist/operations/semantic-advisor/analysis-receipt.d.ts +2 -2
- package/dist/operations/semantic-advisor/analysis-receipt.d.ts.map +1 -1
- package/dist/operations/semantic-advisor/analysis-receipt.js +30 -16
- package/dist/operations/semantic-advisor/analyze-prose.d.ts +1 -1
- package/dist/operations/semantic-advisor/analyze-prose.d.ts.map +1 -1
- package/dist/operations/semantic-advisor/analyze-prose.js +464 -27
- 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 -7
- package/dist/operations/semantic-advisor/ingestion-boundary.d.ts +18 -0
- package/dist/operations/semantic-advisor/ingestion-boundary.d.ts.map +1 -0
- package/dist/operations/semantic-advisor/ingestion-boundary.js +167 -0
- package/dist/operations/semantic-advisor/observation-plan.d.ts.map +1 -1
- package/dist/operations/semantic-advisor/observation-plan.js +15 -3
- package/dist/operations/semantic-advisor/shared.d.ts +9 -0
- package/dist/operations/semantic-advisor/shared.d.ts.map +1 -1
- package/dist/operations/semantic-advisor/shared.js +38 -4
- package/dist/operations/semantic-advisor/types.d.ts +66 -1
- package/dist/operations/semantic-advisor/types.d.ts.map +1 -1
- package/dist/prolog/codec.d.ts.map +1 -1
- package/dist/prolog/codec.js +19 -2
- package/dist/prolog.d.ts +6 -0
- package/dist/prolog.d.ts.map +1 -1
- package/dist/prolog.js +247 -63
- package/dist/public/diagnostic-usage.d.ts +17 -0
- package/dist/public/diagnostic-usage.d.ts.map +1 -0
- package/dist/public/diagnostic-usage.js +152 -0
- package/dist/public/distribution-parity.d.ts +90 -0
- package/dist/public/distribution-parity.d.ts.map +1 -0
- package/dist/public/distribution-parity.js +367 -0
- package/dist/public/impact/full-kb-quality.d.ts +2 -0
- package/dist/public/impact/full-kb-quality.d.ts.map +1 -1
- package/dist/public/impact/full-kb-quality.js +53 -1
- package/dist/public/impact-diagnostics.d.ts +2 -0
- package/dist/public/impact-diagnostics.d.ts.map +1 -1
- package/dist/public/impact-diagnostics.js +1 -0
- package/dist/public/operations/catalog.d.ts +235 -11
- 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 +4 -0
- package/dist/public/operations/discovery-executors.d.ts +6 -0
- package/dist/public/operations/discovery-executors.d.ts.map +1 -1
- package/dist/public/operations/discovery-executors.js +18 -2
- package/dist/public/operations/index.d.ts +5 -0
- package/dist/public/operations/index.d.ts.map +1 -1
- package/dist/public/operations/index.js +5 -0
- package/dist/public/operations/legacy-migration-plan.d.ts +113 -0
- package/dist/public/operations/legacy-migration-plan.d.ts.map +1 -0
- package/dist/public/operations/legacy-migration-plan.js +409 -0
- package/dist/public/operations/node-ports.d.ts.map +1 -1
- package/dist/public/operations/node-ports.js +90 -0
- package/dist/public/operations/repair-plan.d.ts +184 -0
- package/dist/public/operations/repair-plan.d.ts.map +1 -0
- package/dist/public/operations/repair-plan.js +397 -0
- package/dist/public/operations/runtime-types.d.ts +7 -0
- package/dist/public/operations/runtime-types.d.ts.map +1 -1
- package/dist/public/operations/specs/check.d.ts +3 -3
- package/dist/public/operations/specs/check.d.ts.map +1 -1
- package/dist/public/operations/specs/check.js +5 -2
- package/dist/public/operations/specs/discovery.d.ts +1 -1
- package/dist/public/operations/specs/discovery.js +1 -1
- package/dist/public/operations/specs/modeling.d.ts +35 -1
- package/dist/public/operations/specs/modeling.d.ts.map +1 -1
- package/dist/public/operations/specs/modeling.js +32 -1
- package/dist/public/operations/specs/mutation-schemas.d.ts +133 -3
- package/dist/public/operations/specs/mutation-schemas.d.ts.map +1 -1
- package/dist/public/operations/specs/mutation-schemas.js +67 -1
- package/dist/public/operations/specs/reporting.d.ts +42 -1
- package/dist/public/operations/specs/reporting.d.ts.map +1 -1
- package/dist/public/operations/specs/reporting.js +70 -6
- package/dist/public/operations/specs/semantic.d.ts +30 -2
- package/dist/public/operations/specs/semantic.d.ts.map +1 -1
- package/dist/public/operations/specs/semantic.js +35 -3
- package/dist/public/operations/specs/upsert.d.ts +133 -3
- package/dist/public/operations/specs/upsert.d.ts.map +1 -1
- package/dist/public/operations/workspace-snapshot.d.ts +10 -0
- package/dist/public/operations/workspace-snapshot.d.ts.map +1 -0
- package/dist/public/operations/workspace-snapshot.js +20 -0
- package/dist/public/schemas/entity.d.ts.map +1 -1
- package/dist/public/schemas/entity.js +332 -0
- package/dist/public/schemas/relationship.d.ts.map +1 -1
- package/dist/public/schemas/relationship.js +1 -0
- package/dist/public/skills/kibi-traceability/SKILL.md +7 -1
- package/dist/public/skills/kibi-usage/SKILL.md +44 -12
- package/dist/public/skills/kibi-usage/resources/fact-lanes.md +12 -2
- package/dist/public/skills/kibi-usage/resources/logic-ir.md +43 -0
- package/dist/public/skills/kibi-usage/resources/operation-access.md +19 -19
- package/dist/public/skills/kibi-usage/resources/ui-requirements.md +96 -0
- package/dist/public/skills/kibi-usage/resources/workflows.md +40 -8
- package/dist/public/symbol-granularity.d.ts +9 -0
- package/dist/public/symbol-granularity.d.ts.map +1 -1
- package/dist/public/symbol-granularity.js +16 -0
- package/dist/public/telemetry-acceptance.d.ts +89 -0
- package/dist/public/telemetry-acceptance.d.ts.map +1 -0
- package/dist/public/telemetry-acceptance.js +597 -0
- package/dist/public/telemetry-remediation.d.ts +33 -0
- package/dist/public/telemetry-remediation.d.ts.map +1 -0
- package/dist/public/telemetry-remediation.js +257 -0
- package/dist/public/verification-receipt.d.ts +75 -0
- package/dist/public/verification-receipt.d.ts.map +1 -0
- package/dist/public/verification-receipt.js +129 -0
- package/dist/schemas/entity.schema.json +401 -4
- package/dist/traceability/staged-diagnostics.d.ts +1 -1
- package/dist/traceability/staged-diagnostics.d.ts.map +1 -1
- package/dist/traceability/staged-diagnostics.js +17 -10
- package/dist/traceability/staged-impact-contract.js +1 -1
- package/dist/traceability/staged-symbols-manifest.d.ts.map +1 -1
- package/dist/traceability/staged-symbols-manifest.js +28 -10
- package/dist/traceability/temp-kb.d.ts.map +1 -1
- package/dist/traceability/temp-kb.js +49 -3
- package/dist/types/entities.d.ts +1 -0
- package/dist/types/entities.d.ts.map +1 -1
- package/dist/types/relationships.d.ts +1 -1
- package/dist/types/relationships.d.ts.map +1 -1
- package/dist/utils/rule-registry.d.ts +2 -0
- package/dist/utils/rule-registry.d.ts.map +1 -1
- package/dist/utils/rule-registry.js +18 -0
- package/dist/utils/schema-version.d.ts +1 -1
- package/dist/utils/schema-version.js +1 -1
- package/package.json +34 -2
- package/src/public/diagnostic-usage.ts +206 -0
- package/src/public/distribution-parity.ts +580 -0
- package/src/public/impact/full-kb-quality.ts +74 -1
- package/src/public/impact-diagnostics.ts +16 -0
- package/src/public/operations/check-executor.ts +4 -0
- package/src/public/operations/discovery-executors.ts +24 -2
- package/src/public/operations/index.ts +5 -0
- package/src/public/operations/legacy-migration-plan.ts +688 -0
- package/src/public/operations/node-ports.ts +109 -0
- package/src/public/operations/repair-plan.ts +562 -0
- package/src/public/operations/runtime-types.ts +8 -0
- package/src/public/operations/specs/check.ts +5 -2
- package/src/public/operations/specs/discovery.ts +1 -1
- package/src/public/operations/specs/modeling.ts +39 -1
- package/src/public/operations/specs/mutation-schemas.ts +77 -1
- package/src/public/operations/specs/reporting.ts +91 -6
- package/src/public/operations/specs/semantic.ts +42 -3
- package/src/public/operations/workspace-snapshot.ts +28 -0
- package/src/public/schemas/entity.ts +340 -1
- package/src/public/schemas/relationship.ts +1 -0
- package/src/public/skills/kibi-traceability/SKILL.md +7 -1
- package/src/public/skills/kibi-usage/SKILL.md +44 -12
- package/src/public/skills/kibi-usage/resources/fact-lanes.md +12 -2
- package/src/public/skills/kibi-usage/resources/logic-ir.md +43 -0
- package/src/public/skills/kibi-usage/resources/operation-access.md +19 -19
- package/src/public/skills/kibi-usage/resources/ui-requirements.md +96 -0
- package/src/public/skills/kibi-usage/resources/workflows.md +40 -8
- package/src/public/symbol-granularity.ts +25 -0
- package/src/public/telemetry-acceptance.ts +859 -0
- package/src/public/telemetry-remediation.ts +462 -0
- package/src/public/verification-receipt.ts +170 -0
- package/src/schemas/entity.schema.json +401 -4
- package/src/schemas/relationship.schema.json +1 -0
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { requirementSemanticText } from "../../extractors/markdown.js";
|
|
3
|
+
import { buildSuggestion } from "../../operations/modeling/predicate-applyplan.js";
|
|
4
|
+
import { BUILT_IN_PREDICATE_SCHEMAS } from "../../operations/modeling/predicate-catalog.js";
|
|
5
|
+
import { inferSubject } from "../../operations/modeling/predicate-inference.js";
|
|
6
|
+
import { loadExistingPredicateSchemas } from "../../operations/modeling/predicate-loader.js";
|
|
7
|
+
import { scoreSchema } from "../../operations/modeling/predicate-ranker.js";
|
|
8
|
+
import { analyzeSemanticAdvisorInput } from "../../operations/semantic-advisor/analyze-prose.js";
|
|
9
|
+
import { semanticSourceHash } from "../../operations/semantic-advisor/shared.js";
|
|
10
|
+
import { loadMarkdownBody } from "../../search-ranking.js";
|
|
11
|
+
import { loadEntities } from "./discovery-entities.js";
|
|
12
|
+
export const LEGACY_MIGRATION_PLAN_VERSION = "kibi.legacy-migration-plan.v1";
|
|
13
|
+
function isRecord(value) {
|
|
14
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
15
|
+
}
|
|
16
|
+
function stringList(value) {
|
|
17
|
+
if (typeof value === "string")
|
|
18
|
+
return [stripKbEntityPrefix(value)];
|
|
19
|
+
if (!Array.isArray(value))
|
|
20
|
+
return [];
|
|
21
|
+
return value.flatMap((item) => typeof item === "string" ? [stripKbEntityPrefix(item)] : []);
|
|
22
|
+
}
|
|
23
|
+
function stripKbEntityPrefix(value) {
|
|
24
|
+
return value.replace(/^kb:entity\//, "");
|
|
25
|
+
}
|
|
26
|
+
function clampInteger(value, fallback, minimum, maximum) {
|
|
27
|
+
if (!Number.isInteger(value))
|
|
28
|
+
return fallback;
|
|
29
|
+
return Math.min(maximum, Math.max(minimum, value ?? fallback));
|
|
30
|
+
}
|
|
31
|
+
function clampScore(value) {
|
|
32
|
+
if (typeof value !== "number" || !Number.isFinite(value))
|
|
33
|
+
return 0.35;
|
|
34
|
+
return Math.min(1, Math.max(0, value));
|
|
35
|
+
}
|
|
36
|
+
function stableValue(value) {
|
|
37
|
+
if (Array.isArray(value))
|
|
38
|
+
return value.map(stableValue);
|
|
39
|
+
if (!isRecord(value))
|
|
40
|
+
return value;
|
|
41
|
+
return Object.fromEntries(Object.entries(value)
|
|
42
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
43
|
+
.map(([key, item]) => [key, stableValue(item)]));
|
|
44
|
+
}
|
|
45
|
+
function stableStringify(value) {
|
|
46
|
+
return JSON.stringify(stableValue(value));
|
|
47
|
+
}
|
|
48
|
+
function hash(value) {
|
|
49
|
+
return createHash("sha256").update(stableStringify(value)).digest("hex");
|
|
50
|
+
}
|
|
51
|
+
function migrationRepairBatches(plan) {
|
|
52
|
+
const seen = new Set();
|
|
53
|
+
return plan.batches
|
|
54
|
+
.filter((batch) => batch.phase === "semantic_inventory" && batch.state === "ready")
|
|
55
|
+
.filter((batch) => {
|
|
56
|
+
if (seen.has(batch.requirementId))
|
|
57
|
+
return false;
|
|
58
|
+
seen.add(batch.requirementId);
|
|
59
|
+
return true;
|
|
60
|
+
})
|
|
61
|
+
.sort((left, right) => left.requirementId.localeCompare(right.requirementId));
|
|
62
|
+
}
|
|
63
|
+
function schemaIdentity(schema) {
|
|
64
|
+
return `${schema.predicate_name}(${schema.argument_names.join(",")}):${schema.argument_types.join(",")}`;
|
|
65
|
+
}
|
|
66
|
+
function predicateCatalog(projectSchemas) {
|
|
67
|
+
const result = [];
|
|
68
|
+
const seen = new Set();
|
|
69
|
+
for (const [origin, schemas] of [
|
|
70
|
+
["project_local", projectSchemas],
|
|
71
|
+
["built_in", BUILT_IN_PREDICATE_SCHEMAS],
|
|
72
|
+
]) {
|
|
73
|
+
for (const schema of schemas) {
|
|
74
|
+
const identity = schemaIdentity(schema);
|
|
75
|
+
if (seen.has(identity))
|
|
76
|
+
continue;
|
|
77
|
+
seen.add(identity);
|
|
78
|
+
result.push({ schema, origin });
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return result;
|
|
82
|
+
}
|
|
83
|
+
function rankPredicateCandidates(claimText, catalog, limit, minimumScore) {
|
|
84
|
+
const subject = inferSubject(claimText, undefined);
|
|
85
|
+
return catalog
|
|
86
|
+
.map(({ schema, origin }) => ({
|
|
87
|
+
schema,
|
|
88
|
+
origin,
|
|
89
|
+
score: scoreSchema(schema, claimText),
|
|
90
|
+
}))
|
|
91
|
+
.filter(({ score }) => score >= minimumScore)
|
|
92
|
+
.sort((left, right) => right.score - left.score ||
|
|
93
|
+
(left.origin === right.origin
|
|
94
|
+
? 0
|
|
95
|
+
: left.origin === "project_local"
|
|
96
|
+
? -1
|
|
97
|
+
: 1) ||
|
|
98
|
+
left.schema.predicate_name.localeCompare(right.schema.predicate_name) ||
|
|
99
|
+
left.schema.id.localeCompare(right.schema.id))
|
|
100
|
+
.slice(0, limit)
|
|
101
|
+
.map(({ schema, origin, score }) => {
|
|
102
|
+
const suggestion = buildSuggestion(schema, claimText, subject, score);
|
|
103
|
+
return {
|
|
104
|
+
schemaId: schema.id,
|
|
105
|
+
origin,
|
|
106
|
+
predicateName: schema.predicate_name,
|
|
107
|
+
argumentNames: [...schema.argument_names],
|
|
108
|
+
argumentTypes: [...schema.argument_types],
|
|
109
|
+
score,
|
|
110
|
+
bindingStatus: suggestion.binding_status,
|
|
111
|
+
unboundArguments: [...suggestion.unbound_arguments],
|
|
112
|
+
polarity: suggestion.polarity,
|
|
113
|
+
canonicalKey: suggestion.canonical_key,
|
|
114
|
+
writeEligible: false,
|
|
115
|
+
};
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
function propositionDisposition(proposition, suggestion, candidates) {
|
|
119
|
+
if (proposition.status === "nonlogical") {
|
|
120
|
+
return { recommendedLane: "nonlogical", disposition: "nonlogical" };
|
|
121
|
+
}
|
|
122
|
+
if (suggestion?.kind === "strict_property") {
|
|
123
|
+
return {
|
|
124
|
+
recommendedLane: "strict_property",
|
|
125
|
+
disposition: "strict_property_candidate",
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
if (suggestion?.kind === "rule") {
|
|
129
|
+
return { recommendedLane: "rule", disposition: "rule_candidate" };
|
|
130
|
+
}
|
|
131
|
+
if (suggestion?.kind === "predicate" || candidates.length > 0) {
|
|
132
|
+
return {
|
|
133
|
+
recommendedLane: "predicate",
|
|
134
|
+
disposition: "predicate_candidate",
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
if (proposition.status === "ambiguous" ||
|
|
138
|
+
suggestion?.kind === "ambiguity_observation") {
|
|
139
|
+
return {
|
|
140
|
+
recommendedLane: "unresolved",
|
|
141
|
+
disposition: "unresolved_ambiguity",
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
return {
|
|
145
|
+
recommendedLane: "unresolved",
|
|
146
|
+
disposition: "unresolved_ontology_gap",
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
function claimDelta(existing, expected) {
|
|
150
|
+
const existingSet = new Set(existing);
|
|
151
|
+
const expectedSet = new Set(expected);
|
|
152
|
+
return {
|
|
153
|
+
preserved: expected.filter((claim) => existingSet.has(claim)).sort(),
|
|
154
|
+
added: expected.filter((claim) => !existingSet.has(claim)).sort(),
|
|
155
|
+
stale: existing.filter((claim) => !expectedSet.has(claim)).sort(),
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
async function buildBatch(repairBatch, requirement, readSource, catalog, predicateLimit, predicateMinScore) {
|
|
159
|
+
const requirementId = repairBatch.requirementId;
|
|
160
|
+
const sourceFile = typeof requirement?.source === "string" ? requirement.source : null;
|
|
161
|
+
const sourceText = requirement ? await readSource(requirement) : null;
|
|
162
|
+
const existingTextRef = typeof requirement?.text_ref === "string" && requirement.text_ref.trim()
|
|
163
|
+
? requirement.text_ref.trim()
|
|
164
|
+
: null;
|
|
165
|
+
const existingSemanticText = typeof requirement?.semantic_text === "string" &&
|
|
166
|
+
requirement.semantic_text.trim()
|
|
167
|
+
? requirement.semantic_text.trim()
|
|
168
|
+
: null;
|
|
169
|
+
const sourceHash = sourceText ? semanticSourceHash(sourceText) : null;
|
|
170
|
+
const sourceMissing = requirement === undefined || !sourceText;
|
|
171
|
+
const sourceConflict = !sourceMissing &&
|
|
172
|
+
existingSemanticText !== null &&
|
|
173
|
+
existingSemanticText !== sourceText;
|
|
174
|
+
const sourceStatus = sourceMissing
|
|
175
|
+
? "missing"
|
|
176
|
+
: sourceConflict
|
|
177
|
+
? "conflict"
|
|
178
|
+
: "compatible";
|
|
179
|
+
const diagnostics = [];
|
|
180
|
+
if (requirement === undefined) {
|
|
181
|
+
diagnostics.push(`Requirement ${requirementId} is present in the repair plan but absent from exact KB query results.`);
|
|
182
|
+
}
|
|
183
|
+
else if (!sourceText) {
|
|
184
|
+
diagnostics.push(`Requirement ${requirementId} has no readable authored Markdown body inside the workspace.`);
|
|
185
|
+
}
|
|
186
|
+
else if (sourceConflict) {
|
|
187
|
+
diagnostics.push(`Requirement ${requirementId} has semantic_text that differs from its normalized authored Markdown body; review the source drift before applying this migration.`);
|
|
188
|
+
}
|
|
189
|
+
if (!requirement || !sourceText || !sourceHash) {
|
|
190
|
+
return {
|
|
191
|
+
id: `legacy-migration-${requirementId}`,
|
|
192
|
+
requirementId,
|
|
193
|
+
repairBatchId: repairBatch.id,
|
|
194
|
+
dependsOn: [...repairBatch.dependsOn],
|
|
195
|
+
state: "blocked",
|
|
196
|
+
autoApplicable: false,
|
|
197
|
+
sourceBinding: {
|
|
198
|
+
status: sourceStatus,
|
|
199
|
+
sourceFile,
|
|
200
|
+
sourceKind: "authored_markdown_body",
|
|
201
|
+
sourceHash,
|
|
202
|
+
sourceByteLength: sourceText
|
|
203
|
+
? Buffer.byteLength(sourceText, "utf8")
|
|
204
|
+
: 0,
|
|
205
|
+
persistedField: null,
|
|
206
|
+
existingTextRef,
|
|
207
|
+
existingSemanticText,
|
|
208
|
+
reason: diagnostics[0] ?? "Authored requirement source is unavailable.",
|
|
209
|
+
},
|
|
210
|
+
sourceText,
|
|
211
|
+
claimDelta: { preserved: [], added: [], stale: [] },
|
|
212
|
+
propositions: [],
|
|
213
|
+
requirementPropertyPatchPreview: null,
|
|
214
|
+
diagnostics,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
const existingLogicClaims = stringList(requirement.logic_claims);
|
|
218
|
+
const analysis = analyzeSemanticAdvisorInput({
|
|
219
|
+
payload: {
|
|
220
|
+
type: "req",
|
|
221
|
+
id: requirementId,
|
|
222
|
+
properties: {
|
|
223
|
+
title: requirement.title,
|
|
224
|
+
status: requirement.status,
|
|
225
|
+
source: sourceFile ?? undefined,
|
|
226
|
+
semantic_text: sourceText,
|
|
227
|
+
logic_claims: existingLogicClaims,
|
|
228
|
+
},
|
|
229
|
+
relationships: [],
|
|
230
|
+
},
|
|
231
|
+
});
|
|
232
|
+
const suggestions = new Map(analysis.receipt.suggestions.map((suggestion) => [
|
|
233
|
+
suggestion.claim_key,
|
|
234
|
+
suggestion,
|
|
235
|
+
]));
|
|
236
|
+
const propositions = analysis.receipt.propositions.map((proposition) => {
|
|
237
|
+
const predicateCandidates = proposition.status === "nonlogical"
|
|
238
|
+
? []
|
|
239
|
+
: rankPredicateCandidates(proposition.claim_text, catalog, predicateLimit, predicateMinScore);
|
|
240
|
+
const disposition = propositionDisposition(proposition, suggestions.get(proposition.claim_key), predicateCandidates);
|
|
241
|
+
return {
|
|
242
|
+
claimKey: proposition.claim_key,
|
|
243
|
+
claimText: proposition.claim_text,
|
|
244
|
+
role: proposition.role,
|
|
245
|
+
inventoryStatus: proposition.status,
|
|
246
|
+
span: { ...proposition.span },
|
|
247
|
+
...disposition,
|
|
248
|
+
predicateCandidates,
|
|
249
|
+
reviewRequired: true,
|
|
250
|
+
};
|
|
251
|
+
});
|
|
252
|
+
const expectedClaimKeys = [
|
|
253
|
+
...analysis.receipt.logic_coverage.expected_claim_keys,
|
|
254
|
+
];
|
|
255
|
+
const propertyPatch = sourceConflict
|
|
256
|
+
? null
|
|
257
|
+
: {
|
|
258
|
+
semantic_text: sourceText,
|
|
259
|
+
logic_claims: expectedClaimKeys,
|
|
260
|
+
semantic_clauses: analysis.receipt.clauses.map((clause) => clause.text),
|
|
261
|
+
semantic_inventory_version: analysis.receipt.inventory_contract.version,
|
|
262
|
+
semantic_source_field: analysis.receipt.inventory_contract.source_field,
|
|
263
|
+
semantic_source_hash: analysis.receipt.inventory_contract.source_hash,
|
|
264
|
+
semantic_inventory: analysis.receipt.propositions.map((proposition) => ({
|
|
265
|
+
claim_key: proposition.claim_key,
|
|
266
|
+
claim_text: proposition.claim_text,
|
|
267
|
+
role: proposition.role,
|
|
268
|
+
status: proposition.status,
|
|
269
|
+
span: { ...proposition.span },
|
|
270
|
+
...(proposition.reason ? { reason: proposition.reason } : {}),
|
|
271
|
+
})),
|
|
272
|
+
};
|
|
273
|
+
return {
|
|
274
|
+
id: `legacy-migration-${requirementId}`,
|
|
275
|
+
requirementId,
|
|
276
|
+
repairBatchId: repairBatch.id,
|
|
277
|
+
dependsOn: [...repairBatch.dependsOn],
|
|
278
|
+
state: sourceConflict ? "blocked" : "ready_for_review",
|
|
279
|
+
autoApplicable: false,
|
|
280
|
+
sourceBinding: {
|
|
281
|
+
status: sourceStatus,
|
|
282
|
+
sourceFile,
|
|
283
|
+
sourceKind: "authored_markdown_body",
|
|
284
|
+
sourceHash,
|
|
285
|
+
sourceByteLength: Buffer.byteLength(sourceText, "utf8"),
|
|
286
|
+
persistedField: sourceConflict ? null : "semantic_text",
|
|
287
|
+
existingTextRef,
|
|
288
|
+
existingSemanticText,
|
|
289
|
+
reason: sourceConflict
|
|
290
|
+
? (diagnostics[0] ?? "Existing semantic_text has drifted from source.")
|
|
291
|
+
: existingTextRef
|
|
292
|
+
? "Authored Markdown can be reviewed in semantic_text while preserving the independent text_ref evidence."
|
|
293
|
+
: "Authored Markdown can be reviewed in the dedicated semantic_text field.",
|
|
294
|
+
},
|
|
295
|
+
sourceText,
|
|
296
|
+
claimDelta: claimDelta(existingLogicClaims, expectedClaimKeys),
|
|
297
|
+
propositions,
|
|
298
|
+
requirementPropertyPatchPreview: propertyPatch,
|
|
299
|
+
diagnostics: [...diagnostics, ...analysis.warnings],
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
// implements REQ-kibi-legacy-migration-preview-v2
|
|
303
|
+
export async function buildLegacyMigrationPlan(repairPlan, input, codeSnapshot, dependencies) {
|
|
304
|
+
const offset = clampInteger(input.migrationOffset, 0, 0, Number.MAX_SAFE_INTEGER);
|
|
305
|
+
const limit = clampInteger(input.migrationLimit, 1, 1, 10);
|
|
306
|
+
const predicateLimit = clampInteger(input.migrationPredicateLimit, 5, 1, 20);
|
|
307
|
+
const predicateMinScore = clampScore(input.migrationPredicateMinScore);
|
|
308
|
+
const candidateBatches = migrationRepairBatches(repairPlan);
|
|
309
|
+
const selected = candidateBatches.slice(offset, offset + limit);
|
|
310
|
+
const requirementById = new Map(dependencies.requirements.flatMap((requirement) => typeof requirement.id === "string"
|
|
311
|
+
? [[requirement.id, requirement]]
|
|
312
|
+
: []));
|
|
313
|
+
const catalog = predicateCatalog(dependencies.projectPredicateSchemas);
|
|
314
|
+
const predicateCatalogHash = hash(catalog.map(({ schema, origin }) => ({ origin, schema })));
|
|
315
|
+
const batches = [];
|
|
316
|
+
for (const repairBatch of selected) {
|
|
317
|
+
batches.push(await buildBatch(repairBatch, requirementById.get(repairBatch.requirementId), dependencies.readSource, catalog, predicateLimit, predicateMinScore));
|
|
318
|
+
}
|
|
319
|
+
const readyBatchCount = batches.filter((batch) => batch.state === "ready_for_review").length;
|
|
320
|
+
const blockedBatchCount = batches.length - readyBatchCount;
|
|
321
|
+
const propositionCount = batches.reduce((count, batch) => count + batch.propositions.length, 0);
|
|
322
|
+
const assertivePropositionCount = batches.reduce((count, batch) => count +
|
|
323
|
+
batch.propositions.filter((proposition) => proposition.disposition !== "nonlogical").length, 0);
|
|
324
|
+
const unresolvedPropositionCount = batches.reduce((count, batch) => count +
|
|
325
|
+
batch.propositions.filter((proposition) => proposition.disposition.startsWith("unresolved_")).length, 0);
|
|
326
|
+
const predicateCandidateCount = batches.reduce((count, batch) => count +
|
|
327
|
+
batch.propositions.reduce((subtotal, proposition) => subtotal + proposition.predicateCandidates.length, 0), 0);
|
|
328
|
+
const nextOffset = offset + selected.length < candidateBatches.length
|
|
329
|
+
? offset + selected.length
|
|
330
|
+
: null;
|
|
331
|
+
const diagnostics = [...(dependencies.diagnostics ?? [])];
|
|
332
|
+
if (!repairPlan.scope.complete) {
|
|
333
|
+
diagnostics.push("Legacy migration scope is partial because requirement coverage omitted actionable requirements; rerun complete coverage before treating this as a project inventory.");
|
|
334
|
+
}
|
|
335
|
+
if (candidateBatches.length > 0 && selected.length === 0) {
|
|
336
|
+
diagnostics.push(`Migration offset ${offset} is beyond ${candidateBatches.length} ready semantic-inventory requirement batch(es).`);
|
|
337
|
+
}
|
|
338
|
+
const planCore = {
|
|
339
|
+
version: LEGACY_MIGRATION_PLAN_VERSION,
|
|
340
|
+
codeSnapshot,
|
|
341
|
+
repairPlanId: repairPlan.planId,
|
|
342
|
+
predicateCatalogHash,
|
|
343
|
+
scope: {
|
|
344
|
+
repairPlanComplete: repairPlan.scope.complete,
|
|
345
|
+
candidateRequirements: candidateBatches.length,
|
|
346
|
+
selectedRequirements: selected.length,
|
|
347
|
+
offset,
|
|
348
|
+
limit,
|
|
349
|
+
selectionComplete: offset === 0 && selected.length === candidateBatches.length,
|
|
350
|
+
nextOffset,
|
|
351
|
+
},
|
|
352
|
+
batches,
|
|
353
|
+
};
|
|
354
|
+
const planId = `legacy-migration-plan-${hash(planCore).slice(0, 24)}`;
|
|
355
|
+
const status = !repairPlan.scope.complete
|
|
356
|
+
? "partial"
|
|
357
|
+
: candidateBatches.length === 0
|
|
358
|
+
? "no_candidates"
|
|
359
|
+
: readyBatchCount === 0
|
|
360
|
+
? "blocked"
|
|
361
|
+
: "ready";
|
|
362
|
+
return {
|
|
363
|
+
...planCore,
|
|
364
|
+
planId,
|
|
365
|
+
readOnly: true,
|
|
366
|
+
status,
|
|
367
|
+
applicationPolicy: {
|
|
368
|
+
previewOnly: true,
|
|
369
|
+
reviewEveryProposition: true,
|
|
370
|
+
preserveExistingTextRefs: true,
|
|
371
|
+
exactBindingsBeforeWrite: true,
|
|
372
|
+
validateBeforeEachWrite: true,
|
|
373
|
+
sequentialUpsertsOnly: true,
|
|
374
|
+
recheckContradictionsAfterEachBatch: true,
|
|
375
|
+
},
|
|
376
|
+
summary: {
|
|
377
|
+
batchCount: batches.length,
|
|
378
|
+
readyBatchCount,
|
|
379
|
+
blockedBatchCount,
|
|
380
|
+
propositionCount,
|
|
381
|
+
assertivePropositionCount,
|
|
382
|
+
unresolvedPropositionCount,
|
|
383
|
+
predicateCandidateCount,
|
|
384
|
+
},
|
|
385
|
+
diagnostics,
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
// implements REQ-kibi-legacy-migration-preview-v2
|
|
389
|
+
export async function buildLegacyMigrationPlanFromContext(repairPlan, input, codeSnapshot, context) {
|
|
390
|
+
if (!context.prolog) {
|
|
391
|
+
throw new Error("Legacy migration planning requires a Prolog context");
|
|
392
|
+
}
|
|
393
|
+
const requirements = await loadEntities(context.prolog, { type: "req" });
|
|
394
|
+
const schemaDiagnostics = [];
|
|
395
|
+
const projectPredicateSchemas = await loadExistingPredicateSchemas(context.prolog, true, schemaDiagnostics);
|
|
396
|
+
return buildLegacyMigrationPlan(repairPlan, input, codeSnapshot, {
|
|
397
|
+
requirements,
|
|
398
|
+
projectPredicateSchemas,
|
|
399
|
+
diagnostics: schemaDiagnostics,
|
|
400
|
+
readSource: async (requirement) => {
|
|
401
|
+
const source = typeof requirement.source === "string" ? requirement.source : "";
|
|
402
|
+
const body = await loadMarkdownBody(source, context.workspaceRoot);
|
|
403
|
+
if (body === null)
|
|
404
|
+
return null;
|
|
405
|
+
const semanticText = requirementSemanticText(body);
|
|
406
|
+
return semanticText || null;
|
|
407
|
+
},
|
|
408
|
+
});
|
|
409
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node-ports.d.ts","sourceRoot":"","sources":["../../../src/public/operations/node-ports.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"node-ports.d.ts","sourceRoot":"","sources":["../../../src/public/operations/node-ports.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAE/E,KAAK,kBAAkB,GAAG,cAAc,GAAG;IACzC,QAAQ,CAAC,IAAI,EAAE,CACb,QAAQ,EAAE,SAAS,MAAM,EAAE,EAC3B,OAAO,EAAE;QAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,OAAO,CAAA;KAAE,KACjE,OAAO,CAAC,SAAS,MAAM,EAAE,CAAC,CAAC;CACjC,CAAC;AAEF,KAAK,WAAW,GAAG,OAAO,GAAG;IAC3B,QAAQ,CAAC,YAAY,EAAE,CACrB,aAAa,EAAE,MAAM,EACrB,KAAK,EAAE,SAAS,MAAM,EAAE,KACrB,OAAO,CAAC,SAAS,MAAM,EAAE,CAAC,CAAC;CACjC,CAAC;AA2HF,eAAO,MAAM,cAAc,EAAE,kBAkB5B,CAAC;AAEF,eAAO,MAAM,OAAO,EAAE,WAiBrB,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,WAEzB,CAAC"}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { execFile } from "node:child_process";
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
2
3
|
import * as fs from "node:fs/promises";
|
|
4
|
+
import path from "node:path";
|
|
3
5
|
import { promisify } from "node:util";
|
|
4
6
|
import fg from "fast-glob";
|
|
5
7
|
import { createRepoIgnorePolicy } from "../ignore-policy.js";
|
|
6
8
|
const execFileAsync = promisify(execFile);
|
|
9
|
+
const SNAPSHOT_EXCLUDED_PREFIXES = [".changeset/", ".kb/", "docs/"];
|
|
7
10
|
const ALWAYS_IGNORED_GLOBS = [
|
|
8
11
|
"**/.git/**",
|
|
9
12
|
"**/.kb/**",
|
|
@@ -17,6 +20,92 @@ const ALWAYS_IGNORED_GLOBS = [
|
|
|
17
20
|
"**/coverage/**",
|
|
18
21
|
"**/target/**",
|
|
19
22
|
];
|
|
23
|
+
function includedSnapshotPath(relativePath) {
|
|
24
|
+
return !SNAPSHOT_EXCLUDED_PREFIXES.some((prefix) => relativePath === prefix.slice(0, -1) || relativePath.startsWith(prefix));
|
|
25
|
+
}
|
|
26
|
+
function withoutVerificationReceiptFrontmatter(content) {
|
|
27
|
+
const lines = content.match(/[^\n]*\n|[^\n]+$/g) ?? [];
|
|
28
|
+
if (lines[0]?.trim() !== "---")
|
|
29
|
+
return content;
|
|
30
|
+
let inFrontmatter = true;
|
|
31
|
+
let skippingReceipts = false;
|
|
32
|
+
const retained = [];
|
|
33
|
+
for (const [index, line] of lines.entries()) {
|
|
34
|
+
const trimmed = line.trim();
|
|
35
|
+
if (index > 0 && inFrontmatter && trimmed === "---") {
|
|
36
|
+
inFrontmatter = false;
|
|
37
|
+
skippingReceipts = false;
|
|
38
|
+
retained.push(line);
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
if (inFrontmatter && /^verification_receipts\s*:/.test(line)) {
|
|
42
|
+
skippingReceipts = true;
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
if (inFrontmatter &&
|
|
46
|
+
skippingReceipts &&
|
|
47
|
+
/^[A-Za-z_][A-Za-z0-9_-]*\s*:/.test(line)) {
|
|
48
|
+
skippingReceipts = false;
|
|
49
|
+
}
|
|
50
|
+
if (!skippingReceipts)
|
|
51
|
+
retained.push(line);
|
|
52
|
+
}
|
|
53
|
+
return retained.join("");
|
|
54
|
+
}
|
|
55
|
+
function snapshotFileContent(relativePath, content) {
|
|
56
|
+
if (relativePath.startsWith("documentation/") &&
|
|
57
|
+
relativePath.endsWith(".md")) {
|
|
58
|
+
return Buffer.from(withoutVerificationReceiptFrontmatter(content.toString("utf8")));
|
|
59
|
+
}
|
|
60
|
+
return content;
|
|
61
|
+
}
|
|
62
|
+
async function workspaceSnapshot(workspaceRoot) {
|
|
63
|
+
const { stdout: listed } = await execFileAsync("git", [
|
|
64
|
+
"-C",
|
|
65
|
+
workspaceRoot,
|
|
66
|
+
"ls-files",
|
|
67
|
+
"--cached",
|
|
68
|
+
"--others",
|
|
69
|
+
"--exclude-standard",
|
|
70
|
+
"-z",
|
|
71
|
+
], { encoding: "buffer", maxBuffer: 64 * 1024 * 1024 });
|
|
72
|
+
const paths = listed
|
|
73
|
+
.toString("utf8")
|
|
74
|
+
.split("\0")
|
|
75
|
+
.filter(Boolean)
|
|
76
|
+
.filter(includedSnapshotPath)
|
|
77
|
+
.sort();
|
|
78
|
+
const digest = createHash("sha256");
|
|
79
|
+
digest.update("kibi.workspace-snapshot.v1\0");
|
|
80
|
+
for (const relativePath of paths) {
|
|
81
|
+
digest.update(relativePath);
|
|
82
|
+
digest.update("\0");
|
|
83
|
+
try {
|
|
84
|
+
const content = await fs.readFile(path.join(workspaceRoot, relativePath));
|
|
85
|
+
digest.update(snapshotFileContent(relativePath, content));
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
const code = typeof error === "object" && error !== null && "code" in error
|
|
89
|
+
? String(error.code)
|
|
90
|
+
: "unreadable";
|
|
91
|
+
digest.update(`<${code}>`);
|
|
92
|
+
}
|
|
93
|
+
digest.update("\0");
|
|
94
|
+
}
|
|
95
|
+
const { stdout: status } = await execFileAsync("git", [
|
|
96
|
+
"-C",
|
|
97
|
+
workspaceRoot,
|
|
98
|
+
"status",
|
|
99
|
+
"--porcelain=v1",
|
|
100
|
+
"--untracked-files=normal",
|
|
101
|
+
], { maxBuffer: 16 * 1024 * 1024 });
|
|
102
|
+
return {
|
|
103
|
+
version: "kibi.workspace-snapshot.v1",
|
|
104
|
+
hash: digest.digest("hex"),
|
|
105
|
+
dirty: status.trim().length > 0,
|
|
106
|
+
fileCount: paths.length,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
20
109
|
export const nodeFilesystem = {
|
|
21
110
|
readFile: (filePath) => fs.readFile(filePath, "utf8"),
|
|
22
111
|
writeFile: async (filePath, data) => {
|
|
@@ -47,6 +136,7 @@ export const nodeGit = {
|
|
|
47
136
|
]);
|
|
48
137
|
return stdout.trim();
|
|
49
138
|
},
|
|
139
|
+
workspaceSnapshot,
|
|
50
140
|
ignoredPaths: async (workspaceRoot, paths) => {
|
|
51
141
|
const policy = createRepoIgnorePolicy(workspaceRoot);
|
|
52
142
|
return paths.filter((candidate) => policy.isIgnored(candidate));
|