igneum/packaging/README-ship.md
igneum-labs 7eed16a29a Pre-public scrub, the text pass (7 October 2026, 19:5x UK): no founder name, personal login, earlier business or personal address in any tracked text file, and a gate check that keeps it so
The sweep (main's item 1): 199 tracked text files, 783 lines. The founder's full name, first name and possessive become "the founder" (sentence starts capitalised); the lowercase operating-system user name in WSL paths and commands becomes <user>; the second owner login becomes "the second owner login"; the three earlier businesses and the two other brands become "the other business", "the earlier entity", "the earlier business" and "another brand"; the Chrome profile rule names the igneum.network profile, not the profile's label. The standing commit login igneum-labs is not a founder term here: the fresh-repository step renames it in the history (docs/plans/history-rewrite.md, tools/repo/fresh-repo.sh).

The patterns never appear in plain text in the tree (a plaintext list would be the hit): tools/ci/founder-strings.b64 (perl regex, tab, a sample per row) is read by tools/ci/founder-strings-check.sh (every tracked text file, perl, known-failed first: the self-test plants each row's sample in a fixture and the hit must name the file), by tools/community/discord-hooks.mjs (the guard's founder and business rows; the test takes its fixtures from the samples) and by tools/repo/fresh-repo.sh (the business names of the rewrite rules). site/forbidden-strings.txt carries the same patterns as b64: lines, decoded case-insensitive by site/scrub.mjs and tools/ci/launch-gates-check.mjs (whose fixture now plants an encoded made-up name). The check runs in the gate's tree checks on every merge.

Not in this commit, by main's word: the 105 commit messages and 40 personal-identity commits that need the history rewrite (listed, not run), and the secrets found by gitleaks over the history (reported with owners).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-07 18:39:50 +00:00

127 lines
10 KiB
Markdown

# Shipping an Igneum Miner version (packaging/README-ship.md)
One command cuts a version for both platforms. 4 October 2026: 0.3.1, 0.3.2 and 0.3.3 each took eight hand steps and
an hour; `tools/ship-app.mjs` is those steps in order, each one checked and resumable.
node tools/ship-app.mjs 0.3.4 --node vendor/igneum-node-v4 --notes "one line for the changelog"
Add `--dry-run` first: it reads everything, prints the plan and writes nothing.
## What it does
| Step | What happens | Skips itself when |
|---|---|---|
| preflight | this tree clean and on master, the fork worktree clean (`--node-commit <sha>` pins it), tools, binaries, secrets present, gh account, what is live | never (reads only) |
| bump | the six version files, written by one function and read back | the files already say the version |
| inputs | `packaging/windows/push-inputs.sh` with the fork's Windows exes (`IGNEUM_WIN_RELEASE`, `IGNEUM_NODE_SRC`) | the live `payload-inputs.json` carries these exact files from this fork commit |
| commit | `Igneum Miner <v>: <notes>`, push master (the push starts the Windows build) | committed and on origin/master |
| ci | the `windows.yml` run for that commit (dispatched when the push started none), polled every 30 s | a green run for the commit exists |
| fetch | `packaging/windows/fetch-ci-artifacts.sh <run>`: installer and payload zip into the downloads folder | the installer from that run is there |
| dmg | `packaging/mac/build-dmg.sh` under `tools/lock/with-lock.sh build` | the DMG is newer than the bump (`--rebuild` forces) |
| copy | the DMG into the downloads folder | same sha256 already there |
| manifest | `packaging/ota/publish-manifest.sh --no-deploy`: signed, signature verified locally | never (cheap) |
| deploy | the downloads folder, one Vercel deploy for the files and the manifest together | never |
| verify | HEAD and GET of the DMG, the installer and the zip (size and sha256 against the local copies); the live manifest through `igneum-ota-sign verify` | never |
| console | one `build` item on the console (version, sizes, hashes, run, commit), then `sync-dl` | never (upsert on `ship:<v>`) |
The six version files: `app/igneum-app/Cargo.toml`, `app/igneum-app/Cargo.lock`, `app/windows/version.h`,
`app/igneum-app/resources/igneum-app.rc`, `packaging/windows/Igneum-Miner.iss`, `packaging/mac/app/Info.plist`.
`node tools/ship-app.mjs --check` says whether they agree; `--self-test` runs the bump on a scratch copy.
## Flags
| Flag | Meaning |
|---|---|
| `--node <dir>` | the igneum-node worktree the node and miner were built from (required); binaries from its `target-integration/`, else `target/` |
| `--notes "..."` | the manifest's changelog line and the commit message |
| `--dry-run` | reads only, prints the plan (exit 1 when preflight would stop the real run) |
| `--from <step>` | resume at that step (preflight runs again first); the failure message prints this command |
| `--skip-windows`, `--skip-mac` | one platform only (the other entry is carried over when the live manifest is the same version) |
| `--node-commit <sha>` | the fork must be on this commit |
| `--win-release <dir>`, `--mac-release <dir>` | other binary folders |
| `--min-supported`, `--activation-height`, `--deadline-note`, `--channel` | passed to `publish-manifest.sh` |
| `--rebuild` | build the DMG again even when a fresh one exists |
| `--branch <name>` | accept another branch than master (a dry run from a worktree; the Windows build still runs on pushes to master) |
| `--public` | the manifest step also publishes the version into `dl/public/` (no token in any URL; its own signed manifest; the `/public/` aliases rewritten), the same deploy carries it, verify checks every public file and alias. The token folders are untouched |
## The public downloads path (5 October 2026, testnet launch)
`dl/public/` in the downloads folder holds only the current installers, the HiveOS package and the two signed manifests
(app and wallet) with URLs under `https://dl.igneum.network/dl/public/`, plus an unsigned index `igneum-downloads.json`
that the site build reads. Four stable aliases are rewrites in the downloads folder's `vercel.json`, written from what the
folder holds, so they follow every release by themselves:
| Alias | Rewrites to |
|---|---|
| `https://dl.igneum.network/public/igneum-miner-windows.exe` | `dl/public/Igneum-Miner-Setup-<v>.exe` |
| `https://dl.igneum.network/public/igneum-miner-mac.dmg` | `dl/public/Igneum-Miner-<v>.dmg` |
| `https://dl.igneum.network/public/igneum-miner-hive.tar.gz` | `dl/public/igneum-hive-<v>.tar.gz` |
| `https://dl.igneum.network/public/igneum-wallet-mac.dmg` | `dl/public/Igneum-Wallet-<v>.dmg` |
`packaging/ota/publish-public.sh --app | --wallet | --hive <tar.gz> [--deploy] [--verify] [--dry-run]` does the work;
`publish-manifest.sh --public` and `ship-app.mjs --public` call it, so every future release lands there too. The
HiveOS package comes from `packaging/hive/make-hive-package.sh` (Linux node and miner from a PC `build` job, the two GPU
workers from `infra/cross/build-workers-linux.sh`) and is published with `--hive`. The site (`site/build.mjs`) reads the
index at build time and stamps every download button with the version and size; `TESTNET_OPEN` there removes the
"Public testnet: not yet open" line on the go.
## When a step fails
The tool stops, prints why and the `--from` command to retry. Nothing is skipped silently. State that is not a secret
(commit, run id, bump time, the hashes) is in `~/.cache/igneum/ship/<version>.json`.
Secrets come from `~/.config/igneum` (dl-token, dlsite-dir, ota-signing-key, relay token and key, the Vercel login) and are
never printed; every output line is scrubbed. `gh auth switch --user igneum-labs` runs before every gh call and before the
push.
## What a cut needs before it starts
- The node fork built for both targets in `--node`: `target-integration/release/{igneumd,igneum-miner}` and
`target-integration/x86_64-pc-windows-gnu/release/{igneumd,igneum-miner}.exe` (`proto-cuda/windows-node/cross-build.sh`).
- The prebuilt workers (`proto-cuda/nvrtc/igneum-worker-cuda.exe`, `proto-opencl/igneum-worker-opencl.exe`) and the prover
(`proving/igneum-prove/target/release/igneum-prove-{host,export}`); missing ones are noted, not fatal.
- The Mac on mains, nothing else building (the DMG step waits for the build lock).
## The site project on Vercel (4 October 2026, checked by hand)
Two Vercel projects are called `igneum`, in two teams, and the link file under `site/.vercel` points at the wrong one:
| Team | Login (global config) | Project | Holds | Deploys |
|---|---|---|---|---|
| `igneum` | `igneum-labs` (`~/.config/igneum/vercel`) | `igneum` (`prj_HcNO2NLY4jkhikmLMugpJ8nLcWNW`, root directory `site`, build `node build.mjs`) | `igneum.network`, `igneum.com`; env `DATABASE_URL`, `LOG_INTAKE_KEY` | GitHub integration: every push to master is a production deploy, every branch push a preview (`igneum-git-<branch>-igneum.vercel.app`) |
| `other-business` | `<user>-4826` (the default `~/.vercel`) | `igneum` (`prj_y5lQg3C87fXAgoj3vug6iwWU3KwV`, same settings) | the 13 redirect domains (`igneum.app`, `.art`, `.co.uk`, `.email`, `.info`, `.io`, `.net`, `.online`, `.org`, `.pro`, `.shop`, `.store`, `.vip`, `.xyz`) | nothing live |
So `vercel env add` from `site/` fails with "Could not retrieve Project Settings" under the igneum login (the link file names
the other business's project, which that login cannot read), and would silently add the value to the wrong project under the default
login. The working commands, from `site/` in the shared checkout (the link step rewrites `site/.vercel/project.json`, which
is ignored by git):
cd site
npx --yes vercel@latest --global-config ~/.config/igneum/vercel link --scope igneum --project igneum --yes
npx --yes vercel@latest --global-config ~/.config/igneum/vercel env ls --scope igneum # names only
npx --yes vercel@latest --global-config ~/.config/igneum/vercel env add LOG_INTAKE_KEY_NEXT production --scope igneum
A production deploy by hand is `npx --yes vercel@latest --global-config ~/.config/igneum/vercel deploy --prod --yes --scope igneum`
from the repository root (the project's root directory is `site`), but the normal path is a push to master. The relay
(`igneum-relay`) and the downloads folder (`igneum-dl`) are the other two projects in the `igneum` team; both deploy by CLI
from their own folders (`relay/README.md`, `packaging/ota/README.md`). CLAUDE.md still says the site sits in the the other business
team and deploys with `--scope the other business` from `site/`: that was true on 3 October and is not now.
## Job scripts (5 October 2026, the lost-quote class)
A bash body in a PowerShell job (`relay/playbooks/*.ps1`, `tools/**/*.ps1`) is written to a file and run with
`bash <file>`, never inline. That is the 0.3.6 cut's rule. Twice on 5 October a body travelled inside a PowerShell
string, a quote was lost on the way through PowerShell, bash refused the whole body, and the job either reported exit 0
having done nothing (`tools/amd-prove/pc1-cpu-prove.ps1`, first version: an apostrophe inside a single-quoted awk
program) or failed in 4 s (the 0.3.10 installer job). The file shape keeps the body readable by `bash -n` before it runs;
`pc1-cpu-prove.ps1` does that in the job itself. `tools/ci/bash-body-check.sh` fails CI on an inline body that does not
parse: it finds every body handed to bash (`bash -c "..."`, `bash -lc $var`, a `+` concatenation, a here-string written to a
file and run), unescapes it the way PowerShell would, and runs `bash -n` on it. A body it sees but cannot read fails too.
`--self-test` shows it firing on the fixtures under `tools/ci/fixtures/`. A job script is published from a worktree and
never passes CI before it runs, so `packaging/ota/publish-jobs.sh add --kind run` runs the same check (and
`tools/ci/prover-socket-check.sh`, the root-socket class; `bash -n` for a `.sh` script) on the script before anything is
signed, and refuses the publish with the check's output. `packaging/ota/test-publish-jobs.sh` proves the refusals.
The wiped-jobs-folder class (5 October 2026, 21:49Z): an app install clears the jobs folder, so a run job that uses a kit
fetched by an earlier fetch job tests the kit is there (Test-Path on the kit root or any file under it) before its first
use, and the fetch is republished under a new id after any app update. `tools/ci/kit-path-check.sh` fails CI and the
publish on a kit path used before that check.