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 amendmentView on GitHub (pinned to fa13ee4ad6)
Solutions
- Wait for the window to elapse — history entries age out of the count based on their timestamp
- For tests or batch replays, construct the governor with a higher maxAmendmentsPerWindow or a shorter amendmentWindowMs
- Batch several rule changes into a single amendment's changes[] instead of proposing many small amendments
- 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
- Batch multiple rule changes into one amendment's changes[] array
- Configure maxAmendmentsPerWindow / amendmentWindowMs explicitly for test and batch environments
- Remember the throttle is in-memory and counts enacted/vetoed amendments, not mere proposals
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
- Amendment not found: ${amendmentId}
- Cannot vote on amendment with status: ${amendment.status}
- Amendment already resolved: ${amendment.status}
- Cannot enact amendment with status: ${amendment.status}
- Cannot modify immutable invariant: ${change.target}
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/cb0225e06aa8390b.
Report an issue: GitHub.