test(e2e-live): HMA-orchestrated trade-flow control plane - #16
Merged
Merged
Conversation
Adds the trade-ops layer on top of PR-B's HMA-orchestrated lifecycle
foundation. Demonstrates the full Architecture-B path:
Test
├── sphere host spawn → HMA → escrow + 2 traders (PR-B)
└── sphere trader set-strategy / portfolio / list-… (this PR)
Files:
test/e2e-live/helpers/sphere-trader.ts (~280 lines)
Typed wrappers around `sphere trader …` subcommands:
setStrategy, createIntent, cancelIntent, listIntents,
listDeals, portfolio, status, waitForDealInState. All accept
a tenant address (@NameTag, DIRECT://, or hex pubkey) and
parse the AcpResultPayload JSON shape sphere-cli emits with
--json. Throws on ok=false with the trader-side error_code +
message so tests don't repeat the defensive parse.
test/e2e-live/hma-trade-flow.e2e-live.test.ts (~250 lines)
Live test: bootstraps controller wallet, boots HMA, spawns
escrow + Alice + Bob via `sphere host spawn`, then drives
each trader via `sphere trader …`:
- set-strategy: configures trusted_escrows on each trader
- portfolio: reads the (empty) initial balance
- list-intents: reads the (empty) intent list
The test is intentionally scoped to the read+config surface.
Three known issues block the full create-intent / list-deals
path; all are upstream sphere-cli bugs tracked as follow-ups:
1. `sphere trader status` calls STATUS over ACP, but STATUS
is a system-scoped command — the trader correctly rejects
with UNAUTHORIZED ("System command STATUS can only be
sent by the host manager"). Controllers should use
`sphere host inspect <name>` instead. Skipped here.
2. `sphere trader create-intent` sends `expiry_ms` over the
wire but trader-service's ACP schema requires
`expiry_sec`. INVALID_PARAM. One-line fix in sphere-cli.
3. (Not encountered in this trimmed test but related:)
`sphere trader create-intent` previously used
`--volume-total` flag; now `--volume-max` matching the
trader's `volume_max` ACP wire field. Helper updated.
A separate file `hma-trade-settlement.e2e-live.test.ts` will
cover the swap-completion flow (faucet-fund both traders,
post matching intents, wait for COMPLETED on both sides,
assert balances reflect the swap) once issues 1-2 are fixed
in sphere-cli.
Verified live (2026-05-04 testnet, 5/5 services healthy):
$ npm run test:e2e-live -- hma-trade-flow.e2e-live.test.ts
✓ drives the full trader CLI surface against HMA-spawned tenants
Duration: 39s
Combined with PR-B's lifecycle test:
✓ both tests pass in 66s end-to-end
Default suite unaffected: 651 tests still pass.
Now that PR-D fixes sphere-cli's expiry_ms→expiry_sec wire mismatch and removes the architecturally-broken `sphere trader status` (which called a system-scoped command over ACP), the full create-intent → list-intents → cancel-intent → verify-CANCELLED flow works end-to-end against live testnet. Verified: 48s (up from 40s with the +3 additional CLI round-trips).
Steelman round 1 on PR-D (sphere-cli #7) found that trader-service's own `src/cli/main.ts` (the trader-ctl shim used by direct-docker e2e tests) still emitted `volume_total` / `expiry_ms` on the wire — the EXACT bugs PR-D fixes upstream. Without this commit, the canonical sphere-cli would talk correctly to the trader but trader-service's own tooling would still produce INVALID_PARAM rejections, leaving a silent half-fix. src/cli/main.ts: - Rename `--volume-total` flag → `--volume-max` (matches the trader's `volume_max` ACP wire field per acp-types.ts:23). - Convert `expiry_ms` wire param → `expiry_sec` via `Math.floor(n / 1000)` matching sphere-cli's fix. - CLI-layer guards: reject sub-1000ms expiry with a helpful message; reject expiries > 7 days. Mirrors the trader-side validation in trader-command-handler.ts:331-342. Cascade: 7 other test/helper files referenced the old wire shape and needed renaming for consistency: - test/e2e-live/helpers/scenario-helpers.ts (createMatchingIntents builder used by direct-docker tests) - test/e2e-live/helpers/contracts.ts (MatchingIntents interface) - test/e2e-live/helpers/sphere-trader.ts (IntentSummary response field; the trader's outbound list-intents response also uses `volume_max` per trader-command-handler.ts:143) - test/e2e-live/helpers/tenant-fixture.test.ts (unit-test assertions on trader-ctl argv) - test/e2e-live/negotiation-failures.e2e-live.test.ts - test/e2e-live/basic-roundtrip.e2e-live.test.ts - test/e2e-live/edge-cases.e2e-live.test.ts - test/e2e-live/multi-agent.e2e-live.test.ts Verified: - Default suite: 651/651 tests pass (was 651, no regression) - Live e2e (hma-trade-flow): passes in 56s (full set-strategy + portfolio + list-intents + create-intent + cancel-intent + verify-CANCELLED flow) - Zero remaining `volumeTotal` / `--volume-total` / `volume_total` references in src/ or test/ Depends on sphere-cli PR #7 for the canonical CLI's matching fix.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Replaces #15 — PR-B merged via squash, which deleted the base branch and auto-closed #15. This PR has the same content rebased onto master.
Summary
Builds on PR #14 (now merged) by adding the trade-ops layer. Demonstrates the full Architecture-B path end-to-end against live testnet:
Verified live (2026-05-04, 5/5 testnet services HEALTHY)
The full flow:
sphere wallet init(controller bootstrap)dist/host-manager.js(HMA)sphere host spawn× 3 (escrow + Alice + Bob)sphere trader set-strategy× 2 (configure trusted_escrows)sphere trader portfolio× 2 (read balances, expect empty)sphere trader list-intents(empty)sphere trader create-intent(Alice posts buy)sphere trader list-intents(verify CREATED, non-terminal)sphere trader cancel-intentsphere trader list-intents(verify CANCELLED)sphere host stop× 3 (parallel teardown)Files
test/e2e-live/helpers/sphere-trader.ts(+317)sphere tradersubcommandtest/e2e-live/hma-trade-flow.e2e-live.test.ts(+250)src/cli/main.ts(modified)sphere trader …(volume_max,expiry_sec) — direct-docker tests no longer use the broken wire shape eithertest/e2e-live/helpers/{scenario-helpers,contracts,sphere-trader,tenant-fixture.test}.ts, plus 4 e2e test filesvolumeTotal/volume_total/--volume-total→volumeMax/volume_max/--volume-maxfor consistency with the trader's ACP wire fieldSteelman
Steelman ran on this PR via the wire-shape changes already validated alongside sphere-cli's PR-D (closed/replaced as PR-D2 #8 — now merged). The cascading rename here is mechanical and verified by:
grep -rn "volumeTotal\|--volume-total\|volume_total" src/ test/returns zero hitsDefault suite
651 tests still pass. Live tests opt-in via
npm run test:e2e-liveonly.