36.4 IX. ellenőrző pont: működő rendszer és bizonyítékai

Átvételi követelmény: a bemutatóban a hibás bemenetet, a hiányzó címkét és a jogosulatlan hozzáférési próbát is demonstrálni kell. A sikeres normál futás nem bizonyítja a helyreállíthatóságot és a biztonságot.

36.4.1 Cél és konkrét helyzet

A korábbi ellenőrző pontokon egy szivárgásmentes modellt építettünk (VI. ellenőrző pont: szivárgásmentes modellkísérlet), csomagként átadhatóvá tettük (VIII. ellenőrző pont: átadható modellprojekt), és release-feltételekkel kiadtuk (Kiadás, visszaállítás és terhelési próba). Most a kérdés az, hogy a futó rendszerről milyen bizonyítékokat gyűjtünk, és mit teszünk, ha a bizonyíték hibát mutat. A IX. ellenőrző pont ezért nem egy szűk programozási feladat, hanem egy mérési és hibakezelési terv, amelyet a Northstar késői kézbesítés modelljén futtatunk végig.

A konkrét helyzet: a northstar-late modell minden rendeléskor becsüli, hogy a kézbesítés 7 napnál később lesz-e. Reggelenként batch módban 5000 rendelési rekordot pontozunk, napközben pedig egy kis FastAPI-végpont válaszol egyedi kérésekre. A bemenet rendelésenként az Adatéletciklus és a predikció pillanata alfejezetben rögzített, a rendelés pillanatában ismert feature-vektor; a megfigyelési egység egy order_id/request_id; a kimenet pred_prob, pred_label, model_version és request_id. Az igazi target_late csak a kézbesítés után, tehát késleltetve érkezik meg. A rendszer LOCalhoston, CPU-n fut, nincs felhő, fizetős API vagy titkos ügyféladat.

Az elvárt ellenőrzés: a p95 válaszidő legfeljebb 250 ms; a batch futás 5000 soron legfeljebb 60 másodperc; 30 napos referenciaablakhoz képest a folytonos feature-ök PSI driftje 0,1 alatt marad; a 7 napnál régebbi kérések legalább 95%-ában rendelkezésre áll a címke; a rollback 5 percen belül visszaáll egy ismert verzióra; a szolgáltatás csak a szükséges jogosultságokkal fér a titkokhoz és a modellhez.

Induló becslés a megoldás előtt: egy naplóban 20 kérés késleltetése érkezett, rendezve: 8, 9, 10, 11, 12, 12, 13, 14, 15, 15, 16, 17, 18, 20, 21, 22, 25, 31, 48, 510 ms. Körülbelül mekkora a p95? Mielőtt tovább olvasol, válaszolj egy számmal, és indokold, miért veszélyes ebből a 20 mintából a valódi farokról dönteni.

36.4.2 Fogalmi magyarázat: a hat működési blokk

36.4.2.1 Compute budget: erőforrás-keret

A compute budget (számítási keret) egy megállapodás arról, hogy egy futtatási egység mennyi CPU-időt, memóriát, késleltetést és tárhelyet használhat. A cél nem az, hogy mindig alacsony legyen a terhelés, hanem hogy előre ismert korlátunk és mérésünk legyen. Az API esetén a kulcsmutató a válaszidő-eloszlás p95 kvantilisa. Ha nn mért késleltetés van, rendezzük őket növekvő sorrendbe: L(1)≤L(2)≤…≤L(n)L_{(1)} \le L_{(2)} \le \dots \le L_{(n)}. Az alsó 95%-os tapasztalati kvantilis az a L(k)L_{(k)}, ahol kk a legkisebb egész, amelyre k/n≥0.95k/n \ge 0.95. A mértékegység ms, a shape egy nn hosszú vektor.

