genro-asgi · stato attuale

Dove siamo, voce per voce

I tre documenti di presentazione descrivono il punto di arrivo. Questa pagina è il solo posto dove si legge quanto di quel disegno esiste oggi, e l'unico che cambia mentre l'implementazione procede. Ogni riga porta la propria prova: un file con la sua copertura, un test che la esercita, oppure la constatazione che non esiste una riga di codice.

Test
1519verdi, 0 falliti
Copertura
97%8.028 stmt, 279 scoperti
Voci
33sui tre mondi di internals/
Consolidate
208 con riserve, 5 solo progettate

Le quattro voci della scala

Consolidato

codice completo, test dedicati, decisione ratificata e chiusa

Attivo con riserve

funziona ed è testato, ma con punti esplicitamente differiti o costanti provvisorie

Solo progettato

ratificato o discusso, nessuna riga di codice

Questione aperta

nessuna decisione presa: resta una domanda

La scala non è un giudizio: è derivata da fatti verificabili — se il codice esiste, se esistono test dedicati che lo esercitano, e se la decisione che lo riguarda è chiusa o ancora aperta.

documento 1

Il server

La macchina su cui gira ogni installazione, da BaseServer in su.

15 consolidato · 5 attivo con riserve · 2 solo progettato

Il server e le sue applicazioni

Attivo con riserve

L'oggetto server, le applicazioni che ospita, come una richiesta ne trova una, avvio e spegnimento ordinati.

  • server.py 130 stmt · 99% · asgi_server.py 97% · pool.py 100% · lifespan.py 98% · request_registry.py 99%
  • test_contract.py, test_demux.py, test_pool.py, test_lifespan.py, test_request_registry.py
  • Gli stati di vita del server — running, quitting, stopping — e il drenaggio limitato delle richieste in volo (lifespan.py)
Riserve
  • L'indice di sito su / è ratificato (D29, 24 agosto) e non costruito: oggi quel caso risponde 404.

La configurazione

Consolidato

L'albero da cui ogni voce legge le proprie parole: strati, pila di lettura, sottoscrittori.

  • config/handler.py 147 stmt · 100% · elements.py 100% · builder.py 100% · default_config.py 98%
  • test_config.py — 82 casi, il file più esercitato del progetto — e test_config_env.py

Le applicazioni e il loro albero di rotte

Consolidato

RoutedApplication e l'albero di rotte che serve REST e MCP insieme.

  • application.py 100% · routed_application.py 95%
  • test_routed_application.py, test_package.py

OpenAPI

Consolidato

Lo schema e le pagine di documentazione, tradotti dalla lettura dell'albero.

  • applications/openapi.py 100% · plugins/openapi/translator.py 86% · plugin.py 77%
  • test_openapi_application.py, test_plugins.py (32 casi)

MCP

Consolidato

Il motore JSON-RPC e il trasporto Streamable HTTP sullo stesso albero.

  • applications/mcp.py 96% · mcp/engine.py 98%
  • test_mcp_application.py, test_mcp_engine.py (31), test_mcp_push.py

Il sistema di routing

Consolidato

L'albero, la passeggiata filtrata, e i plugin armati sopra di esso.

  • plugin_mixin.py 100% — cinque plugin di libreria: auth, env, channel, pydantic, logging
  • test_plugins.py (32 casi)

La catena dei middleware

Consolidato

La catena uniforme che ogni richiesta attraversa, ordinata da un numero.

  • otto moduli: errors 99% · session 100% · cors 96% · logging 85% · wellknown 100%
  • test_middleware.py e test_middleware_std.py (27)

Le sessioni

Consolidato

Stato per utente sul server fra una richiesta e l'altra.

  • session/store.py 100% · session.py 100% · mixin.py 100%
  • test_session.py (50), test_login_flow.py (28)

L'autenticazione

Consolidato

