Implementační plán — dopravní model /doprava (orchestrované workflow)
Implementační plán — dopravní model /doprava (orchestrované workflow)
Cíl: nástroj, kterým lze na zastupitelstvu i směrem k veřejnosti věrohodně ukázat, co udělá rozkopání konkrétní ulice s dopravou ve dvojměstí. Stavíme na stávajícím modelu v prohlížeči (MSA + BPR nad MapLibre); SUMO projekt slouží jen k závěrečnému ověření scénářů.
Model orchestrace
- Orchestrátor (Fable): spouští workflow fází, kontroluje výsledky mezi fázemi, dělá kroky vyžadující prohlížeč nebo rozhodnutí (data z mapové aplikace ŘSD, vizuální kontrola UI, schválení kalibrace), navrhuje commity.
- Sonnet: mechanické implementační úlohy s přesným zadáním — úpravy kódu podle specifikace, datové JSON soubory, dokumentace z dodaných podkladů.
- Opus: úlohy vyžadující úsudek — ladění kalibrace, adversariální verifikace změn, návrh metodiky, práce se SUMO.
- Každá fáze = jeden workflow (Workflow tool). Mezi fázemi orchestrátor čte výsledky a rozhoduje o pokračování. Implementační agenti běží paralelně jen tam, kde mají disjunktní soubory a předem daný kontrakt rozhraní.
- Po každé fázi:
node doprava/tools/test_model.mjs+ ruční kontrola v prohlížeči (orchestrátor), commit až po schválení uživatelem.
Pořadí: fáze 0 → 1 jsou závazné (kalibrace potřebuje stabilní ID). Fáze 2–4 navazují volně, fáze 5 je volitelná (kdykoli po fázi 2).
Fáze 0 — Stabilní ID úseků
Uzavírky, sdílené URL i scénáře se dnes odkazují na pořadové číslo featury
v sit.geojson; každá regenerace sítě je přečísluje a rozbije odkazy.
Kontrakt rozhraní (závazný pro oba agenty): každá featura dostane
v properties stabilní klíč osm ve tvaru "<OSM way id>#<pořadí segmentu>";
JS používá osm, a pokud v datech chybí (síť ještě nepřegenerovaná),
spadne zpět na číselné id. Neznámé klíče z URL se tiše přeskočí
s upozorněním uživateli.
| Úloha | Agent | Soubory |
|---|---|---|
A. Klíč osm do generátoru sítě |
Sonnet | tools/stahni_sit.py |
| B. Uzavírky + URL hash na stabilní klíče | Sonnet | js/app.js, js/graf.js, js/mapa.js |
| C. Adversariální review A+B, spuštění testu | Opus | čtení + test_model.mjs |
D. Regenerace sítě (GitHub Actions doprava-osm-data.yml), kontrola odkazů |
orchestrátor | — |
Hotovo, když: regenerace sítě nezneplatní uložené scénáře ani sdílené odkazy (test: uzavřít most, zkopírovat URL, přegenerovat síť, otevřít znovu).
export const meta = {
name: 'doprava-faze0-stabilni-id',
description: 'Stabilní ID úseků sítě: generátor + JS přechod na klíče osm',
phases: [
{ title: 'Implementace', detail: 'dva sonnet agenti paralelně (disjunktní soubory)' },
{ title: 'Verifikace', detail: 'opus adversariální review + test' },
],
}
const DIR = '/Users/imac/Github/brandys-pirati/doprava'
const KONTRAKT = `KONTRAKT: každá featura v sit.geojson má v properties klíč "osm" = "<OSM way id>#<pořadí segmentu way>". JS preferuje "osm", fallback na číselné "id", neznámé klíče z URL tiše přeskočí a zobrazí upozornění. Piš česky komentáře i commit-ready kód, zachovej styl souborů.`
phase('Implementace')
const [py, js] = await parallel([
() => agent(`${KONTRAKT}\nUprav ${DIR}/tools/stahni_sit.py: při dělení way na segmenty přidej do properties featury klíč "osm" (way id + '#' + index segmentu v rámci way). Nic jiného neměň. Vrať stručné shrnutí změn a případná rizika.`,
{ label: 'stahni_sit.py', model: 'sonnet', phase: 'Implementace' }),
() => agent(`${KONTRAKT}\nUprav v ${DIR}/js soubory app.js, graf.js (a mapa.js jen pokud nutno): uzavírky (stav.zavrene), URL hash #u= a budoucí scénáře referencují stabilní klíč "osm" místo pořadového featId. Interně může zůstat mapování osm->featId vybudované při načtení sítě. Data sit.geojson zatím klíč "osm" NEobsahují — fallback na "id" musí fungovat. Vrať shrnutí změn.`,
{ label: 'js-stabilni-kluce', model: 'sonnet', phase: 'Implementace' }),
])
phase('Verifikace')
const verdikt = await agent(`Adversariálně zkontroluj čerstvé změny v ${DIR} (git diff): 1) dodržení kontraktu: ${KONTRAKT} 2) zpětná kompatibilita starých URL, 3) spusť node ${DIR}/tools/test_model.mjs a přilož výstup. Hledej, co je ROZBITÉ, ne co je hezké. Shrnutí změn implementátorů: PY: ${py} JS: ${js}`,
{ label: 'review', model: 'opus', phase: 'Verifikace',
schema: { type: 'object', properties: { ok: { type: 'boolean' }, problemy: { type: 'array', items: { type: 'string' } }, testVystup: { type: 'string' } }, required: ['ok', 'problemy'] } })
return { py, js, verdikt }
Krok D po workflow (orchestrátor): gh workflow run doprava-osm-data.yml,
po commitu nových dat ruční test odkazů.
Fáze 1 — Kalibrace na data ŘSD
Vstupní krok orchestrátoru (před workflow): z mapové aplikace sčítání
(scitani.rsd.cz, předběžná data CSD 2025; křížově finální CSD 2020) vypsat
profily v okolí — D10 (u exitů 8 a 14), II/610 (průtahy oběma městy),
II/101, II/331, II/245 — a předat je workflow jako args
(RPDI, podíl těžkých vozidel, poloha/název úseku). Mapová aplikace je
JS bez API, tohle se agentům delegovat nedá.
| Úloha | Agent | Výstup |
|---|---|---|
A. data/kalibrace.json z podkladů + mapování na úseky modelu |
Sonnet | kalibrace.json |
B. GEH srovnávací tabulka do test_model.mjs |
Sonnet | rozšířený test |
C. Iterativní ladění zony.json (max 6 kol) |
Opus (smyčka) | vyladěné parametry |
| D. Kontrola struktury poptávky proti ČSÚ dojížďce 2021 | Opus | zpráva |
E. docs/kalibrace.md — tabulka model vs. měření |
Sonnet | dokumentace |
| F. Schválení kalibrace | orchestrátor + uživatel | — |
Hotovo, když: GEH < 5 na ≥ 2/3 profilů, průtahy + most ±20 % vůči měření; tabulka zveřejněná v dokumentaci.
export const meta = {
name: 'doprava-faze1-kalibrace',
description: 'Kalibrace modelu na profily ŘSD (CSD 2025/2020), GEH tabulka, ladění zon',
phases: [
{ title: 'Priprava', detail: 'kalibrace.json + GEH test (sonnet, paralelně)' },
{ title: 'Ladeni', detail: 'opus smyčka nad zony.json' },
{ title: 'Zaver', detail: 'ČSÚ kontrola + dokumentace' },
],
}
// args = { profily: [{ id, nazev, silnice, rok, rpdi, podilTezkych, popisPolohy }, ...] }
const DIR = '/Users/imac/Github/brandys-pirati/doprava'
if (!args || !Array.isArray(args.profily) || !args.profily.length) throw new Error('args.profily chybí — nejdřív vypsat profily z scitani.rsd.cz')
phase('Priprava')
const [kal, geh] = await parallel([
() => agent(`Vytvoř ${DIR}/data/kalibrace.json z těchto profilů ŘSD: ${JSON.stringify(args.profily)}. Ke každému profilu najdi v ${DIR}/data/sit.geojson odpovídající úsek (podle silnice a polohy) a doplň jeho stabilní klíč "osm". Špičkovou hodinovou intenzitu odvoď koeficientem 0.09 z RPDI (ulož koeficient do souboru, ať je změnitelný). Vrať JSON se seznamem profilů a jistotou mapování (vysoká/nízká) u každého.`,
{ label: 'kalibrace.json', model: 'sonnet', phase: 'Priprava' }),
() => agent(`Rozšiř ${DIR}/tools/test_model.mjs: po výpočtu základního scénáře načti data/kalibrace.json (formát: profily s klíčem "osm" a špičkovou intenzitou) a vypiš tabulku model vs. měření včetně GEH statistiky (GEH = sqrt(2*(M-C)^2/(M+C)), M=model, C=měření, obojí voz/h) a souhrn: kolik profilů má GEH<5. Musí fungovat i bez kalibrace.json (přeskočí se). Vrať shrnutí.`,
{ label: 'geh-test', model: 'sonnet', phase: 'Priprava' }),
])
phase('Ladeni')
let stav = 'první kolo, zatím nic neladěno'
let vysledek = null
for (let kolo = 1; kolo <= 6; kolo++) {
vysledek = await agent(`Ladíš kalibraci dopravního modelu v ${DIR}. Spusť node ${DIR}/tools/test_model.mjs, prostuduj GEH tabulku. Pokud kritérium (GEH<5 na >=2/3 profilů A průtahy+most do ±20 %) splněno, nic neměň a vrať hotovo=true. Jinak uprav ${DIR}/data/zony.json (váhy w podle reálných počtů obyvatel částí města — ověř webem, tripRate, tau, tauBrana, intenzity bran, matice pruchozi), spusť test znovu a vrať výsledek. Neměň kód modelu, jen parametry. Kontext z minulých kol: ${stav}`,
{ label: `ladeni-kolo-${kolo}`, model: 'opus', phase: 'Ladeni',
schema: { type: 'object', properties: { hotovo: { type: 'boolean' }, gehOk: { type: 'integer' }, gehCelkem: { type: 'integer' }, zmeny: { type: 'string' }, tabulka: { type: 'string' } }, required: ['hotovo', 'zmeny', 'tabulka'] } })
log(`Kolo ${kolo}: GEH ok ${vysledek.gehOk}/${vysledek.gehCelkem}`)
if (vysledek.hotovo) break
stav = `kolo ${kolo}: ${vysledek.zmeny}; tabulka: ${vysledek.tabulka}`
}
phase('Zaver')
const [csu, dokum] = await parallel([
() => agent(`Ověř strukturu poptávky modelu ${DIR} proti veřejným datům ČSÚ o dojížďce (SLDB 2021): hlavní proudy Brandýs n. L.-Stará Boleslav <-> Praha, Čelákovice, Mladá Boleslav. Porovnej řádově s OD parami modelu (viz js/poptavka.js + data/zony.json). Vrať zprávu: sedí/nesedí a doporučené korekce.`,
{ label: 'csu-dojizdka', model: 'opus', phase: 'Zaver' }),
() => agent(`Napiš ${DIR}/docs/kalibrace.md: metodika kalibrace (zdroje ŘSD CSD 2025 předběžná / CSD 2020, koeficient špičkové hodiny), finální srovnávací tabulka model vs. měření s GEH: ${JSON.stringify(vysledek)}, datum, omezení. Česky, věcně, bez marketingu.`,
{ label: 'kalibrace.md', model: 'sonnet', phase: 'Zaver' }),
])
return { kal, geh, ladeni: vysledek, csu, dokum }
Fáze 2 — Kurátorované scénáře jako obsah
Formát data/scenare.json (kontrakt): pole objektů { id, nazev,
popis, stav: "planovano"|"probiha"|"hypoteticky", termin, odkaz,
useky: [stabilní klíče "osm"] }.
| Úloha | Agent | Soubory |
|---|---|---|
A. Loader scénářů + karty + #s=<id> sdílení, odstranit zadrátované SCENARE |
Sonnet | js/app.js, index.html, css/styl.css |
| B. Převod 3 stávajících scénářů do JSON + tlačítko „zkopírovat scénář” (export naklikaných uzavírek jako JSON blok) | Sonnet | data/scenare.json, js/app.js (jiná část) |
| C. Adversariální review + test | Opus | — |
| D. Vizuální kontrola v prohlížeči | orchestrátor | — |
Pozn.: A a B sahají oba do app.js → běží sekvenčně (pipeline),
B dostane shrnutí změn A.
Hotovo, když: nový výkop = jedna položka v JSON bez zásahu do JS;
scénář jde sdílet odkazem #s=<id>.
export const meta = {
name: 'doprava-faze2-scenare',
description: 'Kurátorované scénáře uzavírek jako data/scenare.json + export tlačítko',
phases: [{ title: 'Implementace', detail: 'sekvenčně (sdílený app.js)' }, { title: 'Verifikace' }],
}
const DIR = '/Users/imac/Github/brandys-pirati/doprava'
const FORMAT = `FORMÁT scenare.json: pole objektů { id, nazev, popis, stav: "planovano"|"probiha"|"hypoteticky", termin, odkaz, useky: [stabilní klíče "osm"] }. Česky, styl projektu.`
phase('Implementace')
const a = await agent(`${FORMAT}\nV ${DIR}: nahraď zadrátované pole SCENARE v js/app.js načítáním data/scenare.json; karty scénářů zobrazí termín a odkaz (úřední deska); sdílení scénáře přes hash #s=<id> (kombinovatelné s #u=). Vytvoř zatím prázdné/minimální data/scenare.json. Vrať shrnutí změn včetně názvů nových funkcí.`,
{ label: 'loader-scenaru', model: 'sonnet', phase: 'Implementace' })
const b = await agent(`${FORMAT}\nV ${DIR} (naváže na změny: ${a}): 1) převeď původní tři scénáře (most Maxe Švabinského, centrum Brandýsa, Boleslavská) do data/scenare.json — úseky dohledej v data/sit.geojson podle názvů ulic a polohy a použij jejich klíče "osm"; 2) přidej do panelu tlačítko „Zkopírovat scénář", které z aktuálně naklikaných uzavírek sestaví JSON blok ve formátu scénáře a zkopíruje do schránky. Vrať shrnutí.`,
{ label: 'export-a-data', model: 'sonnet', phase: 'Implementace' })
phase('Verifikace')
const verdikt = await agent(`Adversariálně zkontroluj git diff v ${DIR}: ${FORMAT} Ověř: staré URL #u= fungují, #s= načte scénář, prázdný/vadný scenare.json nerozbije aplikaci, export tlačítko generuje validní formát. Spusť node ${DIR}/tools/test_model.mjs. Změny: A: ${a} B: ${b}`,
{ label: 'review', model: 'opus', phase: 'Verifikace',
schema: { type: 'object', properties: { ok: { type: 'boolean' }, problemy: { type: 'array', items: { type: 'string' } } }, required: ['ok', 'problemy'] } })
return { a, b, verdikt }
Fáze 3 — Metriky srozumitelné laikovi
| Úloha | Agent | Soubory |
|---|---|---|
A. data/mista.json — 6–8 referenčních bodů (Masarykovo nám., centrum St. Boleslavi, poliklinika, nájezd D10, Vrábí, sídliště západ, Zápská) s ověřenými souřadnicemi |
Sonnet | data/mista.json |
| B. Panel „Typické cesty”: Dijkstra nad finálními časy hran před × po, zvýraznění nárůstů; scénář může určit relevantní dvojice | Sonnet | js/app.js, js/assignment.js (export), index.html, css |
| C. Review + kontrola věrohodnosti časů (srovnání s mapy.cz/Google) | Opus | — |
Hotovo, když: u aktivní uzavírky panel ukazuje „X → Y: A min → B min”.
export const meta = {
name: 'doprava-faze3-metriky',
description: 'Panel „Typické cesty" — doby jízdy mezi referenčními body před × po uzavírce',
phases: [{ title: 'Implementace' }, { title: 'Verifikace' }],
}
const DIR = '/Users/imac/Github/brandys-pirati/doprava'
phase('Implementace')
const mista = await agent(`Vytvoř ${DIR}/data/mista.json: 6–8 referenčních bodů dvojměstí (Masarykovo náměstí, centrum Staré Boleslavi, poliklinika Brandýs, nájezd D10 exit 14, Vrábí, sídliště západ, Zápská průmyslová zóna) — id, název, lon/lat ověřené přes OSM/web, a seznam výchozích dvojic pro panel (např. sb-centrum -> br-namesti). Vrať obsah souboru.`,
{ label: 'mista.json', model: 'sonnet', phase: 'Implementace' })
const panel = await agent(`V ${DIR} přidej panel „Typické cesty": po každém přepočtu spočítej Dijkstrou nad finálními BPR časy (funkce v js/assignment.js — exportuj co chybí) doby jízdy pro dvojice z data/mista.json (obsah: ${mista}); body přichytávej na síť stejně jako zóny (viz najdiUzel v js/graf.js). Zobraz „X → Y: A min → B min" se zvýrazněním nárůstů; bez uzavírky jen aktuální časy. Scénář v scenare.json může volitelně mít pole "cesty" s preferovanými dvojicemi. Vrať shrnutí.`,
{ label: 'panel-cesty', model: 'sonnet', phase: 'Implementace' })
phase('Verifikace')
const verdikt = await agent(`Zkontroluj git diff v ${DIR} (panel Typické cesty). Kromě korektnosti kódu ověř VĚROHODNOST: spusť node ${DIR}/tools/test_model.mjs, spočti si ručně z dat pár dob jízdy a porovnej s realitou (web: mapy.cz / Google směry, volný provoz). Odchylka >50 % = problém. Změny: ${panel}`,
{ label: 'review-verohodnost', model: 'opus', phase: 'Verifikace',
schema: { type: 'object', properties: { ok: { type: 'boolean' }, problemy: { type: 'array', items: { type: 'string' } }, srovnaniCasu: { type: 'string' } }, required: ['ok', 'problemy'] } })
return { mista, panel, verdikt }
Fáze 4 — Metodika a publikace
| Úloha | Agent | Výstup |
|---|---|---|
A. Stránka /doprava/metodika/: laická část + technická příloha (MSA, BPR, gravitační model, zdroje, kalibrační tabulka z fáze 1, omezení) |
Opus (návrh) → Sonnet (Jekyll stránka) | metodika |
| B. Oponentní čtení metodiky („čím by ji napadl dopravní inženýr / politický oponent”) | Opus | posudek |
C. Prolinkování z navigace webu a ze sekce /vykopy/ |
Sonnet | šablony webu |
| D. Kontrola na mobilu + finální projití | orchestrátor + uživatel | — |
Hotovo, když: stránka je odkázaná z webu, obstojí proti oponentnímu posudku a je použitelná z telefonu.
export const meta = {
name: 'doprava-faze4-metodika',
description: 'Stránka metodiky, oponentní posudek, prolinkování z webu',
phases: [{ title: 'Metodika' }, { title: 'Oponentura' }, { title: 'Publikace' }],
}
const DIR = '/Users/imac/Github/brandys-pirati'
phase('Metodika')
const navrh = await agent(`Navrhni obsah stránky metodiky dopravního modelu ${DIR}/doprava (přečti README.md, docs/kalibrace.md, js/assignment.js, js/poptavka.js). Dvě úrovně: 1) srozumitelně pro občana (co model umí/neumí, jak číst mapu), 2) technická příloha (MSA, BPR, gravitační model, zdroje ŘSD/ČSÚ/OSM, kalibrační tabulka, omezení — bez křižovatkových zdržení, orientační boční ulice). Česky. Vrať kompletní text v markdownu.`,
{ label: 'navrh-metodiky', model: 'opus', phase: 'Metodika' })
phase('Oponentura')
const oponentura = await agent(`Jsi kritický oponent (dopravní inženýr najatý protistranou). Najdi v této metodice všechna slabá místa, která by šla napadnout na zastupitelstvu, a navrhni, jak formulace zpevnit či doplnit: ${navrh}`,
{ label: 'oponent', model: 'opus', phase: 'Oponentura' })
phase('Publikace')
const stranka = await agent(`Vytvoř Jekyll stránku metodiky v repu ${DIR} (permalink /doprava/metodika/, zjisti konvence z existujících stránek, např. vykopy.md). Text: ${navrh}\nZapracuj doporučení oponenta: ${oponentura}\nPřidej odkazy: z aplikace /doprava (index.html, patička/panel) a ze sekce /vykopy/ na model i metodiku. Vrať seznam změněných souborů.`,
{ label: 'jekyll-stranka', model: 'sonnet', phase: 'Publikace' })
return { navrh, oponentura, stranka }
Krok D po workflow: orchestrátor projde web v prohlížeči (desktop + mobilní viewport), uživatel schválí publikaci.
Fáze 5 — Ověření mikrosimulací SUMO (volitelné)
| Úloha | Agent | Poznámka |
|---|---|---|
A. Oprava mechaniky uzavírek v sumo-brandys: hrany zakázat, duarouter přepočítá trasy (žádné mazání hran — vozidla se přesměrují, nezmizí) |
Opus | /Users/imac/Github/sumo/sumo-brandys |
B. Poptávka v SUMO ze stejných OD dat jako webový model (export ze zony.json + gravitační model) |
Opus | férové srovnání |
| C. Běh 2–3 kurátorovaných scénářů (most, průtah) + srovnávací tabulka | Sonnet (běhy) → Opus (interpretace) | docs/validace-sumo.md |
Hotovo, když: v metodice může stát „výsledky ověřeny nezávislou mikrosimulací SUMO” s odkazem na srovnání. Workflow skript vznikne až po fázi 2 (potřebuje finální formát scénářů) — úlohy A a B jsou na sobě nezávislé (parallel), C je pipeline přes scénáře.
Backlog (po základních fázích)
- Z reverifikace fáze 2 (okrajové případy fallbacku konektorů, vědomě odloženo): obklíčení OBOU uzlů brány slepí odjezdový/příjezdový pás do jednoho uzlu; náhradní uzel se hledá přísněji (obousměrná dosažitelnost) než původní přichycení bran a při nenalezení tiše vrátí zónu beze změny; přesun konektoru může snížit vozKm/vozH i při neobslouzeno=0 (řádově −0,7 %, jen při zavírání přímo u modelové brány) — pojistka MEZ_NEOBSLOUZENO to nepokrývá. Dále pre-existující závod při rychlém tahání posuvníkem intenzity (základna se nespočítá, dopad ukáže +0).
- Z reverifikace fáze 0 (vědomě odloženo): automatický test pořadí výpočtu
základny v
start()(logika s DOM, v Node se necvičí); assertklicUseku({osm}) === osma test guardu duplicit v graf.js; kosmetika hashe#u=,,(nezobrazí hlášku, hash zůstane viset). - Křižovatkové penalizace (odbočení vlevo, semafory) — zvěrní centrum.
- Vlastní sčítání dopravy na mostě a klíčových křižovatkách.
- Částečné uzavírky (kyvadlový provoz = snížená kapacita, třetí stav úseku).
- MHD vrstva (
mhd/) — dopad uzavírek na autobusové linky. - Tisková verze mapy pro materiály na zastupitelstvo.
Provozní poznámky
- Repo
brandys-pirati(GitHub Pages, deploy z gitu)./dopravanení do fáze 4 prolinkovaná — fáze 0–3 lze mergovat průběžně; fáze 4 je vědomý krok „jde to ven”. - Workflow skripty výše jsou připravené k přímému spuštění (Workflow tool);
fáze 1 vyžaduje
args.profilyod orchestrátora (data ze scitani.rsd.cz). - Commity navrhuje orchestrátor po schválené verifikaci každé fáze.