Played a full dock plus part of the relay. The find / diagnose / resolve loop reads clean, and the one-fault guarantee holds in engine.mjs (singleViolationUnit rejects any candidate with more than one violation), so it never cheats you with two faults. Three things, first one first.
1. Your penalty feedback under-reports the cost. The message only says "Minus 6 seconds" (wrong unit) or "Minus 8 seconds" (wrong rule, wrong route). The code also does score -= 35 and score -= 50 in the same handlers. The clock is on screen; the score hit isn't. I mis-tapped twice and watched the score drop with no explanation. Say the real cost, or drop the hidden score penalty.
2. Supply hint copy is wrong for shape and stamp repairs. renderSupply always opens with "The number is a power setting from 1 to 4." even when the broken field is core shape or stamp. On a core-shape fix the first line describes a field that isn't on screen.
3. Learn rounds are free. In engine.mjs, on a "learn" round ruleIndex = activeRuleCount - 1 and newRuleId is that same rule, so step 02's answer is always the highlighted "new rule" badge. A player notices fast (I did, mid dock 1) and stops reading the rule panel. Good for teaching, but diagnose then carries no information on half the dock.
No sandwich in, none out. GL with the relay.