401 all'anonimo, 403 a chi è già noto. Password con blocco progressivo, OIDC con PKCE, basic, bearer, JWT, chiavi API.

  • auth/core.py 95% · oidc_method.py 97% · user_store.py 94% · api_key_store.py 95%
  • test_auth.py (46), test_oidc.py (27), test_user_store.py, test_api_key_store.py

L'avatar

Consolidato

Chi è l'utente corrente, con i suoi tag, dal login alla richiesta.

  • session/avatar.py 94% — coperto da test_session.py e test_auth.py

I tag di autorizzazione

Consolidato

L'autorizzazione dichiarata sulla rotta, non scritta dentro l'handler.

  • i tag entrano dalla grammatica (auth/core.py:105) e sono letti dal plugin auth del router

Lo storage

Consolidato

L'unico accesso al filesystem, attraverso nodi di storage. Pinnato sincrono.

  • storage_mixin.py 100% — set_sync() imposto dal mixin
  • test_storage_mixin.py

Il database

Consolidato

Il contratto minimo per un database montato dalla ricetta. Nessun backend nel core, per disegno.

  • db.py 17 stmt · 100% · test_db.py

I task

Attivo con riserve

Il lavoro che non è una richiesta HTTP: pianificazione in tre forme, spool su file, esecuzione.

  • tasks/spool.py 148 stmt · 100% · schedule.py 98% · scheduler.py 91% · store.py 94% · manager.py 97% · executor.py 100%
  • cinque file di test, fra cui test_task_spool.py (28)
Riserve
  • L'esecuzione è in-processo sul server vivo (LocalTaskExecutor). L'esecuzione su processi dedicati è dichiarata fuori scope in D22 e non esiste.

I termometri dei batch

Attivo con riserve

Vedere un batch muoversi, e fermarlo con garbo.

  • manager.publish_progress (manager.py:160) scrive progress.json e pubblica sul canale vivo in una chiamata sola
  • letto da tasks_section.py:230 e da applications/mcp.py:262
Riserve
  • Il segnale di stop è deposto (spool.request_cancel) e leggibile (is_cancelled), ma nessun consumatore in src/: il core non ferma nulla. Un batch che non lo controlla da sé non si ferma. L'unico lettore è un test.

L'app di sistema _server

Attivo con riserve

Montata su ogni server, mai configurata: login, utenti, credenziali, task, monitor, inspector.

  • server_app.py 100% · sezioni auth, users, tokens, tasks tutte al 100%
Riserve
  • Restano da fare i tag di autenticazione per sezione e la pagina di configurazione dei plugin.

Il monitor

Consolidato

Una pagina sola su ogni applicazione montata, attraverso il contratto app_snapshot/app_panel/panel_source.

  • monitor_section.py 51 stmt · 100% · test_server_monitor.py (20 casi)

L'inspector

Consolidato

La sezione che apre un server vivo all'ispezione.

  • inspector_section.py 37 stmt · 95% · test_inspector_section.py

La riga di comando

Consolidato

Guidare le installazioni dalla shell. Un config.py più genroasgi serve sono un'unità di rilascio completa.

  • __main__.py 291 stmt · 98% — verbi serve, apps, stop, remove
  • test_cli.py (50 casi)

Il riavvio

Attivo con riserve

Il soft quit e il soft start: uscendo tutti gli utenti vengono parcheggiati congelati, rientrando le mappe tornano al loro posto e il risveglio è pigro.

  • SpaCommander.quit e adopt_frozen_registers (spa_commander.py:1306) · freeze_handler.py 110 stmt · 99%
  • il rinominare la cartella È la prova di completezza: reboot_tempreboot_data
  • sotto serve --reload ogni uscita salva — verificato dal vivo: stesso cookie, processo nuovo, nessun nuovo login
Riserve
  • Manca il comando deliberato su _server (reboot now / reboot wait N) e la corsia dei messaggi di servizio verso il consumer.
  • La sentinella dei sorgenti guarda il progetto per intero: manca il classificatore che dice a quale gruppo appartiene il file cambiato, e quindi il riavvio del solo gruppo interessato.
  • Il ponte genropy-asgi non passa ancora --reload al nucleo: la sua riga di comando lo accetta e lo ignora.

