feat(db): add global soft-delete query filter#2998
Merged
Conversation
Contributor
Author
daryllimyt
marked this pull request as ready for review
July 8, 2026 17:36
|
✅ No security or compliance issues detected. Reviewed everything up to ab533d6. Security Overview
Detected Code Changes
|
Contributor
Author
|
@codex review |
Contributor
There was a problem hiding this comment.
All reported issues were addressed across 6 files
Confidence score: 5/5
- Safe to merge after the addressed issues were fixed.
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
|
Codex Review: Didn't find any major issues. You're on a roll. Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
jordan-umusu
approved these changes
Jul 8, 2026
daryllimyt
force-pushed
the
daryl/eng-1519-soft-delete-query-filter
branch
from
July 8, 2026 18:32
98e6f3a to
ab533d6
Compare
Contributor
Author
Merge activity
|
This was referenced Jul 8, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Summary
do_orm_executelistener onSessionapplieswith_loader_criteria(SoftDeleteMixin, deleted_at IS NULL, include_aliases=True)to top-level ORM SELECTs, so soft-deleted rows disappear from product queries by default.with_deleted(stmt)/ theinclude_deletedexecution option, reserved for staging/provenance/sync-reconciliation/erasure helpers (later PRs). Other uses are a review smell.Part of ENG-1517 (version-less resource refs). Stacks on #2931, which introduced
SoftDeleteMixin(columns-only) onAgentPreset. This addresses thewith_loader_criteriasuggestion raised in #2931's review — including its caveats, which are pinned as tests here.Review guide
tracecat/db/soft_delete.py(~80 lines, the whole mechanism): listener guards (is_select and not is_column_load and not is_relationship_load),propagate_to_loaders=False, theINCLUDE_DELETEDexecution option, andassert_soft_delete_listener_registered().Session.get()identity-map hits bypass SQL and therefore the filter; UPDATE/DELETE are unfiltered; Core/text statements are unfiltered.db/engine.py,api/app.py): registration is an import side-effect mirroringsession_events; the API lifespan asserts registration at startup so a missing import fails fast in prod instead of silently no-op'ing. Worker processes get registration transitively viaengine.py.tests/unit/test_soft_delete_filter.py: one test per pinned behavior — entity selects, mapped-column tuple selects (filtered — verified), aliased joins, relationship loads (see tombstones), cold vs warmSession.get(), RLS-bypass sessions (still filtered), UPDATE/DELETE (unfiltered), direct-engine sessions (import wiring canary).AgentPresetService.get_preset(include_deleted=True)/get_preset_by_slug(include_deleted=True)now also set the execution option. All otherdeleted_atpredicates were audited and deliberately left in place — redundant filtering is rollback-safe, and they're stripped only in a later cleanup once this suite has baked.File/case-commentdeleted_atcolumns don't inherit the mixin and are untouched.Note
We will be updating the explicit filters introduced in the original PR upstream
Back-compat / rollback
Validation
uv run pytest tests/unit/test_soft_delete_filter.py— 9 passeduv run ruff check ./format --checkclean;uv run basedpyright --warnings— 0 errors, 0 warningsSummary by cubic
Adds a global ORM SELECT filter to hide soft-deleted rows by default, with a
with_deleted()escape hatch. Part of ENG-1519.New Features
SoftDeleteMixinaddsdeleted_at IS NULLto ORM SELECTs; relationship loads and UPDATE/DELETE remain unfiltered.with_deleted(stmt)for narrow opt-outs;AgentPresetServiceuses it wheninclude_deleted=True.tracecat.db.engine;api/app.pyasserts withassert_soft_delete_listener_registered(). Tests cover SELECTs, joins, relationship loads, cold/warmSession.get(), RLS-bypass, direct-engine sessions, and a subprocess check for engine wiring.Migration
with_deleted(stmt)when tombstones are intentionally required.Written for commit ab533d6. Summary will update on new commits.