Werkplaats / De werkplaats
In jouw eigen tempo
← AI in de wereld
MODULE 06 · LES 13

Verbind een rol en peildatum aan geselecteerde eisen en bewijs

Vergelijk expliciete termijnen en vind ontbrekende bewijs-ids zonder een telling voor juridische naleving aan te zien.

90 min3 checkpoints
DIT GA JE ONTDEKKEN
  • Je selecteert vooraf beoordeelde eisen voor een expliciete rol en peildatum.
  • Je onderscheidt ontbrekend bewijs, extra ids en een lege noemer.

Een organisatie heeft een map “AI-regels” en een leverancier zegt dat alles geregeld is. Maar wie houdt toezicht, welke verplichting geldt wanneer en waaruit blijkt dat iemand haar uitvoert? Een mapnaam geeft nog geen antwoord.

Denk aan een onderhoudslogboek. Je hebt een concrete taak, een verantwoordelijke en controleerbaar bewijs nodig. Een vinkje zonder uitgevoerde controle kan het ontbrekende werk verhullen.

Deze les gebruikt een kleine, expliciet geselecteerde oefenlijst. De EU AI Act-bronnen zijn gecontroleerd op 30 oktober 2026; context, andere rollen en overgangsrecht vragen een afzonderlijke beoordeling. De code vindt geen wetgeving en bepaalt geen juridische naleving.

1. Dezelfde organisatie kan verschillende rollen hebben

Een aanbieder, provider, ontwikkelt een systeem of laat het ontwikkelen en brengt het onder eigen naam of merk op de markt of in gebruik. Een gebruiksverantwoordelijke, deployer, gebruikt een systeem onder eigen gezag; persoonlijk niet-professioneel gebruik valt buiten deze rolomschrijving. Alleen “we kopen software” zeggen stelt de volledige rolverdeling niet vast.

Artikel 16 noemt verplichtingen voor aanbieders van hoog-risicosystemen, zoals kwaliteitsmanagement, documentatie en de bedoelde conformiteitsbeoordeling. Artikel 26 vraagt bij gebruikers onder meer passend gebruik, bekwaam en bevoegd menselijk toezicht en monitoring. Die taken verschillen, ook wanneer betrokken partijen samenwerken.

Onze lijst hieronder is een benoemde deelverzameling, geen volledige wettelijke checklist. Monitoring bij beide rollen betekent niet dat hun taken identiek zijn. Iedere regel krijgt vooraf beoordeelde rollen; je functie selecteert alleen de bijbehorende ids.

requirements = [
    {'id': 'dossier',
     'roles': ['provider']},
    {'id': 'toezicht',
     'roles': ['deployer']},
    {'id': 'monitoring',
     'roles': ['provider', 'deployer']},
]
required = role_requirements(
    requirements, 'deployer')
print(required)
# ['monitoring', 'toezicht']
01
CHECKPOINTSelecteer ids voor een expliciete rol

2. Een termijn hoort bij een concrete bepaling

Inwerkingtreding en toepasselijkheid zijn verschillende momenten. De verordening trad op 1 augustus 2024 in werking, maar verplichtingen worden stapsgewijs toepasselijk. Een algemene startdatum geeft dus niet het antwoord voor iedere bepaling.

Volgens de gecontroleerde gewijzigde tijdlijn gelden de bedoelde bijlage-III-hoog-risicoregels vanaf 2 december 2027, en de bedoelde productregels uit bijlage I vanaf 2 augustus 2028. Andere regels gelden eerder, zoals de algemene transparantieregels vanaf 2 augustus 2026. Specifieke overgangssituaties bij bestaande systemen moet je apart bekijken.

Voor de oefening is applies_on al voor het concrete geval geselecteerd. Je vergelijkt die kalenderdatum met de expliciete peildatum on_date. De computerklok verandert je uitkomst niet.

VERKEN HET ZELFWelke gekozen eisen gelden, en welk bewijs ontbreekt?

Kies een beperkt oefendossier, rol en peildatum. De tabel is vooraf geselecteerd; een toekomstige regel of lege oefenset zegt niets over andere huidige verplichtingen.

Reikwijdte en hoog-risicoroute vooraf beoordeeld. Alleen de drie gekozen dossieronderdelen, geen volledige wettelijke checklist.