A 20 elemű példában n=20n=20, tehát k=19k=19, és a p95 a 19. rendezett érték, azaz 48 ms. Ez megfelel annak, hogy a mérések 95%-a legfeljebb 48 ms, és 5%-uk, azaz egyetlen kérés, lassú. A legnagyobb érték, 510 ms, a farokban van, ezért a p95 robusztusabb, mint a maximum, de még így is erősen függ a minta elemszámától.

A batch munkánál a keret a teljes futási időre és memóriára vonatkozik. A p95-öt becsülhetjük a fejlesztőgépen ismételt méréssel, azonban teljesítményállításhoz hardver, inputméret, verzió és ismétlésszám is kell. Az alábbi chart egy számított függvénypélda arra, hogyan nőhet a válaszidő a párhuzamos terheléssel:

Szemléltető párhuzamos terhelés és válaszidő - A latency=30+0.4*concurrency^2 képletből számított példa, nem mérés.

A görbe csak a tervezési logikát mutatja: amíg a párhuzamos terhelés a CPU korlát alatt van, a válaszidő közel állandó; utána a sorban állás miatt meredeken nő. A tényleges méréshez a Kiadás, visszaállítás és terhelési próba alfejezetben tanult load budget tesztet kell futtatni.

36.4.2.2 Batch és API: két kiszolgálási szerződés

A batch és API nem ugyanaz a modell kétféle meghívása, hanem két külön szerződés. A batch inputja egy előre összegyűjtött fájl vagy tábla; a futás azonosítóval rendelkezik, az output idempotens, tehát ugyanaz a futás ugyanazt az eredményfájlt állítja elő. Az API inputja egyetlen kérés; a válasznak gyorsnak kell lennie, és a szerződés a /health, /ready, séma és verzió mezőket is tartalmazza.

A döntési lap három kérdésből áll: milyen késleltetést bír el a folyamat, mekkora a tranzakciós egység, és mi történjen, ha a futás félbeszakad? A rendeléskor hozott döntéshez API kell, mert a választ azonnal felhasználjuk. A napi riport vagy modellminőségi utóellenőrzés viszont batch, mert a teljes forgalmat egyben, lassabban is feldolgozhatjuk, és a függőséget jobban rögzítjük.

36.4.2.3 Drift: az input eloszlásának eltérése

A drift (adateltolódás, data drift) azt jelenti, hogy a szolgáltatás inputjának eloszlása eltér a modellépítéskori vagy a referenciaablak szerinti eloszlástól. A Population Stability Index (PSI) a folytonos feature-öt diszkrét bucketekre osztja, és a referencia- meg az aktuális gyakoriságok eltérését méri:

PSI=∑i=1B(ai−ei)ln(aiei), \mathrm{PSI} = \sum_{i=1}^{B} (a_i - e_i)\ln\left(\frac{a_i}{e_i}\right),

ahol BB a bucketek száma, eie_i a referenciaablakban az ii. bucketbe eső rendelések aránya, aia_i pedig a friss ablakban mért arány. Az eie_i és aia_i egyaránt BB hosszú vektor, minden elemük 0 és 1 közötti arány, mértékegység nélkül, és ∑iei=∑iai=1\sum_i e_i = \sum_i a_i = 1. A PSI értéke 0-tól felfelé terjed; 0 akkor, ha a két eloszlás azonos, nagyobb érték erősebb eltérést mutat. Ha valamelyik bucket üres, a tagot kihagyjuk vagy kis epszilont használunk.

Kézi kontroll két bucketre: legyen e=[0.5,0.5]e=[0.5,0.5], a=[0.6,0.4]a=[0.6,0.4]. Ekkor

PSI=(0.6−0.5)ln(0.60.5)+(0.4−0.5)ln(0.40.5)=0.1ln(1.2)−0.1ln(0.8)≈0.0405. \mathrm{PSI} = (0.6-0.5)\ln\left(\frac{0.6}{0.5}\right) + (0.4-0.5)\ln\left(\frac{0.4}{0.5}\right) = 0.1\ln(1.2) - 0.1\ln(0.8) \approx 0.0405.

