Skip to content

✨ Feat/gov decide#770

Merged
ccamel merged 17 commits intomainfrom
feat/gov-decide
Jan 11, 2026
Merged

✨ Feat/gov decide#770
ccamel merged 17 commits intomainfrom
feat/gov-decide

Conversation

@ccamel
Copy link
Copy Markdown
Member

@ccamel ccamel commented Jan 11, 2026

Adds the decide query to axone-gov - important one, obviously.

You can now ask the stored Prolog constitution for a governance verdict (and motivation when requested). Includes input validation, clearer errors, and tests covering the main paths. Docs are intentionally minimal for now. I'll follow up with examples and integration notes once the API is fully stable...

Summary by CodeRabbit

Release Notes

  • New Features

    • Added governance decision query with optional motivation/reasoning support
    • Implemented case validation for decision inputs
  • Improvements

    • Enhanced error messages with specific variants for constitution validation, Prolog engine operations, and decision execution
    • Updated API documentation for new governance decision capabilities and response types

✏️ Tip: You can customize this high-level summary in your review settings.

@ccamel ccamel self-assigned this Jan 11, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jan 11, 2026

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

The pull request refactors error handling in the Axone governance contract by replacing a generic InvalidConstitution error with nine specialized error variants covering UTF-8 validation, Prolog engine operations, constitution validation, case validation, and decision execution. Simultaneously, it introduces new functionality for case validation and a decision query handler that orchestrates Prolog-based governance decisions through on-chain constitution evaluation.

Changes

Cohort / File(s) Summary
Error System Refinement
contracts/axone-gov/src/error.rs
Replaced single InvalidConstitution(String) variant with nine specific error types: ConstitutionUtf8, ConstitutionInvalid, PrologEngineNoAnswer, PrologEngineError, InvalidCase, DecisionFailed, DecisionNoResult, DecisionMissingVerdict, DecisionMissingMotivation
Guard Implementations
contracts/axone-gov/src/guards/case.rs, contracts/axone-gov/src/guards/constitution.rs, contracts/axone-gov/src/guards/mod.rs
New case module validates Prolog dict-based case strings with ground term enforcement; refactored constitution.rs to use new error variants; exposed case function publicly via module re-export
Query Handler Extension
contracts/axone-gov/src/handlers/query.rs
Expanded query_handler signature and added new AxoneGovQueryMsg::Decide variant handler; introduced query_decide function that validates case, loads constitution, orchestrates Prolog query execution, and extracts verdict and motivation from engine responses
Message & Response Types
contracts/axone-gov/src/msg.rs
Added Decide query variant with case and motivated parameters; introduced DecideResponse type with verdict and optional motivation fields; expanded documentation for governance program semantics
Prolog AST Enhancement
contracts/axone-gov/src/prolog/ast.rs
Added is_ground() method to Term enum to recursively verify absence of unbound variables; comprehensive unit tests covering all term variants
State Management
contracts/axone-gov/src/state.rs
Added load_constitution_as_string() helper function for UTF-8 conversion with error mapping to ConstitutionUtf8
Gateway Logic
contracts/axone-gov/src/gateway/logic.rs
Minor error variant change from generic_err to not_found for unset mock query handler
Test Coverage
contracts/axone-gov/tests/integration.rs
Added comprehensive test suite covering decision flow (success/failure paths), case validation, missing verdicts/motivations, and Prolog engine error scenarios

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant QueryHandler as Query Handler
    participant CaseGuard as Case Guard
    participant Storage as Constitution Storage
    participant PrologEngine as Prolog Engine
    
    Client->>QueryHandler: Decide { case, motivated }
    QueryHandler->>CaseGuard: case(case)
    CaseGuard-->>QueryHandler: ✓ Valid Dict (Ground)
    QueryHandler->>Storage: Load Constitution
    Storage-->>QueryHandler: Constitution Bytes
    QueryHandler->>QueryHandler: Build Prolog Query<br/>(decide/2 or decide/3)
    QueryHandler->>PrologEngine: QueryServiceAskRequest
    PrologEngine-->>QueryHandler: QueryServiceAskResponse
    QueryHandler->>QueryHandler: Extract Substitutions<br/>(Verdict, Motivation)
    QueryHandler-->>Client: DecideResponse<br/>{ verdict, motivation }
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • bdeneux
  • amimart
🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 53.85% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title uses an emoji and vague phrasing ('Feat/gov decide') that doesn't clearly convey the primary change, though it references the feature area. Revise to a clear, descriptive title without emojis, such as 'Add decide query to axone-gov contract for governance verdicts' to improve clarity for history scanning.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/gov-decide

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@codecov
Copy link
Copy Markdown

codecov Bot commented Jan 11, 2026

Codecov Report

