Skip to content

fix(db): cascade policy_results when deleting a policy (FK 500) - #23

Merged
iaj6 merged 1 commit into
mainfrom
fix/delete-policy-fk
Jul 12, 2026
Merged

iaj6 merged 1 commit into
mainfrom
fix/delete-policy-fk

Conversation

@iaj6

@iaj6 iaj6 commented Jul 12, 2026

Copy link
Copy Markdown
Owner

Summary

From the July audit: deleting any policy that had ever been evaluated threw SQLITE_CONSTRAINT_FOREIGNKEY and the dashboard DELETE 500'd. Since finalizeRun writes one policy_results row per active policy on every completed run, this made policies effectively undeletable in normal operation.

  • deletePolicy now deletes policy_results children first inside a transaction (mirroring the deleteOldRuns pattern) and returns how many evaluation rows were removed.
  • The DELETE route surfaces the count ({ok: true, deletedResults: N}) and records it in the audit-log metadata, so an admin deleting a heavily-evaluated policy leaves a trace of how much history went with it.

Tests

  • db-level: evaluated policy deletes cleanly under foreign_keys = ON; other policies' results untouched; never-evaluated policy reports 0.
  • route-level: DELETE returns 200 for an evaluated policy (the exact request that used to 500).

Full workspace suite green (1,292 tests).

🤖 Generated with Claude Code

policy_results.policy_id is NOT NULL REFERENCES policies(id) with no ON
DELETE CASCADE, connections run foreign_keys = ON, and finalizeRun writes
one result row per active policy on every completed run. So once a single
run completed, deleting any policy threw SQLITE_CONSTRAINT_FOREIGNKEY and
the dashboard's DELETE 500'd — policies were effectively undeletable in
normal operation.

deletePolicy now deletes children-first inside a transaction (same
pattern as deleteOldRuns) and returns the number of evaluation rows that
went with the policy; the route surfaces that count in the response and
in the audit-log entry.

Tests: db-level regression (evaluated policy deletes cleanly, sibling
policies' results untouched, fresh policy reports 0) plus a route-level
regression asserting DELETE returns 200 for an evaluated policy.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@iaj6
iaj6 merged commit f5b3090 into main Jul 12, 2026
3 checks passed
@iaj6
iaj6 deleted the fix/delete-policy-fk branch July 12, 2026 14:15
iaj6 added a commit that referenced this pull request Jul 12, 2026
…24)

Doc/config drift flagged by the July audit:

- CLAUDE.md was the stalest file in the repo and actively misled agent
  sessions: claimed 6 policy types incl. a nonexistent RequiredApproval
  (actual: 8, with guard/check modes), "eight tables" (actual: 16 — the
  whole auth/webhook/audit/budget layer was missing), no mention of the
  auth model, login/doctor/user/admin/cleanup commands, or the transcript
  cost pipeline. Also marks the jobs/locks/dispatch layer as vestigial
  and documents the stale-dist gotcha for web tests.
- CHANGELOG now covers the June audit sweep (PRs #1-#16) and the July
  revival audit (PRs #17-#23); previously it stopped before both.
- `agentops serve` printed "The API is currently unauthenticated" when
  binding beyond localhost — false since the auth layer shipped. The
  warning now says what's true: auth is required, but traffic is plain
  HTTP, so use the caddy profile beyond a trusted LAN.
- Litestream sidecar mounted the DB read-only, which breaks replication
  outright (litestream needs the checkpoint lock + sidecar files). Now
  rw, with a comment explaining why. The S3-compatible endpoint comment
  now says explicitly that setting AGENTOPS_S3_ENDPOINT alone does
  nothing while the config line stays commented.
- scripts/demo-seed.mjs (previously untracked) is committed, now gated
  behind --yes since it wipes runs/events/policy_results/run_metrics.
- packages/cli/src/build-info.ts is generated on every build, so the
  working tree was permanently dirty. Gitignored; the generator now also
  runs as pretest so fresh clones can run cli tests before a build.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
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