Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ require (
github.com/aws/aws-sdk-go-v2/config v1.32.14
github.com/aws/aws-sdk-go-v2/service/s3 v1.98.0
github.com/bytedance/sonic v1.15.0
github.com/formancehq/numscript v0.0.24
github.com/formancehq/numscript v0.0.25-0.20260608064954-1fcd4893eafe
github.com/go-chi/chi/v5 v5.2.5
github.com/go-jose/go-jose/v4 v4.1.4
github.com/golang-jwt/jwt/v5 v5.3.1
Expand Down Expand Up @@ -164,7 +164,7 @@ require (
github.com/fatih/color v1.18.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/getkin/kin-openapi v0.134.0 // indirect
github.com/getsentry/sentry-go v0.35.1 // indirect
github.com/getsentry/sentry-go v0.43.0 // indirect
github.com/go-chi/chi v4.1.2+incompatible // indirect
github.com/go-chi/render v1.0.3 // indirect
github.com/go-faster/city v1.0.1 // indirect
Expand Down Expand Up @@ -303,7 +303,7 @@ require (
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect
golang.org/x/crypto v0.52.0 // indirect
golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b // indirect
golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90 // indirect
golang.org/x/mod v0.35.0 // indirect
golang.org/x/net v0.55.0 // indirect
golang.org/x/sys v0.45.0 // indirect
Expand Down
30 changes: 14 additions & 16 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -242,24 +242,22 @@ github.com/formancehq/go-libs/v5 v5.7.0 h1:2Z2S3vtOJr45tKpofhPqd0qKrPr6KB/LZZ+Ef
github.com/formancehq/go-libs/v5 v5.7.0/go.mod h1:+jfCYWJ4Z10NGbhmbfon0hGoLe5pysbVQgePrg8M8W4=
github.com/formancehq/invariants v0.11.0 h1:AHFBhK7U8Ak/qoJwgaNU+cAb9w61Ba7dwlcrJTkWBE4=
github.com/formancehq/invariants v0.11.0/go.mod h1:ywzSexCUdhw2dC9Njiv0t4u2KfPVKj6SecFujPgmXno=
github.com/formancehq/numscript v0.0.24 h1:YBiDZ9zLVxTZVhtQ+taRcb6q2jArAvznWMfoWRVYGT0=
github.com/formancehq/numscript v0.0.24/go.mod h1:hC/VY5Vg04F5QkgdPPc6z/YsS/vh8V1qVJVa1VWnYMA=
github.com/formancehq/numscript v0.0.25-0.20260608064954-1fcd4893eafe h1:CL92PtU4vx7NGoTj6yohop09p8t5e4qpNWLSoPd24zM=
github.com/formancehq/numscript v0.0.25-0.20260608064954-1fcd4893eafe/go.mod h1:vQZOSwJItpYeCwUYNtV7bwu9naQoh2pdkkqs0ewkTiI=
github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
github.com/getkin/kin-openapi v0.134.0 h1:/L5+1+kfe6dXh8Ot/wqiTgUkjOIEJiC0bbYVziHB8rU=
github.com/getkin/kin-openapi v0.134.0/go.mod h1:wK6ZLG/VgoETO9pcLJ/VmAtIcl/DNlMayNTb716EUxE=
github.com/getsentry/sentry-go v0.35.1 h1:iopow6UVLE2aXu46xKVIs8Z9D/YZkJrHkgozrxa+tOQ=
github.com/getsentry/sentry-go v0.35.1/go.mod h1:C55omcY9ChRQIUcVcGcs+Zdy4ZpQGvNJ7JYHIoSWOtE=
github.com/getsentry/sentry-go v0.43.0 h1:XbXLpFicpo8HmBDaInk7dum18G9KSLcjZiyUKS+hLW4=
github.com/getsentry/sentry-go v0.43.0/go.mod h1:XDotiNZbgf5U8bPDUAfvcFmOnMQQceESxyKaObSssW0=
github.com/ghemawat/stream v0.0.0-20171120220530-696b145b53b9 h1:r5GgOLGbza2wVHRzK7aAj6lWZjfbAwiu/RDCVOKjRyM=
github.com/ghemawat/stream v0.0.0-20171120220530-696b145b53b9/go.mod h1:106OIgooyS7OzLDOpUGgm9fA3bQENb/cFSyyBmMoJDs=
github.com/gkampitakis/ciinfo v0.3.3 h1:28PgAHtW3wG7UCAKuCK+17rBib9iqtLjajuWsVLUPQY=
github.com/gkampitakis/ciinfo v0.3.3/go.mod h1:1NIwaOcFChN4fa/B0hEBdAb6npDlFL8Bwx4dfRLRqAo=
github.com/gkampitakis/go-diff v1.3.2 h1:Qyn0J9XJSDTgnsgHRdz9Zp24RaJeKMUHg2+PDZZdC4M=
github.com/gkampitakis/go-diff v1.3.2/go.mod h1:LLgOrpqleQe26cte8s36HTWcTmMEur6OPYerdAAS9tk=
github.com/gkampitakis/go-snaps v0.5.15 h1:amyJrvM1D33cPHwVrjo9jQxX8g/7E2wYdZ+01KS3zGE=
github.com/gkampitakis/go-snaps v0.5.15/go.mod h1:HNpx/9GoKisdhw9AFOBT1N7DBs9DiHo/hGheFGBZ+mc=
github.com/gkampitakis/ciinfo v0.3.4 h1:5eBSibVuSMbb/H6Elc0IIEFbkzCJi3lm94n0+U7Z0KY=
github.com/gkampitakis/ciinfo v0.3.4/go.mod h1:1NIwaOcFChN4fa/B0hEBdAb6npDlFL8Bwx4dfRLRqAo=
github.com/gkampitakis/go-snaps v0.5.21 h1:SvhSFeZviQXwlT+dnGyAIATVehkhqRVW6qfQZhCZH+Y=
github.com/gkampitakis/go-snaps v0.5.21/go.mod h1:gC3YqxQTPyIXvQrw/Vpt3a8VqR1MO8sVpZFWN4DGwNs=
github.com/go-chi/chi v4.1.2+incompatible h1:fGFk2Gmi/YKXk0OmGfBh0WgmN3XB8lVnEyNz34tQRec=
github.com/go-chi/chi v4.1.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
github.com/go-chi/chi/v5 v5.2.5 h1:Eg4myHZBjyvJmAFjFvWgrqDTXFyOzjj7YIm3L3mu6Ug=
Expand Down Expand Up @@ -297,8 +295,8 @@ github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk=
github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw=
github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM=
github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
Expand Down Expand Up @@ -435,8 +433,8 @@ github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8S
github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mailru/easyjson v0.9.2 h1:dX8U45hQsZpxd80nLvDGihsQ/OxlvTkVUXH2r/8cb2M=
github.com/mailru/easyjson v0.9.2/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
github.com/maruel/natural v1.1.1 h1:Hja7XhhmvEFhcByqDoHz9QZbkWey+COd9xWfCfn1ioo=
github.com/maruel/natural v1.1.1/go.mod h1:v+Rfd79xlw1AgVBjbO0BEQmptqb5HvL/k9GRHB7ZKEg=
github.com/maruel/natural v1.3.0 h1:VsmCsBmEyrR46RomtgHs5hbKADGRVtliHTyCOLFBpsg=
github.com/maruel/natural v1.3.0/go.mod h1:v+Rfd79xlw1AgVBjbO0BEQmptqb5HvL/k9GRHB7ZKEg=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
Expand Down Expand Up @@ -774,8 +772,8 @@ golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.52.0 h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988=
golang.org/x/crypto v0.52.0/go.mod h1:1QgfPxDqh0T2M/elOJtp9RvuR95kVjir0e6/BvEmGbc=
golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b h1:DXr+pvt3nC887026GRP39Ej11UATqWDmWuS99x26cD0=
golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b/go.mod h1:4QTo5u+SEIbbKW1RacMZq1YEfOBqeXa19JeshGi+zc4=
golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90 h1:jiDhWWeC7jfWqR9c/uplMOqJ0sbNlNWv0UkzE0vX1MA=
golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90/go.mod h1:xE1HEv6b+1SCZ5/uscMRjUBKtIxworgEcEi+/n9NQDQ=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
Expand Down
121 changes: 121 additions & 0 deletions internal/domain/processing/numscript/emulate.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"math/big"

numscriptlib "github.com/formancehq/numscript"
"github.com/formancehq/numscript/accounts"

"github.com/formancehq/ledger/v3/internal/domain"
)
Expand Down Expand Up @@ -154,6 +155,48 @@ func DiscoverNumscriptDependencies(cache *NumscriptCache, script string, vars ma
}
}

// Emulation gap fill: the discovery store returns fake infinite (positive)
// balances, so a balance-dependent amount can collapse to zero. In particular
// overdraft(@acc, A) folds to zero against a positive balance, turning
// `send overdraft(...)` into a zero-amount send that emits no posting. The
// source account then appears in neither queriedVolumes nor the postings and
// is missed entirely, causing "read of undeclared key" at execution
// (formancehq/ledger#1500).
//
// GetInvolvedAccounts statically walks the AST and reports every account each
// send touches — including `... allowing unbounded overdraft` sources —
// regardless of the resolved amount. We union the statically-resolvable pairs
// that emulation did not already classify as destinations into sourceVolumes.
// Over-preloading is safe (it only locks an extra row); under-preloading is
// the bug. Accounts already in destinationVolumes are skipped so the
// source/destination partition is preserved for scripts emulation handles.
//
// Best-effort: GetInvolvedAccounts can legitimately error on experimental
// constructs it does not model yet (e.g. asset scaling / colored sources)
// AND the interpreter can still panic on open issues (see e.g.
// formancehq/numscript#153). safeGetInvolvedAccounts degrades a panic to
// the same nil result as an error, so admission never rejects a script that
// emulation already accepted.
if involved, involvedErr := safeGetInvolvedAccounts(parsed, variablesMap); involvedErr == nil {
for _, ia := range involved {
account, okAccount := resolveInvolvedAccount(ia.AccountExpr)
asset, okAsset := resolveInvolvedAsset(ia.AssetExpr)
if !okAccount || !okAsset {
continue
}

key := domain.VolumeKey{
AccountKey: domain.AccountKey{LedgerName: ledgerName, Account: account},
Asset: asset,
}
if _, isDestination := destinationVolumes[key]; isDestination {
continue
}

sourceVolumes[key] = struct{}{}
}
}

// Collect account metadata keys written via set_account_meta.
var writtenMetadata map[domain.MetadataKey]struct{}
if len(execResult.AccountsMetadata) > 0 {
Expand All @@ -174,3 +217,81 @@ func DiscoverNumscriptDependencies(cache *NumscriptCache, script string, vars ma
WrittenMetadata: writtenMetadata,
}, nil
}

// resolveInvolvedAccount folds an involved-account name expression to a concrete
// account string. Variables are already substituted (they are bound in
// variablesMap during GetInvolvedAccounts) and meta() is rejected earlier, so
// the only shapes that reach here are literals and concatenations of them.
// Returns false for anything it cannot statically resolve, so the caller skips
// it rather than preloading a wrong key.
func resolveInvolvedAccount(expr accounts.InvolvedAccountExpr) (string, bool) {
switch e := expr.(type) {
case accounts.AccountLiteral:
return e.Account, true
case accounts.StringLiteral:
return e.String, true
case accounts.NumberLiteral:
if e.Amount == nil {
return "", false
}

return e.Amount.String(), true
case accounts.ConcatAccount:
left, ok := resolveInvolvedAccount(e.Left)
if !ok {
return "", false
}
right, ok := resolveInvolvedAccount(e.Right)
if !ok {
return "", false
}

return left + right, true
}

return "", false
}

// resolveInvolvedAsset folds an involved-account asset expression to a concrete
// asset string. GetAsset is transparent, and the asset of a monetary produced by
// balance()/overdraft()/a monetary literal is its asset argument, so the whole
// chain (e.g. GetAsset{GetOverdraft{@credit, USD/2}}) collapses to the literal
// "USD/2". Monetary arithmetic (Add/Sub/Div/SubPrefix) is asset-preserving —
// numscript requires operands to share an asset — so we recurse into either
// operand. Returns false for shapes it cannot statically resolve.
func resolveInvolvedAsset(expr accounts.InvolvedAccountExpr) (string, bool) {
switch e := expr.(type) {
case accounts.AssetLiteral:
return e.Asset, true
case accounts.MakeMonetary:
return resolveInvolvedAsset(e.Asset)
case accounts.GetBalance:
return resolveInvolvedAsset(e.Asset)
case accounts.GetOverdraft:
return resolveInvolvedAsset(e.Asset)
case accounts.GetAsset:
Comment thread
NumaryBot marked this conversation as resolved.
Comment thread
NumaryBot marked this conversation as resolved.
return resolveInvolvedAsset(e.Monetary)
case accounts.Add:
if asset, ok := resolveInvolvedAsset(e.Left); ok {
return asset, true
}

return resolveInvolvedAsset(e.Right)
case accounts.Sub:
if asset, ok := resolveInvolvedAsset(e.Left); ok {
return asset, true
}

return resolveInvolvedAsset(e.Right)
case accounts.Div:
if asset, ok := resolveInvolvedAsset(e.Left); ok {
return asset, true
}

return resolveInvolvedAsset(e.Right)
case accounts.SubPrefix:
return resolveInvolvedAsset(e.Expr)
}

return "", false
}
64 changes: 64 additions & 0 deletions internal/domain/processing/numscript/emulate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,70 @@ func TestDiscoverNumscriptDependencies(t *testing.T) {
require.True(t, hasBob, "should discover second destination")
})

t.Run("overdraft send discovers the unbounded-overdraft source (ledger#1500)", func(t *testing.T) {
t.Parallel()

script := `
#![feature("experimental-overdraft-function", "experimental-mid-script-function-call")]
send overdraft(@credit, USD/2) (
source = @repay allowing unbounded overdraft
destination = @credit
)
`

result, err := DiscoverNumscriptDependencies(testCache, script, nil, ledgerName)
require.NoError(t, err)

// @repay is the source. overdraft() folds to zero against emulation's fake
// positive balance, so the send emits no posting and @repay is never seen
// by emulation alone — it is recovered only via the static involved-accounts
// union.
_, hasRepay := result.SourceVolumes[domain.VolumeKey{
AccountKey: domain.AccountKey{LedgerName: ledgerName, Account: "repay"},
Asset: "USD/2",
}]
require.True(t, hasRepay, "should discover the unbounded-overdraft source @repay")

// @credit is read by overdraft(), so it is captured via GetBalances too.
_, hasCredit := result.SourceVolumes[domain.VolumeKey{
AccountKey: domain.AccountKey{LedgerName: ledgerName, Account: "credit"},
Asset: "USD/2",
}]
require.True(t, hasCredit, "should discover @credit")
})

t.Run("overdraft send inside arithmetic still discovers the unbounded-overdraft source", func(t *testing.T) {
t.Parallel()

// Same class of bug as ledger#1500, but the amount wraps overdraft() in
// monetary arithmetic. Emulation folds overdraft() to zero against a fake
// positive balance and [USD/2 0] is trivially zero, so the whole `+` folds
// to zero and no posting is emitted — @repay is missed by emulation. The
// static-involved-accounts union catches this iff resolveInvolvedAsset can
// see through Add/Sub/Div/SubPrefix nodes to the embedded asset. Two
// overdrafts in one script would trip the determinism guard, so we combine
// overdraft() with a literal zero instead.
script := `
#![feature("experimental-overdraft-function")]
vars {
monetary $due = overdraft(@credit, USD/2)
}
send [USD/2 0] + $due (
source = @repay allowing unbounded overdraft
destination = @credit
)
`

result, err := DiscoverNumscriptDependencies(testCache, script, nil, ledgerName)
require.NoError(t, err)

_, hasRepay := result.SourceVolumes[domain.VolumeKey{
AccountKey: domain.AccountKey{LedgerName: ledgerName, Account: "repay"},
Asset: "USD/2",
}]
require.True(t, hasRepay, "should discover @repay even when the amount wraps overdraft() in an Add node")
})

