Skip to content

fix(cache): retry zero-node semantic results - #2931

Open
hopstreax wants to merge 1 commit into
Graphify-Labs:v8from
hopstreax:fix/2927-empty-node-semantic-cache
Open

fix(cache): retry zero-node semantic results#2931
hopstreax wants to merge 1 commit into
Graphify-Labs:v8from
hopstreax:fix/2927-empty-node-semantic-cache

Conversation

@hopstreax

Copy link
Copy Markdown
Contributor

Closes #2927

Summary

Semantic extraction results containing edges but no nodes can currently be
cached as successful results. Because the cache is keyed by content hash, the
file is then treated as unchanged on subsequent incremental runs and is never
redispatched.

This can permanently leave the file without its semantic nodes.

Root Cause

During incremental extraction:

  1. A dispatched file produces an edge-only result:
    nodes=[], edges=[...].
  2. save_semantic_cache() writes the result to the semantic cache.
  3. The manifest records the current semantic hash because edges count as output.
  4. On the next run, the cache entry is treated as a hit.
  5. The file is not redispatched even though its semantic extraction omitted its
    nodes.
  6. The file remains without semantic nodes until it is modified or a forced
    rebuild is performed.

Fix

A semantic extraction is now considered valid for caching and manifest stamping
when it contains:

  • at least one node, or
  • at least one hyperedge.

Edge-only results are therefore treated as incomplete and remain retryable.

The fix:

  • prevents edge-only semantic results from being written to the cache,
  • treats existing zero-node/zero-hyperedge cache entries as cache misses,
  • prevents edge-only results from stamping the semantic manifest,
  • detects and heals already-poisoned manifest state during incremental
    extraction,
  • preserves legitimate hyperedge-only documents.

Tests

Added regression coverage for:

  • edge-only results not being cached,
  • zero-node/zero-hyperedge cache entries being rejected,
  • normal node-containing results remaining cached,
  • hyperedge-only results remaining valid,
  • edge-only semantic results remaining retryable,
  • stale poisoned manifest entries being re-dispatched,
  • hyperedge-only documents not being incorrectly re-queued.

All #2927-focused and adjacent tests pass.

@graphify-labs graphify-labs Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Graphify reviewed this change.

Worth a look — the grounded gate found no coupling regressions or blocking issues, but 3 advisory finding(s) below merit a look before merge.

Formal verification. No changes could be formally verified in this run.


Graphify review — findings

Rejects zero-node/zero-hyperedge semantic extractions (edge-only or empty results) in save_semantic_cache and load_cached, so such files are treated as cache misses and re-dispatched (#2927). Stops stamping the manifest for edge-only semantic output in _stamped_manifest_files (drops edges from the counted collections), and adds _zero_node_stamped_semantic_sources plus dispatch_command wiring to re-queue doc/paper/image files that pre-#2927 manifests already stamped despite having no nodes or hyperedges in graph.json. Adds tests/test_cache.py coverage for edge-only rejection, node/hyperedge-only acceptance, and legacy poisoned-entry healing.

Worth a look

  • Edge-only semantic results silently dropped from cache and manifest, discarding valid edgesgraphify/cache.py:999 · Escalate · medium
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
  • Semantic edge-only cache entries now load as missesgraphify/cache.py:1005 · Escalate · medium
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
  • Semantic heal ignores nodes stored under graph.nodesgraphify/cli.py:454 · Escalate · medium
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 1468 functions depend on the 381 functions this change touches.

Health — this change adds coupling hotspots:

  • new: extract() — 474 callers, 42 callees
  • new: _rebuild_code() — 98 callers, 50 callees
  • new: detect() — 108 callers, 15 callees
  • new: save_semantic_cache() — 58 callers, 11 callees
  • new: load_cached() — 48 callers, 7 callees
  • new: file_hash() — 48 callers, 6 callees
  • new: extract_corpus_parallel() — 26 callers, 11 callees
  • new: dispatch_command() — 2 callers, 120 callees
  • …and 19 more — each is listed as a finding

Verification — 1468 functions in the blast radius were not formally verified this run (proofs are advisory here).

Gate & verification

graphify gate

PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.

Advisory (not blocking):

  • verification_scope: 1152 function(s) in the blast radius were not formally verified this run

Formal verification

Could not verify: Could not verify load\_cached.

The verifier did not have enough to check load\_cached, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `path` is annotated `Path` — outside the synthesizable primitive/collection set

Could not verify: Could not verify save\_semantic\_cache.

The verifier did not have enough to check save\_semantic\_cache, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `root` is annotated `Path` — outside the synthesizable primitive/collection set

Could not verify: Could not verify dispatch\_command.

The verifier did not have enough to check dispatch\_command, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: not verifiable: all 23 sampled inputs raised on both versions — the function never executed, so 'no divergence' would be vacuous (mostly SystemExit — names the real obstacle, not a sampling gap)

Could not verify: Could not verify \_stamped\_manifest\_files.

The verifier did not have enough to check \_stamped\_manifest\_files, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `root` is annotated `Path` — outside the synthesizable primitive/collection set

· 27 more finding(s) on lines outside this diff (see the check run).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Semantic results with edges but no nodes are cached, permanently freezing the file out of the graph

1 participant