## Mærket
Urds oplagte mærke var ᚢ uruz — bogstavet navnet begynder med i den ældre
futhark, præcis som Verdandes er ᚹ wunjo. Det blev tegnet sådan først.
Men uruz er allerede et af husets egne produkter, og dets egen
`scripts/gen-icons.ts` siger i sin kommentar at den "draws the Uruz rune (ᚢ)
in rune-gold" med "a tall left vertical, a shoulder across the top, and a
shorter" — altså samme glyf, samme konstruktion, kun en anden farve. To af
samme persons apps side om side på en hjemmeskærm, hvilket er nøjagtig det
sted mærket skal kunne skelnes.
ᚦ thurisaz blev forkastet et niveau nede af samme grund: en stav med en
trekant til højre, og det er ᚹ også. Ved 16px er de én form.
Så bogstavet frem for runen: ð, ethet i Urðr. Centreret ved at tælle malede
pixels frem for ud fra path-tallene, fordi en centreret kasse ikke er en
centreret glyf:
verdande ᚹ blæk x 53–108 midte 80.5 · y 18–131 midte 74.5
urd ð blæk x 39–110 midte 74.5 · y 15–134 midte 74.5
Verdandes +5.5 i x er dens egen bevidste forskydning — en tung stav ved
siden af et let flag skal sidde til højre for midten for at se centreret ud.
ð er symmetrisk nok til at undvære den, og de to er enige i y.
Læsbarhed, målt: ð læses fra 32px og op. Ved 16px er det en klat, og det er
ᚹ også — en favicon er ikke det, der skiller to installerede apps i en dock.
`productRune` hedder nu `productMark`, fordi ð ikke er en rune.
## Determinisme
SvelteKits `kit.version.name` er som standard `Date.now()`. Millisekundet
landede i version.json, i index.html og i service-workeren, ændrede
indholdshashen på hver chunk der refererer dem, og dermed deres filnavne. To
bygninger af samme commit havde forskellige filer i sig.
Dockerfilen har i et år sagt at `-trimpath` og en tom buildid "keep the
output reproducible". Flagene gjorde deres arbejde; frontenden i binæren bar
et tidsstempel. Sætningen var falsk, og ingen læste den.
Fastgjort til VERSION, som udgivelsen allerede sender ind, og `dev` når
intet sætter den. Målt ved at bygge to gange og diffe træet, før og efter.
Prisen er at et lokalt `npm run build` ikke længere ligner en ny version for
service-workeren — hvilket kun betyder noget på en udrullet instans, hvor
udgivelsen sender det rigtige mærkat.
Det gør også CI's nye påstand mulig: de to images deler alle lag, så urd
bærer samme binær som verdande frem for en genbygning der tilfældigvis
matcher.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Prøven, der skal holde udgaverne adskilt, stod grøn gennem to merges, mens
34 opgaveruter blev betjent af noter-udgaven. Den fejlede ikke: den
sammenligner routeren med en nedskreven liste, og listen var skrevet ud
fra de ruter, nogen havde tænkt på. Den er en DRIFT-kontrol, og den kan
ikke være en fuldstændighedskontrol. Det står nu i prøven selv.
Lukket: CalDAV-træet (8 ruter, alle læser eller skriver en VTODO),
.well-known/caldav (en påstand om at der er en CalDAV-server), ICS-feedet
og de to ruter til dets token, de fire opgave-eksporter, Todoist- og
CSV-importen, skabelonerne, sektionerne, de seks AI-opgaveruter og
indbakke-krogen. Plus fem af ni MCP-værktøjer — endepunktet er der
stadig, værktøjslisten er kortere.
Tre blev afgjort ved at læse frem for ved navnet: en skabelon laver
opgaver (CreateProjectFromTemplate), `section_id` står på `tasks` og
findes ikke på `notes`, og add_comment hænger på en opgave.
Men den dyre halvdel var fladen. En vandring gennem hver side, der kan
nås i noter-udgaven, med konsollen og svarene aflæst, fandt SYV brud —
fire af dem fra den første port:
sidebjælken GET /filters 404 ved hver navigation, ædt af .catch()
sidebjælken GET /labels 404 ved hver navigation, ædt af .catch()
notifikationer GET /ai/plan 404, stille
notesbogens side GET /tasks kastede → status = 'failed'
notesbogens side GET /sections kastede → samme fejlskærm
indstillinger GET /templates toast med fejlbesked på skærmen
integrationer GET /feed 404, stille
Den fjerde er den, der har kostet noget: /projekt/{id} er notesbogens
side, og kaldene samles i et Promise.all, så én 404 tog hele siden med.
Den har vist en fejlskærm frem for noter siden porten blev sat. Ingen
prøve åbnede en notesbog i den udgave, og .catch(() => {}) sørgede for,
at resten ikke sagde noget. "Fladen følger udgaven" var sandt om menuen
og falsk om hentningerne.
Vagten for opgaver står i butikken frem for ved kaldestederne: der var
tre, og den fjerde blev glemt — hvilket er præcis sådan, den slap
igennem.
Og rettelsen lavede selv en fejl, som vandringen fangede: da opgavekaldet
holdt op med at fejle, kom en uendelig effekt-løkke frem, som 404'eren
havde holdt låg på. En ubetinget tilskrivning til app.tasks får
projektsidens effekt til at kalde tilbage. 404'eren var låget på en
løkke, ikke bare støj.
Også: -timeout 20m i begge CI-workflows. internal/httpapi tog 664s her og
498s i CI på #95, mod Go's standardgrænse på 600 — og når den krydses, er
beskeden "panic: test timed out after 10m0s" plus et goroutine-dump, som
læser som en deadlock i koden frem for som en suite, der blev for stor.
watchForTrouble udskilt til web/e2e/trouble.js, så udgave-suiten kan bruge
den samme.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Serverens side er bekræftet — Gitea tillader fetch ved hash, målt direkte mod
instansen. Tilbage stod kun, om act_runners auto-token duer som kodeord i
basic auth, og hvilket brugernavn den vil have. Det kan kun en kørende runner
svare på.
Feedback-sløjfen går gennem en kø og et andet menneske, så en kørsel, der kun
siger 'checkout fejlede', er for dyr. Trinnet prøver nu x-access-token først —
den form actions/checkout bruger, og som økosystemet beviser virker mod Gitea —
derefter $GITHUB_ACTOR, og skriver hvilken der blev godkendt. Én kørsel
besvarer spørgsmålet, uanset om den ender grøn eller rød.
Køen på Gitea kan kun ryddes ved at slå Actions fra og til igen, og det
dropper alt, også den kørsel man ville beholde. Uden en dispatch-udløser er
den eneste vej tilbage at skubbe en tom commit — en løgn om, at der skete
noget. Nu kan en kørsel startes mod uændret kode.
DEFAULT_ACTIONS_URL står ikke i app.ini på gitea.nolimit.dk, og standarden er
github.com. Et `uses: actions/checkout@v4` i et Gitea-workflow bliver derfor
hentet fra GitHub, hver gang, også når både koden, runneren og registret er
vores egne — så et workflow, der bruger markedspladsen, ser uafhængigt ud uden
at være det.
Begge Gitea-workflows er skrevet om uden `uses:`. Værktøjskæden kommer fra
jobbets container, hvilket er det, setup-go ellers ville bruge et trin på;
checkout, login, metadata og buildx er de rå kommandoer, handlingerne pakker.
Det, der ikke fulgte med: rapporten fra en fejlet e2e-kørsel. upload-artifact
har ingen `run:`-form, så grunden står i loggen frem for i en zip.
Udgivelsen fik samtidig en rettelse, GitHub-udgaven ikke har: en forudgivelse
(v1.4.2-rc1) får kun sit eget mærkat. At lade en rc overskrive :latest eller :1
ville sende den ud til alle, der troede, de fulgte det stabile spor.
Issue-skabeloner i .gitea/ for sig: Gitea kræver `about`, hvor GitHub skriver
`description`, og afviser en skabelon uden.