Cycle Mechanics

How cycles, deadlines, grace periods, and state transitions work in detail.

Cycle Mechanics

A cycle is the core accountability unit in ShipLock: a time window in which the project must produce an accepted check-in.

Cycle Timeline

Every cycle follows this sequence:

  1. Cycle starts → countdown to deadline begins
  2. Deadline hits → grace buffer begins
  3. Grace ends → if no accepted check-in → project becomes slashable

Formula

deadline = cycleStartAt + cadence
graceEndsAt = deadline + grace

Canonical Time Variables

Every project stores these timestamps on-chain:

VariableDescription
cycleNonceInteger cycle counter (starts at 0)
cycleStartAtTimestamp when the current cycle began
nextDeadlineAtDeadline timestamp for current cycle
graceEndsAtnextDeadlineAt + grace
lastAcceptedCheckinAtTimestamp of last accepted check-in (for streaks)
lastSlashedCycleNonceCycle nonce that was last slashed (prevents double-slash)

Both nextDeadlineAt and graceEndsAt are stored explicitly to avoid repeated computation and enforcement ambiguity.

Project States

These are derived from canonical timestamps — not stored as a field. The UI computes them in real time.

ACTIVE

now <= nextDeadlineAt

Project is within its deadline window. Either already has an accepted check-in or still has time.

AT_RISK

now is within riskWindow of deadline (e.g. 12h before)
AND hasAcceptedInCycle == false

Purely a UX state — drives alerts and highlighting. Not an on-chain enforcement boundary.

VIOLATION (Slashable)

now > graceEndsAt
AND hasAcceptedInCycle == false

This is the enforcement boundary. The project can now be slashed by anyone.

SLASHED

lastSlashedCycleNonce == cycleNonce

The cycle has been resolved by penalty. Prevents re-slashing the same missed cycle.

Check-in Lifecycle

Each check-in has its own lifecycle within a cycle:

FieldDescription
submittedAtWhen the check-in was posted
endorseWindowEndsAtWhen endorsements close
totalWeightRunning sum of endorsement weights
endorserCountNumber of unique endorsers
statusPENDING → ACCEPTED or REJECTED

PENDING

During the endorse window: watchers can endorse.

ACCEPTED

Reached when within the endorse window:

totalWeight >= thresholdWeight
AND endorserCount >= minEndorsers
AND now <= endorseWindowEndsAt

When a check-in becomes ACCEPTED, the cycle is immediately satisfied and the project advances to the next cycle.

REJECTED

When now > endorseWindowEndsAt and thresholds were never met.

Critical Rule: Endorse Window vs Grace

The endorse window must end before grace ends. Otherwise ambiguity arises: a project could be slashable while endorsements are still happening.

endorseWindowHours <= graceHours

ShipLock enforces this constraint at project creation.

Cycle Advancement

When a check-in becomes ACCEPTED, the cycle advances immediately:

lastAcceptedCheckinAt = now
cycleNonce += 1
cycleStartAt = now
nextDeadlineAt = now + cadence
graceEndsAt = nextDeadlineAt + grace

This is a rolling cadence: shipping sooner resets the timer. There is no fixed weekly schedule — accountability is continuous.

One Accepted Check-in Per Cycle

Only the first check-in that reaches ACCEPTED satisfies the cycle.

After that:

  • Additional check-ins can be posted for transparency
  • But they do not affect cycle timing or slashability

For MVP: once a check-in is accepted, new check-ins are blocked until the next cycle starts.

Multiple Attempts Per Cycle

A builder can submit multiple check-ins in the same cycle:

  1. Check-in #1: weak proof → no endorsement → rejected
  2. Check-in #2: improved proof → endorsement → accepted

This creates a strong incentive: "If the community isn't convinced, improve your proof."

Window Overlap Prevention

To keep things clean, only one PENDING check-in is allowed per project at a time. Before submitting, the protocol verifies no check-in exists with status PENDING.

What Happens If a Check-in Is Never Endorsed?

That's normal and intended:

  1. Builder submits check-in at time T
  2. Endorse window ends, thresholds not met
  3. Check-in becomes REJECTED
  4. Cycle continues — builder can try again
  5. If grace ends with no accepted check-in → slashable

Rejection is passive. The project is not punished unless grace ends with no accepted check-in.

Edge Cases

Exactly at graceEndsAt

Strict inequality: slashable only if now > graceEndsAt (not >=).

Endorsement at exact window end

Endorsements count only if now <= endorseWindowEndsAt.

Indexer lag

UI must not rely on indexer for slash eligibility. If the indexer is behind, show a warning and allow direct RPC check.

Project owner disappears

No issue. Enforcement is permissionless. The project either ships or gets slashed.