Skip to content

feat(staging): run three Piris on the shared disk - #171

Merged
bajtos merged 1 commit into
mainfrom
miroslav/fil-1503-staging
Oct 20, 2026
Merged

bajtos merged 1 commit into
mainfrom
miroslav/fil-1503-staging

Conversation

@bajtos

@bajtos bajtos commented Oct 15, 2026 •

Copy link
Copy Markdown
Member

Written by Claude.

Move staging to piri-0, piri-1 and piri-2 behind its one Ingot, as dev runs them, at piri-<n>.eu-central-3.staging.fil-forge.com.

The bare-metal host keeps one data disk, so each Piri gets a directory on it, /mnt/data/fil-one/data/piri-<n>, and a loopback port, 15100 to 15102. A volume per Piri needs the host reconfigured and is left for later.

The host Caddy snippet, the DNS records and postgres-init follow the same names. The host Caddy reload and the host Alloy edits are manual.

Migrating the staging node

This PR merges in the middle of the migration, after the node and central are reset and every Piri is onboarded. If it merged earlier, the reconcile timer would start three Piris with no keys and no onboarding. Dev moved the same way on 2026-10-16, in #170.

The node loses its Ingot and Piri databases and data. Central's staging stage loses its providers, tenants and Piri DIDs. These stay:

  • OpenBao and the unseal token;
  • every key and wallet;
  • hilt's delegation to Ingot.

The existing Piri keeps its DID and funded wallet as piri-0. Its old on-chain data set faults and is left to fault, stranding about 0.9 USDFC of the payer's lockup. The node takes no uploads from step 1 to step 10, and the smoke test alerts in that window.

Commands run in four places:

  • the staging host: ssh root@23.83.66.244, then cd /root/fil-one/infra-nodes. The login shell is Fish, and every command below works in it.
  • an infra-central checkout on main, with the filone-sandbox AWS profile.
  • an infra-nodes checkout, with the same profile.
  • a fil-one checkout, with credentials for FilOne's AWS account.

Before the window

This procedure assumes two infra-central changes have landed:

Then, before the window:

  • Merge the open infra-central staging promotion, Promote dev's images to staging infra-central#247 or whatever replaced it. Its apply brings #264's Hilt settings to staging.
  • After that, merge no other infra-central staging promotion until step 10. Each one applies terraform/envs/staging/apps, which sets every service's desired count back to 1 and can bring a service up while step 2 has it at zero. Pushes to infra-central's main apply only dev and can go ahead.
  • Merge Promote dev's images to staging #176, the infra-nodes staging promotion, or whichever version of it is open. Staging pins piri sha256:1e91500 and ingot sha256:f629535, while dev runs the three-Piri layout on piri sha256:7feed0e and ingot sha256:1ef08c4. Promoting first makes staging's first three-Piri deploy run digests already proven on that layout. Hold any later promotion until step 10.
  • Mark this PR ready: gh pr ready 171 --repo fil-forge/infra-nodes.
  • Leave dev's image bumps running. They pin dev only, and step 1 stops staging's timer.
  • Tell #filone-alerts that eu-central-3 is down for the window.

1. Reset the node (staging host)

git fetch origin
git checkout --detach origin/main
systemctl stop filone-reconcile.timer
scripts/host/reset-apps.sh

Check the plan it prints before you type reset-staging. It should list the containers filone-piri and filone-ingot, the databases piri and ingot, and data directories under /mnt/data/fil-one/data. The script ends with "apps reset; they stay stopped". Skip its "Next" line, which is for a plain reset.

2. Reset central (infra-central)

make reset-apps STAGE=staging

It asks for reset-staging. Emptying sprue's agent-message and delegation buckets takes minutes, and the script prints a running count while it does (fil-forge/infra-central#262). It ends with Done. once every service is back up. Skip its "Next" line too.

3. DNS (infra-nodes, on this branch)

git fetch origin
git checkout --detach origin/miroslav/fil-1503-staging
tofu -chdir=terraform/envs/staging/eu-central-3 init
tofu -chdir=terraform/envs/staging/eu-central-3 plan

The plan should create three A records, piri-0 to piri-2.eu-central-3.staging.fil-forge.com, all pointing at 23.83.66.244. It should destroy piri-0.staging.fil-forge.com and change nothing else. Then apply it and check that each name resolves:

tofu -chdir=terraform/envs/staging/eu-central-3 apply
dig +short piri-0.eu-central-3.staging.fil-forge.com
dig +short piri-1.eu-central-3.staging.fil-forge.com
dig +short piri-2.eu-central-3.staging.fil-forge.com

4. Keys (staging host, on this branch)

git fetch origin
git checkout --detach origin/miroslav/fil-1503-staging
install -d -m 0755 /mnt/data/fil-one/data/piri-0 /mnt/data/fil-one/data/piri-1 /mnt/data/fil-one/data/piri-2
scripts/host/keygen.sh

The host was bootstrapped with one piri directory, so the install -d creates the three new ones. keygen.sh must report that it copied OpenBao path piri to piri-0 and generated piri-1 and piri-2. If it generates a new piri-0 instead, stop: piri-0 would get a new DID and an unfunded wallet.

5. Host Caddy (staging host)

The host owns Caddy. Its /root/storacha/caddy/Caddyfile imports this node's snippet from the checkout. On this branch the snippet serves the three new Piri hostnames on ports 15100 to 15102 and no longer serves piri-0.staging.fil-forge.com. With the timer stopped, nothing reloads Caddy on its own, so reload it by hand.

First check that the import still points at the checkout:

grep -n 'infra-nodes/nodes' /root/storacha/caddy/Caddyfile

Then check that nothing else in the host's file names the old hostname:

grep -n 'piri-0.staging.fil-forge.com' /root/storacha/caddy/Caddyfile

Change any match from the second grep to the new hostnames, then validate and reload:

scripts/host/reload-staging-host-caddy.sh

The script validates the combined configuration before it reloads caddy-guppy, so a broken edit stops there rather than taking down the host's other sites. Caddy then requests certificates for the three new names, which needs step 3's DNS to resolve. Each name should serve the status document over HTTPS with HTTP 200, even before its Piri runs:

curl -sS -o /dev/null -w '%{http_code}\n' https://piri-0.eu-central-3.staging.fil-forge.com/.well-known/filone-node-status.json

Repeat for piri-1 and piri-2. A TLS error means Caddy has no certificate for that name yet.

6. Host Alloy (staging host)

Make the three edits to /etc/alloy/config.alloy that the RUNBOOK's "The eu-central-3 staging appliance on Servers.com" shows:

  • Docker logs: the rule that sets instance from filone-apps;(piri-[0-9]+);
  • prometheus.relabel "host_caddy": the host regex piri-[0-9]+\.eu-central-3\.staging\.fil-forge\.com;
  • prometheus.relabel "filone_forge": the rule that maps Piri's service.instance.id to instance.

Then validate and restart:

alloy validate /etc/alloy/config.alloy
systemctl restart alloy

Restart rather than reload: Alloy v1.17 keeps the Docker log tailers, and their old labels, across a reload.

7. Onboarding and wallets (staging host, then infra-central)

scripts/host/onboarding-request.sh

It prints three make onboard-appliance STAGE=staging REGION=eu-central-3 … commands and the three owner wallet addresses. Run the three commands in infra-central. Each run logs "returning the delegation issued earlier". All three write the same ingot-proof.txt, which is hilt's delegation to the region's one Ingot. The node still holds it, so there is nothing to store with store-hilt-proof.sh.

Each Piri's first start registers it on chain and spends 5 tFIL from its own wallet. Before step 10, look up each address on a Calibration block explorer. Any wallet holding less than 6 tFIL needs funding from a faucet.

8. FilOne's tenants (fil-one)

Run the dry run first:

node bin/reset-region-provisioning.ts --stage staging --region eu-central-3 --dry-run

Then the real run, typing yes at the prompt:

node bin/reset-region-provisioning.ts --stage staging --region eu-central-3

Every non-production FilOne stage offers eu-central-3. Repeat for any personal or preview stage that has tenants there.

