Skip to content

test: #156 — comprehensive CLI integration coverage post-extraction#13

Merged
vrogojin merged 10 commits into
integration/all-fixesfrom
test/cli-send-coverage
May 15, 2026
Merged

test: #156 — comprehensive CLI integration coverage post-extraction#13
vrogojin merged 10 commits into
integration/all-fixesfrom
test/cli-send-coverage

Conversation

@vrogojin
Copy link
Copy Markdown
Contributor

Summary

Fills the CLI test coverage gap from sphere-sdk issue #156. When the in-tree sphere-sdk CLI was extracted to @unicity-sphere/cli, the binary-level test coverage went dark — SDK-module-level tests existed but nothing exercised the CLI plumbing (namespace bridge, arg parsing, exit codes, output shapes).

This PR adds 10 new integration test files (~120 tests, ~2500 lines) covering every practical CLI surface, plus pins 4 security/correctness invariants end-to-end.

What's covered

File Tests Surface
cli-send.integration.test.ts 6 payments send (5 active + 1 funded-gated)
cli-invoice.integration.test.ts 29 invoice create/import/list/status/pay/close/cancel/return/receipts/notices/auto-return/transfers/export/parse-memo + bug fix in legacy-cli.ts
cli-nametag.integration.test.ts 13 nametag register/info/my/sync
cli-l1.integration.test.ts 2 payments l1-balance (only L1 verb in CLI)
cli-faucet.integration.test.ts 7 topup/top-up/faucet (live faucet gated by E2E_RUN_FAUCET=1)
cli-multiaddress.integration.test.ts 18 payments addresses/switch/hide/unhide
cli-wallet-profile.integration.test.ts 25 wallet list/use/create/current/delete
cli-wallet-state.integration.test.ts 8 payments history/sync/receive + verify-balance
cli-assets.integration.test.ts 7 payments assets/asset-info
cli-wallet-lifecycle.integration.test.ts 10 init/status/clear/config

Security/correctness invariants pinned

  1. HD-address token isolation (cli-multiaddress) — same mnemonic, different HD indices. After switch 1, payments tokens at feat: sphere-cli phase 2 — legacy bridge + host DM transport #1 shows NO tokens from #0. On-disk per-address tokens/DIRECT_<6hex>_<6hex>/ subdirs are physically separate. Funded-gated proof: faucet at #0 invisible at feat: sphere-cli phase 2 — legacy bridge + host DM transport #1, preserved after round-trip.

  2. Cross-profile wallet isolation (cli-wallet-profile) — different mnemonics per profile. Create alice + wallet init → captures directAddrAlice; create bob (auto-switches) + wallet init → directAddrBob differs; switch back to alice → status shows alice's directAddress exactly. Per-profile wallet.json files in separate dataDirs.

  3. clear confirmation guard (cli-wallet-lifecycle) — destructive wipe demands literal "yes" stdin OR --yes flag. Pinning both paths: clear with stdin "no\n" prints "Aborted." + wallet survives; clear --yes bypasses guard + wallet wiped.

  4. BIP-39 + HD derivation determinism (cli-wallet-lifecycle) — wallet init (with SPHERE_ALLOW_MNEMONIC_NON_TTY=1) captures mnemonic + directAddress → clear --yeswallet init --mnemonic <captured> re-derives the SAME directAddress. Any regression in BIP-39 → seed → HD-path → secp256k1 → bech32 anywhere along the pipeline flips this red.

CLI bug fixed (commit ee41241)

src/legacy/legacy-cli.ts invoice-create and invoice-return were passing the 64-char hex resolveCoin().coinId to AccountingModule, which validates coinId as ≤20 chars alphanumeric (i.e. expects the symbol UCT, not the hex). Switched both call sites to resolveCoin().symbol. Bug surfaced by the new cli-invoice create-then-status e2e test.

Gotchas pinned (documented inline)

  • Asymmetric registration: topup, top-up, verify-balance, assets, asset-info are NOT top-level commands. Only reachable via payments <name>. Only faucet is a bare top-level verb.
  • L1 surface narrow: only l1-balance in CLI. No l1-send/l1-history/l1-receive (those are SDK-only via sphere.payments.l1).
  • Faucet delivery async: API returns "Received" when queued on relay, NOT when wallet finalizes. Tests that depend on token presence poll a sync-enabled payments tokens until UCT lands locally.
  • parse-wallet/wallet-info: exist in legacy-cli but unreachable via the new dispatch (dead code).
  • Sphere generates 12-word BIP-39 mnemonics (some older docs imply 24). Mnemonic regex accepts BIP-39's full valid range (12/15/18/21/24).

