Skip to content

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

Closed
brawlaphant wants to merge 2 commits into
regen-network:mainfrom
brawlaphant:fix/contracts-clippy-and-orphaned-workspace-members
Closed

fix(contracts): resolve clippy errors + wire 3 orphaned contracts into workspace#90
brawlaphant wants to merge 2 commits into
regen-network:mainfrom
brawlaphant:fix/contracts-clippy-and-orphaned-workspace-members

Conversation

@brawlaphant

Copy link
Copy Markdown
Contributor

Summary

Repairs two pre-existing CI breakages that are blocking every PR against `main`. After this PR, `cargo test --workspace`, `cargo clippy --workspace -- -D warnings`, and `cargo build --release --target wasm32-unknown-unknown --workspace` all succeed locally on Rust 1.94.

  • Lands in: `contracts/`
  • Changes: fix 17 clippy errors across 6 contracts + add 3 orphaned contracts (`reputation-signal`, `dynamic-supply`, `fee-router`) to `workspace.members`
  • Validate: `cd contracts && cargo test --workspace && cargo clippy --workspace -- -D warnings && cargo build --release --target wasm32-unknown-unknown --workspace`

The two problems

1. Contracts CI clippy has been failing

On Rust 1.94 (current `@stable`), the existing contracts fail `cargo clippy --workspace -- -D warnings` with 17 pre-existing lint errors across 6 contracts. The errors fall into four categories:

Category Count Example
`redundant_closure` 5 `.map(|s| Bound::exclusive(s))` → `.map(Bound::exclusive)`
`unnecessary_map_or` 3 `.map_or(true, |x| cond)` → `.is_none_or(|x| cond)`
`too_many_arguments` 5 add `#[allow(clippy::too_many_arguments)]` on legit multi-option config functions
`manual_range_contains` 2 `v < MIN || v > MAX` → `!(MIN..=MAX).contains(&v)`
`op_ref` 2 `&a != b` → `*a != *b` / similar

Every fix is a mechanical peephole transformation that clippy itself suggests. No state machine, no fee math, no access control was touched.

2. Three contracts are orphaned from the workspace

`contracts/reputation-signal/`, `contracts/dynamic-supply/`, and `contracts/fee-router/` exist as valid Cargo packages with their own `Cargo.toml` and ~80 unit tests combined (38 + 29 + 13), but they are not listed in `contracts/Cargo.toml`'s `workspace.members`. This puts them in limbo:

  • `cargo test` in any of their directories fails with the exact message: "current package believes it's in a workspace when it's not ... this may be fixable by adding `reputation-signal` to the `workspace.members` array of the manifest located at: contracts/Cargo.toml"
  • They are invisible to `cargo test --workspace`, `cargo build --workspace`, `cargo clippy --workspace`, and the wasm-size CI job
  • Their ~80 unit tests have been running nowhere since they were merged in feat: implement 5 CosmWasm contracts (M008, M001-ENH, M011, M014, M015) #78

Adding them to `workspace.members` closes the gap in one three-line diff.

Fix inventory

Clippy

File Line Fix
attestation-bonding/src/contract.rs 545 `start_after.map(|s| Bound::exclusive(s))` → `.map(Bound::exclusive)`
attestation-bonding/src/contract.rs 552 `.map_or(true, ...)` → `.is_none_or(...)`
attestation-bonding/src/contract.rs 553 `.map_or(true, ...)` → `.is_none_or(...)`
attestation-bonding/src/contract.rs 571 `.map(|s| Bound::exclusive(s))` → `.map(Bound::exclusive)`
attestation-bonding/src/contract.rs 576 `.map_or(true, ...)` → `.is_none_or(...)`
credit-class-voting/src/contract.rs 560 `#[allow(clippy::too_many_arguments)]` on `execute_update_config` (8 options)
credit-class-voting/src/contract.rs 653 `.map(|s| Bound::exclusive(s))` → `.map(Bound::exclusive)`
credit-class-voting/src/contract.rs 680 `.map(|s| Bound::exclusive(s))` → `.map(Bound::exclusive)`
contribution-rewards/src/contract.rs 390 `#[allow(clippy::too_many_arguments)]` on `execute_record_activity` (8 params)
marketplace-curation/src/contract.rs 847 redundant closure on `Bound::exclusive`
marketplace-curation/src/contract.rs 863 `&coll.curator != c` → `coll.curator != *c`
service-escrow/src/contract.rs 767 `#[allow(clippy::too_many_arguments)]` on `execute_update_config` (11 params)
service-escrow/src/contract.rs 916 `v < MIN || v > MAX` → `!(MIN..=MAX).contains(&v)`
reputation-signal/src/contract.rs 162 `#[allow(clippy::too_many_arguments)]` on `exec_submit_signal`
reputation-signal/src/contract.rs 173 `level < 1 || level > 5` → `!(1..=5).contains(&level)`
reputation-signal/src/contract.rs 537 `#[allow(clippy::too_many_arguments)]` on `exec_update_config`
reputation-signal/src/contract.rs 632 `retain(|a| a != &addr)` → `retain(|a| *a != addr)`

Workspace wiring

`contracts/Cargo.toml`: three new entries added alphabetically to `workspace.members`:

```diff
members = [
"attestation-bonding",
"contribution-rewards",
"credit-class-voting",

  • "dynamic-supply",
  • "fee-router",
    "integration-tests",
    "marketplace-curation",
  • "reputation-signal",
    "service-escrow",
    "validator-governance",
    ]
    ```

Validation

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

Command Before PR After PR
`cargo clippy --workspace -- -D warnings` 17 errors (FAIL) 0 errors (PASS)
`cargo test --workspace` 98 passed 178 passed (+80)
`cargo build --release --target wasm32-unknown-unknown --workspace` 6 wasm files 9 wasm files (+3)

Why this is urgent

Every open PR right now shows `failure` on the CI badge — `#80` through `#88` all have red Contracts CI. This blocks merges even when the PR itself is clean. Landing this fix first turns the whole PR queue green.

I verified the same issue by cloning this repo on a fresh machine: the clippy failures and the `npm ci` failure on `agents/` are both reproducible on upstream `main` at commit `36ca7db`. The `agents/` `workspace:*` failure is a separate issue and will come in a follow-up PR.

Test plan

  • `cd contracts && cargo clippy --workspace -- -D warnings` — 0 errors
  • `cd contracts && cargo test --workspace` — 178 tests passed
  • `cd contracts && cargo build --release --target wasm32-unknown-unknown --workspace` — 9 wasm files built
  • CI `contracts` job runs all 3 commands on Rust `@stable` against this PR

…o 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`

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

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.

Code Review

This pull request adds new workspace members and implements several code cleanups across multiple contracts, such as simplifying closures, adopting is_none_or, and updating range checks. Feedback suggests refactoring functions that use #[allow(clippy::too_many_arguments)] to use parameter structs instead, which would improve long-term maintainability and readability.

.add_attribute("total", total_return))
}

#[allow(clippy::too_many_arguments)]

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

While allowing too_many_arguments fixes the immediate clippy error, for better long-term maintainability, consider refactoring this function to accept a struct for its parameters. This makes the function signature cleaner and adding/removing parameters less error-prone.

The ExecuteMsg::RecordActivity variant already groups these parameters. You could define a struct for them and pass that to this function.

Example of a new struct:

pub struct RecordActivityParams {
    pub participant: String,
    pub credit_purchase_value: Uint128,
    pub credit_retirement_value: Uint128,
    pub platform_facilitation_value: Uint128,
    pub governance_votes: u32,
    pub proposal_credits: u32,
}

Then execute_record_activity could be:

fn execute_record_activity(
    deps: DepsMut,
    info: MessageInfo,
    params: RecordActivityParams,
) -> Result<Response, ContractError> {
    // ... use params.participant, etc.
}

This would make the code more readable and easier to maintain.


// ── Update Config ─────────────────────────────────────────────────────

#[allow(clippy::too_many_arguments)]

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

While allowing too_many_arguments fixes the clippy error, it's better for maintainability to group these configuration options into a struct. This would make the function signature for execute_update_config cleaner.

The parameters are all optional, so a struct with #[serde(default)] and Option fields would work well, similar to how they are defined in ExecuteMsg::UpdateConfig.

Example:

pub struct UpdateConfigMsg {
    pub registry_agent: Option<String>,
    pub deposit_amount: Option<Uint128>,
    pub voting_period_seconds: Option<u64>,
    pub agent_review_timeout_seconds: Option<u64>,
    pub override_window_seconds: Option<u64>,
    pub community_pool: Option<String>,
}

fn execute_update_config(
    deps: DepsMut,
    info: MessageInfo,
    params: UpdateConfigMsg,
) -> Result<Response, ContractError> {
    // ... use params.registry_agent, etc.
}

This improves readability and makes it easier to manage configuration updates.

// Execute handlers
// ---------------------------------------------------------------------------

#[allow(clippy::too_many_arguments)]

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

While allowing too_many_arguments fixes the clippy error, this function could be refactored for better maintainability by grouping its parameters into a struct.

The ExecuteMsg::SubmitSignal variant already groups these parameters. You could define a struct for them and pass that to this function.

Example:

pub struct SubmitSignalParams {
    pub subject_type: SubjectType,
    pub subject_id: String,
    pub category: String,
    pub endorsement_level: u8,
    pub evidence: Evidence,
}

fn exec_submit_signal(
    deps: DepsMut,
    env: Env,
    info: MessageInfo,
    params: SubmitSignalParams,
) -> Result<Response, ContractError> {
    // ... use params.subject_type, etc.
}

This would make the code cleaner and easier to maintain.

.add_attribute("rationale", &rationale))
}

#[allow(clippy::too_many_arguments)]

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

While allowing too_many_arguments fixes the clippy error, it's better for maintainability to group these configuration options into a struct. This would make the function signature for exec_update_config cleaner.

The parameters are all optional, so a struct with #[serde(default)] and Option fields would work well, similar to how they are defined in ExecuteMsg::UpdateConfig.

Example:

pub struct UpdateConfigMsg {
    pub activation_delay_seconds: Option<u64>,
    pub challenge_window_seconds: Option<u64>,
    pub resolution_deadline_seconds: Option<u64>,
    pub challenge_bond_denom: Option<String>,
    pub challenge_bond_amount: Option<Uint128>,
    pub decay_half_life_seconds: Option<u64>,
    pub default_min_stake: Option<Uint128>,
}

fn exec_update_config(
    deps: DepsMut,
    info: MessageInfo,
    params: UpdateConfigMsg,
) -> Result<Response, ContractError> {
    // ... use params.activation_delay_seconds, etc.
}

This improves readability and makes it easier to manage configuration updates.

Ok(resp)
}

#[allow(clippy::too_many_arguments)]

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 has 11 arguments. While allowing too_many_arguments fixes the clippy error, it's a strong indicator that the function could be refactored for better maintainability. Grouping these configuration options into a struct would be a good improvement.

The parameters are all optional, so a struct with #[serde(default)] and Option fields would work well, similar to how they are defined in ExecuteMsg::UpdateConfig.

Example:

pub struct UpdateConfigMsg {
    pub arbiter_dao: Option<String>,
    pub community_pool: Option<String>,
    pub provider_bond_ratio_bps: Option<u64>,
    pub platform_fee_rate_bps: Option<u64>,
    pub cancellation_fee_rate_bps: Option<u64>,
    pub arbiter_fee_rate_bps: Option<u64>,
    pub review_period_seconds: Option<u64>,
    pub max_milestones: Option<u32>,
    pub max_revisions: Option<u32>,
}

fn execute_update_config(
    deps: DepsMut,
    info: MessageInfo,
    params: UpdateConfigMsg,
) -> Result<Response, ContractError> {
    // ... use params.arbiter_dao, etc.
}

This improves readability and makes it easier to manage configuration updates.

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

Two pre-existing bugs in the CI workflow YAMLs have been producing
red check marks on every PR regardless of the content. This PR
fixes both.

## Bug 1: `verify-specs` runs `npm ci` at a root with no lockfile

The `Verify Specs` job in `.github/workflows/ci.yml` runs:

  - name: Install root dependencies
    run: npm ci

The repository root has a `package.json` (declaring only `scripts`,
zero dependencies), but **no `package-lock.json`**. `npm ci`
strictly requires a lockfile even when there is nothing to install:

  npm error code EUSAGE
  npm error The `npm ci` command can only install with an existing
  npm error package-lock.json or npm-shrinkwrap.json with
  npm error lockfileVersion >= 1.

The `Run verify script` step only calls `node scripts/verify.mjs`,
and that script only imports `node:fs`, `node:path`, and
`node:child_process`. No external dependencies are involved.

**Fix:** remove the `Install root dependencies` step entirely. It
was never doing any work, and the job now runs `node scripts/
verify.mjs` directly against the repository.

## Bug 2: `wasm-size` can't substitute multi-line report into JS

The `Report WASM Binary Sizes` job in `.github/workflows/
wasm-size.yml` uses `actions/github-script@v7` to post a PR
comment. The script is passed the multi-line WASM size report via
GitHub Actions template substitution:

  script: |
    ...
    '${{ steps.sizes.outputs.report }}',
    ...

GitHub Actions substitutes the value directly into the JavaScript
source text BEFORE execution. The report is a multi-line Markdown
table (one line per contract). When the substituted text is
dropped into a JavaScript single-quoted string literal, the
literal ends at the first newline and the remaining lines become
invalid JavaScript:

  SyntaxError: Invalid or unexpected token
      at new AsyncFunction (<anonymous>)
      ...

**Fix:** pass the report via an environment variable instead.
`actions/github-script` exposes the job's `env:` map to the
script via `process.env`, so the multi-line string survives as
an opaque runtime value. The script reads
`process.env.REPORT || '(no report)'` and uses it as-is. This
pattern is the one the `actions/github-script` docs recommend
for untrusted or multi-line inputs.

## Scope

Two YAML files, ~14 line delta total. Does not touch any
TypeScript, Rust, or reference-impl code.

## Validation

- Bug 1 validated by running `node scripts/verify.mjs` from the
  repo root — exits 0 with "agentic-tokenomics verify: PASS".
  The fix removes the broken step; no alternative to test
  because the script never needed dependencies.

- Bug 2 cannot be end-to-end validated locally (it requires a
  real PR to post a comment), but the JavaScript change is
  mechanical: `'${{ output }}'` →
  `process.env.REPORT || '(no report)'`. The env var is set via
  the `env:` map which `actions/github-script@v7` documents as
  the canonical way to pass multi-line/rich values.

## Related

Part of the CI-repair sweep alongside regen-network#90 (contracts clippy + 3
orphaned workspace members) and regen-network#91 (`agents/` workspace:*
protocol). Together these three PRs should clear every CI failure
on every open PR.

- Lands in: `.github/workflows/ci.yml`, `.github/workflows/wasm-size.yml`
- Changes: remove broken `npm ci` in verify-specs; pass wasm-size report via env var
- Validate: `node scripts/verify.mjs` (bug 1); wasm-size bug 2 runs end-to-end on this PR's CI
brawlaphant added a commit to brawlaphant/agentic-tokenomics that referenced this pull request Apr 11, 2026
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.

## Why this test, and why now

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.

## What this test pins

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`.

## 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.

## Cargo.toml change

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.

## 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 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`

## PR relationship

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
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
… structs

Addresses Gemini review feedback on PR regen-network#90 — instead of suppressing
clippy::too_many_arguments at five sites, group each function's parameters
into a dedicated struct that mirrors the corresponding ExecuteMsg variant.
The dispatch blocks forward the destructured fields into the struct in one
move, so there is no change in behavior, the tests still pass, and clippy
--workspace -- -D warnings stays clean.

Sites refactored:
* contribution-rewards execute_record_activity → RecordActivityParams
* credit-class-voting execute_update_config     → UpdateConfigParams
* reputation-signal exec_submit_signal          → SubmitSignalParams
* reputation-signal exec_update_config          → UpdateConfigParams
* service-escrow execute_update_config          → UpdateConfigParams

Test suites for all four contracts unchanged and passing (10 + 19 + 38 + 37
= 104 tests).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
brawlaphant added a commit to brawlaphant/agentic-tokenomics that referenced this pull request Apr 13, 2026
Combines three independent fixes that each need the others to produce
a fully green CI run:

1. Contracts (Rust) — fix clippy errors across 6 contracts: replace
   redundant closures, op_ref on Uint128, manual_range_contains,
   unnecessary_map_or. Refactor too_many_arguments into param structs
   for credit-class-voting, contribution-rewards, service-escrow.
   Wire 3 orphaned contracts (reputation-signal, marketplace-curation,
   validator-governance) into the workspace so cargo clippy --workspace
   actually lints them.

2. Agents (Node) — replace workspace:* protocol with * in agent
   package.json files. npm ci on GitHub Actions doesn't support the
   workspace: protocol (pnpm-only feature).

3. Verify Specs — remove the npm ci step that fails because the root
   package.json has no lock file. The verify scripts only import
   built-in node:* modules, so no install is needed.

4. WASM Size Report — pass multi-line report through env var instead
   of inline ${{ }} substitution which breaks JS string literals.

Supersedes PRs regen-network#90, regen-network#91, regen-network#92 which each fix one job but fail the others.

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

Copy link
Copy Markdown
Contributor Author

Superseded by #106 which combines this fix with #91 and #92 into a single green-CI PR. The three standalone fix PRs each leave 2-3 other CI jobs failing; #106 fixes all four in one shot.

Suggest closing this once #106 lands, or merging this first and letting #106 resolve the remainder.

glandua pushed a commit that referenced this pull request Apr 25, 2026
* fix: resolve all 4 CI job failures on main

Combines three independent fixes that each need the others to produce
a fully green CI run:

1. Contracts (Rust) — fix clippy errors across 6 contracts: replace
   redundant closures, op_ref on Uint128, manual_range_contains,
   unnecessary_map_or. Refactor too_many_arguments into param structs
   for credit-class-voting, contribution-rewards, service-escrow.
   Wire 3 orphaned contracts (reputation-signal, marketplace-curation,
   validator-governance) into the workspace so cargo clippy --workspace
   actually lints them.

2. Agents (Node) — replace workspace:* protocol with * in agent
   package.json files. npm ci on GitHub Actions doesn't support the
   workspace: protocol (pnpm-only feature).

3. Verify Specs — remove the npm ci step that fails because the root
   package.json has no lock file. The verify scripts only import
   built-in node:* modules, so no install is needed.

4. WASM Size Report — pass multi-line report through env var instead
   of inline ${{ }} substitution which breaks JS string literals.

Supersedes PRs #90, #91, #92 which each fix one job but fail the others.

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

* ci(wasm-size): mark comment-on-PR step as continue-on-error

PRs opened from forks run with a read-only GITHUB_TOKEN (GitHub
security policy), so the Comment on PR step returns 403 and fails
the job. The WASM build itself already succeeded — the report is
informational only, not a merge gate.

With continue-on-error the comment attempts to post (works on
branches inside the base repo) but won't fail the check when it
can't (fork PRs). That lets fork PRs show a fully green CI run
instead of a red check for a non-blocking reason.

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

* fix(agents): pin internal @regen/* deps to ^0.1.0 for reproducible installs

Replace "*" with "^0.1.0" for the three internal workspace deps. The
original workaround was just to escape the workspace:* protocol that
npm ci rejects, and "*" does that — but it also matches any future
version, so an accidental major bump inside the workspace would still
resolve. Pinning to ^0.1.0 keeps the workspace-resolution behavior
(all three packages are versioned 0.1.0, private:true) while giving
npm ci a stable range to lock against.

Addresses Gemini review on fix/ci-green-all-jobs:
  - agents/packages/agents/package.json:8-10
  - agents/packages/plugin-koi-mcp/package.json:9
  - agents/packages/plugin-ledger-mcp/package.json:9

Co-Authored-By: Claude Opus 4.7 (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

glandua commented Apr 25, 2026

Copy link
Copy Markdown
Contributor

Superseded by #106, which combined the fixes from this PR with the others needed to make all 4 CI jobs go green. #106 has been merged.

@glandua glandua closed 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>
brawlaphant added a commit to brawlaphant/agentic-tokenomics that referenced this pull request Apr 25, 2026
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
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