Next Steps: Priority Roadmap
Based on: ACTUAL_IMPLEMENTATION_STATUS_AUDIT.md
Date: 2025-12-17
Current Status: SDK Ready, Backend Incomplete
The TypeScript SDK now has complete amendment voting hooks, but the Rust backend gateway API endpoints don't exist yet. This creates a partial stack situation:
Mobile App (React Native) ✅ Has VotingScreen.tsx
↓
SDK (@icn/react-native) ✅ Has useAmendmentVoting/Results hooks
↓
Client HTTP Methods ✅ Has voteOnAmendment(), getAmendmentResults()
↓
Gateway API (icn-gateway) ❌ Missing /v1/constitutional/amendments/:id/vote
↓
Governance Actor ✅ Has data structures, storage
↓
Storage (Sled) ✅ Working
Priority 1: Complete Amendment Voting Backend (URGENT)
Tasks
1.1: Add Gateway API Endpoints
File: icn/crates/icn-gateway/src/api/governance.rs
Add three new endpoints:
// POST /v1/constitutional/amendments/:id/vote
pub async fn vote_on_amendment(
Path(amendment_id): Path<String>,
State(state): State<Arc<AppState>>,
Json(req): Json<VoteOnAmendmentRequest>,
) -> Result<Json<AmendmentVote>, ApiError> {
// 1. Parse amendment_id (hex)
// 2. Get voter DID from auth
// 3. Validate choice: approve, reject, abstain
// 4. Call governance_handle.vote_on_amendment()
// 5. Return vote record
}
// GET /v1/constitutional/amendments/:id/my-vote
pub async fn get_my_amendment_vote(
Path(amendment_id): Path<String>,
State(state): State<Arc<AppState>>,
) -> Result<Json<AmendmentVote>, ApiError> {
// 1. Parse amendment_id
// 2. Get voter DID from auth
// 3. Call governance_handle.get_amendment_vote(amendment_id, did)
// 4. Return vote record or 404
}
// GET /v1/constitutional/amendments/:id/results
pub async fn get_amendment_results(
Path(amendment_id): Path<String>,
State(state): State<Arc<AppState>>,
) -> Result<Json<AmendmentResults>, ApiError> {
// 1. Parse amendment_id
// 2. Call governance_handle.get_amendment_results(amendment_id)
// 3. Compute:
// - Vote counts (approve, reject, abstain)
// - Eligible voters
// - Quorum status
// - Approval status
// 4. Return results
}
Request/Response Types:
#[derive(Deserialize)]
pub struct VoteOnAmendmentRequest {
pub choice: VoteChoice,
pub comment: Option<String>,
}
#[derive(Serialize, Deserialize)]
pub enum VoteChoice {
Approve,
Reject,
Abstain,
}
#[derive(Serialize)]
pub struct AmendmentVote {
pub amendment_id: String,
pub voter_did: String,
pub vote: VoteChoice,
pub comment: Option<String>,
pub voted_at: u64,
}
#[derive(Serialize)]
pub struct AmendmentResults {
pub amendment_id: String,
pub status: AmendmentStatus,
pub approve_count: u32,
pub reject_count: u32,
pub abstain_count: u32,
pub total_votes: u32,
pub eligible_voters: u32,
pub has_quorum: bool,
pub quorum_threshold: f64,
pub approval_threshold: f64,
pub is_approved: bool,
}
1.2: Add Governance Actor Methods
File: icn/crates/icn-governance/src/handle.rs
Add methods to GovernanceHandle:
impl GovernanceHandle {
/// Vote on an amendment
pub async fn vote_on_amendment(
&self,
amendment_id: [u8; 32],
voter_did: String,
choice: VoteChoice,
comment: Option<String>,
) -> Result<AmendmentVote> {
// Send message to actor
// Actor validates:
// - Amendment exists and is in "voting" status
// - Voter is eligible (member of jurisdiction)
// - Voter hasn't already voted
// Store vote in amendment_votes table
// Update amendment vote counts
// Broadcast VoteCast event
}
/// Get a specific vote
pub async fn get_amendment_vote(
&self,
amendment_id: [u8; 32],
voter_did: String,
) -> Result<Option<AmendmentVote>> {
// Query amendment_votes table
// Return vote or None
}
/// Get amendment voting results
pub async fn get_amendment_results(
&self,
amendment_id: [u8; 32],
) -> Result<AmendmentResults> {
// Load amendment
// Count votes by choice
// Get eligible voter count from jurisdiction membership
// Calculate quorum: (total_votes / eligible_voters) >= quorum_threshold
// Calculate approval: (approve_count / (approve + reject)) >= approval_threshold
// Return results
}
}
1.3: Add Storage Schema
File: icn/crates/icn-governance/src/store.rs
Add amendment votes table:
// Key: amendment_id || voter_did
// Value: AmendmentVote
pub fn store_amendment_vote(&self, vote: &AmendmentVote) -> Result<()> {
let key = format!("amendment_votes:{}:{}",
hex::encode(vote.amendment_id),
vote.voter_did
);
self.db.insert(key.as_bytes(), bincode::serialize(vote)?)?;
Ok(())
}
pub fn get_amendment_vote(
&self,
amendment_id: [u8; 32],
voter_did: &str,
) -> Result<Option<AmendmentVote>> {
let key = format!("amendment_votes:{}:{}",
hex::encode(amendment_id),
voter_did
);
match self.db.get(key.as_bytes())? {
Some(bytes) => Ok(Some(bincode::deserialize(&bytes)?)),
None => Ok(None),
}
}
pub fn list_amendment_votes(
&self,
amendment_id: [u8; 32],
) -> Result<Vec<AmendmentVote>> {
let prefix = format!("amendment_votes:{}:", hex::encode(amendment_id));
// Scan with prefix, deserialize all votes
}
1.4: Register Routes
File: icn/crates/icn-gateway/src/server.rs
Add to router:
.route("/v1/constitutional/amendments/:id/vote", post(governance::vote_on_amendment))
.route("/v1/constitutional/amendments/:id/my-vote", get(governance::get_my_amendment_vote))
.route("/v1/constitutional/amendments/:id/results", get(governance::get_amendment_results))
1.5: Test End-to-End
# 1. Start daemon
./target/debug/icnd
# 2. Create amendment
curl -X POST http://localhost:8080/v1/constitutional/amendments \
-H "Authorization: Bearer $TOKEN" \
-d '{
"amendment_type": "policy",
"scope_type": "jurisdiction",
"scope_id": "coop:test",
"title": "Test Amendment",
"description": "Testing voting",
"changes": []
}'
# 3. Open voting
curl -X POST http://localhost:8080/v1/constitutional/amendments/$AMENDMENT_ID/voting \
-H "Authorization: Bearer $TOKEN"
# 4. Vote (as different users)
curl -X POST http://localhost:8080/v1/constitutional/amendments/$AMENDMENT_ID/vote \
-H "Authorization: Bearer $ALICE_TOKEN" \
-d '{"choice": "approve", "comment": "Looks good"}'
curl -X POST http://localhost:8080/v1/constitutional/amendments/$AMENDMENT_ID/vote \
-H "Authorization: Bearer $BOB_TOKEN" \
-d '{"choice": "reject"}'
# 5. Check my vote
curl http://localhost:8080/v1/constitutional/amendments/$AMENDMENT_ID/my-vote \
-H "Authorization: Bearer $ALICE_TOKEN"
# 6. Get results
curl http://localhost:8080/v1/constitutional/amendments/$AMENDMENT_ID/results
1.6: Test Mobile App
import { useAmendmentVoting, useAmendmentResults } from '@icn/react-native';
function VotingScreen({ amendmentId }) {
const { vote, loading, myVote } = useAmendmentVoting(client, amendmentId);
const { results } = useAmendmentResults(client, amendmentId);
return (
<View>
{!myVote && (
<>
<Button onPress={() => vote('approve')} title="Approve" />
<Button onPress={() => vote('reject')} title="Reject" />
</>
)}
{results && (
<Text>
Approve: {results.approve_count} | Reject: {results.reject_count}
</Text>
)}
</View>
);
}
Estimated Effort
- Gateway endpoints: 3-4 hours
- Actor methods: 2-3 hours
- Storage schema: 1-2 hours
- Testing: 2-3 hours
- Total: ~1 day
Success Criteria
- ✅ Can vote on amendments via REST API
- ✅ Can fetch my vote
- ✅ Can get live vote tallies
- ✅ Mobile app VotingScreen.tsx works end-to-end
- ✅ WebSocket broadcasts VoteCast events
- ✅ Quorum/approval logic correct
Priority 2: Server-Side Economic Safety (3-5 days)
Why Critical
Currently, budgets and credit limits are client-side only. A malicious client can bypass them. Must enforce on server.
Tasks
2.1: Credit Limits in Ledger
- Add
credit_limitfield to account metadata - Enforce in
Ledger::record_transaction() - Return error if transaction would exceed limit
2.2: Budget Validation in Gateway
- Before creating payment, check budgets via new method
- Return error if budget exceeded
- Update budget spent amount after payment
2.3: Velocity Limits
- Track payment frequency per account
- Reject if too many payments in time window
- Configurable: "max 10 payments per hour"
2.4: Dispute Resolution API
- Add endpoints for filing disputes
- Queue disputed transactions
- Admin endpoints for resolution
Priority 3: Cooperative Lifecycle (1-2 weeks)
Why Important
Cooperatives are the core entity but have no formation/dissolution logic.
Tasks
3.1: Create icn-cooperative Crate
- CooperativeActor
- Formation workflow (founding members, charter signature)
- Dissolution workflow
- Member admission/removal
3.2: Governance Integration
- Hook member admission to governance votes
- Charter amendments
- Dissolution proposals
3.3: Gateway APIs
- POST /v1/coops (formation)
- POST /v1/coops/:id/members (admission)
- DELETE /v1/coops/:id/members/:did (removal)
- POST /v1/coops/:id/dissolve
Priority 4: Federation (2-3 weeks)
Why Important
Enable inter-cooperative collaboration and resource sharing.
Tasks
4.1: Create icn-federation Crate
- FederationActor
- Inter-coop protocols
- Resource sharing contracts
4.2: Federated Identity
- Cross-coop trust resolution
- Federated DID resolution
4.3: Gateway APIs
- POST /v1/federations
- POST /v1/federations/:id/join
- GET /v1/federations/:id/resources
Priority 5: Integrate PQ Crypto (1 week)
Why Important
Quantum threat timeline: 10-15 years. Start migration now.
Tasks
5.1: Make Hybrid Default
- Update
icn-identityto generate ML-DSA + Ed25519 by default - Update
KeyPairstruct
5.2: Hybrid Signing
- Update
SignedEnvelopeto include both signatures - Verify both on receipt
5.3: Hybrid Encryption
- Update
EncryptedEnvelopeto use ML-KEM + X25519 - Mix shared secrets
5.4: Key Rotation
- Add
icnctl identity upgrade-pqcommand - Publish rotation transactions
Summary Timeline
| Priority | Feature | Effort | Status |
|---|---|---|---|
| P1 | Amendment voting backend | 1 day | ✅ Complete (2025-12-25) |
| P2 | Economic safety | 3-5 days | ✅ Complete (2025-12-25) |
| P3 | Cooperative lifecycle | 1-2 weeks | Not started |
| P4 | Federation | 2-3 weeks | Not started |
| P5 | PQ crypto integration | 1 week | PQ crypto exists, not integrated |
Immediate Action
Next sprint: Priority 3 (Cooperative lifecycle) - formation, dissolution, member admission/removal.
P1 Note: Backend endpoints already existed in icn-gateway/src/api/constitutional/voting.rs. Only SDK bug fix was needed (commit 64fc08c9).
P2 Note: CreditPolicyManager and VelocityLimiter were already implemented but not wired up. PR #288 initializes them in supervisor and gateway respectively.