A 0,1 alatti PSI-t gyakran stabilnak, a 0,1 és 0,25 közöttit figyelmeztetésnek, a 0,25 felettit erős eltérésnek tekintik, de ez heurisztika, nem statisztikai garancia. A PSI nem mondja meg, hogy a drift rontja-e a modellt; először a predikció és a későbbi címke közötti teljesítményt kell nézni. Folytonos feature-ökre a scipy.stats.ks_2samp is adhat p-értéket, de a p-érték itt is a nullmodell szerinti szélsőséget méri, nem a drift valószínűségét.

36.4.2.4 Delayed labels: a késleltetett címkék cenzúrája

A delayed label (késleltetett címke) azt jelenti, hogy a predikció pillanatában még nem ismerjük a valódi eredményt. A Northstar adatban a label_available_at az actual_delivery_at értékével egyezik, tehát a címke csak a teljes kézbesítés után áll rendelkezésre. Ha egy rendelés OO időben érkezik, és a kézbesítésig eltelt idő DD, akkor a TT időpontban a címke pontosan akkor ismert, ha O+D≤TO+D \le T. A DD eloszlásfüggvénye F(d)=P(D≤d)F(d)=P(D\le d); ezzel a TT-ben megfigyelhető, legalább ww napos rendelések arányának várható értéke F(w)F(w). Az F(d)F(d) értéke 0 és 1 közötti valószínűség, dd mértékegysége nap, az input shape pedig a rendelésekhez tartozó {0,1}\{0,1\} label-availability vektor.

A legfontosabb statisztikai veszély a korai mérés szelektív torzítása. A 7 napos cél esetén a pozitív esetek egy része eleve csak 8. vagy későbbi napon derül ki. Ha a 2. napon számolunk modellminőséget, akkor a gyorsan kézbesített, túlnyomórészt negatív esetekre látunk címkét, a lassú pozitív esetekre nem. Az így kapott AUC vagy accuracy optimista. Ez ugyanaz a leakage-logika, mint a VI. ellenőrző pont: szivárgásmentes modellkísérlet alfejezetben: a mérés pillanatában még nem megérkezett címkét nem vonhatjuk be az értékelésbe, és a hiányzó címkét nem tölthetjük fel hallgatólagosan nullával.

36.4.2.5 Rollback: előre rögzített visszaállítás

A rollback (visszaállítás) nem a hiba bekövetkezésekor kitalált improvizáció, hanem release-kori döntési szabály. Rögzítjük, hogy mely feltételek váltják ki, melyik verzióra állunk vissza, és hogyan ellenőrizzük a visszaállítás eredményét. A feltételek lehetnek: p95 késleltetés tartósan a budget fölött, a batch output sémája nem egyezik a manifesttel, a PSI-riasztást nem tudjuk üzleti eseménnyel magyarázni, vagy a címkék késése miatt a modellminőségi ablakban a hiba elszabadul. Maga a visszaállítás pointer-váltás: a live pointer egy korábbi, hash-elt modellverzióra mutat.

36.4.2.6 Access: hozzáférési határ

A Hozzáférés, titkok és adatminimalizálás alfejezetben tanított elvek itt futási feltétellé válnak. A szolgáltatásnak csak a modell olvasására, a metrikák írására és a saját naplójára van joga; nyers rendelési adathoz vagy a tanító adathoz nem fér. A titkok környezeti változóban élnek, nem a kódban; a napló redaction-szabálya kitakarja a tokeneket, kulcsokat és személyes azonosítókat; a retention pedig meghatározza, hogy a nyers kérések meddig őrizhetők. A provider boundary azt is rögzíti, hogy ha egy külső szolgáltatás kap adatot, az átadott mezők listája és a törlési folyamat előre dokumentált.

36.4.3 Teljes minimális munkapélda: incidens-szimuláció

