Skip to content

payments: kv-to-sql migration (tests + wiring)#10485

Open
ziggie1984 wants to merge 10 commits intolightningnetwork:elle-payment-sql-series-newfrom
ziggie1984:migration-kvdb-sql-payments-part1
Open

payments: kv-to-sql migration (tests + wiring)#10485
ziggie1984 wants to merge 10 commits intolightningnetwork:elle-payment-sql-series-newfrom
ziggie1984:migration-kvdb-sql-payments-part1

Conversation

@ziggie1984
Copy link
Collaborator

@ziggie1984 ziggie1984 commented Jan 8, 2026

Adds the KV db migration code to native SQL.

After merging this PR, the migration is still hidden behind test_native_sql

@ziggie1984 ziggie1984 self-assigned this Jan 8, 2026
@ziggie1984 ziggie1984 added migration sql payments Related to invoices/payments labels Jan 8, 2026
@gemini-code-assist
Copy link

Summary of Changes

Hello @ziggie1984, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a significant architectural change by migrating the payments database from a Key-Value (KV) store to a native SQL schema. The primary goal is to enhance database robustness, query flexibility, and overall performance for payment-related operations. It includes the complete implementation of the migration logic, a new SQL-backed payment store, and a comprehensive suite of tests to ensure data integrity and correct functionality during and after the migration. This change also prepares the system for future database optimizations and features by leveraging the capabilities of a relational database.

Highlights

  • KV-to-SQL Migration Logic: Introduced the core migration logic to transfer payment data from the existing Key-Value (KV) store to a new native SQL schema, including handling of historical duplicate payments by converting them into additional HTLC attempts.
  • New SQL Payment Store Implementation: Implemented a new SQL-backed payment store (SQLStore) that adheres to the existing payment database interfaces, providing methods for querying, fetching, initializing, registering, settling, failing, and deleting payments and their HTLC attempts.
  • Comprehensive Testing: Added extensive testing for the migration process, including basic happy-path tests, data integrity checks, property-based tests for various payment scenarios (MPP, AMP, custom records, blinded routes), and a helper for debugging with external database files.
  • Database Schema Integration: Integrated the new payment migration into the main database build process by adding a new paymentMigration constant and a custom migration function in config_builder.go, along with a mechanism to prevent reopening the old KV payments bucket after migration.
  • Payment Data Structures and Utilities: Defined new Go data structures for payments, HTLC attempts, and their statuses (MPPayment, HTLCAttempt, PaymentStatus), along with serialization/deserialization codecs and error types specific to the migration and new SQL store.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@ziggie1984 ziggie1984 added this to v0.21 Jan 8, 2026
@ziggie1984 ziggie1984 added this to the v0.21.0 milestone Jan 8, 2026
Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a comprehensive migration for the payments database from a key-value store to SQL. The changes are well-structured, with the migration logic encapsulated in a new payments/db/migration1 package. This package includes a reader for the old KV store format, cleverly handling historical data quirks like duplicate payments by migrating them as HTLC attempts on the primary payment. The migration is correctly wired into the application startup, guarded by a new migration version and a tombstone mechanism to prevent accidental use of the old database post-migration. The testing strategy is particularly strong, featuring data integrity checks, property-based tests, and specific tests for various payment features, which provides high confidence in the correctness of this complex change. My review is positive, with only a couple of minor stylistic suggestions to improve readability.

Comment on lines +232 to +233
return fmt.Errorf("non bucket element" +
"in duplicate bucket")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This string concatenation is unnecessary and can be combined into a single string to improve readability and adhere to the style guide's principle of minimizing lines for error messages.

return fmt.Errorf("non bucket element in duplicate bucket")
References
  1. The style guide states to 'Minimize lines for log and error messages, while adhering to the 80-character limit.' The current code unnecessarily splits a short line, which goes against the 'minimize lines' principle. (link)

@ziggie1984 ziggie1984 force-pushed the elle-payment-sql-series-new branch from d8531d2 to 2930b37 Compare January 8, 2026 12:56
@ziggie1984 ziggie1984 force-pushed the migration-kvdb-sql-payments-part1 branch 2 times, most recently from 2802da4 to 83bce46 Compare January 8, 2026 12:59
@saubyk saubyk moved this to In progress in v0.21 Jan 8, 2026
@ziggie1984 ziggie1984 force-pushed the elle-payment-sql-series-new branch from 2930b37 to 8c106c7 Compare January 8, 2026 15:43
@ziggie1984 ziggie1984 force-pushed the migration-kvdb-sql-payments-part1 branch from 622021b to fc449ad Compare January 10, 2026 23:12
@ziggie1984
Copy link
Collaborator Author

