🌐 Languages: 🇺🇸 English · 🇪🇹 am · 🇸🇦 ar · 🇦🇿 az · 🇧🇬 bg · 🇧🇩 bn · 🇧🇦 bs · 🇨🇿 cs · 🇩🇰 da · 🇩🇪 de · 🇬🇷 el · 🇪🇸 es · 🇪🇪 et · 🇮🇷 fa · 🇫🇮 fi · 🇫🇷 fr · 🇮🇪 ga · 🇮🇳 gu · 🇳🇬 ha · 🇮🇱 he · 🇮🇳 hi · 🇭🇷 hr · 🇭🇺 hu · 🇦🇲 hy · 🇮🇩 id · 🇳🇬 ig · 🇯🇵 ja · 🇬🇪 ka · 🇰🇭 km · 🇮🇳 kn · 🇰🇷 ko · 🇱🇹 lt · 🇱🇻 lv · 🇮🇳 ml · 🇮🇳 mr · 🇲🇾 ms · 🇲🇹 mt · 🇲🇲 my · 🇳🇵 ne · 🇳🇱 nl · 🇳🇴 no · 🇮🇳 or · 🇮🇳 pa · 🇵🇭 phi · 🇵🇱 pl · 🇵🇹 pt · 🇧🇷 pt-BR · 🇷🇴 ro · 🇷🇺 ru · 🇱🇰 si · 🇸🇰 sk · 🇸🇮 sl · 🇷🇸 sr · 🇸🇪 sv · 🇰🇪 sw · 🇮🇳 ta · 🇮🇳 te · 🇹🇭 th · 🇹🇷 tr · 🇺🇦 uk-UA · 🇵🇰 ur · 🇺🇿 uz · 🇻🇳 vi · 🇳🇬 yo · 🇨🇳 zh-CN · 🇹🇼 zh-TW
Questo file fornisce indicazioni a Claude Code (claude.ai/code) quando si lavora con il codice in questo repository.
npm install # Installa le dipendenze (genera automaticamente .env da .env.example)
npm run dev # Server di sviluppo su http://localhost:20128
npm run build # Build di produzione (Next.js 16 standalone)
npm run lint # ESLint (0 errori previsti; avvisi già esistenti)
npm run typecheck:core # Controllo TypeScript (dovrebbe essere pulito)
npm run typecheck:noimplicit:core # Controllo rigoroso (nessun implicit any)
npm run test:coverage # Test unitari + gate di copertura (75/75/75/70 — dichiarazioni/righe/funzioni/rami)
npm run check # lint + test combinati
npm run check:cycles # Rileva dipendenze circolari# Singolo file di test (runner di test nativo di Node.js — la maggior parte dei test)
node --import tsx/esm --test tests/unit/your-file.test.ts
# Vitest (server MCP, autoCombo, cache)
npm run test:vitest
# Tutti i suite
npm run test:allPer la matrice completa dei test, vedere CONTRIBUTING.md → "Esecuzione dei Test". Per un'architettura approfondita, vedere AGENTS.md.
OmniRoute — proxy/router AI unificato. Un endpoint, 329 fornitori di LLM, fallback automatico.
| Livello | Posizione | Scopo |
|---|---|---|
| API Routes | src/app/api/v1/ |
Next.js App Router — punti di ingresso |
| Handlers | open-sse/handlers/ |
Elaborazione delle richieste (chat, embeddings, ecc.) |
| Executors | open-sse/executors/ |
Dispatch HTTP specifico per fornitore |
| Translators | open-sse/translator/ |
Conversione di formato (OpenAI↔Claude↔Gemini) |
| Transformer | open-sse/transformer/ |
API delle risposte ↔ Completamenti Chat |
| Services | open-sse/services/ |
Routing combinato, limiti di velocità, caching, ecc. |
| Database | src/lib/db/ |
110 top-level SQLite domain modules, 130 migrations |
| Domain/Policy | src/domain/ |
Motore di policy, regole di costo, logica di fallback |
| MCP Server | open-sse/mcp-server/ |
107 unique tools, 3 transports (stdio / SSE / Streamable HTTP), 32 scopes |
| A2A Server | src/lib/a2a/ |
Protocollo agente JSON-RPC 2.0 |
| Skills | src/lib/skills/ |
Framework di abilità estensibile |
| Memory | src/lib/memory/ |
Memoria conversazionale persistente |
Monorepo: src/ (app Next.js 16), open-sse/ (workspace del motore di streaming), electron/ (app desktop), tests/, bin/ (punto di ingresso CLI).
Client → /v1/chat/completions (rotta Next.js)
→ CORS → validazione Zod → auth? → controllo della policy → guardia contro l'iniezione del prompt
→ handleChatCore() [open-sse/handlers/chatCore.ts]
→ controllo cache → limite di frequenza → routing combo?
→ resolveComboTargets() → handleSingleModel() per target
→ translateRequest() → getExecutor() → executor.execute()
→ fetch() upstream → retry w/ backoff
→ traduzione della risposta → stream SSE o JSON
→ Se Responses API: responsesTransformer.ts TransformStream
Le rotte API seguono uno schema coerente: Roatta → preflight CORS → validazione del corpo Zod → Auth opzionale (extractApiKey/isValidApiKey) → applicazione della policy della chiave API → delega del gestore (open-sse). Nessun middleware globale di Next.js — l'intercettazione è specifica per rotta.
Combo routing (open-sse/services/combo.ts): 19 public strategies (priority, weighted, fill-first, round-robin, p2c, random, least-used, cost-optimized, reset-aware, reset-window, headroom, strict-random, auto, lkgp, context-optimized, cache-optimized, context-relay, fusion, pipeline). Each target calls handleSingleModel(), which wraps handleChatCore() with per-target error handling and circuit-breaker checks. See docs/routing/AUTO-COMBO.md for the 13-factor Auto-Combo scoring and docs/architecture/RESILIENCE_GUIDE.md for the 3 resilience layers.
OmniRoute ha tre meccanismi di guasto temporaneo correlati ma distinti. Mantieni il loro ambito separato durante il debug del comportamento di routing. Vedi il diagramma di resilienza a 3 livelli (fonte: docs/diagrams/resilience-3layers.mmd) per una mappa a colpo d'occhio.
Ambito: intero fornitore, ad esempio glm, openai, anthropic.
Scopo: fermare l'invio di traffico a un fornitore che sta ripetutamente fallendo a livello upstream/servizio, in modo che un fornitore non sano non rallenti ogni richiesta.
Implementazione:
- Classe principale:
src/shared/utils/circuitBreaker.ts - Cablaggio di gate/esecuzione chat:
src/sse/handlers/chatHelpers.ts,src/sse/handlers/chat.ts - API di stato di esecuzione:
src/app/api/monitoring/health/route.ts - Wrapper condivisi:
open-sse/services/accountFallback.ts - Tabella di stato persistente:
domain_circuit_breakers
Stati:
CLOSED: il traffico normale è consentito.OPEN: il fornitore è temporaneamente bloccato; i chiamanti ricevono una risposta di circuito-fornitore-aperto oppure il routing combo salta a un altro target.HALF_OPEN: il timeout di reset è scaduto; consenti una richiesta di probe. Il successo chiude il circuito, il fallimento lo riapre.
Predefiniti (open-sse/config/constants.ts):
- Fornitori OAuth: soglia
3, timeout di reset60s. - Fornitori di chiavi API: soglia
5, timeout di reset30s. - Fornitori locali: soglia
2, timeout di reset15s.
Solo gli stati di fallimento a livello di fornitore dovrebbero attivare l'interruttore del fornitore:
(408, 500, 502, 503, 504);Non attivare l'interruttore dell'intero fornitore per errori normali di account/chiave/modello come la maggior parte
dei casi 401, 403, o 429. Questi di solito appartengono a cooldown di connessione o lockout del modello. Un generico errore 403 del fornitore di chiavi API dovrebbe essere recuperabile a meno che non sia classificato
come errore terminale di fornitore/account.
L'interruttore utilizza un recupero pigro, non un timer in background. Quando OPEN scade, letture come
getStatus(), canExecute(), e getRetryAfterMs() aggiornano lo stato a
HALF_OPEN, in modo che i dashboard e i costruttori di candidati combo non continuino a escludere un
fornitore scaduto per sempre.
Ambito: una connessione/account/chiave del fornitore.
Scopo: saltare temporaneamente una chiave/account difettosa consentendo ad altre connessioni per lo stesso fornitore di continuare a servire richieste.
Implementazione:
- Percorso di scrittura/aggiornamento:
src/sse/services/auth.ts::markAccountUnavailable() - Selezione/filtraggio dell'account:
src/sse/services/auth.ts::getProviderCredentials... - Calcolo del cooldown:
open-sse/services/accountFallback.ts::checkFallbackError() - Impostazioni:
src/lib/resilience/settings.ts
Campi importanti sulle connessioni del fornitore:
rateLimitedUntil;
testStatus: "unavailable";
lastError;
lastErrorType;
errorCode;
backoffLevel;Durante la selezione dell'account, una connessione viene saltata mentre:
new Date(rateLimitedUntil).getTime() > Date.now();I cooldown sono anche pigri: quando rateLimitedUntil è nel passato, la connessione diventa
nuovamente idonea. All'uso riuscito, clearAccountError() cancella testStatus,
rateLimitedUntil, campi di errore e backoffLevel.
Comportamento predefinito del cooldown di connessione:
- Cooldown base OAuth:
5s. - Cooldown base per chiavi API:
3s. 429per chiavi API dovrebbe preferire suggerimenti di retry upstream (Retry-After, intestazioni di reset, o testo di reset analizzabile) quando disponibili.- Fallimenti recuperabili ripetuti utilizzano un backoff esponenziale:
baseCooldownMs * 2 ** failureIndex;La guardia anti-thundering-herd previene fallimenti concorrenti sulla stessa connessione da
estendere ripetutamente il cooldown o incrementare doppiamente backoffLevel.
Gli stati terminali non sono cooldown. banned, expired, e credits_exhausted sono
destinati a rimanere non disponibili fino a quando le credenziali/impostazioni non cambiano o un operatore le ripristina.
Non sovrascrivere stati terminali con stati di cooldown transitori.
Ambito: fornitore + connessione + modello.
Scopo: evitare di disabilitare un'intera connessione quando solo un modello è non disponibile o limitato per quota per quella connessione.
Esempi:
- Fornitori per quota per modello che restituiscono
429. - Fornitori locali che restituiscono
404per un modello mancante. - Fallimenti di permesso di modalità/modello specifici del fornitore come le modalità Grok selezionate.
Il lockout del modello vive in open-sse/services/accountFallback.ts e consente alla stessa
connessione di continuare a servire altri modelli.
- Se tutte le chiavi per un fornitore vengono saltate, ispeziona sia lo stato dell'interruttore del fornitore che
rateLimitedUntil/testStatusdi ciascuna connessione. - Se un fornitore appare permanentemente escluso dopo la finestra di reset, controlla se il codice
sta leggendo lo stato grezzo invece di utilizzare
getStatus()/canExecute(). - Se una chiave di fornitore fallisce ma altre dovrebbero funzionare, preferisci il cooldown di connessione rispetto all'interruttore del fornitore.
- Se solo un modello fallisce, preferisci il lockout del modello rispetto al cooldown di connessione.
- Se uno stato dovrebbe auto-recuperarsi, dovrebbe avere un timestamp futuro/timeout di reset e un percorso di lettura che aggiorna lo stato scaduto. Gli stati permanenti richiedono modifiche manuali alle credenziali o alla configurazione.
- 2 spazi, punti e virgola, virgolette doppie, larghezza 100 caratteri, virgole finali es5 (imposte da lint-staged tramite Prettier)
- Importazioni: esterne → interne (
@/,@omniroute/open-sse) → relative - Nomenclatura: file=camelCase/kebab, componenti=PascalCase, costanti=UPPER_SNAKE
- ESLint:
no-eval,no-implied-eval,no-new-func= errore ovunque;no-explicit-any= avviso inopen-sse/etests/ - TypeScript:
strict: false, target ES2022, modulo esnext, risoluzione bundler. Preferire tipi espliciti.
- Sempre passare attraverso i moduli di dominio
src/lib/db/— mai scrivere SQL raw in rotte o gestori - Mai aggiungere logica a
src/lib/localDb.ts(solo livello di re-export) - Mai importare a barre da
localDb.ts— importare invece moduli specificidb/ - Singleton DB:
getDbInstance()dasrc/lib/db/core.ts(journaling WAL) - Migrazioni:
src/lib/db/migrations/— file SQL versionati, idempotenti, eseguiti in transazioni
- try/catch con tipi di errore specifici, log con contesto pino
- Non nascondere errori nei flussi SSE — utilizzare segnali di abort per la pulizia
- Restituire codici di stato HTTP appropriati (4xx/5xx)
- Mai usare
eval(),new Function(), o eval implicito - Validare tutti gli input con schemi Zod
- Crittografare le credenziali a riposo (AES-256-GCM)
- Denylist degli header upstream:
src/shared/constants/upstreamHeaders.ts— mantenere sanitizzazione, schemi Zod e test unitari allineati durante la modifica - Credenziali pubbliche upstream (client_id/secret OAuth stile Gemini/Antigravity/Windsurf + chiavi Web Firebase estratte da CLI pubblici): DEVONO essere incorporate tramite
resolvePublicCred()daopen-sse/utils/publicCreds.ts— mai come stringhe letterali. Vedidocs/security/PUBLIC_CREDS.mdper il modello obbligatorio. - Risposte di errore (HTTP / SSE / gestore executor / gestore MCP): DEVONO passare attraverso
buildErrorBody()osanitizeErrorMessage()daopen-sse/utils/error.ts— mai mettereerr.stackoerr.messageraw nel corpo della risposta. Vedidocs/security/ERROR_SANITIZATION.md. - Comandi shell costruiti da variabili: quando si chiama
exec()/spawn()con uno script che necessita di valori di runtime, passarli tramite l'opzioneenv(automaticamente shell-escaped) — mai interpolare stringhe percorsi non fidati/esterni nel corpo dello script. Riferimento:src/mitm/cert/install.ts::updateNssDatabases. - Librerie sicure per impostazione predefinita (tldrsec/awesome-secure-defaults): preferire Helmet.js, DOMPurify, ssrf-req-filter, safe-regex, Google Tink rispetto a implementazioni personalizzate ogni volta che si aggiungono nuove superfici sensibili alla sicurezza.
- Registrare in
src/shared/constants/providers.ts(validato da Zod al caricamento) - Aggiungere executor in
open-sse/executors/se necessaria logica personalizzata (estendereBaseExecutor) - Aggiungere traduttore in
open-sse/translator/se formato non OpenAI - Aggiungere configurazione OAuth in
src/lib/oauth/constants/oauth.tsse basato su OAuth — se il CLI upstream fornisce un client_id/secret pubblico, incorporare tramiteresolvePublicCred()(vedidocs/security/PUBLIC_CREDS.md), mai come letterale - Registrare modelli in
open-sse/config/providerRegistry.ts - Scrivere test in
tests/unit/(includere l'asserzione della forma publicCreds se hai aggiunto un nuovo default incorporato)
- Creare directory sotto
src/app/api/v1/your-route/ - Creare
route.tscon gestoriGET/POST - Seguire il modello: CORS → validazione del corpo Zod → auth opzionale → delega del gestore
- Il gestore va in
open-sse/handlers/(importare da lì, non inline) - Le risposte di errore utilizzano
buildErrorBody()/errorResponse()daopen-sse/utils/error.ts(auto-sanitizzate — non mettereerr.stackoerr.messageraw nel corpo). Vedidocs/security/ERROR_SANITIZATION.md. - Aggiungere test — includendo almeno un'asserzione che le risposte di errore non rivelino tracce di stack (
!body.error.message.includes("at /"))
- Creare
src/lib/db/yourModule.ts— importaregetDbInstanceda./core.ts - Esportare funzioni CRUD per la tua tabella di dominio
- Aggiungere migrazione in
src/lib/db/migrations/se necessarie nuove tabelle - Re-esportare da
src/lib/localDb.ts(aggiungere solo all'elenco di re-export) - Scrivere test
- Aggiungere definizione dello strumento in
open-sse/mcp-server/tools/con schema di input Zod + gestore async - Registrare nel set di strumenti (collegato da
createMcpServer()) - Assegnare agli ambiti appropriati
- Scrivere test (invocazione dello strumento registrata nella tabella
mcp_audit)
- Creare abilità in
src/lib/a2a/skills/(5 già esistenti: smart-routing, quota-management, provider-discovery, cost-analysis, health-report) - L'abilità riceve il contesto del compito (messaggi, metadati) → restituisce un risultato strutturato
- Registrare in
A2A_SKILL_HANDLERSinsrc/lib/a2a/taskExecution.ts - Esporre in
src/app/.well-known/agent.json/route.ts(Agent Card) - Scrivere test in
tests/unit/ - Documentare nella tabella delle abilità in
docs/frameworks/A2A-SERVER.md
- Creare classe agente in
src/lib/cloudAgent/agents/estendendoCloudAgentBase(3 già esistenti: codex-cloud, devin, jules) - Implementare
createTask,getStatus,approvePlan,sendMessage,listSources - Registrare in
src/lib/cloudAgent/registry.ts - Aggiungere gestione OAuth/credenziali se necessario (
src/lib/oauth/providers/) - Test + documentare in
docs/frameworks/CLOUD_AGENT.md
- Guardrail:
src/lib/guardrails/→ documenti:docs/security/GUARDRAILS.md - Suite Eval:
src/lib/evals/→ documenti:docs/frameworks/EVALS.md - Abilità (sandbox):
src/lib/skills/→ documenti:docs/frameworks/SKILLS.md - Evento Webhook:
src/lib/webhookDispatcher.ts→ documenti:docs/frameworks/WEBHOOKS.md
Per qualsiasi modifica non banale, leggi prima il documento di approfondimento corrispondente:
| Area | Documento |
|---|---|
| Navigazione del repository | docs/architecture/REPOSITORY_MAP.md |
| Architettura | docs/architecture/ARCHITECTURE.md |
| Riferimento ingegneristico | docs/architecture/CODEBASE_DOCUMENTATION.md |
| Auto-Combo (13-factor scoring, 19 public strategies) | docs/routing/AUTO-COMBO.md |
| Resilienza (3 meccanismi) | docs/architecture/RESILIENCE_GUIDE.md |
| Riproduzione del ragionamento | docs/routing/REASONING_REPLAY.md |
| Framework delle competenze | docs/frameworks/SKILLS.md |
| Sistema di memoria (FTS5 + Qdrant) | docs/frameworks/MEMORY.md |
| Agenti cloud | docs/frameworks/CLOUD_AGENT.md |
| Guardrail (PII / injection / visione) | docs/security/GUARDRAILS.md |
| Credenziali pubbliche upstream (Gemini/ecc.) | docs/security/PUBLIC_CREDS.md |
| Sanitizzazione dei messaggi di errore | docs/security/ERROR_SANITIZATION.md |
| Valutazioni | docs/frameworks/EVALS.md |
| Conformità / audit | docs/security/COMPLIANCE.md |
| Webhook | docs/frameworks/WEBHOOKS.md |
| Pipeline di autorizzazione | docs/architecture/AUTHZ_GUIDE.md |
| Stealth (TLS / impronta digitale) | docs/security/STEALTH_GUIDE.md |
| Protocolli degli agenti (A2A / ACP / Cloud) | docs/frameworks/AGENT_PROTOCOLS_GUIDE.md |
| Server MCP | docs/frameworks/MCP-SERVER.md |
| Server A2A | docs/frameworks/A2A-SERVER.md |
| Riferimento API + OpenAPI | docs/reference/API_REFERENCE.md + docs/reference/openapi.yaml |
| Catalogo dei fornitori (generato automaticamente) | docs/reference/PROVIDER_REFERENCE.md |
| Flusso di rilascio | docs/ops/RELEASE_CHECKLIST.md |
| Cosa | Comando |
|---|---|
| Test unitari | npm run test:unit |
| Singolo file | node --import tsx/esm --test tests/unit/file.test.ts |
| Vitest (MCP, autoCombo) | npm run test:vitest |
| E2E (Playwright) | npm run test:e2e |
| Protocol E2E (MCP+A2A) | npm run test:protocols:e2e |
| Ecosistema | npm run test:ecosystem |
| Porta di copertura | npm run test:coverage (75/75/75/70 — dichiarazioni/righe/funzioni/rami) |
| Rapporto di copertura | npm run coverage:report |
Regola PR: Se modifichi il codice di produzione in src/, open-sse/, electron/, o bin/, devi includere o aggiornare i test nella stessa PR.
Preferenza per il livello di test: unità prima → integrazione (multi-modulo o stato DB) → e2e (solo UI/flusso di lavoro). Codifica le riproduzioni di bug come test automatizzati prima o insieme alla correzione.
Politica di copertura di Copilot: Quando una PR modifica il codice di produzione e la copertura è inferiore al 75% (dichiarazioni/righe/funzioni) o al 70% (rami), non limitarti a segnalare — aggiungi o aggiorna i test, riesegui la porta di copertura, poi chiedi conferma. Includi i comandi eseguiti, i file di test modificati e il risultato finale della copertura nel rapporto PR.
# Non impegnarti mai direttamente su main
git checkout -b feat/your-feature
git commit -m "feat: descrivi la tua modifica"
git push -u origin feat/your-featurePrefissi dei branch: feat/, fix/, refactor/, docs/, test/, chore/
Formato del commit (Conventional Commits): feat(db): aggiungi circuit breaker — scope: db, sse, oauth, dashboard, api, cli, docker, ci, mcp, a2a, memory, skills
Hook di Husky:
- pre-commit: lint-staged +
check-docs-sync+check:any-budget:t11 - pre-push:
npm run test:unit
- Runtime: Node.js ≥20.20.2 <21 | | ≥22.22.2 <23 | | ≥24 <25, ES Modules
- TypeScript: 5.9+, target ES2022, module esnext, risoluzione bundler
- Alias di percorso:
@/*→src/,@omniroute/open-sse→open-sse/,@omniroute/open-sse/*→open-sse/* - Porta predefinita: 20128 (API + dashboard sulla stessa porta)
- Directory dei dati: variabile d'ambiente
DATA_DIR, predefinita a~/.omniroute/ - Variabili d'ambiente chiave:
PORT,JWT_SECRET,API_KEY_SECRET,INITIAL_PASSWORD,REQUIRE_API_KEY,APP_LOG_LEVEL - Configurazione:
cp .env.example .envpoi generaJWT_SECRET(openssl rand -base64 48) eAPI_KEY_SECRET(openssl rand -hex 32)
- Non impegnare mai segreti o credenziali
- Non aggiungere mai logica a
localDb.ts - Non usare mai
eval()/new Function()/ eval implicito - Non impegnarsi mai direttamente su
main - Non scrivere mai SQL raw nelle route — usa i moduli in
src/lib/db/ - Non ignorare mai silenziosamente gli errori nei flussi SSE
- Validare sempre gli input con gli schemi Zod
- Includere sempre test quando si modifica il codice di produzione
- La copertura deve rimanere ≥75% (dichiarazioni, righe, funzioni) / ≥70% (rami). Misurato attualmente: ~82%.
- Non bypassare mai gli hook di Husky (
--no-verify,--no-gpg-sign) senza esplicita approvazione dell'operatore. - Non incorporare mai client_id/secret OAuth pubblici upstream o chiavi Web Firebase come stringhe letterali — passare sempre attraverso
resolvePublicCred()(open-sse/utils/publicCreds.ts). Vedidocs/security/PUBLIC_CREDS.md. - Non restituire mai
err.stack/err.messageraw nelle risposte HTTP / SSE / executor — instradare sempre attraversobuildErrorBody()osanitizeErrorMessage()(open-sse/utils/error.ts). Vedidocs/security/ERROR_SANITIZATION.md. - Non interpolare mai stringhe percorsi esterni o valori di runtime in script shell passati a
exec()/spawn()— passare invece tramite l'opzioneenv. Riferimento:src/mitm/cert/install.ts::updateNssDatabases. - Non ignorare mai un avviso CodeQL / Secret-Scanning senza (a) controllare prima la documentazione del pattern sopra per vedere se l'aiuto si applica, e (b) registrare la giustificazione tecnica nel commento di dismissione. Precedente:
js/stack-trace-exposuresollevato su callsites che già instradano attraversosanitizeErrorMessage()è una limitazione nota di CodeQL (sanitizzatori personalizzati non riconosciuti) — dismettere comefalse positivefacendo riferimento adocs/security/ERROR_SANITIZATION.md. - Non esporre mai route che generano processi figlio (
/api/mcp/,/api/cli-tools/runtime/) senza classificazioneisLocalOnlyPath()insrc/server/authz/routeGuard.ts. L'applicazione del loopback avviene incondizionatamente prima di qualsiasi controllo di autenticazione — un JWT trapelato tramite tunnel non può attivare la generazione di processi. Vedidocs/security/ROUTE_GUARD_TIERS.md. - Non includere mai trailer
Co-Authored-Byche accreditano un assistente AI, LLM o account di automazione (es. nomi contenenti "Claude", "GPT", "Copilot", "Bot"; email suanthropic.com/openai.com/ indirizzinoreply.github.comdi proprietà di bot). Tali trailer indirizzano l'attribuzione del commit all'account del bot su GitHub, nascondendo l'autore reale (diegosouzapw) nella cronologia della PR. I collaboratori umani — inclusi gli autori di PR upstream e i segnalatori di issue portati in OmniRoute — POSSONO e DEVONO essere accreditati con trailer standardCo-authored-by: Name <email>; i workflow di port upstream (/port-upstream-features,/port-upstream-issues) ne dipendono.