feat(git): laat de notities meereizen naar een repo, en houd ze heel (#541) #673

Merged
brenno merged 8 commits from feat/notities-naar-git into main 2026-07-22 19:23:39 +00:00
Owner

Deel 1 van #541: de notities reizen mee naar een git-repo. Ink en zegel blijven bewust liggen — die wachten niet op werk maar op een ontwerpbesluit (streekidentiteit in het annotatieformaat; wat een zegel betekent op een tak die herschreven kan worden).

Wat er verandert

De notities staan nu als deck.user-notes.json naast deck.md, op een vast pad — niet in de op inhoud geadresseerde pool, want daar zou elk getypt teken een nieuw bestand minten en het vorige laten wegkwijnen. Bij het openen hangen ze weer aan de juiste dia, herkend aan de vingerafdruk en niet aan het id (dat wordt bij elke parse opnieuw uitgedeeld).

De waarschuwing vóór de commit verliest exact de regel die onwaar werd, en houdt die over tekeningen en het zegel. De regressiepoort die het issue vraagt toetst nu per verhuisde laag dat er niets meer over gemeld wordt — media sinds #515, notities sinds #541.

D7 klopte niet zoals het er stond

Dat ontwerpbesluit zegt dat dit bestand door git's gewone tekst-merge gaat, "so that two authors editing different slides' notes merge cleanly". Maar de sidecar is JSON en jsonEncode zet die op één regel, en op één regel botst élke wijziging met élke andere. Regelgebaseerd mergen heeft regels nodig.

De repo-kopie wordt daarom ingesprongen geschreven, één veld per regel; het bestand op schijf — dat niemand ooit samenvoegt — blijft compact. Beide decoderen identiek, en FILE_FORMAT §6.3.1 zegt nu expliciet dat een ander werktuig beide vormen mag schrijven.

De bewakerreview vond drie manieren om notities kwijt te raken

Alle drie nagemeten voor ik ze aannam, alle drie stil, alle drie ontstaan dóór deze tak — en daarmee slechter dan de waarschuwing die hij vervangt, want dáár wist de gebruiker het.

  1. De offline-wachtrij wiste ze. SyncEngine leidt zijn deletes af uit wat lokaal ontbreekt. Online opslaan, offline één woord wijzigen, weer online → het notitiebestand van de tak verwijderd, met een groene melding. De inline map in de state-laag is nu één functie met één lijst (mirrorDeckFiles) mét de regel erboven dat wat er niet in staat verwíjderd wordt.
  2. De merge wiste ze bij het gewoonste geval dat er is. merged erfde userNotes letterlijk van onze kant, gesleuteld op id's uit onze parse, terwijl de samengevoegde dia's grotendeels uit de basis en van de ander komen. Twee auteurs, notities op verschillende dia's → beider werk weg, status merged.
  3. "Ik kon het niet lezen" werd "ik gooi het weg". Conflictmarkeringen uit een merge buiten OciDeck zijn geen geldige JSON; een sidecar van een nieuwere build leest deze build bewust niet.

En in de tweede ronde bleek reparatie 2 op het REST-pad te landen terwijl native het pad is dat de app kiest zodra git geïnstalleerd is. Daar kreeg de resolver alleen de deck.md-bytes van de drie kanten, dus alle drie de decks leken notitieloos — en omdat de deckmap wordt vervangen door wat de resolver teruggeeft, stond het bestand als verwijdering in de merge-commit. mergeRemote geeft nu een MergeSideReader mee.

In de derde ronde: de regel dekte het verwijderen maar niet het overschrijven. Eén gebruiker, geen merge nodig — een collega schrijft version: 3, jij ziet geen notities, typt er één, en jouw v2-bestand ging over hun hele bestand heen. De vraag is omgedraaid naar "mag ik hier aan komen", één keer vóór de vertakking, net als _sidecarUntouchable op schijf.

Waar de code terechtkwam

De klasseratchet viel twee keer, en had beide keren gelijk. Het hele native oplosblok is resolveRepoDeckMerge in de servicelaag geworden — elke regel erin ging over opslag — en de state-laag levert alleen nog de importpoort en de afbeeldingsresolver. TabsNotifier staat daarmee 16 regels ónder zijn oude plafond; dat plafond is meeverlaagd. Dat is meteen een hap uit #518.

Privacy

Notities kunnen gevoeliger zijn dan de dia's zelf, ze worden door OciWacht bewust niet gescand, en ze belanden nu in een gedeelde repo onder je eigen naam in het commitlog. Dat staat nu waar iemand het leest vóórdat hij typt — in de gids bij de sectie waar je kiest wat je in dit veld zet, niet bij de git-lijst — en het commentaar in privacy_projection.dart is gecorrigeerd, want dat zei nog dat deze notities "geen enkel exportartefact bereiken".

Getoetst

  • make check groen, ook na de rebase op de huidige main.
  • Elke reparatie heeft een test die rood wordt zonder de fix; per stuk nagemeten met een geplante mutatie in plaats van aangenomen. Vijf van de zes merge-tests, beide native tests, de schrijfpoort.
  • De native tests draaien tegen een échte bare origin op schijf.

Niet gedraaid: make check-secrets en make sast — gitleaks, trufflehog en semgrep staan geen van drieën op deze machine. Deze wijziging voegt geen sleutel, netwerkpad of afhankelijkheid toe, maar de eis is daarmee niet gehaald.

Apart gemeld

#670 — een native merge verwijdert <deckDir>/data/*.json, in de faaltak én bij een geslaagde merge. Dat dateert van vóór deze tak (de grafiekdata liep er al tegenaan) en repareren vraagt een wijziging aan wat mergeRemote/_writeAll beloven over bestanden die de resolver niet noemt.

Werkt deel 1 van #541 af; het issue blijft open voor ink en zegel.

Deel 1 van #541: de notities reizen mee naar een git-repo. Ink en zegel blijven bewust liggen — die wachten niet op werk maar op een ontwerpbesluit (streekidentiteit in het annotatieformaat; wat een zegel betekent op een tak die herschreven kan worden). ## Wat er verandert De notities staan nu als `deck.user-notes.json` naast `deck.md`, op een vast pad — niet in de op inhoud geadresseerde pool, want daar zou elk getypt teken een nieuw bestand minten en het vorige laten wegkwijnen. Bij het openen hangen ze weer aan de juiste dia, herkend aan de vingerafdruk en niet aan het id (dat wordt bij elke parse opnieuw uitgedeeld). De waarschuwing vóór de commit verliest exact de regel die onwaar werd, en houdt die over tekeningen en het zegel. De regressiepoort die het issue vraagt toetst nu per verhuisde laag dat er *niets* meer over gemeld wordt — media sinds #515, notities sinds #541. ## D7 klopte niet zoals het er stond Dat ontwerpbesluit zegt dat dit bestand door git's gewone tekst-merge gaat, "so that two authors editing different slides' notes merge cleanly". Maar de sidecar is JSON en `jsonEncode` zet die op één regel, en op één regel botst élke wijziging met élke andere. Regelgebaseerd mergen heeft regels nodig. De repo-kopie wordt daarom ingesprongen geschreven, één veld per regel; het bestand op schijf — dat niemand ooit samenvoegt — blijft compact. Beide decoderen identiek, en `FILE_FORMAT` §6.3.1 zegt nu expliciet dat een ander werktuig beide vormen mag schrijven. ## De bewakerreview vond drie manieren om notities kwijt te raken Alle drie nagemeten voor ik ze aannam, alle drie stil, alle drie ontstaan dóór deze tak — en daarmee slechter dan de waarschuwing die hij vervangt, want dáár wist de gebruiker het. 1. **De offline-wachtrij wiste ze.** `SyncEngine` leidt zijn `deletes` af uit wat lokaal ontbreekt. Online opslaan, offline één woord wijzigen, weer online → het notitiebestand van de tak verwijderd, met een groene melding. De inline map in de state-laag is nu één functie met één lijst (`mirrorDeckFiles`) mét de regel erboven dat wat er niet in staat verwíjderd wordt. 2. **De merge wiste ze bij het gewoonste geval dat er is.** `merged` erfde `userNotes` letterlijk van onze kant, gesleuteld op id's uit onze parse, terwijl de samengevoegde dia's grotendeels uit de basis en van de ander komen. Twee auteurs, notities op verschillende dia's → beider werk weg, status *merged*. 3. **"Ik kon het niet lezen" werd "ik gooi het weg".** Conflictmarkeringen uit een merge buiten OciDeck zijn geen geldige JSON; een sidecar van een nieuwere build leest deze build bewust niet. En in de tweede ronde bleek reparatie 2 op het REST-pad te landen terwijl **native het pad is dat de app kiest zodra git geïnstalleerd is**. Daar kreeg de resolver alleen de `deck.md`-bytes van de drie kanten, dus alle drie de decks leken notitieloos — en omdat de deckmap wordt *vervangen* door wat de resolver teruggeeft, stond het bestand als verwijdering in de merge-commit. `mergeRemote` geeft nu een `MergeSideReader` mee. In de derde ronde: de regel dekte het verwijderen maar niet het **overschrijven**. Eén gebruiker, geen merge nodig — een collega schrijft `version: 3`, jij ziet geen notities, typt er één, en jouw v2-bestand ging over hun hele bestand heen. De vraag is omgedraaid naar "mag ik hier aan komen", één keer vóór de vertakking, net als `_sidecarUntouchable` op schijf. ## Waar de code terechtkwam De klasseratchet viel twee keer, en had beide keren gelijk. Het hele native oplosblok is `resolveRepoDeckMerge` in de servicelaag geworden — elke regel erin ging over opslag — en de state-laag levert alleen nog de importpoort en de afbeeldingsresolver. `TabsNotifier` staat daarmee 16 regels ónder zijn oude plafond; dat plafond is meeverlaagd. Dat is meteen een hap uit #518. ## Privacy Notities kunnen gevoeliger zijn dan de dia's zelf, ze worden door OciWacht bewust niet gescand, en ze belanden nu in een gedeelde repo onder je eigen naam in het commitlog. Dat staat nu waar iemand het leest vóórdat hij typt — in de gids bij de sectie waar je kiest wat je in dit veld zet, niet bij de git-lijst — en het commentaar in `privacy_projection.dart` is gecorrigeerd, want dat zei nog dat deze notities "geen enkel exportartefact bereiken". ## Getoetst - `make check` groen, ook na de rebase op de huidige main. - Elke reparatie heeft een test die rood wordt zonder de fix; per stuk nagemeten met een geplante mutatie in plaats van aangenomen. Vijf van de zes merge-tests, beide native tests, de schrijfpoort. - De native tests draaien tegen een échte bare origin op schijf. **Niet gedraaid:** `make check-secrets` en `make sast` — gitleaks, trufflehog en semgrep staan geen van drieën op deze machine. Deze wijziging voegt geen sleutel, netwerkpad of afhankelijkheid toe, maar de eis is daarmee niet gehaald. ## Apart gemeld #670 — een native merge verwijdert `<deckDir>/data/*.json`, in de faaltak én bij een geslaagde merge. Dat dateert van vóór deze tak (de grafiekdata liep er al tegenaan) en repareren vraagt een wijziging aan wat `mergeRemote`/`_writeAll` beloven over bestanden die de resolver niet noemt. Werkt deel 1 van #541 af; het issue blijft open voor ink en zegel.
Wie zijn presentaties in git bewaarde, raakte bij het verhuizen van een map
naar een repo stilletjes zijn notities kwijt: niets in `services/git/` schreef
die sidecar. Er stond een waarschuwing vóór de commit, maar een waarschuwing is
geen oplossing.

De notities gaan nu als `deck.user-notes.json` naast `deck.md`, op een vast pad
— niet in de op inhoud geadresseerde pool. Daar zou elk getypt teken een nieuw
bestand minten en het vorige laten wegkwijnen, en dan valt er geen wijziging
meer te lézen. Dezelfde afweging als bij de grafiekdata.

**D7 klopte niet zoals het er stond.** Dat ontwerpbesluit zegt dat dit bestand
door git's gewone tekst-merge gaat, zodat twee auteurs op verschillende dia's
schoon samenvoegen. Maar de sidecar is JSON en `jsonEncode` zet die op één
regel — en op één regel botst élke wijziging met élke andere. Regelgebaseerd
mergen heeft regels nodig. De kopie die naar de repo gaat wordt daarom
ingesprongen geschreven, één veld per regel; het bestand op schijf, dat niemand
ooit samenvoegt, blijft compact. Beide decoderen identiek.

De laatste notitie wissen levert een `deletes`-pad op in plaats van een stil
achterblijvend bestand. Zonder dat hing die notitie er bij de volgende open
gewoon weer aan, en een wissing die terugkomt is erger dan een die niet werkt.

`gitDeckOmissions` verliest zijn notitieteller. Niet "voor de zekerheid" laten
staan: een waarschuwing die meer opsomt dan er misgaat, leert de lezer hem in
zijn geheel weg te klikken — en dan verdwijnt ook de regel over het zegel.
Dezelfde reden als waarom media er bij #540 uitging.

Het leespad is fail-open, zoals op schijf en bij de grafiekdata: geen bestand,
onleesbare JSON, geen geldige UTF-8, boven de bytegrens of een leesfout leveren
een deck zónder notities op, geen mislukte open. Notities zijn een laag over
het deck, niet het deck.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Drie plekken lezen een deck uit een repo — een tak, een uitgebrachte versie, en
de wachtrij die offline werk later alsnog commit. Alle drie moeten dezelfde
lagen terughangen in dezelfde volgorde, dus dat is één functie geworden
(`withRepoSidecars`) in plaats van drie losse paren aanroepen. Drie plekken zijn
drie kansen om een volgende laag te vergeten, en die vergissing is stil: het
deck opent gewoon, alleen zonder wat er ook nog bij hoorde.

De wachtrij was daarbij het minst voor de hand liggende geval en het naarste:
dat deck wordt uit de opslag opnieuw geserialiseerd, dus wat er niet aan hangt
schrijft `buildDeckRepoFiles` niet terug. Wachtend werk zou zijn notities
verliezen op precies het moment dat het eindelijk landt.

`commitFiles(deletes:)` bestond al maar kreeg overal `const []` mee; nu draagt
het de paden die `buildDeckRepoFiles` teruggeeft.

De regel over gebruikersnotities is uit de waarschuwingsdialoog verdwenen. De
klasseratchet wees onderweg de weg: `TabsNotifier` kwam boven zijn plafond, en
dat was de wenk om de herhaling er werkelijk uit te halen in plaats van de
basislijn op te schroeven. Meteen ook de basislijn van `_SettingsDialogState`
verlaagd naar wat die klasse inmiddels is (7107); die winst kwam van elders en
stond nog los.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
De regressiepoort die het issue vraagt: de melding moet precies de regel
kwijtraken die onwaar werd en de rest houden. Daarom staat er nu per verhuisde
laag een toets dat er níéts meer over gemeld wordt — media sinds #515,
notities sinds #541 — naast de toets dat tekenlaag en zegel er nog wél in staan.

De serializer-tests dekken de heen- en terugweg (op vingerafdruk, niet op id,
want die worden bij elk parsen opnieuw uitgedeeld), dat de notities per regel in
het bestand staan zodat git ze kan mergen, dat wissen het bestand weghaalt, en
de vijf manieren waarop een bestand niet kan deugen.

Drie mutaties geplant om te zien dat ze werkelijk iets bewijzen: de inspringing
weghalen, de delete weglaten, en de notities niet wegschrijven. Alle drie rood.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
GIT_STORAGE §9.1 en §9.7 en besluit D7 bijgewerkt met wat er werkelijk staat, en
met wat het ontwerp niet had voorzien: dat de sidecar JSON is en op één regel
uitkomt, waardoor de belofte 'twee auteurs op verschillende dia's mergen schoon'
niet klopte. Dat is een eigenschap van het transport, niet van het formaat, en
staat daarom in het opslagontwerp en niet in FILE_FORMAT.

Ook in §9.7 gezet wat er nog níét is: OciDeck lost een conflict niet in de app
op. Git laat conflictmarkeringen achter, die zijn geen geldige JSON, dus het
bestand decodeert niet en het deck opent zonder notities in plaats van met
verhaspelde. Nagegaan tegen de code, niet aangenomen.

USER_GUIDE beweerde daarnaast nog dat video en audio niet meereizen; dat was
sinds #515 onwaar. Die alinea is in zijn geheel rechtgezet en gedateerd.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Uit de bewakerreview op deze tak, alle drie nagemeten voor ik ze aannam. De
tak verplaatste notities van "gaan niet mee" naar "gaan mee, en verdwijnen op
drie paden die de gebruiker geen van alle ziet" — en dat is slechter dan de
waarschuwing die hij vervangt, want dáár wist de gebruiker het.

**1. De offline-wachtrij wiste ze.** `_queueGitSave` schreef `deck.md` en de
grafiekdata naar de werkkopie, met een comment dat uitlegde waarom dat moest —
de notities stonden er niet bij. `SyncEngine` leidt zijn `deletes` áf uit wat
er in de repo staat maar niet in de werkkopie, dus: online opslaan (notities
landen), offline één woord wijzigen, weer online — en de commit verwijdert het
notitiebestand van de tak. Groene melding erbij.

Dat de map inline in de state-laag werd opgebouwd was de reden dat dit kón
gebeuren, dus die is nu één functie met één lijst: `mirrorDeckFiles`, met de
regel erboven dat wat er niet in staat verwíjderd wordt.

**2. De merge wiste ze — bij het gewoonste geval dat er is.** `mergeDeckVersions`
gaf `ours.copyWith(slides: out)` terug, dus `userNotes` kwam letterlijk van onze
kant, gesleuteld op de id's van ónze parse. `out` bestaat grotendeels uit dia's
van de basis en van de ander, en die id's worden bij élke parse opnieuw
uitgedeeld: geen enkele sleutel wees nog een dia aan. A schrijft een notitie bij
dia 2, B bij dia 5, ze botsen — en beider werk was weg, met status "merged".
`_mergedUserNotes` verankert nu beide kanten opnieuw via de vingerafdruk, het
patroon dat `deck_provider_markdown.dart` al gebruikt mét een comment over
precies dit gevaar.

**3. "Ik kon het niet lezen" werd "ik gooi het weg".** Conflictmarkeringen uit
een merge buiten OciDeck zijn geen geldige JSON; een sidecar van een nieuwere
build leest deze build bewust niet. In beide gevallen zag de schrijfkant een
deck zonder notities en zette het pad in `deletes`. Op schijf is dat contract al
dichtgezet (`_sidecarUntouchable`); hier weegt het zwaarder, want dit bestand is
niet van jou alleen. Verwijderen mag nu alleen na het bestand gelézen te hebben
én vast te stellen dat het er een van dit formaat is. Zonder lezer nooit.

Zes merge-tests, drie wachtrij-tests en zeven "blijft staan"-tests; vijf van de
zes merge-tests werden rood tegen de ónherstelde code.

FILE_FORMAT was als enige document blijven staan met het omgekeerde van wat de
code doet, en is het document dat iemand leest die hier een ander werktuig op
bouwt — die krijgt nu §6.3.1, inclusief waarom de repo-kopie ingesprongen is.
En de keerzijde staat er nu bij, in de gids en in het commentaar van de
privacyprojectie: notities in een gedeelde repo leest iedereen met leesrechten,
ongescand, onder je eigen naam in het commitlog.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Tweede bewakerronde. De vorige reparatie landde op het REST-pad; het native pad
is wat de app kiest zodra git geïnstalleerd is, en dáár verdween nog steeds
alles.

**Waarom het misging.** `mergeRemote` gaf zijn resolver alleen de
`deck.md`-bytes van de drie kanten. Een deck is meer dan zijn markdown: de
notities staan in een eigen bestand per ref. Alle drie de decks leken dus
notitieloos, de merge had niets terug te geven, en omdat de deckmap wordt
vervángen door wat de resolver oplevert, stond het notitiebestand als
verwijdering in de merge-commit. Twee auteurs met een notitie op verschillende
dia's waren beiden alles kwijt — bij het gewoonste scenario dat er is, op de
standaardconfiguratie, met status "merged" en zonder melding.

`mergeRemote` geeft nu een `MergeSideReader` mee waarmee de resolver elk pad in
de deckmap per kant kan lezen (`git show <ref>:<pad>`). Ook het faalgeval draagt
nu onze notities: `{deckFile: ourBytes}` heette "onze kant blijft staan zoals
hij was" en was dat niet.

**Waar het nu woont.** De klasseratchet wees de weg: het hele oplosblok is naar
`resolveRepoDeckMerge` in de servicelaag verhuisd. Elke regel erin gaat over
opslag — welke lagen een kant draagt, wat er overblijft als het niet lukt, wat
de deckmap wordt — en de state-laag levert alleen wat zij als enige weet: de
importpoort en waar afbeeldingsbytes vandaan komen. `TabsNotifier` staat daarmee
16 regels ónder zijn oude plafond; dat plafond is meeverlaagd. Dit is een hap
uit #518.

**Twee kleinere gaten uit dezelfde ronde.** `SyncEngine` leidt zijn `deletes`
zelfstandig af en kwam langs de "niet aanraken"-regel heen: een onleesbaar
notitiebestand plus een offline bewerking wiste alsnog beide kanten. Die ene
uitzondering staat er nu, mét de reden dat dit het enige bestand in de deckmap
is dat van iemand anders kan zijn. En `declaredSidecarVersion` valt bij alles
wat geen map is terug op versie 1, dus een top-level array heette
"verwijderbaar" — nu sinds FILE_FORMAT §6.3.1 uitnodigt dit bestand vanuit een
ander werktuig te schrijven, is dat geen theorie meer.

Twee native tests tegen een echte bare origin op schijf; beide worden rood
tegen de onherstelde code. Plus drie in de sync-engine, met tegenproef.

Ten slotte in GIT_STORAGE §9.7 opgeschreven wat correct is maar nergens stond:
een notitie hoort bij de dia zoals die was, dus wie de dia van een ander
herschrijft laat diens notitie erop los. Dat is de codecregel, niet iets wat
deze merge verzint — maar in een gedeelde repo is het nu destructief, en dan
hoort het opgeschreven.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Het verhuizen van het native oplosblok naar de servicelaag haalde 16 regels uit
de klasse. Een ratchet die niet meezakt na een opruiming is geen ratchet: het
volgende stuk state-logica zou er zo weer in passen.

Alleen TabsNotifier. _SettingsDialogState kromp ook, maar die winst komt van een
andere tak en hoort daar vastgezet te worden — eerder deze sessie zette ik hem
op een meting van vóór de rebase, en dat brak de poort op code die niet van mij
was.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
fix(git): de "niet aanraken"-regel dekt nu ook het overschrijven (#541)
Some checks failed
CI / Web hardening (push) Failing after 23s
CI / Gate (Linux) · Format · Analyze · Coverage (push) Failing after 26s
CI / Docs links (push) Failing after 27s
CI / Supply-chain (Trivy · advisory) (push) Failing after 28s
CI / Gate (Linux) · Format · Analyze · Coverage (pull_request) Failing after 23s
CI / Docs links (pull_request) Failing after 24s
CI / Web hardening (pull_request) Failing after 26s
CI / Supply-chain (Trivy · advisory) (pull_request) Failing after 25s
CI / Test (macos-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Test (macos-latest) (pull_request) Has been cancelled
CI / Test (windows-latest) (pull_request) Has been cancelled
9450a7721c
Laatste uit de bewakerreeks, en de naarste van de familie. De regel bewaakte
het verwijderen van een notitiebestand dat deze build niet kon lezen, maar niet
het overschríjven ervan. Op schijf staat `_sidecarUntouchable` vóór de
vertakking en dekt hij beide richtingen; dat was hier niet gelijkgetrokken.

Het scenario heeft geen merge en geen tweede sessie nodig: een collega op een
nieuwere build schrijft `version: 3`. Jij opent het deck op 0.1.x, ziet terecht
geen notities, typt er één en slaat op. Er ging dan een v2-bestand met jouw ene
notitie over hun hele bestand heen. Dat is erger dan de verwijdering die deze
tak net dichtzette, want het resultaat ziet er daarna gezond uit — niemand gaat
in de historie zoeken.

De vraag is daarom omgedraaid: niet "mag dit weg" maar "mag ik hier aan komen",
één keer gesteld vóór de vertakking. `repoUserNotesState` geeft drie
toestanden — er ligt niets, er ligt iets van ons, er ligt iets wat we niet
begrijpen — en schrijven én verwijderen hangen daaraan. Zonder lezer is de
uitkomst "er ligt niets": schrijven mag dan wél (anders reizen de notities op
het native pad nooit) en verwijderen niet. Die asymmetrie is de veilige helft
van dezelfde onwetendheid, en staat er met zoveel woorden bij.

Vier tests op de schrijfkant, met tegenproef in twee richtingen; de poort
weghalen maakt ze rood.

Ook het #670-commentaar verbreed: dat gat zit niet alleen in de faaltak. Ook een
gelúkte native merge verwijdert `data/*.json`, want `merge.merged` draagt geen
inline cijfers. Aangevuld op het issue zelf, inclusief dat de tussenstap sinds
`resolveRepoDeckMerge` klein is geworden.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
brenno merged commit 5bcd620a37 into main 2026-07-22 19:23:39 +00:00
Sign in to join this conversation.
No description provided.