Il trasporto WSX

Solo progettato

Il secondo trasporto del motore unico: stesso albero di rotte, stessi plugin, stessa autorizzazione di HTTP.

  • Scritto e provato nel prototipo genro-asgi-legacy: src/genro_asgi/wsx/ — 690 righe su quattro moduli (protocol.py, handler.py, registry.py) — con 68 casi su quattro file di test
  • WSX sta per WebSocket eXtended: un messaggio porta il prefisso WSX:// e poi il JSON con id, method, path, headers, cookies, query e data — semantica HTTP sopra il WebSocket
  • Su develop non è ancora stato trasportato: BaseServer.on_websocket (server.py:287) accetta nulla e chiude con codice 1000, e non c'è una sola occorrenza di websocket.accept in src/
Riserve
  • Il trasporto non si ricopia: nel prototipo lo smistamento HTTP e quello WSX erano divergenti perché nulla li obbligava a restare uguali. La lezione è registrata come invariante 9 della specifica — prove di contratto su ogni interfaccia con più implementazioni — e il trasporto va rifatto sotto quella regola, con un motore di smistamento solo.

Il limite di frequenza per IP

Solo progettato

Un middleware dedicato che limita per indirizzo, distinto dal blocco progressivo per identità.

  • zero occorrenze di rate_limit in src/
  • il blocco progressivo per identità esiste ed è operativo (D28), ed è un'altra cosa

documento 2

Il mondo SPA

Il mondo che ospita un sito a pagina singola con stato vivo sul server.

5 consolidato · 3 attivo con riserve

Il front SPA

Consolidato

Una porta sola e stabile verso il sito ospitato, senza stato nella porta: cookie, demux a due stadi, traduzione HTTP.

  • applications/spa_app.py 106 stmt · 99% · test_spa_application.py
  • un rifiuto esce 503 con Retry-After, un sito che fallisce dentro il proprio processo esce 502

L'orchestrazione

Attivo con riserve

Molti utenti con stato vivo, distribuiti su più processi e mai spezzati. La catena è commander → gruppo → worker.

  • spa_commander.py 490 stmt · 97% · spa_worker.py 921 · 97% · group_handler.py 207 · 97% · worker_handler.py 172 · 97% · envelope_handler.py 100%
  • 27 file sotto tests/orchestration/
  • il gruppo che dichiara engine_factory possiede un processo template: costruisce il motore una volta, congela l'heap, e ogni worker è un suo fork (template_entry.py, template_connector.py)
  • la ricetta di un gruppo dichiara executable: il processo del server e i worker di ogni gruppo possono stare su interpreti diversi (worker_handler.py:425, template_connector.py:133)
  • i massimali sono worker_max_number e worker_max_users; la memoria è una cascata di percentuali e solo il fondo è in byte
Riserve
  • Non esiste il worker in-processo. Il canale locale c'è ed è testato (channel/local.py 92%), ma nessun percorso dell'orchestrazione lo usa per costruire un worker dentro il commander.
  • Non esiste il ribilanciamento che sceglie chi spostare in base al consumo recente: il pool cresce, riavvia un worker oltre soglia, e chiude quello in esubero.
  • Non esiste la serie storica della memoria né la stima di quando un processo toccherà il limite: restart_occupancy_max_percent è una soglia secca.

Il canale

Consolidato

Il filo: frame con prefisso di lunghezza, hub, corsia. Zero dipendenze esterne.

  • channel/hub.py 202 stmt · 90% · client.py 91% · frame.py 94% · local.py 92%
  • test_channel.py, test_channel_hub.py, test_channel_local.py

Lo store globale

Consolidato

