Audamir

č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.

· 13 min čítania

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).

91 súborov Kastgardu podľa balíka4 súbory v balíku kastgard, 67 v kastgard/stacks a 20 v kastgard/campaign: spolu 91 súborov v js/realms/kastgard/ (stav hry 0.63.7 a tabuľka balíkov z 31. októbra 2026).kastgard (manifest, režimy)4kastgard/stacks (hra s kockami)67kastgard/campaign (kampaň)20
Súbory js/realms/kastgard/ podľa balíka po presune (stav hry 0.63.7).

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:

KrokZlúčenéČoČísla
T1a (§72)01:20testy do priečinka balíka194 presunov, 1 607 odkazov v 246 súboroch, názvy všetkých 2 793 testov rovnaké
T1b (§73)03:47bežec tools/test.js --changedzmena pravidiel Kolónie: 24 zo 186 súborov, 49 s z 296 s
T2 (§74)07:16nástroje do tools/<balík>/79 súborov
T1c (§75)08:42testy zrkadlia priečinky js/127 súborov, test Kolónie rozdelený na štyri
T3 (§76)11:04testy nástrojov a fixtúrytools.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.

111 porovnaných výstupov a súborov: 103 rovnakých, 8 vysvetlených74 nástrojov sa pustilo na starom a novom kóde s rovnakými argumentmi: 89 výstupov je rovných bajt po bajte, 14 rovných inak (103 − 89), 8 sa líši z dôvodu, ktorý sa prečítal (čas, dočasné meno, skratka commitu, relatívna cesta).rovnaké bajt po bajte89rovnaké, nie bajt po bajte14líšia sa, dôvod je prečítaný8
Porovnanie starého a nového kódu s rovnakými argumentmi: 74 nástrojov. Z ôsmich rozdielov päť nesie čas.

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:

  1. K3: nástroje dostali pomôcku tools/paths.js a cesty už nepíšu ručne. Bez nej by move.js nechal 109 skladaných ciest v 25 súboroch.
  2. 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.
  3. 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 v js/.
  4. K6: až teraz sa presunul samotný kód js/, nástrojom move.js --package pre každý balík. CACHE v sw.js sa zvýšil raz (v72 → v73).
Poradie krokov presunu K1 až K6Kroky presunu podľa času autora z git log: K3 01:29, K1 01:40, K2 01:46, K4 01:59, K5 02:03 a K6 02:24 (31. októbra 2026). K6 je presun súborov js/.01:29 · K3 paths.js01:40 · K1 kampaň01:46 · K2 buildsOn01:59 · K4 testy02:03 · K5 tabuľka02:24 · K6 presun
Čas autora podľa git log. K4 až K6 sa do histórie zapísali neskôr.

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 cez path.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 importScripts v pevnom js/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.js a 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.js poznal novú obrazovku len ako súbor v js/ui/; bez opravy by nová obrazovka hry bola počítaná ako „fix“.
  • Pomôcka sama: Paths.dirOf medzi K4 a K6 hlásila priečinok balíka, ktorého súbory ešte ležali v js/. Opravené.
  • Drobnosti: hlavička Used by: v board-events.js a 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:

Porušenia smeru závislostí: 120 hrán pred presunom aj po ňomHrany, ktoré hlási node tools/packages.js --check z 31. októbra 2026: core do kastgard/stacks 65, core do kastgard/campaign 45, kastgard/stacks do kastgard/campaign 4, core do kastgard 2, core do taflgard, colony a chains 4.core → kastgard/stacks65core → kastgard/campaign45kastgard/stacks → kastgard/campaign4core → kastgard2core → taflgard, colony, chains4
Hrany, ktoré hlási node tools/packages.js --check z 31. októbra 2026; spolu 120 hrán v 22 súboroch.

Čí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:

VrstvaVýsledok
tri poistky po každom krokuexit 0, 120 hrán v 22 súboroch
baseline.js, calibrate.js --verifyvšetkých 188 odtlačkov hry sedí; 18 meraní kalibrácie identických, 0 zmenených
replay.js --golden, --golden-mapszlaté 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óduvšetky „as promised“; colony-id-migration zlyháva aj bez presunu s rovnakým textom
build.js --checkobe 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 klikyhub 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.jsgen-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á sadaprvý 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 after a 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 z kastgard/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 mv je v ňom najmenšia časť; zvyšok sa pripravuje tak, aby sa dal overiť.
  • Nástroj, ktorý prepisuje, nesmie zabúdať. formatTable potichu 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) a docs/KASTGARD-MOVED.md (odkazy, ktoré move.js neprepíše).
  • Čísla: node tools/packages.js --check z 31. 10. 2026 (hra 0.65.6), git log a git diff -M --name-status pre 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

  1. Do verzie 0.65.6 z 31. októbra 2026 sa volal Klasik. ↩︎