<!-- MIT License. Copyright (c) 2026 Decentralized Science Labs LLC. -->
<!-- summary: Publishing a deployment to this site, from the Deploy tab or an existing record, what the server writes, unpublishing, and the Check tab. -->
# Publish, unpublish and check

Publishing tells a COLLAB site which contracts its pages read. Until a deployment is published,
every page says that COLLAB is not deployed on this site yet. This page is for the operator: what
publishing writes on the server, how to publish a deployment you have made or one that already
exists, how to take it off the site again, and how anyone can check which contracts a site uses.

## What publishing does

Publishing sends the deployment record, the content of `deployments/29.json`, to the admin
service. The server then:
1. checks the record again, strictly (see [What the server refuses](#what-the-server-refuses));
2. keeps it as `/var/www/collab/shared/deployments/29.json`, and the record it replaces in
   `shared/history/`;
3. writes `config.js` again from the record and the site settings, keeping the old one in the
   history too;
4. asks for a prerender run, and for the content policy step when the policy `config.js` needs
   differs from the one the pages carry.

`config.js` is revalidated on every load, so every page reads the new contracts on its next load.
The site leaves its undeployed mode at once: the window "COLLAB is not deployed on this site yet"
gives way to the DAOs, votes and tokens of the new deployment. Pages already open pick it up when
they are loaded again.

Publishing changes nothing on chain. It only chooses what this site shows.

## Publishing from the Deploy tab

Right after a deployment, the Deploy tab's last step, **Publish to this site**, publishes it: sign
in, press the button and confirm. See
[Deploy the protocol from /admin](deploy-from-admin.md#step-6-publish-to-this-site).

## The Publish tab

The Publish tab, `/admin/publish`, needs the admin token. It has two cards.

### On this site now

The deployment the site publishes: badge **Published** or **Nothing published**, its version and
chain, the DAO factory, the start block and the integrations, with **Check it** and **Unpublish**.

### Publishing an existing deployment

**Publish a deployment** publishes a deployment of this release that already exists, for example
one made with Foundry, or one deployed from another browser. Choose where it comes from: **A
deployments file** or **Read it from the chain**. Either way, the page checks the record on chain
before **Publish to this site** unlocks.

#### From a deployments file

Choose the file in **Deployments JSON file** (`deployments/<chainId>.json`, as `script/Deploy.s.sol`
or the Deploy tab writes it, at most 256 KB), or paste its contents into **Or paste its contents**.

The page first says what the server would refuse ("The server would refuse this record."). A record
the server would accept is checked at once: "Checking 12 of 60…", then **Verified** or **Failed**
with the results. It reads the chain through your wallet when the wallet is on the record's chain,
and otherwise through this site's RPC endpoint, which it says ("Read through this site's RPC
endpoint."). **Run the checks** runs them again.

#### Read from the chain

Without the file, the page can rebuild the record from the chain:
- **DAO factory address:** the address every DAO of the deployment was created by.
- **The account that deployed it:** the account that created the factory and, right after it, the
  two lenses. Your wallet's account is filled in when it is connected.

**Find the deployment** then reads:
- 18 of the 20 contracts and wL1, through the factory's getters and the contracts they point at;
- the two lenses, as the deployer's next two creations after the factory;
- the start block, as the block before the text store's creation (on a node that keeps old
  state);
- the integration lists from the factory, named after this site's configuration or Deploy.s.sol's
  chain 29 list when the addresses match.

What the chain cannot tell, the page asks for: **DAO lens** and **Market lens** when the account
that deployed it is not given or did not create the factory; **Start block** in those cases too, or
when the node keeps no old state ("GL1X shows the text store's creation"); and the **Name**, **Id**,
**Site** and **Model store** of an integration it cannot name.

#### Confirming

**Publish to this site** asks first: "Publish to collab.genesisl1.com?" (your host). When the site
shows another deployment, the dialog says that this replaces it and that the replaced record stays
in the server's history.

### What the server refuses

The server checks every record again, whatever the page said, and answers with the reason and the
field: "The server refused the record." It refuses a record:
- for another chain: "this site serves chain 29; the record is for chain …";
- without a COLLAB version, or of another minor version than the release: "the record is for COLLAB
  DAO v2.1.0, but this site runs COLLAB 2.2.0, which needs COLLAB DAO v2.2.x contracts";
- without a start block: "startBlock must be a block number";
- missing an address: "missing or invalid address for daoLens: None", for any of `factory`,
  `daoLens`, `marketLens`, `textStore`, `keyring`, `desciFactory`, `desciRouter`, `lockFactory`,
  `distributor`, `launcher`, `wl1` and `policyBuilder`;
- with a zero address, an address used twice, or a mixed-case address with a wrong checksum: "the
  address for factory has a wrong checksum: …";
- with integration entries the site could not show, as in the Deploy tab's step 2: an id, a name or
  a site that is not allowed, a zero or repeated address, or more than 8 of a kind;
- with any other key whose value is not an address (apart from an optional `rpc` URL), or with more
  than 64 keys.

The full format is in [Data formats](data-formats.md#deployment-records), and the request in the
[Admin API reference](admin-api.md#publish-a-deployment).

## After publishing

![What the server wrote, and the prerender's progress, right after publishing](figure:admin-publish)

The page shows what the server wrote:
- `deployments/29.json`, with the one it replaces kept in the history folder;
- `config.js`, which every page loads, now naming these contracts;
- the security policy, with its badge: **In step**, or **Updating** for a few seconds.

Beside it, **Static pages** follows the prerender run live: **Requested**, **Running**, then **Pages
written**, **Written, with warnings** or **Failed**. The first run after publishing writes the
pages, the sitemap and the member network; DAO pages appear for each DAO as members create them.

Then open the home page as a visitor would, and Status for the prerender's log.

## Unpublishing

**Unpublish**, on the Publish tab, takes the deployment off the site. The dialog, "Take this
deployment off the site?", says what follows:
- every page goes back to saying that COLLAB is not deployed here, with a link to the admin page;
- the contracts stay on chain and keep working everywhere else;
- the record is kept in the server's history, and you can publish it again at any time.

The page sends the admin API's `{"record": null}`. The server writes an undeployed `config.js`,
moves the record to the history and asks for a prerender run, which removes that deployment's
pages, preview images and data files; [Static pages, data files and prices](prerender.md#before-a-deployment-is-published)
says what stays.

## Replacing a deployment

Publishing another record replaces the one on the site; there is one deployment per chain. The
replaced record goes to the history, and the next prerender run removes the pages and preview
images of DAOs the new factory does not list. DAOs of the old factory keep working on chain, but
this site no longer shows them.

## The history folder

`/var/www/collab/shared/history/` keeps the newest 50 replaced versions of each file: the deployment
record (`…-deployment-29.json`), `config.js` and `site.json`, each named after the time it was
replaced. Only `collab` and root can read it:

```bash
sudo ls -l /var/www/collab/shared/history/
```

To publish an earlier record again, copy it from there to your computer and publish it from the
Publish tab's file field.

## Checking any deployment

The Check tab, `/admin/check`, reads a deployment back from the chain and compares it with this
release. It needs no admin token and sends nothing, so anyone can use it to confirm that a COLLAB
site points at genuine contracts. The tab runs the code the site serves, so its answer is only as
trustworthy as that code: to check a site you do not trust, first compare the files it serves with
the release's `SHA256SUMS`. 2.1's `/deploy?mode=check` arrives here.

Under **What to check**, choose:
- **This site's configuration:** the contracts `config.js` names (once a deployment is published);
- **A deployments file:** any `deployments/<chainId>.json`, chosen or pasted.

**Run the checks** then checks:
- **Code:** each of the 20 contracts holds the code of this release, byte for byte except its
  immutables;
- **Wiring:** every constructor argument reads back as Deploy.s.sol passes it;
- **External contracts:** wL1 exists and answers as it should; on GenesisL1 it must be the one
  Deploy.s.sol names;
- **Integrations:** each listed GL1F collection is one collection whose contracts point at each
  other, each CIPNFT contract answers like CIPNFT, and the DAO factory lists exactly these;
- **Found on chain:** contracts a record does not name, like the six DAO implementations, are
  found through the factory and checked too.

The checks read the chain through your wallet when it is connected to the record's chain, and
otherwise through the RPC endpoint in your settings, which the result says: "Read through the RPC
endpoint in your settings." A result is only as trustworthy as that endpoint; connect a wallet and
run the checks again to read through your wallet's own network.

## Related

- [Deploy the protocol from /admin](deploy-from-admin.md)
- [The admin page](admin.md)
- [Static pages, data files and prices](prerender.md)
- [Data formats](data-formats.md)
- [Troubleshooting](troubleshooting.md)