/gemini review

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces the migration logic for moving payment data from the key-value store to a SQL database. The changes are extensive, including a new payments/db/migration1 package that encapsulates the migration logic, new SQL schema definitions for duplicate payments, and the necessary wiring in the configuration builder to trigger the migration. The approach is solid, with good isolation of migration code and thorough validation checks to ensure data integrity. I've found a few minor issues related to code style and typos in error messages and comments, which I've detailed in the review comments.

@ziggie1984 ziggie1984 force-pushed the migration-kvdb-sql-payments-part1 branch from fc449ad to 83a9946 Compare January 11, 2026 19:01
@ziggie1984 ziggie1984 force-pushed the migration-kvdb-sql-payments-part1 branch 4 times, most recently from 27f2fec to 5a25e61 Compare January 12, 2026 09:07
@ziggie1984 ziggie1984 marked this pull request as ready for review January 12, 2026 09:09
@ziggie1984 ziggie1984 force-pushed the migration-kvdb-sql-payments-part1 branch 5 times, most recently from 0360b30 to 915f282 Compare January 12, 2026 09:48
@ziggie1984 ziggie1984 moved this from In progress to In review in v0.21 Jan 12, 2026
@ziggie1984 ziggie1984 added the size/kilo medium, proper context needed, less than 1000 lines label Jan 12, 2026
@ZZiigguurraatt
Copy link

Do you want to update https://github.com/ziggie1984/lnd/blob/migration-kvdb-sql-payments-part1/docs/postgres.md or is that going to be part of a different PR?

@lightninglabs-deploy
Copy link
Collaborator

@yyforyongyu: review reminder
@ellemouton: review reminder
@ziggie1984, remember to re-request review from reviewers when ready

Copy link
Collaborator

@ellemouton ellemouton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

first pass done! great work!!

*/

// InsertPaymentMig is a migration-only variant of InsertPayment that
// allows setting fail_reason when inserting historical payments.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cool - i'd just expand this to say "since for real payments, they have not failed at creation time and so no failure reason would exist yet" or something to that tune

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done — expanded the comment to explain why the migration variant needs the fail_reason parameter.

Comment on lines 16 to 18
-- Logical identifier for the duplicate payment. This is the payment hash
-- of the duplicate payment.
payment_identifier BLOB NOT NULL,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isnt this implied given the payment_id? ie, is this data not duplicating something already stored in the payemtns table?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point — removed. Since payment_id is a FK to payments.id and payments already stores payment_identifier, the column was redundant. Duplicates by definition share the same hash as the parent payment, so it can always be looked up via the FK join.

Comment on lines +16 to +17
// UnknownElementType is an alias for channeldb.UnknownElementType.
type UnknownElementType = channeldb.UnknownElementType
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

think we should not do this type alias. when we "freeze" code, we really want it to be properly frozen. So rather do a bit of copying here i'd say.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed on the principle — the frozen code should truly be self-contained. The scope is fairly large though (copying UnknownElementType + minimal codec, copying route.Hop/route.Route/Vertex types + methods, removing dead code like generateSphinxPacket that depends on ToSphinxPath, and updating all references across ~8 files). Will address this in a follow-up PR to keep this one focused.


// ReadElement deserializes a single element from the provided io.Reader.
func ReadElement(r io.Reader, element interface{}) error {
err := channeldb.ReadElement(r, element)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here: to truly be frozen, these helpers from channeldb should also be frozen.

Same goes for the types used in this "freeze" from the route package - route.Hop and route.Route

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above — will address the full freeze (channeldb helpers + route types) in a follow-up PR.

return ai.CreatedAt.Before(aj.CreatedAt)
}

return ai.AmountMsat < aj.AmountMsat
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wont amount mainly be the same for duplicate payments?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Usually yes, but for zero-amount invoices each duplicate payment could specify a different amount, so the tiebreaker is still meaningful in that case. Also sort.SliceStable preserves insertion order for fully equal elements, so the sort stays deterministic regardless.

@@ -0,0 +1,52 @@
# Payment Migration External Testdata
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

got this for one of the tests:

go test -v -tags="test_db_sqlite kvdb_sqlite" \
  -run TestMigrationWithExternalDB
=== RUN   TestMigrationWithExternalDB
=== RUN   TestMigrationWithExternalDB/testdata
    migration_external_test.go:170: Connecting to channel DB at: testdata/channel.sqlite
    test_sqlite.go:51: Creating new SQLite DB for testing
2026-02-02 15:05:11.024 [INF]: Starting payment migration from KV to SQL...
    migration_external_test.go:71: 
                Error Trace:    /Users/elle/LL/lnd/payments/db/migration1/migration_external_test.go:71
                                                        /Users/elle/LL/lnd/payments/db/migration1/migration_external_test.go:177
                Error:          Received unexpected error:
                                migrate payments: migrate payment d775df0ead97b006: migrate attempt 0: HTLC attempt 0 missing payment hash (parent payment hash=d775df0ead97b0069c58664d3eb1a1ec6b75ca4a445b0104f584851d577187d8)
                Test:           TestMigrationWithExternalDB/testdata
--- FAIL: TestMigrationWithExternalDB (0.29s)
    --- FAIL: TestMigrationWithExternalDB/testdata (0.29s)
FAIL
exit status 1
FAIL    github.com/lightningnetwork/lnd/payments/db/migration1  0.612s

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this for another:

=== RUN   TestMigrationWithExternalDB/testdata
    migration_external_test.go:170: Connecting to channel DB at: testdata/channel.db
    test_postgres.go:72: Creating new Postgres DB 'test_e01f16e8c3aa37b4' for testing
2026-02-02 15:14:04.990 [INF]: Starting payment migration from KV to SQL...
2026-02-02 15:14:07.525 [INF]: Validated 92/92 payments
2026-02-02 15:14:07.528 [INF]: ========================================
2026-02-02 15:14:07.528 [INF]:    Payment Migration Summary
2026-02-02 15:14:07.528 [INF]: ========================================
2026-02-02 15:14:07.528 [INF]: Total Payments:        92
2026-02-02 15:14:07.528 [INF]:   Successful:       76
2026-02-02 15:14:07.528 [INF]:   Failed:           16
2026-02-02 15:14:07.528 [INF]:   In-Flight:        0
2026-02-02 15:14:07.528 [INF]:   Initiated:        0
2026-02-02 15:14:07.528 [INF]: 
2026-02-02 15:14:07.528 [INF]: Total HTLC Attempts:   318
2026-02-02 15:14:07.528 [INF]:   Settled:          76
2026-02-02 15:14:07.528 [INF]:   Failed:           242
2026-02-02 15:14:07.528 [INF]:   In-Flight:        0
2026-02-02 15:14:07.528 [INF]: 
2026-02-02 15:14:07.528 [INF]: Total Route Hops:      1283
2026-02-02 15:14:07.528 [INF]: 
2026-02-02 15:14:07.528 [INF]: Migration Duration:    2.538169416s
2026-02-02 15:14:07.528 [INF]: ========================================
--- PASS: TestMigrationWithExternalDB/testdata (6.04s)
--- PASS: TestMigrationWithExternalDB (6.04s)
PASS

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and:

go test -v -tags="test_db_sqlite kvdb_sqlite" \
  -run TestMigrationWithExternalDB
=== RUN   TestMigrationWithExternalDB
=== RUN   TestMigrationWithExternalDB/testdata
    migration_external_test.go:170: Connecting to channel DB at: testdata/channel.db
    test_sqlite.go:51: Creating new SQLite DB for testing
2026-02-02 15:18:56.829 [INF]: Starting payment migration from KV to SQL...
2026-02-02 15:18:56.932 [INF]: Validated 92/92 payments
2026-02-02 15:18:56.932 [INF]: ========================================
2026-02-02 15:18:56.932 [INF]:    Payment Migration Summary
2026-02-02 15:18:56.932 [INF]: ========================================
2026-02-02 15:18:56.932 [INF]: Total Payments:        92
2026-02-02 15:18:56.932 [INF]:   Successful:       76
2026-02-02 15:18:56.932 [INF]:   Failed:           16
2026-02-02 15:18:56.932 [INF]:   In-Flight:        0
2026-02-02 15:18:56.932 [INF]:   Initiated:        0
2026-02-02 15:18:56.932 [INF]: 
2026-02-02 15:18:56.932 [INF]: Total HTLC Attempts:   318
2026-02-02 15:18:56.932 [INF]:   Settled:          76
2026-02-02 15:18:56.932 [INF]:   Failed:           242
2026-02-02 15:18:56.932 [INF]:   In-Flight:        0
2026-02-02 15:18:56.932 [INF]: 
2026-02-02 15:18:56.932 [INF]: Total Route Hops:      1283
2026-02-02 15:18:56.932 [INF]: 
2026-02-02 15:18:56.932 [INF]: Migration Duration:    102.832041ms
2026-02-02 15:18:56.932 [INF]: ========================================
--- PASS: TestMigrationWithExternalDB (0.67s)
    --- PASS: TestMigrationWithExternalDB/testdata (0.67s)
PASS
ok      github.com/lightningnetwork/lnd/payments/db/migration1  1.147s

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for testing! The "HTLC attempt 0 missing payment hash" failure was caused by legacy payments where the HTLC hash field is nil in bbolt. This is fixed by falling back to the parent payment hash when the HTLC-specific hash is nil (consistent with how patchLegacyPaymentHash works in payment_lifecycle.go). The fix is in a follow-up commit.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Specifically: for legacy/older payments the htlc.Hash field can be nil in bbolt. The fix changes migrateHTLCAttempt to fall back to the parent payment hash (parentPaymentHash) when htlc.Hash is nil, instead of returning an error. This is consistent with how the router already handles these in patchLegacyPaymentHash (payment_lifecycle.go). The validation logic applies the same fallback so the KV↔SQL comparison passes. Fix is in a follow-up commit (adf8264).

"graph to SQL: %w", err)
}

return nil
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

another option could be to do "sample validation". so like, validate every 100th payment or something like that. so like, set a ValidationSampleRate or something? just an idea

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting idea, but I think we can defer this to a follow-up if needed. A few reasons:

  1. The current binary choice is cleanSkipMigrationValidation is simple: validate everything or skip entirely. A sample rate adds a config knob most users won't know how to tune.
  2. Sampling gives a false sense of security — if there's a systematic bug, even 1% sampling catches it. If there's a rare edge case, sampling might miss it. So it's either "validate all" for confidence or "skip" for speed — the middle ground doesn't buy much.
  3. Real-world timing looks fine — from your own test output, 92 payments + 318 HTLC attempts validated in ~2.5s. Even for a node with 10k payments full validation should be manageable. The skip flag covers truly massive databases.
  4. YAGNI — if users report validation being too slow we can add it then with real data on what sample rate is useful.

Happy to add it if you feel strongly though!

@ziggie1984 ziggie1984 force-pushed the elle-payment-sql-series-new branch from 8c106c7 to 2104014 Compare February 5, 2026 22:06
@ziggie1984 ziggie1984 force-pushed the migration-kvdb-sql-payments-part1 branch from 915f282 to 0b84764 Compare February 5, 2026 22:31
Add a migration specific query which allows to set the failure
reason when inserting a payment into the db.
Older LND versions could create multiple payments for the same hash.
We need to preserve those historical records during KV→SQL migration,
but they don’t fit the normal payment schema because we enforce a
unique payment hash constraint. Introduce a lean payment_duplicates
table to store only the essential fields (identifier, amount,
timestamps, settle/fail data).

This keeps the primary payment records stable and makes the migration
deterministic even when duplicate records lack attempt info. The table
is intentionally minimal and can be dropped after migration if no
duplicate payments exist.

For now there is no logic in place which allows the noderunner to
fetch duplicate payments after the migration.
Copy the core payments/db code into payments/db/migration1 and
add the required sqlc-generated types/queries from sqldb/sqlc.
This effectively freezes the migration code so it stays robust
against future query or schema changes in the main payments package.
Implement the KV→SQL payment migration and add an in-migration
validation pass that deep-compares KV and SQL payment data in batches.
Duplicate payments are migrated into the payment_duplicates table,
and duplicates without attempt info or explicit resolution are marked
failed to ensure terminal state. Validation checks those rows as well.
Add test helpers plus sql_migration_test coverage for KV→SQL migration.
Basic migration, sequence ordering, data integrity, and feature-specific cases
(MPP/AMP, custom records, blinded routes, metadata, failure messages). Also
cover duplicate payment migration to payment_duplicates, including missing
attempt info to ensure terminal failure is recorded.

This gives broad regression coverage for the migration path and its edge-cases.
Add a developer-facing migration_external_test that allows
running the KV→SQL payments migration against a real channel.db
backend to debug migration failures on actual data. The accompanying
testdata README documents how to supply a database file and configure
the test, so users can validate their data and confirm the migration
completes successfully.

The test is skipped by default and meant for manual diagnostics.
Hook the payments KV→SQL migration into the SQL migration config.
The migration is still only available when building with the build tag
"test_native_sql".

Moreover a tombstone protection similar to the invoice migration is added
to prevent re-runningi with the KV backend  once migration completes.
Add a config flag to skip in-migration validation for
the KV->SQL payments migration. This is added as an option
in case bigger payment databases don't require strict
validation but instead prefer speed.

This commit  wires the option through the config, documents
it in the sample config, and disables batch/count validation
when requested.
@ziggie1984 ziggie1984 force-pushed the migration-kvdb-sql-payments-part1 branch from 0b84764 to b03694a Compare February 6, 2026 02:06
@lightninglabs-deploy
Copy link
Collaborator

🔴 PR Severity: CRITICAL

Database Migration | 40 files | 12,282 lines added

🔴 Critical (4 files)
  • sqldb/migrations_dev.go - Migration registration/versioning
  • sqldb/sqlc/migrations/000010_payment_duplicates.up.sql - Database schema migration
  • sqldb/sqlc/migrations/000010_payment_duplicates.down.sql - Migration rollback
  • payments/db/migration1/sql_migration.go - KV-to-SQL migration logic (814 lines)
🟠 High (30 files)

Payment Database Operations:

  • payments/db/kv_tombstone.go - Tombstone handling
  • payments/db/sql_store.go - SQL store implementation
  • payments/db/migration1/*.go - Migration implementation (26 files including codec, duplicate payments, validation, converters)

SQL Database Layer:

  • sqldb/sqlc/models.go - Database models
  • sqldb/sqlc/payments.sql.go - Generated payment queries
  • sqldb/sqlc/querier.go - Query interface
  • sqldb/sqlc/queries/payments.sql - SQL query definitions
🟡 Medium (4 files)
  • config_builder.go - Configuration builder changes
  • lncfg/db.go - Database configuration
  • sample-lnd.conf - Sample configuration
  • go.mod - Dependency update
🟢 Low (2 files)
  • docs/release-notes/release-notes-0.21.0.md - Release notes
  • payments/db/migration1/testdata/README.md - Test documentation

Analysis

This PR is classified as CRITICAL for the following reasons:

  1. Database Migration: Contains SQL schema migrations (000010_payment_duplicates.up.sql) which permanently alter the database structure. Database migrations are always critical as they can cause data loss or corruption if not properly reviewed.

  2. Large-Scale Migration Logic: Implements a complete KV-to-SQL migration path with 2,000+ lines of migration code. This involves:

    • Payment data transformation and validation
    • Duplicate payment handling
    • Complex SQL converters and codecs
    • Migration validation logic
  3. Payment System Core: Touches the payment database layer extensively, which is critical infrastructure for Lightning payment routing and settlement.

  4. Scope: 40 files changed with 12,282 lines added. The sheer scale of changes across multiple critical subsystems requires expert review.

  5. Risk Profile: Migration code has high risk potential:

    • Data integrity concerns during KV→SQL transition
    • Rollback complexity
    • Production payment data at risk
    • Performance implications for payment processing

Recommendation: This PR requires review by maintainers with deep knowledge of:

  • LND's payment database architecture
  • SQL migration patterns
  • Payment state machine semantics
  • Database transaction handling

To override, add a severity-override-{critical,high,medium,low} label.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

migration payments Related to invoices/payments size/kilo medium, proper context needed, less than 1000 lines sql

Projects

Status: In review

Development

Successfully merging this pull request may close these issues.

4 participants