Test plan

  • npx vitest run --config vitest.integration.config.ts — all 10 new files green (with SKIP_INTEGRATION=1 for offline tier ~3s; full ~5min)
  • npx eslint . clean on all new files
  • npm run typecheck clean
  • E2E_RUN_FAUCET=1 verified for cli-faucet live-faucet test (~36s)
  • E2E_RUN_FAUCET=1 verified for cli-multiaddress funded isolation proof (~111s)

Vladimir Rogojin added 10 commits May 15, 2026 14:42
Replaces coverage previously held by sphere-sdk's deleted placeholder
`tests/integration/cli/uxf-transfer.test.ts` (sphere-sdk issue #156).
That file pinned the in-tree `cli/index.ts` source which no longer
exists post-extraction; this is a real subprocess integration test
against the same surface in its new home.

Pins:
  1. `sphere payments help send` lists --instant / --conservative /
     positionals — the help-grep half of the old test.
  2. `sphere payments send` with no args exits non-zero with the
     documented usage line.
  3. `sphere payments send <addr> 0.001 UCT --instant` from an empty
     wallet exercises arg-parse → Sphere.init → payments.send →
     insufficient-funds error → non-zero CLI exit. The full path is
     covered without needing a funded fixture.
  4. `sphere payments send <addr> 0.001 UCT --conservative` likewise,
     proving the `transferMode` flag reaches the SDK without tripping
     the mutual-exclusion guard.
  5. `sphere payments send <addr> 0.001 UCT --instant --conservative`
     trips the mutual-exclusion guard fast (pre-init), exits non-zero.
  6. Funded transfer (gated on E2E_FUNDED_MNEMONIC) — imports a
     pre-funded testnet wallet, sends 0.001 UCT to a fresh recipient,
     polls receiver balance for receipt. Opt-in to avoid faucet/drain
     burden on every test runner.

Suite runs in ~10s end-to-end against the public testnet (1 funded
test skipped without the env var). Verified locally with the latest
sphere-cli build linked against sphere-sdk @ branch
fix/156-cli-test-coverage.
Adds cli-invoice.integration.test.ts (29 tests, 5s offline + 110s e2e):
- 14 offline help-shape pins, one per invoice subcommand (create, list,
  status, pay, close, cancel, return, receipts, notices, auto-return,
  transfers, export, import, parse-memo). Asserts documented flags and
  positionals so a help-text drift is caught immediately.
- 10 offline arg-validation pins (8 subcommands × no-id usage exit +
  parse-memo no-memo + one helper test). These exercise the arg-check
  paths that run BEFORE getSphere() in legacy-cli.ts dispatch, keeping
  the suite offline-safe.
- 5 e2e lifecycle tests against real testnet: empty-wallet list, create,
  list-after-create, status (OPEN), close (→ CLOSED). Pins the namespace
  bridge, accounting module wiring, prefix-resolution, and the OPEN →
  CLOSED state transition end-to-end.

Bug fix surfaced by the new tests: invoice-create and invoice-return
were passing the 64-char hex coinId from `resolveCoin().coinId` to
AccountingModule, which validates coinId as `/^[A-Za-z0-9]+$/` with
length ≤20 — i.e. it expects the human-readable symbol (UCT, USDU, ...),
not the hex token-type id that `payments.send` uses. Switched to
`resolveCoin().symbol` for both call sites; resolveCoin still validates
that the symbol is known.

Companion fix in sphere-sdk (commit 6f957af on fix/156-cli-test-coverage)
addresses the null-dueDate-treated-as-EXPIRED issue that the same e2e
lifecycle test discovered while asserting state === 'OPEN'.
Add cli-nametag.integration.test.ts covering the four nametag CLI
subcommands (register / info / my / sync) that lost binary-level coverage
when the in-tree sphere-sdk CLI was extracted. SDK-layer coverage exists
for the underlying registerNametag + transport binding plumbing; this
file pins the CLI plumbing — namespace bridge, arg parsing, help text —
that sits between the user and the SDK.

Three layers, same shape as cli-invoice.integration.test.ts:

1. Help-shape pins (offline, 4 tests) — `payments help <legacy>` for
   nametag / nametag-info / my-nametag / nametag-sync. Pins the usage
   line + a small set of must-match regexes.

2. Arg-validation pins (offline, 3 tests) — `sphere nametag`,
   `sphere nametag register`, `sphere nametag info` with no name. These
   exit non-zero with a "Usage: ..." hint before any wallet load
   because legacy-cli.ts checks args[1] before getSphere() in both the
   `nametag` (~2592) and `nametag-info` (~2619) cases.

3. End-to-end lifecycle (network, 6 tests) — real testnet wallet,
   real Nostr relay, real aggregator. Drives:
     a. `nametag my` on fresh wallet → "No nametag registered"
     b. `nametag info <ghost>` → "not found"
     c. `nametag register <random>` → on-chain mint + Nostr publish
     d. `nametag my` → returns the registered name
     e. `nametag info <registered>` → returns binding record
     f. `nametag sync` → re-publishes the binding
   Each run mints a fresh `it_<8hex>` nametag to avoid collisions.

13 tests total, all green. Offline subset runs in <2s; e2e in ~28s
against testnet. Gated by SKIP_INTEGRATION=1 like the sibling suites.
Add cli-l1.integration.test.ts pinning the only L1 (ALPHA blockchain)
command exposed by this CLI: `payments l1-balance`. SDK-layer coverage
for L1 balance / Fulcrum / vesting lives in sphere-sdk
`tests/unit/l1/*.test.ts`. What this file pins is the CLI plumbing:
legacy-CLI dispatch, the human-readable output format that wallet
scripts grep.

Scope note: `l1-send`, `l1-history`, and `l1-receive` are NOT exposed
as CLI verbs (only `l1-balance` is wired through legacy-cli.ts ~2168).
The full L1 API is available via `sphere.payments.l1` at the SDK
layer. Memory snapshot for #156 previously listed l1-send as a gap;
correcting that: no L1 send CLI exists to test.

Two layers:

1. Help-shape pin (offline) — `payments help l1-balance` returns the
   legacy block with the usage line, "ALPHA" symbol mention, and the
   "Fulcrum" connection hint (load-bearing for ops / network policy).

2. End-to-end pin (network) — Fresh testnet wallet → run
   `payments l1-balance` → assert the 3-line output block:
     "L1 (ALPHA) Balance:"
     "Confirmed: <number> ALPHA"
     "Unconfirmed: <number> ALPHA"
   A fresh wallet has zero balance; assertion is purely on line
   structure, not on a specific numeric value.

The "L1 module not available" error path in legacy-cli.ts is
deliberately NOT pinned — Sphere.init() creates the L1 module by
default, so that path is unreachable through this CLI's normal init.
Pinning unreachable error paths produces brittle tests.

2 tests, both green: offline <500ms, e2e ~1s against testnet.
…erage

Add cli-faucet.integration.test.ts pinning the testnet-faucet CLI
surface across all three command aliases (topup / top-up / faucet).
No SDK-layer coverage exists for this — the faucet client is
implemented entirely inside the legacy-CLI handler (~line 2942), so
this file is the only layer that pins it.

Three layers:

1. Help-shape pins (offline, 3 tests) — `payments help <alias>` for
   each of topup / top-up / faucet. All three HELP_TEXT entries
   (~lines 597-636) live independently; pinning all three catches a
   refactor that drops one alias's doc without updating dispatch.

2. No-nametag dispatch pins (network, wallet init only, 3 tests) —
   Asserts that running each alias on a fresh wallet (no nametag)
   exits non-zero with "No nametag registered" stderr BEFORE any
   faucet HTTP call. Proves:
     a. namespace registration is asymmetric (only `faucet` is
        registered top-level via LEGACY_NAMESPACES; topup / top-up
        are reachable via `payments <alias>`)
     b. all three names land in the same fall-through case label
     c. the precondition fires before the HTTP round-trip so a
        broken/rate-limited faucet doesn't mask a wallet-setup error

3. Live faucet round-trip (opt-in, E2E_RUN_FAUCET=1, 1 test) —
   Registers a fresh `it_<hex>` nametag, requests 1 UCT from the
   faucet, asserts the "Received 1 unicity" success line (pins the
   UCT → unicity symbol-to-faucet-name resolution at ~line 2996).
   Gated because the faucet has rate limits + drain protection +
   external service flakiness; consumes real testnet tokens.

Verified live faucet round-trip succeeds against
faucet.unicity.network — 4 tests run by default + 1 opt-in gated.
Offline ~1s, default e2e ~5s, with-live-faucet ~36s.
Add cli-multiaddress.integration.test.ts pinning the four multi-address
commands (addresses / switch / hide / unhide) plus, critically, the
TOKEN ISOLATION INVARIANT across HD-derived addresses.

The CLI extraction left two distinct things uncovered:

  A) CLI plumbing for the multi-address commands (namespace bridge,
     arg parsing, help text).

  B) The security-critical guarantee that tokens belonging to address
     #N never leak to address #M after a switch. A regression here
     would mean a user who switched to a fresh address could
     accidentally spend tokens that belong to a different HD branch.

