# Release Checklist (Română) 🌐 **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) · 🇩🇰 [da](../../../da/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) · 🇷🇺 [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) --- > **Ultima actualizare:** 2026-08-28 — v3.8.51 > Flux de lansare simplificat, care utilizează abilitățile Claude Code pentru automatizare. > > **Mențineți coada/ramura verde între lansări:** consultați [RELEASE_GREEN.md](./RELEASE_GREEN.md) > (familia `/green-prs` + `npm run check:release-green` + `/babysit` + rularea nocturnă). Rularea > periodică a acestora — și mai ales **înaintea** acestei liste de verificare — face ca PR-ul de lansare să pornească verde. ## Pe scurt ```bash # 1. Actualizați versiunea + generați CHANGELOG-ul (abilitate) /version-bump-cc patch # sau minor/major # 2. Rulați local verificarea de calitate npm run check # linting + teste npm run test:coverage # verificarea completă a acoperirii (60/60/60/60) # 3. Compilați și efectuați testul de bază npm run build npm run test:e2e # opțional, dar recomandat # 4. Generați lansarea (abilitate) /generate-release-cc # 5. Efectuați implementarea (abilitate) /deploy-vps-both-cc # sau akamai-cc / local-cc # 6. Capturați dovezile lansării (abilitate) /capture-release-evidences-cc ``` ## Publicarea de încredere npm (implicită începând cu v3.8.51) — etapizată la cerere, directă ca soluție de rezervă `npm-publish.yml` publică implicit prin **npm Trusted Publishing (OIDC)**: jobul `stage-npm` (găzduit de GitHub) schimbă id-token-ul GitHub cu o credențială npm cu durată scurtă de viață pentru rularea respectivă — fără token npm cu durată lungă de viață în secretele depozitului, fără solicitare 2FA, cu proveniența atașată. Aceasta este metoda de ocolire aprobată acum de npm, deoarece tokenurile care omit 2FA sunt retrase; restabilește fluxul complet automat pe care proiectul l-a avut până la v3.8.48, păstrând în același timp garanția WS1.3 (un token divulgat nu poate publica singur — nu există niciun token). **Configurare unică (proprietar):** npmjs.com → pachetul `omniroute` → Settings → _Trusted Publisher_ → GitHub: proprietar `diegosouzapw`, depozit `OmniRoute`, flux de lucru `npm-publish.yml` (mediu: niciunul). Până când acesta există, pasul automat eșuează cu `ENEEDAUTH`: relansați cu `publish_mode=staged` (mai jos) sau `direct`. ### Publicare etapizată (la cerere — `publish_mode=staged`) Fluxul de lucru npm-publish nu mai publică direct: pornește arhiva tar împachetată (`check:pack-boot`), apoi rulează `npm stage publish` — octeții exacți sunt stocați în registru, dar **nu pot fi instalați** până când proprietarul nu aprobă. Verificarea umană 2FA a fost mutată DUPĂ validare, nu înaintea acesteia. **Fluxul proprietarului după ce fluxul de lucru devine verde:** 1. `npm stage list omniroute` — găsiți id-ul etapei (afișat și în rezumatul fluxului de lucru). 2. Verificați octeții etapizați (recomandat): `npm stage download `, apoi instalați arhiva tar descărcată într-un prefix temporar și porniți-o (`npm run check:pack-boot` automatizează aceeași verificare împachetare→instalare→pornire în CI). 3. `npm stage approve ` — solicitarea 2FA REPREZINTĂ publicarea. `npm stage reject ` elimină etapa. 4. Plasă de siguranță după publicare: verificatorul post-publicare (WS1.4 din planul v3.8.49) instalează versiunea publicată din registrul public într-un container curat și o pornește. **Soluție de rezervă pentru urgențe:** `workflow_dispatch` cu `publish_mode=direct` restabilește comanda imediată tradițională `npm publish` (utilizați-o numai dacă etapizarea însăși funcționează defectuos; consemnați motivul). **Consolidare unică a securității (proprietar, npmjs.com):** configurați Trusted Publisher pentru `omniroute` în modul exclusiv etapizat, astfel încât un token cu durată lungă de viață care a fost divulgat să nu poată executa `npm publish` direct de nicăieri — CI poate doar să etapizeze; numai verificarea 2FA a proprietarului permite lansarea. **Procedură pentru artefacte defecte (neschimbată):** `npm deprecate omniroute@ " — use "` ca reacție implicită (durează câteva minute, este reversibilă); `npm unpublish` numai în intervalul de 72 de ore/fără dependenți și niciodată ca primă acțiune. Docker: nu rescrieți niciodată o etichetă de versiune — revenirea înseamnă redirecționarea `latest` către ultimul digest valid. **Docker Hub `latest` (obligatoriu la fiecare publicare SemVer stabilă):** fluxul de lucru `docker-publish` trebuie să eticheteze **atât** `X.Y.Z`, cât și, atunci când `should-promote-latest.sh` confirmă că aceasta este cea mai mare versiune SemVer stabilă, `:latest` cu **același digest**. După job: digestul `latest` din Hub este egal cu noul digest SemVer, iar `last_updated` a fost actualizat. Nu lăsați `:latest` pe un build mai vechi în timp ce notele de lansare menționează remedieri care există numai în git. Configurările rapide Compose utilizează `:latest`; GitOps trebuie să păstreze fixarea la `X.Y.Z`. Consultați [Canalele de lansare Docker](../guides/DOCKER_GUIDE.md#release-channels) și #10317. ## Bandă rapidă pentru remedieri urgente (eticheta `hotfix`) Un PR etichetat `hotfix` omite matricea CI complexă (E2E cu 9 partiții, creșterea progresivă a acoperirii, quality-gate, quality-extended) și păstrează verificările rapide, cu semnal puternic: build, partițiile unitare, integrarea, vitest, lint/typecheck, docs-sync, `check:pack-artifact` și testul rapid de pornire din arhiva tar (`check:pack-boot`). Obiectiv: rezultat verde în ≤15min în loc de ~33min. **Politica de acces — toate cele patru condiții sunt obligatorii (modelată după fluxurile de urgență Chromium/VS Code/Node):** 1. **Severitate**: producția este nefuncțională — un artefact publicat se blochează la pornire / o remediere de securitate / fiecare utilizator al versiunii este afectat. „Important” nu înseamnă „nefuncțional”. 2. **Autoritate**: numai proprietarul repository-ului aplică eticheta `hotfix`. Eticheta REPREZINTĂ aprobarea — nu se aplică niciodată pe cont propriu unui PR dintr-o campanie. 3. **Dovezi**: corpul PR-ului conține un link către ultima rulare complexă complet verde (suita pe care joburile omise ar valida-o din nou), plus testul remedierii care mai întâi eșuează, apoi trece. 4. **Domeniu**: exclusiv cherry-pick — remedierea minimă, fără refactorizări, fără modificări suplimentare. Suprafața omisă de acoperire/creștere progresivă este validată din nou de următoarea rulare completă pe ramura de release (stare verde continuă a release-ului) — banda omite AȘTEPTAREA, niciodată validarea. Diferențele care conțin numai teste (toate fișierele sub `tests/`, niciunul sub `tests/e2e/`) omit automat matricea E2E, fără nicio etichetă. ## Listă de verificare detaliată ### Înainte de lansare - [ ] Toate PR-urile vizate pentru această versiune sunt îmbinate în `release/vX.Y.0` - [ ] Toate elementele Linear/problemele deschise pentru această versiune sunt închise sau mutate la următoarea etapă - [ ] CI este verde pe ramura `release/vX.Y.0` - [ ] Nu există marcaje `TODO(release)` în cod: `grep -r "TODO(release)" src/ open-sse/` - [ ] Imaginea de bază Docker este actualizată (în prezent `node:24.15.0-trixie-slim`) ### Versiune și jurnal de modificări - [ ] Rulați `/version-bump-cc ` (abilitate Claude Code) - Incrementează versiunile din `package.json`, `electron/package.json` - Regenerează `CHANGELOG.md` din commiturile git de după ultima etichetă - Actualizează insignele din README.md - [ ] Verificați manual CHANGELOG.md și corectați mesajele commiturilor, dacă este necesar - [ ] Asigurați-vă că cea mai recentă secțiune semver din `CHANGELOG.md` corespunde versiunii din `package.json` - [ ] Păstrați `## [Unreleased]` ca prima secțiune a jurnalului de modificări pentru lucrările viitoare - [ ] Actualizați `docs/openapi.yaml` → `info.version` trebuie să corespundă versiunii din `package.json` ### Calitatea codului - [ ] `npm run lint` — 0 erori (avertismentele existau deja) - [ ] `npm run typecheck:core` — fără probleme - [ ] `npm run typecheck:noimplicit:core` — fără probleme (strict) - [ ] `npm run check:cycles:ratchet` — în limita plafonului fixat `metrics.cycles` (`check:cycles` simplu se încheie cu codul 1 la orice ciclu, #15281) - [ ] `npm run check:any-budget:t11` — în limitele bugetului - [ ] `npm run check:route-validation:t06` — fără probleme - [ ] `npm run check:node-runtime` — pragul minim al mediului de execuție acceptat este respectat (`>=22.22.2 <23`, `>=24.0.0 <27`, conform `SUPPORTED_NODE_RANGE` din `src/shared/utils/nodeRuntimeSupport.ts`; aliniat cu `engines` din `package.json`) ### Testare - [ ] `npm run test:unit` — reușește - [ ] `npm run test:vitest` — reușește (server MCP, autoCombo, cache) - [ ] `npm run test:coverage` — pragul 60/60/60/60 este îndeplinit (instrucțiuni/linii/funcții/ramuri) - [ ] `npm run test:integration` — reușește (dacă modificările afectează baza de date / gestionarii) - [ ] `npm run test:combo:matrix` — reușește (matricea strategiilor combo: demonstrează în mod determinist deciziile de selecție ale tuturor celor 19 strategii publice de rutare; rulați când modificați rutarea combo, rezolvarea strategiilor sau logica de rezervă) - [ ] `RUN_COMBO_LIVE=1 npm run test:combo:live` — **opțional/manual** (test smoke condiționat cu servicii upstream reale; preia de pe VPS `root@192.168.0.15` un instantaneu în mod doar pentru citire al bazei de date; apelează furnizori reali, consumă credite; nu rulează niciodată în CI; este omis fără probleme dacă nu este activată condiția) - [ ] `npm run test:combo:live:vps` — **opțional/manual** (test smoke live VPS din faza 3: 7 scenarii HTTP pe serverul live `.15`, prin Node ESM simplu; necesită `ssh root@192.168.0.15`; creează/șterge numai combinații `__live_test__*`; apelează furnizori reali; nu rulează niciodată în CI) - [ ] `npm run test:e2e` — reușește (modificări UI) - [ ] `npm run test:protocols:e2e` — reușește (modificări MCP/A2A) - [ ] `npm run test:ecosystem` — reușește ### Hook-uri (validate de Husky) Hook-urile Husky se află în `.husky/` și rulează automat la operațiunile git. - **pre-commit:** `npx lint-staged + node scripts/check/check-docs-sync.mjs + npm run check:any-budget:t11` - **pre-push:** verificări rapide și deterministe — `npm run check:any-budget:t11 && npm run check:tracked-artifacts` (activate la 2026-06-13). Exclude în mod intenționat `test:unit` (lent; acoperit de jobul CI `test-unit`). - Rulați manual `npm run test:unit` înainte de a publica ramurile de lansare. Dacă un hook eșuează: remediați problema de bază, nu îl ocoliți cu `--no-verify`. ### Commituri convenționale Toate commiturile destinate lansării trebuie să respecte formatul `type(scope): subject`. **Tipuri valide:** `feat`, `fix`, `refactor`, `docs`, `test`, `chore`, `perf`, `style`, `ci` **Domenii valide:** `db`, `sse`, `oauth`, `dashboard`, `api`, `cli`, `docker`, `ci`, `mcp`, `a2a`, `memory`, `skills`, `cloud-agent`, `guardrails`, `compression`, `auto-combo`, `resilience`, `providers`, `executors`, `translator`, `domain`, `authz` Modificări incompatibile: adăugați subsolul `BREAKING CHANGE:` sau `!` după domeniu (de exemplu, `feat(api)!: drop /v0`). ### Documentație - [ ] `npm run check:docs-sync` reușește (rulat automat de pre-commit) - [ ] `npm run check:docs-all` reușește (comandă agregată: docs-sync + docs-counts + env-doc-sync + deprecated-versions + doc-links) - [ ] `npm run check:env-doc-sync` se încheie cu codul 0 — contractul variabilelor de mediu dintre cod ↔ `.env.example` ↔ `docs/reference/ENVIRONMENT.md` este intact - [ ] `npm run check:doc-links` se încheie cu codul 0 — nu există referințe Markdown interne întrerupte după restructurare - [ ] `docs/architecture/ARCHITECTURE.md` a fost verificat pentru discrepanțe privind stocarea/mediul de execuție - [ ] `docs/guides/TROUBLESHOOTING.md` a fost verificat pentru discrepanțe privind variabilele de mediu și operațiunile - [ ] Dacă `.env.example` s-a modificat: `docs/reference/ENVIRONMENT.md` este actualizat - [ ] Dacă o funcționalitate nouă are interfață UI: `docs/guides/USER_GUIDE.md` o menționează - [ ] Dacă o funcționalitate nouă are API: `docs/reference/API_REFERENCE.md` + `docs/openapi.yaml` sunt actualizate - [ ] Dacă o funcționalitate nouă este un modul: există un fișier dedicat `docs/.md` - [ ] Dacă este o modificare incompatibilă: `docs/guides/TROUBLESHOOTING.md` conține o notă de migrare ### i18n - [ ] `npm run i18n:check` se încheie cu codul 0 — starea traducerilor (`.i18n-state.json`) este sincronizată cu documentele sursă (nicio sursă divergentă în modul strict; avertizarea din modul de avertizare este acceptabilă pentru retușuri de ultim moment ale documentației, dar rezultatul trebuie să fie 0 înainte de etichetare) - [ ] `npm run i18n:check-ui-coverage` se încheie cu codul 0 — fiecare limbă UI atinge sau depășește pragul minim de acoperire de 80% - [ ] `npm run i18n:sync-ui:dry` raportează 0 chei lipsă în toate cele 66 de limbi țintă (fiecare limbă, cu excepția sursei `en`) - [ ] Dacă documentele sursă în limba engleză s-au modificat, rulați `npm run i18n:run` (necesită `OMNIROUTE_TRANSLATION_API_KEY` în `.env`) înainte de etichetare - [ ] Contribuțiile la traduceri pot fi amânate pentru versiunea următoare dacă sunt minore (urmăriți-le în CHANGELOG) ### Migrări ale bazei de date - [ ] Dacă `src/lib/db/migrations/` conține fișiere noi: - [ ] Fiecare migrare este idempotentă (`CREATE TABLE IF NOT EXISTS` etc.) - [ ] Migrările sunt încadrate în tranzacții - [ ] Sunt numerotate corect (fără goluri în secvență) - [ ] Testați pe o instalare nouă: ștergeți `~/.omniroute/omniroute.db` și rulați `npm run dev` - [ ] Testați pe o instalare existentă: creați o copie de siguranță a bazei de date, rulați migrarea și verificați schema - [ ] Fișierele WAL (`-wal`, `-shm`) sunt gestionate corect dacă migrarea rescrie tabelele ### Catalog de furnizori (validat cu Zod) - [ ] Schema Zod din `src/shared/constants/providers.ts` este validă la momentul încărcării - [ ] Toți furnizorii au câmpurile obligatorii (`id`, `label`, `kind` etc.) - [ ] `freeNote` este furnizat pentru furnizorii gratuiți noi - [ ] Furnizorii OAuth au `oauthConfig` înregistrat în `src/lib/oauth/constants/oauth.ts` - [ ] Dacă a fost adăugat un furnizor nou: executorul corespunzător există în `open-sse/executors/` - [ ] Dacă formatul nu este OpenAI: există un adaptor în `open-sse/translator/` - [ ] Modelele sunt înregistrate în `open-sse/config/providerRegistry.ts` - [ ] Testele unitare din `tests/unit/` acoperă clasificarea și rutarea furnizorilor ### Desktop (Electron) Dacă `electron/` s-a modificat: - [ ] `npm run electron:smoke:packaged` trece - [ ] Buildurile au fost testate pentru cel puțin unul dintre `:win`, `:mac`, `:linux` - [ ] Certificatele de semnare a codului nu sunt expirate (dacă se efectuează semnarea) - [ ] Versiunea din `electron/package.json` corespunde celei din `package.json` de la rădăcină - [ ] Indicatorul canalului de actualizare automată este actualizat dacă se lansează în `stable` ### Structura buildului Depozitul utilizează trei directoare de ieșire distincte — nu le confundați niciodată: | Director | Scop | Urmărit? | | --------- | ---------------------------------------------------------------- | ------------------- | | `src/` | Sursa aplicației (TypeScript / TSX) | Da | | `.build/` | Fișiere intermediare de build — ieșirea `next build` (`distDir`) | Nu (ignorat de git) | | `dist/` | Pachet npm distribuibil — asamblat de `assembleStandalone` | Nu (ignorat de git) | > **Notă pentru operator:** directorul de imagini de pe VPS-ul la distanță rămâne `/usr/lib/node_modules/omniroute/app/`. > Numai ieșirea buildului **din depozit** a fost mutată (`app/` → `dist/`). Rutinele de implementare sincronizează prin rsync > conținutul din `dist/` în directorul `app/` de la distanță — nu sunt necesare modificări ale căilor de pe VPS. **Flux cu un singur build:** ``` npm run build:release └─ rm -rf .build dist (curățare) └─ next build → .build/next/ (fișiere intermediare) └─ assembleStandalone (copiază standalone + static + public + natives → dist/) └─ scrie dist/BUILD_SHA (santinelă HEAD) ``` NU rulați `npm run build` urmat de un `npm run build:cli` separat pentru implementare — utilizați `npm run build:release`, care efectuează o reconstruire curată și creează santinela într-o singură comandă. ### Validarea artefactelor - [ ] `npm run build:release` reușește și `dist/BUILD_SHA` == `git rev-parse --short HEAD` - [ ] `npm run check:pack-artifact` nu raportează probleme — fără `app.__qa_backup`, `scripts/scratch`, `package-lock.json` sau alte reziduuri locale - [ ] `dist/server.js` există după build - [ ] Test de bază local opțional pentru mediul de execuție împachetat: `npm run dev:candidate -- validate` după ce `npm run dev:candidate -- build` pornește arhiva împachetată într-un `DATA_DIR` izolat și verifică `/api/health` + `/v1/models` (consultați [Fluxul recomandat pentru contribuții](CONTRIBUTION_GOLDEN_PATH.md#local-candidate-loop)) ### Etichetare și lansare - [ ] Rulați `/generate-release-cc` (rutină Claude Code): - Creează eticheta `vX.Y.Z` - Publică eticheta și ramura - Deschide o versiune GitHub cu jurnalul modificărilor în descriere - Atașează programele de instalare Electron (dacă au fost construite) - [ ] Sau manual: ```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 ``` ### Implementare Rutinele de implementare utilizează fluxul rsync simplificat — fără `npm pack`, fără `npm i -g`: - [ ] Utilizați rutina de implementare care corespunde țintei: - `/deploy-vps-local-cc` — VPS local (192.168.0.15) - `/deploy-vps-akamai-cc` — VPS Akamai (69.164.221.35) - `/deploy-vps-both-cc` — ambele - [ ] Înainte de implementare, confirmați că `dist/BUILD_SHA` == `git rev-parse --short HEAD` - [ ] Buildul trebuie să ruleze acolo unde `node_modules` este real (directorul principal de lucru sau un worktree în care s-a rulat `npm ci` — NU un worktree cu legături simbolice) - [ ] Efectuați un test de bază al instanței implementate: - Deschideți `/dashboard/health` → verificați dacă șirul versiunii corespunde versiunii lansate - Rulați o solicitare `/v1/chat/completions` folosind un furnizor cunoscut - Verificați dacă `/api/monitoring/health` returnează întrerupătoare de circuit cu starea `CLOSED` - Confirmați că transporturile MCP răspund (`/mcp` HTTP, `/mcp-sse` SSE) ### După lansare - [ ] Rulați `/capture-release-evidences-cc` (rutină Claude Code) - Realizează capturi de ecran/înregistrări WebP ale funcționalităților noi - Le atașează la notele versiunii / articolul de blog - [ ] Actualizați GitHub Discussions / Discord cu anunțul lansării - [ ] Deschideți un reper pentru versiunea următoare - [ ] Dacă este esențial: fixați discuția sau publicați în `news.json` pentru bannerul din aplicație ### Criterii de lansare publică pentru Radar Anunțul Radar este inclus intenționat cu `active: false`. Activarea este o modificare separată, efectuată după ce există dovezi pentru fiecare element de mai jos: - [ ] Toate PR-urile Radar suprapuse sunt îmbinate, iar CI-ul pentru vârful versiunii trece - [ ] Implementați și testați rutele OSS Radar cu `RADAR_ENABLED` în continuare dezactivat implicit - [ ] Testați `GET /planos`, `/termos`, `/privacidade` și `/reembolso` pe gazda Radar desemnată - [ ] Înregistrați identitatea/datele de contact/adresa operatorului și evaluarea juridică aprobată de proprietar în serviciul privat - [ ] Testați Stripe Checkout și webhookul semnat numai în modul de testare - [ ] Testați livrarea unui e-mail tranzacțional criptat folosind expeditorul/domeniul aprobat - [ ] Demonstrați restaurarea copiei de siguranță și o rulare de cercetare supravegheată, cu buget limitat - [ ] Aprobați politica de verificare BRL/PIX înainte de a accepta dovezi privind donațiile - [ ] Activați Checkout public numai după îndeplinirea criteriilor precedente, apoi activați noul ID din `news.json` - [ ] Verificați dacă bannerul de pe pagina principală utilizează text localizat și dacă un ID nou reapare după ce un ID mai vechi este respins ## Teste de fum pentru serviciile încorporate (v3.8.4+) Înainte de a publica orice versiune care include modificări ale serviciilor încorporate, verificați: ### Pornire cu bază de date nouă (detectează coliziunile migrărilor — adăugat după remedierea rapidă v3.8.4) - [ ] `DATA_DIR=$(mktemp -d) npm start &` — așteptați 10 s pentru pornire - [ ] `curl -s http://127.0.0.1:20128/api/services/9router/status | jq '.tool'` returnează `"9router"` (NU 404, NU 500). Confirmă că migrarea `071_services.sql` a fost aplicată și rândul a fost inserat. - [ ] `sqlite3 $DATA_DIR/storage.sqlite "PRAGMA table_info(version_manager);" | grep -E "provider_expose|logs_buffer_path|last_sync_at"` returnează 3 rânduri. - [ ] `sqlite3 $DATA_DIR/storage.sqlite "PRAGMA table_info(webhooks);" | grep -E "kind|metadata_encrypted"` returnează 2 rânduri (validează aplicarea migrării `070_webhooks_kind_metadata.sql`). - [ ] `node --import tsx/esm --test tests/unit/db/no-migration-collisions.test.ts` trece — protejează împotriva coliziunilor viitoare. ### 9Router - [ ] `POST /api/services/9router/install` returnează 200 cu `installedVersion` în mai puțin de 2 min - [ ] `POST /api/services/9router/start` returnează 200 și `state: "running"` în mai puțin de 30 s - [ ] `GET /api/services/9router/status` raportează `health: "healthy"` - [ ] `POST /v1/chat/completions` cu `"model": "9router/auto/..."` returnează 200 (rutare integrală prin 9Router) - [ ] `GET /dashboard/providers/services/9router/embed/dashboard` redă interfața nativă 9Router în interiorul proxy-ului (fără iframe direct către `127.0.0.1:port`) - [ ] `POST /api/services/9router/rotate-key` returnează `{ keyRotated: true }`, iar serviciul repornește fără probleme - [ ] `POST /api/services/9router/stop` returnează 200 și `state: "stopped"` - [ ] `GET /api/services/9router/logs?tail=50` returnează un flux SSE cu un eveniment `snapshot` care conține linii recente - [ ] Instalarea într-un mediu fără `npm` în PATH returnează 500 cu un mesaj de eroare clar (fără urmărirea stivei) ### CLIProxyAPI - [ ] `POST /api/services/cliproxy/install` returnează 200 în mai puțin de 2 min - [ ] `POST /api/services/cliproxy/start` returnează 200 și `state: "running"` în mai puțin de 30 s - [ ] `GET /api/services/cliproxy/status` raportează `health: "healthy"` - [ ] `POST /api/services/cliproxy/stop` returnează 200 și `state: "stopped"` - [ ] `GET /api/services/cliproxy/logs?tail=50` returnează un flux SSE ### Regresie de securitate - [ ] `curl -H "X-Forwarded-For: 1.2.3.4" http://localhost:20128/api/services/9router/start` returnează `403 LOCAL_ONLY` - [ ] `curl -H "X-Forwarded-For: 1.2.3.4" http://localhost:20128/api/services/cliproxy/start` returnează `403 LOCAL_ONLY` - [ ] Răspunsurile de eroare de la `/api/services/*` nu conțin `err.stack` sau căi absolute către fișiere ## Verificări pentru v3.8.0+ Înainte de a publica orice versiune v3.8.x, verificați și următoarele elemente: - [ ] `omniroute --tray` pornește pe macOS (systray2 instalat în `~/.omniroute/runtime/`) - [ ] `omniroute --tray` pornește pe Linux (necesită DISPLAY; eroare gestionată elegant dacă nu este setată) - [ ] `omniroute --tray` pornește pe Windows (PowerShell NotifyIcon, fără fișiere binare suplimentare) - [ ] `omniroute config tray enable` creează intrarea de pornire automată; dezactivarea o elimină - [ ] `npm install -g omniroute@` rulează postinstall fără ieșire fatală - [ ] Calea de actualizare păstrează dependențele opționale: `omniroute update --apply` și actualizatorul automat rulează `npm install -g … --include=optional`, astfel încât `optionalDependencies` (better-sqlite3, keytar, tls-client și stiva SLM llmlingua: `@atjsh/llmlingua-2@2.0.5`, `js-tiktoken`) să supraviețuiască unei actualizări. Nivelul SLM ultra `modelPath` necesită și modelul tinybert, descărcat automat în `${DATA_DIR}/models/llmlingua` la prima utilizare. Postinstall (`scripts/build/colocateOptionals.mjs`) amplasează apoi împreună în `dist/node_modules` ansamblul dependențelor opționale SLM, astfel încât worker-ul să rezolve o SINGURĂ instanță `@huggingface/transformers` ^4.2.0 — urma autonomă include numai transformers, nu și dependențele opționale importate dinamic, astfel încât, fără această măsură, worker-ul ar încărca llmlingua-2 folosind transformers din rădăcină, iar nivelul SLM ar eșua silențios în modul permisiv. - [ ] `omniroute status` funcționează fără `.env` (calea tokenului CLI, numai loopback) - [ ] `curl http://localhost:20128/api/shutdown` returnează 401 (rută protejată permanent) - [ ] `curl -H "host: evil.com" http://localhost:20128/api/mcp/sse` returnează 401 (protecție loopback) - [ ] La prima rulare, runtime-ul SQLite este rezolvat la `bundled` (fișierul binar inclus este valid pentru platformă) - [ ] Runtime-ul SQLite revine la `runtime` când `node_modules/better-sqlite3` este șters - [ ] Filtrul MCP inteligent comprimă ieșirea reală `playwright-mcp browser_snapshot` (reducere ≥50%) - [ ] Toate cele 10 fișiere `skills/omniroute*/SKILL.md` pot fi accesate public printr-un URL GitHub raw - [ ] Expertul de integrare afișează pasul de prezentare a nivelurilor „Cum funcționează” la configurarea inițială - [ ] Widgetul de acoperire a nivelurilor din panoul principal afișează numărul elementelor configurate/active --- ## Separarea 3.9.0 LTS (repetată în 3.8.58) După v3.8.59, următoarea versiune este 3.9.0, iar vârful acesteia devine baza pentru două ramuri cu durată lungă de viață: `stable/v3` (linia v3 LTS, npm `latest`) și `develop` (v4, incrementată la 4.0.0, npm `nightly`). Modelul de ramuri/canale, portarea înainte și etichetele sunt descrise în [RELEASE_STRATEGY.md](./RELEASE_STRATEGY.md); planul se află în [ROADMAP](../../ROADMAP.md) (Faza 3). Separarea se execută o singură dată; 3.8.58 o repetă integral pe un fork, iar 3.8.59 se încheie cu [lista de verificare GO/NO-GO](./LTS_GO_NO_GO.md). ### Simulare (doar în citire, sigură oricând) ```bash npm run release:dry-run-lts-cut # separarea reală: 3.9.0 din HEAD, eticheta anterioară v3.8.59 npm run release:dry-run-lts-cut -- --from <3.9.0-tip> # fixează commitul sursă ``` `scripts/release/dry-run-lts-cut.mjs` nu execută nimic: citește git și `gh` și afișează întreaga secvență — precondițiile (sursa poate fi rezolvată, depozitul sursă are istoricul complet — o clonă superficială nu poate trimite `stable/v3`, partea care primește respinge pachetul la primul părinte grefat, așadar efectuați separarea dintr-o clonă completă sau rulați mai întâi `git fetch --unshallow origin` — eticheta anterioară există, `package.json` conține versiunea țintă, este deschis un tichet `release-freeze`, nu există niciun tichet deschis `Release branch not green` pe o ramură de lansare existentă — o ramură care nu există raportează `?` necunoscut, niciodată verde — coada Mergify `release` este configurată (G11: `queue_rules`, `checks_timeout`, eticheta `queue`), setul de reguli `release/*` încă blochează ștergerea și trimiterea forțată, iar `stable/v3` și `develop` nu există încă), cei doi pași pentru ramuri, ce declanșatoare ale fluxurilor de lucru inactive și ce condiții `if:` devin adevărate (și care rămân blocate de o variabilă a depozitului sau fixate la depozitul canonic), etichetele dist așteptate (`latest` → 3.9.0, `next` și `nightly` goale) și revenirea. Codul de ieșire `0` = `RESULT: READY`, `1` = o precondiție blocantă a eșuat (`✗`), `2` = eroare de utilizare. `--advisory ` retrogradează o verificare la avertisment (`!`) fără a o ascunde. Rulați simularea separării reale cât timp blocarea lansării 3.9.0 este încă activă — ramurile sunt create după etichetă și înainte ca Faza 12c să ridice blocarea. ### Repetiția 3.8.58 (doar pe fork) ```bash # 1. Simulare pe vârful curent, cu parametrii repetiției npm run release:dry-run-lts-cut -- --target-version 3.8.58 --previous-tag v3.8.57 \ --advisory freeze,base-green # 2. Executați pe o destinație remote de tip FORK (origin sau orice destinație remote al cărei URL este cel al # depozitului canonic este refuzată; fiecare pas solicită confirmare în terminal) 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. Exercitați fluxurile de lucru inactive în fork (workflow_dispatch acolo unde simularea # raportează o fixare la depozitul canonic), apoi reveniți 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 ``` Commitul de incrementare pentru develop este construit prin mecanismele interne git (fără a modifica arborele de lucru) și incrementează aceleași cinci fișiere ca un commit de deschidere a ciclului: `package.json`, `open-sse/package.json`, `electron/package.json`, `package-lock.json` și `docs/openapi.yaml`. Secțiunea `[4.0.0]` din CHANGELOG și copiile sale i18n sunt deschise ulterior pe `develop`, înainte de primul său PR. Scriptul nu modifică niciodată etichetele dist npm — repetați aceste operațiuni pe un pachet de test. ### Artefact de previzualizare pentru PR (construiți o singură dată, promovați aceiași octeți) `.github/workflows/preview-artifact.yml` construiește o arhivă tar de producție din capul unui PR și validează exact acea construcție (segmentul (a) din #8084). Sunt acceptate doar PR-uri din același depozit; nu se publică nimic. ```bash gh workflow run preview-artifact.yml -f pr_number= # sau adăugați eticheta `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 # instalare de previzualizare ``` Rularea execută `npm ci`, `npm run build:release`, `npm run check:pack-artifact`, împachetează arhiva tar, execută `npm run check:pack-boot` (secrete fictive, director de date efemer), reîmpachetează și eșuează dacă rezumatul nu este identic, apoi înregistrează `artifact-identity.json` (SHA-ul capului, SHA-ul bazei, hashul fișierului de blocare, platforma, arhitectura, ABI-ul node, instrumentul de împachetare, politica de construire — `scripts/release/artifact-identity.mjs`) și atestă arhiva tar într-un job separat. Promovarea unei previzualizări înseamnă instalarea acelei arhive tar: nu reconstruiți niciodată din sursă. ### Separarea (3.9.0, după GO) 1. GO este consemnat în [LTS_GO_NO_GO.md](./LTS_GO_NO_GO.md). 2. `npm run release:dry-run-lts-cut -- --from v3.9.0` afișează `RESULT: READY`. 3. Creați manual ramurile pe `origin`, folosind comenzile afișate de simulare — scriptul refuză să trimită către `origin`. Pentru a reutiliza un commit develop revizuit, executați mai întâi repetiția cu `--execute` pe vârful 3.9.0, folosind forkul dumneavoastră; aceasta afișează ambele SHA-uri, iar aceleași commituri pot fi trimise: ```bash git push origin :refs/heads/stable/v3 :refs/heads/develop ``` 4. Protejați `stable/v3` și `develop` (seturi de reguli + coadă de îmbinare) înainte de integrarea primului PR. 5. Fluxurile de lucru inactive se activează în funcție de existența ramurii: `forward-port.yml` (push către `stable/v3`), `validate-stable-pr.yml` (PR-uri către `stable/v3`) și `nightly-v4-build.yml` (construiește `develop`). Înainte de lansare, setați secretul depozitului `secrets.FORWARD_PORT_TOKEN` (astfel încât CI să ruleze pentru PR-urile de propagare); publicarea nocturnă rămâne dezactivată până când proprietarul setează variabila depozitului `vars.NIGHTLY_PUBLISH` la `true`, iar npm Trusted Publishing acceptă `nightly-v4-build.yml`. Rezolvarea canalului este realizată de `scripts/release/dist-tag.mjs`, același resolver utilizat de `npm-publish.yml`. 6. Verificați canalele: `npm view omniroute dist-tags --json` afișează `latest` = 3.9.0 și niciun `next` / `nightly` până la publicarea v4. 7. Revenire, dacă este necesar: `git push origin --delete refs/heads/stable/v3 refs/heads/develop` și `npm dist-tag add omniroute@3.8.59 latest`. --- ## Revenire la versiunea anterioară Dacă versiunea lansată are o problemă critică: 1. `gh release edit vX.Y.Z --prerelease` (o marchează ca nefiind cea mai recentă) 2. `git tag -d vX.Y.Z && git push --delete origin vX.Y.Z` (doar dacă nu a fost încă adoptată de utilizatori) 3. Sau: remediere rapidă pe `release/vX.Y.0` → versiune patch `vX.Y.(Z+1)` 4. Comunicați imediat în GitHub Discussions și pe Discord ## Reguli stricte - Nu faceți niciodată commit direct în `main` - Nu utilizați niciodată `git push --force` pentru ramurile `main` sau `release/*` - Nu omiteți niciodată hook-urile Husky (`--no-verify`) - Nu includeți niciodată în commit secrete, credențiale sau fișiere `.env` - Acoperirea trebuie să rămână ≥60/60/60/60 (instrucțiuni/linii/funcții/ramuri) - Includeți sau actualizați întotdeauna testele atunci când modificați codul de producție din `src/`, `open-sse/`, `electron/` sau `bin/` ## Verificarea automată a sincronizării Rulați local verificarea de sincronizare a documentației înainte de a deschide un PR: ```bash npm run check:docs-sync ``` CI rulează, de asemenea, această verificare în `.github/workflows/ci.yml` (sarcina de linting).