# Public-testnet deployment preparation

This is an **offline preparation tool**, not a deployed public testnet. Hosting,
operators and network parameters are still undecided. Testnet coins
have no financial value. Mainnet economics, physical-device coverage and a
production audit are separate scopes; they are not prerequisites for preparing
these templates. Cologna and klick-game remain external games for later
[API integration](../../marketplace/docs/game-integration.md).

Publisher **Monkey-Games.Productions** and the base domains
`grc.monkey-games.productions` / `test.grc.monkey-games.productions` are selected.
The [domain and service layout](../../docs/domain-layout.md) records the prepared
service names and authoritative DNS observations for both environments. Additional
reward hosts remain proposed. The separate [web edge preparer](../web-edge/README.md)
renders client/API routing without starting services. TLS checks of the deeper test/wallet
names still fail; hosting, service operation and public-network approval remain open.

Node 22.13+ (supported 22.x) or 24+ is required. There are no npm dependencies.
Use the pinned complete integration checkout for real operator preparation.
The renderer verifies the selected public Root/Chain/Wallet/Platform source hashes in
`source-pins.json`; it never invokes Git, binaries, a shell, SSH, DNS or RPC.

## Application contracts after anchoring

[Contracts 0.2.0](../../contracts/docs/approved-deployment.md) provides a separate
keyless deployment plan and read-only preflight for the approved positive network
identity. An operator signs its four fixed CREATE transactions externally; the
execution CLI binds them to a private local POSIX journal and verifies canonical
receipts and runtime code. This renderer does not execute it or choose signer,
role, gas or budget values. The legacy `42801` devnet command cannot deploy this
public-testnet profile.

## Optional testnet faucet

The separately configured [native faucet](../../platform/services/testnet-faucet/README.md)
requires Node 24, a dedicated funded sponsor, the approved positive network
anchor, private key and Captcha-secret files, and one authoritative SQLite
journal. Configure the fixed amount, principal and gas budgets, cooldowns and
initial nonce explicitly. Its key-free browser example uses the existing
PoW-Captcha service. A separate [Node 24 operator package](../testnet-faucet/README.md)
bundles dependencies, the browser example and rendered service/proxy templates;
build it with `npm run build:testnet-faucet -- --output /private/new-faucet-build`.
This deployment renderer still generates no Faucet units, secrets or funding.
Public TLS/proxy, load, backup cutover and operator acceptance
remain separate deployment work once hosting is chosen.

## Commands and output contract

From the integration repository, with absolute canonical paths:

```sh
node deploy/public-testnet/prepare.mjs \
  --manifest /absolute/repo/deploy/public-testnet/manifest.example.json \
  --output /absolute/new-template-bundle
```

The example deliberately contains `null` for every undecided operator value.
Default mode produces only **non-startable `.template` files** and reports the
missing values. It does not silently fill them from a devnet, environment or RPC.
Invalid supplied values fail even in template mode. To prepare concrete files:

```sh
node deploy/public-testnet/prepare.mjs \
  --manifest /absolute/operator/bootstrap.json \
  --output /absolute/new-reviewed-bundle --strict
node deploy/public-testnet/prepare.mjs \
  --verify-bundle /absolute/new-reviewed-bundle \
  --complete-sha256 EXTERNALLY_RECORDED_COMPLETE_SHA256
```

Strict mode refuses incomplete/proposal input before creating output. Every
successful output includes `preparation.json` and a last-written `COMPLETE.json`
inventory. Record the printed `completeSha256` separately; the manifest cannot
authenticate itself. A missing marker, wrong pin, altered file, link or extra
entry invalidates the bundle. Never install a partial directory. New directories
and `wx` files prevent overwrites; this is **not atomic directory publication**.
Only owner-controlled input/output paths are supported. No existing tree is
adopted, modified or removed; failed writes can leave an incomplete new tree.

Input files and templates must be bounded regular files without symlinks or
hardlinks. Linux opens use `O_NONBLOCK | O_NOFOLLOW`, then `fstat` before reading;
a FIFO cannot hang waiting for a writer. File hashes and metadata are checked
across the read. Output directory identity is checked before each write. These
guards do not defend against a malicious filesystem owner replacing ancestors
between system calls. Windows directory-fsync limitations are not a claim of
crash-atomic publication.

## Explicit manifest values

`manifest.example.json` lists the exact top-level schema. Unknown fields fail.
Do not put keys, mnemonics, secrets, passwords or private backups in this file.
All review references are public identifiers, **caller declarations**, not
cryptographically verified approvals.

- `phase`: `proposal`, `bootstrap` or `anchored`.
- `network`: distinct Cosmos ID, explicitly reviewed positive decimal EVM ID,
  UTC `genesisTime` (`YYYY-MM-DDTHH:mm:ssZ`), `nonValuable: true` and a public
  `resetPolicyReference`. Devnet/multinode Cosmos names and EVM `42801` are rejected.
- `approvals`: public `operatorPlanReference`, `genesisValidationReference`,
  `networkIdReviewReference`; `anchorReviewReference` is null until `anchored`.