❌ Patch coverage is 99.53917% with 1 line in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
contracts/axone-gov/src/prolog/ast.rs 99.24% 1 Missing ⚠️
Files with missing lines Coverage Δ
contracts/axone-gov/src/gateway/logic.rs 86.36% <100.00%> (ø)
contracts/axone-gov/src/guards/case.rs 100.00% <100.00%> (ø)
contracts/axone-gov/src/guards/constitution.rs 100.00% <100.00%> (+33.87%) ⬆️
contracts/axone-gov/src/handlers/query.rs 100.00% <100.00%> (ø)
contracts/axone-gov/src/msg.rs 0.00% <ø> (ø)
contracts/axone-gov/src/state.rs 100.00% <100.00%> (ø)
contracts/axone-gov/src/prolog/ast.rs 99.24% <99.24%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@bot-anik
Copy link
Copy Markdown
Member

bot-anik commented Jan 11, 2026

size-limit report 📦

Path Size
target/wasm32-unknown-unknown/release/axone_gov.wasm 706.65 KB (+8.82% 🔺)

@ccamel ccamel marked this pull request as ready for review January 11, 2026 16:11
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @contracts/axone-gov/src/handlers/query.rs:
- Around line 34-43: The validation is run on the untrimmed input which can
mismatch the later trimmed value used in the query; in function query_decide
ensure you trim the incoming case before calling guards::case by assigning let
case = case.trim(); (or let case = case.trim().to_string() if needed) and then
call guards::case(&case)? so both validation and the formatted query use the
same trimmed string; update any subsequent uses (the query format! and
guards::case invocation) to use this trimmed variable name.
🧹 Nitpick comments (4)
contracts/axone-gov/tests/integration.rs (2)

135-176: Helper responses are good; consider strengthening the mock expectation to validate request.query (and limit) too.
Right now, LogicAskScenario::install() only asserts request.program, so a malformed/incorrect query string could still “pass” these tests.


217-470: Excellent decide-path integration coverage (success + broad failure modes); main risk is brittle string matching in a few tests.
For the decide failures, consider using the same msg + chain approach you used earlier (instead of format!("{err:?}")) to reduce sensitivity to debug formatting changes.
Also, per coding guidelines: if this PR changed msg.rs / query message types for decide, ensure cargo make schema was run and updated schemas were committed.

contracts/axone-gov/src/msg.rs (1)

10-11: Clarify "resource AA" reference in documentation.

The phrase "on the resource AA" appears to be a placeholder or incomplete reference. Consider specifying what "AA" refers to or removing it if it is extraneous.

contracts/axone-gov/src/guards/constitution.rs (1)

17-20: Consider simplifying the UTF-8 conversion.

The .map(ToString::to_string) call is functional but could be expressed more directly.

♻️ Suggested simplification
     let program = std::str::from_utf8(constitution.as_slice())
-        .map(ToString::to_string)
+        .map(str::to_owned)
         .map_err(|err| AxoneGovError::ConstitutionUtf8(err.to_string()))?;
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 544eb99 and a261523.

⛔ Files ignored due to path filters (1)
  • docs/axone-gov.md is excluded by !docs/*.md
📒 Files selected for processing (10)
  • contracts/axone-gov/src/error.rs
  • contracts/axone-gov/src/gateway/logic.rs
  • contracts/axone-gov/src/guards/case.rs
  • contracts/axone-gov/src/guards/constitution.rs
  • contracts/axone-gov/src/guards/mod.rs
  • contracts/axone-gov/src/handlers/query.rs
  • contracts/axone-gov/src/msg.rs
  • contracts/axone-gov/src/prolog/ast.rs
  • contracts/axone-gov/src/state.rs
  • contracts/axone-gov/tests/integration.rs
🧰 Additional context used
📓 Path-based instructions (5)
**/*.rs

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.rs: Run cargo make schema to generate JSON schemas for each contract after any change to msg.rs or message types, and commit the updated schemas
Use standard CosmWasm contract entry points with #[cfg_attr(not(feature = "library"), entry_point)] attribute for instantiate, execute, and query functions
Validate all user inputs and apply strict access control using MessageInfo.sender, Addr, and CanonicalAddr properly to prevent reentrancy, integer overflows, and unauthorized state changes
Place unit tests in src/ alongside source code using cosmwasm-std::testing mocks to test contract entry points
Implement a migrate entry point following CosmWasm patterns with migration logic in the contract module when storage or logic changes in a breaking way
Use /// for public API documentation and // sparingly for non-obvious reasoning, explaining system invariants, trade-offs, and design intent
Use English for all comments, focusing on 'why' not 'what' when documenting architecture, interfaces, and design decisions
RDF data requires proper namespace/prefix management when working with Cognitarium contract that stores subject-predicate-object triples with SPARQL queries
Optimize for low gas usage by avoiding redundant state reads/writes in smart contract code

