Skip to content

test(integration): M010 reputation-signal coexistence with M011 curation#101

Open
brawlaphant wants to merge 2 commits intoregen-network:mainfrom
brawlaphant:test/integration-m010-m011
Open

test(integration): M010 reputation-signal coexistence with M011 curation#101
brawlaphant wants to merge 2 commits intoregen-network:mainfrom
brawlaphant:test/integration-m010-m011

Conversation

@brawlaphant
Copy link
Copy Markdown
Contributor

Summary

Adds a new integration test that exercises the M010 reputation-signal lifecycle end-to-end in the same cw-multi-test App as M011 marketplace-curation. This is now possible because #90 wired `reputation-signal` into the workspace members list — before that merge, the contract could not be imported by `integration-tests` at all.

  • Lands in: `contracts/integration-tests/`
  • Changes: new test (192 LOC) + one `Cargo.toml` dep line
  • Validate: `cd contracts && cargo test --workspace`

Why now

m011 SPEC §5 names m010 as the data source for three of its seven factors (`project_reputation`, `class_reputation`, `seller_reputation`). But v0 does NOT have m011 making on-chain queries to m010 — the integration story is off-chain. An agent reads the reputation score from m010 and supplies it as input to m011.

Until now there was no test that both contracts could even be deployed in the same App without state or type collisions, because reputation-signal wasn't a workspace member. After #90, it is. This PR is the sanity check that exercise that wiring.

What this test pins

Invariant How
Workspace coexistence Both contracts deploy in the same `App` without type or state collisions
Activation-delay enforcement Pre-activation: `contributing_signals == 0`. Advance time past delay, Activate. Post-activation: `contributing_signals == 1`
Score shape at the m011 boundary `ReputationScoreResponse` carries `score` / `contributing_signals` / `total_signals` — the exact three numbers an off-chain curation agent needs. An endorsement_level of 5 produces score 1000 in the v0 normalized range.

What this test does NOT do

It is not a cross-contract MESSAGE flow. The curation contract still takes a pre-computed quality score as input in v0. A future upgrade that adds a real on-chain m010 query from m011 can extend this test to cover that path; for now the test guards the workspace wiring and the data contract at the boundary.

Validation

```
$ cd contracts && cargo test --package integration-tests test_reputation_signal_coexistence
test result: ok. 1 passed; 0 failed

$ cd contracts && cargo test --workspace
(179 tests passed — +1 over the 178 baseline after #90)
```

PR relationship

Based on PR #90 (contracts CI fix — where reputation-signal was added to workspace members). If #90 merges first, this PR rebases cleanly. If this PR is reviewed first, it implicitly reviews the workspace wiring along with it.

Refs `mechanisms/m010-reputation-signal/SPEC.md` §5
Refs `mechanisms/m011-marketplace-curation/SPEC.md` §5

brawlaphant added a commit to brawlaphant/agentic-tokenomics that referenced this pull request Apr 11, 2026
Adds a new integration test that exercises the canonical Economic
Reboot flow: fees are collected by M013 fee-router, the burn
portion accumulates in its burn pool, and an off-chain aggregator
hands that burn amount to M012 dynamic-supply as the burn_amount
argument to ExecutePeriod. The two contracts do not message each
other on-chain in v0 — but their data contract at the boundary
must be bit-exact.

This is now possible because PR regen-network#90 wired both fee-router and
dynamic-supply into the workspace members list. Before that, they
could not be imported by integration-tests.

## What this test pins

1. **Workspace coexistence** — both contracts deploy in the same
   App and instantiate without collisions.

2. **Fee Conservation inside m013** — after collecting a fee, the
   burn share lands in `burn_pool` and matches the dry-run
   calculation from `CalculateFee`. Specifically:
     burn + validator + community + agent == fee_amount
   A 10B uregen marketplace trade at the default 1% rate produces
   fee 100M, split 30M/40M/25M/5M (pins the Model A 30/40/25/5
   distribution).

3. **Supply conservation inside m012** — after ExecutePeriod runs:
     current_supply = supply_before + total_minted - total_burned
   The test asserts this identity directly rather than hardcoding
   exact supply numbers (which would pin the regrowth math as a
   side effect). The identity must hold regardless of the
   effective multiplier's numerical value.

