mindnet_obsidian/docs/10_Workbench_Findings_Integration.md
Lars a9b3e2f0e2
Some checks are pending
Node.js build / build (20.x) (push) Waiting to run
Node.js build / build (22.x) (push) Waiting to run
Implement Chain Workbench and Vault Triage features in Mindnet plugin
- 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.
2026-01-26 10:51:12 +01:00

10 KiB

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():

/**
 * 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:

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:

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

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:

// 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