Files
graphify/graphify/__init__.py
T
safishamsi 89dd00f140 feat: self-improving work-memory — save-result outcomes + graphify reflect (#1441)
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>
2026-06-24 11:43:13 +01:00

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}")