4. **m013 → m012 hand-off is bit-exact** — the burn amount m012
   records via `total_burned` equals the burn amount we read from
   m013's `pools.burn_pool`. No off-by-one, no rounding drift.
   This is the single most important assertion in the test —
   if the two contracts' uregen accounting ever drifts, the
   Economic Reboot burn ladder breaks silently.

## What this test does NOT do

It is not a cross-contract MESSAGE flow — m012 does not call
m013 and vice versa. The hand-off is off-chain in v0. A future
upgrade that adds a real IBC or Wasm-level query can extend this
test to cover that path; for now the test guards the workspace
wiring and the uregen data contract at the boundary.

## Cargo.toml change

Adds `fee-router` and `dynamic-supply` to
`contracts/integration-tests/Cargo.toml` under
`[dev-dependencies]`. Both contracts were already in the
workspace members list after PR regen-network#90.

## Validation

  $ cd contracts && cargo test --package integration-tests \
    test_fee_router_to_dynamic_supply_burn_flow
  test result: ok. 1 passed; 0 failed

The full workspace test suite still passes — 180 tests total
after this PR (179 after regen-network#101, +1 from this test).

- Lands in: `contracts/integration-tests/`
- Changes: new M013→M012 burn flow test (222 LOC) + Cargo.toml deps
- Validate: `cd contracts && cargo test --workspace`

## PR relationship

Based on PR regen-network#90 (which wired fee-router and dynamic-supply into
the workspace members list). Sibling to regen-network#101 (M010/M011
coexistence test). The two integration tests together exercise
two of the three conceptual flows in the Economic Reboot design
— with the third (M009 escrow → M015 rewards) deferred to a
future follow-up.

Refs `mechanisms/m013-value-based-fee-routing/SPEC.md` §5
Refs `mechanisms/m012-fixed-cap-dynamic-supply/SPEC.md` §5.3
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request integrates the dynamic-supply, fee-router, and reputation-signal contracts into the workspace and introduces a comprehensive integration test for the reputation signal lifecycle. It also applies several idiomatic Rust refactors, including the use of is_none_or, simplified closures, and range contains checks. Feedback suggests refactoring functions with excessive arguments into dedicated structs rather than suppressing Clippy lints in the contribution-rewards and service-escrow contracts. Additionally, a redundant variable suppression in the new integration test should be removed.

// future extensions of this test can exercise a curator flow
// inside the same App to cover the full M010 → M011 handoff
// once m011 acquires a real cross-contract reputation query.
let _ = curator;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The variable curator is already used at line 1787 when building the App balances. This explicit silence of the unused variable warning is redundant and can be removed.

