Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ együttes megadására hibát ad.
| Horgony: a `szakaszokraBont()` horgonya bit szerint egyezik az `mdRender()`-ével (`-2`, `-3` utótagokkal) | `packages/szoveg/src/szakaszok.ts`, `apps/web/lib/md.ts` | `packages/szoveg/test/szakaszok.test.ts` |
| XSS: minden szövegcsomópont `esc()`-en megy át; a horgony-id `[a-z0-9-]`; csak a rögzített tag-készlet kerül ki | `apps/web/lib/md.ts` | `packages/szoveg/test/md-xss.test.ts` |
| Keresési kiemelés STX/ETX, nem HTML | `packages/pipeline/supabase/02-`, `04-`, `05-*.sql`; `apps/web/app/kereses/page.tsx` | `kapuk.yml` `kiemeles` job (grep az SQL-ekre és a `dangerouslySetInnerHTML`-re) |
| Rossz adat nem kerül az adat-repóba: szerkezeti hibánál a delta semmit nem commitol, terjedelem-anomáliánál az érintett jogszabályt kihagyja | `packages/pipeline/src/delta.ts`, `health.ts` | `packages/pipeline/test/health.test.ts` (terjedelem-őr, szétcsúszás-őr, parser-őrfeltételek; a delta commit-elhagyó ága maga teszteletlen) |
| Rossz adat nem kerül az adat-repóba: szerkezeti hibánál a delta semmit nem commitol, terjedelem-anomáliánál a jogszabály anomáliás és aznapi későbbi állapotait kihagyja, a korábbiak bekerülnek az indexbe | `packages/pipeline/src/delta.ts`, `health.ts` | `packages/pipeline/test/health.test.ts` (terjedelem-őr, szétcsúszás-őr, parser-őrfeltételek, `bekerultAllapot()`, `helyreallitasKell()`; a delta commit-elhagyó ága maga teszteletlen) |
| Az index-szinkron hibája nem buktatja a deltát | `delta.ts` `keresoIndexSzinkron()` | csak a kód |
| A diff szerver oldalon renderel | `apps/web/components/DiffNezet.tsx` | csak a kódkomment |
| A `napi-delta.yml` két példánya byte-azonos | `packages/pipeline/adatrepo/napi-delta.yml` ↔ `godavid/magyar-jog` | `kapuk.yml` `napi-delta-masolat` job (heti `cmp` az élő példánnyal; PR-en nem fut) |
Expand Down
7 changes: 4 additions & 3 deletions docs/uzemeltetes.md
Original file line number Diff line number Diff line change
Expand Up @@ -196,9 +196,10 @@
Tünet: piros napi delta futás + `parser-riasztas` issue. Szerkezeti hibánál (cím-,
hatálydátum-eltérés, ismeretlen osztály, splicing) a delta SEMMIT nem commitol —
rossz adat nem kerülhet a repóba. A terjedelem-anomália ezzel szemben
JOGSZABÁLYONKÉNTI: az érintett jogszabályt (és aznapi további állapotait) kihagyja,
a többit normálisan commitolja, a végén külön issue-val riaszt, és a kihagyott
állapotokat a következő futások újra megpróbálják. (2026-08-26-tól kilenc napig
JOGSZABÁLYONKÉNTI: az anomáliás állapotot (és a jogszabály aznapi további állapotait)
kihagyja, a korábbi mai állapotait és a többi jogszabályt normálisan commitolja és
indexeli, a végén külön issue-val riaszt, és a kihagyott állapotokat a következő
futások újra megpróbálják. (2026-08-26-tól kilenc napig
egyetlen módosító törvény duzzadása miatt 37 más törvény állapota sem került be —
ez volt a tanulság.)

Expand Down
44 changes: 25 additions & 19 deletions packages/pipeline/src/delta.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ import { markdownGeneralas } from "./normalize.js";
import { megjelolesIllesztes, parsolSnapshot } from "./parse.js";
import { naploIras, type FelvetelTetel } from "./felvetel.js";
import {
bekerultAllapot,
helyreallitasKell,
modositoBlokkValtozas,
modositoTorveny,
regebbiAllapot,
Expand Down Expand Up @@ -102,14 +104,21 @@ async function retegTerkepMentes(terkep: RetegTerkep): Promise<void> {
}

/**
* Terjedelem-anomáliára futott jogszabályok (slug → a hiba üzenete). Ezeket a
* futás kihagyja — a mai további állapotaikkal együtt, hogy a HEAD ne egy
* későbbi állapotot mutasson, miközben egy korábbi hiányzik —, a többi
* jogszabály viszont normálisan bekerül. A végén riasztunk. Egy jogszabály
* tartalmi anomáliája nem állíthatja le az egész napi frissítést: 2026-08-26-tól
* kilenc napig egyetlen módosító törvény miatt 37 új időállapot nem került be.
* Terjedelem-anomáliára futott jogszabályok (slug → az anomáliás állapot napja
* és a hiba üzenete). Az anomáliás állapotot a futás kihagyja — a jogszabály
* mai további állapotaival együtt, hogy a HEAD ne egy későbbi állapotot
* mutasson, miközben egy korábbi hiányzik. Az anomália előtti mai állapotai
* viszont már commitolódtak, ezek bekerülnek (bekerultAllapot()), ahogy a többi
* jogszabály is. A végén riasztunk. Egy jogszabály tartalmi anomáliája nem
* állíthatja le az egész napi frissítést: 2026-08-26-tól kilenc napig egyetlen
* módosító törvény miatt 37 új időállapot nem került be.
*/
const anomaliak = new Map<string, string>();
const anomaliak = new Map<string, { datum: string; uzenet: string }>();

/** A mai esemény ténylegesen bekerült-e (commitolódott-e) az adat-repóba. */
function bekerultEsemeny(e: UjEsemeny): boolean {
return bekerultAllapot(e.allapot.hatalyba, anomaliak.get(e.js.slug)?.datum);
}

async function fut(): Promise<void> {
if (!existsSync(join(ADAT_REPO_DIR, "index", "allapotok.json"))) {
Expand Down Expand Up @@ -257,7 +266,7 @@ async function fut(): Promise<void> {
});
} catch (e) {
if (!(e instanceof TerjedelemAnomalia)) throw e;
anomaliak.set(js.slug, e.message);
anomaliak.set(js.slug, { datum: allapot.hatalyba, uzenet: e.message });
console.error(`[kihagyva] ${e.message}`);
continue;
}
Expand All @@ -279,29 +288,26 @@ async function fut(): Promise<void> {
);
}
if (uzenetSorok.length === 0) continue; // a nap minden tétele kimaradt
const nevek = napiak
.filter((n) => !anomaliak.has(n.js.slug))
.map((n) => n.js.rovidites ?? n.js.megjeloles);
const nevek = napiak.filter(bekerultEsemeny).map((n) => n.js.rovidites ?? n.js.megjeloles);
const cim =
nevek.length === 1
? `${nevek[0]} — időállapot ${datum}`
: `Időállapotok ${datum}: ${nevek.join(", ")}`;
await commit(`${cim}\n\nForrás (njt):\n${uzenetSorok.map((s) => `- ${s}`).join("\n")}`, datum);
console.log(`Commit: ${datum} — ${nevek.join(", ")}`);
}
const bekerult = esemenyek.filter((e) => !anomaliak.has(e.js.slug));
const bekerult = esemenyek.filter(bekerultEsemeny);

// 2b. HEAD-helyreállítás: ha egy jogszabálynak ma csak a legutóbb ismert
// állapotánál régebbi állapota került be, a HEAD szövege a régi szöveg lett.
// A legutóbbi állapot szövegét a saját commitjából visszaírjuk és a saját
// dátumával újra commitoljuk, így a HEAD soha nem áll vissza régebbi
// szövegre. (Ez a git-ág teszteletlen: a regebbiAllapot() döntése tesztelt.)
// szövegre. (Ez a git-ág teszteletlen: a regebbiAllapot() és a
// helyreallitasKell() döntése tesztelt.)
for (const { js, utolso } of helyreallitasok.values()) {
if (anomaliak.has(js.slug)) continue; // ma semmi nem került be belőle
const maiLegujabb = bekerult
.filter((e) => e.js.slug === js.slug)
.reduce<string>((m, e) => (e.allapot.hatalyba > m ? e.allapot.hatalyba : m), "");
if (!maiLegujabb || maiLegujabb >= utolso.datum) continue; // a HEAD már a legújabbat mutatja
// anomáliás jogszabálynál is: az anomália előtti mai állapota már commitolódott
const maiDatumok = bekerult.filter((e) => e.js.slug === js.slug).map((e) => e.allapot.hatalyba);
if (!helyreallitasKell(maiDatumok, utolso.datum)) continue;
if (!utolso.sha) {
throw new Error(`HEAD-helyreállítás sikertelen: ${js.slug} ${utolso.datum} állapotához az indexben nincs sha`);
}
Expand Down Expand Up @@ -394,7 +400,7 @@ async function fut(): Promise<void> {
await keresoIndexSzinkron(valtozottSlugok, listaIndex, retegTerkep);

if (anomaliak.size > 0) {
const sorok = [...anomaliak.values()].map((s) => `- ${s}`).join("\n");
const sorok = [...anomaliak.values()].map((a) => `- ${a.uzenet}`).join("\n");
console.error(`${anomaliak.size} jogszabály terjedelem-anomália miatt kimaradt:\n${sorok}`);
await riaszt(
"Terjedelem-anomália — kézi ellenőrzés kell",
Expand Down
24 changes: 24 additions & 0 deletions packages/pipeline/src/health.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,30 @@ export function regebbiAllapot<T extends { datum: string }>(
return utolso && utolso.datum > ujDatum ? utolso : undefined;
}

/**
* Bekerült-e a jogszabály egy mai állapota, ha a jogszabály `anomaliaDatum`
* napú állapota terjedelem-anomáliára futott (undefined: nem futott).
*
* A napi delta dátum szerint növekvő sorrendben dolgozik, és az első anomália
* után a jogszabály további mai állapotait kihagyja; az anomália ELŐTTI mai
* állapotai viszont már commitolódtak. Ezeknek az indexbe, a felvételi naplóba
* és a HEAD-helyreállításba is be kell kerülniük (#38) — a jogszabály egészét
* kidobni ezért hiba.
*/
export function bekerultAllapot(datum: string, anomaliaDatum: string | undefined): boolean {
return anomaliaDatum === undefined || datum < anomaliaDatum;
}

/**
* Kell-e HEAD-helyreállítás: a jogszabály ma bekerült állapotai közül a
* legújabb is régebbi a legutóbb ismert állapotánál, így a HEAD szövege a régi
* szöveg lett. Ha ma semmi nem került be belőle, nincs mit helyreállítani.
*/
export function helyreallitasKell(maiDatumok: string[], utolsoDatum: string): boolean {
if (maiDatumok.length === 0) return false;
return maiDatumok.reduce((m, d) => (d > m ? d : m)) < utolsoDatum;
}

/** A terjedelem-őr hibája — a hívó ezt jogszabályonként kezeli, nem futás-szinten. */
export class TerjedelemAnomalia extends Error {}

Expand Down
34 changes: 34 additions & 0 deletions packages/pipeline/test/health.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { describe, expect, it } from "vitest";
import {
bekerultAllapot,
helyreallitasKell,
modositoBlokkValtozas,
modositoTorveny,
regebbiAllapot,
Expand Down Expand Up @@ -178,3 +180,35 @@ describe("regebbiAllapot (régebbi-állapot-őr, HEAD-helyreállítás)", () =>
expect(regebbiAllapot([], "1930-11-08")).toBeUndefined();
});
});

describe("anomáliás jogszabály mai bekerülése (#38)", () => {
// egy jogszabály két mai állapota: d1 átment és commitolódott, d2 anomáliás
const d1 = "2026-01-01";
const d2 = "2026-03-01";
const maiak = [d1, d2];
const bekerultek = (anomaliaDatum: string | undefined) =>
maiak.filter((d) => bekerultAllapot(d, anomaliaDatum));

it("az anomália előtti, már commitolt állapot bekerül, az anomáliás nem", () => {
expect(bekerultek(d2)).toEqual([d1]);
});
it("ha az első mai állapot anomáliás, semmi nem kerül be", () => {
expect(bekerultek(d1)).toEqual([]);
});
it("anomália nélkül minden mai állapot bekerül", () => {
expect(bekerultek(undefined)).toEqual([d1, d2]);
});
it("HEAD-helyreállítás kell, ha a bekerült d1 régebbi a legutóbb ismertnél", () => {
expect(helyreallitasKell(bekerultek(d2), "2026-02-01")).toBe(true);
});
it("nincs helyreállítás, ha a bekerült d1 nem régebbi a legutóbb ismertnél", () => {
expect(helyreallitasKell(bekerultek(d2), d1)).toBe(false);
expect(helyreallitasKell(bekerultek(d2), "2025-12-01")).toBe(false);
});
it("nincs helyreállítás, ha ma semmi nem került be", () => {
expect(helyreallitasKell(bekerultek(d1), "2026-02-01")).toBe(false);
});
it("több bekerült állapotnál a legújabb dönt", () => {
expect(helyreallitasKell(["2026-01-01", "2026-04-01"], "2026-02-01")).toBe(false);
});
});
Loading