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:
co-authored by
Claude Sonnet 4.6
parent
a01e0981ed
commit
91f4d120b6
@@ -28,6 +28,15 @@ def build_from_json(extraction: dict) -> nx.Graph:
|
|||||||
hyperedges = extraction.get("hyperedges", [])
|
hyperedges = extraction.get("hyperedges", [])
|
||||||
if hyperedges:
|
if hyperedges:
|
||||||
G.graph["hyperedges"] = 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
|
return G
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+14
-1
@@ -75,8 +75,21 @@ def _hooks_dir(root: Path) -> Path:
|
|||||||
return p
|
return p
|
||||||
except (OSError, FileNotFoundError):
|
except (OSError, FileNotFoundError):
|
||||||
pass
|
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 = root / ".git" / "hooks"
|
||||||
d.mkdir(exist_ok=True)
|
d.mkdir(parents=True, exist_ok=True)
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+4
-1
@@ -195,7 +195,10 @@ Rules:
|
|||||||
|
|
||||||
Code files: focus on semantic edges AST cannot find (call relationships, shared data, arch patterns).
|
Code files: focus on semantic edges AST cannot find (call relationships, shared data, arch patterns).
|
||||||
Do not re-extract imports - AST already has those.
|
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.
|
Image files: use vision to understand what the image IS - do not just OCR.
|
||||||
UI screenshot: layout patterns, design decisions, key elements, purpose.
|
UI screenshot: layout patterns, design decisions, key elements, purpose.
|
||||||
Chart: metric, trend/insight, data source.
|
Chart: metric, trend/insight, data source.
|
||||||
|
|||||||
Reference in New Issue
Block a user