fix worktree hook crash, prune isolated code nodes, restore rationale-node prohibition

- hooks.py: use git rev-parse --git-path hooks so install/status/uninstall
  work in linked worktrees where .git is a file not a directory (fixes #865)
- build.py: prune degree-0 code nodes after graph assembly to remove
  bundled/synthetic symbols with no connections (fixes #728)
- skill.md: restore explicit rule prohibiting file_type:"rationale" nodes
  and remind model to store rationale as an attribute instead (fixes #751)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Safi
2026-05-14 23:03:21 +01:00
co-authored by Claude Sonnet 4.6
parent a01e0981ed
commit 91f4d120b6
3 changed files with 27 additions and 2 deletions
+9
View File
@@ -28,6 +28,15 @@ def build_from_json(extraction: dict) -> nx.Graph:
hyperedges = extraction.get("hyperedges", [])
if hyperedges:
G.graph["hyperedges"] = hyperedges
# Strip degree-0 code nodes — they are bundled/synthetic symbols with no
# connections and only inflate god-node centrality and clustering noise.
# Document, paper, and image nodes are kept even when isolated since they
# may be leaf concepts intentionally referenced by the skill.
isolated_code = [
n for n in list(G.nodes())
if G.degree(n) == 0 and G.nodes[n].get("file_type") == "code"
]
G.remove_nodes_from(isolated_code)
return G
+14 -1
View File
@@ -75,8 +75,21 @@ def _hooks_dir(root: Path) -> Path:
return p
except (OSError, FileNotFoundError):
pass
# In a linked worktree .git is a file not a directory, so we ask git
# for the real hooks path rather than constructing it ourselves.
try:
result = subprocess.run(
["git", "-C", str(root), "rev-parse", "--path-format=absolute", "--git-path", "hooks"],
capture_output=True, text=True,
)
if result.returncode == 0:
d = Path(result.stdout.strip())
d.mkdir(parents=True, exist_ok=True)
return d
except (OSError, FileNotFoundError):
pass
d = root / ".git" / "hooks"
d.mkdir(exist_ok=True)
d.mkdir(parents=True, exist_ok=True)
return d
+4 -1
View File
@@ -195,7 +195,10 @@ Rules:
Code files: focus on semantic edges AST cannot find (call relationships, shared data, arch patterns).
Do not re-extract imports - AST already has those.
Doc/paper files: extract named concepts, entities, citations.
Doc/paper files: extract named concepts, entities, citations. For rationale (WHY decisions were made,
trade-offs, design intent): store as a `rationale` attribute on the relevant concept node — do NOT
create a separate rationale node. Valid `file_type` values are ONLY `code|document|paper|image` —
never emit `file_type:"rationale"` or `file_type:"concept"`.
Image files: use vision to understand what the image IS - do not just OCR.
UI screenshot: layout patterns, design decisions, key elements, purpose.
Chart: metric, trend/insight, data source.