Files:

  • contracts/axone-gov/src/prolog/ast.rs
  • contracts/axone-gov/src/error.rs
  • contracts/axone-gov/src/state.rs
  • contracts/axone-gov/src/gateway/logic.rs
  • contracts/axone-gov/src/guards/constitution.rs
  • contracts/axone-gov/src/guards/mod.rs
  • contracts/axone-gov/tests/integration.rs
  • contracts/axone-gov/src/guards/case.rs
  • contracts/axone-gov/src/msg.rs
  • contracts/axone-gov/src/handlers/query.rs

⚙️ CodeRabbit configuration file

**/*.rs: Review the Rust code, point out issues relative to principles of clean code, expressiveness, and performance.
Suggest idiomatic solutions and best practices.

Files:

  • contracts/axone-gov/src/prolog/ast.rs
  • contracts/axone-gov/src/error.rs
  • contracts/axone-gov/src/state.rs
  • contracts/axone-gov/src/gateway/logic.rs
  • contracts/axone-gov/src/guards/constitution.rs
  • contracts/axone-gov/src/guards/mod.rs
  • contracts/axone-gov/tests/integration.rs
  • contracts/axone-gov/src/guards/case.rs
  • contracts/axone-gov/src/msg.rs
  • contracts/axone-gov/src/handlers/query.rs
**/error.rs

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Define custom error types in error.rs using thiserror crate and ContractError enum for all contract-specific errors

Files:

  • contracts/axone-gov/src/error.rs
**/state.rs

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Define state in state.rs using cw-storage-plus typed storage items with the pattern pub const STORE: Item<Store> = Item::new("store");

Files:

  • contracts/axone-gov/src/state.rs
**/tests/**/*.rs

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Place integration tests in tests/ directory using real contract instantiation with test dependencies

Files:

  • contracts/axone-gov/tests/integration.rs
**/msg.rs

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Define message types in msg.rs files, including InstantiateMsg, ExecuteMsg, and QueryMsg enums

Files:

  • contracts/axone-gov/src/msg.rs
🧠 Learnings (5)
📚 Learning: 2025-12-22T18:47:03.919Z
Learnt from: CR
Repo: axone-protocol/contracts PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-22T18:47:03.919Z
Learning: Applies to **/error.rs : Define custom error types in `error.rs` using `thiserror` crate and `ContractError` enum for all contract-specific errors

Applied to files:

  • contracts/axone-gov/src/error.rs
  • contracts/axone-gov/src/guards/constitution.rs
📚 Learning: 2025-12-22T18:47:03.919Z
Learnt from: CR
Repo: axone-protocol/contracts PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-22T18:47:03.919Z
Learning: Applies to **/state.rs : Define state in `state.rs` using `cw-storage-plus` typed storage items with the pattern `pub const STORE: Item<Store> = Item::new("store");`

Applied to files:

  • contracts/axone-gov/src/state.rs
📚 Learning: 2025-12-22T18:47:03.919Z
Learnt from: CR
Repo: axone-protocol/contracts PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-22T18:47:03.919Z
Learning: Applies to **/tests/**/*.rs : Place integration tests in `tests/` directory using real contract instantiation with test dependencies

Applied to files:

  • contracts/axone-gov/tests/integration.rs
📚 Learning: 2025-12-22T18:47:03.919Z
Learnt from: CR
Repo: axone-protocol/contracts PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-22T18:47:03.919Z
Learning: Applies to **/*.rs : Place unit tests in `src/` alongside source code using `cosmwasm-std::testing` mocks to test contract entry points

Applied to files:

  • contracts/axone-gov/tests/integration.rs
📚 Learning: 2025-12-22T18:47:03.919Z
Learnt from: CR
Repo: axone-protocol/contracts PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-22T18:47:03.919Z
Learning: Applies to **/msg.rs : Define message types in `msg.rs` files, including `InstantiateMsg`, `ExecuteMsg`, and `QueryMsg` enums

Applied to files:

  • contracts/axone-gov/src/msg.rs
🧬 Code graph analysis (3)
contracts/axone-gov/src/state.rs (1)
contracts/axone-gov/src/guards/constitution.rs (1)
  • constitution (17-50)
contracts/axone-gov/src/guards/mod.rs (2)
contracts/axone-gov/src/guards/case.rs (1)
  • case (6-21)
contracts/axone-gov/src/guards/constitution.rs (1)
  • constitution (17-50)
contracts/axone-gov/src/handlers/query.rs (3)
contracts/axone-gov/src/gateway/logic.rs (3)
  • query_service_ask (73-79)
  • query_service_ask (122-133)
  • new (16-22)