t.Run("parse error returns error", func(t *testing.T) {
t.Parallel()

Expand Down
23 changes: 23 additions & 0 deletions internal/domain/processing/numscript/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"

numscriptlib "github.com/formancehq/numscript"
"github.com/formancehq/numscript/accounts"

"github.com/formancehq/ledger/v3/internal/domain"
)
Expand Down Expand Up @@ -82,3 +83,25 @@ func SafeRun(parsed numscriptlib.ParseResult, ctx context.Context, vars numscrip

return
}

// safeGetInvolvedAccounts wraps ParseResult.GetInvolvedAccounts with a deferred
// recover. The numscript interpreter can still panic on open issues (see e.g.
// formancehq/numscript#153); admission callers treat both an error and a nil
// slice as "keep the emulation-only result", so we surface a panic through the
// same path rather than crashing the request. InvolvedMeta is intentionally
// dropped — the ledger admission layer only consumes InvolvedAccount.
func safeGetInvolvedAccounts(parsed numscriptlib.ParseResult, vars numscriptlib.VariablesMap) (involved []accounts.InvolvedAccount, err error) {
defer func() {
if r := recover(); r != nil {
involved = nil
err = fmt.Errorf("numscript panic: %v", r)
}
}()

involved, _, ierr := parsed.GetInvolvedAccounts(vars)
if ierr != nil {
return nil, ierr
}

return involved, nil
}
4 changes: 2 additions & 2 deletions tests/antithesis/workload/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ require (
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/formancehq/invariants v0.11.0 // indirect
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
github.com/getsentry/sentry-go v0.35.1 // indirect
github.com/getsentry/sentry-go v0.43.0 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-openapi/jsonpointer v0.21.0 // indirect
Expand Down Expand Up @@ -113,7 +113,7 @@ require (
go.uber.org/zap v1.27.1 // indirect
go.yaml.in/yaml/v2 v2.4.3 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b // indirect
golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90 // indirect
golang.org/x/oauth2 v0.35.0 // indirect
golang.org/x/sys v0.45.0 // indirect
golang.org/x/term v0.43.0 // indirect
Expand Down
12 changes: 6 additions & 6 deletions tests/antithesis/workload/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -103,12 +103,12 @@ github.com/formancehq/go-libs/v5 v5.7.0 h1:2Z2S3vtOJr45tKpofhPqd0qKrPr6KB/LZZ+Ef
github.com/formancehq/go-libs/v5 v5.7.0/go.mod h1:+jfCYWJ4Z10NGbhmbfon0hGoLe5pysbVQgePrg8M8W4=
github.com/formancehq/invariants v0.11.0 h1:AHFBhK7U8Ak/qoJwgaNU+cAb9w61Ba7dwlcrJTkWBE4=
github.com/formancehq/invariants v0.11.0/go.mod h1:ywzSexCUdhw2dC9Njiv0t4u2KfPVKj6SecFujPgmXno=
github.com/formancehq/numscript v0.0.24 h1:YBiDZ9zLVxTZVhtQ+taRcb6q2jArAvznWMfoWRVYGT0=
github.com/formancehq/numscript v0.0.24/go.mod h1:hC/VY5Vg04F5QkgdPPc6z/YsS/vh8V1qVJVa1VWnYMA=
github.com/formancehq/numscript v0.0.25-0.20260608064954-1fcd4893eafe h1:CL92PtU4vx7NGoTj6yohop09p8t5e4qpNWLSoPd24zM=
github.com/formancehq/numscript v0.0.25-0.20260608064954-1fcd4893eafe/go.mod h1:vQZOSwJItpYeCwUYNtV7bwu9naQoh2pdkkqs0ewkTiI=
github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
github.com/getsentry/sentry-go v0.35.1 h1:iopow6UVLE2aXu46xKVIs8Z9D/YZkJrHkgozrxa+tOQ=
github.com/getsentry/sentry-go v0.35.1/go.mod h1:C55omcY9ChRQIUcVcGcs+Zdy4ZpQGvNJ7JYHIoSWOtE=
github.com/getsentry/sentry-go v0.43.0 h1:XbXLpFicpo8HmBDaInk7dum18G9KSLcjZiyUKS+hLW4=
github.com/getsentry/sentry-go v0.43.0/go.mod h1:XDotiNZbgf5U8bPDUAfvcFmOnMQQceESxyKaObSssW0=
github.com/ghemawat/stream v0.0.0-20171120220530-696b145b53b9 h1:r5GgOLGbza2wVHRzK7aAj6lWZjfbAwiu/RDCVOKjRyM=
github.com/ghemawat/stream v0.0.0-20171120220530-696b145b53b9/go.mod h1:106OIgooyS7OzLDOpUGgm9fA3bQENb/cFSyyBmMoJDs=
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
Expand Down Expand Up @@ -289,8 +289,8 @@ golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUu
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b h1:DXr+pvt3nC887026GRP39Ej11UATqWDmWuS99x26cD0=
golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b/go.mod h1:4QTo5u+SEIbbKW1RacMZq1YEfOBqeXa19JeshGi+zc4=
golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90 h1:jiDhWWeC7jfWqR9c/uplMOqJ0sbNlNWv0UkzE0vX1MA=
golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90/go.mod h1:xE1HEv6b+1SCZ5/uscMRjUBKtIxworgEcEi+/n9NQDQ=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
Expand Down
Loading
Loading