# Release Checklist (Dansk) 🌐 **Languages:** 🇺🇸 [English](../../../../ops/RELEASE_CHECKLIST.md) · 🇪🇹 [am](../../../am/docs/ops/RELEASE_CHECKLIST.md) · 🇸🇦 [ar](../../../ar/docs/ops/RELEASE_CHECKLIST.md) · 🇦🇿 [az](../../../az/docs/ops/RELEASE_CHECKLIST.md) · 🇧🇬 [bg](../../../bg/docs/ops/RELEASE_CHECKLIST.md) · 🇧🇩 [bn](../../../bn/docs/ops/RELEASE_CHECKLIST.md) · 🇧🇦 [bs](../../../bs/docs/ops/RELEASE_CHECKLIST.md) · 🇨🇿 [cs](../../../cs/docs/ops/RELEASE_CHECKLIST.md) · 🇩🇪 [de](../../../de/docs/ops/RELEASE_CHECKLIST.md) · 🇬🇷 [el](../../../el/docs/ops/RELEASE_CHECKLIST.md) · 🇪🇸 [es](../../../es/docs/ops/RELEASE_CHECKLIST.md) · 🇪🇪 [et](../../../et/docs/ops/RELEASE_CHECKLIST.md) · 🇮🇷 [fa](../../../fa/docs/ops/RELEASE_CHECKLIST.md) · 🇫🇮 [fi](../../../fi/docs/ops/RELEASE_CHECKLIST.md) · 🇫🇷 [fr](../../../fr/docs/ops/RELEASE_CHECKLIST.md) · 🇮🇪 [ga](../../../ga/docs/ops/RELEASE_CHECKLIST.md) · 🇮🇳 [gu](../../../gu/docs/ops/RELEASE_CHECKLIST.md) · 🇳🇬 [ha](../../../ha/docs/ops/RELEASE_CHECKLIST.md) · 🇮🇱 [he](../../../he/docs/ops/RELEASE_CHECKLIST.md) · 🇮🇳 [hi](../../../hi/docs/ops/RELEASE_CHECKLIST.md) · 🇭🇷 [hr](../../../hr/docs/ops/RELEASE_CHECKLIST.md) · 🇭🇺 [hu](../../../hu/docs/ops/RELEASE_CHECKLIST.md) · 🇦🇲 [hy](../../../hy/docs/ops/RELEASE_CHECKLIST.md) · 🇮🇩 [id](../../../id/docs/ops/RELEASE_CHECKLIST.md) · 🇳🇬 [ig](../../../ig/docs/ops/RELEASE_CHECKLIST.md) · 🇮🇹 [it](../../../it/docs/ops/RELEASE_CHECKLIST.md) · 🇯🇵 [ja](../../../ja/docs/ops/RELEASE_CHECKLIST.md) · 🇬🇪 [ka](../../../ka/docs/ops/RELEASE_CHECKLIST.md) · 🇰🇭 [km](../../../km/docs/ops/RELEASE_CHECKLIST.md) · 🇮🇳 [kn](../../../kn/docs/ops/RELEASE_CHECKLIST.md) · 🇰🇷 [ko](../../../ko/docs/ops/RELEASE_CHECKLIST.md) · 🇱🇹 [lt](../../../lt/docs/ops/RELEASE_CHECKLIST.md) · 🇱🇻 [lv](../../../lv/docs/ops/RELEASE_CHECKLIST.md) · 🇮🇳 [ml](../../../ml/docs/ops/RELEASE_CHECKLIST.md) · 🇮🇳 [mr](../../../mr/docs/ops/RELEASE_CHECKLIST.md) · 🇲🇾 [ms](../../../ms/docs/ops/RELEASE_CHECKLIST.md) · 🇲🇹 [mt](../../../mt/docs/ops/RELEASE_CHECKLIST.md) · 🇲🇲 [my](../../../my/docs/ops/RELEASE_CHECKLIST.md) · 🇳🇵 [ne](../../../ne/docs/ops/RELEASE_CHECKLIST.md) · 🇳🇱 [nl](../../../nl/docs/ops/RELEASE_CHECKLIST.md) · 🇳🇴 [no](../../../no/docs/ops/RELEASE_CHECKLIST.md) · 🇮🇳 [or](../../../or/docs/ops/RELEASE_CHECKLIST.md) · 🇮🇳 [pa](../../../pa/docs/ops/RELEASE_CHECKLIST.md) · 🇵🇭 [phi](../../../phi/docs/ops/RELEASE_CHECKLIST.md) · 🇵🇱 [pl](../../../pl/docs/ops/RELEASE_CHECKLIST.md) · 🇵🇹 [pt](../../../pt/docs/ops/RELEASE_CHECKLIST.md) · 🇧🇷 [pt-BR](../../../pt-BR/docs/ops/RELEASE_CHECKLIST.md) · 🇷🇴 [ro](../../../ro/docs/ops/RELEASE_CHECKLIST.md) · 🇷🇺 [ru](../../../ru/docs/ops/RELEASE_CHECKLIST.md) · 🇱🇰 [si](../../../si/docs/ops/RELEASE_CHECKLIST.md) · 🇸🇰 [sk](../../../sk/docs/ops/RELEASE_CHECKLIST.md) · 🇸🇮 [sl](../../../sl/docs/ops/RELEASE_CHECKLIST.md) · 🇷🇸 [sr](../../../sr/docs/ops/RELEASE_CHECKLIST.md) · 🇸🇪 [sv](../../../sv/docs/ops/RELEASE_CHECKLIST.md) · 🇰🇪 [sw](../../../sw/docs/ops/RELEASE_CHECKLIST.md) · 🇮🇳 [ta](../../../ta/docs/ops/RELEASE_CHECKLIST.md) · 🇮🇳 [te](../../../te/docs/ops/RELEASE_CHECKLIST.md) · 🇹🇭 [th](../../../th/docs/ops/RELEASE_CHECKLIST.md) · 🇹🇷 [tr](../../../tr/docs/ops/RELEASE_CHECKLIST.md) · 🇺🇦 [uk-UA](../../../uk-UA/docs/ops/RELEASE_CHECKLIST.md) · 🇵🇰 [ur](../../../ur/docs/ops/RELEASE_CHECKLIST.md) · 🇺🇿 [uz](../../../uz/docs/ops/RELEASE_CHECKLIST.md) · 🇻🇳 [vi](../../../vi/docs/ops/RELEASE_CHECKLIST.md) · 🇳🇬 [yo](../../../yo/docs/ops/RELEASE_CHECKLIST.md) · 🇨🇳 [zh-CN](../../../zh-CN/docs/ops/RELEASE_CHECKLIST.md) · 🇹🇼 [zh-TW](../../../zh-TW/docs/ops/RELEASE_CHECKLIST.md) --- > **Senest opdateret:** 2026-08-28 — v3.8.51 > Strømlinet udgivelsesflow, der udnytter Claude Code-færdigheder til automatisering. > > **Hold køen/branchen grøn mellem udgivelser:** se [RELEASE_GREEN.md](./RELEASE_GREEN.md) > (`/green-prs`-familien + `npm run check:release-green` + `/babysit` + natlig kørsel). Hvis dette > køres regelmæssigt — og især **før** denne tjekliste — starter udgivelses-PR'en grønt. ## Kort fortalt ```bash # 1. Opdatér versionen + generér CHANGELOG (færdighed) /version-bump-cc patch # eller minor/major # 2. Kør kvalitetskontrollen lokalt npm run check # linting + tests npm run test:coverage # fuld dækningskontrol (60/60/60/60) # 3. Byg og udfør en smoke-test npm run build npm run test:e2e # valgfrit, men anbefalet # 4. Generér udgivelsen (færdighed) /generate-release-cc # 5. Udrul (færdighed) /deploy-vps-both-cc # eller akamai-cc / local-cc # 6. Indsaml udgivelsesdokumentation (færdighed) /capture-release-evidences-cc ``` ## npm Trusted Publishing (standard siden v3.8.51) — trinvis efter anmodning, direkte som reserve `npm-publish.yml` udgiver som standard via **npm Trusted Publishing (OIDC)**: `stage-npm`-jobbet (hostet af GitHub) udveksler GitHubs id-token med en kortlivet npm-legitimationsoplysning til den pågældende kørsel — intet langlivet npm-token i repository-hemmelighederne, ingen 2FA-anmodning, og proveniens er vedhæftet. Det er den omgåelse, npm nu tillader, efterhånden som tokens, der springer 2FA over, udfases; det genopretter det fuldautomatiske flow, som projektet havde frem til v3.8.48, samtidig med at WS1.3-garantien bevares (et lækket token kan ikke udgive alene — der findes intet token). **Engangsopsætning (ejer):** npmjs.com → pakken `omniroute` → Settings → _Trusted Publisher_ → GitHub: ejer `diegosouzapw`, repository `OmniRoute`, workflow `npm-publish.yml` (miljø: intet). Indtil dette findes, mislykkes det automatiske trin med `ENEEDAUTH`: start det igen med `publish_mode=staged` (nedenfor) eller `direct`. ### Trinvis udgivelse (efter anmodning — `publish_mode=staged`) npm-publish-workflowet udgiver ikke længere direkte: Det starter den pakkede tarball (`check:pack-boot`) og kører derefter `npm stage publish` — de præcise bytes parkeres i registreringsdatabasen og kan **ikke installeres**, før ejeren godkender dem. Den menneskelige 2FA-kontrol er flyttet til EFTER beviset, ikke før det. **Ejerens flow, efter at workflowet bliver grønt:** 1. `npm stage list omniroute` — find stage-id'et (det vises også i workflowoversigten). 2. Verificér de trinvist klargjorte bytes (anbefalet): `npm stage download `, installér derefter den downloadede tarball i et midlertidigt præfiks, og start den (`npm run check:pack-boot` automatiserer den samme pak→installér→start-vurdering i CI). 3. `npm stage approve ` — 2FA-anmodningen ER udgivelsen. `npm stage reject ` kasserer den. 4. Sikkerhedsnet efter udgivelse: Verifikatoren efter udgivelse (WS1.4 i v3.8.49-planen) installerer den udgivne version fra den offentlige registreringsdatabase i en ren container og starter den. **Nødreserve:** `workflow_dispatch` med `publish_mode=direct` genopretter den ældre, øjeblikkelige `npm publish` (brug kun dette, hvis den trinvise klargøring selv fejler; dokumentér hvorfor). **Engangssikring (ejer, npmjs.com):** Konfigurér Trusted Publisher for `omniroute` i en tilstand, der kun tillader trinvis klargøring, så et lækket langlivet token ikke kan køre `npm publish` direkte nogetstedsfra — CI kan kun klargøre trinvist; kun ejerens 2FA kan frigive udgivelsen. **Procedure for defekte artefakter (uændret):** `npm deprecate omniroute@ " — use "` som standardreaktion (tager få minutter og kan tilbageføres); brug kun `npm unpublish` inden for 72-timersvinduet/perioden uden afhængige pakker og aldrig som første handling. Docker: Omskriv aldrig et versionstag — tilbagerulning sker ved at omdirigere `latest` til den seneste fungerende digest. **Docker Hub `latest` (påkrævet ved hver stabil SemVer-udgivelse):** `docker-publish`-workflowet skal tagge **både** `X.Y.Z` og, når `should-promote-latest.sh` bekræfter, at dette er den højeste stabile SemVer, `:latest` med **samme digest**. Efter jobbet: Hub-`latest`-digesten skal være lig med den nye SemVer-digest, og `last_updated` skal være ændret. Lad ikke `:latest` pege på et ældre build, mens udgivelsesnoterne omtaler rettelser, som kun findes i git. Compose- hurtigstarter bruger `:latest`; GitOps bør fortsat fastlåse `X.Y.Z`. Se [Docker-udgivelseskanaler](../guides/DOCKER_GUIDE.md#release-channels) og #10317. ## Hurtig hotfix-bane (label `hotfix`) En PR med labelen `hotfix` springer den tunge CI-matrix over (E2E med 9 shards, dæknings-ratchet, quality-gate, quality-extended) og beholder de hurtige kontrolpunkter med høj signalværdi: build, unit-shards, integration, vitest, lint/typecheck, docs-sync, `check:pack-artifact` og tarball-boot-smoke-testen (`check:pack-boot`). Mål: grøn på ≤15 min. i stedet for ~33 min. **Adgangspolitik — alle fire krav skal være opfyldt (modelleret efter nødbaner i Chromium/VS Code/Node):** 1. **Alvorlighed**: Produktion er brudt — en publiceret artefakt crasher ved opstart / en sikkerhedsrettelse / alle brugere af udgivelsen er berørt. "Vigtigt" er ikke det samme som "brudt". 2. **Bemyndigelse**: Kun repository-ejeren anvender labelen `hotfix`. Labelen ER godkendelsen — aldrig selvbetjening på en kampagne-PR. 3. **Dokumentation**: PR-beskrivelsen linker til den foregående helt grønne, tunge kørsel (den suite, som de oversprungne jobs ellers ville genvalidere) samt rettelsens egen test, der først fejler og derefter består. 4. **Omfang**: Kun cherry-pick — den mindst mulige rettelse, ingen refaktoreringer, ingen medfølgende ændringer. Den oversprungne dæknings-/ratchet-flade genvalideres af den næste fulde kørsel på release-branchen (kontinuerligt grøn release) — banen springer VENTETID over, aldrig validering. Diffs, der kun indeholder tests (alle filer under `tests/`, ingen under `tests/e2e/`), springer automatisk E2E-matrixen over uden nogen label. ## Detaljeret tjekliste ### Før udgivelse - [ ] Alle PR'er, der er målrettet denne udgivelse, er flettet ind i `release/vX.Y.0` - [ ] Alle åbne Linear-/issue-elementer for denne version er lukket eller flyttet til næste milepæl - [ ] CI er grøn på grenen `release/vX.Y.0` - [ ] Ingen `TODO(release)`-markører i koden: `grep -r "TODO(release)" src/ open-sse/` - [ ] Docker-basisimaget er opdateret (aktuelt `node:24.15.0-trixie-slim`) ### Version og ændringslog - [ ] Kør `/version-bump-cc ` (Claude Code-færdighed) - Opdaterer versionen i `package.json`, `electron/package.json` - Gendanner `CHANGELOG.md` ud fra Git-commits siden seneste tag - Opdaterer badges i README.md - [ ] Gennemgå CHANGELOG.md manuelt, og ryd op i commit-beskeder efter behov - [ ] Sørg for, at den seneste semver-sektion i `CHANGELOG.md` svarer til versionen i `package.json` - [ ] Behold `## [Unreleased]` som den første sektion i ændringsloggen til kommende arbejde - [ ] Opdater `docs/openapi.yaml` → `info.version` skal svare til versionen i `package.json` ### Kodekvalitet - [ ] `npm run lint` — 0 fejl (advarslerne fandtes i forvejen) - [ ] `npm run typecheck:core` — fejlfri - [ ] `npm run typecheck:noimplicit:core` — fejlfri (streng) - [ ] `npm run check:cycles:ratchet` — inden for det fastlåste `metrics.cycles`-loft (den rene `check:cycles` afslutter med 1 ved enhver cyklus, #15281) - [ ] `npm run check:any-budget:t11` — inden for budgettet - [ ] `npm run check:route-validation:t06` — fejlfri - [ ] `npm run check:node-runtime` — minimumskravet til understøttet runtime er opfyldt (`>=22.22.2 <23`, `>=24.0.0 <27`, jf. `SUPPORTED_NODE_RANGE` i `src/shared/utils/nodeRuntimeSupport.ts`; afstemt med `engines` i `package.json`) ### Test - [ ] `npm run test:unit` — bestået - [ ] `npm run test:vitest` — bestået (MCP-server, autoCombo, cache) - [ ] `npm run test:coverage` — kravet på 60/60/60/60 er opfyldt (instruktioner/linjer/funktioner/grene) - [ ] `npm run test:integration` — bestået (hvis ændringer berører DB/håndteringsfunktioner) - [ ] `npm run test:combo:matrix` — bestået (matrix for combo-strategier: dokumenterer deterministisk udvælgelsesbeslutningerne for alle 19 offentlige routingstrategier; kør ved ændringer af combo-routing, strategiopløsning eller fallback-logik) - [ ] `RUN_COMBO_LIVE=1 npm run test:combo:live` — **valgfri/manuel** (adgangsstyret smoke-test mod reelle upstream-tjenester; henter et skrivebeskyttet DB-snapshot fra VPS'en `root@192.168.0.15`; rammer reelle udbydere og koster kreditter; kører aldrig i CI; springes problemfrit over uden adgangsparameteren) - [ ] `npm run test:combo:live:vps` — **valgfri/manuel** (fase 3-VPS-smoke-test i produktion: 7 HTTP-scenarier mod den aktive `.15`-server via ren Node ESM; kræver `ssh root@192.168.0.15`; opretter/sletter kun `__live_test__*`-comboer; rammer reelle udbydere; kører aldrig i CI) - [ ] `npm run test:e2e` — bestået (UI-ændringer) - [ ] `npm run test:protocols:e2e` — bestået (MCP-/A2A-ændringer) - [ ] `npm run test:ecosystem` — bestået ### Hooks (valideret af Husky) Husky-hooks ligger i `.husky/` og kører automatisk ved Git-handlinger. - **pre-commit:** `npx lint-staged + node scripts/check/check-docs-sync.mjs + npm run check:any-budget:t11` - **pre-push:** hurtige, deterministiske kontroller — `npm run check:any-budget:t11 && npm run check:tracked-artifacts` (aktiveret 2026-06-13). Udelader bevidst `test:unit` (langsom; dækket af CI-jobbet `test-unit`). - Kør `npm run test:unit` manuelt, før udgivelsesgrene pushes. Hvis en hook fejler: Ret det underliggende problem; omgå den ikke med `--no-verify`. ### Konventionelle commits Alle commits, der skal med i udgivelsen, skal følge formatet `type(scope): subject`. **Gyldige typer:** `feat`, `fix`, `refactor`, `docs`, `test`, `chore`, `perf`, `style`, `ci` **Gyldige scopes:** `db`, `sse`, `oauth`, `dashboard`, `api`, `cli`, `docker`, `ci`, `mcp`, `a2a`, `memory`, `skills`, `cloud-agent`, `guardrails`, `compression`, `auto-combo`, `resilience`, `providers`, `executors`, `translator`, `domain`, `authz` Inkompatible ændringer: Tilføj sidefoden `BREAKING CHANGE:` eller `!` efter scopet (f.eks. `feat(api)!: drop /v0`). ### Dokumentation - [ ] `npm run check:docs-sync` består (køres automatisk af pre-commit) - [ ] `npm run check:docs-all` består (samlet kontrol: docs-sync + docs-counts + env-doc-sync + deprecated-versions + doc-links) - [ ] `npm run check:env-doc-sync` afslutter med 0 — kontrakten for miljøvariabler mellem kode ↔ `.env.example` ↔ `docs/reference/ENVIRONMENT.md` er intakt - [ ] `npm run check:doc-links` afslutter med 0 — ingen ugyldige interne Markdown-referencer efter omstrukturering - [ ] `docs/architecture/ARCHITECTURE.md` er gennemgået for afvigelser i lager/runtime - [ ] `docs/guides/TROUBLESHOOTING.md` er gennemgået for afvigelser i miljøvariabler og drift - [ ] Hvis `.env.example` er ændret: `docs/reference/ENVIRONMENT.md` er opdateret - [ ] Hvis en ny funktion har en UI: `docs/guides/USER_GUIDE.md` omtaler den - [ ] Hvis en ny funktion har et API: `docs/reference/API_REFERENCE.md` + `docs/openapi.yaml` er opdateret - [ ] Hvis en ny funktion er et modul: Der findes en dedikeret `docs/.md` - [ ] Hvis der er en inkompatibel ændring: `docs/guides/TROUBLESHOOTING.md` indeholder en migreringsbemærkning ### i18n - [ ] `npm run i18n:check` afslutter med 0 — oversættelsestilstanden (`.i18n-state.json`) er synkroniseret med kildedokumenterne (ingen afvigende kilder i streng tilstand; en vejledende advarselstilstand er acceptabel ved dokumentrettelser i sidste øjeblik, men resultatet bør være 0 før tagging) - [ ] `npm run i18n:check-ui-coverage` afslutter med 0 — hver UI-lokalitet opfylder eller overstiger minimumskravet på 80 % dækning - [ ] `npm run i18n:sync-ui:dry` rapporterer 0 manglende nøgler på tværs af alle 66 mållokaliteter (alle lokaliteter undtagen kilden `en`) - [ ] Hvis de engelske kildedokumenter er ændret, skal `npm run i18n:run` køres (kræver `OMNIROUTE_TRANSLATION_API_KEY` i `.env`) før tagging - [ ] Oversættelsesbidrag kan udskydes til næste udgivelse, hvis de er mindre væsentlige (registrér det i CHANGELOG) ### Databasemigreringer - [ ] Hvis `src/lib/db/migrations/` har nye filer: - [ ] Hver migrering er idempotent (`CREATE TABLE IF NOT EXISTS` osv.) - [ ] Migreringer er pakket ind i transaktioner - [ ] Korrekt nummereret (ingen huller i rækkefølgen) - [ ] Test på en ny installation: Slet `~/.omniroute/omniroute.db`, og kør `npm run dev` - [ ] Test på en eksisterende installation: Sikkerhedskopiér DB'en, kør migreringen, og verificér skemaet - [ ] WAL-filer (`-wal`, `-shm`) håndteres korrekt, hvis migreringen omskriver tabeller ### Udbyderkatalog (Zod-valideret) - [ ] `src/shared/constants/providers.ts`-Zod-skemaet er gyldigt ved indlæsning - [ ] Alle udbydere har obligatoriske felter (`id`, `label`, `kind` osv.) - [ ] `freeNote` er angivet for nye gratis udbydere - [ ] OAuth-udbydere har `oauthConfig` registreret i `src/lib/oauth/constants/oauth.ts` - [ ] Hvis en ny udbyder tilføjes: tilsvarende executor i `open-sse/executors/` - [ ] Hvis formatet ikke er OpenAI: translator i `open-sse/translator/` - [ ] Modeller er registreret i `open-sse/config/providerRegistry.ts` - [ ] Enhedstests i `tests/unit/` dækker klassificering og routing af udbydere ### Desktop (Electron) Hvis `electron/` er ændret: - [ ] `npm run electron:smoke:packaged` består - [ ] Builds er testet for mindst én af `:win`, `:mac`, `:linux` - [ ] Certifikater til kodesignering er ikke udløbet (hvis der signeres) - [ ] Versionen i `electron/package.json` matcher rodprojektets `package.json` - [ ] Markøren for den automatiske opdateringskanal er opdateret, hvis der udgives til `stable` ### Buildstruktur Repositoryet bruger tre separate outputmapper — bland dem aldrig sammen: | Mappe | Formål | Versionsstyret? | | --------- | ------------------------------------------------------------- | ---------------- | | `src/` | Applikationens kildekode (TypeScript / TSX) | Ja | | `.build/` | Midlertidige buildfiler — output fra `next build` (`distDir`) | Nej (gitignored) | | `dist/` | Distribuerbar npm-pakke — samlet af `assembleStandalone` | Nej (gitignored) | > **Bemærkning til operatøren:** Mappen i det eksterne VPS-image forbliver `/usr/lib/node_modules/omniroute/app/`. > Kun buildoutputtet **i repositoryet** er flyttet (`app/` → `dist/`). Deploy-funktionerne bruger rsync til at overføre > indholdet af `dist/` til den eksterne `app/`-mappe — ingen ændringer af VPS-stier er nødvendige. **Flow med ét build:** ``` npm run build:release └─ rm -rf .build dist (oprydning) └─ next build → .build/next/ (midlertidige filer) └─ assembleStandalone (kopierer standalone + static + public + natives → dist/) └─ skriver dist/BUILD_SHA (HEAD-markør) ``` Kør IKKE `npm run build` efterfulgt af et separat `npm run build:cli` ved deployment — brug `npm run build:release`, som udfører et rent rebuild og opretter markøren med én kommando. ### Validering af artefakter - [ ] `npm run build:release` lykkes, og `dist/BUILD_SHA` == `git rev-parse --short HEAD` - [ ] `npm run check:pack-artifact` er ren — ingen `app.__qa_backup`, `scripts/scratch`, `package-lock.json` eller andre lokale rester - [ ] `dist/server.js` findes efter buildet - [ ] Valgfri lokal smoke-test af den pakkede runtime: `npm run dev:candidate -- validate` efter `npm run dev:candidate -- build` starter den pakkede tarball med en isoleret `DATA_DIR` og kontrollerer `/api/health` + `/v1/models` (se [Contribution Golden Path](CONTRIBUTION_GOLDEN_PATH.md#local-candidate-loop)) ### Tagging og udgivelse - [ ] Kør `/generate-release-cc` (Claude Code-funktion): - Opretter tagget `vX.Y.Z` - Pusher tag og branch - Opretter en GitHub Release med changelog som brødtekst - Vedhæfter Electron-installationsprogrammer (hvis de er bygget) - [ ] Eller gør det manuelt: ```bash git tag -a vX.Y.Z -m "Release vX.Y.Z" git push origin vX.Y.Z gh release create vX.Y.Z --notes-from-tag ``` ### Deployment Deploy-funktionerne bruger det lette rsync-flow — ingen `npm pack`, ingen `npm i -g`: - [ ] Brug den deploy-funktion, der matcher destinationen: - `/deploy-vps-local-cc` — lokal VPS (192.168.0.15) - `/deploy-vps-akamai-cc` — Akamai-VPS (69.164.221.35) - `/deploy-vps-both-cc` — begge - [ ] Før deployment skal du bekræfte, at `dist/BUILD_SHA` == `git rev-parse --short HEAD` - [ ] Buildet skal køres et sted, hvor `node_modules` er fysisk til stede (primær checkout eller worktree med kørt `npm ci` — IKKE en worktree med symlink) - [ ] Udfør en smoke-test af den deployede instans: - Åbn `/dashboard/health` → kontrollér, at versionsstrengen matcher udgivelsen - Kør en `/v1/chat/completions`-anmodning mod en kendt udbyder - Bekræft, at `/api/monitoring/health` returnerer circuit breakers med tilstanden `CLOSED` - Bekræft, at MCP-transporter svarer (`/mcp` HTTP, `/mcp-sse` SSE) ### Efter udgivelsen - [ ] Kør `/capture-release-evidences-cc` (Claude Code-funktion) - Optager WebP-skærmbilleder/-optagelser af nye funktioner - Vedhæfter dem til udgivelsesnoter/blogindlæg - [ ] Opdater GitHub Discussions/Discord med en udgivelsesmeddelelse - [ ] Opret en milestone for den næste version - [ ] Hvis det er kritisk: fastgør diskussionen, eller opret et indlæg i `news.json` til banneret i appen ### Gate for offentlig lancering af Radar Radar-meddelelsen er bevidst committet med `active: false`. Aktivering er en separat ændring, efter at der foreligger dokumentation for hvert punkt nedenfor: - [ ] Alle stablede Radar-PR'er er merget, og CI for release-tip er grøn - [ ] Deploy og smoke-test OSS Radar-ruterne med `RADAR_ENABLED` fortsat slået fra som standard - [ ] Smoke-test `GET /planos`, `/termos`, `/privacidade` og `/reembolso` på den angivne Radar-host - [ ] Registrer operatørens identitet/kontaktoplysninger/adresse og en juridisk gennemgang godkendt af ejeren i den private tjeneste - [ ] Afprøv Stripe Checkout og den signerede webhook udelukkende i testtilstand - [ ] Afprøv én krypteret levering af transaktionsmail med den godkendte afsender/det godkendte domæne - [ ] Dokumentér gendannelse fra backup og én overvåget forskningskørsel med et begrænset budget - [ ] Godkend gennemgangspolitikken for BRL/PIX, før dokumentation for donationer accepteres - [ ] Aktivér først offentlig Checkout, når de foregående gates er bestået, og aktivér derefter det nye `news.json`-ID - [ ] Bekræft, at Home-banneret bruger lokaliseret tekst, og at et nyt ID vises igen, efter at et ældre ID er blevet afvist ## Smoke-test af indlejrede tjenester (v3.8.4+) Før en udgivelse, der indeholder ændringer til indlejrede tjenester, frigives, skal følgende verificeres: ### Opstart med ny database (opdager migrationskollisioner — tilføjet efter hotfixet til v3.8.4) - [ ] `DATA_DIR=$(mktemp -d) npm start &` — vent 10 sek. på opstart - [ ] `curl -s http://127.0.0.1:20128/api/services/9router/status | jq '.tool'` returnerer `"9router"` (IKKE 404, IKKE 500). Bekræfter, at migrationen `071_services.sql` er anvendt, og at rækken er oprettet. - [ ] `sqlite3 $DATA_DIR/storage.sqlite "PRAGMA table_info(version_manager);" | grep -E "provider_expose|logs_buffer_path|last_sync_at"` returnerer 3 rækker. - [ ] `sqlite3 $DATA_DIR/storage.sqlite "PRAGMA table_info(webhooks);" | grep -E "kind|metadata_encrypted"` returnerer 2 rækker (validerer, at `070_webhooks_kind_metadata.sql` er anvendt). - [ ] `node --import tsx/esm --test tests/unit/db/no-migration-collisions.test.ts` består — beskytter mod fremtidige kollisioner. ### 9Router - [ ] `POST /api/services/9router/install` returnerer 200 med `installedVersion` på under 2 min. - [ ] `POST /api/services/9router/start` returnerer 200 og `state: "running"` på under 30 sek. - [ ] `GET /api/services/9router/status` rapporterer `health: "healthy"` - [ ] `POST /v1/chat/completions` med `"model": "9router/auto/..."` returnerer 200 (ende-til-ende-routing gennem 9Router) - [ ] `GET /dashboard/providers/services/9router/embed/dashboard` gengiver 9Routers oprindelige brugergrænseflade i proxyen (ingen direkte `127.0.0.1:port`-iframe) - [ ] `POST /api/services/9router/rotate-key` returnerer `{ keyRotated: true }`, og tjenesten genstarter uden problemer - [ ] `POST /api/services/9router/stop` returnerer 200 og `state: "stopped"` - [ ] `GET /api/services/9router/logs?tail=50` returnerer en SSE-strøm med en `snapshot`-hændelse, der indeholder de seneste linjer - [ ] Installation i et miljø uden `npm` i PATH returnerer 500 med en brugervenlig fejlmeddelelse (uden stacktrace) ### CLIProxyAPI - [ ] `POST /api/services/cliproxy/install` returnerer 200 på under 2 min. - [ ] `POST /api/services/cliproxy/start` returnerer 200 og `state: "running"` på under 30 sek. - [ ] `GET /api/services/cliproxy/status` rapporterer `health: "healthy"` - [ ] `POST /api/services/cliproxy/stop` returnerer 200 og `state: "stopped"` - [ ] `GET /api/services/cliproxy/logs?tail=50` returnerer en SSE-strøm ### Sikkerhedsregression - [ ] `curl -H "X-Forwarded-For: 1.2.3.4" http://localhost:20128/api/services/9router/start` returnerer `403 LOCAL_ONLY` - [ ] `curl -H "X-Forwarded-For: 1.2.3.4" http://localhost:20128/api/services/cliproxy/start` returnerer `403 LOCAL_ONLY` - [ ] Fejlsvar fra `/api/services/*` indeholder ikke `err.stack` eller absolutte filstier ## Kontroller for v3.8.0+ Før en v3.8.x-udgivelse frigives, skal disse yderligere punkter verificeres: - [ ] `omniroute --tray` starter på macOS (systray2 installeret i `~/.omniroute/runtime/`) - [ ] `omniroute --tray` starter på Linux (kræver DISPLAY; brugervenlig fejl, hvis den ikke er angivet) - [ ] `omniroute --tray` starter på Windows (PowerShell NotifyIcon, ingen ekstra binære filer) - [ ] `omniroute config tray enable` opretter en autostartpost; deaktivering fjerner den - [ ] `npm install -g omniroute@` kører postinstall uden fatal afslutning - [ ] Opdateringsstien bevarer valgfrie afhængigheder: `omniroute update --apply` og den automatiske opdateringsfunktion kører `npm install -g … --include=optional`, så `optionalDependencies` (better-sqlite3, keytar, tls-client og llmlingua SLM-stakken: `@atjsh/llmlingua-2@2.0.5`, `js-tiktoken`) overlever en opdatering. SLM-niveauet ultra `modelPath` kræver også tinybert-modellen, som automatisk downloades til `${DATA_DIR}/models/llmlingua` ved første brug. Postinstall (`scripts/build/colocateOptionals.mjs`) placerer derefter den valgfrie SLM-afhængighedskæde sammen i `dist/node_modules`, så workeren indlæser EN ENKELT `@huggingface/transformers` ^4.2.0-instans — det selvstændige trace bundler kun transformers, ikke de dynamisk importerede valgfrie afhængigheder, så uden dette ville workeren indlæse llmlingua-2 mod rodniveauets transformers, og SLM-niveauet ville stille og roligt falde tilbage uden fejl. - [ ] `omniroute status` fungerer uden `.env` (CLI-tokensti, kun loopback) - [ ] `curl http://localhost:20128/api/shutdown` returnerer 401 (altid beskyttet rute) - [ ] `curl -H "host: evil.com" http://localhost:20128/api/mcp/sse` returnerer 401 (loopback-beskyttelse) - [ ] SQLite-runtime indlæses som `bundled` ved første kørsel (den medfølgende binære fil er gyldig for platformen) - [ ] SQLite-runtime falder tilbage til `runtime`, når `node_modules/better-sqlite3` slettes - [ ] Det intelligente MCP-filter komprimerer reelt output fra `playwright-mcp browser_snapshot` (≥50 % reduktion) - [ ] Alle 10 `skills/omniroute*/SKILL.md`-filer kan hentes offentligt via en rå GitHub-URL - [ ] Introduktionsguiden viser trinnet "Sådan fungerer det" i gennemgangen af niveauer ved en ny opsætning - [ ] Widgetten for niveaudækning på startdashboardet viser antal konfigurerede/aktive --- ## 3.9.0 LTS-udskæring (afprøvet i 3.8.58) Efter v3.8.59 er den næste version 3.9.0, og dens spids bliver til to langlivede branches: `stable/v3` (v3 LTS-linjen, npm `latest`) og `develop` (v4, opgraderet til 4.0.0, npm `nightly`). Branch-/kanalmodellen, forward-port og labels findes i [RELEASE_STRATEGY.md](./RELEASE_STRATEGY.md); planen findes i [ROADMAP](../../ROADMAP.md) (fase 3). Udskæringen køres én gang; 3.8.58 afprøver den fra ende til anden på en fork, og 3.8.59 afsluttes med [GO/NO-GO-tjeklisten](./LTS_GO_NO_GO.md). ### Prøvekørsel (skrivebeskyttet, sikker når som helst) ```bash npm run release:dry-run-lts-cut # den rigtige udskæring: 3.9.0 fra HEAD, forrige tag v3.8.59 npm run release:dry-run-lts-cut -- --from <3.9.0-tip> # fastlås kildecommit ``` `scripts/release/dry-run-lts-cut.mjs` udfører intet: det læser git og `gh` og udskriver hele sekvensen — forudsætninger (kilden kan opløses, kilderepositoriet har fuld historik — en shallow clone kan ikke pushe `stable/v3`, den modtagende side afviser pakken ved den første grafted parent, så foretag udskæringen fra en fuld klon, eller kør først `git fetch --unshallow origin` — det forrige tag findes, `package.json` har målversionen, en `release-freeze`-issue er åben, der er ingen åben `Release branch not green`-issue på en eksisterende release-branch — en branch, der ikke findes, rapporterer `?` ukendt, aldrig grøn — Mergifys `release`-kø er konfigureret (G11: `queue_rules`, `checks_timeout`, label `queue`), `release/*`-regelsættet blokerer stadig sletning og force-push, og `stable/v3` og `develop` findes endnu ikke), de to branch-trin, hvilke udløsere for inaktive workflows og `if:`-betingelser der bliver sande (og hvilke der fortsat er blokeret af en repositorievariabel eller fastlåst til det kanoniske repositorium), de forventede dist-tags (`latest` → 3.9.0, `next` og `nightly` tomme) samt tilbagerulningen. Afslutningskode `0` = `RESULT: READY`, `1` = en blokerende forudsætning mislykkedes (`✗`), `2` = brugsfejl. `--advisory ` nedgraderer et tjek til en advarsel (`!`) uden at skjule det. Kør prøvekørslen for den rigtige udskæring, mens release freeze for 3.9.0 stadig er aktiv — branchene oprettes efter tagget og før fase 12c ophæver fastfrysningen. ### 3.8.58-afprøvning (kun fork) ```bash # 1. Prøvekørsel på den aktuelle spids med afprøvningsparametre npm run release:dry-run-lts-cut -- --target-version 3.8.58 --previous-tag v3.8.57 \ --advisory freeze,base-green # 2. Udfør mod en FORK-remote (origin eller enhver remote, hvis URL er det kanoniske # repositorium, afvises; hvert trin beder om bekræftelse i terminalen) git remote add rehearsal https://github.com//OmniRoute.git node scripts/release/dry-run-lts-cut.mjs --execute --remote rehearsal \ --target-version 3.8.58 --previous-tag v3.8.57 --advisory freeze,base-green # 3. Afprøv de inaktive workflows i forken (workflow_dispatch, hvor prøvekørslen # rapporterer en fastlåsning til det kanoniske repositorium), og rul derefter tilbage node scripts/release/dry-run-lts-cut.mjs --execute --rollback --remote rehearsal \ --target-version 3.8.58 --previous-tag v3.8.57 --advisory freeze,base-green ``` Develop-opgraderingscommittet bygges med Git-plumbing (intet working tree berøres) og opgraderer de samme fem filer som et commit, der åbner en cyklus: `package.json`, `open-sse/package.json`, `electron/package.json`, `package-lock.json` og `docs/openapi.yaml`. `[4.0.0]`- sektionen i CHANGELOG og dens i18n-spejlinger åbnes efterfølgende på `develop`, før dens første PR. Scriptet ændrer aldrig npm-dist-tags — afprøv dem på en midlertidig pakke. ### PR-preview-artifakt (byg én gang, promover de samme bytes) `.github/workflows/preview-artifact.yml` bygger én produktionstarball fra et PR-head og validerer præcis dette build (#8084 del (a)). Kun PR'er fra samme repositorium; intet publiceres. ```bash gh workflow run preview-artifact.yml -f pr_number= # eller tilføj labelen `preview-artifact` gh run download --name preview-artifact-pr- --dir preview cd preview && sha256sum -c SHA256SUMS gh attestation verify omniroute-*.tgz --repo diegosouzapw/OmniRoute npm install -g ./omniroute-*.tgz # preview-installation ``` Kørslen udfører `npm ci`, `npm run build:release`, `npm run check:pack-artifact`, pakker tarballen, kører `npm run check:pack-boot` (falske secrets, midlertidig datamappe), pakker igen og mislykkes, medmindre digest-værdien er identisk, hvorefter den registrerer `artifact-identity.json` (head-SHA, base- SHA, lockfile-hash, platform, arkitektur, Node ABI, bundler, build-politik — `scripts/release/artifact-identity.mjs`) og attesterer tarballen i et separat job. Promovering af en preview betyder installation af denne tarball: genbyg aldrig fra kildekoden. ### Udskæringen (3.9.0, efter GO) 1. GO registreret i [LTS_GO_NO_GO.md](./LTS_GO_NO_GO.md). 2. `npm run release:dry-run-lts-cut -- --from v3.9.0` udskriver `RESULT: READY`. 3. Opret branchene på `origin` manuelt med de kommandoer, som prøvekørslen udskriver — scriptet nægter at pushe til `origin`. For at genbruge et gennemgået develop-commit skal du først køre `--execute`-afprøvningen på 3.9.0-spidsen mod din fork; den udskriver begge SHA'er, og de samme commits kan pushes: ```bash git push origin :refs/heads/stable/v3 :refs/heads/develop ``` 4. Beskyt `stable/v3` og `develop` (regelsæt + fletningskø), før den første PR lander. 5. De inaktive workflows aktiveres, når branchene findes: `forward-port.yml` (push til `stable/v3`), `validate-stable-pr.yml` (PR'er til `stable/v3`) og `nightly-v4-build.yml` (bygger `develop`). Før idriftsættelse skal repository-hemmeligheden `secrets.FORWARD_PORT_TOKEN` angives (så CI kører på forward-port-PR'er); natlig publicering forbliver deaktiveret, indtil ejeren angiver repository-variablen `vars.NIGHTLY_PUBLISH` til `true`, og npm Trusted Publishing accepterer `nightly-v4-build.yml`. Kanalbestemmelsen foretages af `scripts/release/dist-tag.mjs`, den samme resolver, som `npm-publish.yml` bruger. 6. Verificer kanalerne: `npm view omniroute dist-tags --json` viser `latest` = 3.9.0 og ingen `next` / `nightly`, før v4 publiceres. 7. Tilbagerulning om nødvendigt: `git push origin --delete refs/heads/stable/v3 refs/heads/develop` og `npm dist-tag add omniroute@3.8.59 latest`. --- ## Tilbagerulning Hvis udgivelsen har et kritisk problem: 1. `gh release edit vX.Y.Z --prerelease` (markerer den som ikke den seneste) 2. `git tag -d vX.Y.Z && git push --delete origin vX.Y.Z` (kun hvis den endnu ikke er taget i brug af brugere) 3. Eller: hotfix på `release/vX.Y.0` → patchudgivelse `vX.Y.(Z+1)` 4. Kommunikér straks i GitHub Discussions og Discord ## Ufravigelige regler - Commit aldrig direkte til `main` - Brug aldrig `git push --force` til `main`- eller `release/*`-branches - Spring aldrig Husky-hooks over (`--no-verify`) - Commit aldrig hemmeligheder, loginoplysninger eller `.env`-filer - Kodedækningen skal forblive ≥60/60/60/60 (sætninger/linjer/funktioner/branches) - Inkludér eller opdater altid tests, når produktionskode i `src/`, `open-sse/`, `electron/` eller `bin/` ændres ## Automatisk synkroniseringskontrol Kør dokumentationens synkroniseringskontrol lokalt, før du åbner en PR: ```bash npm run check:docs-sync ``` CI kører også denne kontrol i `.github/workflows/ci.yml` (lint-job).