contracts/axone-gov/src/state.rs (1)
  • load_constitution_as_string (8-13)
contracts/axone-gov/src/guards/case.rs (1)
  • case (6-21)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (rust)
🔇 Additional comments (18)
contracts/axone-gov/src/prolog/ast.rs (2)

21-35: Term::is_ground() is correct and nicely idiomatic.
The recursive checks for Compound, List (including tail), and Dict values align with the intended “no variables anywhere” semantics.


37-170: Solid unit coverage for is_ground, including nested and tail-list cases.
The table-driven approach with per-case descriptions will be helpful for future regressions.

contracts/axone-gov/src/gateway/logic.rs (1)

126-133: Improved missing-handler signaling; ensure downstream assertions match the new not_found wording.
This will change the rendered error string (typically not found: ...) compared to the previous generic error.

contracts/axone-gov/src/guards/mod.rs (1)

1-5: Guard module wiring looks correct; guards::case is cleanly exposed.

contracts/axone-gov/tests/integration.rs (2)

4-7: Import updates are fine; the Result as LogicResult alias avoids name collisions cleanly.


207-215: Improved assertion strategy by checking both top-level message and error chain.
This makes the test resilient to wrapping (e.g., anyhow) while still asserting the user-facing wording.

contracts/axone-gov/src/state.rs (1)

1-13: The code is correct and will compile without issue. The AxoneGovError enum implements From<StdError> via the #[from] attribute on the Std variant (line 12 of error.rs), which the thiserror crate automatically generates. The ? operator on line 9 properly propagates and converts the StdError from CONSTITUTION.load(storage) into AxoneGovError. Additionally, the function correctly handles the UTF-8 conversion error and maps it to the domain-specific AxoneGovError::ConstitutionUtf8 variant. The implementation aligns with established state patterns and error handling conventions.

Likely an incorrect or invalid review comment.

contracts/axone-gov/src/msg.rs (3)

20-25: Well-structured instantiate message definition.

The documentation clearly explains the constitution requirements including UTF-8 encoding and required predicates. The message structure follows CosmWasm conventions.


49-64: Clear and comprehensive Decide query documentation.

The documentation provides an excellent example of the case dict format and clearly explains the behavior differences between decide/2 and decide/3 predicates. The motivated flag semantics are well-defined.


73-80: DecideResponse structure is well-designed.

The response type correctly models the verdict as mandatory and motivation as optional, aligning with the motivated flag semantics in the query.

contracts/axone-gov/src/guards/constitution.rs (2)

26-36: Robust handling of missing answers and predicates.

The error handling correctly distinguishes between a missing answer envelope (engine failure) and an empty result set (missing predicates). The formatted error message provides actionable context.


38-47: Appropriate error extraction from Prolog results.

Using filter_map with next() efficiently retrieves the first error without unnecessary allocations. The error context is preserved in the ConstitutionInvalid variant.

contracts/axone-gov/src/error.rs (1)

29-88: Excellent error variant granularity and documentation.

The refactoring from a generic InvalidConstitution to specific error variants significantly improves error handling clarity. Each variant is well-documented, explaining the precise failure context. This aligns with coding guidelines for defining custom error types in error.rs using the thiserror crate.

contracts/axone-gov/src/guards/case.rs (2)

6-21: Well-structured case validation guard.

The validation logic correctly enforces three requirements: valid syntax, dict type, and groundness. The error messages are descriptive and actionable. The pattern of parsing first, then validating structural constraints is clean.


23-30: Clean helper functions for parsing and error conversion.

The separation of parse_term and parse_error keeps the main validation function focused. Including the offset in syntax error messages aids debugging.

contracts/axone-gov/src/handlers/query.rs (3)

45-59: Robust Prolog query execution and error handling.

The query construction correctly differentiates between decide/2 and decide/3 based on the motivated flag. Error extraction using filter_map with next() is efficient. The Some(1) limit ensures only the first solution is retrieved, which is appropriate for governance decisions.


61-80: Clear result extraction with appropriate error variants.

The extraction logic correctly handles the mandatory verdict and conditionally required motivation. The use of specific error variants (DecisionNoResult, DecisionMissingVerdict, DecisionMissingMotivation) provides clear failure diagnostics.


82-88: Clean substitution lookup helper.

The find_substitution function is concise and correctly extracts the expression for a given variable name. Consider whether the expression.clone() could be avoided by returning a reference, though given the usage context, the current approach is reasonable.

Comment thread contracts/axone-gov/src/handlers/query.rs
@ccamel ccamel merged commit 92dbf66 into main Jan 11, 2026
25 checks passed
@ccamel ccamel deleted the feat/gov-decide branch January 11, 2026 16:41
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