Ga naar inhoud

Wie een document verplaatste, en waarheen

Een dossier bepaalt wat een gescopete zoekopdracht teruggeeft. Een document verplaatsen verandert dus wat iemand wél en niet ziet — en tot 2026-09-22 bleef daar niets van over. De securityreview greptte op audit over dossiers.py, dossier_tools.py en backfill_dossier.py en vond nul treffers. Je zag achteraf de uitkomst en niet de handeling.

Twee soorten feit, twee plekken

wat waar waarom
lidmaatschap erbij of eraf de hashketen van dat document het gaat over één document
dossier hernoemd de sleutel-levensloopstroom het verplaatst geen document

Die scheiding is de hele beslissing. Een hernoeming raakt duizend documenten zonder er één te verplaatsen; duizend identieke records zouden de keten volschrijven met kopieën van hetzelfde feit, en één record zonder document past niet in die tabel. Daarom staat hij waar grants, sleutelrotaties en rolwijzigingen al staan — dezelfde redenering als in roles.py.

Wat een lidmaatschapsrecord is

Een gebeurtenis, geen toestandsovergang: from == to, net als deanonymize. Een document dat in een andere zaak belandt, staat in precies dezelfde staat als daarvoor. Een overgang claimen zou current_state laten liegen.

step     : dossier_added | dossier_removed
payload  : dossier, dossier_id, actor [, reason] [, batch]

De reden is verplicht bij weghalen, niet bij toevoegen

Dat is geen slordigheid maar de kern:

  • toevoegen is terug te zien in het resultaat — het document staat er;
  • weghalen laat niets achter. De enige herleiding is wat iemand op dat moment opschreef, en een maand later reconstrueert niemand dat.

remove() zonder reden is daarom een DossierError, geen waarschuwing.

Wie het deed

actor heeft geen default. Een default maakt het anonieme geval het makkelijkste geval, en dan staat er over een jaar "iemand heeft dit verplaatst". Aankomen via ingest telt ook als handeling: die records dragen actor: ingest — niemand verplaatste dat document, het arriveerde.

Eén handeling, honderden records

Een terugvulling die 791 documenten toewijst is eerlijk als 791 records: elk document kreeg echt een lidmaatschap. Zonder iets dat ze bindt is een dag geschiedenis alleen niet te lezen — het oogt als honderden losse beslissingen.

Daarom draagt elk record van zo'n run hetzelfde batch-kenmerk. Een lezer kan ze samenvouwen; het spoor blijft per document kloppen.

Terugzoeken

-- alles wat er met dit document in dossiers gebeurde
SELECT ts, step, payload FROM audit_records
WHERE document_id = '…' AND step LIKE 'dossier_%' ORDER BY seq;

-- één handeling, alle documenten die hij raakte
SELECT document_id, payload->>'dossier' FROM audit_records
WHERE payload->>'batch' = '…';

Hernoemingen staan niet in deze tabel maar in de sleutel-levensloopstroom, als dossier_renamed, met old, new en hoeveel documenten het dossier op dat moment hield — het getal waarvoor dat record bestaat.