Skip to content

The game stops saying five things that are not true - #28

Merged
pshenok merged 1 commit into
mainfrom
fix/ui-tells-the-truth
Aug 17, 2026
Merged

pshenok merged 1 commit into
mainfrom
fix/ui-tells-the-truth

Conversation

@pshenok

@pshenok pshenok commented Aug 17, 2026

Copy link
Copy Markdown
Owner

Found by an adversarial audit of the whole codebase, each reproduced independently. 535 → 558 tests. No sim file touched — the diff is src/ui/*, src/locales/*, docs and tests.

They share one shape: the game told the player something the simulation does not do. CONTRIBUTING's first rule is about mechanics, but a label is a claim too.

1. Every link's inspector was labelled "Draw" and printed its nameplate. grid_feed, transformer and pdu all fell through to row(insp_draw, "cap N kW") — the label said Draw (uk «Споживання», consumption), the value was a constant, and the literal cap was hardcoded English no locale could reach. The carried kW, the number the entire power model is about, was never visible anywhere in the game for a link. A player watching a bus approach its rating had no way to watch it.

2. A failed chiller diagnosed "LOOP OVER-COMMITTED". The crac branch has a broken row; the chiller branch did not. When chiller_fail kills the plant, capacity goes to 0 and ratio to 0, so it fell into the starvation row — telling the player to buy fewer heads when the plant is dead. On the level whose whole lesson is "one plant is a shared blast radius", the inspector pointed at the wrong cause. It now says the plant failed, without promising a repair that does not exist.

3. dark_chain invented a physics fact the config contradicts. The briefing said "their transfer switch needs longer to pick up than the blackout lasts." cutoverSec is 3; the outages are 6 s. The cutover is half the blackout. Generators are off the table on that level because it banned them — a true restriction with a false justification attached. Now it says the true reason, and a test asserts the claim against CONFIG rather than against today's wording.

4. The sag level's bonus read "WHILE the grid is down". objectiveLabel mapped every serve_kwh_during_event to one string, ignoring the objective's event. sag carries event: "brownout", and its entire lesson is that a brownout is degraded-not-dead — the grid is emphatically still up. The label now follows the event it is gated on.

5. The Ukrainian FAQ stated the wrong earning rule. The English gives the two rules — racks earn while POWERED and COOL. The Ukrainian capitalised «ЗАТРЕБУВАНІ», which means in demand, not powered. First rule a Ukrainian player reads, and wrong. Also unified «утиліта» → «підстанція» to match the HUD.

Each fix is mutation-checked with real output; reverting any one turns its own test red. For 3 and 5 the tests assert the claim against the config and the simulation — the FAQ test runs tickDemand to prove both earning gates before checking that each locale names them — so the next retune breaks the test rather than the truth.

Five places where the game told the player something the sim does not do.
Each was reproduced before it was fixed, and each ships with a test that
goes red when the fix is reverted.

A LINK's inspector read "Draw: cap 30 kW". The label said consumption, the
value was a constant nameplate, and "cap" was hardcoded English no locale
could translate. Links carry, they do not draw — sim/power.js writes
actualKw as the kW crossing the node — and that number appeared nowhere in
the game for a link, so a player watching a bus climb toward its breaker
rating had nothing on screen that moved. Now the rack's shape: carried kW
against the rating, under a new insp_carried in both locales.

A FAILED chiller plant read "LOOP OVER-COMMITTED — every CRAH is throttled",
i.e. buy fewer heads. chiller_fail zeroes the plant's duty, which zeroes the
loop's capacity and its ratio, which dropped the panel into the starvation
row — on the level whose whole lesson is that one plant is a shared blast
radius. It now names the failure and, because chiller_fail sets repairAt to
Infinity and repairCrac refuses anything that is not a CRAC, promises no
repair. The starvation row still fires when starvation is the truth.

dark_chain's briefing justified the missing generators with "their transfer
switch needs longer to pick up than the blackout lasts". cutoverSec is 3 and
the blackouts are 6: the cutover is HALF the outage. The real reason is the
level's own `banned` list, which is what the briefing now says, in both
locales.

The sag bonus was labelled "Serve N kWh WHILE the grid is down" (uk "ПОКИ
мережа лежить") on the level that teaches a sag is degraded-not-dead. The
label ignored the objective's `event` field that campaign.js gates the
counter on; it now follows evaluateObjective's own mapping — brownout,
heatwave, or the grid outage — with obj_serve_sag / obj_serve_heat added to
both locales.

The uk FAQ's first rule said racks earn "поки ЗАТРЕБУВАНІ й ОХОЛОДЖЕНІ" —
in demand and cooled. The sim's gates are power and heat. It now reads "поки
мають ЖИВЛЕННЯ і ОХОЛОДЖЕННЯ", and the two rooms that called a substation
"утиліта" now use the HUD's own «підстанція».

Tests are written against CONFIG and the sim, not against copies of the new
sentences: the transfer-switch test reads generator.cutoverSec and the
level's own outage durations, the ban test reads the level's `banned` list,
and the FAQ test proves the two gates by running tickDemand three times
(powered+cool earns, unpowered loses, cooked loses) before checking that both
locales name them.

Mutation-tested, each independently:
  - link row back to `cap ${capacityKw} kW`      -> 6 red
  - chiller loses its broken row                 -> 2 red
  - starvation row no longer gated on b.broken   -> 1 red
  - EN dark_chain blames the transfer switch     -> 1 red
  - uk dark_chain blames the transfer switch     -> 2 red
  - uk FAQ back to "ЗАТРЕБУВАНІ"                 -> 1 red
  - uk says "утиліта A" again                    -> 1 red
  - objectiveLabel/objectiveRow back to one key  -> 3 red

No sim module touched: this is UI and copy only. The thirteen campaign pairs
are unmoved — campaign, generator, prebuilt, lab and bonuses are 124 tests
green and unchanged. 535 -> 558 tests, 30 -> 33 files; the counts quoted in
README.md and CONTRIBUTING.md moved with them.
@pshenok
pshenok merged commit ab601b2 into main Aug 17, 2026
1 check passed
@pshenok
pshenok deleted the fix/ui-tells-the-truth branch August 17, 2026 08:32
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.

1 participant