You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(graph): refresh preserved dependent nodes on increment (PR-P4) (#343)
PR-P2 replaced the per-row `_MERGE_SYMBOL` upsert in `_write_nodes_impl` with a
skip-if-exists filter, which dropped the property refresh on preserved dependent
type nodes. A dependent's `role`/`capabilities` depend on project-wide inputs
(meta-annotation chain, brownfield overrides) and can shift without its own
source changing, so the incremental graph diverged from a full rebuild — a
preserved dependent whose role lever changed stayed stale until the next full
rebuild. The `_delete_file_scope` contract (issue #305) relied on that re-MERGE
to refresh preserved dependents in place.
Found by fanning out reviewer subagents over the landed init/increment-perf plan
and adjudicating a B-vs-D conflict empirically (the "benign" verdict came from a
reviewer that couldn't run ladybug; the "bug" verdict reproduced).
Changes:
- Mark `TypeIndexEntry`/`MemberEntry` `loaded_from_db` when
`_load_existing_{types,members}` creates them, so DB-loaded stubs (placeholder
decls) are distinguishable from freshly-parsed scoped/dependent decls.
- After the bulk COPY of new nodes, re-SET every mutable Symbol field on
preserved, non-stub, type-kind nodes (`_SET_SYMBOL_BY_ID`), restoring the
upsert the design relied on. Stubs are skipped (their stored values are
authoritative); non-type kinds carry no mutable role/capabilities; the full
path is unaffected (empty DB → no existing nodes).
- `_populate_declares_rows` skips loaded members: their DECLARES edges already
persist and re-emitting duplicated them (REL tables carry no PK). This second
incremental≠full divergence surfaced once the equivalence test was fixed.
- Delete dead `_existing_symbol_ids` (zero callers); correct the Route-MERGE
loop comment (it iterates all routes, not phantoms).
Tests:
- `test_incremental_bulk_write_equivalent_to_full_rebuild` now asserts real
incremental≡full equivalence (node count, per-type edge counts, type roles)
instead of the prior tautology (`set(keys)==set(keys)` + `count>0`).
- New `test_incremental_refreshes_dependent_role_on_meta_chain_change` guards
the exact regression.
- Rename `test_bulk_write_edges_match_per_row_baseline` →
`test_bank_chat_bulk_build_matches_committed_baseline`: the per-row path is
gone, so the fixture (bulk-generated) is a drift anchor, not a per-row proof.
Known follow-ups (out of scope): converting the remaining per-row Route MERGE
to bulk; OVERRIDES may have an analogous duplication for cross-file pairs;
annotation-definition edits don't pull annotation-users into incremental scope
(a separate, pre-existing scope gap, not the upsert regression fixed here).
Co-authored-by: Claude <noreply@anthropic.com>
0 commit comments