Commit Graph
5 Commits
Author SHA1 Message Date
Kristian WindandClaude Opus 5 241c5ed37d fix(mail): den samme mail blev en opgave igen og igen
Release / Build and publish image (push) Failing after 9m58s
Rapporteret fra drift med et skærmbillede af den samme mail seks gange i træk.

**IMAP: flaget kommer af, når mailen er blevet en opgave.** Markøren var et uid —
husk det højeste, begynd over det næste gang — og den holdt kun, hvis uids var,
hvad serveren sagde. Den brød på et fetch-svar uden uid, på en UIDVALIDITY, der
skiftede under en genopbygget postkasse, og på to postkasse-rækker, der pegede
samme sted og hver især førte deres eget regnskab. Alle tre gav det samme
symptom.

Så regnskabet flytter derhen, hvor spørgsmålet bliver stillet. "Flaget" betyder
"lav det her om til en opgave"; når den er en opgave, har flaget gjort sit
arbejde og er ikke sandt længere. Så er der ingenting at huske, og dermed
ingenting, der kan komme ud af trit — en anden synkronisering, en anden
postkasse-række eller en database gendannet fra en kopi finder alle det samme
svar, fordi svaret ligger i postkassen.

Flaget tages af *efter* opgaven er skrevet. Et flag fjernet fra en mail, hvis
opgave aldrig blev gemt, er en mail, ingen ser igen.

**Gmail havde den samme fejl af en anden grund.** Listen over allerede behandlede
beskeder blev bygget om ved hver kørsel af *kun de id'er, Gmail svarede med den
gang* — for at den ikke skulle vokse uendeligt. Men forespørgslen er begrænset,
så på en konto med mere stjernemarkeret post, end der er plads til i ét svar,
glemte hver kørsel det, den forrige havde husket. De kom tilbage som ubehandlede
og blev opgaver igen. Det var ikke en grænse, det var en måde at glemme på.
Listen har nu et loft på antal i stedet, nyeste først.

Gmail kan ikke få taget stjernen af: scopet er `gmail.readonly`, med vilje, fordi
det er dét, der gør samtykkeskærmen til noget, et menneske kan sige ja til. Derfor
skal regnskabet blive på vores side dér — men det skal så være et regnskab, der
kan holde.

Prøven kører hele vejen mod en rigtig IMAP-server: find de flagede, tag flaget af,
og spørg så forfra med markøren sat til nul — altså det værst tænkelige tilfælde,
hvor alt, vi selv havde husket, er væk. Der kommer ingenting tilbage.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 07:04:40 +02:00
Kristian WindandClaude Opus 5 86ec0ce2d9 fix(imap): markøren er vores, ikke serverens
Samme mail blev en opgave hver tiende minut, og markøren stod stille på 1271.
Målt i produktion: en manuel synk lavede én opgave og flyttede ikke last_uid en
eneste plads.

Årsagen er ikke vores regnestykke, men hvad søgningen svarer. Vi beder om
1272:* — og en rigtig server læser det som 0:1272 og sender hele postkassen
tilbage. Alt, hvad den finder, ligger så under markøren, og markøren kan derfor
aldrig komme videre.

Uid'er ved eller under markøren frasorteres nu hos os. Det koster ét gennemløb
af nogle hundrede tal og afhænger ikke af nogen andens læsning af specifikationen.

De to tidligere forsøg var ikke forkerte, de var bare ikke årsagen: at tage
uid'en fra søgningen frem for fra fetch-svaret, og at give hver postkasse sin
egen lås, var begge reelle fejl. Denne er den, der fik den til at gentage sig.

Prøven læser en postkasse med markøren over alt i den og kræver nul tilbage —
og gentager det for hver enkelt besked.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 12:33:30 +02:00
Kristian WindandClaude Opus 5 f3fecbd0b4 fix(imap): samme mail blev en ny opgave hver gang, og uddraget var rå MIME
To fejl fra ét skærmbillede.

Markøren stod stille. Den blev sat ud fra uid'en i fetch-svaret, og den kommer
ikke fra alle servere — så next-run læste fra nul hver gang. Den sættes nu ud fra
hvad SØGNINGEN fandt, når kørslen kom hele vejen igennem: så er alt op til det
punkt betragtet, uanset hvad fetch-svaret bar med. En afbrudt kørsel flytter kun
til den sidste, den faktisk lavede en opgave af. Prøven mod hukommelsesserveren
ville aldrig have fanget det, for den svarer altid med uid.

Og uddraget hentede BODY[TEXT], som ved multipart er grænser og dele-hoveder og
det hele — derfor stod der "--=_be71cb39… Content-Transfer-Encoding: 8bit" foran
teksten i hver eneste opgave. Nu hentes hele beskeden og MIME-strukturen gås
igennem: text/plain foretrækkes, HTML er reserven med mærkerne pillet af. Groft,
for det er linjen under en overskrift og ikke en gengivelsesmotor.

Multipart-prøven er sat på prøve: med den gamle hentning fejler den med præcis
den tekst, skærmbilledet viste.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 22:44:00 +02:00
Kristian WindandClaude Opus 5 6b4ef5b2f2 feat(imap): postkasser kan læses, og det er bevist mod en rigtig server
Handlere til at forbinde, koble fra og hente nu, plus baggrundssynk hvert tiende
minut ved siden af Gmails. Forbindelsen prøves FØR den gemmes: en postkasse, der
blev taget imod og så fejler stille hvert tiende minut, er værre end en, der blev
afvist ved døren, mens man stadig sidder med kodeordet i hånden.

Ingen "set"-liste til deduplikering som Gmail har. Uid'er er monotone, så
last_uid er hele svaret — og den skrives også, når budgettet løb ud, for en
kørsel, der lavede opgaver og glemte hvor langt den nåede, laver dem alle igen
næste gang.

Rundturen køres nu mod go-imap's egen server i processen: flaget post kommer med,
uflaget gør ikke, og fortsættelsen fra et uid henter kun det nyere. De hidtidige
prøver dækkede de rene dele og ville alle have bestået med selve hentningen i
stykker.

Testen kræver et selvsigneret certifikat, og klienten nægter dem. Account.RootCAs
lader en test TILFØJE tillid; der er stadig ingen måde at fjerne den på. Forskellen
er en søm og ikke et hul — en prøve viser, at samme server afvises uden.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 22:15:50 +02:00
Kristian WindandClaude Opus 5 aabbbac583 feat(imap): en postkasse, der ikke er Gmail
Første del af IMAP-understøttelsen: selve klienten, som sit eget hjørne uden
tråde ud i noget bestående. Den logger ind over TLS, henter de flagede beskeder
nyere end et givet uid, og giver dem tilbage i samme form som Gmail-klienten —
afsender, emne, uddrag — så den, der senere kalder dem, kan få at vide hvor der
skal kigges og ikke hvordan.

Flagede og ikke ulæste: ulæst er en tilstand, ejeren stadig bruger, og en synk,
der brugte den op, ville tage noget fra ham. Det er samme begrundelse som stjerner
på Gmail-siden.

TLS er ikke valgfrit, og der er ingen kontakt til at slå det fra. Det her bærer et
kodeord, der åbner en hel postkasse, og en kontakt til at fjerne beskyttelsen er
en kontakt, der en dag bliver fundet allerede slået fra.

iCloud og enhver almindelig udbyder taler det her. Office 365 gør ikke længere —
Microsoft har lukket for kodeord på IMAP og vil have sit eget OAuth — så det er
ikke en vært, man kan nå herfra, og at lade som om ville kun fejle senere og
mindre tydeligt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 20:21:45 +02:00