Skip to content

fix(agent): make preset deletion a soft delete#2931

Merged
daryllimyt merged 14 commits into
mainfrom
daryl/fix-agent-preset-archive-core
Jul 8, 2026
Merged

fix(agent): make preset deletion a soft delete#2931
daryllimyt merged 14 commits into
mainfrom
daryl/fix-agent-preset-archive-core

Conversation

@daryllimyt

@daryllimyt daryllimyt commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Agent preset deletion becomes a soft delete: presets get deleted_at via a new columns-only SoftDeleteMixin, preserving published version history while hiding deleted rows from active product surfaces.
  • Slug uniqueness moves to a partial unique index uq_agent_preset_workspace_slug_active on (workspace_id, slug) WHERE deleted_at IS NULL, so a deleted preset frees its slug immediately.
  • Hardens active lookup paths: preset/skill delete guards, version reads, folders/tags/integrations, Slack channel tokens, and Slack OAuth all reject or disable soft-deleted presets.

This PR is the root of the ENG-1517 stack (version-less resource refs with HEAD-pointer pinning). It was reworked from the earlier archived_at naming so presets never need a rename migration later; the follow-up sync PR #2932 was closed as superseded by ENG-1517 stack 3.

Review guide

  • Start with tracecat/db/models.py: SoftDeleteMixin (columns-only, per repo rule) applied to AgentPreset; Skill keeps its own archived_at column untouched (skills migrate in a later PR).
  • Migration alembic/versions/32b7a1f4d9c2_add_agent_preset_soft_delete.py: revises 11d479597e08 (reparented after restack), adds deleted_at, swaps the full slug constraint for the partial index. Downgrade is honest: it recreates the full constraint only after checking no reused slugs would violate it, otherwise raises with an explanation.
  • Services/routers/sync adapters: mechanical archived_at → deleted_at rename for presets plus the original hardening logic; no behavior change beyond the rename and index swap.
  • Tests (~1.3k lines): each pins one invariant (docstring on each test); key ones — deleted preset frees its slug for reuse; deleted presets are excluded from active lookups, channel tokens, and Slack OAuth; version history survives deletion.

Back-compat / rollback

  • Purely additive schema change plus a constraint→partial-index swap; no data destroyed. App rollback keeps working (old code never reads deleted_at).
  • No API schema exposes the column yet, so no client regen in this PR.

Validation

  • uv run ruff check . / uv run ruff format --check . — clean
  • uv run basedpyright --warnings — 0 errors, 0 warnings
  • uv run pytest focused suites: 187 passed (preset/skill/channels/folders/activities) + 88 passed (workspace-sync acceptance contract), against a live cluster DB with the migration applied
  • uv run alembic heads — single head 32b7a1f4d9c2

Copy link
Copy Markdown
Contributor Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@daryllimyt daryllimyt added fix Bug fix agents LLM agents api Improvements or additions to the backend API migration Database migration tests Changes to unit and integration tests labels Jul 1, 2026
@daryllimyt
daryllimyt marked this pull request as ready for review July 1, 2026 17:44
@zeropath-ai

zeropath-ai Bot commented Jul 1, 2026

Copy link
Copy Markdown

No security or compliance issues detected. Reviewed everything up to 44a50a0.

Security Overview
Detected Code Changes
Change Type Relevant files
Enhancement ► tests/unit/test_agent_channel_management_router.py
    Update Slack OAuth-related route tests and callback handling

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7e7dd43e83

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

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".

Comment thread tracecat/agent/preset/service.py Outdated
Comment thread tracecat/agent/skill/service.py Outdated

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

2 issues found across 17 files

