# helm ## Using atgc When doing repo operations, always use the global install of `atgc`. `atgc agent` is compiled into the binary and provides an up-to-date view of the current version's capabilities. ## Building in a worktree A fresh worktree has no `target/`, so its first build compiles the whole dependency tree before it can run a single test — and `rusqlite` builds a bundled libsqlite3, which is C and takes minutes on its own. Several agents doing that at once is what puts this machine under load. - Always `-j 2`. A full-parallel build has taken this machine down. - A worktree keeps its `target/` after the branch merges and these run to gigabytes — this one reached 3.8GB beside the main checkout's 2.2GB. Remove the worktree when the branch lands, not just the branch. ## Running the tests Most of the suite is ordinary `cargo test`. Three things are not: - The conformance and oracle tests are `#[ignore]`d and need a MegaMek install and a bridge dump: `HELM_MEGAMEK= HELM_BRIDGE= cargo test -p helm-bv --test conformance -- --ignored`. `HELM_BV_BLESS=1` re-records `conformance.txt`, and a commit that moves a figure should say why. - `tests/performance.rs` is **release only** — an unoptimised build has a different shape, not just a different speed, and is printed rather than checked. `HELM_PERF_BLESS=1` re-records `performance.txt`. - `tests/mekset_install.rs` in `helm-unitfile` resolves every design against a real release's own art: `HELM_MEGAMEK= cargo test -p helm-unitfile -- --ignored`. It is the check that says a bucket sync of the art tree is complete, so run it when the pinned MegaMek moves. - `crates/helm-wasm/smoke.mjs` drives the wasm boundary from Node, which is the only thing that exercises the interface a browser calls through. Build the module first: `cargo build -p helm-wasm --target wasm32-unknown-unknown --release`. - `crates/helm-wasm/facets.mjs` is the filtering half of the same question: `helm index --megamek --bridge-dir --out /units.json --filters crates/helm-wasm/filters.json` writes the spine, every chunk and what this build selects from them, and `node crates/helm-wasm/facets.mjs /units.json /answers.json` re-runs every filter through wasm - fetching the chunks each one reads, as a page does - and fails on any disagreement. About a second. - `crates/helm-wasm/wire.mjs` is the same boundary over the whole library rather than one design: `helm wire-check --megamek --bridge-dir --out ` writes what a page would be handed and what this build says the answers are, and the script scores every design twice - fresh and damaged - and fails on any disagreement. About 40 seconds to build the bundle and 8 to check it. Never read test fixtures out of a MegaMek install's `logs/` directory. That is MegaMek's own scratch, rewritten by anything that starts it — including `bridge/dump.sh` — so a case covered today can vanish tomorrow with nothing in this repository changing. ## Deploying `scripts/deploy.sh` builds the wasm, the index, the loadout and the catalogue and puts them in the assets bucket under `//`, then writes `releases.helm` in infra. It applies nothing — the apply is infra's, and jmm runs it. The index is a spine and seven chunks - `art`, `figures`, `paperwork`, `combat`, `curve`, `quirks`, `loadout` - and `units.json` names them all in `chunks`. `equipment.json` sits beside them: every name MegaMek answers to for every item, which is how `weapon: ["particle"]` finds a PPC without a synonym table of ours. One command writes the whole set: a prefix holding a spine and half its columns would have a page filter on a library that quietly answers a narrower question. Every one of those files carries the same `build` block and they are joined by position, so a page that mixes two prefixes is refused rather than answered. `catalogue.jsonl` has no identity of its own and is keyed only by the prefix it sits under. - A prefix is written once. Never overwrite one, and never reach for a CloudFront invalidation: a rebuild is a new ref, which is what makes the immutable cache header true. - The index and the catalogue need a bridge dump, so they need Docker. `scripts/fetch-megamek.sh` gets the release; `bridge/dump.sh` gets the dump. - A dump from anywhere else is not interchangeable. `~/.cache/mul-build` holds one from a different dumper whose catalogue is missing flags the rules read: battle value conformance against it is 29.6% rather than 99.0%, and `helm force` under-scores an Atlas by 122 points. If a figure looks wrong, check which dump produced it before reading the arithmetic. ## The firepower model `helm-core::expected` is the one opinionated figure in this repository: what a design can expect to *land*, not what it can throw. It weights MegaMek's own per-weapon averages by how often each weapon hits a gunnery 4 crew's target on open ground with nothing moving. - The rules in it are tables - `WEAPON_MODIFIERS`, `NOT_FIREPOWER`, `loadings` - so somebody with the rulebook can read the set and check it. - Three parts are helm's reading rather than MegaMek's data, and are listed in TODO.md so they can be argued with: the ranges an MML or an ATM fires at under each loading, an infantry weapon of range nought reaching one hex, and which weapons are left out entirely. - Physical weapons are not in it, deliberately: their damage scales with the design's tonnage, and counting them gives every design carrying one a spike at one hex that drowns the shape of its curve. - Rear-mounted weapons are not in it either. They cannot fire at what the front guns are firing at. - `crates/helm-facet/tests/firepower.rs` pins it to designs a player would recognise - an Awesome is worse in your face than at six hexes, a Catapult outreaches an Atlas - so a change to the model has to argue with a machine rather than with a number: `HELM_MEGAMEK= HELM_BRIDGE= cargo test -p helm-facet --test firepower -- --ignored`. ## Feature branch workflow If asked to do work, unless directly instructed otherwise, do not make changes to the user's top-level git checkout. All of your work will be on feature branches and inside git worktrees. To start work on a feature branch: 1. Run `git fetch origin main` 2. Create the branch and its worktree: `git worktree add -b claude/short-feature-name .claude/worktrees/short-feature-name origin/main` 3. Enter the worktree so that all commands run inside of it 4. Double check that the repo-local `.git/config` `[user]` section has an ATProto `@-` handle as a `name` and its `did:plc` as an email. If it does not, run `atgc repo configure` 5. Ensure that `prek` is installed in your worktree via `prek install` While doing work, be a good neighbor to humans and agents on your machine: - Do not restart, reload, or otherwise modify the configuration of shared services. - If you need temporary folders or other artifacts that exist outside your worktree (such as Docker images), reduce conflicts by tagging them with your current branch and/or SHA. - Check available system resources before running expensive commands (memory or CPU). Make sure your work includes a "maintenance budget" for code directly related to your current feature: - Reducing duplicated or dead code - Adding new debug log lines and similar observability - Updating documentation pages or test suites - Checking off completed issues in TODO.md Structure your commits for human review: - Break work into a sequence of logical commits, typically 1-5 for an average feature. - Use Conventional Commits, including adding "!" indicators for breaking behavior changes. - Don't write more than 1 short sentence + 1 short paragraph into a commit body. Confirm your work is acceptable before submitting a PR: 1. Rebase onto `origin/main` and fix any conflicts. 2. Ensure that all `prek` feedback has been fixed. 3. Run the tests your change affects, and confirm they pass. When your work is ready for review, you must create a pull request. When writing any PRs, updates to PRs, or comments on PRs: - The PR title should be simple and descriptive, and should use Conventional Commits. - The PR body should be three paragraphs at most. Focus on a concise, descriptive explanation of what changed. Avoid commentary on implementation details or future work. - The PR body should contain a before/after screenshot if the change has a visible effect (UI, rendered output, a CLI's printed text). Attach this with Markdown image syntax and a local image path: the `atgc` commands will upload it for you. The file does not need to be committed anywhere, and each image must be under 1 MB or the command refuses it before sending anything. - Do not report your work as "done" until you post the Tangled PR link for the user to review. If the branch is a single reviewable feature, create the PR using `atgc pr create`. If the branch holds several separable but related feature PRs that must land in a given order, use `atgc stack create` instead: - Each PR carries multiple commits, and its own description and screenshots. - Use `atgc stack mark` when you need to turn commit ranges into stacked feature PRs. - Use `atgc stack resubmit` when you need to reconcile the upstream stack after any rebase, amend or reorder. When review feedback arrives, you will need to submit a new "round" on the existing PR. Follow these steps for each round: 1. Rebase against the latest `origin/main`, or if stacked, use `atgc stack sync`. 2. Implement the requested changes. 3. Repeat the required verification steps. 4. If your PR is not yet stacked and you need to begin stacking a new feature on top of it, use `atgc stack link`. 5. Append a new review round to the PR with `atgc pr resubmit` (non-stacked) or `atgc stack resubmit` (stacked). Both republish the branch themselves, leased against the head the last round recorded, so do not `git push` first; if one refuses because the branch is somewhere neither of you expected, look at what is there rather than forcing past it. 6. Update the PR title, body and any new screenshots with `atgc pr edit`. After a feature is merged: 1. Fetch `origin/main`. 2. Confirm the work landed by checking that `git cherry origin/main ` prints no `+` lines. 3. Clean up your own worktree. 4. Delete both the local and the remote feature branch, passing `-D` to account for the patch-based workflow. 5. Leave any temporary artifacts (like Docker images). Another agent may be using them, and they are a shared cache.