Comment on lines +390 to 391
#[allow(clippy::too_many_arguments)]
fn execute_record_activity(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Instead of suppressing the clippy::too_many_arguments lint, consider refactoring the activity data into a dedicated struct (e.g., ActivityData). This would improve maintainability and make the function signature cleaner, especially since these parameters are logically grouped as ecosystem activity metrics.

Comment on lines +767 to 768
#[allow(clippy::too_many_arguments)]
fn execute_update_config(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This function signature has 11 arguments. While suppressing the lint allows the code to compile, it is a strong indicator that the configuration parameters should be grouped into a struct (e.g., ConfigUpdate). This would reduce the risk of argument swapping and improve readability.

brawlaphant added a commit to brawlaphant/agentic-tokenomics that referenced this pull request Apr 11, 2026
…tence

Addresses Gemini review feedback on PR regen-network#101: the trailing `let _ = curator;`
was silencing an unused-variable warning that never fired, because
`curator` was already consumed on line 1787 by the `build_app` balance
tuple (`(&curator, 10_000_000_000)`). Remove the dead silence and the
comment that justified it — the test still compiles and the full
integration-tests suite (6 tests) still passes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@glandua glandua closed this Apr 25, 2026
@glandua glandua reopened this Apr 25, 2026
@glandua glandua closed this Apr 25, 2026
@glandua glandua reopened this Apr 25, 2026
glandua pushed a commit that referenced this pull request Apr 25, 2026
)

* fix(contracts): resolve clippy errors + wire 3 orphaned contracts into workspace

Repairs two pre-existing CI breakages that have been blocking every
PR against main:

1. `cargo clippy --workspace -- -D warnings` failed on Rust 1.94
   with 17 errors across 6 contracts — pre-existing lint issues
   from before the toolchain auto-upgraded. Fixed mechanically
   with no behavior change.

2. `reputation-signal`, `dynamic-supply`, and `fee-router` were
   present as sibling package directories under `contracts/` but
   NOT listed in `contracts/Cargo.toml`'s `workspace.members`
   array. The packages were in limbo — cargo refused to run their
   tests standalone (refusing with "current package believes it's
   in a workspace when it's not"), AND they were invisible to
   workspace-scoped commands like `cargo test --workspace` and
   `cargo build --release --target wasm32-unknown-unknown
   --workspace`. The result was that ~80 unit tests (38 in
   reputation-signal, 29 in dynamic-supply, 13 in fee-router)
   were running nowhere. This PR adds them to the workspace.

Combined impact:

- Contracts CI clippy job: FAIL → PASS
- Contracts CI test job: 98 tests → 178 tests (+80)
- Contracts CI wasm build job: 6 contracts → 9 contracts (+3)
- Future integration tests can now depend on the three
  previously-orphaned contracts (they were already valid
  CosmWasm contracts, just not visible to the workspace)

## Clippy fixes (mechanical, no behavior change)

attestation-bonding/src/contract.rs
- Line 545, 571: `start_after.map(|s| cw_storage_plus::Bound::exclusive(s))`
  → `start_after.map(cw_storage_plus::Bound::exclusive)` (redundant_closure)
- Line 552, 553, 576: `.map_or(true, |x| ...)` → `.is_none_or(|x| ...)`
  (unnecessary_map_or — modern Rust idiom)

credit-class-voting/src/contract.rs
- Line 560: `execute_update_config` has 8 parameters; added
  `#[allow(clippy::too_many_arguments)]` above the fn declaration
  (all 8 are legitimately independent optional fields on the config)
- Line 653, 680: redundant closure on `Bound::exclusive`

contribution-rewards/src/contract.rs
- Line 390: `execute_record_activity` has 8 parameters; added
  `#[allow(clippy::too_many_arguments)]`

marketplace-curation/src/contract.rs
- Line 847: redundant closure on `Bound::exclusive`
- Line 863: `&coll.curator != c` comparing a reference to a reference →
  `coll.curator != *c` (op_ref on left operand)

service-escrow/src/contract.rs
- Line 767: `execute_update_config` has 11 parameters; added
  `#[allow(clippy::too_many_arguments)]`
- Line 916: `value < MIN_BOND_RATIO || value > MAX_BOND_RATIO`
  → `!(MIN_BOND_RATIO..=MAX_BOND_RATIO).contains(&value)`
  (manual_range_contains — modern Rust idiom)

reputation-signal/src/contract.rs
- Line 162: `exec_submit_signal` has 8 parameters; added
  `#[allow(clippy::too_many_arguments)]`
- Line 173: `endorsement_level < 1 || endorsement_level > 5`
  → `!(1..=5).contains(&endorsement_level)` (manual_range_contains)
- Line 537: `exec_update_config` has 9 parameters; added
  `#[allow(clippy::too_many_arguments)]`
- Line 632: `config.arbiters.retain(|a| a != &addr)`
  → `config.arbiters.retain(|a| *a != addr)` (op_ref on right operand)

## Workspace wiring

contracts/Cargo.toml: added `"dynamic-supply"`, `"fee-router"`,
`"reputation-signal"` to `workspace.members` in alphabetical order
between existing entries. No change to `workspace.dependencies`.

## Validation

Ran locally on `rustc 1.94.0 (85eff7c80 2026-01-15)` with the
same commands CI uses:

- `cargo clippy --workspace -- -D warnings` — PASS (0 errors)
- `cargo test --workspace` — 178 passed, 0 failed
- `cargo build --release --target wasm32-unknown-unknown --workspace`
  — all 9 contracts compile, release profile, ~55s cold

Every behavior change in this PR is a mechanical refactor that
the Rust compiler can prove equivalent (clippy's suggestions are
peephole transformations). No state machine, no fee math, no
access control was touched.

- Lands in: `contracts/`
- Changes: fix 17 clippy errors + add 3 orphaned contracts to workspace.members
- Validate: `cd contracts && cargo test --workspace && cargo clippy --workspace -- -D warnings`

* test(integration): M013 fee-router → M012 dynamic-supply burn flow

Adds a new integration test that exercises the canonical Economic
Reboot flow: fees are collected by M013 fee-router, the burn
portion accumulates in its burn pool, and an off-chain aggregator
hands that burn amount to M012 dynamic-supply as the burn_amount
argument to ExecutePeriod. The two contracts do not message each
other on-chain in v0 — but their data contract at the boundary
must be bit-exact.

This is now possible because PR #90 wired both fee-router and
dynamic-supply into the workspace members list. Before that, they
could not be imported by integration-tests.

## What this test pins

1. **Workspace coexistence** — both contracts deploy in the same
   App and instantiate without collisions.

2. **Fee Conservation inside m013** — after collecting a fee, the
   burn share lands in `burn_pool` and matches the dry-run
   calculation from `CalculateFee`. Specifically:
     burn + validator + community + agent == fee_amount
   A 10B uregen marketplace trade at the default 1% rate produces
   fee 100M, split 30M/40M/25M/5M (pins the Model A 30/40/25/5
   distribution).

3. **Supply conservation inside m012** — after ExecutePeriod runs:
     current_supply = supply_before + total_minted - total_burned
   The test asserts this identity directly rather than hardcoding
   exact supply numbers (which would pin the regrowth math as a
   side effect). The identity must hold regardless of the
   effective multiplier's numerical value.

4. **m013 → m012 hand-off is bit-exact** — the burn amount m012
   records via `total_burned` equals the burn amount we read from
   m013's `pools.burn_pool`. No off-by-one, no rounding drift.
   This is the single most important assertion in the test —
   if the two contracts' uregen accounting ever drifts, the
   Economic Reboot burn ladder breaks silently.

## What this test does NOT do

It is not a cross-contract MESSAGE flow — m012 does not call
m013 and vice versa. The hand-off is off-chain in v0. A future
upgrade that adds a real IBC or Wasm-level query can extend this
test to cover that path; for now the test guards the workspace
wiring and the uregen data contract at the boundary.

## Cargo.toml change

Adds `fee-router` and `dynamic-supply` to
`contracts/integration-tests/Cargo.toml` under
`[dev-dependencies]`. Both contracts were already in the
workspace members list after PR #90.

## Validation

  $ cd contracts && cargo test --package integration-tests \
    test_fee_router_to_dynamic_supply_burn_flow
  test result: ok. 1 passed; 0 failed

The full workspace test suite still passes — 180 tests total
after this PR (179 after #101, +1 from this test).

- Lands in: `contracts/integration-tests/`
- Changes: new M013→M012 burn flow test (222 LOC) + Cargo.toml deps
- Validate: `cd contracts && cargo test --workspace`

## PR relationship

Based on PR #90 (which wired fee-router and dynamic-supply into
the workspace members list). Sibling to #101 (M010/M011
coexistence test). The two integration tests together exercise
two of the three conceptual flows in the Economic Reboot design
— with the third (M009 escrow → M015 rewards) deferred to a
future follow-up.

Refs `mechanisms/m013-value-based-fee-routing/SPEC.md` §5
Refs `mechanisms/m012-fixed-cap-dynamic-supply/SPEC.md` §5.3

* test(integration): send calculated fee as funds in CollectFee call

Addresses Gemini review feedback on PR #102: the CollectFee call passed
`&[]` for funds, which both hid the intended integrator call shape and
masked any future on-chain funds-validation check. Wire `calc.fee_amount`
through the mock bank as `Coin { denom: DENOM, amount: calc.fee_amount }`
and annotate that v0 m013 is accounting-only so the funds currently just
sit in the contract — but the test will fail closed the day m013 enforces
that `info.funds == calculated_fee`.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: brawlaphant <brawlaphant@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@glandua
Copy link
Copy Markdown
Contributor

glandua commented Apr 25, 2026

Hey @brawlaphant — this PR is now CONFLICTING / DIRTY against main after #106 merged. Could you rebase onto the new main and force-push? Should go green automatically once rebased.

brawlaphant and others added 2 commits April 25, 2026 16:49
Adds a new integration test that exercises the M010 reputation-signal
lifecycle end-to-end in the same cw-multi-test App as M011
marketplace-curation. This is now possible because PR regen-network#90 wired
reputation-signal into the workspace members list — before that
merge, the contract could not be imported by integration-tests at
all.

The m011 SPEC §5 names m010 as the data source for
`project_reputation`, `class_reputation`, and `seller_reputation`
— three of the seven factors that drive the m011 composite
curation score. But the v0 design does NOT have m011 making
on-chain queries to m010. The integration story is off-chain: a
curation agent reads the reputation score from m010 and supplies
it as an input to m011's curation workflow.

Until now there was no test that both contracts could even be
deployed in the same App without state or type collisions. This
test is the workspace-level sanity check.

1. **Workspace coexistence.** Both contracts can be deployed in
   the same App without collisions. This was not possible before
   reputation-signal was added to the workspace via the CI fix
   PR (regen-network#90).

2. **Activation-delay enforcement.** A signal submitted at t0
   does NOT contribute to the score until it has been activated
   after the delay has elapsed:
     - pre-activation: contributing_signals == 0, total_signals == 1
     - post-activation (t0 + delay + 1 second, then Activate):
       contributing_signals == 1, total_signals == 1
   The pre→post transition proves the delay guard fires AND that
   the explicit Activate call actually moves the signal to the
   Active state.

3. **Score shape at the m011 boundary.** The
   ReputationScoreResponse is usable by an off-chain curation
   agent — it carries the exact three numbers an agent needs:
   `score` (0..1000), `contributing_signals`, and `total_signals`.
   An endorsement_level of 5 (the max) produces score 1000 in the
   v0 normalized range, which is what an m011 consumer would
   pass as `project_reputation`.

It is NOT a cross-contract MESSAGE flow — the curation contract
still takes a pre-computed quality score as input in v0. A
future upgrade that adds a real on-chain m010 query from m011
can extend this test to cover that path. For now, the test
guards the workspace wiring and the data contract at the
boundary.

Adds `reputation-signal = { path = "../reputation-signal",
features = ["library"] }` to `contracts/integration-tests/
Cargo.toml` under `[dev-dependencies]`. This is the only
dependency change — the contract was already in the workspace
members list after PR regen-network#90.

  $ cd contracts && cargo test --package integration-tests \
    test_reputation_signal_coexistence
  test result: ok. 1 passed; 0 failed

  $ cd contracts && cargo test --workspace
  (179 tests passed, +1 over the 178 from the baseline after regen-network#90)

- Lands in: `contracts/integration-tests/`
- Changes: add M010 coexistence integration test (192 LOC) + Cargo.toml dep
- Validate: `cd contracts && cargo test --workspace`

Based on PR regen-network#90 (which wired reputation-signal into the workspace
members list). If regen-network#90 merges first, this PR rebases cleanly. If
this PR is reviewed first, it implicitly reviews the workspace
wiring along with it.

Refs `mechanisms/m010-reputation-signal/SPEC.md` §5
Refs `mechanisms/m011-marketplace-curation/SPEC.md` §5
…tence

Addresses Gemini review feedback on PR regen-network#101: the trailing `let _ = curator;`
was silencing an unused-variable warning that never fired, because
`curator` was already consumed on line 1787 by the `build_app` balance
tuple (`(&curator, 10_000_000_000)`). Remove the dead silence and the
comment that justified it — the test still compiles and the full
integration-tests suite (6 tests) still passes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@brawlaphant brawlaphant force-pushed the test/integration-m010-m011 branch from 9eccbd3 to 8dcaa49 Compare April 25, 2026 23:50
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