Confidence score: 2/5

  • In tracecat/agent/preset/service.py, resolve_agent_preset_version() can still return a version when a pinned preset_version_id points to an archived preset, which bypasses the active-preset guard and could let retired configuration continue running in production — block archived presets in the pinned-version path before merging.
  • In tracecat/agent/channels/router.py, require_active_preset_for_token throws TracecatNotFoundError with a generic “not found” message that is then handled by the existing except TracecatNotFoundError branch, risking incorrect error mapping/response semantics for inactive presets — raise a distinct error (or adjust the handler) so inactive-vs-missing presets are handled explicitly before merge.

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread tracecat/agent/preset/service.py Outdated
Comment thread tracecat/agent/channels/router.py

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fa0ac84e85

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

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".

Comment thread tracecat/workspace_sync/adapters/agent_preset.py Outdated
Comment thread tracecat/agent/skill/service.py

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

2 issues found across 8 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="tracecat/agent/skill/service.py">

<violation number="1" location="tracecat/agent/skill/service.py:2254">
P2: The archived skill check is only enforced in the LATEST resolution path (`_get_latest_skill_refs_for_preset_version`). In non-LATEST/pinned mode, the exact-version branch of `get_resolved_skill_refs_for_preset_version()` still returns `SkillVersion` rows without verifying `Skill.archived_at`. This means a user can archive a skill and still execute an older pinned preset version that references it, bypassing the new archived-skill restrictions. Consider adding the same `Skill.archived_at` check to the exact-version resolution path for consistency.</violation>
</file>

<file name="tracecat/workspace_sync/adapters/agent_preset.py">

<violation number="1" location="tracecat/workspace_sync/adapters/agent_preset.py:415">
P2: The `archived_at` predicates added here filter the preset rows being imported via `plan_name_swap`, but the subagent target resolution step (`_resolved_subagent_target()`) still queries `AgentPreset` by workspace and slug without an `archived_at IS NULL` condition. If a parent preset references a slug that belongs to an archived preset, the import could persist the archived child's `preset_id` into the active parent's `agents` config, after which runtime resolution would reject the child as not found. Consider applying the same active-preset predicate to subagent target lookups.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread tracecat/agent/skill/service.py
Comment thread tracecat/workspace_sync/adapters/agent_preset.py Outdated

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 645dfeb16b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

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".

Comment thread tracecat/agent/preset/service.py Outdated
@daryllimyt
daryllimyt force-pushed the daryl/fix-agent-preset-archive-core branch from b4ba2f8 to 8c27e97 Compare July 3, 2026 21:17

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8c27e97d4c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

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".

Comment thread tracecat/agent/skill/service.py

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d25d57d44a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

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".

Comment thread tracecat/agent/preset/service.py
@daryllimyt
daryllimyt force-pushed the daryl/fix-agent-preset-archive-core branch from 1ea94df to af9cb5d Compare July 8, 2026 16:01
@daryllimyt daryllimyt changed the title fix(agent): archive deleted presets safely fix(agent): make preset deletion a soft delete Jul 8, 2026

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: af9cb5d8fe

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

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".

Comment thread tracecat/agent/preset/service.py
Comment thread tracecat/agent/skill/service.py
@daryllimyt
daryllimyt force-pushed the daryl/fix-agent-preset-archive-core branch from af9cb5d to 4a091aa Compare July 8, 2026 16:14

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4a091aae38

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

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".

Comment thread tracecat/agent/preset/service.py
@daryllimyt
daryllimyt force-pushed the daryl/fix-agent-preset-archive-core branch from 4a091aa to 44a50a0 Compare July 8, 2026 16:47
@daryllimyt
daryllimyt requested a review from jordan-umusu July 8, 2026 16:53
@daryllimyt daryllimyt added the priority:critical Critical priority ticket — drop everything label Jul 8, 2026

@jordan-umusu jordan-umusu left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM one known concern

Comment thread tracecat/agent/folders/service.py
@daryllimyt
daryllimyt merged commit 3201a4c into main Jul 8, 2026
16 checks passed
@daryllimyt
daryllimyt deleted the daryl/fix-agent-preset-archive-core branch July 8, 2026 17:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents LLM agents api Improvements or additions to the backend API fix Bug fix migration Database migration priority:critical Critical priority ticket — drop everything tests Changes to unit and integration tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants