Skip to content

fix(ledger): add internal foreign keys - #4652

Merged
GAlexIHU merged 3 commits into
mainfrom
codex/ledger-data-layer-fks
Jul 10, 2026
Merged

fix(ledger): add internal foreign keys#4652
GAlexIHU merged 3 commits into
mainfrom
codex/ledger-data-layer-fks

Conversation

@GAlexIHU

@GAlexIHU GAlexIHU commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add ledger-internal foreign keys for ledger_customer_accounts.account_id and ledger_breakage_records ledger references.
  • Keep external ids such as customer and charge ids as soft references.
  • Regenerate Ent code and add the Atlas migration with the new FK constraints marked NOT VALID for deploy safety.
  • Add an OSS migration guide with the post-migration validation commands.

Deploy Callout

After the migration has been applied, run the manual validation commands below after orphan preflight is clean:

SET lock_timeout = '5s';
SET statement_timeout = '0';

ALTER TABLE ledger_breakage_records VALIDATE CONSTRAINT ledger_breakage_records_ledger_breakage_records_planned_release;
ALTER TABLE ledger_breakage_records VALIDATE CONSTRAINT ledger_breakage_records_ledger_breakage_records_release_reopens;
ALTER TABLE ledger_breakage_records VALIDATE CONSTRAINT ledger_breakage_records_ledger_entries_source_breakage_records;
ALTER TABLE ledger_breakage_records VALIDATE CONSTRAINT ledger_breakage_records_ledger_sub_accounts_breakage_records;
ALTER TABLE ledger_breakage_records VALIDATE CONSTRAINT ledger_breakage_records_ledger_sub_accounts_fbo_breakage_record;
ALTER TABLE ledger_breakage_records VALIDATE CONSTRAINT ledger_breakage_records_ledger_transaction_groups_breakage_reco;
ALTER TABLE ledger_breakage_records VALIDATE CONSTRAINT ledger_breakage_records_ledger_transaction_groups_source_breaka;
ALTER TABLE ledger_breakage_records VALIDATE CONSTRAINT ledger_breakage_records_ledger_transactions_breakage_records;
ALTER TABLE ledger_breakage_records VALIDATE CONSTRAINT ledger_breakage_records_ledger_transactions_source_breakage_rec;

ALTER TABLE ledger_customer_accounts VALIDATE CONSTRAINT ledger_customer_accounts_ledger_accounts_customer_accounts;

Validation

  • nix develop --impure .#ci -c atlas migrate --env local hash
  • nix develop --impure .#ci -c atlas migrate --env local diff ledger_internal_fks_check
  • nix develop --impure .#ci -c make generate
  • nix develop --impure .#ci -c go vet -tags=dynamic ./openmeter/ledger/...
  • nix develop --impure .#ci -c env POSTGRES_HOST=127.0.0.1 go test -tags=dynamic ./openmeter/ledger/...

Summary by CodeRabbit

  • New Features

    • Expanded ledger relationships with additional edges linking customer accounts, breakage records, and source breakage records.
    • Added stricter internal ledger foreign-key enforcement, including self-referential and cross-table relationships, with deletes restricted where appropriate.
  • Bug Fixes

    • Improved breakage adapter test data generation to reliably seed expired records and derive record identifiers from committed transactions/groups.
  • Documentation

    • Added a migration guide covering “Ledger Internal Foreign Key Validation,” including NOT VALID rollout and manual post-deployment validation steps.

Greptile Summary

This PR adds internal ledger foreign keys and rollout guidance. The main changes are:

  • New Ent relationships for ledger customer accounts and breakage records.
  • A migration that adds ledger-owned foreign keys with deferred validation.
  • Regenerated Ent query, mutation, and migration metadata.
  • Updated breakage adapter tests that create real ledger references.
  • A migration guide with manual constraint validation commands.

Confidence Score: 5/5

This looks safe to merge from the follow-up changes reviewed here.

  • No new blocking issue cleared the follow-up selection bar.
  • The latest changes stay within the existing ledger foreign-key rollout area.
  • The adjusted tests now create real ledger references for the new constraints.

Important Files Changed

Filename Overview
tools/migrate/migrations/20260709134422_add_ledger_internal_fks.up.sql Adds deferred-validation foreign keys for ledger breakage records and customer accounts.
openmeter/ent/schema/ledger_breakage_record.go Defines internal breakage-record relationships over existing ledger reference fields.
openmeter/ent/schema/ledger_customer_account.go Links customer account mappings to ledger accounts through the existing account id.
openmeter/ledger/breakage/adapter/record_test.go Updates test records to use persisted ledger transactions and sub-accounts.

Reviews (5): Last reviewed commit: "fix(ledger): move FK migration to tail" | Re-trigger Greptile

Context used (3)

  • Context used - CLAUDE.md (source)
  • Context used - AGENTS.md (source)
  • Context used - api/spec/AGENTS.md (source)

@GAlexIHU GAlexIHU added the release-note/ignore Ignore this change when generating release notes label Jul 6, 2026
@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR adds Ent edges and internal foreign keys for ledger breakage and customer-account relationships, introduces a NOT VALID migration with manual validation guidance, and updates breakage adapter fixtures to seed records through committed historical ledger transactions.

Changes

Ledger internal FK wiring

Layer / File(s) Summary
LedgerBreakageRecord edges and related wiring
openmeter/ent/schema/ledger_breakage_record.go, ledger_account.go, ledger_entry.go, ledger_transaction.go, ledger_transaction_group.go
Adds FK-backed breakage, source, sub-account, and self-referential plan/release edges, with matching outgoing edges and restrictive delete behavior.
LedgerCustomerAccount account_id typing and edge
openmeter/ent/schema/ledger_customer_account.go
Sets account_id to Postgres char(26) and adds a required, immutable, unique edge to LedgerAccount.
SQL migration and migration guide
tools/migrate/migrations/20260709134422_add_ledger_internal_fks.up.sql, ...down.sql, docs/migration-guides/2026-07-07-ledger-internal-foreign-keys.md
Adds and reverses NOT VALID foreign keys, changes the account ID column type, and documents manual constraint validation.
Breakage adapter test helper refactor
openmeter/ledger/breakage/adapter/record_test.go
Resolves route-based sub-accounts, commits historical transactions, derives record IDs, and expands feature and currency fixtures.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Test as record_test.go
  participant Helper as newExpiredRecord
  participant Ledger as HistoricalLedger
  participant Records as breakage.Record

  Test->>Helper: newExpiredRecord(env, currency, name, features, expiresAt)
  Helper->>Helper: GetSubAccountForRoute for FBO and breakage
  Helper->>Ledger: CommitGroup(AnyTransactionInput at expiresAt)
  Ledger-->>Helper: committed group and transaction IDs
  Helper->>Records: build record with derived IDs and annotations
  Records-->>Test: seeded expired record
Loading

Suggested reviewers: turip, chrisgacsal

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: adding internal foreign keys in the ledger schema.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/ledger-data-layer-fks

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@GAlexIHU
GAlexIHU marked this pull request as ready for review July 6, 2026 14:41
@GAlexIHU
GAlexIHU requested a review from a team as a code owner July 6, 2026 14:41
@greptile-apps

greptile-apps Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds ledger-internal foreign keys and generated Ent relationships. The main changes are:

  • New constraints for ledger_customer_accounts.account_id and ledger_breakage_records ledger references.
  • Regenerated Ent edge/query/mutation code for the new relationships.
  • An Atlas migration and operator guide for validating the new constraints.

Confidence Score: 5/5

This looks safe to merge.

  • No blocking issues found in the changed code.

Important Files Changed

