{"record":{"id":"b783bbc22d4b169c","repo":"Egonex-AI/Understand-Anything","slug":"assembled-graph-is-missing-whole-file-nodes-for-an","errorCode":null,"errorMessage":"Assembled graph is missing whole-file nodes for analyzed paths: ${missingAnalyzedPaths.join(', ')}; baseline not advanced","messagePattern":"Assembled graph is missing whole-file nodes for analyzed paths: (.+?); baseline not advanced","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"understand-anything-plugin/skills/understand/finalize-incremental.mjs","lineNumber":441,"sourceCode":"\n  if (plan.action !== 'SKIP') {\n    const previousGraph = readJson(graphPath, {});\n    const assembledRaw = readJson(join(intermediateDir, 'assembled-graph.json'));\n    if (!assembledRaw || !Array.isArray(assembledRaw.nodes) || !Array.isArray(assembledRaw.edges)) {\n      throw new Error('assembled-graph.json is missing or invalid; baseline not advanced');\n    }\n    const assembled = refreshGraphImports(\n      normalizeAssembled(assembledRaw),\n      scan.importMap ?? {},\n      importMapRefreshPaths,\n    );\n    const nodeIds = new Set(assembled.nodes.map(node => node.id));\n    const pathIndex = buildPathIndex(assembled.nodes);\n    const missingAnalyzedPaths = plan.filesToReanalyze.filter(\n      path => !hasAnalyzedFileCoverage(assembled.nodes, path),\n    );\n    if (missingAnalyzedPaths.length > 0) {\n      throw new Error(\n        `Assembled graph is missing whole-file nodes for analyzed paths: ` +\n        `${missingAnalyzedPaths.join(', ')}; baseline not advanced`,\n      );\n    }\n    if (plan.rerunArchitecture && !existsSync(join(intermediateDir, 'layers.json'))) {\n      throw new Error('Architecture update requires layers.json; baseline not advanced');\n    }\n    if (plan.rerunTour && !existsSync(join(intermediateDir, 'tour.json'))) {\n      throw new Error('Architecture update requires tour.json; baseline not advanced');\n    }\n    const rawLayers = plan.rerunArchitecture\n      ? readJson(join(intermediateDir, 'layers.json'))\n      : previousGraph.layers ?? [];\n    const rawTour = plan.rerunTour\n      ? readJson(join(intermediateDir, 'tour.json'))\n      : previousGraph.tour ?? [];\n    const now = new Date().toISOString();\n    const graph = {","sourceCodeStart":423,"sourceCodeEnd":459,"githubUrl":"https://github.com/Egonex-AI/Understand-Anything/blob/07edf82a04371b6f69779b067bdc8a1a8753a9db/understand-anything-plugin/skills/understand/finalize-incremental.mjs#L423-L459","documentation":"After assembling the updated graph, finalize verifies that every path in plan.filesToReanalyze has whole-file node coverage in the assembled output (via hasAnalyzedFileCoverage). If any reanalyzed file produced no corresponding whole-file node, the graph would silently lose coverage for that file, so the script throws and leaves the baseline unadvanced. This is an anti-data-loss invariant for incremental updates.","triggerScenarios":"An analysis agent returned an empty or partial result for one of plan.filesToReanalyze; a renamed/deleted file is still listed in filesToReanalyze; the assembler dropped nodes for files whose parsing failed; path casing/normalization mismatches make hasAnalyzedFileCoverage miss the node.","commonSituations":"File deleted from the working tree after planning but before analysis; syntax-error or unsupported-language file the analyzer skips; Windows/POSIX path separator differences; merge that both renamed and modified files, so the plan references the old path.","solutions":["Regenerate the incremental plan so filesToReanalyze matches files that actually exist, then rerun analysis and finalize","Check the listed missing paths: if files were deleted/renamed, replan instead of reusing the stale plan","Inspect the analyzer logs for the listed paths to find parse failures, then fix or exclude those files","Ensure path normalization (forward slashes, relative to project root) matches between plan, scan, and assembler"],"exampleFix":"// before: plan references a deleted file\n\"filesToReanalyze\": [\"src/old-name.ts\"]  // file no longer exists\n// Error: Assembled graph is missing whole-file nodes for analyzed paths: src/old-name.ts ...\n\n// after: replan so deleted files are excluded\nrm .ua/intermediate/incremental-plan.json && rerun /understand incremental\n// plan.filesToReanalyze now reflects the current tree","handlingStrategy":"validation","validationCode":"const plan = JSON.parse(fs.readFileSync('.ua/intermediate/incremental-plan.json','utf8'));\nconst missing = plan.filesToReanalyze.filter(p => !fs.existsSync(path.join(projectRoot, p)));\nif (missing.length) throw new Error(`Stale plan paths (deleted/renamed): ${missing.join(', ')}; replan first`);","typeGuard":"const hasFullCoverage = (assembled, plan) =>\n  plan.filesToReanalyze.every(p => assembled.nodes.some(n => n.path === p && n.type === 'file'));","tryCatchPattern":"try {\n  await run('node finalize-incremental.mjs .');\n} catch (err) {\n  if (String(err.message).includes('missing whole-file nodes for analyzed paths')) {\n    fs.rmSync('.ua/intermediate/incremental-plan.json', { force: true });\n    await replanAndRerunIncremental();\n  } else throw err;\n}","preventionTips":["Replan after any file rename/delete instead of reusing a stale plan","Check analyzer output for skipped or failed files before finalizing","Normalize paths to forward slashes relative to project root everywhere","Rerun the pipeline rather than forcing finalize when this invariant trips; the baseline stays safe by design"],"tags":["incremental","knowledge-graph","data-loss","validation"],"backgroundTag":"internal-invariant-violation","analyzedSha":"07edf82a04371b6f69779b067bdc8a1a8753a9db","analyzedAt":"2026-09-07T23:20:10.829Z","contentChangedAt":"2026-09-07T23:20:10.829Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}