Monitoring, ingevuld per rolGeselecteerd en actueel

monitoring · start

Startdag bereikt

De werking volgen volgens de gebruiksinstructies (artikel 26(5)).

Primaire bron voor dit onderdeel
Vooraf beoordeelde bewijsverwijzingen

Selecteer ids waarvan het bewijs in deze oefening al is beoordeeld. De bestandsinhoud wordt hier niet onderzocht.

Opgegeven ids, inclusief herhalingen: monitoring, oude-notitie.

1 van 2 ids gedekt (50%)

Dekking telt vooraf beoordeelde bewijs-ids, geen juridische naleving. Een lege geselecteerde oefenset zegt niets over andere verplichtingen.

Geselecteerd en actueel 2

  • monitoring
  • toezicht

Gedekt 1

  • monitoring

Nog geen bewijs 1

  • toezicht

Buiten deze actuele set 1

  • oude-notitie

Dubbele verwijzingen tellen één keer. Extra ids vervangen geen ontbrekend bewijs. Een volledige id-lijst bewijst nog geen uitgevoerde taak of juridische naleving.

Bronstand 30 oktober 2026. Dit zijn vooraf beoordeelde, beperkte oefengegevens. De visualisatie stelt geen juridische feiten vast en geeft geen toestemming om een systeem te gebruiken.

Noem het kalenderdagnummer van de start S en van de peildatum D. Het verschil d telt resterende dagen; nul betekent dat de startdag is bereikt, een negatief getal dat die dag voorbij is. Applicable geldt hier dus ook op de startdag zelf.

d=S−Dd≤0
events = [
    {'id': 'hoog-risico',
     'applies_on': '2027-12-02'},
]
before = timeline_status(
    events, '2027-12-01')[0]
start = timeline_status(
    events, '2027-12-02')[0]
print(before['days_until'],
      before['status'])
print(start['days_until'],
      start['status'])
# 1 future
# 0 applicable
02
CHECKPOINTVergelijk geselecteerde termijnen met een vaste peildatum

Een toekomstige toepasselijkheidsdatum is geen advies om voorbereiding, privacy of andere huidige verplichtingen uit te stellen. Timeline_status ordent uitsluitend de aangeleverde regels, eerst op datum en bij gelijke datums op id. Hij leidt geen uitzonderingen af.

3. Bewijsdekking maakt ontbrekend werk zichtbaar

Stel dat monitoring en toezicht op jouw geselecteerde lijst staan. Er is gecontroleerd bewijs voor monitoring, plus een oude notitie die geen van beide vereisten dekt. Het toezicht ontbreekt nog; de extra notitie kan dat niet compenseren.

Noem de verzameling vereiste ids R en de vooraf beoordeelde bewijs-ids B. De ontbrekende ids M vormen het verschil R zonder B. Dubbele verwijzingen voegen geen nieuw bewijs toe.

M=R∖B

De doorsnede R ∩ B bevat gedekte vereisten. Verticale strepen tellen unieke elementen; de fractie C deelt het aantal gedekte door het aantal vereiste ids. Als R leeg is, rapporteren we None: er is dan geen zinvolle verhouding.

C=|R∩B||R|,|R|>0
proof = evidence_coverage(
    required,
    ['monitoring', 'oude-notitie'])
print(proof['missing'])
print(proof['extra'])
print(proof['fraction'])
# ['toezicht']
# ['oude-notitie']
# 0.5
03
CHECKPOINTMaak ontbrekende bewijs-ids zichtbaar

Een dubbele kopie van hetzelfde stuk verandert deze telling niet. Zonder geselecteerde vereisten verschijnt ook geen verzonnen perfecte score.

duplicate = evidence_coverage(
    required,
    ['monitoring', 'monitoring'])
print(duplicate['fraction'])
print(evidence_coverage([], [])[
    'fraction'])
# 0.5
# None

Deze halve dekking is een administratieve telling, geen halve juridische naleving. Beoordeel ieder bewijsstuk op doel, verantwoordelijke, versie, controledatum en beperkingen. Een bestand met de naam toezicht bewijst nog niet dat bevoegd toezicht werkelijk plaatsvindt.

Wat je nu kunt

  • Je koppelt geselecteerde eisen aan een expliciete rol en peildatum.
  • Je controleert de startdag zonder toekomstige termijnen als vrijstelling te behandelen.
  • Je vindt ontbrekend bewijs zonder duplicaten of extra bestanden mee te laten tellen.

