mirror of
https://github.com/safishamsi/graphify.git
synced 2026-07-16 20:37:08 +00:00
89dd00f140
Adds the deterministic work-memory loop: `save-result --outcome useful|dead_end|corrected [--correction]` records how a saved Q&A turned out, and `graphify reflect` aggregates graphify-out/memory/ into a deterministic reflections/LESSONS.md an agent loads next session. Source nodes are scored, not counted: signed, recency-decayed (useful +, dead_end/corrected -, configurable --half-life-days, default 30), so a fresh dead end outweighs a stale useful. A node is "preferred" only once corroborated by >=--min-corroboration distinct results (default 2); others are "tentative", and mixed-signal nodes render once as "contested" (recency-wins). Source nodes are matched to the graph by label OR id, and citations whose node no longer exists are dropped, so a plain `graphify update` after deleting code clears stale lessons. Deterministic, no LLM; bare save-result and existing behavior unchanged. Rigorously verified end-to-end on real data: corroboration boundary, recency flip, contested verdict, foreign/malformed memory docs, cold start, 300-doc scale + byte-stable output, and the node-gate dropping deleted-code lessons after update. Full suite 2383 passed; skillgen --check clean; ruff clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
31 lines
1.4 KiB
Python
31 lines
1.4 KiB
Python
"""graphify - extract · build · cluster · analyze · report."""
|
|
|
|
|
|
def __getattr__(name):
|
|
# Lazy imports so `graphify install` works before heavy deps are in place.
|
|
_map = {
|
|
"extract": ("graphify.extract", "extract"),
|
|
"collect_files": ("graphify.extract", "collect_files"),
|
|
"build_from_json": ("graphify.build", "build_from_json"),
|
|
"cluster": ("graphify.cluster", "cluster"),
|
|
"score_all": ("graphify.cluster", "score_all"),
|
|
"cohesion_score": ("graphify.cluster", "cohesion_score"),
|
|
"god_nodes": ("graphify.analyze", "god_nodes"),
|
|
"surprising_connections": ("graphify.analyze", "surprising_connections"),
|
|
"suggest_questions": ("graphify.analyze", "suggest_questions"),
|
|
"generate": ("graphify.report", "generate"),
|
|
"to_json": ("graphify.export", "to_json"),
|
|
"to_html": ("graphify.export", "to_html"),
|
|
"to_svg": ("graphify.export", "to_svg"),
|
|
"to_canvas": ("graphify.export", "to_canvas"),
|
|
"to_wiki": ("graphify.wiki", "to_wiki"),
|
|
"reflect": ("graphify.reflect", "reflect"),
|
|
"save_query_result": ("graphify.ingest", "save_query_result"),
|
|
}
|
|
if name in _map:
|
|
import importlib
|
|
mod_name, attr = _map[name]
|
|
mod = importlib.import_module(mod_name)
|
|
return getattr(mod, attr)
|
|
raise AttributeError(f"module 'graphify' has no attribute {name!r}")
|