Un solo stato condiviso, con lettura-e-scrittura sicura. Un master sul commander e nessuna replica: un worker legge con una chiamata sulla corsia e scrive attraverso la concessione.

  • spa/global_store.py 66 stmt · 94% · test_spa_global_store.py
  • store_get è una chiamata; la concessione porta con sé il contenuto del master, e le modifiche atterrano tutte al rilascio
  • prove di contratto: fasi 10, 12, 13 sotto tests/orchestration/

I datachange

Consolidato

Quello che una pagina cambia, le altre lo devono vedere. Consegna indirizzata attraverso il DeliveryDesk, mai una fotografia per processo.

  • subscription_index.py 44 stmt · 100% · il banco vive sul commander (spa_commander.py:251)
  • la consegna è a richiesta: nulla viene mai spinto dal banco
  • prove di contratto: fasi 3, 8, 13

I dbevent

Consolidato

Il database ha cambiato una tabella, e la pagina lo deve sapere. La sottoscrizione è attiva appena depositata, quindi chi sottoscrive e committa nella stessa richiesta si ritrova servito.

  • prova di contratto: fase 4 · code con età limitata, esclusione dell'origine dal fan-out

La console

Attivo con riserve

Chiedere a un pool vivo le domande che nessuno aveva previsto, servite come strumenti MCP.

  • applications/spa_console.py 33 stmt · 88% · test_orchestration_console.py
  • eval in un processo qualunque del pool — commander o un worker per nome — attraverso la corsia che il commander già tiene
Riserve
  • Il montaggio È il cancello: è eval pieno per costruzione, e non deve mai essere montata in produzione.

Il contratto del bridge

Attivo con riserve

Che cosa il sito ospitato deve fornire e che cosa può consumare: la callable WSGI dietro WsgiSeam, il sito che battezza la propria connessione mentre serve, i verbi del piano dati.

  • spa/environ.py 60 stmt · 85% — l'ambiente WSGI sintetizzato, invocato in-processo su un pool di thread dedicato
  • l'identità è quella del sito: il cookie spa_connection_id porta il connection id che il sito stesso ha coniato
Riserve
  • genropy-asgi, il primo cliente del contratto, non è ancora stato ribasato su develop: il contratto non è mai stato esercitato qui da un sito vero.

documento 3

Rilascio e scala

Come un'installazione si spedisce, si aggiorna e cresce oltre una macchina. Tutto qui è proposta non ratificata.

3 solo progettato

Gruppi dinamici e bundle applicativi

Solo progettato

Gruppi come oggetti vivi — aggiunti, aggiornati e rimossi a server acceso — ciascuno agganciato a un bundle applicativo immutabile costruito dalla CI dell'applicazione e distribuito su S3.

  • nessuna riga: le cinque occorrenze di «bundle» in src/ sono i bundled plugins di genro-routes, altro significato
  • fonte: codex/progetto-distribuzione-bundle-applicativi-s3-2026-08-20.md, 791 righe, decisioni D1–D7, che dichiara di non autorizzare alcuna modifica al codice
Riserve
  • Restano da decidere: il formato esatto del bundle, la sorte dello stato residente durante l'aggiornamento di un gruppo, e l'API pubblica del ciclo di vita.
  • La §3.5 del progetto — «tutti i worker di una installazione usano lo stesso Python» — è superata da una decisione del titolare del 26 agosto: il processo del server e i worker di ogni gruppo possono stare su interpreti diversi, portati dall'immagine. Il meccanismo esiste già nel codice (executable nella ricetta del gruppo).

Kubernetes

Solo progettato

Il cluster esegue, il commander decide. Se ne prendono i muscoli e non il giudizio.

  • nessuna riga · proposta non ratificata

I subcommander

Solo progettato

Autorità delegata lungo la catena: radice → subcommander → gruppo → worker.

  • nessuna riga · proposta non ratificata
  • il protocollo del canale è disegnato dall'inizio per due collocazioni, in-processo e su rete; oggi ne esiste una