#796: add edge_data()/edge_datas() helpers in build.py that tolerate
MultiGraph/MultiDiGraph; replace all G.edges[u,v] 2-tuple call sites in
__main__.py, serve.py, wiki.py, export.py, analyze.py, benchmark.py;
fix same pattern in 10 skill file inline heredocs
#795: all 12 skill files now short-circuit on /graphify --help or -h
and print the Usage block without running any pipeline steps
#792 (hollow response): add _response_is_hollow() predicate in llm.py;
when Ollama (or any backend) returns empty/null/whitespace content or a
parsed result with no nodes/edges, rewrite finish_reason="length" so
_extract_with_adaptive_retry bisects the chunk instead of silently
dropping it; applied to _call_openai_compat, _call_claude, _call_bedrock
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Users running `graphify update .` against a graph that contains nodes
preserved from older graphify versions see the warning:
[graphify] Extraction warning (31 issues): Node 1661 (id='telepathy_app')
has invalid file_type 'None' - must be one of [...]
The cause: `_rebuild_code` in watch.py preserves nodes from the existing
graph.json that aren't in the new AST output. Some of those nodes
(stubs, semantic concepts created before file_type was always
populated) have file_type=null in the on-disk JSON, which becomes
Python None on load. The validator in validate.py:33 then flags every
such node.
Add a normalization step in `build_from_json` next to the existing
`source` -> `source_file` legacy canonicalization: if a node's
file_type is None or empty, default it to "concept" before validation.
This silences the false positive while keeping the validator strict for
genuinely invalid values like "weird_type".