Config Agent ChangeSet table

PR #6719 adds the durable schema for Config Agent mutation proposals, approvals, execution state, and receipts without changing runtime behavior.

Author: @mehulshinde PR: dealops#6719 State: open Stacked on: #6689 Linear: DEA-7387 Files: 4 Diff: +155 / -0 Package: packages/prisma

What it adds

One new Prisma model: ConfigAgentChangeSet.

It records proposed mutations, frozen args, computed diffs, approval metadata, execution state, and DB-derived receipts.

What changes

An additive migration creates two enums, one table, two indexes, and two foreign keys.

No existing columns are altered and no existing data is migrated.

What it preserves

The agent still behaves exactly as before.

This PR only lands schema for Phase 0; runtime reads/writes arrive later in T5/T7.

Why now

Migrations have long lead time in this repo.

Landing the schema early keeps Phase 1 runtime work from chasing a moving contract.

ConfigAgentChangeSet
Organization
AgentConversationV3
Worker / job execution
Future approval UI

1. Why this exists

Current failure mode

The agent has no durable mutation memory.

  • AgentConversationV3.body keeps only user / assistant prose.
  • Tool calls are dropped at the end of the turn.
  • Datadog keeps tool names, not queryable per-org mutation facts.
  • recordCatalogMutationReceipt uses request-local memory.
Target invariant

Every proposed mutation becomes a row.

  • The model proposes; code computes the diff.
  • Approval is tied to frozen args and an argsHash.
  • Execution replays stored args, not a fresh model interpretation.
  • Success requires a DB-derived receipt.
Concrete driver: the Xendit incident made the gap visible. The agent said it updated 29 products; it created 70 duplicates. This table is the audit substrate needed to answer “what changed, why, and who approved it” from data instead of chat prose.
Rollout position

This is Phase 0 of the Config Agent ChangeSet rollout, bead dealops-1j00.16 / T16. It is stacked on #6689, so that base PR should merge first.

RFC: rfcs/2026-08-17-config-agent-changeset-runtime.md

2. What changes

Migration shape
Enums2 CREATE TYPE
Tables1 CREATE TABLE
Indexes2 CREATE INDEX
Foreign keys2 ALTER TABLE
Destructive changes0
Files touched
packages/prisma/migrations/20260819235606_add_config_agent_changeset/migration.sql+41
packages/prisma/schema/models/v3/config-agent-changeset.prisma+108
packages/prisma/schema/models/organizations.prisma+3
packages/prisma/schema/models/v3/config-agent.prisma+3

New table: ConfigAgentChangeSet

Scope + subject

  • idString @id uuid
  • orgIdOrganization FK
  • conversationIdAgentConversationV3 FK

Proposal payload

  • toolNameString
  • landingZonedraft | live
  • argsJson
  • argsHashString
  • diffJson

Approval audit

  • statusenum default proposed
  • proposedByString
  • approvedByString?
  • approvedAtDateTime?

Execution record

  • jobIdString?
  • executionLeaseExpiresAtDateTime?
  • receiptJson?
  • executedAtDateTime?
  • completedAtDateTime?

Relationships added to existing models

Model New relation field Delete behavior Reasoning
Organization configAgentChangeSets ConfigAgentChangeSet[] Cascade Org deletion should take org-scoped audit rows with it. The direct org FK also lets sandbox extraction derive scoping without a registry override.
AgentConversationV3 changeSets ConfigAgentChangeSet[] Restrict Conversation rows are audit pointers, not containers. If hard-delete is added later, it should not silently delete mutation audit records.

Enums and indexes

Lifecycle enum
proposed approved queued executing applied failed superseded
Query paths
  • @@index([orgId, createdAt]) supports audit reads: newest changes for an org.
  • @@index([conversationId, status]) supports runtime reads: pending / in-flight rows for one thread.

3. How it works

Important boundary

This PR does not implement the runtime. It defines the database contract that T5/T7 will use.

The intended flow below comes from the PR description and schema comments.

1
Propose
Agent selects tool + args, but does not write catalog data.
2
Compute
Code computes the diff and inserts status: proposed.
3
Approve
UI renders from the row, including draft vs live.
4
Claim
Worker sets execution state and lease to avoid wedged rows.
5
Replay
Worker replays exact stored args, revalidating in the write transaction.
6
Receipt
Success requires DB-derived receipt; no receipt means no success claim.
Frozen input contract

args and argsHash are intended to be immutable from proposed onward.

Approval should validate against the matching (id, argsHash) pair, then execution should replay the stored payload.

Landing zone clarity

landingZone is explicit: draft or live.

This supports approval copy like “stages 17 drafts” versus “creates this pricebook LIVE” using data, not model narration.

Lease decision

executionLeaseExpiresAt is included even though it is beyond the bead’s original column list.

Reason: an atomic worker claim cannot safely model executing recovery without lease expiry. This follows the existing catalogDirectMutationState.executionLeaseExpiresAt pattern.

Actor storage

proposedBy and approvedBy are plain strings, not user foreign keys.

Reason: an audit row should not fail to write, or become undeletable, because of user-table state.

Expected volume

Row count

One mutation intent = one row.

A CSV import with N product rows is still one ChangeSet because the tool takes a file pointer and reconciles server-side.

Estimated monthly usage

Prod-replica keyword proxy: about 3–5 rows per session and 150–250 rows/month org-wide.

Inputs: 182 threads, 14 orgs, May–Aug 2026.

Payload watchpoint

Row count is not the risk. JSON payload size is.

A full-catalog import could put roughly 2.4 MB into one diff for the largest current org.

4. What it doesn't change

Explicit non-goals in this PR

5. Risks / rollback / open questions

Dependency risk: this PR is stacked on #6689. Merge the base branch first to avoid applying this schema work against the wrong migration history.
Rollback

Rollback is simple while no runtime writes exist:

  1. Do not deploy code that writes the table.
  2. Drop ConfigAgentChangeSet.
  3. Drop ConfigAgentChangeSetStatus and ConfigAgentChangeSetLandingZone.
Validation already reported
  • prisma validate clean.
  • apps/server typecheck clean.
  • 390/390 configAgent Jest tests green.
  • Sandbox extraction scoping resolves via direct org FK.
Open Phase 3 choice: diff is JSON, and large imports can make it heavy. The compact representation and retention policy are still RFC questions.
Deployment note: the migration was applied only to the Neon dev branch per the PR notes. Production still needs an explicit deploy plan.