9. Merge (infra-nodes, the stack's checkout)

gh stack merge 172 --yes --squash

This merges this PR and #172.

10. First deploy (staging host)

git fetch origin
git checkout --detach origin/main
scripts/host/deploy-platform.sh
scripts/host/provision-apps.sh
systemctl start filone-reconcile.timer

deploy-platform.sh runs postgres-init, which creates piri_0 to piri_2. provision-apps.sh removes the old filone-piri container and starts the Piris one after another. It prints their logs, prefixed piri-<n> |, while each first start runs piri init, registers on chain and creates a proof set. That takes minutes per Piri, and a 403 means that Piri's onboarding didn't complete. The script ends with acceptance checks for OpenBao, the three Piris' /readyz, Ingot's /health, and every hostname's certificate and status document. The timer is still enabled from before, so start is enough, and its first pass should report "nothing to deploy".

11. Verify

  • Node: on the host, run scripts/ci/smoke-test.sh staging/eu-central-3 and systemctl list-timers | grep filone.

  • Central: in infra-central, run make smoke STAGE=staging.

  • End to end: from a checkout of Test each node end to end after its smoke test #154 until it merges, load the partner key into the shell without printing it, run the test, clean up, and drop the key:

    export HILT_PARTNER_KEY="$(AWS_REGION=us-east-2 aws ssm get-parameter --name /forge-central/staging/hilt/partner-key --with-decryption --query Parameter.Value --output text)"
    E2E_RUN_ID=migration-1 scripts/ci/e2e-test.sh staging/eu-central-3
    E2E_RUN_ID=migration-1 scripts/ci/e2e-test.sh staging/eu-central-3 --cleanup
    unset HILT_PARTNER_KEY

    On dev, the final tenant delete in --cleanup failed with HTTP 500. Hilt on dev and staging has no revocation settings, so it sent revocations to prod's Swarf, which answered 404. Point Hilt's revocations at its own stage's Swarf infra-central#264 fixes that, and it reaches staging with the promotion merged before the window.

  • Logs: in Grafana, {service_name="appliance-staging-eu-central-3-piri"} |= "/blob/accept" should show the test's blobs under instance values staging/eu-central-3/piri-0 to piri-2. That also confirms step 6's Alloy edits.

  • FilOne: run gh workflow run e2e-staging.yaml --repo fil-one/fil-one.

  • Proofs: over the next day, each Piri should submit its first proof for its new proof set.

12. Clean up (staging host)

reset-apps.sh recreated an empty piri database, which the new layout doesn't use. Confirm it has no tables:

docker exec filone-platform-postgres-1 psql -U admin -d piri -c '\dt'

If it reports no relations, drop it and remove the old data directory. rmdir refuses a directory that isn't empty.

docker exec filone-platform-postgres-1 psql -U admin -d admin -c 'DROP DATABASE piri'
rmdir /mnt/data/fil-one/data/piri

Refs FIL-1503

@bajtos
bajtos added this pull request to stack #173 October 15, 2026 16:07
@bajtos
bajtos force-pushed the miroslav/fil-1503-staging branch from 918e46e to e9d96c8 Compare October 16, 2026 06:01
@bajtos
bajtos force-pushed the miroslav/fil-1503-staging branch from e9d96c8 to 1473855 Compare October 16, 2026 06:17
@bajtos
bajtos force-pushed the miroslav/fil-1503-staging branch from 1473855 to cfa4492 Compare October 16, 2026 06:34
@bajtos
bajtos force-pushed the miroslav/fil-1503-staging branch 2 times, most recently from b12d003 to 270c42f Compare October 16, 2026 13:33
@bajtos
bajtos force-pushed the miroslav/fil-1503-staging branch from 270c42f to 63da28f Compare October 16, 2026 13:41
@bajtos
bajtos force-pushed the miroslav/fil-1503-staging branch from 63da28f to 364005c Compare October 16, 2026 14:25
@bajtos
bajtos force-pushed the miroslav/fil-1503-staging branch from 364005c to 3dfd5ed Compare October 16, 2026 14:32
@bajtos
bajtos force-pushed the miroslav/fil-1503-staging branch from 3dfd5ed to 57d77b4 Compare October 16, 2026 14:42
@bajtos
bajtos force-pushed the miroslav/fil-1503-staging branch from 57d77b4 to 62ef536 Compare October 16, 2026 14:43
Base automatically changed from miroslav/fil-1503-dev to main October 16, 2026 15:22
@bajtos
bajtos force-pushed the miroslav/fil-1503-staging branch from 62ef536 to 114a9e3 Compare October 16, 2026 15:22
@bajtos
bajtos marked this pull request as ready for review October 20, 2026 10:04
Copilot AI balanced review requested due to automatic review settings October 20, 2026 10:04
Move staging to piri-0, piri-1 and piri-2 behind its one Ingot, as
dev runs them, at piri-<n>.eu-central-3.staging.fil-forge.com.

The bare-metal host keeps one data disk, so each Piri gets a
directory on it, /mnt/data/fil-one/data/piri-<n>, and a loopback
port, 15100 to 15102. A volume per Piri needs the host reconfigured
and is left for later.

The host Caddy snippet, the DNS records and postgres-init follow the
same names; the host Alloy edits are manual and documented in the
runbook.

Refs FIL-1503

Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Miroslav Bajtoš <oss@bajtos.net>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-20T10:12:06.047013Z 114a9e3 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@bajtos
bajtos force-pushed the miroslav/fil-1503-staging branch from 114a9e3 to 6f217f3 Compare October 20, 2026 10:04
@bajtos
bajtos merged commit b7ed531 into main Oct 20, 2026
5 checks passed
@bajtos
bajtos deleted the miroslav/fil-1503-staging branch October 20, 2026 10:08

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Although the committed diff is clean and consistent, it is one step of a coordinated live staging migration involving DNS teardown/recreate, a Postgres database-layout change, on-chain wallet implications, and manual multi-repo/host steps that warrant human sign-off.

No open issues 🎉

What changed in this PR

This PR moves the staging eu-central-3 bare-metal appliance from a single Piri to three (piri-0, piri-1, piri-2) behind its one Ingot, mirroring the layout dev already adopted in #170. Because the host keeps a single data disk, each Piri gets a directory under /mnt/data/fil-one/data/piri-<n> and a loopback port (15100–15102) rather than a dedicated volume. The committed changes are the declarative pieces of a larger, carefully ordered live migration (the manual host Caddy/Alloy edits and docs land out-of-band, per the PR description and #172).

Changes:

  • Define three Piri services from a shared x-piri-base anchor, each with its own hostname, loopback port, Postgres database (piri_0..2), key/wallet, data directory, and service.instance.id OTEL attribute; start them one-at-a-time via depends_on.
  • Serve each Piri hostname through a new (filone-piri) host-Caddy snippet, create per-Piri DNS A records (piri-<n>.eu-central-3.staging.fil-forge.com), and split postgres-init into ensure_role/ensure_database to create one role and three databases.
  • Update node.env to a PIRI_HOSTNAME_SUFFIX (dropping PIRI_HOSTNAME/PIRI_PUBLIC_URL) and provision three per-Piri data directories at bootstrap.
File Description
terraform/​envs/​staging/​eu-central-3/​main.tf Replaces the single piri A record with a for_each creating piri-0..2.eu-central-3.staging.fil-forge.com.
scripts/​host/​bootstrap-staging-eu-central-3.sh Creates piri-0/1/2 data directories instead of a single piri directory.
nodes/​staging/​eu-central-3/​platform/​config/​caddy/​host-caddy.caddy Adds a reusable (filone-piri) snippet and routes three hostnames to ports 15100–15102.
nodes/​staging/​eu-central-3/​platform/​compose.yml Splits postgres-init into role/database helpers and creates piri_0..2 for the one piri role.
nodes/​staging/​eu-central-3/​node.env Switches to PIRI_HOSTNAME_SUFFIX, removing PIRI_HOSTNAME/PIRI_PUBLIC_URL.
nodes/​staging/​eu-central-3/​apps/​compose.yml Defines piri-0/1/2 from a shared base anchor with per-Piri port, URL, DB, secrets, data dir, and OTEL instance id.

I verified the changes are internally consistent (ports, hostnames, databases, and data directories all align across the six files), that the removed PIRI_HOSTNAME/PIRI_PUBLIC_URL are only consumed as fallbacks when PIRI_HOSTNAME_SUFFIX is unset (scripts/host/lib.sh, scripts/ci/smoke-test.sh, .github/workflows/smoke.yml), that ${FILONE_NODE} is defined in node.env, that the {args[0]} snippet syntax matches the existing dev Caddyfile convention, and that the smoke test auto-enumerates all three Piris. The diff faithfully follows the already-merged dev pattern (#170), and I found no concrete code defects to comment on.

Review effort: Balanced

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 114a9e3801

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Peeja added a commit that referenced this pull request Oct 20, 2026
Staging now runs three Piris (#171), which share their environment
through an x-piri-base anchor. PIRI_INIT_TIMEOUT moves into that
anchor, as on dev, so every staging Piri gets it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Petra Jaros <petra@fil.org>
Claude-Session: https://claude.ai/code/session_01JCF8gyb8jNRmHmWqQmVhRJ
Peeja added a commit that referenced this pull request Oct 20, 2026
Staging has run three Piris since #171, so the decommission hint and the
retry recipe's staging note no longer name a single `filone-piri`
container, `piri` service and `data/piri/` directory.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Petra Jaros <petra@fil.org>
Claude-Session: https://claude.ai/code/session_01JCF8gyb8jNRmHmWqQmVhRJ
Peeja added a commit that referenced this pull request Oct 20, 2026
Since #171, staging runs filone-piri-0 to filone-piri-2 with databases
piri_0 to piri_2, like dev, so the note on which Piri to check applies
to both.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Petra Jaros <petra@fil.org>
Claude-Session: https://claude.ai/code/session_01JCF8gyb8jNRmHmWqQmVhRJ
Peeja added a commit that referenced this pull request Oct 23, 2026
* Add a runbook section for each Piri proving alert

infra-central's proving rules now link here, one section each. Each
section says how soon to act and why: the chain-head rules within about
three hours, before AddRoots strands its batches (FIL-1508), with the
query that finds and frees them; "proving is failing" now, before the
fifth rejection ends the proof set; the rest within a day, since they
cost about one proving period's payment a day and catch up once fixed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Petra Jaros <petra@fil.org>
Claude-Session: https://claude.ai/code/session_01JCF8gyb8jNRmHmWqQmVhRJ

* Address review: wallet case, retry sums, batch count, restart command

- The warning sections say how an AddRoots failure with a moving head,
  such as an empty wallet, can strand batches, and to check for them.
- The proving-failing section no longer offers the wallet as its fix.
- Retry totals are 3.5 and 6.9 hours.
- The stranded query counts batches as well as roots.
- Restarts name docker restart filone-piri.
- The intro no longer says all three warnings cost a period a day.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Petra Jaros <petra@fil.org>
Claude-Session: https://claude.ai/code/session_01JCF8gyb8jNRmHmWqQmVhRJ

* Say how the proving commands change with one Piri per volume

The reset script that just landed names the per-volume layout's
containers (filone-piri-N) and databases (piri_N).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Petra Jaros <petra@fil.org>
Claude-Session: https://claude.ai/code/session_01JCF8gyb8jNRmHmWqQmVhRJ

* Address round 2 nits: per-volume names, wallet funding, wrapping

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Petra Jaros <petra@fil.org>
Claude-Session: https://claude.ai/code/session_01JCF8gyb8jNRmHmWqQmVhRJ

* Name each stage's Piri containers now that dev runs three

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Petra Jaros <petra@fil.org>
Claude-Session: https://claude.ai/code/session_01JCF8gyb8jNRmHmWqQmVhRJ

* docs: staging runs three Piris in the proving runbook

Since #171, staging runs filone-piri-0 to filone-piri-2 with databases
piri_0 to piri_2, like dev, so the note on which Piri to check applies
to both.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Petra Jaros <petra@fil.org>
Claude-Session: https://claude.ai/code/session_01JCF8gyb8jNRmHmWqQmVhRJ

* docs: name each Piri by number in the proving runbook

The section used `filone-piri` and `piri` as placeholders to substitute.
Staging may still hold a database named `piri` from its single-Piri
days, so an unsubstituted psql would read and update a dead database
without an error. The commands now take the Piri's number in `n`
(`filone-piri-$n`, `piri_$n`) and fail if it is unset. The wallet checks
say each Piri has its own owner wallet, at OpenBao path `piri-$n`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Petra Jaros <petra@fil.org>
Claude-Session: https://claude.ai/code/session_01JCF8gyb8jNRmHmWqQmVhRJ

* docs: make the proving runbook's log search fail on an unset n

`docker logs filone-piri-$n 2>&1 | grep …` with n unset printed nothing:
grep swallowed docker's error, which reads like a Prove task that never
ran. It now says `${n:?}`. The wallet checks also say the path is
`piri-$n`, not the `piri` that step 6's direct lookup reads.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Petra Jaros <petra@fil.org>
Claude-Session: https://claude.ai/code/session_01JCF8gyb8jNRmHmWqQmVhRJ

* docs: keep docker's error visible in the proving log search

grep now also matches 'No such container', so a wrong `n` prints
docker's error rather than nothing. The Prove-task entry's wallet check
says to read `piri-$n` in place of step 6's `piri`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Petra Jaros <petra@fil.org>
Claude-Session: https://claude.ai/code/session_01JCF8gyb8jNRmHmWqQmVhRJ

* Point the proving runbook at Chain.Love and per-Piri wallets

main moved staging to Chain.Love (#193), so neither stage has a Lotus of
its own to check, and step 6 now reads each Piri's wallet (#172). The
chain-head entries check Piri's head and the endpoint's token instead, and
the wallet entries drop the caveat about step 6 reading `piri`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Petra Jaros <petra@fil.org>
Claude-Session: https://claude.ai/code/session_01JCF8gyb8jNRmHmWqQmVhRJ

* Read the chain head from proofset state, not piri status

`piri status` prints no chain head. `piri client pdp proofset state`
prints Current Epoch from a live ChainHead call, so the stale-head entry
compares that with an explorer, and both chain-head entries take its
"failed to get chain head" as the sign Piri cannot reach Chain.Love.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Petra Jaros <petra@fil.org>
Claude-Session: https://claude.ai/code/session_01JCF8gyb8jNRmHmWqQmVhRJ

* Pass --config to the runbook's piri commands

Inside the container `piri status` and `piri client pdp proofset state`
find no config on their own: it lives at /data/piri/piri-config.toml,
which pdp-gate.sh also passes explicitly. Also note that a Current Epoch
of 0 means an uninitialised proof set, and tidy two sentences.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Petra Jaros <petra@fil.org>
Claude-Session: https://claude.ai/code/session_01JCF8gyb8jNRmHmWqQmVhRJ

* Run the runbook's piri checks from the data directory

`docker exec -w /data/piri` lets the bare `piri status` and `piri client
pdp proofset state` in each alert entry find piri-config.toml, so an
operator who lands on an entry from an alert does not need the intro's
--config. Also name --proof-set, and say other proofset state errors are
not the chain endpoint's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Petra Jaros <petra@fil.org>
Claude-Session: https://claude.ai/code/session_01JCF8gyb8jNRmHmWqQmVhRJ

* Rewrite the Piri proving entries as steps to follow

Each entry now says how soon to act, then gives numbered steps: what
to run, how to read the result, and what to do for each outcome. The
setup shared by every entry moves to "Before you start", with a table
of the commands. Freeing stranded batches becomes its own entry, with
a count first, the update only when there is something to free, and a
recount to confirm. The six entry headings, which the alerts link to,
are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Petra Jaros <petra@fil.org>
Claude-Session: https://claude.ai/code/session_01JCF8gyb8jNRmHmWqQmVhRJ

* Fix the proving entries' dead ends and wrong turns

Review round 4 of the step rewrite:
- Drop the gas-or-funds branch under "Piri proving is failing". Curio
  counts only contract reverts there, and an underfunded owner wallet
  fails before the contract, so it never raises this alert. Say so,
  and send any revert to whoever runs infra-central, which sets up the
  data set's payments.
- "No chain head" now returns to its own steps after the token check,
  instead of following the stale-head entry's later steps, and has an
  "any other error" branch.
- The token check runs on the host, and a timeout has a branch.
- A Current Epoch of 0 points at an initialised proof set to read the
  head from, rather than straight at a restart.
- piri status reporting unhealthy also means restart, and a healthy
  status still goes on to the logs. Step 1 also checks the no-head
  alert.
- Move the log command out of the table, where copying the source
  gave a stray backslash, and keep lines within 100 columns.
- Say to keep a host terminal with n set alongside the container shell.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Petra Jaros <petra@fil.org>
Claude-Session: https://claude.ai/code/session_01JCF8gyb8jNRmHmWqQmVhRJ

* Name the Piri from the alert, and read proof set errors in one place

infra-central#270 merged, so the chain-head and Prove-task alerts now
carry the Piri's instance, and the proving alerts already carry its
proof set. Say how to get n from each, and keep "work through each
Piri" for the unrecoverable alert, which names only the node.

Review round 5 of the step rewrite:
- A working key check prints the 101 line and then curl's timeout, so
  only a missing HTTP line counts as unreachable.
- piri status makes the same call as proofset state and is never
  unhealthy when it answers. Its errors, and the "any other error"
  branches, now go to one list in Before you start that says where
  each one points: the chain endpoint, Piri's database, or the Piri
  not answering.
- A Current Epoch of 0 also covers a proof set Curio has given up on.
- The no-head entry runs only the stale entry's key check, not its
  go-to steps, and the Prove-task entry's reused step no longer names
  the other entry's step number.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Petra Jaros <petra@fil.org>
Claude-Session: https://claude.ai/code/session_01JCF8gyb8jNRmHmWqQmVhRJ

* Cut the proof-set error list to what each error tells the reader

Review round 6 found the error list routing two cases wrong:
- "no proof set found" is a database that answered without the row:
  a proof set ID from another Piri, or a data set Curio deleted. Check
  the ID against proofset list, and record a deleted data set.
- The chain branch sent readers into the stale-head entry's later
  steps from entries where no head alert is firing. Run only the key
  check, restart Piri, and return to the entry the reader came from.
Everything else is now a restart, with how long health: starting lasts,
the reboot case, and what to record if the error survives it, instead
of guessing which component failed.

Also: n=1 is now an example tied to its instance, and the loop that
finds a proof set's Piri is spelled out, with its own variable.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Petra Jaros <petra@fil.org>
Claude-Session: https://claude.ai/code/session_01JCF8gyb8jNRmHmWqQmVhRJ

* Give a restart that never becomes healthy a next step

Review round 7: Piri's healthcheck has a 180 s start period and 30
retries 10 s apart, so health: starting can last about eight minutes,
not three. A restart that ends unhealthy or keeps restarting now goes
to docker logs, where a missing file or "is a directory" means the
node rebooted. Each branch of the error list ends by saying where to
go next, a container that isn't running points at the restart, and
the proving-failing entry reads proofset state errors like the others.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Petra Jaros <petra@fil.org>
Claude-Session: https://claude.ai/code/session_01JCF8gyb8jNRmHmWqQmVhRJ

* Read the restart error, not just the logs, after a failed restart

A reboot's missing bind-mount source fails in the Docker daemon before
Piri starts, so it shows in docker restart's output and State.Error,
not in docker logs. Also name the step-4 bullet step 2 points at, and
say Docker marks the container unhealthy rather than giving up on it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Petra Jaros <petra@fil.org>
Claude-Session: https://claude.ai/code/session_01JCF8gyb8jNRmHmWqQmVhRJ

* Check the key file on the host instead of matching a mount error

Rounds 8 and 9 disagreed on the exact error a restart prints after a
reboot, and neither was run on a node. Whether piri-$n.pem is missing
or a directory on the host answers the question without depending on
Docker's wording. Also cover a container that is restarting, and send
a reader from step 2 back to step 2.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Petra Jaros <petra@fil.org>
Claude-Session: https://claude.ai/code/session_01JCF8gyb8jNRmHmWqQmVhRJ

* Guard n in the restart branch and check every tmpfs mount

With n unset, the key-file check reported the file missing and sent the
reader to a reboot fix on a node that hadn't rebooted. Guard it with
${n:?} like the other host commands, and check all three files a Piri
mounts from the tmpfs, printing only the ones missing or a directory.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Petra Jaros <petra@fil.org>
Claude-Session: https://claude.ai/code/session_01JCF8gyb8jNRmHmWqQmVhRJ

* Don't read an unset-n error as a reboot, and switch to bash on staging

The tmpfs check's verdict counted any output, so the ${n:?} error
itself would send the reader to the reboot fix. Name the line that
means a reboot, and say what to do on the unset-n error. Staging's
root shell is Fish, which can't run the section's host commands, so
step 1 now says to run bash first. Guard the remaining $n commands.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Petra Jaros <petra@fil.org>
Claude-Session: https://claude.ai/code/session_01JCF8gyb8jNRmHmWqQmVhRJ

* Put the second host terminal in bash too, and match any n error

Round 12 nits: the second host terminal on staging also opens in Fish,
and dash words the unset-n error differently from bash.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Petra Jaros <petra@fil.org>
Claude-Session: https://claude.ai/code/session_01JCF8gyb8jNRmHmWqQmVhRJ

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants