> For the complete documentation index, see [llms.txt](https://docs.bitsafe.finance/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.bitsafe.finance/decentralization-manager/operations-and-reference/membership-and-governance-changes.md).

# Membership and governance changes

## Goal

Change the membership or approval rules of an existing Decentralized Party. Keep access to the active contract state, and keep governance and Canton topology consistent.

This page covers Decentralized Parties. For other party types, use these guides:

* A party local to one participant: [Decentralize an existing party](/decentralization-manager/operations-and-reference/decentralize-an-existing-party.md).
* A party with its own key, held by a wallet: [Decentralize an external party](/decentralization-manager/operations-and-reference/decentralize-an-external-party.md).

## Understand the four sets

Decentralization Manager tracks four related sets. A change to one set does not change the others.

| Set                            | What it controls                                                     | How to change it                         |
| ------------------------------ | -------------------------------------------------------------------- | ---------------------------------------- |
| Governance members             | Daml parties that can confirm governed actions                       | `GovernanceRules` self-management action |
| Namespace owners               | Keys that authorize topology changes for the decentralized namespace | Add-member or kick workflow              |
| Hosting participants           | Canton participants in the `PartyToParticipant` mapping              | Add-member or kick workflow              |
| Decentralization Manager peers | Nodes that can coordinate over the Noise transport                   | Peer configuration                       |

An additional proposer is separate again. An additional proposer can submit a domain action, but does not get a governance vote.

{% hint style="info" %}
**A combined membership change is not one atomic action.** A governance member change edits a Daml contract. A hosting participant change edits Canton topology. Plan and verify each change separately.
{% endhint %}

## Two thresholds

A Decentralized Party has two thresholds:

* The **topology threshold** is how many namespace owners must sign a topology change. Decentralization Manager also uses it as the party's confirmation threshold in the `PartyToParticipant` mapping. The add-member, kick, and change-threshold workflows set it.
* The **governance threshold** is how many member confirmations a governed action needs. The `GovernanceRules` contract holds it, and a `core_self` action changes it.

## Before you begin

* Confirm that every participating node is healthy, and that each pair of nodes lists the other as a peer.
* Confirm that every node of the Decentralized Party runs the same release. The code itself accepts any peer that has the same wire version and reports version `0.1.9` or later.
* Record the governance members, the governance threshold, the additional proposers, the namespace owners, the hosting participants, the topology threshold, and the peer records.
* Record the pending governance actions and the active workflow runs.
* Confirm the final governance threshold and the final topology threshold separately.
* Confirm that the remaining governance members and namespace owners can meet both final thresholds after a removal.
* Back up the persistent data of each node, and follow your Canton backup procedure.
* Test the exact change on DevNet with the same release and Canton version.
* Plan one run at a time for each party. A node refuses to start a kick, add-member, change-threshold, or contracts run for a party that already has a run in progress on that node. The node counts its runs in either role, as coordinator or as peer. The refusal says "already has a … workflow in flight". Runs for different parties can run at the same time. The guard is local to each node. Decentralization Manager does not stop two different nodes from coordinating conflicting runs on the same party.

## Choose the change

<table data-search="false"><thead><tr><th>Goal</th><th>Required operation</th><th>Does not do</th></tr></thead><tbody><tr><td>Add a voter only</td><td>Add a <code>GovernanceRules</code> member</td><td>Does not host the Decentralized Party on another participant</td></tr><tr><td>Add a host and namespace owner</td><td>Run the add-member workflow</td><td>Does not add the new member party to <code>GovernanceRules</code></td></tr><tr><td>Remove a voter only</td><td>Remove a <code>GovernanceRules</code> member</td><td>Does not remove a hosting participant or peer record</td></tr><tr><td>Remove a host and namespace owner</td><td>Run the kick workflow</td><td>Does not remove the member party from <code>GovernanceRules</code></td></tr><tr><td>Change topology approvals</td><td>Run the change-threshold workflow</td><td>Does not change the governance threshold</td></tr><tr><td>Change governance approvals</td><td>Execute a <code>core_self</code> threshold action</td><td>Does not change the topology threshold</td></tr><tr><td>Grant or revoke propose-only access</td><td>Execute an additional-proposer <code>core_self</code> action</td><td>Does not grant a vote or topology authority</td></tr></tbody></table>

## Recommended ordering

### Add a participant and a governance member

1. Complete the add-member workflow. See [Add a member to a Decentralized Party](/decentralization-manager/operations-and-reference/add-a-member.md).
2. Verify that the new participant is active and holds the party's contracts.
3. Store the party credentials on the new participant's node, and grant its Canton rights. See the Party credentials section of [Authentication and operator roles](/decentralization-manager/operations-and-reference/authentication-and-operator-roles.md#party-credentials).
4. Add the new member party to `GovernanceRules`.
5. Raise the topology threshold with **Change Threshold** if the plan counts the new participant.
6. Verify that the new governance member can read, confirm, and execute only the intended actions.

This order grants a vote only after the new participant can see the state that the vote is about.

### Remove a participant and a governance member

1. Complete or cancel the pending governance actions.
2. Remove the departing member party from `GovernanceRules`, and set a valid final governance threshold.
3. Verify that the remaining governance members can govern the application.
4. Run the kick workflow with a valid final topology threshold.
5. Revoke the peer, identity-provider, Canton, and operational access that is no longer necessary.

This order keeps the departing participant available while the governance change still needs it.

## Add a hosting participant

The add-member workflow adds a participant as a namespace owner and a host, then copies the party's contracts to it. [Add a member to a Decentralized Party](/decentralization-manager/operations-and-reference/add-a-member.md) has the full procedure. Three rules matter for planning:

* **Threshold.** The new topology threshold must be between 1 and the current number of namespace owners. The new participant does not count, because it cannot sign until its contract import completes. To count it, run **Change Threshold** after the add completes.
* **Downtime.** The new participant leaves the synchronizer when it signs the proposals. It reconnects after the contract import ends. While it is disconnected, every party on that participant pauses, not only this party. The existing hosts keep running.
* **Recovery.** When a run fails, click **Retry** on the coordinator. Do not cancel the run, and do not reconnect the new participant by hand.

## Add a governance member

The governance member is a Daml party. It can differ from the Canton participant ID that the topology workflow uses.

Set `GOV_THRESHOLD` to the final governance threshold. Each eligible member then confirms the same `core_self` action from its own node:

```bash
curl -X POST "$DECPM_URL/governance/confirm" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "party_id": "joint-party::1220...",
    "rules_contract_id": "<governance-rules-cid>",
    "action": {
      "type": "governance_add_member",
      "member": "member-d::1220...",
      "new_threshold": '"$GOV_THRESHOLD"'
    },
    "governance_type": "core_self"
  }'
```

After enough eligible confirmations exist, execute the exact same action with the active confirmation contract IDs:

```bash
curl -X POST "$DECPM_URL/governance/execute" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "party_id": "joint-party::1220...",
    "rules_contract_id": "<governance-rules-cid>",
    "action": {
      "type": "governance_add_member",
      "member": "member-d::1220...",
      "new_threshold": '"$GOV_THRESHOLD"'
    },
    "confirmation_cids": ["<confirmation-cid-1>", "<confirmation-cid-2>"],
    "governance_type": "core_self"
  }'
```

A successful self-management action creates a new `GovernanceRules` contract. Record its contract ID, and verify the new member set and threshold.

## Remove a governance member

Use `governance_remove_member` with the final governance threshold:

```json
{
  "type": "governance_remove_member",
  "member": "member-c::1220...",
  "new_threshold": <final-governance-threshold>
}
```

Confirm and execute it through the same `core_self` flow. Verify the new rules contract before you change topology.

## Remove a hosting participant

### 1. Start the workflow

Start the kick on the node of another host, not on the node of the departing participant. A node cannot kick itself.

In the web interface, open **Parties**, click the party, and find the participant in the **Participants** section. Click its **Kick participant** icon. In the **Kick Participant** dialog, check the namespace owner key, and set **New Threshold**.

The new topology threshold must be between 1 and the current number of namespace owners minus one.

For the API path, set `NEW_THRESHOLD` and `OLD_THRESHOLD` first:

```bash
curl -X POST "$DECPM_URL/kick" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "decentralized_party_id": "joint-party::1220...",
    "participant_id": "participant-c::1220...",
    "new_threshold": '"$NEW_THRESHOLD"',
    "previous_threshold": '"$OLD_THRESHOLD"'
  }'
```

`previous_threshold` is for display only. The answer is HTTP `202` with the run's `instance_name`.

### 2. Complete the workflow

The node of every remaining host accepts the invitation under **Approvals**. After `WaitingForPeers`, the kick workflow runs these steps, then `Complete`:

1. `ExportState`: the coordinator reads the active namespace and party mappings.
2. `CreateProposals`: the coordinator builds the new mappings, without the departing participant.
3. `SignProposals`: the remaining namespace owners sign.
4. `SubmitKick`: the coordinator submits the change to Canton.
5. `RetireLegacyKeys`: the namespace owners remove the party's old key mapping, if it has one.

The coordinator first signs the proposals in a temporary topology store. It publishes them to the synchronizer at the submit step. A namespace owner that never signs therefore leaves the party unchanged.

### 3. Verify the result

* Confirm that the departing namespace owner is absent from the active decentralized namespace definition.
* Confirm that the departing participant is absent from the active `PartyToParticipant` mapping.
* Confirm that the final topology threshold is valid and active.
* Confirm that every remaining participant sees the same topology.
* Confirm that the remaining governance members can complete a low-risk action.
* Revoke the departing node's peer record and credentials only after you confirm the topology result.

{% hint style="info" %}
A topology removal ends future hosting and signing authority. It does not delete the local contract data, logs, backups, or secrets of the former operator. Handle data cleanup and evidence through your offboarding and retention process.
{% endhint %}

Do not reconnect a removed participant later as a host without the party's contracts. The Re-adding a former member section of [Add a member to a Decentralized Party](/decentralization-manager/operations-and-reference/add-a-member.md#re-adding-a-former-member) explains the rules.

## Change a threshold

### Topology threshold

In the web interface, open the party and click **Change Threshold**. Set **New Threshold**, and start the run. The party needs at least two namespace owners.

For the API path, set `NEW_THRESHOLD` and `OLD_THRESHOLD` first:

```bash
curl -X POST "$DECPM_URL/change-threshold" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "decentralized_party_id": "joint-party::1220...",
    "new_threshold": '"$NEW_THRESHOLD"',
    "previous_threshold": '"$OLD_THRESHOLD"'
  }'
```

The new threshold must be between 1 and the number of namespace owners. The workflow reissues the namespace and party mappings with the new threshold. It ends with the `RetireLegacyKeys` step, as the kick does. It does not change `GovernanceRules`.

A new host with Canton's onboarding marker cannot sign yet. Run this workflow after the marker of every new host has cleared.

### Governance threshold

Use a `core_self` action:

```json
{
  "type": "governance_set_threshold",
  "new_threshold": <final-governance-threshold>
}
```

Confirm and execute the action through the [Governance lifecycle](/decentralization-manager/concepts-and-development/governance-lifecycle.md). Verify the new `GovernanceRules` contract, and keep its contract ID.

### Legacy key retirement

The add-member, kick, and change-threshold workflows end with a `RetireLegacyKeys` step. After the new mappings take effect, the namespace owners remove the party's obsolete `PartyToKeyMapping`. A party without that mapping skips the step.

The step needs enough upgraded namespace owners online to meet the current namespace threshold. If it times out, bring those owners online and click **Retry**. The retry resumes at the cleanup step and does not repeat the topology change.

## Manage additional proposers

Grant propose-only access with:

```json
{
  "type": "governance_add_additional_proposer",
  "additional_proposer": "ops-console::1220..."
}
```

Revoke it with `governance_remove_additional_proposer`. Both are `core_self` actions and need the active governance threshold. Propose-only access does not grant confirmation or execution authority.

## Pending actions and concurrent changes

Complete or cancel pending work before you change membership, proposer authorization, the confirmation timeout, or either threshold.

* Do not assume that a confirmation under the previous rules is still eligible.
* Read the active rules contract again before execution.
* Match confirmations to the exact action or proposal contract.
* If execution returns an unclear result, query the current contract and topology state before you retry.
* Do not start a second membership run to repair the first. Retry the failed run instead.

## Troubleshooting

| Symptom                                     | Check                                                                                  | Safe response                                                                                                                                                                           |
| ------------------------------------------- | -------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| The joining participant is not in the list  | Peer configuration, and whether the participant already hosts the party                | Configure and verify the peer before you start again                                                                                                                                    |
| The run waits for peers                     | Invitation acceptance, Noise reachability, Noise keys, and releases                    | Resolve connectivity, or decline the invitation. Do not create a duplicate run                                                                                                          |
| "already has a … workflow in flight"        | Another run in progress for this party on this node                                    | Wait for that run to end, or cancel it                                                                                                                                                  |
| "new\_threshold must be between 1 and N"    | The current number of namespace owners                                                 | Pick a value in the range. Run **Change Threshold** later to count a new participant                                                                                                    |
| Topology changed, but contracts are missing | Onboarding marker, contract import, packages, and synchronizer state                   | Stop. Follow the If something goes wrong section of [Add a member to a Decentralized Party](/decentralization-manager/operations-and-reference/add-a-member.md#if-something-goes-wrong) |
| A removal cannot meet the threshold         | Current owners, current threshold, available signers, and final threshold              | Restore signer availability, or change the threshold before the removal                                                                                                                 |
| A governance action cannot execute          | Active rules contract, member set, action value, expiry, and confirmation contract IDs | Read the state again. Confirm or propose again only when the current contracts require it                                                                                               |
| The coordinator restarts                    | Run state on the coordinator                                                           | The coordinator resumes each in-progress run at the step that it recorded. Do not start the run from another node                                                                       |
| A run fails                                 | The run's `error` on the coordinator's card                                            | Fix the cause, then click **Retry** on the coordinator                                                                                                                                  |

## Expected outcome

The Decentralized Party keeps the same party ID. Its governance rules, namespace owners, hosting participants, thresholds, and peer access match the approved final state. Every remaining participant sees the same topology and the required active contracts.

## Next actions

* Run a low-risk governance action, and keep the result record.
* Update the operator inventory, peer records, access controls, backup inventory, and incident contacts.
* Record the governance contract IDs and topology serials before and after the change.

## Technical sources

* [Add-member, kick, and change-threshold handlers](https://github.com/DLC-link/decentralization-manager/blob/main/crates/decman/src/server/handlers/workflows.rs)
* [Kick workflow steps](https://github.com/DLC-link/decentralization-manager/blob/main/crates/decman/src/workflow/kick/mod.rs)
* [Change-threshold workflow steps](https://github.com/DLC-link/decentralization-manager/blob/main/crates/decman/src/workflow/change_threshold/mod.rs)
* [Temporary proposal stores](https://github.com/DLC-link/decentralization-manager/blob/main/crates/decman/src/workflow/proposal_store.rs)
* [Governance action types](https://github.com/DLC-link/decentralization-manager/blob/main/crates/decman-lib/src/catalog/action.rs)
* [Adding a member guide](https://github.com/DLC-link/decentralization-manager/blob/main/docs/ADDING_A_MEMBER_TO_A_DECENTRALIZED_PARTY.md)
* [Architecture](https://github.com/DLC-link/decentralization-manager/blob/main/docs/ARCHITECTURE.md)
* [Deployment guide: legacy party-key retirement](https://github.com/DLC-link/decentralization-manager/blob/main/docs/DEPLOYMENT_GUIDE.md)
* [Use cases](https://github.com/DLC-link/decentralization-manager/blob/main/docs/USE_CASES.md)

## Next step

👉 **Protect the changed party:** [Backup, recovery, and upgrades](/decentralization-manager/operations-and-reference/backup-recovery-and-upgrades.md).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.bitsafe.finance/decentralization-manager/operations-and-reference/membership-and-governance-changes.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
