mirror of
https://github.com/Egonex-AI/Understand-Anything.git
synced 2026-06-22 10:58:03 +08:00
perf(understand): gate LLM graph-reviewer behind --review flag, add inline deterministic validation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -12,6 +12,7 @@ Analyze the current codebase and produce a `knowledge-graph.json` file in `.unde
|
||||
|
||||
- `$ARGUMENTS` may contain:
|
||||
- `--full` — Force a full rebuild, ignoring any existing graph
|
||||
- `--review` — Run full LLM graph-reviewer instead of inline deterministic validation
|
||||
- A directory path — Scope analysis to a specific subdirectory
|
||||
|
||||
---
|
||||
@@ -327,7 +328,93 @@ Assemble the full KnowledgeGraph JSON object:
|
||||
|
||||
2. Write the assembled graph to `$PROJECT_ROOT/.understand-anything/intermediate/assembled-graph.json`.
|
||||
|
||||
3. Dispatch a subagent using the prompt template at `./graph-reviewer-prompt.md`. Read the template file and pass the full content as the subagent's prompt, appending the following additional context:
|
||||
3. **Check `$ARGUMENTS` for `--review` flag.** Then run the appropriate validation path:
|
||||
|
||||
---
|
||||
|
||||
#### Default path (no `--review`): inline deterministic validation
|
||||
|
||||
Write the following Node.js script to `$PROJECT_ROOT/.understand-anything/tmp/ua-inline-validate.cjs`:
|
||||
|
||||
```javascript
|
||||
#!/usr/bin/env node
|
||||
const fs = require('fs');
|
||||
const graphPath = process.argv[2];
|
||||
const outputPath = process.argv[3];
|
||||
try {
|
||||
const graph = JSON.parse(fs.readFileSync(graphPath, 'utf8'));
|
||||
const issues = [], warnings = [];
|
||||
if (!Array.isArray(graph.nodes)) { issues.push('graph.nodes is missing or not an array'); graph.nodes = []; }
|
||||
if (!Array.isArray(graph.edges)) { issues.push('graph.edges is missing or not an array'); graph.edges = []; }
|
||||
const nodeIds = new Set();
|
||||
const seen = new Map();
|
||||
graph.nodes.forEach((n, i) => {
|
||||
if (!n.id) { issues.push(`Node[${i}] missing id`); return; }
|
||||
if (!n.type) issues.push(`Node[${i}] '${n.id}' missing type`);
|
||||
if (!n.name) issues.push(`Node[${i}] '${n.id}' missing name`);
|
||||
if (!n.summary) issues.push(`Node[${i}] '${n.id}' missing summary`);
|
||||
if (!n.tags || !n.tags.length) issues.push(`Node[${i}] '${n.id}' missing tags`);
|
||||
if (seen.has(n.id)) issues.push(`Duplicate node ID '${n.id}' at indices ${seen.get(n.id)} and ${i}`);
|
||||
else seen.set(n.id, i);
|
||||
nodeIds.add(n.id);
|
||||
});
|
||||
graph.edges.forEach((e, i) => {
|
||||
if (!nodeIds.has(e.source)) issues.push(`Edge[${i}] source '${e.source}' not found`);
|
||||
if (!nodeIds.has(e.target)) issues.push(`Edge[${i}] target '${e.target}' not found`);
|
||||
});
|
||||
const fileNodes = graph.nodes.filter(n => n.type === 'file').map(n => n.id);
|
||||
const assigned = new Map();
|
||||
(graph.layers || []).forEach(layer => {
|
||||
(layer.nodeIds || []).forEach(id => {
|
||||
if (!nodeIds.has(id)) issues.push(`Layer '${layer.id}' refs missing node '${id}'`);
|
||||
if (assigned.has(id)) issues.push(`Node '${id}' appears in multiple layers`);
|
||||
assigned.set(id, layer.id);
|
||||
});
|
||||
});
|
||||
fileNodes.forEach(id => {
|
||||
if (!assigned.has(id)) issues.push(`File node '${id}' not in any layer`);
|
||||
});
|
||||
(graph.tour || []).forEach((step, i) => {
|
||||
(step.nodeIds || []).forEach(id => {
|
||||
if (!nodeIds.has(id)) issues.push(`Tour step[${i}] refs missing node '${id}'`);
|
||||
});
|
||||
});
|
||||
const withEdges = new Set([
|
||||
...graph.edges.map(e => e.source),
|
||||
...graph.edges.map(e => e.target)
|
||||
]);
|
||||
graph.nodes.forEach(n => {
|
||||
if (!withEdges.has(n.id)) warnings.push(`Node '${n.id}' has no edges (orphan)`);
|
||||
});
|
||||
const stats = {
|
||||
totalNodes: graph.nodes.length,
|
||||
totalEdges: graph.edges.length,
|
||||
totalLayers: (graph.layers || []).length,
|
||||
tourSteps: (graph.tour || []).length,
|
||||
nodeTypes: graph.nodes.reduce((a, n) => { a[n.type] = (a[n.type]||0)+1; return a; }, {}),
|
||||
edgeTypes: graph.edges.reduce((a, e) => { a[e.type] = (a[e.type]||0)+1; return a; }, {})
|
||||
};
|
||||
fs.writeFileSync(outputPath, JSON.stringify({ issues, warnings, stats }, null, 2));
|
||||
process.exit(0);
|
||||
} catch (err) { process.stderr.write(err.message + '\n'); process.exit(1); }
|
||||
```
|
||||
|
||||
Execute it:
|
||||
```bash
|
||||
node $PROJECT_ROOT/.understand-anything/tmp/ua-inline-validate.cjs \
|
||||
"$PROJECT_ROOT/.understand-anything/intermediate/assembled-graph.json" \
|
||||
"$PROJECT_ROOT/.understand-anything/intermediate/review.json"
|
||||
```
|
||||
|
||||
If the script exits non-zero, read stderr, fix the script, and retry once.
|
||||
|
||||
---
|
||||
|
||||
#### `--review` path: full LLM reviewer
|
||||
|
||||
If `--review` IS in `$ARGUMENTS`, dispatch the LLM graph-reviewer subagent as follows:
|
||||
|
||||
Dispatch a subagent using the prompt template at `./graph-reviewer-prompt.md`. Read the template file and pass the full content as the subagent's prompt, appending the following additional context:
|
||||
|
||||
> **Additional context from main session:**
|
||||
>
|
||||
@@ -343,14 +430,16 @@ Assemble the full KnowledgeGraph JSON object:
|
||||
|
||||
Pass these parameters in the dispatch prompt:
|
||||
|
||||
> Validate the knowledge graph at `$PROJECT_ROOT/.understand-anything/intermediate/assembled-graph.json`.
|
||||
> Project root: `$PROJECT_ROOT`
|
||||
> Read the file and validate it for completeness and correctness.
|
||||
> Write output to: `$PROJECT_ROOT/.understand-anything/intermediate/review.json`
|
||||
> Validate the knowledge graph at `$PROJECT_ROOT/.understand-anything/intermediate/assembled-graph.json`.
|
||||
> Project root: `$PROJECT_ROOT`
|
||||
> Read the file and validate it for completeness and correctness.
|
||||
> Write output to: `$PROJECT_ROOT/.understand-anything/intermediate/review.json`
|
||||
|
||||
4. After the subagent completes, read `$PROJECT_ROOT/.understand-anything/intermediate/review.json`.
|
||||
---
|
||||
|
||||
5. **If `approved: false`:**
|
||||
4. Read `$PROJECT_ROOT/.understand-anything/intermediate/review.json`.
|
||||
|
||||
5. **If `issues` array is non-empty:**
|
||||
- Review the `issues` list
|
||||
- Apply automated fixes where possible:
|
||||
- Remove edges with dangling references
|
||||
@@ -359,7 +448,7 @@ Pass these parameters in the dispatch prompt:
|
||||
- Re-run the final graph validation after automated fixes
|
||||
- If critical issues remain after one fix attempt, save the graph anyway but include the warnings in the final report and mark dashboard auto-launch as skipped
|
||||
|
||||
6. **If `approved: true`:** Proceed to Phase 7.
|
||||
6. **If `issues` array is empty:** Proceed to Phase 7.
|
||||
|
||||
---
|
||||
|
||||
@@ -401,7 +490,7 @@ Pass these parameters in the dispatch prompt:
|
||||
## Error Handling
|
||||
|
||||
- If any subagent dispatch fails, retry **once** with the same prompt plus additional context about the failure.
|
||||
- Track all warnings and errors from each phase in a `$PHASE_WARNINGS` list. Pass this list to the graph-reviewer in Phase 6 for comprehensive validation.
|
||||
- Track all warnings and errors from each phase in a `$PHASE_WARNINGS` list. When using `--review`, pass this list to the graph-reviewer in Phase 6. On the default path, include accumulated warnings in the Phase 7 final report.
|
||||
- If it fails a second time, skip that phase and continue with partial results.
|
||||
- ALWAYS save partial results — a partial graph is better than no graph.
|
||||
- Report any skipped phases or errors in the final summary so the user knows what happened.
|
||||
|
||||
Reference in New Issue
Block a user