- Introduced new workflows for Chain Workbench and Vault Triage, enhancing user capabilities for managing template matches and identifying chain gaps. - Added commands for opening the Chain Workbench and scanning the vault for chain gaps, improving the overall functionality of the plugin. - Updated documentation to include detailed instructions for the new workflows, ensuring users can effectively utilize the features. - Enhanced the UI for both the Chain Workbench and Vault Triage Scan, providing a more intuitive user experience. - Implemented tests for the new functionalities to ensure reliability and accuracy in various scenarios.
343 lines
10 KiB
Markdown
343 lines
10 KiB
Markdown
# Chain Workbench - Findings Integration (Vorschlag)
|
|
|
|
> **Status:** Vorschlag für zukünftige Implementierung
|
|
> **Stand:** 2025-01-XX
|
|
> **Zielgruppe:** Entwickler
|
|
|
|
---
|
|
|
|
## Problemstellung
|
|
|
|
Die Chain Workbench (0.5.x) verwendet aktuell **nur** Template Matches aus Chain Inspector (0.4.x), nicht aber die **Findings** und **Gap-Heuristiken**, die aufwendig getestet wurden.
|
|
|
|
**Verlorene Informationen:**
|
|
- `dangling_target` - Target-Datei existiert nicht
|
|
- `dangling_target_heading` - Target-Heading existiert nicht
|
|
- `only_candidates` - Nur Candidate-Edges, keine expliziten
|
|
- `missing_edges` - Section hat Content aber keine Edges
|
|
- `no_causal_roles` - Section hat Edges aber keine kausalen Rollen
|
|
- `one_sided_connectivity` - Nur incoming oder nur outgoing edges
|
|
|
|
---
|
|
|
|
## Lösungsvorschlag
|
|
|
|
### 1. Findings zu Todos konvertieren
|
|
|
|
Erweitere `todoGenerator.ts` um eine Funktion `generateFindingsTodos()`:
|
|
|
|
```typescript
|
|
/**
|
|
* Generate todos from Chain Inspector findings.
|
|
*/
|
|
export function generateFindingsTodos(
|
|
findings: Finding[],
|
|
allEdges: IndexedEdge[],
|
|
context: { file: string; heading: string | null }
|
|
): WorkbenchTodoUnion[] {
|
|
const todos: WorkbenchTodoUnion[] = [];
|
|
|
|
for (const finding of findings) {
|
|
switch (finding.code) {
|
|
case "dangling_target":
|
|
// Find edge with dangling target
|
|
const danglingEdge = allEdges.find(
|
|
(e) => e.target.file === finding.evidence?.file
|
|
);
|
|
if (danglingEdge) {
|
|
todos.push({
|
|
type: "dangling_target",
|
|
id: `dangling_target_${finding.evidence?.file}`,
|
|
description: finding.message,
|
|
priority: finding.severity === "error" ? "high" : "medium",
|
|
targetFile: danglingEdge.target.file,
|
|
targetHeading: danglingEdge.target.heading,
|
|
sourceEdge: {
|
|
file: "sectionHeading" in danglingEdge.source
|
|
? danglingEdge.source.file
|
|
: danglingEdge.source.file,
|
|
heading: "sectionHeading" in danglingEdge.source
|
|
? danglingEdge.source.sectionHeading
|
|
: null,
|
|
},
|
|
actions: ["create_missing_note", "retarget_link"],
|
|
});
|
|
}
|
|
break;
|
|
|
|
case "dangling_target_heading":
|
|
// Similar to dangling_target, but for headings
|
|
todos.push({
|
|
type: "dangling_target_heading",
|
|
id: `dangling_target_heading_${finding.evidence?.file}_${finding.evidence?.sectionHeading}`,
|
|
description: finding.message,
|
|
priority: finding.severity === "warn" ? "medium" : "low",
|
|
targetFile: finding.evidence?.file || "",
|
|
targetHeading: finding.evidence?.sectionHeading || null,
|
|
actions: ["create_missing_heading", "retarget_to_existing_heading"],
|
|
});
|
|
break;
|
|
|
|
case "only_candidates":
|
|
// Find all candidate edges in section
|
|
const candidateEdges = allEdges.filter(
|
|
(e) => e.scope === "candidate" &&
|
|
("sectionHeading" in e.source
|
|
? e.source.sectionHeading === context.heading
|
|
: false)
|
|
);
|
|
if (candidateEdges.length > 0) {
|
|
todos.push({
|
|
type: "only_candidates",
|
|
id: `only_candidates_${context.file}_${context.heading}`,
|
|
description: finding.message,
|
|
priority: "medium",
|
|
candidateEdges: candidateEdges.map((e) => ({
|
|
rawEdgeType: e.rawEdgeType,
|
|
from: "sectionHeading" in e.source
|
|
? { file: e.source.file, heading: e.source.sectionHeading }
|
|
: { file: e.source.file, heading: null },
|
|
to: e.target,
|
|
})),
|
|
actions: ["promote_all_candidates", "create_explicit_edges"],
|
|
});
|
|
}
|
|
break;
|
|
|
|
case "missing_edges":
|
|
todos.push({
|
|
type: "missing_edges",
|
|
id: `missing_edges_${context.file}_${context.heading}`,
|
|
description: finding.message,
|
|
priority: "medium",
|
|
section: {
|
|
file: context.file,
|
|
heading: context.heading,
|
|
},
|
|
actions: ["add_edges_to_section"],
|
|
});
|
|
break;
|
|
|
|
case "no_causal_roles":
|
|
// Find edges without causal roles
|
|
const nonCausalEdges = allEdges.filter(
|
|
(e) => e.scope === "section" &&
|
|
("sectionHeading" in e.source
|
|
? e.source.sectionHeading === context.heading
|
|
: false)
|
|
);
|
|
todos.push({
|
|
type: "no_causal_roles",
|
|
id: `no_causal_roles_${context.file}_${context.heading}`,
|
|
description: finding.message,
|
|
priority: "medium",
|
|
edges: nonCausalEdges.map((e) => ({
|
|
rawEdgeType: e.rawEdgeType,
|
|
from: "sectionHeading" in e.source
|
|
? { file: e.source.file, heading: e.source.sectionHeading }
|
|
: { file: e.source.file, heading: null },
|
|
to: e.target,
|
|
currentRole: null, // Would need to resolve via chain_roles
|
|
suggestedRoles: ["causal", "influences", "enables_constraints"],
|
|
})),
|
|
actions: ["change_edge_type"],
|
|
});
|
|
break;
|
|
|
|
case "one_sided_connectivity":
|
|
// Informational only
|
|
todos.push({
|
|
type: "one_sided_connectivity",
|
|
id: `one_sided_connectivity_${context.file}_${context.heading}`,
|
|
description: finding.message,
|
|
priority: "low",
|
|
section: {
|
|
file: context.file,
|
|
heading: context.heading,
|
|
},
|
|
actions: [], // No actions, informational only
|
|
});
|
|
break;
|
|
}
|
|
}
|
|
|
|
return todos;
|
|
}
|
|
```
|
|
|
|
### 2. Erweitere Todo-Types
|
|
|
|
Füge neue Todo-Types zu `types.ts` hinzu:
|
|
|
|
```typescript
|
|
export type TodoType =
|
|
| "missing_slot"
|
|
| "missing_link"
|
|
| "weak_roles"
|
|
| "candidate_cleanup"
|
|
| "create_candidates_zone"
|
|
| "create_note_links_zone"
|
|
| "dangling_target" // NEU
|
|
| "dangling_target_heading" // NEU
|
|
| "only_candidates" // NEU
|
|
| "missing_edges" // NEU
|
|
| "no_causal_roles" // NEU
|
|
| "one_sided_connectivity"; // NEU
|
|
|
|
export interface DanglingTargetTodo extends WorkbenchTodo {
|
|
type: "dangling_target";
|
|
targetFile: string;
|
|
targetHeading: string | null;
|
|
sourceEdge: {
|
|
file: string;
|
|
heading: string | null;
|
|
};
|
|
actions: Array<"create_missing_note" | "retarget_link">;
|
|
}
|
|
|
|
export interface DanglingTargetHeadingTodo extends WorkbenchTodo {
|
|
type: "dangling_target_heading";
|
|
targetFile: string;
|
|
targetHeading: string | null;
|
|
actions: Array<"create_missing_heading" | "retarget_to_existing_heading">;
|
|
}
|
|
|
|
export interface OnlyCandidatesTodo extends WorkbenchTodo {
|
|
type: "only_candidates";
|
|
candidateEdges: Array<{
|
|
rawEdgeType: string;
|
|
from: { file: string; heading: string | null };
|
|
to: { file: string; heading: string | null };
|
|
}>;
|
|
actions: Array<"promote_all_candidates" | "create_explicit_edges">;
|
|
}
|
|
|
|
export interface MissingEdgesTodo extends WorkbenchTodo {
|
|
type: "missing_edges";
|
|
section: {
|
|
file: string;
|
|
heading: string | null;
|
|
};
|
|
actions: Array<"add_edges_to_section">;
|
|
}
|
|
|
|
export interface NoCausalRolesTodo extends WorkbenchTodo {
|
|
type: "no_causal_roles";
|
|
edges: Array<{
|
|
rawEdgeType: string;
|
|
from: { file: string; heading: string | null };
|
|
to: { file: string; heading: string | null };
|
|
currentRole: string | null;
|
|
suggestedRoles: string[];
|
|
}>;
|
|
actions: Array<"change_edge_type">;
|
|
}
|
|
|
|
export interface OneSidedConnectivityTodo extends WorkbenchTodo {
|
|
type: "one_sided_connectivity";
|
|
section: {
|
|
file: string;
|
|
heading: string | null;
|
|
};
|
|
actions: []; // Informational only
|
|
}
|
|
```
|
|
|
|
### 3. Integriere Findings in Workbench Builder
|
|
|
|
Erweitere `workbenchBuilder.ts`:
|
|
|
|
```typescript
|
|
export async function buildWorkbenchModel(
|
|
app: App,
|
|
report: ChainInspectorReport,
|
|
chainTemplates: ChainTemplatesConfig | null,
|
|
chainRoles: ChainRolesConfig | null,
|
|
edgeVocabulary: EdgeVocabulary | null,
|
|
allEdges: IndexedEdge[]
|
|
): Promise<WorkbenchModel> {
|
|
const matches: WorkbenchMatch[] = [];
|
|
const globalTodos: WorkbenchTodoUnion[] = []; // NEU: Global todos from findings
|
|
|
|
// ... existing template match processing ...
|
|
|
|
// NEU: Generate todos from findings
|
|
if (report.findings && report.findings.length > 0) {
|
|
const findingsTodos = generateFindingsTodos(
|
|
report.findings,
|
|
allEdges,
|
|
report.context
|
|
);
|
|
globalTodos.push(...findingsTodos);
|
|
}
|
|
|
|
return {
|
|
context: report.context,
|
|
matches,
|
|
globalTodos, // NEU: Add global todos
|
|
timestamp: Date.now(),
|
|
};
|
|
}
|
|
```
|
|
|
|
### 4. Erweitere WorkbenchModel Interface
|
|
|
|
```typescript
|
|
export interface WorkbenchModel {
|
|
context: {
|
|
file: string;
|
|
heading: string | null;
|
|
zoneKind: string;
|
|
};
|
|
matches: WorkbenchMatch[];
|
|
globalTodos?: WorkbenchTodoUnion[]; // NEU: Todos from findings (not template-based)
|
|
timestamp: number;
|
|
}
|
|
```
|
|
|
|
### 5. UI-Integration
|
|
|
|
Erweitere `ChainWorkbenchModal.ts`:
|
|
|
|
```typescript
|
|
// Show global todos (from findings) separately
|
|
if (model.globalTodos && model.globalTodos.length > 0) {
|
|
// Render "Section-Level Issues" section
|
|
// Show findings-based todos before template matches
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Vorteile
|
|
|
|
1. **Nutzt getestete Heuristiken** - Findings aus 0.4.x werden verwendet
|
|
2. **Vollständigere Analyse** - Nicht nur Template-basiert, sondern auch Section-Level
|
|
3. **Konsistenz** - Chain Inspector und Workbench zeigen dieselben Probleme
|
|
4. **Bessere UX** - User sieht alle Probleme auf einen Blick
|
|
|
|
---
|
|
|
|
## Implementierungsreihenfolge
|
|
|
|
1. **Phase 1:** Todo-Types erweitern (`types.ts`)
|
|
2. **Phase 2:** `generateFindingsTodos()` implementieren (`todoGenerator.ts`)
|
|
3. **Phase 3:** `buildWorkbenchModel()` erweitern (`workbenchBuilder.ts`)
|
|
4. **Phase 4:** UI erweitern (`ChainWorkbenchModal.ts`)
|
|
5. **Phase 5:** Actions implementieren (z.B. `create_missing_note`, `retarget_link`)
|
|
|
|
---
|
|
|
|
## Offene Fragen
|
|
|
|
1. **Priorität:** Sollen Findings-Todos höhere Priorität haben als Template-Todos?
|
|
2. **Duplikate:** Wie vermeiden wir Duplikate zwischen Findings-Todos und Template-Todos?
|
|
- Beispiel: `dangling_target` könnte auch als `missing_link` Todo erscheinen
|
|
3. **Filterung:** Sollen Findings-Todos gefiltert werden können (z.B. nur Errors)?
|
|
4. **Actions:** Welche Actions sind für welche Findings sinnvoll?
|
|
|
|
---
|
|
|
|
**Letzte Aktualisierung:** 2025-01-XX
|
|
**Status:** Vorschlag für zukünftige Implementierung
|