Summary
Finish the TestTarget::Devnet wiring so the CIP-104 Mode A coupon-reassignment integration test can run automatically against devnet and reproduce the manual pre-merge exercise (reassign + 0.8/0.2 split verified against real cbtc-network coupons).
This is the Option B follow-up to the localnet-seeding hardening (Option A), which lands separately and gives deterministic every-PR CI coverage. Option B is complementary: it targets the real network, so it can never be a required CI gate (it depends on live coupon timing and Mode-B coordination) — its value is an on-demand, automated reproduction of the manual devnet run.
Context: PR #255 (CIP-104 Mode A coupon-reassignment automation) is the feature; the IT hardening is being done as separate follow-up PR(s). The devnet scaffolding is already half-built (TestTarget::{Localnet,Devnet}, discover_network_parties(), Keycloak auth::Refresher, ParticipantAdminCreds).
Blockers to wire
-
Target-aware HTTP layer. crates/decman/tests/common/http.rs hardcodes http://localhost:{port} and always attaches the static/mock bearer. Make the base URL target-aware (HTTPS host on devnet) and attach the auth::Refresher (Keycloak client-credentials) token so requests authenticate against real DecMan nodes.
-
Standalone reward-only entrypoint. The reward phase currently runs at the END of the full localnet bootstrap sequence in crates/decman/tests/governance_workflows.rs. Pointed at devnet, the earlier phases would try to onboard a NEW decparty (topology writes/freeze) instead of using the pre-existing cbtc-network. Add an entry that runs ONLY the reward phase against the existing devnet decparty and skips the bootstrap phases.
-
Real beneficiary/assigner parties from config/ledger. crates/decman/tests/common/phases/coupon_reassignment.rs hardcodes beneficiaries to fixture parties (p2_member/p3_member). On devnet read the real cbtc-beneficiary / operator parties (and the active attestor assigners) from config or the ledger.
-
PQS split-by-value assertion. Add the per-beneficiary field-level check against devnet PQS pqs_cbtc: one RewardCouponV2 per beneficiary with beneficiary ∈ {cbtc-beneficiary, operator} and the 0.8/0.2 amount shares. Query archives('splice-amulet:Splice.Amulet:RewardCouponV2') grouped by payload->>'beneficiary'. Reference numbers from the manual run: cbtc-beneficiary 27,689.39 vs operator 6,922.35 (exactly 4:1).
Acceptance
DECPM_IT_TARGET=devnet DECPM_IT_REWARD=1 <entrypoint> runs the reward phase against cbtc-network, exercises Delegation_Assign, and asserts the 0.8/0.2 split by value via PQS.
- Documented operational preconditions (Mode-B collection paused for
cbtc-network, short DECPM_REWARD_AUTOMATION_INTERVAL_SECS, coupons re-accumulated unassigned).
- NOT added as a required CI check (non-deterministic; depends on live network state).
Non-goals
- Localnet coupon-seeding CI coverage — handled by the Option A follow-up PR.
- The ledger-level non-assigner negative — covered in DAML (
test_non_assigner_cannot_reassign); a devnet ledger-level repro stays a manual ops step (no HTTP path to submit as an arbitrary party).
Key files
crates/decman/tests/common/http.rs
crates/decman/tests/common/mod.rs (TestTarget, Fixture, discover_network_parties)
crates/decman/tests/common/auth.rs (Keycloak Refresher)
crates/decman/tests/common/phases/coupon_reassignment.rs
crates/decman/tests/governance_workflows.rs (gating / phase ordering)
Summary
Finish the
TestTarget::Devnetwiring so the CIP-104 Mode A coupon-reassignment integration test can run automatically against devnet and reproduce the manual pre-merge exercise (reassign + 0.8/0.2 split verified against realcbtc-networkcoupons).This is the Option B follow-up to the localnet-seeding hardening (Option A), which lands separately and gives deterministic every-PR CI coverage. Option B is complementary: it targets the real network, so it can never be a required CI gate (it depends on live coupon timing and Mode-B coordination) — its value is an on-demand, automated reproduction of the manual devnet run.
Context: PR #255 (
CIP-104 Mode A coupon-reassignment automation) is the feature; the IT hardening is being done as separate follow-up PR(s). The devnet scaffolding is already half-built (TestTarget::{Localnet,Devnet},discover_network_parties(), Keycloakauth::Refresher,ParticipantAdminCreds).Blockers to wire
Target-aware HTTP layer.
crates/decman/tests/common/http.rshardcodeshttp://localhost:{port}and always attaches the static/mock bearer. Make the base URL target-aware (HTTPS host on devnet) and attach theauth::Refresher(Keycloak client-credentials) token so requests authenticate against real DecMan nodes.Standalone reward-only entrypoint. The reward phase currently runs at the END of the full localnet bootstrap sequence in
crates/decman/tests/governance_workflows.rs. Pointed at devnet, the earlier phases would try to onboard a NEW decparty (topology writes/freeze) instead of using the pre-existingcbtc-network. Add an entry that runs ONLY the reward phase against the existing devnet decparty and skips the bootstrap phases.Real beneficiary/assigner parties from config/ledger.
crates/decman/tests/common/phases/coupon_reassignment.rshardcodes beneficiaries to fixture parties (p2_member/p3_member). On devnet read the realcbtc-beneficiary/ operator parties (and the active attestor assigners) from config or the ledger.PQS split-by-value assertion. Add the per-beneficiary field-level check against devnet PQS
pqs_cbtc: oneRewardCouponV2per beneficiary withbeneficiary ∈ {cbtc-beneficiary, operator}and the 0.8/0.2amountshares. Queryarchives('splice-amulet:Splice.Amulet:RewardCouponV2')grouped bypayload->>'beneficiary'. Reference numbers from the manual run: cbtc-beneficiary 27,689.39 vs operator 6,922.35 (exactly 4:1).Acceptance
DECPM_IT_TARGET=devnet DECPM_IT_REWARD=1 <entrypoint>runs the reward phase againstcbtc-network, exercisesDelegation_Assign, and asserts the 0.8/0.2 split by value via PQS.cbtc-network, shortDECPM_REWARD_AUTOMATION_INTERVAL_SECS, coupons re-accumulated unassigned).Non-goals
test_non_assigner_cannot_reassign); a devnet ledger-level repro stays a manual ops step (no HTTP path to submit as an arbitrary party).Key files
crates/decman/tests/common/http.rscrates/decman/tests/common/mod.rs(TestTarget,Fixture,discover_network_parties)crates/decman/tests/common/auth.rs(KeycloakRefresher)crates/decman/tests/common/phases/coupon_reassignment.rscrates/decman/tests/governance_workflows.rs(gating / phase ordering)