Filename Overview
tools/migrate/migrations/20260706130134_add_ledger_internal_fks.up.sql Adds the ledger-internal foreign-key constraints used by the migration.
openmeter/ent/schema/ledger_breakage_record.go Defines ledger breakage record edges for source, breakage, sub-account, plan, and release references.
openmeter/ent/schema/ledger_customer_account.go Defines the customer account to ledger account relationship over account_id.
docs/migration-guides/2026-07-07-ledger-internal-foreign-keys.md Documents the post-migration validation steps for the new constraints.

Reviews (2): Last reviewed commit: "docs(ledger): add FK migration guide" | Re-trigger Greptile

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@openmeter/ent/schema/ledger_breakage_record.go`:
- Around line 130-187: The LedgerBreakageRecord schema is still missing indexes
on several foreign key fields, causing parent-table deletes to scan this table.
Update the Edges definition in LedgerBreakageRecord to ensure the remaining
FK-backed edges, especially source_transaction, breakage_transaction,
fbo_sub_account, breakage_sub_account, and release, are indexed in the generated
schema by adding the appropriate index annotations or schema indexes tied to
those field names.

In `@tools/migrate/migrations/20260706130134_add_ledger_internal_fks.up.sql`:
- Around line 4-6: The combined ALTER TABLE on ledger_customer_accounts is still
doing a blocking column type rewrite, so separate the account_id type change
from the foreign key addition. Update the migration around the
ledger_customer_accounts ALTER TABLE statement so the TYPE character(26) change
is its own step, then add the
ledger_customer_accounts_ledger_accounts_customer_accounts foreign key in a
separate NOT VALID statement.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 54c3c901-c48c-4c59-bb21-c21a8e2da563

📥 Commits

Reviewing files that changed from the base of the PR and between ef77b70 and 08abedb.

⛔ Files ignored due to path filters (46)
  • openmeter/ent/db/client.go is excluded by !**/ent/db/**
  • openmeter/ent/db/ledgeraccount.go is excluded by !**/ent/db/**
  • openmeter/ent/db/ledgeraccount/ledgeraccount.go is excluded by !**/ent/db/**
  • openmeter/ent/db/ledgeraccount/where.go is excluded by !**/ent/db/**
  • openmeter/ent/db/ledgeraccount_create.go is excluded by !**/ent/db/**
  • openmeter/ent/db/ledgeraccount_query.go is excluded by !**/ent/db/**
  • openmeter/ent/db/ledgeraccount_update.go is excluded by !**/ent/db/**
  • openmeter/ent/db/ledgerbreakagerecord.go is excluded by !**/ent/db/**
  • openmeter/ent/db/ledgerbreakagerecord/ledgerbreakagerecord.go is excluded by !**/ent/db/**
  • openmeter/ent/db/ledgerbreakagerecord/where.go is excluded by !**/ent/db/**
  • openmeter/ent/db/ledgerbreakagerecord_create.go is excluded by !**/ent/db/**
  • openmeter/ent/db/ledgerbreakagerecord_query.go is excluded by !**/ent/db/**
  • openmeter/ent/db/ledgerbreakagerecord_update.go is excluded by !**/ent/db/**
  • openmeter/ent/db/ledgercustomeraccount.go is excluded by !**/ent/db/**
  • openmeter/ent/db/ledgercustomeraccount/ledgercustomeraccount.go is excluded by !**/ent/db/**
  • openmeter/ent/db/ledgercustomeraccount/where.go is excluded by !**/ent/db/**
  • openmeter/ent/db/ledgercustomeraccount_create.go is excluded by !**/ent/db/**
  • openmeter/ent/db/ledgercustomeraccount_query.go is excluded by !**/ent/db/**
  • openmeter/ent/db/ledgercustomeraccount_update.go is excluded by !**/ent/db/**
  • openmeter/ent/db/ledgerentry.go is excluded by !**/ent/db/**
  • openmeter/ent/db/ledgerentry/ledgerentry.go is excluded by !**/ent/db/**
  • openmeter/ent/db/ledgerentry/where.go is excluded by !**/ent/db/**
  • openmeter/ent/db/ledgerentry_create.go is excluded by !**/ent/db/**
  • openmeter/ent/db/ledgerentry_query.go is excluded by !**/ent/db/**
  • openmeter/ent/db/ledgerentry_update.go is excluded by !**/ent/db/**
  • openmeter/ent/db/ledgersubaccount.go is excluded by !**/ent/db/**
  • openmeter/ent/db/ledgersubaccount/ledgersubaccount.go is excluded by !**/ent/db/**
  • openmeter/ent/db/ledgersubaccount/where.go is excluded by !**/ent/db/**
  • openmeter/ent/db/ledgersubaccount_create.go is excluded by !**/ent/db/**
  • openmeter/ent/db/ledgersubaccount_query.go is excluded by !**/ent/db/**
  • openmeter/ent/db/ledgersubaccount_update.go is excluded by !**/ent/db/**
  • openmeter/ent/db/ledgertransaction.go is excluded by !**/ent/db/**
  • openmeter/ent/db/ledgertransaction/ledgertransaction.go is excluded by !**/ent/db/**
  • openmeter/ent/db/ledgertransaction/where.go is excluded by !**/ent/db/**
  • openmeter/ent/db/ledgertransaction_create.go is excluded by !**/ent/db/**
  • openmeter/ent/db/ledgertransaction_query.go is excluded by !**/ent/db/**
  • openmeter/ent/db/ledgertransaction_update.go is excluded by !**/ent/db/**
  • openmeter/ent/db/ledgertransactiongroup.go is excluded by !**/ent/db/**
  • openmeter/ent/db/ledgertransactiongroup/ledgertransactiongroup.go is excluded by !**/ent/db/**
  • openmeter/ent/db/ledgertransactiongroup/where.go is excluded by !**/ent/db/**
  • openmeter/ent/db/ledgertransactiongroup_create.go is excluded by !**/ent/db/**
  • openmeter/ent/db/ledgertransactiongroup_query.go is excluded by !**/ent/db/**
  • openmeter/ent/db/ledgertransactiongroup_update.go is excluded by !**/ent/db/**
  • openmeter/ent/db/migrate/schema.go is excluded by !**/ent/db/**
  • openmeter/ent/db/mutation.go is excluded by !**/ent/db/**
  • tools/migrate/migrations/atlas.sum is excluded by !**/*.sum, !**/*.sum
📒 Files selected for processing (9)
  • openmeter/ent/schema/ledger_account.go
  • openmeter/ent/schema/ledger_breakage_record.go
  • openmeter/ent/schema/ledger_customer_account.go
  • openmeter/ent/schema/ledger_entry.go
  • openmeter/ent/schema/ledger_transaction.go
  • openmeter/ent/schema/ledger_transaction_group.go
  • openmeter/ledger/breakage/adapter/record_test.go
  • tools/migrate/migrations/20260706130134_add_ledger_internal_fks.down.sql
  • tools/migrate/migrations/20260706130134_add_ledger_internal_fks.up.sql

Comment on lines +130 to +187
func (LedgerBreakageRecord) Edges() []ent.Edge {
return []ent.Edge{
edge.From("source_transaction_group", LedgerTransactionGroup.Type).
Ref("source_breakage_records").
Field("source_transaction_group_id").
Immutable().
Unique(),
edge.From("source_transaction", LedgerTransaction.Type).
Ref("source_breakage_records").
Field("source_transaction_id").
Immutable().
Unique(),
edge.From("source_entry", LedgerEntry.Type).
Ref("source_breakage_records").
Field("source_entry_id").
Immutable().
Unique(),
edge.From("breakage_transaction_group", LedgerTransactionGroup.Type).
Ref("breakage_records").
Field("breakage_transaction_group_id").
Required().
Immutable().
Unique(),
edge.From("breakage_transaction", LedgerTransaction.Type).
Ref("breakage_records").
Field("breakage_transaction_id").
Required().
Immutable().
Unique(),
edge.From("fbo_sub_account", LedgerSubAccount.Type).
Ref("fbo_breakage_records").
Field("fbo_sub_account_id").
Required().
Immutable().
Unique(),
edge.From("breakage_sub_account", LedgerSubAccount.Type).
Ref("breakage_records").
Field("breakage_sub_account_id").
Required().
Immutable().
Unique(),
edge.To("planned_releases", LedgerBreakageRecord.Type).
Annotations(entsql.OnDelete(entsql.Restrict)),
edge.To("release_reopens", LedgerBreakageRecord.Type).
Annotations(entsql.OnDelete(entsql.Restrict)),
edge.From("plan", LedgerBreakageRecord.Type).
Ref("planned_releases").
Field("plan_id").
Immutable().
Unique(),
edge.From("release", LedgerBreakageRecord.Type).
Ref("release_reopens").
Field("release_id").
Immutable().
Unique(),
}
}

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.

🚀 Performance & Scalability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Look for index declarations covering the FK columns backing the new edges.
fd -e go . openmeter/ent/schema --exec rg -n 'index\.Fields\(' {} \; 
echo "---- breakage record indexes ----"
rg -nP 'index\.Fields\([^)]*(source_transaction_id|breakage_transaction_id|fbo_sub_account_id|breakage_sub_account_id|release_id)' openmeter/ent/schema/ledger_breakage_record.go || echo "no matching FK-column indexes found in schema"

Repository: openmeterio/openmeter

Length of output: 8239


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== schema outline =="
ast-grep outline openmeter/ent/schema/ledger_breakage_record.go --view expanded || true

echo
echo "== relevant schema sections =="
sed -n '1,260p' openmeter/ent/schema/ledger_breakage_record.go

echo
echo "== generated references for ledger_breakage_records =="
rg -n "ledger_breakage_records|source_transaction_id|breakage_transaction_id|fbo_sub_account_id|breakage_sub_account_id|release_id|plan_id|source_transaction_group_id|source_entry_id|breakage_transaction_group_id" openmeter/ent -g '!**/*.json' -g '!**/*.snap' || true

Repository: openmeterio/openmeter

Length of output: 50377


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the generated schema for this entity if it exists.
fd -a 'ledger_breakage_record.go' openmeter/ent | sed -n '1,20p'
echo
for f in $(fd -a 'ledger_breakage_record.go' openmeter/ent); do
  echo "== $f =="
  rg -n "func \(.*\) Indexes\(\)|index\.Fields|Unique\(|source_transaction_id|breakage_transaction_id|fbo_sub_account_id|breakage_sub_account_id|release_id|plan_id|source_transaction_group_id|source_entry_id|breakage_transaction_group_id" "$f" || true
  echo
done

Repository: openmeterio/openmeter

Length of output: 1605


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '3695,3810p' openmeter/ent/db/migrate/schema.go

Repository: openmeterio/openmeter

Length of output: 4879


Add indexes for the remaining breakage FK columns. source_transaction_id, breakage_transaction_id, fbo_sub_account_id, breakage_sub_account_id, and release_id still don't get indexes in the generated ledger_breakage_records schema, so deletes on the parent tables can end up scanning this table.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@openmeter/ent/schema/ledger_breakage_record.go` around lines 130 - 187, The
LedgerBreakageRecord schema is still missing indexes on several foreign key
fields, causing parent-table deletes to scan this table. Update the Edges
definition in LedgerBreakageRecord to ensure the remaining FK-backed edges,
especially source_transaction, breakage_transaction, fbo_sub_account,
breakage_sub_account, and release, are indexed in the generated schema by adding
the appropriate index annotations or schema indexes tied to those field names.

Source: Path instructions

Comment on lines +4 to +6
-- modify "ledger_customer_accounts" table
-- Manual post-generation step: keep this foreign key NOT VALID for the same rollout reason as above.
ALTER TABLE "ledger_customer_accounts" ALTER COLUMN "account_id" TYPE character(26), ADD CONSTRAINT "ledger_customer_accounts_ledger_accounts_customer_accounts" FOREIGN KEY ("account_id") REFERENCES "ledger_accounts" ("id") ON UPDATE NO ACTION ON DELETE NO ACTION NOT VALID;

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.

🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🌐 Web query:

Does PostgreSQL treat ALTER COLUMN TYPE from varchar to char(n) as a binary-coercible change that avoids a table rewrite?

💡 Result:

PostgreSQL does not treat an ALTER COLUMN TYPE from varchar to char(n) as a binary-coercible change, and it generally requires a table rewrite [1][2][3]. While PostgreSQL can avoid a full table rewrite when changing between certain types that are binary-coercible or are unconstrained domains over the new type (such as changing from varchar(n) to text or increasing the length of a varchar(n)), the conversion between varchar and char(n) is not considered binary-coercible [1][4]. The char(n) type requires that data be padded with spaces to the specified length n, whereas varchar stores only the string itself. Because the internal on-disk representation differs, PostgreSQL must rewrite the table to convert the values to the fixed-length, space-padded format required by char(n) [5][4]. This operation holds an ACCESS EXCLUSIVE lock on the table for the duration of the rewrite, which can cause significant downtime on large tables [4].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

file='tools/migrate/migrations/20260706130134_add_ledger_internal_fks.up.sql'

echo '--- file ---'
cat -n "$file"

echo
echo '--- surrounding migration files ---'
fd -a '20260706130134_add_ledger_internal_fks.*\.sql$|20260706130134_add_ledger_internal_fks\.up\.sql|20260706130134_add_ledger_internal_fks\.down\.sql' tools/migrate/migrations || true

Repository: openmeterio/openmeter

Length of output: 3004


🏁 Script executed:

#!/bin/bash
set -euo pipefail

file='tools/migrate/migrations/20260706130134_add_ledger_internal_fks.up.sql'
wc -l "$file"
sed -n '1,40p' "$file"

Repository: openmeterio/openmeter

Length of output: 2803


Split the type change out from the FK add

ALTER COLUMN "account_id" TYPE character(26) still rewrites ledger_customer_accounts under an ACCESS EXCLUSIVE lock, so the NOT VALID FK doesn’t buy you the low-lock rollout benefit here. Split the type change into its own step.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tools/migrate/migrations/20260706130134_add_ledger_internal_fks.up.sql`
around lines 4 - 6, The combined ALTER TABLE on ledger_customer_accounts is
still doing a blocking column type rewrite, so separate the account_id type
change from the foreign key addition. Update the migration around the
ledger_customer_accounts ALTER TABLE statement so the TYPE character(26) change
is its own step, then add the
ledger_customer_accounts_ledger_accounts_customer_accounts foreign key in a
separate NOT VALID statement.

Source: Path instructions

@GAlexIHU
GAlexIHU enabled auto-merge (squash) July 6, 2026 15:01
@GAlexIHU
GAlexIHU force-pushed the codex/ledger-data-layer-fks branch from 5d575c3 to 97a2dea Compare July 9, 2026 11:42
Comment thread openmeter/ent/db/migrate/schema.go
@@ -0,0 +1,6 @@
-- modify "ledger_breakage_records" table
-- Manual post-generation step: add these foreign keys as NOT VALID so the migration job enforces new writes without validating historical rows. Validate them separately after orphan preflight.
ALTER TABLE "ledger_breakage_records" ADD CONSTRAINT "ledger_breakage_records_ledger_breakage_records_planned_release" FOREIGN KEY ("plan_id") REFERENCES "ledger_breakage_records" ("id") ON UPDATE NO ACTION ON DELETE RESTRICT NOT VALID, ADD CONSTRAINT "ledger_breakage_records_ledger_breakage_records_release_reopens" FOREIGN KEY ("release_id") REFERENCES "ledger_breakage_records" ("id") ON UPDATE NO ACTION ON DELETE RESTRICT NOT VALID, ADD CONSTRAINT "ledger_breakage_records_ledger_entries_source_breakage_records" FOREIGN KEY ("source_entry_id") REFERENCES "ledger_entries" ("id") ON UPDATE NO ACTION ON DELETE RESTRICT NOT VALID, ADD CONSTRAINT "ledger_breakage_records_ledger_sub_accounts_breakage_records" FOREIGN KEY ("breakage_sub_account_id") REFERENCES "ledger_sub_accounts" ("id") ON UPDATE NO ACTION ON DELETE NO ACTION NOT VALID, ADD CONSTRAINT "ledger_breakage_records_ledger_sub_accounts_fbo_breakage_record" FOREIGN KEY ("fbo_sub_account_id") REFERENCES "ledger_sub_accounts" ("id") ON UPDATE NO ACTION ON DELETE NO ACTION NOT VALID, ADD CONSTRAINT "ledger_breakage_records_ledger_transaction_groups_breakage_reco" FOREIGN KEY ("breakage_transaction_group_id") REFERENCES "ledger_transaction_groups" ("id") ON UPDATE NO ACTION ON DELETE NO ACTION NOT VALID, ADD CONSTRAINT "ledger_breakage_records_ledger_transaction_groups_source_breaka" FOREIGN KEY ("source_transaction_group_id") REFERENCES "ledger_transaction_groups" ("id") ON UPDATE NO ACTION ON DELETE RESTRICT NOT VALID, ADD CONSTRAINT "ledger_breakage_records_ledger_transactions_breakage_records" FOREIGN KEY ("breakage_transaction_id") REFERENCES "ledger_transactions" ("id") ON UPDATE NO ACTION ON DELETE NO ACTION NOT VALID, ADD CONSTRAINT "ledger_breakage_records_ledger_transactions_source_breakage_rec" FOREIGN KEY ("source_transaction_id") REFERENCES "ledger_transactions" ("id") ON UPDATE NO ACTION ON DELETE RESTRICT NOT VALID;

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.

P1 Breakage Orphans Freeze Updates

These NOT VALID constraints skip historical ledger_breakage_records, but PostgreSQL still checks them when one of those rows is later updated. Breakage records still have mutable columns such as deleted_at, annotations, amount, and updated_at, so an old row whose source_*, transaction, sub-account, or self-reference no longer exists can start failing routine soft-delete or maintenance updates after this migration. The validation guide is manual and does not enforce cleanup before the constraints are installed, so existing orphaned breakage projections can become rows that are readable but no longer updatable.

Prompt To Fix With AI
This is a comment left during a code review.
Path: tools/migrate/migrations/20260709134422_add_ledger_internal_fks.up.sql
Line: 3

Comment:
**Breakage Orphans Freeze Updates**

These `NOT VALID` constraints skip historical `ledger_breakage_records`, but PostgreSQL still checks them when one of those rows is later updated. Breakage records still have mutable columns such as `deleted_at`, `annotations`, `amount`, and `updated_at`, so an old row whose `source_*`, transaction, sub-account, or self-reference no longer exists can start failing routine soft-delete or maintenance updates after this migration. The validation guide is manual and does not enforce cleanup before the constraints are installed, so existing orphaned breakage projections can become rows that are readable but no longer updatable.

How can I resolve this? If you propose a fix, please make it concise.

Fix in Claude Code Fix in Codex

Comment thread openmeter/ent/db/migrate/schema.go
@GAlexIHU
GAlexIHU force-pushed the codex/ledger-data-layer-fks branch from 29ca255 to f06b56c Compare July 10, 2026 13:35
@GAlexIHU
GAlexIHU merged commit 12ab7b0 into main Jul 10, 2026
27 checks passed
@GAlexIHU
GAlexIHU deleted the codex/ledger-data-layer-fks branch July 10, 2026 13:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release-note/ignore Ignore this change when generating release notes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants