feat(gl): add standalone ledger authority mode
CI/CD Stage / stage (push) Failing after 1m12s

This commit is contained in:
2026-10-06 22:40:07 +03:30
parent 01d13dbbf2
commit 88e227f80c
26 changed files with 2033 additions and 196 deletions
+38 -3
View File
@@ -1,6 +1,6 @@
# General Ledger service design
Status: append-only model accepted on 2026-08-14; authority and availability policy revised on 2026-08-28.
Status: append-only model accepted on 2026-08-14; authority and availability policy revised on 2026-08-28; standalone GL authority API implemented on 2026-10-05.
## Purpose and ownership
@@ -30,9 +30,10 @@ disabled automatically.
5. Account, asset, source transaction, correlation, actor, occurrence time, and
recording time are retained on every applicable record.
6. A journal commits atomically with all its entries or not at all.
7. A financial effect is journaled only when Wallet has committed that effect.
7. In normal Wallet ingestion, a financial effect is journaled only when Wallet has committed that effect.
Pending and failed lifecycle events may be retained as audit events but do
not create monetary entries.
not create monetary entries. For standalone GL-only execution, the GL journal
commit itself is the financial effect; any Wallet copy is a projection.
8. Derived balances are rebuildable solely by ordering and summing immutable
entries. Cached balances are disposable projections, never source data.
@@ -115,6 +116,37 @@ does not hold a wallet database transaction open.
## Operating modes and failure semantics
GL now exposes its own persisted `NORMAL` / `GL_ONLY` operating state through
`GetOperatingMode` and the authenticated `SetOperatingMode` RPC. This is
distinct from Wallet's existing `KUKNOS_DISABLED` configuration, which still
makes Wallet read-only until its callers are integrated with this API.
In `GL_ONLY`, `PostInternalJournal` executes balanced internal effects
synchronously. PostgreSQL locks user accounts and checks available/frozen
balances in the same commit; conflicting spends cannot both succeed. All
journal append paths enforce the GL-only funds rules; ordinary ingestion rejects
new effects in this mode, so internal execution cannot be bypassed. Blockchain
references
and external blockchain account movements are forbidden, new settlement
requests are rejected, and the worker stops claiming existing settlements.
The mode survives restarts and changes have immutable actor/reason/revision
audits and OpenTelemetry spans. Switching drains posting transactions and
rejects in-flight settlement claims or negative user balances. Returning to
`NORMAL` requires explicit operator reconciliation confirmation.
The ledger must be complete before switching: restore/import opening balances
and drain committed Wallet outbox effects and in-flight Wallet processing.
GL-only mode keeps ledger reads/writes available while reporting settlement as
paused; existing normal-mode Wallet clients therefore fail closed rather than
continuing blockchain-dependent processing. Internal executions must not also
be delivered through that outbox as new monetary effects. User authorization,
asset eligibility, fees, and business counterparty mapping remain admission
responsibilities. Actual external payment settlement cannot occur internally.
See [the authority API](deployment/AUTHORITY_API.md) and
[standalone operation](deployment/STANDALONE.md).
The broader Wallet availability policy remains:
- `NORMAL`: GL and Kuknos must both be healthy. A transaction is successful
only after its required GL journal and Kuknos settlement evidence exist.
- `KUKNOS_DISABLED`: explicitly enabled and disabled by an authorized operator
@@ -145,6 +177,9 @@ The first `ledger.v1.GeneralLedgerService` contract provides:
- `AppendTransactionEvent` for non-monetary lifecycle history;
- `GetJournal` and `ListEntries` for audit and replay inspection;
- `GetBalance` for a rebuildable account/asset projection;
- `GetUserBalances` for available, frozen, and total balances per user asset;
- `GetOperatingMode` / `SetOperatingMode` for attributable operator cutover;
- `PostInternalJournal` for atomic internal execution in `GL_ONLY`;
- `Health` for readiness and database health.
Wallet depends on its own `Ledger` port. Its gRPC implementation translates