Skip to content

fix(ci): fix the lockfile, the migration comparison and the web type errors - #601

Merged
adenueltech merged 2 commits into
The-Engineer-Network:mainfrom
EmmanuelDesmond:fix/ci-failures-on-main
Oct 22, 2026
Merged

adenueltech merged 2 commits into
The-Engineer-Network:mainfrom
EmmanuelDesmond:fix/ci-failures-on-main

Conversation

@EmmanuelDesmond

@EmmanuelDesmond EmmanuelDesmond commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

What this changes

main is red, and it has been red for reasons that have nothing to do with whatever a pull request happens to change. Three CI jobs fail, each for its own reason:

Job Step Reason
Backend (Rust) Lint, Tests backend/crates/api/Cargo.toml declares reqwest.workspace = true, but the engipay-api entry in Cargo.lock does not list reqwest. Every step that passes --locked stops with cannot update the lock file.
Ledger guarantees (Postgres) Verify migrations are idempotent backend/scripts/verify-migrations.sh compares two pg_dump outputs, but filters out -- comments and blank lines only. pg_dump also brackets the dump with \restrict and \unrestrict lines carrying a random token, so the two passes never agree and the schemas always "differ".
Web app Type check npm run typecheck reports 18 errors across four files. The Naira ramp, the batch payments page, the buy page and the send page were merged without ever type-checking.

This pull request fixes those three, and one more thing it found on the way.

1. The api crate does not use reqwest. Nothing under backend/crates/api refers to it. The dependency is removed, so the manifest matches Cargo.lock again and cargo clippy --locked, cargo test --locked and cargo deny check can run.

2. pg_dump's random tokens are filtered out of the schema comparison. capture_schema now drops the \restrict and \unrestrict lines along with the comments. The two passes then compare the schema, and nothing else.

3. The web app type-checks again.

  • app/(app)/buy/page.tsx called formatRate(liveQuote.rate_kobo, liveQuote.asset). formatRate takes the quote and reads kobo_per_unit off it, so the call is now formatRate(liveQuote), the way lib/buy.test.ts already calls it.

  • app/(app)/send/page.tsx used Link and ArrowUpRight without importing them. They are imported now: Link from next/link, ArrowUpRight from lucide-react.

  • app/(app)/batch/page.tsx imported BatchPaymentStatusResponse and BatchPaymentRowResult; the client exports BatchPaymentStatus and RowResult. The names are corrected. approveBatchPayment returns nothing, so the page fetches the status again after approving instead of setting it from the empty response.

  • components/naira/NairaAnchorRamp.tsx was written against a Naira API that does not exist. It asked for asset_code and stellar_account, read id and url off the response, and imported NairaDepositResponse, NairaWithdrawalResponse and NairaTransactionStatusResponse, none of which the client exports. It now calls the API the api crate actually serves:

    • POST /v1/naira/deposits takes { amount } and returns { transaction_id, sep24_id, interactive_url, status }.
    • POST /v1/naira/withdrawals takes { amount, bank_account, bank_code, account_name } and returns the same shape.
    • GET /v1/naira/deposits/:id and GET /v1/naira/withdrawals/:id return AnchorTransactionStatus.

    The ramp moves Naira into USDC and USDC back out to a bank account, and the api crate only ever deals in USDC, so the two asset pickers that had no effect on the request are shown as the asset they are rather than as a choice.

  • lib/naira-ramp.ts gains getBankByCode, isSep24Terminal and isSep24Success, which the ramp needs, and the Sep24TransactionState type, the states of the anchor_status enum the api crate stores. lib/naira-ramp.test.ts covers them.

4. The change to the bitcoin sender test that #591 made does not hold. #591 turned assert!(prepared.change_sats > 0 || prepared.change_sats == 0) into assert!(prepared.change_sats >= 0), to clear clippy::double_comparisons. change_sats is a u64, so the new assertion is always true and clippy rejects it as an absurd_extreme_comparisons. The test withdraws 60_000 from 80_000 of input, so the change is 20_000 less the fee, and that is what it asserts now.

What is still red, and why

Fixing the lock file lets clippy run for the first time, and it turns out that the api crate has never compiled on main. cargo clippy --workspace --all-targets reports 65 errors in the api crate's lib target and 102 more in its test target. None of them is caused by this pull request, and none of them is a lint: they are type errors, and the --locked failure was hiding every one of them.

They come from three features that were each merged with code written against a different API than the one in the tree:

