ruvnet/ruflo · warning

Amendment rate limit exceeded: ${this.maxAmendmentsPerWindow

Error message

Amendment rate limit exceeded: ${this.maxAmendmentsPerWindow} per ${this.amendmentWindowMs}ms

What it means

MetaGovernor.proposeAmendment() enforces an in-memory rate limit: it counts amendmentHistory entries newer than amendmentWindowMs and refuses new proposals once the count reaches maxAmendmentsPerWindow. History entries are pushed only by enactAmendment() and vetoAmendment(), so the limit throttles how many amendments you can carry to completion (or veto) inside the window. Defaults are 3 per 24 hours, configurable via MetaGovernanceConfig.

Source

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

      results,
      timestamp: Date.now(),
    };
  }

  /**
   * Propose a new amendment
   */
  proposeAmendment(
    proposal: Omit<Amendment, 'id' | 'timestamp' | 'status' | 'votes'>
  ): Amendment {
    // Check rate limiting
    const now = Date.now();
    const recentAmendments = this.amendmentHistory.filter(
      (a) => now - a.timestamp < this.amendmentWindowMs
    );

    if (recentAmendments.length >= this.maxAmendmentsPerWindow) {
      throw new Error(
        `Amendment rate limit exceeded: ${this.maxAmendmentsPerWindow} per ${this.amendmentWindowMs}ms`
      );
    }

    const amendment: Amendment = {
      id: randomUUID(),
      timestamp: now,
      status: 'proposed',
      votes: new Map(),
      ...proposal,
    };

    this.amendments.set(amendment.id, amendment);
    return amendment;
  }

  /**
   * Vote on an amendment

View on GitHub (pinned to fa13ee4ad6)

Solutions

  1. Wait for the window to elapse — history entries age out of the count based on their timestamp
  2. For tests or batch replays, construct the governor with a higher maxAmendmentsPerWindow or a shorter amendmentWindowMs
  3. Batch several rule changes into a single amendment's changes[] instead of proposing many small amendments
  4. Remember the count is in-memory: a restart resets it (at the cost of losing pending amendment state)

Example fix

// before
const governor = createMetaGovernor(); // 3 per 24h
// after (test/batch config)
const governor = createMetaGovernor({
  maxAmendmentsPerWindow: 50,
  amendmentWindowMs: 60_000,
});
Defensive patterns

Strategy: retry

Validate before calling

const windowStart = Date.now() - amendmentWindowMs;
const recent = governor.getAmendmentHistory().filter(a => a.timestamp > windowStart);
if (recent.length >= maxAmendmentsPerWindow) {
  // wait, batch into fewer amendments, or reconfigure the governor
  throw new Error('Amendment budget exhausted for the window');
}

Try / catch

try {
  governor.proposeAmendment(proposal);
} catch (err) {
  if (err instanceof Error && err.message.startsWith('Amendment rate limit exceeded')) {
    // transient by design: schedule a retry after the window or fold changes into an existing amendment
    return scheduleRetry(proposal, windowRemainingMs);
  }
  throw err;
}

Prevention

When it happens

Trigger: Enacting or vetoing 3 amendments (default) and then proposing another within the 24h window; governance test suites that loop propose → vote → resolve → enact rapidly; tuning MetaGovernanceConfig { maxAmendmentsPerWindow, amendmentWindowMs } without accounting for batch runs.

Common situations: Automated governance pipelines or CI that replay many amendments; seeding a new governor by replaying an amendment backlog; default limits colliding with scripted demos.

Related errors


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