Skip to content

feat(server): Phase 0: add control version history and soft-delete unusable legacy controls#172

Open
lan17 wants to merge 2 commits intomainfrom
feature/control-phase-0
Open

feat(server): Phase 0: add control version history and soft-delete unusable legacy controls#172
lan17 wants to merge 2 commits intomainfrom
feature/control-phase-0

Conversation

@lan17
Copy link
Copy Markdown
Contributor

@lan17 lan17 commented Apr 16, 2026

Summary

This is the first step in the control lifecycle work. It introduces version history for controls and cleans up legacy rows that no longer satisfy the control contract, so later phases can build on a consistent base.

Design doc and implementation plan: https://gist.github.com/lan17/6a08282243576f096626bb10996c024b

What changed

The migration adds controls.deleted_at, replaces the old global name uniqueness constraint with an active-only unique index, and creates the new control_versions table. Every existing control is backfilled into version history as version 1.

During that backfill, we validate each existing control against the shapes we still support today: normal control definitions and unrendered templates. Controls that are empty, corrupted, or otherwise unusable are automatically soft-deleted. Before tombstoning them, the migration removes any policy, agent, or store associations so we do not leave active references behind.

At runtime, active control lookups now consistently ignore soft-deleted rows. GET /api/v1/controls/{id} no longer returns a successful response with data: null; if an active row is corrupted, we surface that as corrupted data instead. Deletes now tombstone the control rather than hard-deleting it, which keeps the newly backfilled version history intact.

The shared API model and generated SDK surfaces were updated to match that tighter contract, and the server tests now cover migration backfill, automatic legacy cleanup, and soft-delete filtering across the affected paths.

Why this shape

We want later phases to assume a clean, explicit control lifecycle instead of carrying around {} controls and other invalid legacy cases. Doing that cleanup here keeps the follow-on work simpler and makes the new version table immediately trustworthy.

Reviewer notes

The migration is the part worth the closest look. In particular:

  • backfill snapshots and version numbering for existing rows
  • automatic cleanup for unusable legacy controls
  • soft-delete filtering across control reads, listings, and agent/policy associations
  • the non-null GetControlResponse.data contract

Validation

  • make check
  • make openapi-spec-check
  • make sdk-ts-generate
  • make sdk-ts-overlay-test
  • make sdk-ts-name-check
  • fresh review-loop pass against origin/main with no findings

@codecov
Copy link
Copy Markdown

codecov bot commented Apr 16, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@lan17 lan17 changed the title [codex] Implement control phase 0 cleanup Add control version history and soft-delete unusable legacy controls Apr 16, 2026
@lan17 lan17 changed the title Add control version history and soft-delete unusable legacy controls feat(server): add control version history and soft-delete unusable legacy controls Apr 16, 2026
@lan17 lan17 marked this pull request as ready for review April 16, 2026 03:18
@lan17 lan17 changed the title feat(server): add control version history and soft-delete unusable legacy controls feat(server): Phase 0: add control version history and soft-delete unusable legacy controls Apr 16, 2026
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.

1 participant