Where How many What
crates/api/src/routes/auth/stellar.rs 63 The code uses the pre-v21 stellar-xdr API - the int64, uint32 and uint64 aliases, TransactionEnvelope::TxV1, MuxedAccount::KeyTypeEd25519, Memo::MemoNone, TransactionV1Envelope::operations - while the workspace pins stellar-xdr = "28".
crates/api/src/routes/auth/evm.rs 18 The same story for ed25519-dalek = "2" and k256 = "0.13": SigningKey::sign moved to the Signer trait, PublicKey::to_encoded_point and recover_from_digest are gone, and sha2::Digest is not implemented for &[u8; 32].
crates/api/src/routes/transfers.rs, withdrawals.rs, buy.rs, crates/api/src/lib.rs 26 The routes call a services::receipts API that does not exist: Receipt has no field named kind, transaction_id, amount, created_at, sender_tag or recipient_tag, there is no Receipt::new, ReceiptSigner::from_seed or ReceiptSigner::from_config_or_test, the module is services::receipts and not services::receipt, and Asset::from_symbol does not exist.
crates/api/src/routes/batch_payments.rs 5 axum::extract::Multipart is not in axum 0.8's default features, plus two unused imports.
crates/api/src/routes/receipts.rs 2 It imports crate::state; the module is crate::AppState.
crates/api/src/routes/naira.rs 4 amount_in, amount_out and amount_fee are not in scope, and amount_requested is unused.

The "Ledger guarantees (Postgres)" job fails at "Database-backed tests" for the same reason: cargo test has to compile the api crate.

These are not lint fixes. They are a rewrite of the wallet sign-in code against the dependency versions in the tree, or a decision to pin the older versions instead - and both of those are decisions about money-handling code that belong in their own pull request, not in one that fixes CI.

How it was tested

  • cargo fmt --all --check in backend: passes.
  • cargo metadata --locked --format-version 1 in backend: passes. It failed with cannot update the lock file before this pull request.
  • npm run typecheck: passes. It reported 18 errors before this pull request.
  • npm test: passes, 145 tests, including the new cases in lib/naira-ramp.test.ts.
  • npm build: passes. All 28 pages are generated, /batch, /buy, /send and /sell among them.
  • On CI, the "Type check" and "Tests" steps of the "Web app" job pass, "Verify migrations are idempotent" and "Database refuses ledger corruption" pass, and "Format" in the "Backend (Rust)" job passes.
  • The migration script's filter was checked against two pg_dump outputs that differ only in their random \restrict token: they now compare equal. On CI the step now reports Schemas match - migrations are idempotent.
  • The Rust workspace could not be compiled on this machine: it has no Windows SDK, so link.exe is missing and every build script fails to link. cargo fmt and cargo metadata do not need a linker and were run in full; cargo clippy and cargo test need CI.

Checklist

  • npm run typecheck, npm test and npm run build pass (web app changes)
  • cargo fmt, cargo clippy -- -D warnings and cargo test pass (backend changes) - cargo fmt --all --check and cargo metadata --locked pass locally; clippy and test are blocked by the api crate's own type errors, listed above
  • No secrets, keys or .env files are included
  • Money is handled as exact integers or decimal strings, never floating point
  • Lockfile changes are intentional and explained above - no lockfile changes: the manifest is brought back in line with the lock file

One thing to know before merging

#594 adds "reqwest" to the engipay-api entry in backend/Cargo.lock, which is the other way of making the lock file agree with the manifest. The api crate does not use reqwest: not in price_source.rs, the code #594 adds, and nowhere else under backend/crates/api. This pull request drops the dependency instead and leaves the lock file alone.

If both are merged, the manifest no longer declares reqwest while the lock file still lists it in engipay-api, and every step that passes --locked stops again with cannot update the lock file. #594's lock file hunk should be dropped, or that branch rebased on this one.

…errors

`main` is red in three places, and none of them has anything to do with
whatever a pull request happens to change.

- the api crate declares `reqwest` but never uses it, and the `engipay-api`
  entry in `Cargo.lock` does not list it either, so every step that passes
  `--locked` stops with "cannot update the lock file". The dependency is
  removed, so the manifest and the lock file agree again.
- `verify-migrations.sh` compares two `pg_dump` outputs but filters out the
  comments and the blank lines only. `pg_dump` also brackets the dump with
  `\restrict` and `\unrestrict` lines carrying a random token, so the two
  passes never matched. Those lines are filtered out now.
- the web app does not type check. The Naira ramp was written against an API
  that does not exist: it asked for `asset_code` and `stellar_account`, read
  `id` and `url` off the response and imported three types the client does
  not export. It calls the API the api crate actually serves now. The batch
  payments page uses the names the client exports, the buy page calls
  `formatRate` the way it is defined, and the send page imports `Link` and
  `ArrowUpRight`.
@vercel

vercel Bot commented Oct 22, 2026

Copy link
Copy Markdown

@EmmanuelDesmond is attempting to deploy a commit to the emmanuel adewunmi's projects Team on Vercel.

A member of the Team first needs to authorize it.

…is non-negative

`change_sats` is a `u64`, so `assert!(prepared.change_sats >= 0)` is always
true and clippy rejects it as an absurd extreme comparison. The test
withdraws 60_000 from 80_000 of input, so the change is 20_000 less the fee.
@adenueltech
adenueltech merged commit e09cacb into The-Engineer-Network:main Oct 22, 2026
1 of 5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants