feat: measure a plan against what the map actually holds - #602
Draft
Maelstromeous wants to merge 10 commits into
Draft
Maelstromeous wants to merge 10 commits into
Maelstromeous wants to merge 10 commits into
Conversation
A plan can balance perfectly and still be unbuildable. The satisfaction maths only ever asks whether a factory's inputs add up, never whether the ground holds enough of the resource to begin with, so a mine asked for 9,107 Crude Oil a minute solved happily against a map that holds 5,040. Raw Resources now carries what the world holds beside what the plan takes. Two ceilings, because they answer different questions: every node worked by the best extractor with no power shards, and the same nodes at the 250% clock cap. Over the first, a plan needs shards and says so; over the second, the resource is not on the map in that quantity and nothing will make it so. Node counts are map facts and cannot be derived from the game data, so they are held in world-resources.ts. Everything else — extractor marks, rates, purity multipliers, well satellite rates — is read from the parsed game data, and the spec multiplies the node counts back out against those rates to assert they reproduce the extraction `limit` the parser reads out of the game for all thirteen resources. A typo in a node count fails there rather than quietly passing a plan that cannot be built. Extractors are counted against nodes as well as rates, which is the check a rate ceiling cannot make: purity is chosen per building group, so nothing stopped a plan describing 24 Raw Quartz miners against the map's 17 quartz nodes while every total still balanced. The hard case (more extractors than nodes, whatever their purity) is separated from the soft one (enough nodes exist, just not of that purity — where a group defaults to a normal node, which most plans never revisit), and nodes are counted apart from well satellites since a miner cannot stand on a micro-node. Where a resource is over the wall, the Converter recipes that make it are named from the game data rather than listed here. Crude Oil and SAM have none — nothing in the game synthesises either — so those say the map's total is final instead of implying a way out. Verified against Mael's MegaPlan in the browser, which turns out to place 57 Oil Extractors on 30 oil nodes, 25 Caterium miners on 17, and 7 Uranium miners on 5. Two things the first run showed: the utilisation chip was green on a resource whose only problem was node count, so it now takes the row's worst finding rather than its rate alone; and the warnings column was sized by whatever the factory chips left over, wrapping to a word a line. Figures assume the default vanilla world. 1.2's randomised worlds and the resource-rich game modes deal different node counts, which the help text and the module say plainly rather than pretending otherwise. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CejFi895Pae9Pqa9MAfnFk
…the headers
The first cut buried the two things a reader wants in prose. Both are ratios,
so both now read as one:
Extraction 6,740 / 12,600 /min 53%
Oil Extractor at 250% · 5,040/min at 100%
Nodes 57 / 30
Extraction is what the plan takes against the most the world can give.
Nodes is how many extractors it places against how many exist to stand on —
the check a rate ceiling cannot make, since purity is picked per building
group and a plan can sit well inside the rate while putting 24 miners on 17
nodes.
The capacity figure now names the machine it assumes. "12,600/min at 250%"
says nothing on its own: the same nodes worked by a Mk.1 come to a quarter of
it, and there was no way to tell from the table which the number meant.
Warnings alone were not enough to reach anyone. Statistics is collapsed by
choice on a returning visitor, so a plan that cannot be built could sit
behind a Show button indefinitely. The Raw Resources header now counts what
is beyond the map and what needs power shards beside its resource count, and
turns red with the first; Statistics repeats the blocker count on its own
header, which survives collapsing the section. Verified both in the browser,
including after collapsing.
The well row is only rendered where wells are in play, rather than every oil
plan carrying a "0 / 18 well nodes" line saying nothing. The warning triangle
was fa-triangle-exclamation, a FontAwesome 6 name absent from the vendored
build, and drew as a missing glyph; it is fa-exclamation-triangle like the
other 25 in the app.
calculateWorldResourceProblems is the one roll-up behind all of it, so the
table and the two headers cannot disagree about what is wrong.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CejFi895Pae9Pqa9MAfnFk
…the resource
Extraction and nodes are the same question asked twice — how much of what
exists is already spoken for — so they are one column of two bars rather than
two columns of numbers:
Extraction ▓▓▓░░░░░░░ 6.7k / 12.6k /min
Oil Extractor at 250% · 5k/min at 100%
Nodes ▓▓▓▓▓▓▓▓▓▓ 57 / 30
Green while there is room, amber from 60%, red from 80%, pinned at full past
the ceiling. A bar is read at a glance where two more numbers had to be
measured against each other first.
What is wrong with a resource now hangs off the resource, as chips beside its
name — Beyond the map, Needs power shards, Not enough nodes, Purity mismatch —
the way the Factories Summary hangs status off a factory. It is a property of
the resource, not a footnote to whichever bar happens to be over. What is left
in prose is advice rather than status: which Converter recipe makes up a
shortfall, or which purities to spread across. The sentence repeating an
overcommitted node count is gone entirely; the bar beside it already reads
19 / 17 in red.
Figures over a thousand read as 2.6k and 92.1k. formatCompact was the obvious
tool and the wrong one: it spends a four-character budget because it sits
under a 36px icon, so 92,100 came out as "92k" and 12,300 as "12k" — fine at
that size, a real loss in a table where the figure is read against the one
beside it. formatCompactPrecise keeps one decimal at every magnitude, with the
promotion threshold tightened by the same factor so 999,900 reads 999.9k
rather than overflowing to "1000k".
Spacing: the heading sat flush against the alert below it. It now carries the
same gap-and-margin shape the Power section's heading uses, and its chips lost
their hand-rolled left margins to the flex gap.
Verified in the browser against Mael's MegaPlan, header chips checked with
Statistics expanded and collapsed. The extractor caption was wrapping "at
100%" onto its own line, where it read as a third bar's label; it no longer
wraps and the column shrink-wraps around it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CejFi895Pae9Pqa9MAfnFk
The bars were laid out `84px | 1fr | figures`, so a longer figure beside a bar stole track from it and no two bars in the table were the same length — the one thing a column of bars has to be. The track is a fixed 190px now, and the extraction figures moved underneath their own bar, snug to it, where nothing they read can change it. That freed the room to say what the caption underneath was saying in prose. Extraction is measured against both ceilings, a bar each: what every node gives unclocked, and what the same nodes give at the 250% cap. Crude Oil at 6.7k against 5k and 6.7k against 12.6k is what "needs power shards" looks like — one bar full and red, the next with room — rather than a sentence about it. The extractor those ceilings assume is its own icon rather than its name, which is both shorter and the thing people recognise. A dashed rule separates the two ceilings, being the same measure twice; a solid one separates extraction from nodes, being a change of subject. Nodes keeps its figures beside its bar, since two short numbers cost nothing there and the bar's width no longer depends on them. The header chip read "5 beyond the map", which said the map is missing rather than that the plan outruns it. It reads "5 beyond map allowances". Verified in the browser against Mael's MegaPlan. The extractor icon came out dimmed at first: the key's 0.75 opacity applied to the icon as well as its text, and that icon is the only thing naming the machine. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CejFi895Pae9Pqa9MAfnFk
The numbers moved out from beside the node bars and under them, where the extraction figures already sat, so the bar takes the whole column rather than whatever the figures leave: every bar in the table is now the same length and as long as the column allows. Each figure line ends with that bar's share of its ceiling, in the bar's own colour — a bar says "nearly full", the percentage says how nearly. Nodes get a diamond in the key, the shape the game draws them as on the map, matching the extractor icons keying the two extraction bars. One rule left in the cell, at the one place the subject changes: dotted, between the 250% ceiling and the nodes. The two extraction ceilings are the same measure twice and no longer have a line between them. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CejFi895Pae9Pqa9MAfnFk
…Water Every figure in Raw Resources is wrong for a world generated with anything but the defaults, and the caveat saying so lived inside the help text, which is off unless you turn it on. It is now a permanent footnote under the table, naming what actually changes the counts: randomised node layouts, the resource-rich and fossil-fuel-rich presets, and the purity settings. A plan holds nothing that says which of those a save was started with. Water is not unlimited, it is unbounded by nodes: an extractor still needs a patch of water to stand on, so a big enough plan does run out of map. There is no node count to measure that against and no plan comes near it, so the row now says "effectively unlimited" and names what does bound it, rather than claiming a limit that does not exist. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CejFi895Pae9Pqa9MAfnFk
The extraction limits in the parser are hand-entered, because Docs.json does not state them, and Limestone's was a transposed digit: 69,900 for a resource whose 94 nodes come to 69,300 with a Miner Mk.3 at the 250% cap. The world resource table was then written backwards from the wrong figure — 15/51/29 reproduces 69,900 exactly, and puts a node on the map that is not there. Counting the actual objects in three 1.2 saves (a vanilla one, a node-randomised one and a fossil-fuel-rich one) gives 459 resource nodes and 118 well satellites in every case, against the 460 this table described. The published split of 15/50/29 agrees with that count and with the corrected limit, so both ends are now consistent. The spec asserts the totals as well as the rates from here on. The rate check alone cannot tell one split from another that sums the same way, which is how a 95-node Limestone passed it in the first place; object counts are the independent measure, and they do not depend on how the world was generated. Game data is republished as 1.2-08 for the corrected limit. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CejFi895Pae9Pqa9MAfnFk
The table held 63 of the map's 118 well satellites. The missing 55 are Water, left out because water is unlimited and has no ceiling to track - true, but it meant the object-count check could only ever verify 63 of them, and it leaves nothing for a game save to patch over when a resource-rich preset moves Water to 58 satellites. Water now carries its wells and keeps `unlimited`, which short-circuits both the utilisation status and the node-usage check before either reads them, so nothing about the warnings changes. Geysers were absent entirely. They are added as their own export rather than a table entry: a geyser yields power, not an item, so it has no part id to key on. Both figures come from the community map. The totals are the half a save can referee and they agree with it exactly - 7/12/36 Water + 2/7/36 Nitrogen + 8/6/4 Oil is the 118 satellites every 1.2 save reports, and 9/13/9 is the 31 geyser actors. Note for anyone tempted to check the well split against a randomised save: the presets redistribute satellites. NRM_Strict reproduces all eleven solid node counts exactly and still reads Water 55 / Nitrogen 42 / Oil 21 against the map's 55/45/18, and the resource-rich presets differ again. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ne-setup-vrbovc # Conflicts: # web/public/gameData_v1.2-07.json # web/public/gameData_v1.2-08.json # web/public/gameData_v1.2-09.json # web/src/components/planner/Statistics.vue # web/src/components/planner/StatisticsResources.vue # web/src/config/config.ts
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This was referenced Aug 25, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Replaces #576 — same commits, renamed branch (
claude/concrete-mf-mine-setup-vrbovcwas a leftover name from unrelated work).The planner has always balanced plans against an infinite world. It asks whether a factory's inputs add up, never whether the ground holds enough to begin with — so a mine set to 9,107 Crude Oil a minute solves happily, against a map that holds 5,040.
This adds the missing question, and in answering it turned up two errors in the map data itself.
Raw Resources says how much of the world a plan uses
Three bars per resource, because a plan can fail in three ways:
Extraction against both ceilings, a bar each: what every node gives with no power shards, and what the same nodes give at the 250% clock cap. Crude Oil at 6.7k against 5k and 6.7k against 12.6k is what "needs power shards" looks like — one bar full and red, the next with room — rather than a sentence about it. Past the second, the resource is not on the map in that quantity, however it is clocked.
The extractor those ceilings assume is named by its own icon: the same nodes worked by a Mk.1 come to a quarter of a Mk.3's, so a bare "12.6k at 250%" says nothing alone.
Nodes is how many extractors the plan places against how many exist to stand on — the check a rate ceiling cannot make. Purity is chosen per building group, so a plan can sit well inside the rate and still put 24 miners on 17 nodes. More extractors than nodes is a blocker; enough nodes but not of the purities named is a note, since a new group starts on a normal node. Nodes and well satellites are counted apart, because a miner cannot stand on a well's micro-node.
Every bar runs the full width of its column with its figures and its share underneath, so no bar is shortened by its numbers and all of them are the same length. Green, amber from 60%, red from 80%, and the percentage takes the bar's colour.
Said where it will be seen
Statistics is collapsed by choice for a returning visitor, so warnings inside a table reach nobody.
calculateWorldResourceProblemsdrives every surface from one roll-up: status chips beside the resource name (Beyond the map, Needs power shards, Not enough nodes, Purity mismatch), counts on both the Raw Resources and Statistics headers, and an alert separating "the world does not hold this much" from "more extractors than nodes", because the fixes differ.Prose is left for advice only: which Converter recipe makes up a shortfall, or which purities to spread across. A plan short of Uranium is pointed at
Uranium Ore (Convert: Bauxite). Crude Oil and SAM have no synthesis route at all, so for those the map's total is final and the warning says so rather than implying a way out.Two corrections to the map data
Node counts are map facts and cannot be derived from the game data, so they live in
web/src/utils/world-resources.ts. Everything else — extractor marks, rates, purity multipliers, satellite rates — is read from the parsed game data, so a game update moves the figures without touching that file.The spec asserted those counts reproduce the extraction
limitthe parser reports. That check passed while both sides were wrong:parsing/src/parts.tsare hand-entered, becauseDocs.jsondoes not state them, and that one was a transposed digit. The node table had then been written backwards from it as 15/51/29 — which reproduces 69,900 exactly and puts a node on the map that is not there. The real split is 15/50/29, agreeing with the published figure, the corrected limit and the object count. Game data is republished for it.unlimited. Geysers are a separate export, since a geyser yields power rather than an item and has no part id to key on.The rate check alone cannot tell one split from another that sums the same way, which is exactly how a 95-node Limestone survived it. So the spec now also asserts the object counts — 459 resource nodes and 118 well satellites — taken by parsing real 1.2 saves. Those hold whatever the world was generated with, so they are the independent measure the rates could never be.
Verification
pnpm lintandvue-tscclean.Caught during those runs and fixed: a green chip on a resource whose only problem was node count; a warnings column sized by whatever the factory chips left over;
fa-triangle-exclamation, a Font Awesome 6 name absent from the vendored build, drawing as a missing glyph; the extractor icon dimmed by an opacity meant for its label; and bars of differing lengths, which is what moved every figure out from beside its bar and under it.Not seen on screen: no resource in the MegaPlan lands in the 60–80% amber band, so that colour is unit-tested but unverified visually.
Scope
Figures assume the default vanilla world. A footnote under the table says so permanently rather than hiding in help text, and names what changes them: randomised node layouts, the resource-rich and fossil-fuel-rich presets, and the purity settings.
Reading a world's actual layout is deliberately not attempted here. It is possible — a 1.2 save records the generation settings, the seed, and a resource and purity override for every node — and it is now #584, along with reading tiers, unlocked buildings and alternate recipes from the same file.
Generated by Claude Code