A példa nem valódi futási jegyzőkönyv, hanem szemléltető, helyi CPU-n futtatható terv. A munkakönyvtár legyen northstar-monitor/. Először szimulált szolgáltatásnaplót készítünk, hogy a későbbi SQL- és Python-mutatók determinisztikusak legyenek:

# generate_service_log.py
from pathlib import Path
import csv
import random
from datetime import datetime, timedelta, timezone

random.seed(20261020)
out = Path("data/service_log.csv")
out.parent.mkdir(exist_ok=True)

start = datetime(2025, 6, 1, tzinfo=timezone.utc)
rows = []
for i in range(5000):
    order_at = start + timedelta(minutes=30 * i)
    distance_km = random.gamma(2.0, 40.0)
    priority_flag = 1 if random.random() < 0.2 else 0
    basket_minor = random.randint(500, 25000)
    latency_ms = int(random.lognormvariate(3.2, 0.6))
    model_version = "northstar-late-0.3.0"
    pred_prob = round(min(0.9, max(0.02, 0.05 + 0.003 * distance_km + 0.15 * priority_flag)), 4)
    request_id = f"req-{i:05d}"
    rows.append([request_id, order_at.isoformat(), distance_km, priority_flag,
                 basket_minor, latency_ms, model_version, pred_prob])

with out.open("w", newline="") as f:
    writer = csv.writer(f)
    writer.writerow(["request_id", "order_at", "distance_km", "priority_flag",
                     "basket_minor", "latency_ms", "model_version", "pred_prob"])
    writer.writerows(rows)

print("wrote", len(rows), "rows")

A kód egyetlen seedből 5000 kérést készít. A predikciós valószínűség determinisztikus függvénye a távolság és prioritás jellemzőknek, tehát itt nincs valódi modellbetöltés, de a séma ugyanaz, mint a VIII. ellenőrző pont: átadható modellprojekt alfejezetben átadott predikciós szerződés. A pred_prob a 0,02–0,90 intervallumba van vágva; a valódi modell kalibrált valószínűsége is 0 és 1 közé esik.

A batch-kontroll és a p95 lekérdezése DuckDB SQL-ben:

-- batch latency control, DuckDB
SELECT
  date_trunc('day', order_at::TIMESTAMP) AS day,
  count(*) AS requests,
  quantile_cont(latency_ms, 0.95) AS p95_latency_ms,
  count(*) FILTER (WHERE latency_ms > 250) AS over_budget_requests
FROM 'data/service_log.csv'
GROUP BY 1
ORDER BY 1;

Ez a lekérdezés napi bontásban adja a kérésszámot, a p95 késleltetést és a költségvetés feletti kérések számát. A quantile_cont DuckDB-függvény; SQLite-ban hasonló célra saját ablakos rendezést kellene írni, ez egy dialektuskülönbség, amit a DuckDB: helyi analitikus SQL szerver nélkül alfejezetben már láttunk. A p95-öt naponta számoljuk, mert a terhelés napszakonként eltér.

A drift-ellenőrzés Pythonban a PSI-t számítja ki a distance_km feature-re:

# monitor_drift.py
import csv
import math
from pathlib import Path

def psi(reference, current, bins=10):
    lo = min(reference + current)
    hi = max(reference + current)
    width = (hi - lo) / bins
    e = [0] * bins
    a = [0] * bins
    for v in reference:
        i = min(bins - 1, int((v - lo) / width))
        e[i] += 1
    for v in current:
        i = min(bins - 1, int((v - lo) / width))
        a[i] += 1
    e = [x / len(reference) for x in e]
    a = [x / len(current) for x in a]
    return sum((ai - ei) * math.log(ai / ei)
               for ei, ai in zip(e, a) if ei > 0 and ai > 0)

with Path("data/service_log.csv").open() as f:
    rows = list(csv.DictReader(f))
dist_all = [float(r["distance_km"]) for r in rows]
ref = [float(r["distance_km"]) for r in rows[:3000]]
cur = [float(r["distance_km"]) for r in rows[3000:]]
print(round(psi(ref, cur), 4))

A függvény 10 egyenlő szélességű bucketre osztja a referencia- és az aktuális ablakot. Ha az utóbbi 2000 kérés távolsága eltolódik, a PSI nő; ha azonos eloszlású marad, a PSI nullához közeli. A kimenet itt egyetlen szám, ezért ki kell egészíteni a döntéssel: 0,1 alatt nincs riasztás, 0,1 fölött a séma- és üzleti naplót is meg kell nézni.

A rollback munkamenet akkor indul, ha a PSI-riasztás nem magyarázható. A live pointer állomány:

# Windows PowerShell; munkakönyvtár: northstar-monitor
Get-FileHash models/northstar-late-0.3.0.bin -Algorithm SHA256
Get-Content models/pointer.json
# szemléltető pointer:
# {"live": "northstar-late-0.3.0", "sha256": "abc123...", "activated_at": "..."}
python -m deployment.rollback --from northstar-late-0.3.0 --to northstar-late-0.2.1 --reason "PSI alert"

A rollback modul a pointert northstar-late-0.2.1-re állítja, és a /ready végpont addig sikertelen, amíg az új pointerrel nem fut le a séma- és hash-ellenőrzés. Ez a Kiadás, visszaállítás és terhelési próba alfejezetben bevezetett release-feltételek futtatása.

Végül a hozzáférési ellenőrzés és naplóredaction:

# access_check.py
import logging
import os

class RedactingFilter(logging.Filter):
    def filter(self, record):
        msg = record.getMessage()
        for name in ["API_KEY", "DB_PASSWORD", "SECRET"]:
            if os.environ.get(name) and os.environ[name] in msg:
                record.msg = msg.replace(os.environ[name], "[REDACTED]")
        return True

logging.basicConfig(level=logging.INFO)
logging.getLogger().addFilter(RedactingFilter())
logging.info("request finished with token=%s", os.environ.get("API_KEY", "missing"))

A szűrő azt ellenőrzi, hogy a naplóüzenetbe került-e egy környezeti titok. Ez nem védi meg a fejlesztőt attól, aki szándékosan logolja a titkot, de megfogja a formátumsztringből beszivárgó gyakori esetet. A titkokat soha nem írjuk notebook-outputba vagy futási naplóba; ahol külső szolgáltatásnak kell átadni, ott a mezők listája a provider boundary dokumentumban él.

36.4.4 Eredmény értelmezése

A p95-ös batch-lekérdezés várhatóan olyan napi értékeket ad, amelyekben a kérésszám 300–500 között mozog, a p95 pedig 200–350 ms körül ingadozik a szimulált lognormális eloszlás miatt. A over_budget_requests oszlop a napi kérések 5%-ánál nem lehet több akkor, ha a p95 éppen a 250 ms-os határon van. A PSI kézi kontrollja visszaadja a korábbi 0,0405-ös értéket, ha a referencia- és aktuális gyakoriságokat explicit bucketekben adjuk meg. A rollback invariánsa: a pointer.json-ban szereplő hash egyezik a northstar-late-0.2.1.bin fájl sha256 értékével, és a /ready csak a sémaellenőrzés után tér vissza 200-as állapottal. Az access-szűrő invariánsa: a log kimenetben a titok értéke nem szerepel, csak a [REDACTED] szöveg. A kódblokkok után tehát nem elég annyit mondani, hogy „rendben”; meg kell nevezni, melyik mérték melyik feltételt igazolja, és mekkora tolerancia engedhető meg.

A fenti értékek szemléltetőek, mert a kapcsolódó példaprojektben még nem ellenőrzött. Ha helyben lefuttatod, a pontos számokat a saját futási jegyzőkönyv rögzíti; a seed 20261020 garantálja a szimulált input azonosságát azonos Python-verzión és azonos könyvtárverzión.

