časť 28
Presun, ktorý nesmie nič zmeniť: Kastgard do vlastného priečinka
Deväťdesiatjeden súborov hry sa 31. októbra 2026 presunulo do js/realms/kastgard/ a hráč nič nezbadal. Čo tomu predchádzalo (testy, nástroje, tabuľka balíkov), čo move.js neprepíše a čo sa presunulo len naoko.
Dňa 31. októbra 2026 o 3:46 sa do hry zlúčil presun Kastgardu (verzia 0.64.5). Deväťdesiatjeden súborov hry, ktoré dovtedy ležali v js/core/, js/data/, js/ui/ a js/worker/, má od tej chvíle miesto v js/realms/kastgard/. Hráč nič nezbadal, a to bola požiadavka: žiadny uložený kľúč, žiadne ID, žiadne pravidlo a žiadna hodnota v zlatých záznamoch sa nezmenila. Zistilo sa, že samotný presun je krátky (päť commitov), no stojí na príprave od 28. októbra: testy a nástroje sa usporiadali podľa balíkov, nástroje prestali skladať cesty ručne a tabuľka balíkov sa naučila vzťah „hra stavia na hre“. Po presune má celá sada 3 268 testov (3 267 prešlo, jeden sa preskakuje) a zoznam 120 porušení smeru závislostí je rovnaký ako pred ním.
Prečo presun a čo sa pri ňom nesmie zmeniť
Podľa zápisu v docs/KASTGARD-GAMES.md (časť 2.1) je môj model z 30. októbra 2026 taký: Kastgard je cárstvo s dvoma hrami. Prvá, stacks, je hra s kockami a územiami s voľnou hrou a konfigurátorom; režim Kniežatstvá[1] je len predvoľba toho konfigurátora. Druhá, campaign, na stacks stavia. Minihry a Puzzle Labs nie sú hry, ale obsah, ktorý hry zaregistrujú. Článok Z jednej hry viac hier opisuje fyzický presun súborov (krok M9) ako git mv; tento záznam ukazuje, čo sa pod tým „iba“ skrývalo.
Presun sa týka len ciest. Nezmenilo sa žiadne uložené ID ani kľúč, Record.RULES_VERSION (2) ani Rules.GEN_VERSION (1). Priečinok sa volá kastgard, no runtime ID cárstva ostalo stacks; tabuľka balíkov to zapisuje ako realms: { "stacks": "kastgard" }. Preto sa presun dokazuje porovnaním starého a nového výstupu, nie novým testom pravidiel. Tak to platilo 31. októbra 2026; od 6. novembra 2026 je id cárstva kastgard a tabuľka balíkov tento zápis už nepotrebuje (príbeh je v článku Ako je poskladaná hra Audamir).
Najprv testy a nástroje
Podľa DESIGN §72 padla 29. októbra 2026 moja požiadavka, aby sa tests/ a tools/ usporiadali tak ako js/ a aby zmena v jednom cárstve alebo hre nespúšťala testy všetkých ostatných. Je to samostatný cieľ (kratší cyklus úprav), no jeho vedľajším účinkom je, že rozloženie testov a nástrojov zrkadlí js/, takže presun balíka je potom premenovanie predpony priečinkov. Všetkých päť krokov sa zlúčilo 30. októbra 2026:
| Krok | Zlúčené | Čo | Čísla |
|---|---|---|---|
| T1a (§72) | 01:20 | testy do priečinka balíka | 194 presunov, 1 607 odkazov v 246 súboroch, názvy všetkých 2 793 testov rovnaké |
| T1b (§73) | 03:47 | bežec tools/test.js --changed | zmena pravidiel Kolónie: 24 zo 186 súborov, 49 s z 296 s |
| T2 (§74) | 07:16 | nástroje do tools/<balík>/ | 79 súborov |
| T1c (§75) | 08:42 | testy zrkadlia priečinky js/ | 127 súborov, test Kolónie rozdelený na štyri |
| T3 (§76) | 11:04 | testy nástrojov a fixtúry | tools.test.js (35 testov, 157 s) na 27 súborov (38 s), 17 fixtúr |
Bežec je skratka na prácu medzi tým; **npm test ostáva bránou** pred zlúčením. Dve veci z týchto krokov sa neskôr ukázali ako dôležité aj pre Kastgard. Pri prvej mutácii Kolónie bežec jeden test vynechal, lebo nástroj skladal cestu z premennej a nikde nestálo meno súboru (§73.4): tá istá slepá škvrna, na ktorú neskôr narazil move.js. A fake DOM losuje semienka partií z mena súboru testu (§72.3), takže premenovaný test by hral iné hry; poistka rozloženia preto stráži jedinečnosť mien.
Tabuľka balíkov a move.js
Základ stojí od 28. októbra 2026 (DESIGN §60, zlúčené o 19:49, verzia 0.51.2). Nástroj tools/move.js presúva súbory cez git mv (aby git blame prešiel cez premenovanie) a prepisuje odkazy: cestu napísanú celú, require, importScripts, značku <script> a položku v sw.js; relatívnu cestu vyhodnotí z miesta, kde súbor bol, a zapíše od miesta, kde je. Potom si overí, čo urobil: žiadna stará cesta nezostala, žiadna fungujúca relatívna cesta nesmeruje nikam, index.html, sw.js aj workery pomenúvajú existujúce súbory a skripty majú poradie, v ktorom každý UMD obal nájde svoje globály. Tabuľka tools/packages-table.json zapisuje každý súbor js/ do presne jedného balíka a tools/packages.js kontroluje smer závislostí. Pilotom bola Kolónia: 9 súborov, 126 odkazov v 31 súboroch.
Pilot našiel chybu, ktorú žiadny test nehľadal (§60.5). js/i18n/boot.js pomenúvalo jazykové balíky pre Web Worker pevným ../../. Z js/realms/colony/worker/ táto cesta nevedie k žiadnemu súboru, importScripts vyhodí chybu, worker zahynie a stránka sa potichu vráti do hlavného vlákna: pomalšia hra, o ktorej nič nehlási. Worker teraz číta svoje miesto z vlastnej adresy. Pri Kastgarde boot.js zmenu nepotreboval, pribudol len test pre worker šesť priečinkov hlboko.
Nástroje nehľadajú súbor podľa cesty
Presun by rozbil nástroje, ktoré skladali cestu z konštánt. DESIGN §94 (zlúčené 31. 10. o 1:29) ich spočítal: 74 nástrojov pomenúva asi 640 súborov js/. Skúšobný beh move.js --dry-run --package stacks vypísal 80 riadkov „skontrolovať ručne“, z toho 64 v 20 nástrojoch.
Riešenie je pomôcka tools/paths.js: nástroj pýta súbor podľa kľúča a tabuľka mu povie, kde leží. Kľúčom je cesta pod priečinkom balíka, core/rules.js pre js/core/rules.js aj pre js/realms/kastgard/games/stacks/core/rules.js. Vrstva patrí ku kľúču, lebo **14 základných mien v js/ nie je jedinečných** (campaign.js leží v core/, data/ aj ui/). Pomôcka je prísna: neznámy kľúč, nejednoznačné meno aj súbor, ktorý tabuľka vedie a disk nemá, sú chyby. Rovnaké funkcie vedia pracovať nad iným stromom (Paths.at(root)), napríklad nad git archive starého commitu pri dôkazoch migrácií.
Poistka rozloženia nástrojov a bežec testov zisťovali, čo nástroj používa, z reťazca js/… v jeho zdroji; nástroj s Paths.require('core/rules.js') takú cestu nemá, a obe by oslepli, preto sa naučili čítať aj volania Paths. Dôkaz: 74 nástrojov sa pustilo na starom aj novom kóde s rovnakými argumentmi; z 111 porovnaných výstupov a súborov bolo 103 rovnakých (89 bajt po bajte) a 8 sa líšilo z dôvodu, ktorý sa prečítal v každom prípade (päť nesie čas, ďalšie meno dočasného súboru, skratku commitu alebo relatívnu cestu). V skúške na kópii stromu, kde sa stacks a campaign presunuli skutočným move.js, sa nemuselo opraviť ani jeden riadok nástroja.
Poradie krokov K1 až K6 a prečo
Presun nešiel priamo. Každý krok mal zostať overiteľný sám, preto sa najprv menilo to, ako sa cesty počítajú, a až potom samotné súbory:
- K3: nástroje dostali pomôcku
tools/paths.jsa cesty už nepíšu ručne. Bez nej bymove.jsnechal 109 skladaných ciest v 25 súboroch. - K1 a K2: tabuľka balíkov sa naučila, že hra smie stavať na inej hre (
buildsOn), a kampaň prestala čítať manifest vlastného cárstva. Bez K1 by kontrola smeru ukázala 122 hrán. - K4 a K5: testy a nástroje sa presunuli do priečinkov, ktoré zrkadlia
js/, a 91 súborov sa zaradilo do tabuľky. Tabuľka odmietne hru, ktorej priečinky testov nezrkadlia jej priečinok vjs/. - K6: až teraz sa presunul samotný kód
js/, nástrojommove.js --packagepre každý balík.CACHEvsw.jssa zvýšil raz (v72 → v73).
Plán sa pred zlúčením vyskúšal na kópii repozitára (git archive, skutočný move.js) a po každom kroku sa spustili tri poistky. Našlo sa sedem chýb plánu. Najdôležitejšia: formatTable zabúdal pole, ktoré nepoznal (buildsOn); takto zapísaná tabuľka by desať hrán z kampane do hry zmenila na porušenia. Presun potreboval aj tiché okno: počas K4 až K6 nesmela žiadna iná zmena meniť tieto súbory, index.html, sw.js ani tabuľku.
Čo move.js neprepíše
move.js prepíše cesty, ktoré sú napísané celé: cesty v require a importScripts, značky <script> a položky v sw.js. Nevidí cesty, ktoré sa skladajú z častí, URL, šablóny ani počet ... Našlo sa to takto:
- **Počet
..:** 20 testov získava koreň repozitára cezpath.join(__dirname, '..', '..', '..'). Po presune treba šesť... - Adresa namiesto cesty:
tools/smoke.jsžiadal/js/worker/gen-worker.js. - Hĺbka workera: dva testy workera analýzy hľadali
importScriptsv pevnomjs/worker/. - Meno súboru skladané v teste: sedem testov teraz pýta súbor cez kľúč z
tools/paths.js; päť čítalo pevnú cestu a v prvom behu zlyhalo. - Hračkový strom: nástroj v
test-runner.test.jsa v častiach dvoch ďalších testov prepísal meno tam, kde ide o skutočný súbor, a inde nie. Zmena sa vrátila späť. - Zlý odhad druhu zmeny:
tools/version.jspoznal novú obrazovku len ako súbor vjs/ui/; bez opravy by nová obrazovka hry bola počítaná ako „fix“. - Pomôcka sama:
Paths.dirOfmedzi K4 a K6 hlásila priečinok balíka, ktorého súbory ešte ležali vjs/. Opravené. - Drobnosti: hlavička
Used by:vboard-events.jsa prázdne priečinky po presune.
Naschvál sa nezmenili dokumenty: ostali v nich staré cesty. Rovnako ostali katalógy v js/i18n/ a staršie články blogu, napríklad Z jednej hry viac hier. Prevod starej cesty na novú je v docs/KASTGARD-MOVED.md.
Smer závislostí a západka
Pravidlo (DESIGN §95.2): **balík smie používať core a seba; cárstvo smie používať svoje hry; hra smie používať hry, na ktorých stavia (buildsOn); nič iné.** Campaign stavia na Stacks, takže campaign → stacks je zákonná hrana (po K1 ich je 10: K1 jednu pridal, lebo section-campaign.js teraz pomenúva ruleset-stacks.js). Hra však nesmie používať svoje cárstvo, a preto K1 prerezal dve hrany do manifestu a tabuľky režimov.
Zoznam porušení, ktorý sa smie len zmenšovať (v nástrojoch ratchet, slovensky západka), sa pri presune nezmenil. Takto vyzerá node tools/packages.js --check z 31. októbra 2026:
Čísla 120 a 22 sú rovnaké pred presunom aj po ňom: presun nepridal porušenie a žiadne neopravil. Z nich 112 hrán (core do Kastgardu: 65 + 45 + 2) je práca kroku M8b, teda rozdelenia zmiešaných súborov platformy. Štyri hrany zo stacks do campaign tvoria skutočný cyklus: legend.js pomenúva CampaignView a Bonuses, kým ui/campaign.js pomenúva Legend. Balíky kastgard a kastgard/campaign sú označené clean (každé nové porušenie zlyhá samo, prísnejšie než západka); kastgard/stacks nie je čistý, kým sa neodstránia tie štyri hrany. Hlásenie optional hovorí, že 49 hrán (45 z core, 4 zo Stacks) vedie do kampane z balíka, ktorý nie je voliteľný; kým nie je 0, zostava hry nemôže kampaň vynechať. Je to hlásenie, nie kontrola.
Dôkaz, že sa nič nezmenilo
Podľa DESIGN §95.4 sa po každom kroku a na celku overilo toto:
| Vrstva | Výsledok |
|---|---|
| tri poistky po každom kroku | exit 0, 120 hrán v 22 súboroch |
baseline.js, calibrate.js --verify | všetkých 188 odtlačkov hry sedí; 18 meraní kalibrácie identických, 0 zmenených |
replay.js --golden, --golden-maps | zlaté záznamy zapísané znova sú bajt po bajte rovnaké, git status neukáže zmenu v tests/fixtures/ |
| 16 migračných nástrojov na dátach starého kódu | všetky „as promised“; colony-id-migration zlyháva aj bez presunu s rovnakým textom |
build.js --check | obe zostavy dvakrát bajt po bajte; text je starý okrem ciest (28 riadkov z K1, jedna hlavička, hash cache); tri workery po normalizovaní ciest identické |
| panel Browser, reálne kliky | hub Kastgardu (8 dlaždíc); hra v režime Kniežatstvá uložená starým kódom 30. 10. sa obnoví a AI ju dohrá; kampaň, 18 minihier, Puzzle Labs, denné výzvy, záloha a obnova |
sieť a sw.js | gen-worker.js a puzzle-worker.js zo js/realms/kastgard/games/stacks/worker/; worker analýzy dobehol zlatý záznam; 195 položiek sw.js, všetky vrátia 200 |
| celá sada | prvý beh po presune: 5 zlyhaní (testy čítajúce súbor js/ pevnou cestou); po oprave 3 268 testov, 3 267 prešlo, 1 preskočený, dvakrát za sebou |
Čo ostáva a čo sa presunulo len naoko
Treba povedať otvorene: presunuli sa cesty a nič iné. Model „cárstvo s dvoma hrami“ sa ešte nedostal do kódu, ktorý hru spúšťa. Manifest cárstva nemá zoznam games; kód stále hovorí o sekcii (Realms.registerSection, tag section: na 94 položkách obsahu) a „hra“ je zatiaľ v tabuľke balíkov a v priečinkoch. Minihry, hlavolamy a lekcie ležia v tých istých troch dátových súboroch ako predtým (18 minihier = 13 + 5, 28 hlavolamov = 5 + 23, 7 lekcií = 6 + 1), len v games/stacks/data/. Podľa DESIGN §95.6 a docs/KASTGARD-GAMES.md zostáva:
- K7: obsah, ktorý hra registruje. Minihry kampane stoja na 5., 7., 10., 13. a 17. mieste z osemnástich, preto analýza odporúča pole
aftera test, ktorý porovná zoznam po položkách; - K8: spoločné huby Minigames a Puzzle Labs, až keď sa objaví prvý obsah pre inú hru než Stacks;
- K9: predvoľby (Kniežatstvá, šablóny, náhodná hra) ako dáta, podľa analýzy v tvare spoločnom s predvoľbami Čiar;
- K11: voliteľné premenovanie „sekcia“ na „hra“ v identifikátoroch;
- M8b: spomenutých 112 hrán z
core, ktoré urobia zkastgard/stacksčistý balík a z kampane voliteľnú; - rozdelenie jazykových katalógov podľa balíkov; časti Kastgardu sa majú rodiť už v
js/realms/kastgard/…/i18n/.
Krok K10, premenovanie režimu Klasik na Kniežatstvá (Principalities), sa zlúčil o päť minút po presune (31. 10. o 3:51, DESIGN §97). Je to zobrazovaný názov a nič iné; ID classic ostáva.
Čo si z toho odnášam
- Presun je posledný krok, nie prvý.
git mvje v ňom najmenšia časť; zvyšok sa pripravuje tak, aby sa dal overiť. - Nástroj, ktorý prepisuje, nesmie zabúdať.
formatTablepotichu zahodil pole, ktoré nepoznal; našlo to až skúšobné spustenie na kópii stromu, pred akýmkoľvek zlúčením. - Rovnaké triedy slepých škvŕn sa vracajú v každom kroku: skladaná cesta, URL s lomkou, hĺbka v
.., nástroj čítajúci starý commit, text zaznamenaný vo fixtúre, hračkový strom v teste. Tabuľka vyššie je kontrolný zoznam pre ďalší presun. - Číslo 120 sa nemenilo a to je výsledok. Čistenie hrán je ďalšia práca a robí sa už na konečných miestach súborov, nie dvakrát.
Zdroje a poznámky
- Model a poradie:
docs/KASTGARD-GAMES.md(časti 2.1, 3 a 6),docs/DESIGN.md§95 (zistenia a dôkazy) adocs/KASTGARD-MOVED.md(odkazy, ktorémove.jsneprepíše). - Čísla:
node tools/packages.js --checkz 31. 10. 2026 (hra 0.65.6),git logagit diff -M --name-statuspre kroky K4 a K6. - Plán, nie hotová vec: kroky K7 až K11 a M8b z
docs/KASTGARD-GAMES.md.
Čo sa nepodarilo overiť: dôkazy (188 odtlačkov, kalibrácia, 3 268 testov, migrácie, zostavenie, panel prehliadača) sa pri písaní nespustili znova a prevzali sa z DESIGN §95.4. Počty súborov, premenovaní a hrán sa overili čítaním. Či hráč „nič nezbadal“, sa overiť nedá: dokázala sa rovnosť výstupov, nie pozorovanie ľudí.
Poznámky
- Do verzie 0.65.6 z 31. októbra 2026 sa volal Klasik. ↩︎