- `files.nodeBinary`: `{path, sha256, installPath, sourceCommit}`. `sourceCommit`
  must equal the pinned Chain revision; `installPath` is a simple absolute path
  below `/opt/grc-testnet/`. The file is hashed, never executed or copied. A source
  declaration plus a file hash is not reproducible-build provenance.
- `files.genesis`: `{path, sha256, hybridFingerprint}`. SHA identifies the exact
  original file, while `hybridFingerprint` is the externally checked `0x`-prefixed
  app-state fingerprint. The renderer preserves the exact genesis bytes.
- `files.networkIdentity`: null before bootstrap; afterwards `{path, sha256}`
  for the [approved identity](../../docs/network-identity.md).
- `nodes`: 1–64 records with `name`, public `operator`, DNS `host`, `role`
  (`validator`, `sentry`, `rpc`, `seed`), 40-lowercase-hex `nodeId`,
  `consensusPublicKey` (canonical base64 32-byte Ed25519 public key for validators,
  null otherwise), `externalP2P` (`host:p2pPort`), peer **names** in
  `persistentPeers`, and `ports: {p2p, comet, evm, websocket, mining, rest, grpc}`.
  Ports are explicit distinct integers 1024–65535 per node and disjoint across
  nodes on the same declared hostname. DNS aliases sharing an actual host still
  need operator review. No operator count or
  stake distribution is selected by this tool. A validator requires a declared
  separate-host sentry peer; this checks the plan, not real firewall isolation.
- `edge`: `{hostname, tlsEmail, node, origins, mining}`. `node` names a separate
  RPC host; `origins` is a nonempty exact HTTPS-origin allowlist, no wildcard.
  `mining` contains exactly one `{node, hostname}` mapping per validator.
- `limits`: explicit integers `memoryBytes`, `cpuQuotaPercent`, `tasks`,
  `openFiles`, `httpBodyBytes`, `maxConnections`, `rpcTimeoutSeconds`; plus
  positive integral `minimumGasPrices` ending in `agrc` and `pruning`
  (`default` or `nothing`). Validator/RPC capacity and acceptable workload still
  require operator sizing. The validator enforces finite resource bounds, not
  chosen chain economics or a throughput SLA.

DNS names, paths, IDs and references have restricted characters to prevent
shell/systemd/TOML/Caddy argument injection. Credentials in origins, URL paths,
wildcards and systemd `%`/environment expansions are rejected.

## Phase 1: original genesis, operators and controlled bootstrap

Operators must first choose the testnet IDs, topology, initial allocations and
stake, hybrid targets/retargeting/reward fraction, genesis time and reset policy.
Approve these explicitly as **testnet values**, not final mainnet tokenomics.
Review the actual pinned module defaults and record every intentional override.
The Root [`genesis/allocations.json`](../../genesis/README.md) is an economic
working model, not an automatically approved public-testnet allocation.

Each operator provisions its own private home/key storage. Use the pinned node's
`init`, `genesis add-genesis-account`, `genesis gentx` and `genesis collect-gentxs`
workflow in operator-controlled storage; exchange only public records and signed
gentxs. **Do not run `grc-devnet.sh`, `grc-hybrid-devnet.sh` or `testnet init-files`
as a public installer**: the development harnesses contain public account keys
or emit local key-seed files. Never pass `--recover` a fixture mnemonic.
Never distribute one live validator key/state pair to two signing processes.

Before accepting the public genesis, operators separately run these existing
commands against the original file and an explicit private node home:

```sh
/approved/grcd genesis validate-genesis --home /private/operator-node
sha256sum /private/operator-node/config/genesis.json
/approved/grcd genesis hybrid-fingerprint \
  /private/operator-node/config/genesis.json --home /private/operator-node
```

The fingerprint command uses Go RawMessage compaction/HTML escaping of the
original `app_state`. It is not the whole-file SHA and must not be recomputed
through JavaScript number parsing or sorted JSON. The renderer checks file
hashes and selected genesis/Hybrid/validator bindings; **it does not execute full
module validation or recompute this fingerprint**. It supports fresh height-one
genutil genesis with an empty Comet validator list, including the SDK `consensus`
envelope and legacy `consensus_params`; exported running Hybrid state is refused.

Review concrete bootstrap output before installation. Per-node files go to the
declared host only: `config.toml`, `app.toml`, exact `genesis.json`, `inputs.sha256`,
`grcd.service`, both operator-preflight modules and the exact public deployment
plan. Units use separate `grc-<node>` accounts and private `0700` homes
`/var/lib/grc-testnet/<node>`. The operator must provision Node.js 24+ at
`/usr/bin/node`, accounts, files and permissions; **nothing is installed, enabled
or started here**. Copy the checksum file, both modules and public plan to the
root-controlled `/etc/grc-testnet/<node>/` directory as documented in the
[operator-file preflight](docs/operator-preflight.md). At eventual start,
`sha256sum --check` binds binary, genesis, helper modules and exact plan bytes.
The read-only preflight then checks private file ownership/permissions, internal
Ed25519 key consistency, declared node/validator identity and the stored state
signature. It never generates keys or resets state. It does not prove state
height/round/step or chain binding, freshness, signer exclusivity or safe restore.
Retain the Chain [LICENSE](../../chain/LICENSE) and [NOTICE](../../chain/NOTICE)
with any later binary distribution.

The Node templates keep Comet/EVM/WS/mining on loopback, disable REST/gRPC,
insecure unlocking, unprotected transactions, profiling and unsafe CORS, and
restrict EVM namespaces to `eth,net,web3`. Only declared P2P listeners bind
publicly. Persistent peers and validator privacy settings still need real
firewall/host verification. Do not replace a live config blindly with a partial
fresh-node template: remaining pinned Comet/SDK defaults require review.

`edges/rpc.Caddyfile` belongs on the RPC host; it forwards only POST `/` with
an exact browser-origin policy. WebSocket, Comet/REST/gRPC and admin routes are
not forwarded. `edges/mining-<validator>.Caddyfile` belongs on that validator's
host and forwards only the actual status/template/proof routes to its loopback
API. A remotely terminated mining ingress needs a **separately reviewed,
authenticated tunnel**; do not substitute an RPC fullnode or claim a pool/gateway.
Direct validator HTTPS ingress affects its exposure and must be reviewed before
launch. The [ingress limits](ingress-limits.md) bind client header/body/write/idle
and upstream dial/header/read/write durations to the explicit plan value.
Connection caps apply per upstream, not per client or globally. Caddy TLS/DNS,
expiry timing, per-client quotas/DDoS handling, firewall rules and actual service
behaviour remain host acceptance work. These templates claim no rate limiter or
public-operation pass.

Bootstrap work must reach the actual validator/proposer APIs. The existing miner
accepts explicit `--api`, `--chain-id`, `--genesis-hash`, `--payout`, `--cpu-percent`
and bounded `--duration`; starting it is a later deliberate operator action.
`/v1/mining/template` can return 204 between rounds and status can be 503 before
committed state. HTTP reachability alone does not establish blocks or finality.

## Phase 2: independent positive anchor and client builds

After actual PoW and stake commitment, independently review a **positive** EVM
height/hash against trusted operator/Comet observations; never trust the same
unapproved RPC to invent its expected identity. Approve the original genesis SHA,
fingerprint, Cosmos/EVM IDs and anchor together and record the public review.
Then provide the exact `grc-network-identity/v1` file and its SHA in an `anchored`
manifest. The shared protocol normalizer checks its schema and the renderer
compares its bindings; neither proves operator quorum, RPC honesty or finality.

The pinned Wallet core and build loader derive the EVM ID from the same approved
identity, preserving its canonical decimal string and using bigint for signing.
Positive uint64 IDs are supported; this tool continues to reject development ID
`42801` for a public-testnet manifest. An anchored strict render copies the exact
approved identity bytes and reports `clientBuildsRequired: true`. It neither
chooses a public ID nor builds or accepts a wallet package.

Rebuild all wallet targets with `GRC_NETWORK_IDENTITY_FILE` and its independently
approved `GRC_NETWORK_IDENTITY_SHA256`; do not relabel the current four packages,
which embed an older Core and stopped local-fixture identity. Explorer and
Marketplace also need approved identity/configuration and actual contract
deployment addresses. The reward-relayer server still needs separate approved
network/anchor and persistent-budget configuration before public use; client
support alone does not prepare that operator service. Cologna/klick-game
integrate later through the existing API.

For subsequent actual operation, configure the existing
[read-only health checker](../../docs/chain-health.md) with the approved IDs,
fingerprint, endpoints and deliberately selected thresholds. Plan monitoring,
alerts, backing up genesis/config and secure operator key recovery. Preserve
validator signing state monotonically; a stale restore or simultaneous signer
can double-sign. No recovery or automatic key/state reset is implemented here.

## Offline validation and remaining acceptance

```sh
node --test deploy/public-testnet/test/public-testnet.test.mjs
npm run test:public-testnet:sources
```

The Node suite uses private synthetic workspace/source-pin fixtures and a named
protocol API double so Root-only CI does not require private component checkouts.
It exercises real CLI processes and actual file/no-clobber boundaries, not a
network or validator. Shared wire-schema conformance and the real selected source graph
are separate scopes. The `test:public-testnet:sources` suite requires the complete
checkout: it verifies the actual selected source hashes and component revisions
against `workspace-lock.json`, renders/verifies the shipped unapproved proposal,
and confirms that strict mode creates no output for that proposal. It runs in
the full-workspace applications CI job; no missing checkout is silently skipped.
When integrating reviewed component changes, refresh the relevant source hashes
and commit pins together. `rootBaselineCommit` identifies the integration base
for that refresh; it is not the commit containing `source-pins.json` itself.
A complete
offline bundle is not proof of a binary's provenance, a valid signed gentx,
operator approval, TLS/firewall isolation, native wallet compatibility, successful
bootstrap, persistent operation or a launched public testnet.