36.4.5 Feladatok

  1. Értelmezés. A drift-jelentés szerint a distance_km PSI-értéke 0,18 a referencia- és a friss ablak között. A referenciaablak 30 nap, 1200 kéréssel; a friss ablak 3 nap, 90 kéréssel. Fogalmazd meg, miért nem állíthatjuk automatikusan, hogy a modell bemenete elromlott, és milyen további két ellenőrzést végeznél el a riasztás lezárása előtt.

  2. Implementálás. Írj SQL lekérdezést DuckDB-re, amely a service_log és egy külön label_events tábla alapján napi bontásban megadja: az adott napon érkezett kérések számát, és közülük azok arányát, amelyeknek 14 napon belül megérkezett a címkéje. A label_events sémája: request_id, label_available_at, target_late. A címke csak akkor számít megérkezettnek, ha label_available_at nem üres és legfeljebb 14 nappal későbbi, mint a kérés ideje.

  3. Hibakeresés. A batch futás 503-at ad, a /health 200-at. A napló utolsó sora: downloaded model with api_key=sk-1234abcd. Nevezd meg a két hibát ebben a helyzetben, és add meg a javító lépéseket a hozzáférési és naplózási szerződés szerint.

  4. Megváltozott feltétel. A termékcsapat a batch pontozásról áttér valósidejű API-pontozásra. A becsült forgalom 500 kérés/óra, a rendelkezésre álló CPU 2 mag. Adj mérési tervet a compute budgethez: milyen inputméret, hány ismétlés, milyen metrikák és milyen rollback-feltétel kell ahhoz, hogy a 250 ms-os p95-célt ellenőrizni tudd?

36.4.6 Megoldások és indoklás

  1. A PSI 0,18 figyelmeztetés, de három nap alatt 90 kérés kis minta; a becsült PSI szórása nagy, és a bucketek véletlenszerűen is elmozdulhatnak. Először a kérések időbeli és szegmensbeli bontását nézném: ha egyetlen nagy ügyfél vagy kampány okozza, a drift magyarázható. Másodszor a modell teljesítményét ellenőrizném a már megérkezett címkéken: ha a PSI ellenére az AUC a toleranciasávon belül marad, akkor az inputeltolódás nem feltétlenül jelent minőségromlást. A riasztást le lehet zárni azzal, hogy a PSI-ra statisztikai bizonytalanságot is számolunk, például bootstrap intervallumot a referenciaablakból, és csak akkor emelünk incidenst, ha a friss PSI a bootstrap 95%-os sávja fölé esik.

  2. Egy lehetséges SQL:

SELECT
  date_trunc('day', s.order_at::TIMESTAMP) AS request_day,
  count(*) AS requests,
  avg(CASE
        WHEN l.label_available_at IS NOT NULL
         AND l.label_available_at::TIMESTAMP <= s.order_at::TIMESTAMP + INTERVAL '14 day'
        THEN 1 ELSE 0 END) AS label_coverage_14d
FROM service_log s
LEFT JOIN label_events l USING (request_id)
GROUP BY 1
ORDER BY 1;

A LEFT JOIN azért szükséges, hogy azok a kérések is szerepeljenek a nevezőben, amelyekhez még nincs címke. A 14 napos feltétel explicit cenzúra: a 15. napon érkező címke már nem javítja a 14 napos coverage-et. A napi bontás a megfigyelési egységet, a kérést tartja meg; az AVG a bináris indikátor átlaga.

  1. A 503 azt jelzi, hogy a batch futás nem tudta betölteni a modellt vagy az inputot, miközben a /health csak a folyamat él, tehát a service maga fut. A második hiba a naplóban lévő sk-1234abcd API-kulcs: a titok értékét naplózzuk. Javítás: a modell letöltése ne igényeljen API-kulcsot, hanem a lokalizált artifact hash-ét ellenőrizze; ha mégis van külső hívás, a kulcs a titokkezelőből jöjjön anélkül, hogy a log formátumsztringbe kerül, és a RedactingFilter aktív legyen a kibocsátó loggeren. A 503 diagnózisához a batch futás stderrjét kell nézni, nem a health-et.

  2. A mérési terv: 500 kérés/óra, 10 perces forgalmi csúcsokat szimulálunk 2 CPU-magos gépen; az input 5000 szintetikus rendelési rekord, mindegyik a Feature-pipeline, baseline és tanulás alfejezetben használt feature-sémával; 10 ismétlés, mindegyikben más request_id, de azonos eloszlás. A mért metrika: p50, p95, p99 válaszidő ms-ban, sikeres válaszok aránya, processz memória maximuma. A /ready ellenőrzése ismétlésenként. Rollback-feltétel: ha a p95 10 ismétlésből legalább 8 alkalommal 250 ms felett van, vagy a sikertelen kérések aránya meghaladja az 1%-ot, automatikusan a korábbi pointert kell aktíválni, és az eredményt a futáskövetőben rögzíteni. Az értékekhez ugyanaz a hardver és verzió kell, mint a termelésben; ha ez nem áll rendelkezésre, a mérés csak előzetes, nem elfogadási bizonyíték.

36.4.7 Gyakori tévedés és önellenőrzés

A leggyakoribb tévedés, hogy egyetlen sikeres demóból tartós megbízhatóságra következtetünk. Ellenpélda: az API egy 1000 kéréses reggeli tesztben minden kérésre 200-as választ adott, a p95 190 ms volt; a csapat ezért engedélyezte a release-t. Másnap a batch folyamat a napi 5000 soros inputon memória-túllépést kapott, mert a teszt csak 1000 sort pontozott, és a teljes nap kibontott DataFrame-jét a folyamat egyszerre tartotta memóriában. A 200-as válaszok és az alacsony p95 igaz mérés volt, de nem bizonyította a batch memória-budgetjét. A rendszer bizonyítéka ezért több, független feltétel együttes teljesülése: p95 a terhelés mellett, batch memória és idő, séma-hash, a késleltetett címkék aránya, és a rollback lefutása. Ez nem különbözik a VIII. ellenőrző pont: átadható modellprojekt alfejezetben használt kontrollfelfogástól: egyetlen tesztfájl sem igazolja a teljes csomagot, és a VI. ellenőrző pont: szivárgásmentes modellkísérlet alfejezetben tanult leakage-védelem is akkor él, ha a mérési ablakot explicitté tesszük.

Önellenőrzés a rendszergazdai átadás előtt: van-e a release-hez PSI-referenciaablak és regisztrált küszöb? A delayed label mérés kizárja-e a még meg nem érkezett címkéket? A rollback-parancs hash-t és naplóbejegyzést is készít? A service account ténylegesen nem fér a nyers rendelési adatokhoz? Ha bármelyik kérdésre nemleges a válasz, a rendszer még nem hordozza azokat a bizonyítékokat, amelyeket a IX. ellenőrző pont kér.

36.4.8 Rövid összefoglaló

A működő rendszer bizonyítéka nem a sikeres demó, hanem a mérési és hibakezelési terv: a compute budget p95-öt és memóriakorlátot ad; a batch és API szerződése különböző késleltetési és idempotencia-elvárásokat rögzít; a drift PSI-vel és statisztikai bizonytalansággal figyelhető; a delayed label mérés explicitté teszi a cenzúrát, hogy a kései pozitív esetek ne torzítsák a modellminőséget; a rollback pointer-váltással és előre írt feltételekkel fut; az access a legkisebb jogosultságot, környezeti titkokat és naplóredakciót tartatja be. A következő alkalmazásban a többnyelvű data science környezetbe lépünk, ahol ugyanezt a statisztikai fegyelmet R-eszközökkel is ismételhetően kell megvalósítani.