ruvnet/ruflo · error

Cannot enact amendment with status: ${amendment.status}

Error message

Cannot enact amendment with status: ${amendment.status}

What it means

enactAmendment() requires status 'approved' — the state set by resolveAmendment() when the supermajority threshold and requiredApprovals are met. Calling enact on an amendment that is still 'proposed' (you forgot resolveAmendment) or that was 'rejected' throws this error with the actual status. The status remains unchanged after the throw, so the amendment stays in the map and the mistake is recoverable.

Source

Thrown at v3/@claude-flow/guidance/src/meta-governance.ts:435

      amendment.status = 'approved';
    } else {
      amendment.status = 'rejected';
    }

    return amendment;
  }

  /**
   * Enact an approved amendment
   * Returns true if enacted successfully
   */
  enactAmendment(amendmentId: string): boolean {
    const amendment = this.amendments.get(amendmentId);
    if (!amendment) {
      throw new Error(`Amendment not found: ${amendmentId}`);
    }
    if (amendment.status !== 'approved') {
      throw new Error(`Cannot enact amendment with status: ${amendment.status}`);
    }

    // Check if any changes would violate immutable invariants
    for (const change of amendment.changes) {
      if (change.type === 'remove-rule' || change.type === 'modify-rule') {
        const invariant = this.invariants.get(change.target);
        if (invariant?.immutable) {
          throw new Error(`Cannot modify immutable invariant: ${change.target}`);
        }
      }
    }

    amendment.status = 'enacted';
    this.amendmentHistory.push(amendment);
    this.amendments.delete(amendmentId);

    return true;
  }

View on GitHub (pinned to fa13ee4ad6)

Solutions

  1. Always run voteOnAmendment() for enough voters, then resolveAmendment(), and check the returned status === 'approved' before enacting
  2. If status is 'proposed', resolve first; if 'rejected', do not enact — re-propose with broader support instead
  3. Because approved-but-unenacted amendments are not exposed by getPendingAmendments(), wrap enact in try-catch and branch on the status in the message
  4. Clear out rejected amendments with vetoAmendment() so enacter loops cannot trip on them

Example fix

// before
governor.enactAmendment(id); // still 'proposed' -> throws
// after
for (const v of voters) governor.voteOnAmendment(id, v, true);
const verdict = governor.resolveAmendment(id);
if (verdict.status !== 'approved') {
  throw new Error(`Amendment ${id} resolved as ${verdict.status}; refusing to enact`);
}
governor.enactAmendment(id);
Defensive patterns

Strategy: try-catch

Validate before calling

// Only 'proposed' amendments are visible via getPendingAmendments();
// confirm the resolved verdict before enacting:
if (governor.getPendingAmendments().some(a => a.id === amendmentId)) {
  throw new Error(`Amendment ${amendmentId} not resolved yet; call resolveAmendment() first`);
}

Try / catch

try {
  governor.enactAmendment(amendmentId);
} catch (err) {
  if (err instanceof Error && err.message.startsWith('Cannot enact amendment with status')) {
    // amendment stays in the map unchanged; if 'proposed', resolve first; if 'rejected', abandon or veto
    const status = err.message.split(': ')[1];
    if (status === 'proposed') {
      const verdict = governor.resolveAmendment(amendmentId);
      if (verdict.status === 'approved') governor.enactAmendment(amendmentId);
    } else {
      governor.vetoAmendment(amendmentId, 'enact-blocked');
    }
  } else {
    throw err;
  }
}

Prevention

When it happens

Trigger: Calling enactAmendment() directly after proposeAmendment() without vote + resolveAmendment(); enacting an amendment that resolveAmendment() marked 'rejected' because approvals fell short of the 0.75 supermajority default or requiredApprovals.

Common situations: Scripts that skip the voting phase in single-admin setups; automation assuming approval succeeded without checking the resolved status; rejected amendments left in the map and later swept up by an enacter loop.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18). Data as JSON: /api/errors/4b3aa5a44a7cdab2. Report an issue: GitHub.