Config Agent ChangeSet table
PR #6719 adds the durable schema for Config Agent mutation proposals, approvals, execution state, and receipts without changing runtime behavior.
One new Prisma model: ConfigAgentChangeSet.
It records proposed mutations, frozen args, computed diffs, approval metadata, execution state, and DB-derived receipts.
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.
The agent still behaves exactly as before.
This PR only lands schema for Phase 0; runtime reads/writes arrive later in T5/T7.
Migrations have long lead time in this repo.
Landing the schema early keeps Phase 1 runtime work from chasing a moving contract.
1. Why this exists
The agent has no durable mutation memory.
AgentConversationV3.bodykeeps only user / assistant prose.- Tool calls are dropped at the end of the turn.
- Datadog keeps tool names, not queryable per-org mutation facts.
recordCatalogMutationReceiptuses request-local memory.
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.
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
packages/prisma/migrations/20260819235606_add_config_agent_changeset/migration.sql+41packages/prisma/schema/models/v3/config-agent-changeset.prisma+108packages/prisma/schema/models/organizations.prisma+3packages/prisma/schema/models/v3/config-agent.prisma+3New table: ConfigAgentChangeSet
Scope + subject
idString @id uuidorgIdOrganization FKconversationIdAgentConversationV3 FK
Proposal payload
toolNameStringlandingZonedraft | liveargsJsonargsHashStringdiffJson
Approval audit
statusenum default proposedproposedByStringapprovedByString?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
@@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
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.
status: proposed.draft vs live.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.
landingZone is explicit: draft or live.
This supports approval copy like “stages 17 drafts” versus “creates this pricebook LIVE” using data, not model narration.
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.
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
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.
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.
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
- No Config Agent runtime reads or writes
ConfigAgentChangeSetyet. - No tRPC route, worker, approval UI, or SSE status path is added.
- No existing table column is altered.
- No existing data is migrated or backfilled.
- No production database has been migrated by this PR text.
- No unrelated Prisma formatting churn is included; the PR notes that v2 model reformatting was reverted.
- No behavior changes for current conversations, tool execution, or catalog writes.
5. Risks / rollback / open questions
#6689. Merge the base branch first to avoid applying this schema work against the wrong migration history.
Rollback is simple while no runtime writes exist:
- Do not deploy code that writes the table.
- Drop
ConfigAgentChangeSet. - Drop
ConfigAgentChangeSetStatusandConfigAgentChangeSetLandingZone.
prisma validateclean.apps/servertypecheck clean.390/390configAgent Jest tests green.- Sandbox extraction scoping resolves via direct org FK.
diff is JSON, and large imports can make it heavy. The compact representation and retention policy are still RFC questions.