- Added new properties to TemplateMatch interface for tracking slots and links completeness, and confidence levels. - Updated resolveCanonicalEdgeType function to handle optional edge vocabulary. - Enhanced computeFindings function to include missing link constraints findings. - Improved inspectChains function to report on links completeness and confidence levels. - Refactored tests to utilize real configuration files and improve integration with the vault structure. - Updated helper functions to support loading from real vault paths, enhancing test reliability.
220 lines
6.6 KiB
TypeScript
220 lines
6.6 KiB
TypeScript
/**
|
|
* Tests for Chain Inspector confidence and missing_link_constraints finding using real files.
|
|
*/
|
|
|
|
import { describe, it, expect } from "vitest";
|
|
import { inspectChains } from "../../analysis/chainInspector";
|
|
import { createVaultAppFromFixtures } from "../helpers/vaultHelper";
|
|
import { loadChainRolesFromFixtures, loadChainTemplatesFromFixtures } from "../helpers/configHelper";
|
|
import type { SectionContext } from "../../analysis/sectionContext";
|
|
import type { ChainTemplatesConfig } from "../../dictionary/types";
|
|
|
|
describe("Chain Inspector confidence and missing_link_constraints", () => {
|
|
it("should emit missing_link_constraints (INFO) for discovery profile with complete slots but incomplete links", async () => {
|
|
const app = createVaultAppFromFixtures();
|
|
|
|
const chainRoles = loadChainRolesFromFixtures();
|
|
const baseTemplates = loadChainTemplatesFromFixtures();
|
|
|
|
if (!chainRoles || !baseTemplates) {
|
|
console.warn("Skipping test: real config files not found in fixtures");
|
|
return;
|
|
}
|
|
|
|
// Create templates config with discovery profile and a template that requires causal links
|
|
const chainTemplates: ChainTemplatesConfig = {
|
|
...baseTemplates,
|
|
defaults: {
|
|
...baseTemplates.defaults,
|
|
profiles: {
|
|
discovery: {
|
|
required_links: false,
|
|
min_slots_filled_for_gap_findings: 1,
|
|
min_score_for_gap_findings: 0,
|
|
},
|
|
},
|
|
},
|
|
templates: [
|
|
{
|
|
name: "loop_learning",
|
|
slots: [
|
|
{ id: "trigger", allowed_node_types: ["experience"] },
|
|
{ id: "transformation", allowed_node_types: ["insight"] },
|
|
],
|
|
links: [
|
|
{ from: "trigger", to: "transformation", allowed_edge_roles: ["causal"] },
|
|
],
|
|
},
|
|
],
|
|
};
|
|
|
|
const context: SectionContext = {
|
|
file: "Tests/01_experience_trigger.md",
|
|
heading: "Kontext",
|
|
zoneKind: "content",
|
|
sectionIndex: 0,
|
|
};
|
|
|
|
const report = await inspectChains(
|
|
app,
|
|
context,
|
|
{
|
|
includeNoteLinks: true,
|
|
includeCandidates: false,
|
|
maxDepth: 3,
|
|
direction: "both",
|
|
},
|
|
chainRoles,
|
|
"_system/dictionary/edge_vocabulary.md",
|
|
chainTemplates,
|
|
undefined,
|
|
"discovery"
|
|
);
|
|
|
|
// Should have template match
|
|
if (!report.templateMatches || report.templateMatches.length === 0) {
|
|
return; // Skip if no matches
|
|
}
|
|
|
|
const match = report.templateMatches[0];
|
|
expect(match).toBeDefined();
|
|
if (!match) return;
|
|
|
|
// If slots are complete but links incomplete, should be plausible
|
|
if (match.slotsComplete && !match.linksComplete) {
|
|
expect(match.confidence).toBe("plausible");
|
|
|
|
// Should emit missing_link_constraints finding with INFO severity
|
|
const missingLinkFinding = report.findings.find((f) => f.code === "missing_link_constraints");
|
|
expect(missingLinkFinding).toBeDefined();
|
|
expect(missingLinkFinding?.severity).toBe("info");
|
|
}
|
|
});
|
|
|
|
it("should emit missing_link_constraints (WARN) for decisioning profile with complete slots but incomplete links", async () => {
|
|
const app = createVaultAppFromFixtures();
|
|
|
|
const chainRoles = loadChainRolesFromFixtures();
|
|
const baseTemplates = loadChainTemplatesFromFixtures();
|
|
|
|
if (!chainRoles || !baseTemplates) {
|
|
console.warn("Skipping test: real config files not found in fixtures");
|
|
return;
|
|
}
|
|
|
|
const chainTemplates: ChainTemplatesConfig = {
|
|
...baseTemplates,
|
|
defaults: {
|
|
...baseTemplates.defaults,
|
|
profiles: {
|
|
decisioning: {
|
|
required_links: true,
|
|
min_slots_filled_for_gap_findings: 3,
|
|
min_score_for_gap_findings: 20,
|
|
},
|
|
},
|
|
},
|
|
templates: [
|
|
{
|
|
name: "loop_learning",
|
|
slots: [
|
|
{ id: "trigger", allowed_node_types: ["experience"] },
|
|
{ id: "transformation", allowed_node_types: ["insight"] },
|
|
],
|
|
links: [
|
|
{ from: "trigger", to: "transformation", allowed_edge_roles: ["causal"] },
|
|
],
|
|
},
|
|
],
|
|
};
|
|
|
|
const context: SectionContext = {
|
|
file: "Tests/01_experience_trigger.md",
|
|
heading: "Kontext",
|
|
zoneKind: "content",
|
|
sectionIndex: 0,
|
|
};
|
|
|
|
const report = await inspectChains(
|
|
app,
|
|
context,
|
|
{
|
|
includeNoteLinks: true,
|
|
includeCandidates: false,
|
|
maxDepth: 3,
|
|
direction: "both",
|
|
},
|
|
chainRoles,
|
|
"_system/dictionary/edge_vocabulary.md",
|
|
chainTemplates,
|
|
undefined,
|
|
"decisioning"
|
|
);
|
|
|
|
// Should emit missing_link_constraints finding with WARN severity
|
|
if (!report.templateMatches || report.templateMatches.length === 0) {
|
|
return; // Skip if no matches
|
|
}
|
|
|
|
const match = report.templateMatches[0];
|
|
if (!match) return;
|
|
|
|
if (match.slotsComplete && !match.linksComplete) {
|
|
const missingLinkFinding = report.findings.find((f) => f.code === "missing_link_constraints");
|
|
expect(missingLinkFinding).toBeDefined();
|
|
expect(missingLinkFinding?.severity).toBe("warn");
|
|
}
|
|
});
|
|
|
|
it("should compute confirmed confidence for complete chain with causal roles", async () => {
|
|
const app = createVaultAppFromFixtures();
|
|
|
|
const chainRoles = loadChainRolesFromFixtures();
|
|
const chainTemplates = loadChainTemplatesFromFixtures();
|
|
|
|
if (!chainRoles || !chainTemplates) {
|
|
console.warn("Skipping test: real config files not found in fixtures");
|
|
return;
|
|
}
|
|
|
|
const context: SectionContext = {
|
|
file: "Tests/01_experience_trigger.md",
|
|
heading: "Kontext",
|
|
zoneKind: "content",
|
|
sectionIndex: 0,
|
|
};
|
|
|
|
const report = await inspectChains(
|
|
app,
|
|
context,
|
|
{
|
|
includeNoteLinks: true,
|
|
includeCandidates: false,
|
|
maxDepth: 3,
|
|
direction: "both",
|
|
},
|
|
chainRoles,
|
|
"_system/dictionary/edge_vocabulary.md",
|
|
chainTemplates,
|
|
undefined,
|
|
"decisioning"
|
|
);
|
|
|
|
// Should have complete match with confirmed confidence if all slots and links are found
|
|
if (!report.templateMatches || report.templateMatches.length === 0) {
|
|
return; // Skip if no matches
|
|
}
|
|
|
|
const match = report.templateMatches[0];
|
|
if (!match) return;
|
|
|
|
if (match.slotsComplete && match.linksComplete) {
|
|
expect(match.confidence).toBe("confirmed");
|
|
|
|
// Should NOT emit missing_link_constraints finding
|
|
const missingLinkFinding = report.findings.find((f) => f.code === "missing_link_constraints");
|
|
expect(missingLinkFinding).toBeUndefined();
|
|
}
|
|
});
|
|
});
|