The architectural mechanism is per-address token storage: Node.js
FileTokenStorageProvider keeps a separate `tokens/<addressId>/`
subdirectory per tracked address. `sphere.payments.getTokens()` reads
from the storage bound to the currently-active address — so as long
as the directory split is honoured, isolation holds.

Four layers of pins:

1. Help-shape pins (offline, 4 tests) — `payments help <cmd>` for
   each of addresses/switch/hide/unhide. HELP_TEXT keys ~707-735.

2. Arg-validation pins (offline, 4 tests) — switch/hide/unhide with
   no <index>, plus `switch abc` (non-numeric guard at ~line 2545).
   All exit non-zero with "Usage: ..." or "Invalid index" before
   getSphere().

3. Stateful local lifecycle (network-light, 7 tests) — fresh wallet
   shows only #0 → switch 1 creates+activates #1 with a DIFFERENT
   directAddress (HD-derivation isolation pin #1) → on-disk
   tokens/ has exactly 2 distinct DIRECT_<...> subdirs (storage
   isolation pin #2) → hide/unhide round-trip → switch back to #0
   restores the original directAddress exactly (state-preservation
   pin #3, no cross-pollination of identity material).

4. Token isolation invariant (opt-in, E2E_RUN_FAUCET=1, 3 tests) —
   the gold-standard funded leak proof:
     a. faucet 1 UCT at #0; beforeAll polls until UCT lands locally
     b. payments tokens at #0 → UCT visible
     c. switch to #1 → payments tokens shows "No tokens found"
        (THE LEAK TEST — would flip red on cross-address visibility)
     d. switch back to #0 → UCT still there, untouched
   Gated because on-chain nametag mint (~20s) plus faucet (~5s)
   plus the polling loop add ~60-90s on top of the default suite.

Verified with E2E_RUN_FAUCET=1: all 18 tests green in ~111s. The
funded leak proof confirms the isolation invariant holds in practice,
not just in the directory-layout pin.

Implementation note: faucet delivery is async — the faucet API
returns success when the gift-wrap is queued on the relay, not when
the wallet has finalized it into local storage. beforeAll polls
`payments tokens` (with sync) up to 3 times until UCT appears at #0,
then tests use --no-sync for fast per-address reads.
Add cli-wallet-profile.integration.test.ts pinning the five wallet
profile-management subcommands (list / use / create / current / delete)
plus the CROSS-PROFILE ISOLATION INVARIANT.

Note on scope: this fills the "token export/import" gap from the #156
follow-up plan. The CLI has no token-level export/import command — the
closest analogues are `parse-wallet` / `wallet-info` which exist in
legacy-cli.ts but are unreachable through the new namespace dispatch
(dead code). What the CLI DOES expose is profile-level wallet
management, and that surface had zero e2e coverage post-extraction
(cli-wallet.integration.test.ts only covers `wallet init`).

The isolation concern is stronger than the HD-address case pinned in
cli-multiaddress: profiles hold INDEPENDENT MNEMONICS. A leak between
profiles could mean signing transactions with the wrong key or losing
access to a profile entirely. Architectural mechanism: `wallet create
<name>` writes a profile with `dataDir = ./.sphere-cli-<name>` and
flips config.json's active dataDir pointer. `getSphere()` reads from
the current pointer.

Four layers of pins:

1. Help-shape pins (offline, 6 tests) — `payments help "wallet"`,
   `"wallet list"`, `"wallet use"`, `"wallet create"`, `"wallet
   current"`, `"wallet delete"`. Multi-word HELP_TEXT keys passed as
   a single argv element (commander preserves them).

2. Arg-validation pins (offline, 5 tests) — `wallet use/create/delete`
   without `<name>` (handlers check profileName before disk write).
   `wallet create '!invalid'` rejects bad charset (~line 1849 guard
   prevents path-traversal-like names). `wallet bogus-sub` exits 1
   via the default `Unknown wallet subcommand` block.

3. CRUD lifecycle (offline, 11 tests) — empty store → create alice →
   duplicate-create rejects → current shows alice → create bob
   auto-switches → list shows both with → marker on bob → use alice
   → use unknown rejects → delete alice (current) refused → delete
   bob succeeds → list no longer shows bob → delete unknown rejects.

4. Cross-profile isolation (network, 3 tests) — init in profile alice
   captures directAddrAlice; init in profile bob captures
   directAddrBob; expect ≠ alice; both per-profile wallet.json files
   exist as separate paths; switch back to alice → `sphere status`
   shows alice's directAddress EXACTLY (not bob's).

All 25 tests green in ~11s total. The isolation suite added ~4s on
top of the 7s offline tier — much faster than expected because fresh
profiles don't carry sync state.

Implementation note: `sphere status` prints human-readable output
("Direct Addr:   DIRECT://..."), not JSON. The isolation pin matches
that format directly; `wallet init` emits JSON which is matched by
its own regex in the per-profile init steps.
…/verify-balance)

Add cli-wallet-state.integration.test.ts covering four wallet-state
inspection / validation commands that lost binary-level coverage when
the in-tree sphere-sdk CLI was extracted:

  - `payments history`        — local transaction history
  - `payments sync`            — pull remote storage into local state
  - `payments receive`         — finalize incoming gift-wraps
  - `payments verify-balance` — validate tokens against aggregator
                                 (spent-token detection)

SDK-layer coverage for each underlying operation exists in
sphere-sdk's PaymentsModule + TokenValidator tests. What this file
pins is the CLI plumbing — exit codes, output shape — that
wallet-management scripts rely on.

Two layers:

1. Help-shape pins (offline, 4 tests) — `payments help <name>` for
   each command, asserting documented flags + positionals.

2. Fresh-wallet lifecycle (network, 4 tests) — brand-new testnet
   wallet → each command exits 0 with the expected empty-state output:
     - history → "Transaction History (last 10):" + "No transactions found"
     - sync → exit 0 (no specific output, load-bearing exit code)
     - receive → exit 0 (no in-flight gift-wraps)
     - verify-balance → "Valid tokens: 0" + "Spent tokens: 0"
   Catches the "empty wallet" regression class where 0-token paths
   inadvertently rely on a non-empty precondition.

Implementation gotcha pinned: `verify-balance` is NOT a top-level
command — same asymmetric registration as `topup`/`top-up` (only
`faucet` is bare top-level). Reachable only via `payments
verify-balance`. Test uses the working form explicitly.

8 tests, all green: offline ~1s, full e2e ~60s. Per-address /
per-profile isolation is already pinned comprehensively by
cli-multiaddress.integration.test.ts and
cli-wallet-profile.integration.test.ts — this file deliberately
focuses on the command surfaces themselves, not re-running isolation
proofs.
Add cli-assets.integration.test.ts covering the two CLI commands that
surface the global TokenRegistry: `payments assets` (list) and
`payments asset-info` (per-asset details).

SDK-layer coverage for TokenRegistry caching / auto-refresh / race-
safe load lives in sphere-sdk's tests/unit/registry/TokenRegistry.test.ts.
What this file pins is the CLI layer: dispatch, multi-strategy lookup,
output shape.

Three layers:

1. Help-shape pins (offline, 2 tests) — `payments help assets`
   (asserts `--type` filter + fungible/nft keywords) and `payments
   help asset-info` (asserts `<symbol|name|coinId>` multi-strategy
   positional).

2. Arg-validation pin (offline, 1 test) — `payments asset-info`
   without identifier exits 1 with usage hint BEFORE getSphere().

3. Network registry queries (4 tests) — fresh testnet wallet drives:
     a. `assets` lists at least UCT (proves remote registry fetch +
        column-aligned table header)
     b. `assets --type fungible` filters out NFTs (no "non-fungible"
        in output)
     c. `asset-info UCT` returns Symbol/Kind=fungible/Coin ID hex/Network
        — pins the symbol-strategy branch of the lookup
     d. `asset-info <bogus>` exits 1 with "Asset not found" — pins
        the negative path (all 3 lookup strategies failed)

Implementation gotcha pinned: `assets` and `asset-info` are NOT
top-level commands (asymmetric registration, same as topup /
verify-balance). Reachable only via `payments assets` / `payments
asset-info`. Test uses the working form explicitly.

7 tests, all green: offline ~1s, full e2e ~5s.
…nic round-trip

Add cli-wallet-lifecycle.integration.test.ts filling the remaining
wallet-management gaps that cli-wallet.integration.test.ts (only
covers `wallet init` + `wallet status`) and cli-wallet-profile
(only covers profile CRUD list/use/create/current/delete) leave
uncovered:

  - `clear`     — destructive wipe + --yes confirmation-guard bypass
  - `config`    — show / set network / dataDir / tokensDir
  - `init --mnemonic` — explicit deterministic import round-trip

The most security-critical pin is `clear`'s confirmation guard.
Without it, a user could accidentally wipe their wallet keys (no
recovery without the backed-up mnemonic). The guard demands literal
"yes" stdin input; --yes / -y bypass for scripted contexts. Both
paths pinned:

  - `clear` with stdin "no\n" → "Aborted." + wallet survives
    (re-verified via `status` still reporting the original
    directAddress)
  - `clear --yes` → wipe succeeds + `status` reports "No wallet
    found"

The BIP-39 determinism round-trip is the strongest integration-level
proof of wallet-recovery correctness:
  1. wallet init (with SPHERE_ALLOW_MNEMONIC_NON_TTY=1) → captures
     mnemonic + directAddress_A from stdout
  2. clear --yes → wallet wiped
  3. wallet init --mnemonic <captured> → directAddress_B
  4. EXPECT directAddress_A === directAddress_B

Any regression in BIP-39 → seed → HD-derivation → secp256k1 →
bech32 along the entire wallet-recovery pipeline flips this red.
SDK-level coverage exists for each individual step; this is the
only end-to-end CLI pin.

Three layers:

1. Help-shape (offline, 4 tests) — init/status/clear/config blocks.

2. Config get/set (local, no network, 3 tests) — `config` shows JSON,
   `config set network dev` mutates + persists, `config set bogus
   value` rejects with "Unknown config key" + valid-key hint.

3. Init / clear / re-init round-trip (network, 3 tests) — described
   above. Wallet init emits mnemonic to stdout when
   SPHERE_ALLOW_MNEMONIC_NON_TTY=1 (test-harness opt-in documented
   at legacy-cli.ts ~line 1675).

10 tests, all green: offline ~2s, full e2e ~5.6s.

Finding: Sphere generates 12-word BIP-39 mnemonics, not 24 as some
older docs/comments suggest. The mnemonic regex accepts BIP-39's full
valid range (12, 15, 18, 21, 24 words) anchored to a stdout line.
@vrogojin vrogojin merged commit 55ae1ea into integration/all-fixes May 15, 2026
vrogojin added a commit that referenced this pull request May 15, 2026
…group + market

Fills the remaining CLI test gaps from PR #13's follow-up comment on
issue #156. 6 commits, +1,827 lines, +89 tests.

Coverage delta:
  - swap        — 18 offline + 3 e2e (2 default + 1 stretch-gated)
  - crypto/util — 37 offline (expanded from 3)
  - init --nametag — 2 e2e
  - group       — 17 offline
  - market      — 9 offline

Infrastructure additions:
  - test/integration/local-infra/ (docker-compose.yml, relay.ts,
    escrow.ts) for swap e2e + reserved for group/market e2e
  - helpers.ts: createSphereEnv accepts { extraEnv }; MaxListeners
    guard fixes 11-listener warning

Review fixes (PR #14):
  - escrow.ts UNICITY_RELAYS → UNICITY_NOSTR_RELAYS (silent ignore bug)
  - UNICITY_MANAGER_DIRECT_ADDRESS now uses DIRECT:// prefix
  - Wallet dir 0700 hardening matches helpers.ts pattern
  - Inline docs on swap full-settlement fragility
  - TODO(security) marker on decrypt-wrong-pw bug

Critical caveat for downstream: ghcr.io/vrogojin/agentic-hosting/escrow:v0.1
is stale vs integration/all-fixes; the swap e2e tier requires a locally
built escrow:local-uxf image (build steps in escrow.ts docstring). A
future agentic-hosting v0.2 publish would remove this requirement.

Test status:
  - Offline tier: 162/162 passing
  - swap e2e default: 2/2 passing (~2.2 min)
  - swap e2e stretch: gated, known fragile
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.

1 participant