Skip to content

fix(network): migrate governance proposal queries to gov v1 endpoints - #3573

Open
baktun14 wants to merge 4 commits into
mainfrom
fix/network-gov-v1-proposals
Open

fix(network): migrate governance proposal queries to gov v1 endpoints#3573
baktun14 wants to merge 4 commits into
mainfrom
fix/network-gov-v1-proposals

Conversation

@baktun14

@baktun14 baktun14 commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Why

Production GET /v1/proposals (and GET /v1/proposals/{id} for some ids) returns 500. The upstream chain REST node rejects the legacy governance endpoint with:

codespace sdk code 29: invalid type: can't convert a gov/v1 Proposal to gov/v1beta1 Proposal when amount of proposal messages not exactly one

On-chain proposals #322 (2 messages) and #329 (0 messages) cannot be represented in the legacy gov v1beta1 shape, so the node 500s the entire /cosmos/gov/v1beta1/proposals list response (reproduced live against api.akashnet.net). As a side effect, the shared chain HTTP client retries 5xx GETs 3×, so every console request was also tripling load on the failing upstream endpoint.

What

Migrate the three governance queries in CosmosHttpService from /cosmos/gov/v1beta1/* to /cosmos/gov/v1/* and adapt to the v1 response shape:

  • packages/http-sdk: rewrite the gov response types to the v1 shape (id, messages[], top-level title/summary, *_count tally fields, nullable voting timestamps). Type names are unchanged; note the shapes are breaking for external consumers of these exported types — though the old shapes described an endpoint that now 500s.
  • apps/api ProposalService: map title/summary from the v1 top-level fields, tally from *_count fields, extract paramChanges from MsgExecLegacyContent messages (multi-/zero-message proposals yield []), and coalesce null voting timestamps to 0001-01-01T00:00:00Z — exactly what the v1beta1 endpoint emitted for unset times.
  • The public /v1/proposals response contract is unchanged (zod schemas and generated console-api-types untouched).
  • Functional spec fixtures rewritten to the v1 shape, adding regression coverage for the two prod-breaking shapes (zero-message proposal with null voting times, multi-message proposal) and for the legacy param-change + final-tally path.

Verified end-to-end by booting the built API locally against the live mainnet node: /v1/proposals returns 200 with all 161 proposals (currently 500 in prod), /v1/proposals/322 and /v1/proposals/329 return 200, legacy param-change proposals still surface parsed paramChanges, and unknown ids still 404.

Summary by CodeRabbit

  • Bug Fixes

    • Updated governance proposal retrieval to use the current Cosmos Gov v1 API.
    • Corrected proposal details, voting periods, tallies, and parameter-change decoding.
    • Added handling for proposals without messages and unset voting or tally values.
  • Tests

    • Expanded coverage for proposal lists, details, tallies, and multiple proposal types.
    • Added validation for unknown proposals and current API response formats.

The chain's legacy /cosmos/gov/v1beta1/proposals endpoint returns 500 once
any on-chain proposal has a message count other than one (proposals 322 and
329 on mainnet), which broke GET /v1/proposals in production. Query the gov
v1 endpoints instead and map the v1 shape (top-level title/summary, *_count
tally fields, param changes extracted from MsgExecLegacyContent messages)
while keeping the public API response contract unchanged.
@baktun14
baktun14 requested a review from a team as a code owner August 7, 2026 16:03
@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 17 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ad2d2d3f-e750-4259-a470-92953b714565

📥 Commits

Reviewing files that changed from the base of the PR and between 9b1e6c1 and 43f232b.

📒 Files selected for processing (3)
  • apps/api/src/proposal/services/proposal/proposal.service.ts
  • apps/api/test/functional/proposals.spec.ts
  • packages/http-sdk/src/cosmos/types.ts
📝 Walkthrough

Walkthrough

Changes

Cosmos Gov v1 migration

Layer / File(s) Summary
Gov v1 response contracts
packages/http-sdk/src/cosmos/types.ts
Adds reusable proposal, message, and tally types. Response types now reference these shared structures.
Gov v1 HTTP requests
packages/http-sdk/src/cosmos/cosmos-http.service.ts, packages/http-sdk/src/cosmos/cosmos-http.service.spec.ts
Uses /cosmos/gov/v1 for proposal and tally requests. Tests verify endpoints and response mapping.
Proposal service mapping
apps/api/src/proposal/services/proposal/proposal.service.ts
Maps Gov v1 fields, applies zero timestamp fallbacks, reads count-based tallies, and extracts parameter changes from legacy execution messages.
Proposal behavior coverage
apps/api/test/functional/proposals.spec.ts
Covers software upgrade, active multi-message, closed parameter-change, and deposit-period proposals with Gov v1 fixtures and endpoints.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Suggested reviewers: ygrishajev

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/network-gov-v1-proposals

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Aug 7, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 75.71%. Comparing base (44bef1f) to head (43f232b).
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3573      +/-   ##
==========================================
- Coverage   76.33%   75.71%   -0.62%     
==========================================
  Files        1134     1070      -64     
  Lines       29598    27680    -1918     
  Branches     7352     6962     -390     
==========================================
- Hits        22593    20959    -1634     
+ Misses       6174     5917     -257     
+ Partials      831      804      -27     
Flag Coverage Δ *Carryforward flag
api 88.94% <100.00%> (+0.01%) ⬆️
deploy-web 66.19% <ø> (ø)
log-collector ?
notifications 93.84% <ø> (ø)
provider-console 81.38% <ø> (ø) Carriedforward from 6dd2719
provider-inventory ?
provider-proxy 88.17% <ø> (ø) Carriedforward from 6dd2719
tx-signer 86.72% <ø> (ø)

*This pull request uses carry forward flags. Click here to find out more.

Files with missing lines Coverage Δ
...src/proposal/services/proposal/proposal.service.ts 95.23% <100.00%> (+19.48%) ⬆️

... and 66 files with indirect coverage changes

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🧹 Nitpick comments (1)
apps/api/src/proposal/services/proposal/proposal.service.ts (1)

68-72: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

Consider tolerating a non-JSON param value.

JSON.parse(change.value) throws if a legacy param change stores a plain string rather than JSON. The throw escapes the 404 branch and surfaces as a 500 for that proposal. Param values are JSON-encoded by convention, so this is an edge case, but the fallback is cheap.

♻️ Proposed refactor
           .map(change => ({
             subspace: change.subspace,
             key: change.key,
-            value: JSON.parse(change.value)
+            value: this.parseParamValue(change.value)
           }))

Add the helper to the class:

private parseParamValue(value: string): unknown {
  try {
    return JSON.parse(value);
  } catch {
    return value;
  }
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/api/src/proposal/services/proposal/proposal.service.ts` around lines 68
- 72, Update the parameter mapping to tolerate legacy non-JSON values by adding
a private parseParamValue helper on the proposal service that returns
JSON.parse(value) when valid and the original string when parsing fails, then
use it instead of JSON.parse(change.value).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/api/src/proposal/services/proposal/proposal.service.ts`:
- Around line 65-67: Update the proposal conversion logic around paramChanges to
safely handle omitted messages by defaulting proposalFromCosmos.messages to an
empty array before filtering. Mark CosmosGovProposal.messages optional so
zero-message Cosmos responses are represented correctly while preserving
existing change extraction.

---

Nitpick comments:
In `@apps/api/src/proposal/services/proposal/proposal.service.ts`:
- Around line 68-72: Update the parameter mapping to tolerate legacy non-JSON
values by adding a private parseParamValue helper on the proposal service that
returns JSON.parse(value) when valid and the original string when parsing fails,
then use it instead of JSON.parse(change.value).
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 1d23ae1b-bb1c-4d49-b411-a20702d5e8be

📥 Commits

Reviewing files that changed from the base of the PR and between 44bef1f and 9b1e6c1.

📒 Files selected for processing (5)
  • apps/api/src/proposal/services/proposal/proposal.service.ts
  • apps/api/test/functional/proposals.spec.ts
  • packages/http-sdk/src/cosmos/cosmos-http.service.spec.ts
  • packages/http-sdk/src/cosmos/cosmos-http.service.ts
  • packages/http-sdk/src/cosmos/types.ts

Comment thread apps/api/src/proposal/services/proposal/proposal.service.ts Outdated

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

LGTM. Correct, well-tested migration from gov v1beta1 to v1 for the three proposal queries, matching the described prod 500 root cause.

Extended reasoning...

Overview

The PR migrates CosmosHttpService's three governance-proposal queries (list, get-by-id, tally) from /cosmos/gov/v1beta1/* to /cosmos/gov/v1/*, and updates ProposalService to map the new v1 response shape (top-level id/title/summary, *_count tally fields, messages[] instead of content, nullable voting timestamps) back onto the unchanged public API contract (zod schemas untouched). Types in packages/http-sdk are rewritten to the v1 shape; I confirmed via grep that ProposalService is the only internal consumer of these exported types, so the acknowledged breaking type change has no other blast radius in this repo.

Security risks

None. This is a read-only proxy of public governance data from a REST full node; no auth, no user input reaches the changed code paths beyond a validated numeric proposal id.

Level of scrutiny

Medium — production-impacting bug fix (upstream 500s) but logically simple field remapping in a single service, with no schema/contract changes. I traced each field mapping (id, title/summary, tally *_count, voting_start/end_time null-coalescing to the sentinel 0001-01-01T00:00:00Z, and paramChanges extraction from MsgExecLegacyContent messages) against both the diff and the new functional test fixtures and found the logic consistent and correctly covered, including the two prod-breaking shapes (zero-message and multi-message proposals) called out in the PR description.

Other factors

Test coverage is strong: new functional tests exercise the zero-message/null-voting-time case, the multi-message case, and the legacy param-change + final-tally path, plus a new unit spec for CosmosHttpService verifying the new endpoint paths. Codecov reports full coverage of changed lines. No outstanding review comments in the timeline to address.

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Looks good overall; the one inline nit (unguarded total_deposit[0]) mirrors a class of issue the author already fixed for messages in this same PR, so I'd trust it to get picked up similarly.

Extended reasoning...

Overview

This PR migrates three governance proposal queries (list, by-id, tally) from the deprecated gov/v1beta1 REST endpoints to gov/v1, updating the shared http-sdk types and the apps/api ProposalService mapping logic accordingly. It's a targeted fix for a live production 500 caused by the chain node rejecting non-v1beta1-representable proposals. The public API response contract (zod schemas, generated types) is explicitly unchanged, and the PR includes solid functional/unit test coverage for the new v1 shapes, including edge cases like proposals with zero, multiple, or legacy-content messages, and null voting timestamps.

Security risks

No security-sensitive surface here — this is read-only data mapping from a public blockchain REST node into the console's existing public API contract. No auth, injection, or data-exposure concerns.

Level of scrutiny

This is a production-critical bug fix (fixing an active 500 in /v1/proposals), and the mapping logic involves several protojson-quirk edge cases (omitted repeated fields, nullable timestamps) that are easy to get subtly wrong. That said, the diff is well-scoped, mechanical in nature (renaming/remapping fields), and backed by good test coverage exercising the exact prod-breaking shapes. The one inline finding (unguarded total_deposit[0] access, mirroring the already-fixed messages guard) is flagged as a nit by the bug hunter itself — current mainnet behavior doesn't trigger it, and the fix is a one-line mirror of the pattern already applied elsewhere in this file.

Other factors

The author was responsive and thorough during CodeRabbit's review, promptly fixing the analogous messages-omission issue and adding regression coverage for it. That track record, plus the triviality and non-blocking nature of the total_deposit nit, gives me confidence a human reviewer doesn't need to gate on it, though the inline comment leaves a clear trail for a follow-up if desired.

Comment thread apps/api/src/proposal/services/proposal/proposal.service.ts

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Beyond the two previously-fixed omitted-field issues (messages, total_deposit), I also checked the tally fields (yes_count/abstain_count/no_count/no_with_veto_count) and content?.changes for the same protojson-omits-empty/default-field risk — both are already read through || 0 or ?? [] fallbacks, so they don't share the crash risk. No new issues found this run; deferring given this migration has already required two rounds of edge-case fixes for a production-critical endpoint.

Extended reasoning...

No new bugs were found by the bug hunting system or in my own review this run. This is a follow-up note only: given the pattern of two real omitted-repeated-field bugs already found and fixed in this same PR (messages, total_deposit), I checked the remaining scalar/optional-chain accesses in ProposalService (tally counts, param-change changes extraction) for the same protojson-default-omission failure mode and found them already safely guarded with || 0 / ?? [] fallbacks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant