[Feature] Dismiss a single privacy finding, not just the whole rule #651

Closed
opened 2026-07-22 16:50:01 +00:00 by brenno · 10 comments
Owner

Split off from #608, where the reported false positive is fixed but the second half of the proposal is a feature in its own right.

Today a privacy finding offers exactly one action: "Never report this rule again" — a global switch. That is the wrong granularity for the common case. A single finding you have looked at and judged fine (a colleague's name that belongs on the slide, an address that is the client's own) forces a choice between living with the warning forever or turning off the whole rule for every deck.

Turning off a rule is the loudest possible response to the quietest possible problem, and it is irreversible in the way that matters: the next real finding of that class never appears.

Shape, and why it is not a bolt-on

  • State. A dismissal is per finding, so it needs an identity — rule id plus the matched span or a hash of it. Where it lives is the first question: per deck (then it touches the file format and the .miauw.json sidecar is the precedent), or in preferences (then it does not travel with the deck, which may be right — a dismissal is a judgement about this deck).
  • UI. A second action on the finding card, and a way to see and undo what you dismissed. A dismissal you cannot find again is a deletion.
  • l10n. At least two new strings × 31 languages.
  • The scanner must keep finding it. A dismissed finding is hidden, not unscanned — otherwise the count in the quality panel starts lying, and MIAUW EIS 1.1 reads that count.

Decide before building: per deck or per user. That determines whether this touches the file format, and the project's rule is that a format change gets a design first.

Not urgent: #608 removed the case that made this hurt on first run.

Split off from #608, where the reported false positive is fixed but the second half of the proposal is a feature in its own right. Today a privacy finding offers exactly one action: **"Never report this rule again"** — a global switch. That is the wrong granularity for the common case. A single finding you have looked at and judged fine (a colleague's name that belongs on the slide, an address that is the client's own) forces a choice between living with the warning forever or turning off the whole rule for every deck. Turning off a rule is the loudest possible response to the quietest possible problem, and it is irreversible in the way that matters: the next real finding of that class never appears. **Shape, and why it is not a bolt-on** - **State.** A dismissal is per finding, so it needs an identity — rule id plus the matched span or a hash of it. Where it lives is the first question: per deck (then it touches the file format and the `.miauw.json` sidecar is the precedent), or in preferences (then it does not travel with the deck, which may be right — a dismissal is a judgement about *this* deck). - **UI.** A second action on the finding card, and a way to see and undo what you dismissed. A dismissal you cannot find again is a deletion. - **l10n.** At least two new strings × 31 languages. - **The scanner must keep finding it.** A dismissed finding is hidden, not unscanned — otherwise the count in the quality panel starts lying, and MIAUW EIS 1.1 reads that count. **Decide before building:** per deck or per user. That determines whether this touches the file format, and the project's rule is that a format change gets a design first. Not urgent: #608 removed the case that made this hurt on first run.
Author
Owner

Gewogen, niet gebouwd — dit issue zegt zelf dat het besluit per deck of per gebruiker vóór de bouw komt omdat het het bestandsformaat raakt, en dat is een keuze van de stichting, niet iets wat een bouwronde namens haar neemt. Hieronder mijn aanbeveling, zodat de keuze scherp is.

Aanbeveling: per deck, in een sidecar — niet in de voorkeuren.

De redenering in het issue draait één kant op tegen zichzelf in: "in preferences … which may be right — a dismissal is a judgement about this deck". Maar juist "een oordeel over dít deck" pleit voor per deck, niet per gebruiker. Een terzijdelegging hoort bij de collega-naam-die-op-de-slide-mag; verhuist het deck naar een andere machine of een andere reviewer, dan hoort het oordeel mee te reizen. In de voorkeuren blijft het achter, en dan ziet de tweede reviewer de bevinding opnieuw — of, erger, ziet de eerste reviewer op een ánder deck een bevinding onterecht onderdrukt omdat de match toevallig hetzelfde hasht.

Waar het landt: niet in deck.md maar in een sidecar, dezelfde grens die de notities en het zegel al volgen (formaatgrens: het .md blijft maximaal uitwisselbaar, het OciDeck-specifieke staat ernaast). Een .miauw.json-achtige deck.dismissals.json met per terzijdelegging: regel-id + een salted commitment over de match-span (géén ruwe waarde — dezelfde reden als het redactiemanifest), plus een tijdstempel. Dat is precies de vorm die het issue voorstelt, alleen in een sidecar in plaats van in de voorkeuren.

De vier eigenschappen die het issue noemt blijven overeind:

  • identiteit = regel-id + commitment over de span;
  • UI = een tweede actie op de kaart, plus een lijst "teruggelegd" met ongedaan-maken (een terzijdelegging die je niet terugvindt is een verwijdering);
  • l10n = twee strings × 31 talen, via de route uit #633;
  • de scanner blijft vinden: de terzijdelegging verbergt in het paneel, telt niet mee als "opgelost", en de ongefilterde scan (die MIAUW EIS 1.1 leest) blijft het volle aantal zien. Dat sluit aan op wat #613 al scheidde tussen privacyRawScanProvider en de paneelweergave.

Wat dit tot een eigen ronde maakt en niet tot bijvangst: het is een formaatwijziging, en die vraagt eerst een afgetoetst ontwerp in FILE_FORMAT.md (nieuwe sidecar, versieverhoging, leespad voor oude decks) plus de sidecar-merge-semantiek — een teruggelegde bevinding die via git terugkomt is dezelfde vraag als bij de notities (#541/D7). Zeg welke kant je op wilt en of je het ontwerp eerst apart wilt zien; dan bouw ik het in die volgorde.

Niet urgent, zoals je zelf schreef — #608 haalde het geval weg dat pijn deed bij de eerste run.

Gewogen, niet gebouwd — dit issue zegt zelf dat het besluit *per deck of per gebruiker* vóór de bouw komt omdat het het bestandsformaat raakt, en dat is een keuze van de stichting, niet iets wat een bouwronde namens haar neemt. Hieronder mijn aanbeveling, zodat de keuze scherp is. **Aanbeveling: per deck, in een sidecar — niet in de voorkeuren.** De redenering in het issue draait één kant op tegen zichzelf in: "in preferences … which may be right — a dismissal is a judgement about *this* deck". Maar juist "een oordeel over dít deck" pleit voor **per deck**, niet per gebruiker. Een terzijdelegging hoort bij de collega-naam-die-op-de-slide-mag; verhuist het deck naar een andere machine of een andere reviewer, dan hoort het oordeel mee te reizen. In de voorkeuren blijft het achter, en dan ziet de tweede reviewer de bevinding opnieuw — of, erger, ziet de eerste reviewer op een ánder deck een bevinding onterecht onderdrukt omdat de match toevallig hetzelfde hasht. **Waar het landt:** niet in `deck.md` maar in een **sidecar**, dezelfde grens die de notities en het zegel al volgen (formaatgrens: het `.md` blijft maximaal uitwisselbaar, het OciDeck-specifieke staat ernaast). Een `.miauw.json`-achtige `deck.dismissals.json` met per terzijdelegging: regel-id + een salted commitment over de match-span (géén ruwe waarde — dezelfde reden als het redactiemanifest), plus een tijdstempel. Dat is precies de vorm die het issue voorstelt, alleen in een sidecar in plaats van in de voorkeuren. **De vier eigenschappen die het issue noemt blijven overeind:** - *identiteit* = regel-id + commitment over de span; - *UI* = een tweede actie op de kaart, plus een lijst "teruggelegd" met ongedaan-maken (een terzijdelegging die je niet terugvindt is een verwijdering); - *l10n* = twee strings × 31 talen, via de route uit #633; - *de scanner blijft vinden*: de terzijdelegging **verbergt** in het paneel, telt niet mee als "opgelost", en de ongefilterde scan (die MIAUW EIS 1.1 leest) blijft het volle aantal zien. Dat sluit aan op wat #613 al scheidde tussen `privacyRawScanProvider` en de paneelweergave. **Wat dit tot een eigen ronde maakt en niet tot bijvangst:** het is een formaatwijziging, en die vraagt eerst een afgetoetst ontwerp in `FILE_FORMAT.md` (nieuwe sidecar, versieverhoging, leespad voor oude decks) plus de sidecar-merge-semantiek — een teruggelegde bevinding die via git terugkomt is dezelfde vraag als bij de notities (#541/D7). Zeg welke kant je op wilt en of je het ontwerp eerst apart wilt zien; dan bouw ik het in die volgorde. Niet urgent, zoals je zelf schreef — #608 haalde het geval weg dat pijn deed bij de eerste run.
Author
Owner

Ik volg de aanbeveling.

Ik volg de aanbeveling.
Author
Owner

Ontwerp en opslaglaag staan op main: 0122d910 en 19f183ff (PR #732). Het issue blijft open voor het paneel; zie onderaan.

Het ontwerp staat in FILE_FORMAT §6.7, zoals dit issue zelf vroeg: eerst op papier, dan bouwen. Per deck in een sidecar <naam>.dismissals.json, niet in de voorkeuren.

Eén correctie op mijn eigen aanbeveling hierboven. Ik schreef: commitment in plaats van ruwe waarde, "dezelfde reden als het redactiemanifest". Die reden klopt niet. Dat manifest verbergt waarden omdat ze uít het artefact zijn gehaald; hier staan ze nog gewoon in de .md, dus tegen wie de sidecar heeft koopt een commitment niets — die leest de dia. De twee redenen die het wél dragen:

  1. Een privacygereedschap hoort geen tweede kopie van een persoonsgegeven te maken. De .md beheert de auteur; deze sidecar is machinerie met een eigen levensduur — mee de git-historie in, mee de synchronisatiemap in. Een naam die je erin schrijft blijft staan nadat de auteur hem van de dia heeft gehaald.
  2. Het zout is per deck en stopt correlatie: dezelfde naam in twee decks geeft twee onvergelijkbare uitkomsten.

Het ontwerp zegt er expliciet bij dat het zout géén geheim is — het staat in dezelfde sidecar — zodat er geen bescherming wordt gesuggereerd die er niet is.

Identiteit is regel + commitment, niet de positie. Elke positie in PrivacyFinding schuift zodra iemand er een woord boven typt, dus een positie-gebonden terzijdelegging zou stil verlopen. seen_at reist mee om te tónen wáár je oordeelde, en is nadrukkelijk geen matchsleutel. Gevolg, en het is bedoeld: een naam die je op dia 4 goedkeurt blijft ook op dia 9 stil — je oordeelde over de naam in dit deck.

De vier eigenschappen die je noemde: identiteit ✔; de scan blijft vinden ✔ (verbergen is geen wegscannen, de ongefilterde telling die MIAUW EIS 1.1 leest ziet het volle aantal); UI en l10n staan nog open.

Samenvoegen is een unie op regel + commitment, latere at wint, met grafstenen. Die zijn dragend: zonder hen verdwijnt een ongedaan-making bij de eerstvolgende samenvoeging — de andere kant draagt de terzijdelegging nog — en blijft de bevinding verborgen. Daarom ruimt "alles herroepen" de sidecar ook níét op, anders dan bij de MIAUW-sidecar. Bij een gelijk tijdstempel wint zichtbaarheid.

Wat er nu werkt, met 22 tests: de codec, het samenvoegen, opslaan, heropenen, opruimen, en de reis in de prullenbak en het pakket.

Wat nog moet, en waarvoor dit open blijft: het paneel dat filtert, de tweede actie op de bevindingskaart, de terzijdegelegd-lijst met ongedaan-maken, twee interfaceteksten × 31 vertalingen, en het git-schrijfpad.

Ontwerp en opslaglaag staan op main: `0122d910` en `19f183ff` (PR #732). **Het issue blijft open** voor het paneel; zie onderaan. **Het ontwerp staat in FILE_FORMAT §6.7**, zoals dit issue zelf vroeg: eerst op papier, dan bouwen. Per deck in een sidecar `<naam>.dismissals.json`, niet in de voorkeuren. **Eén correctie op mijn eigen aanbeveling hierboven.** Ik schreef: commitment in plaats van ruwe waarde, "dezelfde reden als het redactiemanifest". Die reden klopt niet. Dat manifest verbergt waarden omdat ze uít het artefact zijn gehaald; hier staan ze nog gewoon in de `.md`, dus tegen wie de sidecar heeft koopt een commitment niets — die leest de dia. De twee redenen die het wél dragen: 1. Een privacygereedschap hoort geen tweede kopie van een persoonsgegeven te maken. De `.md` beheert de auteur; deze sidecar is machinerie met een eigen levensduur — mee de git-historie in, mee de synchronisatiemap in. Een naam die je erin schrijft blijft staan **nadat de auteur hem van de dia heeft gehaald**. 2. Het zout is per deck en stopt correlatie: dezelfde naam in twee decks geeft twee onvergelijkbare uitkomsten. Het ontwerp zegt er expliciet bij dat het zout géén geheim is — het staat in dezelfde sidecar — zodat er geen bescherming wordt gesuggereerd die er niet is. **Identiteit is regel + commitment, niet de positie.** Elke positie in `PrivacyFinding` schuift zodra iemand er een woord boven typt, dus een positie-gebonden terzijdelegging zou stil verlopen. `seen_at` reist mee om te tónen wáár je oordeelde, en is nadrukkelijk geen matchsleutel. Gevolg, en het is bedoeld: een naam die je op dia 4 goedkeurt blijft ook op dia 9 stil — je oordeelde over de naam in dit deck. **De vier eigenschappen die je noemde:** identiteit ✔; de scan blijft vinden ✔ (verbergen is geen wegscannen, de ongefilterde telling die MIAUW EIS 1.1 leest ziet het volle aantal); UI en l10n staan nog open. **Samenvoegen** is een unie op regel + commitment, latere `at` wint, met grafstenen. Die zijn dragend: zonder hen verdwijnt een ongedaan-making bij de eerstvolgende samenvoeging — de andere kant draagt de terzijdelegging nog — en blijft de bevinding verborgen. Daarom ruimt "alles herroepen" de sidecar ook níét op, anders dan bij de MIAUW-sidecar. Bij een gelijk tijdstempel wint zichtbaarheid. **Wat er nu werkt**, met 22 tests: de codec, het samenvoegen, opslaan, heropenen, opruimen, en de reis in de prullenbak en het pakket. **Wat nog moet, en waarvoor dit open blijft:** het paneel dat filtert, de tweede actie op de bevindingskaart, de terzijdegelegd-lijst met ongedaan-maken, twee interfaceteksten × 31 vertalingen, en het git-schrijfpad.
Author
Owner

Besluit genomen: per deck. Daarmee is dit een sidecar en dus een formaatwijziging, en die krijgt in deze repo eerst een afgetoetst ontwerp. Dat ontwerp staat op main: `docs/design/PRIVACY_DISMISSALS.md` (`c5b2d50f`, PR #734). Er staat nog geen regel code.

Eerst een correctie op dit issue, want die scheelt in wat er gebouwd moet worden. De opening zegt dat een bevinding maar één actie kent — "Never report this rule again", een globale schakelaar. Er zijn er drie:

Hendel Reikwijdte Waar
PrivacyDisposition op het deck elke bevinding in het deck front matter
PrivacyDisposition op een slide elke bevinding op die slide de slide
"Deze regel nooit meer melden" die regel, in élk deck, voorgoed gebruikersinstellingen

accept op een slide is dus al een oordeel per deck dat andere slides en andere decks ongemoeid laat. Het gat zit binnen één slide: een slide met twee bevindingen — de collega-naam die er hoort en het adres dat er niet hoort — kent alleen alles-of-niets. Dát is wat ontbreekt, en het is één stap fijner dan het issue schetst, niet een hele nieuwe as.

Dat verandert de kostenschatting in je oorspronkelijke tekst niet fundamenteel, maar wel de framing: dit is granulariteit toevoegen aan iets dat bestaat, niet een nieuw mechanisme.

Wat het ontwerp vastlegt, kort:

  • Sidecar <naam>.privacy-dismissals.json, niet een sleutel in de front matter — dezelfde reden die in 0.1.0 zeven sleutels daaruit haalde. Een disposition is één woord en leest prima in een editor; een salted commitment is precies de base64-achtige ruis waar dat besluit over ging.
  • Identiteit = regel-id + slide-id + salted commitment over de match-span, nooit de ruwe waarde. Die span ís de persoonsgegevens.
  • Verandert de tekst, dan vervalt de terzijdelegging. Veilige richting, en geen nieuw begrip: de notitiecodec ankert al zo.
  • De scanner blijft vinden; het paneel verbergt. privacyRawScanProvider verandert niet, dus MIAUW EIS 1.1 ziet het volle aantal — dat is jouw eis uit de issue-tekst.
  • Voor de exportpoort telt het wél als afgehandeld, net als accept. Anders houdt de auteur een permanent geblokkeerde export met als enige uitweg de globale schakelaar — precies wat deze functie moet voorkomen. Dat staat als besluit opgeschreven en niet als bijzaak, want het is de enige plek waar dit ontwerp iets toestaat in plaats van iets tegenhoudt.

Drie lessen die deze repo al betaald heeft zijn hergebruikt in plaats van opnieuw ontdekt: het salted commitment (redactiemanifest), de grafsteen bij ongedaan maken in plaats van verwijderen (inklaag, D7) en één regel per entry zodat git's tekst-merge werkt (notities, #541).

Twee dingen die ik van je nodig heb voor de bouw:

  1. OQ-1 in het ontwerp — overleeft een terzijdelegging een wijziging van de regel zelf? Mijn antwoord staat erbij met de reden; bevestigen of verwerpen.
  2. Of de correctie hierboven je beeld verandert. Als "accept op de slide" in de praktijk vaak genoeg is, is dit een kleinere functie dan hij leek — of misschien geen functie. Dat is jouw afweging, niet die van de bouwronde.

Label op needs-info tot die twee er zijn.

**Besluit genomen: per deck.** Daarmee is dit een sidecar en dus een formaatwijziging, en die krijgt in deze repo eerst een afgetoetst ontwerp. Dat ontwerp staat op main: \`docs/design/PRIVACY_DISMISSALS.md\` (\`c5b2d50f\`, PR #734). **Er staat nog geen regel code.** **Eerst een correctie op dit issue, want die scheelt in wat er gebouwd moet worden.** De opening zegt dat een bevinding maar één actie kent — "Never report this rule again", een globale schakelaar. Er zijn er drie: | Hendel | Reikwijdte | Waar | |---|---|---| | `PrivacyDisposition` op het **deck** | elke bevinding in het deck | front matter | | `PrivacyDisposition` op een **slide** | elke bevinding op die slide | de slide | | "Deze regel nooit meer melden" | die regel, in élk deck, voorgoed | gebruikersinstellingen | `accept` op een slide is dus al een oordeel per deck dat andere slides en andere decks ongemoeid laat. Het gat zit **binnen één slide**: een slide met twee bevindingen — de collega-naam die er hoort en het adres dat er niet hoort — kent alleen alles-of-niets. Dát is wat ontbreekt, en het is één stap fijner dan het issue schetst, niet een hele nieuwe as. Dat verandert de kostenschatting in je oorspronkelijke tekst niet fundamenteel, maar wel de framing: dit is granulariteit toevoegen aan iets dat bestaat, niet een nieuw mechanisme. **Wat het ontwerp vastlegt**, kort: - **Sidecar** `<naam>.privacy-dismissals.json`, niet een sleutel in de front matter — dezelfde reden die in 0.1.0 zeven sleutels daaruit haalde. Een disposition is één woord en leest prima in een editor; een salted commitment is precies de base64-achtige ruis waar dat besluit over ging. - **Identiteit** = regel-id + slide-id + salted commitment over de match-span, nooit de ruwe waarde. Die span *ís* de persoonsgegevens. - **Verandert de tekst, dan vervalt de terzijdelegging.** Veilige richting, en geen nieuw begrip: de notitiecodec ankert al zo. - **De scanner blijft vinden**; het paneel verbergt. `privacyRawScanProvider` verandert niet, dus MIAUW EIS 1.1 ziet het volle aantal — dat is jouw eis uit de issue-tekst. - **Voor de exportpoort telt het wél als afgehandeld**, net als `accept`. Anders houdt de auteur een permanent geblokkeerde export met als enige uitweg de globale schakelaar — precies wat deze functie moet voorkomen. Dat staat als besluit opgeschreven en niet als bijzaak, want het is de enige plek waar dit ontwerp iets *toestaat* in plaats van iets tegenhoudt. Drie lessen die deze repo al betaald heeft zijn hergebruikt in plaats van opnieuw ontdekt: het salted commitment (redactiemanifest), de grafsteen bij ongedaan maken in plaats van verwijderen (inklaag, D7) en één regel per entry zodat git's tekst-merge werkt (notities, #541). **Twee dingen die ik van je nodig heb voor de bouw:** 1. **OQ-1 in het ontwerp** — overleeft een terzijdelegging een wijziging van de *regel* zelf? Mijn antwoord staat erbij met de reden; bevestigen of verwerpen. 2. **Of de correctie hierboven je beeld verandert.** Als "accept op de slide" in de praktijk vaak genoeg is, is dit een kleinere functie dan hij leek — of misschien geen functie. Dat is jouw afweging, niet die van de bouwronde. Label op `needs-info` tot die twee er zijn.
Author
Owner

OQ-1 bevestigd, bouw gestart. Tak: feat/privacy-terzijdelegging-651. Volgorde volgens het ontwerp: model + sidecarcodec met het salted commitment, dan het filter in privacyScanProvider, dan de interface (actie op de kaart + de lijst met ongedaan maken), dan de reisroutes (pakket, prullenbak, herstelmomentopname).

OQ-1 bevestigd, bouw gestart. Tak: `feat/privacy-terzijdelegging-651`. Volgorde volgens het ontwerp: model + sidecarcodec met het salted commitment, dan het filter in `privacyScanProvider`, dan de interface (actie op de kaart + de lijst met ongedaan maken), dan de reisroutes (pakket, prullenbak, herstelmomentopname).
Author
Owner

De knop en de lijst staan op main: c1ee69ab (PR #736) en 24523ffb (PR #738). Het issue blijft open voor één ding; zie onderaan.

De knop. "Deze is beoordeeld en mag blijven", bóven "Deze regel nooit meer melden". De volgorde is de boodschap: déze ene treffer is bijna altijd wat iemand bedoelt, de hele regel uitzetten is het zware middel. In 31 talen, met het onderscheid tussen "deze ene" en "de regel" in elke taal expliciet gemaakt.

De lijst. Onder Beveiliging staan de terzijdegelegde bevindingen als chips; tikken zet er een terug. Jouw eigen zin uit dit issue — a dismissal you cannot find again is a deletion — was de maat.

Op een chip staat de regel plus waar je oordeelde, nooit de gevonden waarde. Die staat niet in de sidecar (daar zit een commitment) en hoort niet in een instellingenscherm. Er staat een test op.

Terugzetten schrijft een grafsteen in plaats van de terzijdelegging te verwijderen. Weggooien zou hem bij de eerstvolgende samenvoeging laten terugkeren van de andere kant, en dan was de bevinding weer verborgen zonder dat iemand daarvoor koos.

Over de vier eigenschappen die je noemde: identiteit ✔, UI ✔, l10n ✔ (twee nieuwe strings × 31), en de scanner blijft vinden ✔ — de ongefilterde telling die MIAUW EIS 1.1 leest ziet het volle aantal, en "beoordeeld en akkoord" blijft te onderscheiden van "opgelost".

Twee dingen die de opruiming opleverde. Het instellingenvenster zat 63 regels over zijn plafond; in plaats van dat plafond te verhogen is de lijst een eigen widget geworden — en toen bleek de bestaande uitgezette-regels-lijst exact dezelfde vorm te hebben en er net zomin in te horen. Allebei staan ze nu in widgets/dialogs/settings/; de klasse ging van 6106 naar 5992 regels. En een doc-commentaar bleek bij de verkeerde methode te staan sinds 79f302bf er een schakelaar tussen schoof.

Wat openblijft: het git-schrijfpad. Het ontwerp stelt dat deze sidecar — anders dan de inktlaag — wél in een commit hoort: een terzijdelegging is een reviewbesluit over het rapport, en een tweede reviewer moet niet opnieuw langs wat een collega al beoordeeld heeft. De samenvoeglogica ligt er (mergeDismissals, met de grafstenen), maar het schrijfpad in services/git/ niet. Dat raakt direct aan #541, waar op dit moment aan de sidecars-in-git wordt gewerkt — beter daar meenemen dan er dwars doorheen bouwen.

De knop en de lijst staan op main: `c1ee69ab` (PR #736) en `24523ffb` (PR #738). **Het issue blijft open voor één ding**; zie onderaan. **De knop.** "Deze is beoordeeld en mag blijven", bóven "Deze regel nooit meer melden". De volgorde is de boodschap: déze ene treffer is bijna altijd wat iemand bedoelt, de hele regel uitzetten is het zware middel. In 31 talen, met het onderscheid tussen "deze ene" en "de regel" in elke taal expliciet gemaakt. **De lijst.** Onder Beveiliging staan de terzijdegelegde bevindingen als chips; tikken zet er een terug. Jouw eigen zin uit dit issue — *a dismissal you cannot find again is a deletion* — was de maat. Op een chip staat de regel plus waar je oordeelde, **nooit de gevonden waarde**. Die staat niet in de sidecar (daar zit een commitment) en hoort niet in een instellingenscherm. Er staat een test op. Terugzetten schrijft een grafsteen in plaats van de terzijdelegging te verwijderen. Weggooien zou hem bij de eerstvolgende samenvoeging laten terugkeren van de andere kant, en dan was de bevinding weer verborgen zonder dat iemand daarvoor koos. **Over de vier eigenschappen die je noemde:** identiteit ✔, UI ✔, l10n ✔ (twee nieuwe strings × 31), en de scanner blijft vinden ✔ — de ongefilterde telling die MIAUW EIS 1.1 leest ziet het volle aantal, en "beoordeeld en akkoord" blijft te onderscheiden van "opgelost". **Twee dingen die de opruiming opleverde.** Het instellingenvenster zat 63 regels over zijn plafond; in plaats van dat plafond te verhogen is de lijst een eigen widget geworden — en toen bleek de bestaande uitgezette-regels-lijst exact dezelfde vorm te hebben en er net zomin in te horen. Allebei staan ze nu in `widgets/dialogs/settings/`; de klasse ging van 6106 naar 5992 regels. En een doc-commentaar bleek bij de verkeerde methode te staan sinds `79f302bf` er een schakelaar tussen schoof. **Wat openblijft: het git-schrijfpad.** Het ontwerp stelt dat deze sidecar — anders dan de inktlaag — wél in een commit hoort: een terzijdelegging is een reviewbesluit over het rapport, en een tweede reviewer moet niet opnieuw langs wat een collega al beoordeeld heeft. De samenvoeglogica ligt er (`mergeDismissals`, met de grafstenen), maar het schrijfpad in `services/git/` niet. Dat raakt direct aan #541, waar op dit moment aan de sidecars-in-git wordt gewerkt — beter daar meenemen dan er dwars doorheen bouwen.
Author
Owner

Het meeste van wat ik hier bouwde was duplicaatwerk. Een parallelle sessie bouwde tegelijk hetzelfde, en dat is drie keer op rij gebeurd op dit ene issue: het ontwerp, de opslaglaag én het filter. Wat er van mijn kant overblijft staat op main (`71397ddc`, PR #739); de rest heb ik laten vallen.

Het dubbele ontwerp is ingetrokken. Het hunne (FILE_FORMAT §6.7, PR #732) landde eerst; het mijne (docs/design/PRIVACY_DISMISSALS.md, PR #734) merge er schoon bovenop omdat git alleen een nieuw bestand zag — de botsing was semantisch en dus onzichtbaar voor de poort. Twee ontwerpen voor één bestandsformaat is erger dan geen ontwerp, dus het mijne is weg, mét registratie en 31 vertaalsleutels.

En hun redenering is op het punt dat ertoe doet beter dan de mijne. Ik schreef dat het commitment de waarde beschermt. Dat is niet waar tegen iemand die het deck heeft — die leest de dia gewoon. Hun tekst zegt dat met zoveel woorden en geeft de twee eerlijke redenen: geen tweede kopie van een persoonsgegeven met een eigen levensduur, en een zout per deck tegen kruisverbanden. Dat is scherper, en het is een correctie op wat ik je eerder schreef.

Twee dingen uit mijn versie zijn bewaard, in §6.7:

  • OQ-1, dat je bevestigde: een terzijdelegging verloopt níét bij een wijziging van de regel, met de reden erbij zodat de andere kant niet opnieuw wordt voorgesteld.
  • De exportpoort, als open vraag. "Verborgen in het paneel" en "niet opgelost" waren beslist; wat de póórt ermee doet niet. Beide kanten hebben een prijs, en die staan er nu allebei — als onopgelost tellen geeft een permanent geblokkeerde export waarvan de enige uitweg de globale schakelaar is (precies wat deze functie vervangt); als opgelost tellen laat de poort een schoonheid melden die de nalevingsteller met opzet weigert.

Eén toets toegevoegd die er nog niet was: dat matchedTextOf null geeft wanneer een bevinding nergens meer op wijst. Gaf het een afgekapt stuk tekst terug, dan hasht dat ooit toevallig naar een terzijdelegging en verbergt de app iets wat niemand heeft bekeken. Nagelopen dát hij vangt — met de begrenzing vervangen door een clamp valt hij om.

Eén aanwijzing die ik niet als verbetering indien omdat ik hem niet gemeten heb: matchedTextOf bouwt de fragmentenlijst van een dia opnieuw op per bevinding. Op een dia met veel treffers is dat kwadratisch werk in een pad dat bij élke deckwijziging draait. Voor wie er ooit met de prestatiebril naar kijkt.

Wat er nog te bouwen is: de knop om een bevinding terzijde te leggen en de lijst om dat ongedaan te maken. Die twee horen bij elkaar — een terzijdelegging die je niet terugvindt is een verwijdering — en ze staan er nog niet.

Ik heb in-progress eraf gehaald, zodat wie dit oppakt niet weer naast een ander werkt.

**Het meeste van wat ik hier bouwde was duplicaatwerk.** Een parallelle sessie bouwde tegelijk hetzelfde, en dat is drie keer op rij gebeurd op dit ene issue: het ontwerp, de opslaglaag én het filter. Wat er van mijn kant overblijft staat op main (\`71397ddc\`, PR #739); de rest heb ik laten vallen. **Het dubbele ontwerp is ingetrokken.** Het hunne (FILE_FORMAT §6.7, PR #732) landde eerst; het mijne (`docs/design/PRIVACY_DISMISSALS.md`, PR #734) merge er schoon bovenop omdat git alleen een nieuw bestand zag — de botsing was semantisch en dus onzichtbaar voor de poort. Twee ontwerpen voor één bestandsformaat is erger dan geen ontwerp, dus het mijne is weg, mét registratie en 31 vertaalsleutels. **En hun redenering is op het punt dat ertoe doet beter dan de mijne.** Ik schreef dat het commitment de waarde beschermt. Dat is niet waar tegen iemand die het deck heeft — die leest de dia gewoon. Hun tekst zegt dat met zoveel woorden en geeft de twee eerlijke redenen: geen tweede kopie van een persoonsgegeven met een eigen levensduur, en een zout per deck tegen kruisverbanden. Dat is scherper, en het is een correctie op wat ik je eerder schreef. **Twee dingen uit mijn versie zijn bewaard**, in §6.7: - **OQ-1, dat je bevestigde**: een terzijdelegging verloopt níét bij een wijziging van de regel, met de reden erbij zodat de andere kant niet opnieuw wordt voorgesteld. - **De exportpoort, als open vraag.** "Verborgen in het paneel" en "niet opgelost" waren beslist; wat de póórt ermee doet niet. Beide kanten hebben een prijs, en die staan er nu allebei — als onopgelost tellen geeft een permanent geblokkeerde export waarvan de enige uitweg de globale schakelaar is (precies wat deze functie vervangt); als opgelost tellen laat de poort een schoonheid melden die de nalevingsteller met opzet weigert. **Eén toets toegevoegd die er nog niet was:** dat `matchedTextOf` null geeft wanneer een bevinding nergens meer op wijst. Gaf het een afgekapt stuk tekst terug, dan hasht dat ooit toevallig naar een terzijdelegging en verbergt de app iets wat niemand heeft bekeken. Nagelopen dát hij vangt — met de begrenzing vervangen door een clamp valt hij om. **Eén aanwijzing die ik niet als verbetering indien omdat ik hem niet gemeten heb:** `matchedTextOf` bouwt de fragmentenlijst van een dia opnieuw op per bevinding. Op een dia met veel treffers is dat kwadratisch werk in een pad dat bij élke deckwijziging draait. Voor wie er ooit met de prestatiebril naar kijkt. **Wat er nog te bouwen is:** de knop om een bevinding terzijde te leggen en de lijst om dat ongedaan te maken. Die twee horen bij elkaar — een terzijdelegging die je niet terugvindt is een verwijdering — en ze staan er nog niet. Ik heb `in-progress` eraf gehaald, zodat wie dit oppakt niet weer naast een ander werkt.
Author
Owner

Opgepakt — het laatste deel, het git-schrijfpad. Tak: feat/terzijdelegging-naar-git-651. De route van #541 (deel 2) ligt er nu: deck.dismissals.json volgt dezelfde _repoSidecarState-regels als de notities en de ink, mergeDeckVersions krijgt de al bestaande mergeDismissals-unie erbij (regel+commitment, latere at wint, grafstenen), plus de uitzondering in de sync-delete-lus en de docs (FILE_FORMAT §6.7, GIT_STORAGE §9.1/9.7). Daarna kan dit issue dicht.

Opgepakt — het laatste deel, het git-schrijfpad. Tak: feat/terzijdelegging-naar-git-651. De route van #541 (deel 2) ligt er nu: deck.dismissals.json volgt dezelfde _repoSidecarState-regels als de notities en de ink, mergeDeckVersions krijgt de al bestaande mergeDismissals-unie erbij (regel+commitment, latere at wint, grafstenen), plus de uitzondering in de sync-delete-lus en de docs (FILE_FORMAT §6.7, GIT_STORAGE §9.1/9.7). Daarna kan dit issue dicht.
Author
Owner

Af, en op main geverifieerd: ab06c11 (PR #761). Het laatste deel — het git-schrijfpad — is gebouwd op de route van #541: deck.dismissals.json naast deck.md, gedeelde aanraak-/verwijderregels, en mergeDeckVersions past de al ontworpen unie toe (regel + commitment, latere at wint, herroepingen overleven — geen heranker-stap, want de identiteit is geen dia-positie). De sidecar draagt commitments en nooit de gevonden waarde; daar staat een test op.

Daarmee zijn alle onderdelen uit dit issue en het ontwerp af: identiteit ✔, UI (knop + terzijdegelegd-lijst met ongedaan maken) ✔, l10n ✔, de scanner blijft vinden ✔ (de ongefilterde telling die MIAUW EIS 1.1 leest ziet het volle aantal), en het besluit per-deck-in-een-sidecar is nu ook in git werkelijkheid.

Wat er bewust níét in zat: de MIAUW-dispositie zelf reist nog niet (#756, eerst een merge-semantiek-besluit), en de bewaker liet één klein punt herstellen vóór de merge: het zout-divergentiebesluit van mergeDismissals staat nu in FILE_FORMAT §6.7 in plaats van alleen in een codecommentaar. Poort: make check groen, secrets/SAST schoon. Dicht.

**Af, en op main geverifieerd: ab06c11 (PR #761).** Het laatste deel — het git-schrijfpad — is gebouwd op de route van #541: deck.dismissals.json naast deck.md, gedeelde aanraak-/verwijderregels, en mergeDeckVersions past de al ontworpen unie toe (regel + commitment, latere at wint, herroepingen overleven — geen heranker-stap, want de identiteit is geen dia-positie). De sidecar draagt commitments en nooit de gevonden waarde; daar staat een test op. Daarmee zijn alle onderdelen uit dit issue en het ontwerp af: identiteit ✔, UI (knop + terzijdegelegd-lijst met ongedaan maken) ✔, l10n ✔, de scanner blijft vinden ✔ (de ongefilterde telling die MIAUW EIS 1.1 leest ziet het volle aantal), en het besluit per-deck-in-een-sidecar is nu ook in git werkelijkheid. Wat er bewust níét in zat: de MIAUW-dispositie zelf reist nog niet (#756, eerst een merge-semantiek-besluit), en de bewaker liet één klein punt herstellen vóór de merge: het zout-divergentiebesluit van mergeDismissals staat nu in FILE_FORMAT §6.7 in plaats van alleen in een codecommentaar. Poort: make check groen, secrets/SAST schoon. Dicht.
Author
Owner

Correctie op mezelf. In PR #739 en in mijn reactie hierboven noteerde ik dat matchedTextOf de fragmentenlijst van een dia per bevinding opnieuw opbouwt, en dat dat "kwadratisch werk in een pad dat bij élke deckwijziging draait" zou zijn. Ik zette erbij dat ik het níét had gemeten. Nu wel, en de bewering houdt geen stand.

Geïsoleerd gemeten — alleen het opzoeken, op één dia met álle bevindingen erop:

100 bevindingen →  1,5 ms
400 bevindingen →  8,7 ms
800 bevindingen → 14,7 ms

En door de hele provider heen, met en zonder terzijdeleggingen:

n=400: zonder 85,6 ms · met 85,5 ms

Geen meetbaar verschil. De scan zelf domineert met een factor tien; het filter verdwijnt in de ruis.

De kwadratische term bestáát wel — matchedTextOf loopt de fragmenten van een dia langs tot hij de juiste vindt, dus bevinding i kost i stappen — maar de constante is zo klein dat zelfs 800 treffers op één dia binnen 15 ms blijven. En het pad draait alleen op een deck dat mínstens één terzijdelegging draagt; zonder valt het predicaat meteen terug op (_) => false.

Dus geen issue. Ik had die aanwijzing niet moeten opschrijven zonder meting, ook niet met een voorbehoud erbij: een niet-gemeten prestatiezorg in een PR-tekst leest de volgende lezer als werk dat nog moet gebeuren.

**Correctie op mezelf.** In PR #739 en in mijn reactie hierboven noteerde ik dat `matchedTextOf` de fragmentenlijst van een dia per bevinding opnieuw opbouwt, en dat dat "kwadratisch werk in een pad dat bij élke deckwijziging draait" zou zijn. Ik zette erbij dat ik het níét had gemeten. Nu wel, en **de bewering houdt geen stand.** Geïsoleerd gemeten — alleen het opzoeken, op één dia met álle bevindingen erop: ``` 100 bevindingen → 1,5 ms 400 bevindingen → 8,7 ms 800 bevindingen → 14,7 ms ``` En door de hele provider heen, met en zonder terzijdeleggingen: ``` n=400: zonder 85,6 ms · met 85,5 ms ``` Geen meetbaar verschil. De scan zelf domineert met een factor tien; het filter verdwijnt in de ruis. De kwadratische term bestáát wel — `matchedTextOf` loopt de fragmenten van een dia langs tot hij de juiste vindt, dus bevinding *i* kost *i* stappen — maar de constante is zo klein dat zelfs 800 treffers op één dia binnen 15 ms blijven. En het pad draait alleen op een deck dat mínstens één terzijdelegging draagt; zonder valt het predicaat meteen terug op `(_) => false`. **Dus geen issue.** Ik had die aanwijzing niet moeten opschrijven zonder meting, ook niet met een voorbehoud erbij: een niet-gemeten prestatiezorg in een PR-tekst leest de volgende lezer als werk dat nog moet gebeuren.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
LibreKAT/Ocideck#651
No description provided.