diff --git a/TODO.md b/TODO.md index bdd98e0..0f2e5d4 100644 --- a/TODO.md +++ b/TODO.md @@ -317,6 +317,52 @@ The long pole, and the reason `helm-core` does no I/O. Tracked as and checks nothing. `HELM_PERF_BLESS=1` re-records, and a commit that moves a figure should say why. +## How a design reaches the page + +The one integration question still open, and the only thing on this list that +wants a decision rather than work. A `.mul` names a design by chassis and +model and carries nothing about what is in it, so the page needs the designs +from somewhere regardless. + +Measured rather than guessed. About three quarters of a `.mtf` is prose - +`overview:`, `history:`, `deployment:` - and stripping it leaves every one of +the 4,294 battle values identical: + +| how | per design | whole library | +|---|---|---| +| `.mtf` as shipped | 8.9 KB median | 31.9 MB zip | +| `.mtf` with the prose stripped | 2.6 KB median | **0.56 MB gzipped** | +| a minimal JSON of the fields the rules read | 2.0 KB median | 0.45 MB gzipped | + +Which makes "ship the whole library and look up by chassis and model" the +option that retires the question instead of answering it: 0.56 MB beside the +0.09 MB catalogue is under 0.7 MB for everything a page could ask about, and +it can be fetched in the background while somebody browses. + +The JSON form saves 0.6 KB a design and costs a format: a new encoder in +`helm`, a new decoder in `helm-wasm`, and both able to drift from the `.mtf` +parser that conformance actually tests. Not worth it at that price. + +- [ ] **Decide, then build it.** Either a lean-library command beside + `helm catalogue`, or a per-design fetch. helm's database already stores + `unit_criticals` and `unit_armor`, so headquarters can reconstruct a + design without a `.mtf` if that turns out to suit it better. + +## What MegaMek keeps units in + +Four readers, and that is the whole set - `megamek/common/loaders` in 0.51.0: + +| format | what it is | count | +|---|---|---| +| `.mtf` | one Mek design, line-oriented text | 4,294 | +| `.blk` | every other unit type, from tanks to warships | 6,694 | +| `.mul` | a *force in a state*, XML - not a design format | interchange | +| `units.cache` | a Java-serialised index: name, tonnage, BV, cost | 1 | + +Older MegaMek had HeavyMetal Pro importers (`.hmp`, `.hmv`); they are gone. +MegaMekLab reads and writes `.mtf` and `.blk` and has no format of its own, so +it is not a fifth thing to support. + ## What the web UI needs from a .mul The format lance.blue works in, so these are the jobs it has to do. Written @@ -380,6 +426,55 @@ not obvious from any one of them. - [ ] **Verify a post-match file and show it back.** The upload check above, run on the way out rather than the way in. +- [x] **Checked against the published rules, not only against MegaMek.** The + TechManual's own three worked examples, run through helm term by term: + + | | the book | helm | + |---|---|---| + | MON-66 Mongoose | DBR 433.3, OBR 325.08, BV 758 | 433.3, 325.1, 758 | + | TDR-10SE Thunderbolt | DBR 954.85, OBR 1052.98, BV 2008 | 954.9, 1053.0, 2008 | + | WI-DM DemolitionMech | DBR 328.2 | 328.2 | + + Armour, structure, gyro, defensive equipment, the explosive penalty, + both defensive factors and both speed factors agree. That is the rules, + MegaMek and this crate arriving at the same numbers by three routes. + + Two places the book and MegaMek genuinely differ, where helm follows + MegaMek because that is what conformance means: the book gives a cockpit + modifier only for the small cockpit, where MegaMek also has torso-mounted, + small command console, drone, interface and VRRP; and the book describes a + design's *armament* where MegaMek scores everything with a battle value, + so a DemolitionMech's wrecking ball and rock cutter count. The one real + disagreement is written up in `crates/helm-bv/UPSTREAM.md`. + +- [ ] **Verification still worth having.** The structural round trip and the + generated documents cover the losses found so far. Four more, in the + order they would earn their keep: + + - **Injection into real files.** Put an unknown attribute, element, + comment and text run at every position of every real `.mul` and assert + each survives. The generator makes plausible documents; this proves the + files that actually exist tolerate whatever a later MegaMek adds. + - **A named list of what the writer may touch.** A test asserting it only + ever modifies `points`, `index`, `isDestroyed`, `isHit`, `shots`, + `gunnery`, `piloting`, `hits`, `chassis`, `model`, `type` and + `version`. That turns "do not lose data" from a habit into a check. + - **Deliberately break the guards.** The performance gate was proved to + fire by making something slower on purpose; nothing has proved the + losslessness guards fail when they should. + - **Construct, write, read.** Every round trip currently starts from a + file. Building a force in code and writing it out is lightly covered. + +- [ ] **Generate more forces from MekBay when a reader changes.** + is MegaMek's own web client and its force generator + writes `.mul` files, so it is the only source of documents this + repository did not write. It found the one interop bug nothing in the + corpus could: MekBay folds a Clan design's second name into the chassis - + `Loki (Hellbringer)` - where MegaMek keeps `chassis:Loki` and + `clanname:Hellbringer` apart, so every Clan unit in a MekBay force + matched nothing. It also cross-checked three battle values against a + third implementation. + - [ ] **Zero unregistered disagreements.** Whatever is left after the above is either our bug or theirs, and theirs gets written down by name the way the Alpha Strike specials deviation is. @@ -405,6 +500,23 @@ not obvious from any one of them. being string work. So a lance re-scores in about 0.3 ms in a browser and a company in under a millisecond, which is inside a frame either way. + Measured again through the finished boundary, from Node against the + real module rather than a sketch of one: + + | what a page does | cost | + |---|---| + | instantiate the module | 3 ms | + | load the shipped catalogue | 88 ms, once | + | score a design from its `.mtf` text | 253 us | + | re-score a *held* design, damaged | 326 us | + | re-crew a *held* design | **1 us** | + + Holding the design is what makes the last row true: reading the `.mtf` + is most of what scoring costs, and a crew only scales a base that has + already been worked out. Without a handle the same re-crew was 432us, + which is the promise of the native benchmark being thrown away at the + boundary. A lance re-crews in 4us and re-scores for damage in 1.3ms. + Three things came out of writing it. Asking "is this location exposed" per item rather than per location made the cheapest rating cost more than reading the design; the loadout's mountings were rebuilt on every call