{"record":{"id":"92c4cc8ec4e2c71a","repo":"ruvnet/ruflo","slug":"cannot-modify-immutable-invariant-change-target","errorCode":null,"errorMessage":"Cannot modify immutable invariant: ${change.target}","messagePattern":"Cannot modify immutable invariant: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/guidance/src/meta-governance.ts","lineNumber":443,"sourceCode":"  /**\n   * Enact an approved amendment\n   * Returns true if enacted successfully\n   */\n  enactAmendment(amendmentId: string): boolean {\n    const amendment = this.amendments.get(amendmentId);\n    if (!amendment) {\n      throw new Error(`Amendment not found: ${amendmentId}`);\n    }\n    if (amendment.status !== 'approved') {\n      throw new Error(`Cannot enact amendment with status: ${amendment.status}`);\n    }\n\n    // Check if any changes would violate immutable invariants\n    for (const change of amendment.changes) {\n      if (change.type === 'remove-rule' || change.type === 'modify-rule') {\n        const invariant = this.invariants.get(change.target);\n        if (invariant?.immutable) {\n          throw new Error(`Cannot modify immutable invariant: ${change.target}`);\n        }\n      }\n    }\n\n    amendment.status = 'enacted';\n    this.amendmentHistory.push(amendment);\n    this.amendments.delete(amendmentId);\n\n    return true;\n  }\n\n  /**\n   * Emergency veto of an amendment\n   */\n  vetoAmendment(amendmentId: string, reason: string): void {\n    const amendment = this.amendments.get(amendmentId);\n    if (!amendment) {\n      throw new Error(`Amendment not found: ${amendmentId}`);","sourceCodeStart":425,"sourceCodeEnd":461,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/guidance/src/meta-governance.ts#L425-L461","documentation":"During enactAmendment(), every change with type 'remove-rule' or 'modify-rule' is checked against the invariants map; if change.target names an invariant flagged immutable: true, enactment throws even though the amendment was approved. The check runs before any mutation, so the amendment remains in the map with status 'approved' (and can still be vetoed). This is the constitution's hard floor: even supermajority approval cannot touch immutable invariants.","triggerScenarios":"An approved amendment whose changes[] include a remove-rule/modify-rule entry targeting an invariant registered with immutable: true; replaying a governance log against a governor whose core invariants are immutable; amendment drafts written without consulting getInvariants().","commonSituations":"Teams modelling policy changes as amendments and forgetting which invariants are protected; environments where the invariant set differs between staging (mutable) and production (immutable).","solutions":["Re-propose an amendment that achieves the goal without touching immutable invariants — e.g. add a new rule instead of modifying the protected one","Clear the stuck approved amendment with vetoAmendment(id, reason) — veto has no status gate and removes it from the map","Before proposing, cross-check every changes[].target against governor.getInvariants() and reject drafts that hit immutable entries","If the invariant legitimately must change, rebuild the MetaGovernor at construction time with the new invariant definition — the runtime API will never allow it"],"exampleFix":"// before\nconst a = governor.proposeAmendment({ changes: [{ type: 'modify-rule', target: 'core-safety' }], /* ... */ });\n// ... approved, then:\ngovernor.enactAmendment(a.id); // throws: immutable invariant\n// after — pre-validate targets before proposing\nconst immutable = new Set(\n  governor.getInvariants().filter(i => i.immutable).map(i => i.id)\n);\nconst safe = changes.filter(c => !immutable.has(c.target));\nif (safe.length !== changes.length) {\n  throw new Error('Amendment targets immutable invariants; rewrite the changes');\n}\ngovernor.proposeAmendment({ changes: safe, /* ... */ });","handlingStrategy":"validation","validationCode":"const immutableIds = new Set(\n  governor.getInvariants().filter(i => i.immutable).map(i => i.id)\n);\nconst touchesImmutable = amendment.changes.some(\n  c => (c.type === 'remove-rule' || c.type === 'modify-rule') && immutableIds.has(c.target)\n);\nif (touchesImmutable) {\n  throw new Error('Amendment targets immutable invariants; rewrite its changes before enacting');\n}\ngovernor.enactAmendment(amendment.id);","typeGuard":"function amendmentIsEnactable(governor: MetaGovernor, amendment: Amendment): boolean {\n  const immutable = new Set(governor.getInvariants().filter(i => i.immutable).map(i => i.id));\n  return amendment.changes.every(\n    c => !((c.type === 'remove-rule' || c.type === 'modify-rule') && immutable.has(c.target))\n  );\n}","tryCatchPattern":null,"preventionTips":["Validate every changes[].target against getInvariants() at proposal-draft time, not at enact time","Prefer add-rule changes over modify-rule when the target is constitutional","If enact throws this, the amendment remains 'approved' in the map — veto it and re-propose a safe version"],"tags":["guidance","meta-governance","amendment","invariant","immutability","constitution"],"backgroundTag":"immutable-constraint-violation","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-08-22T04:17:13.399Z"}