Skip to content

feat: Add overdue milestone escalation with 14-day grace period#11

Merged
0xdevcollins merged 2 commits intomainfrom
feat/overdue-milestone-escalation
Apr 4, 2026
Merged

feat: Add overdue milestone escalation with 14-day grace period#11
0xdevcollins merged 2 commits intomainfrom
feat/overdue-milestone-escalation

Conversation

@0xdevcollins
Copy link
Copy Markdown
Contributor

@0xdevcollins 0xdevcollins commented Apr 4, 2026

Summary

  • flag_overdue_milestone() now records flagged_at timestamp on the milestone (previously only emitted an event with no state change)
  • New permissionless escalate_overdue_milestone() — if 14 days pass after flagging with no submission, rejects the milestone and cancels the campaign for refunds
  • Adds flagged_at: u64 field to Milestone struct (0 = not flagged)
  • Adds MilestoneEscalated event for indexer integration
  • Adds MilestoneNotFlagged (828) and GracePeriodNotExpired (829) error variants

Closes #4

Test plan

  • test_overdue_flag_and_escalate — full flow: flag → grace period too early (fails) → grace period expires → escalate → milestone rejected, campaign cancelled, refunds work
  • test_overdue_escalate_not_flagged_fails — escalating without flagging first returns MilestoneNotFlagged
  • test_overdue_creator_submits_during_grace_period — creator submits milestone during grace period → escalation fails (milestone no longer Pending), campaign stays active
  • All 124 tests pass (19 unit + 57 integration + 48 other crates)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Milestone escalation: flagged overdue milestones can be escalated after a 14-day grace period, canceling the campaign and triggering refunds.
    • Milestone flagging now records when a milestone was marked overdue.
  • Events

    • New escalation event published when an overdue milestone is escalated.
  • Tests

    • Added integration tests covering escalation flows and related edge cases.

flag_overdue_milestone() only emitted an event with no on-chain
consequence. Now it records flagged_at timestamp on the milestone,
and a new permissionless escalate_overdue_milestone() rejects the
milestone and cancels the campaign for refunds if the creator
doesn't submit within 14 days of being flagged.

Closes #4

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

coderabbitai bot commented Apr 4, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f7eb0d87-4256-42d4-955c-22bfad011e61

📥 Commits

Reviewing files that changed from the base of the PR and between 048b422 and 0f42100.

📒 Files selected for processing (1)
  • contracts/crowdfund_registry/src/contract.rs

Disabled knowledge base sources:

  • Linear integration is disabled

You can enable these sources in your CodeRabbit configuration.


📝 Walkthrough

Walkthrough

This PR adds enforcement for overdue milestones: milestones gain a flagged_at timestamp, flagging records when a milestone is overdue, and a public, permissionless escalate_overdue_milestone() method that—after a 14-day grace period—rejects the milestone, cancels the campaign, resets refund progress, persists state, and emits a MilestoneEscalated event. Tests and snapshots updated accordingly.

Changes

Cohort / File(s) Summary
Core Escalation Logic
contracts/crowdfund_registry/src/contract.rs
Added pub fn escalate_overdue_milestone(env, campaign_id, milestone_index); updated flag_overdue_milestone() to persist flagged_at and set flagged_at = 0 during milestone initialization in set_milestones(); state transitions: require Funded/Executing, require milestone flagged, enforce 14-day grace, set milestone → Rejected, cancel campaign, reset refund_progress, persist, emit MilestoneEscalated.
Error Handling
contracts/crowdfund_registry/src/error.rs
Added CrowdfundError::MilestoneNotFlagged = 828 and ::GracePeriodNotExpired = 829.
Events
contracts/crowdfund_registry/src/events/mod.rs
Added new #[contractevent] pub struct MilestoneEscalated { #[topic] campaign_id: u64, milestone_id: u32 }.
Storage Schema
contracts/crowdfund_registry/src/storage/mod.rs
Added pub flagged_at: u64 to Milestone (0 means not flagged; otherwise timestamp).
Tests (logic)
contracts/crowdfund_registry/src/tests/mod.rs
Added integration tests: flag + escalate happy path, escalate fails before 14-day grace, escalate fails when milestone not Pending (creator resubmits). Tests assert flagged timestamp, campaign cancellation, and refund processing.
Snapshots — Updated
contracts/crowdfund_registry/test_snapshots/tests/*.1.json, tests/integration/test_snapshots/**
Inserted flagged_at: u64 = 0 into existing CampaignMilestone entries across many snapshot files to reflect schema change (homogeneous additions).
Snapshots — New Escalation Tests
contracts/crowdfund_registry/test_snapshots/tests/test_overdue_*.1.json (new files)
Added full ledger snapshots for new escalation-related tests (flagging, grace period, escalation outcomes).

Sequence Diagram

sequenceDiagram
    participant Creator
    participant Campaign as "Campaign Contract"
    participant Storage as "Milestone Storage"
    participant System as "Escalation Caller"
    participant Refund as "Refund Mechanism"

    Creator->>Campaign: set_milestones()
    Campaign->>Storage: initialize milestone(flagged_at = 0)

    Note over Campaign,Storage: milestone deadline passed

    Creator->>Campaign: flag_overdue_milestone()
    Campaign->>Storage: set flagged_at = now
    Campaign->>Campaign: emit MilestoneOverdue

    Note over Campaign,Storage: 14-day grace period

    alt Creator resubmits within grace
        Creator->>Campaign: submit_milestone()
        Campaign->>Storage: update milestone status (not Pending)
    else Grace period expires
        System->>Campaign: escalate_overdue_milestone(campaign_id, milestone_index)
        Campaign->>Storage: ensure flagged_at != 0 and now >= flagged_at + 14d
        Campaign->>Storage: set milestone.status = Rejected
        Campaign->>Campaign: set campaign.status = Cancelled, refund_progress = 0
        Campaign->>Campaign: persist changes
        Campaign->>Campaign: emit MilestoneEscalated
        Campaign->>Refund: trigger refunds
        Refund->>Storage: process donor refunds
    end
Loading

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A nibble, a nudge, fourteen suns of grace,

I mark the overdue with haste and pace.
If no repair comes after the span,
I hop in to close what the maker began.
Carrots for backers, justice in place.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: Add overdue milestone escalation with 14-day grace period' directly and clearly describes the main change: introduction of escalation logic with a specific 14-day grace period mechanism.
Linked Issues check ✅ Passed The PR fully implements Option A from issue #4: permissionless escalate_overdue_milestone() after 14-day grace, transitions milestone to Rejected, cancels campaign, enables refunds, emits MilestoneEscalated event, and covers the required test flows.
Out of Scope Changes check ✅ Passed All changes are directly scoped to issue #4 requirements: flagged_at field addition, escalate_overdue_milestone() implementation, error variants, event definition, and comprehensive test coverage with snapshot updates.
Docstring Coverage ✅ Passed Docstring coverage is 85.71% which is sufficient. The required threshold is 80.00%.

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

✨ 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 feat/overdue-milestone-escalation

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.

@0xdevcollins 0xdevcollins merged commit 2f7dcda into main Apr 4, 2026
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.

Add overdue milestone enforcement beyond event emission

1 participant