Hiermee eindigt de productietrack. In de securitytrack onderzoek je vervolgens aanvallen én verdedigingen in een eigen afgeschermde oefenomgeving.

Bronnen

Gecontroleerd op 30 oktober 2026: artikel 3 over rollen, artikel 16 over aanbieders, artikel 26 over gebruikers, artikel 113 over toepasselijkheid en de officiële gewijzigde invoeringstijdlijn, van de Europese Commissie.

JOUW EXPERIMENT

Probeer het zelf

Python
main.py

Python start zodra jij code uitvoert.

UITVOER

Je uitvoer verschijnt hier.
Alles rekent in je eigen browser.

Jouw checkpoints0 / 3
01
Selecteer ids voor een expliciete rol

Schrijf role_requirements(requirements,role). Gebruik _gov_role en _gov_rows. Regels zijn exact list/tuple met 0–64 exacte dicts met uitsluitend de gevraagde keys. Regel-ids zijn uniek. Ids zijn exacte Python-strs volgens [a-z][a-z0-9-]{0,39}; niet strippen of normaliseren. Iedere regel heeft id en roles. Roles is exact list/tuple met een of twee unieke exacte strings provider/deployer; role precies een van die twee strings. Valideer alle regels, ook als ze niet matchen. Geef een nieuwe alfabetisch gesorteerde lijst van de ids waarvan roles de gekozen rol bevat. Lege regels geven []. Behoud alle invoerwaarden, vormen, volgorde, readonlyflags en Python-/NumPy-RNG. Gebruik nieuwe resultaatdicts/lijsten zonder mutabele alias naar invoer of elkaar. Ongeldige invoer geeft ValueError; helpers zijn gegeven. Elke functie moet zelfstandig werken terwijl de andere twee TODO zijn. Rol en relevante regels zijn vooraf beoordeeld; geen automatische wettelijke rolbepaling.

Een hint

Controleer eerst de rolwaarden per regel; verzamel daarna de passende ids en sorteer.

02
Vergelijk geselecteerde termijnen met een vaste peildatum

Schrijf timeline_status(events,on_date). Gebruik _gov_date en _gov_rows. Regels zijn exact list/tuple met 0–64 exacte dicts met uitsluitend de gevraagde keys. Regel-ids zijn uniek. Ids zijn exacte Python-strs volgens [a-z][a-z0-9-]{0,39}; niet strippen of normaliseren. Iedere eventregel heeft id en applies_on. Datums zijn exacte Python-strs YYYY-MM-DD, kalendergeldig in jaren 0001–9999; geen weekdatums, tijddeel of andere schrijfwijze. Geef een nieuwe lijst van nieuwe dicts in oplopende applies_on-volgorde, bij gelijkheid alfabetisch op id. Iedere dict heeft precies id/applies_on (ongewijzigde strings), days_until (exact Python-int: startdatum min peildatum in kalenderdagen, negatief blijft negatief) en status (applicable bij days_until<=0, anders future). De startdag is inclusief, on_date ook bij lege events valideren. Behoud alle invoerwaarden, vormen, volgorde, readonlyflags en Python-/NumPy-RNG. Gebruik nieuwe resultaatdicts/lijsten zonder mutabele alias naar invoer of elkaar. Ongeldige invoer geeft ValueError; helpers zijn gegeven. Elke functie moet zelfstandig werken terwijl de andere twee TODO zijn. Alleen vooraf geselecteerde termijnen; geen systeemklok, wetsversiezoeker, vrijstelling of afgeleid overgangsrecht.

Een hint

Trek kalenderdatums van elkaar af; nul hoort bij toepasselijk en is geen toekomstige dag.

03
Maak ontbrekende bewijs-ids zichtbaar

Schrijf evidence_coverage(required,evidence). Gebruik _gov_ids. Beide inputs zijn exact list/tuple met 0–64 items; duplicaten zijn toegestaan en tellen eenmaal. Ids zijn exacte Python-strs volgens [a-z][a-z0-9-]{0,39}; niet strippen of normaliseren. Geef exact een nieuw dict met required (nieuwe gesorteerde lijst unieke benodigde ids), covered (doorsnede), missing (required zonder evidence), extra (evidence zonder required) en fraction (exact Python-float: unieke covered gedeeld door unieke required; None bij geen vereisten). Alle vier lijsten zijn alfabetisch gesorteerd en onafhankelijk, ook als inhoud gelijk is. Behoud alle invoerwaarden, vormen, volgorde, readonlyflags en Python-/NumPy-RNG. Gebruik nieuwe resultaatdicts/lijsten zonder mutabele alias naar invoer of elkaar. Ongeldige invoer geeft ValueError; helpers zijn gegeven. Elke functie moet zelfstandig werken terwijl de andere twee TODO zijn. Bewijs-ids zijn vooraf beoordeeld; de fractie is administratieve telling, geen veiligheids- of juridische nalevingsscore.

Een hint

Werk met verzamelingen voor de inhoud en maak daarna nieuwe gesorteerde lijsten; deel niet door nul.

Vastgelopen? Bekijk de voorbeeldoplossing
from datetime import date
import re

# Jouw functies

def role_requirements(requirements, role):
    """IDs for an explicitly selected role, not legal inference from a business name."""
    selected = _gov_role(role)
    rows = _gov_rows(requirements, ('id', 'roles'))
    matches = []
    for row in rows:
        roles = row['roles']
        if type(roles) not in (list, tuple) or not 1 <= len(roles) <= 2:
            raise ValueError('Geef een of twee rollen per regel')
        checked = [_gov_role(value) for value in roles]
        if len(set(checked)) != len(checked):
            raise ValueError('Geen dubbele rol')
        if selected in checked:
            matches.append(row['id'])
    return sorted(matches)

def timeline_status(events, on_date):
    """Dates are already selected for the case; include the first applicable day.

    Return chronological order, ties by id. Signed days_until is negative for
    past dates. No clock, version lookup, transition or scope inference.
    """
    current = _gov_date(on_date)
    rows = _gov_rows(events, ('id', 'applies_on'))
    parsed = [(row, _gov_date(row['applies_on'])) for row in rows]
    result = []
    for row, starts in sorted(parsed, key=lambda pair: (pair[1], pair[0]['id'])):
        days = (starts - current).days
        result.append({'id': row['id'], 'applies_on': row['applies_on'], 'days_until': days, 'status': 'applicable' if days <= 0 else 'future'})
    return result

def evidence_coverage(required, evidence):
    """Set coverage of previously assessed IDs; presence does not prove compliance."""
    wanted = set(_gov_ids(required))
    provided = set(_gov_ids(evidence))
    covered = wanted & provided
    return {'required': sorted(wanted), 'covered': sorted(covered), 'missing': sorted(wanted - provided), 'extra': sorted(provided - wanted), 'fraction': len(covered) / len(wanted) if wanted else None}

# Gegeven helpers

def _gov_id(value):
    if type(value) is not str or re.fullmatch('[a-z][a-z0-9-]{0,39}', value) is None:
        raise ValueError('Gebruik een id van 1 tot 40 kleine ASCII-tekens')
    return value

def _gov_ids(values):
    if type(values) not in (list, tuple) or len(values) > 64:
        raise ValueError('Geef maximaal 64 ids')
    return [_gov_id(value) for value in values]

def _gov_date(value):
    if type(value) is not str or re.fullmatch('[0-9]{4}-[0-9]{2}-[0-9]{2}', value) is None:
        raise ValueError('Gebruik een geldige kalenderdatum YYYY-MM-DD')
    try:
        return date.fromisoformat(value)
    except ValueError:
        raise ValueError('Ongeldige kalenderdatum') from None

def _gov_rows(rows, fields):
    if type(rows) not in (list, tuple) or len(rows) > 64:
        raise ValueError('Geef maximaal 64 regels')
    seen = set()
    result = []
    for row in rows:
        if type(row) is not dict or set(row) != set(fields):
            raise ValueError('Onjuiste regelvelden')
        key = _gov_id(row['id'])
        if key in seen:
            raise ValueError('Regel-ids moeten uniek zijn')
        seen.add(key)
        result.append(dict(row))
    return result

def _gov_role(value):
    if type(value) is not str or value not in ('provider', 'deployer'):
        raise ValueError('Rol is provider of deployer')
    return value

Voer de code uit en verklaar voor jezelf waarom elke stap werkt.