feat(kt-db): find_out_of_date_graphs helper (Phase 7 #58)#260
feat(kt-db): find_out_of_date_graphs helper (Phase 7 #58)#260charlie83Gs merged 2 commits intomainfrom
Conversation
Pure-ish helper for the Phase 7 startup auto-dispatch hook. Takes a DB session + plugin registry, returns every active graph whose declared graph_type_id resolves to a registered GraphTypePlugin with a higher current_version than the graph's graph_type_version. Split from the dispatcher so the discovery half is unit-testable without Hatchet. The auto-dispatch call site (#58 workflow wiring) composes this with: - plan_migrations (#254, landed) for the hop list - GraphMigrationRunRepository.most_recent_for_graph (PR #258) for "is anything already in flight?" - graph_migration_wf dispatch (#57) Filters: - status='deleted' skipped (don't resurrect banner) - status='provisioning'/'error' skipped (don't run data migrations on half-built schemas) - graph_type_version >= plugin.current_version skipped (at-current or rollback) - unregistered graph_type_id: LOG + skip (not raise). The runtime resolver falls back to 'default'; auto-dispatch should not fail the whole sweep over a single stale pointer. Per CLAUDE.md fail- fast rule: not silently dropping bad data — the log line surfaces the stale id so ops can fix it. Ordered by created_at for deterministic output — operator tailing logs during a migration rollout sees the same order every boot. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…elta tiebreak
- Status filter inverted from ``status == 'active'`` to
``status.not_in(('deleted', 'provisioning', 'error'))`` — matches
the docstring's exclusion list and makes future statuses
(``archived`` / ``suspended`` / etc.) opt-out rather than opt-in.
Reviewer flagged the drift risk correctly; the inversion moves
the question to "do we skip this?" at review time.
- Test uses ``timedelta(microseconds=1)`` instead of mutating via
``replace()`` — same 1/1M flake guard as PR #258.
- Comment on ``_V2Plugin.migrations()`` + ``_M`` stub explaining the
stub is load-bearing for ``register_graph_type``'s hop-coverage
validator (PR #253), not dead code. Discovery tests don't call
the planner, but they DO call ``register_graph_type``, which is
what needs the migration row.
- New test ``test_unknown_status_is_auto_included`` pins the
inverted-filter contract so a future refactor that silently
narrows back to ``== 'active'`` trips here.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Review fixes applied1. Status filter drift — inverted from `status == 'active'` to `status.not_in(('deleted', 'provisioning', 'error'))`. Docstring and code now match; a future status (`archived`, `suspended`, …) is auto-included in auto-dispatch unless we explicitly skip it, which forces the decision at review time. New test `test_unknown_status_is_auto_included` pins the contract so nobody silently narrows back to `== 'active'` later. 2. `created_at.replace(microsecond=…)` flake — swapped for `first.created_at + timedelta(microseconds=1)`. Same fix pattern as PR #258. 3. `_M` stub "dead code" claim — actually load-bearing. Discovery tests don't call the planner, but they DO call `PluginRegistry.register_graph_type`, which validates (via PR #253) that every hop from v1 to `current_version` has at least one migration declared. Without `_V2Plugin.migrations()` returning the stub, registration would raise and every test for v2 plugin scenarios would fail setup. Added a comment on both the `migrations()` override and the `_M` class explaining this. 4. Load-all-active-graphs — noted as future concern for world-graph vision. No fix this PR (per your note). 5. Plugin ref on `OutOfDateGraph` — bootup-scoped use; kept as-is per your note. 11/11 tests pass (1 new). |
|
I have read the CLA Document and I hereby sign the CLA You can retrigger this bot by commenting recheck in this Pull Request. Posted by the CLA Assistant Lite bot. |
Summary
Pure-ish helper for the Phase 7 startup auto-dispatch hook. Given a DB session + plugin registry, returns every active graph whose `graph_type_id` resolves to a registered `GraphTypePlugin` with a higher `current_version` than the graph's `graph_type_version`.
Split from the eventual dispatcher so discovery is unit-testable without Hatchet. The auto-dispatch call site will compose this with:
Once all three land, the startup hook is ~20 lines of orchestration.
Filtering decisions
Unregistered-plugin posture is deliberate: the runtime resolver falls back to `'default'` for the live pipeline, so writes keep flowing. Auto-dispatch shouldn't fail the whole sweep over one stale pointer. Per CLAUDE.md fail-fast rule this is NOT silent data drop — the WARNING line surfaces the stale id so ops can fix it.
Ordering
Results ordered by `created_at` for deterministic output. Operator tailing logs during a migration rollout sees the same order every boot.
Test plan
🤖 Generated with Claude Code