docs: Hub/Agent independent versioning (Missão 4 / Bloco B.3)
Documents what the code already does (no behavior change): GTI_FISCAL_VERSION (Hub) and the Agent's own version are separate numbers with separate release cycles; central.app.installation_identity.reference_agent_version() already compares an Agent's heartbeat version against the highest PUBLISHED Windows AgentRelease, never against the Hub's version - verified against test_version_reference.py. Also documents that there is no real minimum- version connection gate today (only SCHEMA_FINGERPRINT is enforced) and where one would go if ever needed. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
# Versionamento — Hub e Agent (Missão 4 / Bloco B.3)
|
||||
|
||||
Hub e Agent têm números de versão **independentes**, cada um com seu próprio ciclo de release.
|
||||
Um deploy do Hub (`scripts/deploy_hub.ps1`) nunca exige tocar no Agent, e vice-versa. Este
|
||||
documento só descreve o comportamento já existente no código — nada foi alterado no Agent.
|
||||
|
||||
## Fontes de verdade
|
||||
|
||||
- **Hub**: `release/VERSION` == `central/app/version.py::GTI_FISCAL_VERSION` ==
|
||||
`central/pyproject.toml`'s `version` == `RELEASE_MANIFEST.json`'s `GTI_FISCAL_VERSION`/`hub.version`.
|
||||
Exposto em `GET /version`.
|
||||
- **Agent**: `agent/pyproject.toml`'s `version` == o default de `AGENT_VERSION` em
|
||||
`agent/scripts/run_agent_service.py` == `AGENT_VERSION_DEFAULT` em
|
||||
`agent/src/gti_fiscal_agent/preflight.py`. Em produção, o valor real vem de `.env`
|
||||
(`AGENT_VERSION=...`), nunca do default do código — o default só importa para uma instalação
|
||||
legada sem essa variável.
|
||||
- Os dois só coincidem por coincidência numérica ocasional; **não há relação obrigatória entre
|
||||
eles**. `tests/test_release_candidate.py` tem dois testes separados que provam isso:
|
||||
`test_versions_are_coherent_across_hub_and_packages` (só Hub) e
|
||||
`test_agent_version_is_internally_coherent` (só Agent, consigo mesmo).
|
||||
|
||||
## Como o painel decide "Atualização disponível" (já implementado, sem mudança nesta missão)
|
||||
|
||||
`central/app/installation_identity.py::reference_agent_version(session)` retorna a maior versão
|
||||
entre os `AgentRelease` com `status=PUBLISHED` e `platform=windows` — **nunca** a versão do Hub.
|
||||
Só cai de volta para `settings.agent_server_version` (env `CURRENT_SERVER_VERSION`, um valor de
|
||||
compatibilidade legado, não a versão do Hub) quando não existe nenhum release Windows publicado.
|
||||
|
||||
`compute_version_drift(agent_version, reference)` compara a versão relatada pelo Agent com essa
|
||||
referência: `CURRENT` se `agent_version >= reference`, `OUTDATED` caso contrário. Exemplo real
|
||||
verificado nesta missão: Hub em 1.3.11, Agent 2 em 1.3.8, e o último `AgentRelease` Windows
|
||||
publicado também é 1.3.8 → `compute_version_drift("1.3.8", "1.3.8") == "CURRENT"`, **sem alerta
|
||||
falso**, mesmo com o Hub numericamente "à frente". Testado em
|
||||
`central/tests/test_version_reference.py`.
|
||||
|
||||
## Versão mínima do Agent aceita pelo Hub
|
||||
|
||||
Não existe hoje um bloqueio "Agent versão X não pode nem se conectar" — qualquer Agent
|
||||
autenticado (token válido) pode enviar heartbeat e reivindicar Jobs, independentemente da
|
||||
versão. O único controle de compatibilidade real hoje é `SCHEMA_FINGERPRINT` (a impressão do
|
||||
schema Firebird que o Agent relata), não a versão de software. `api_compat` em `GET /version`
|
||||
(hoje `"1.0"`) existe como um número de versão de **contrato de API**, mas nenhum código ainda
|
||||
recusa uma chamada por causa dele — é informativo.
|
||||
|
||||
### Matriz de compatibilidade (estado atual, não uma trava de código)
|
||||
|
||||
| Hub | Agent | Compatível? | Observação |
|
||||
|--------|--------|--------------|------------|
|
||||
| 1.3.11 | 1.3.8 | Sim | Estado real de produção nesta missão. |
|
||||
| 1.3.9+ | 1.1.0+ | Sim | Capabilities (`RTC_CCLASSTRIB_WRITE_V1`, enriquecimento) são negociadas por presença de campo no heartbeat, não por número de versão. |
|
||||
| — | < 1.1.0 | Não testado | Antes da distribuição via installer/enrollment; fora do escopo de missões recentes. |
|
||||
|
||||
Se um dia for necessário recusar Agents antigos de verdade (ex.: um campo obrigatório novo no
|
||||
heartbeat), o mecanismo natural é acrescentar uma verificação explícita em
|
||||
`central/app/api.py` (heartbeat/claim) comparando `agent_version` a um mínimo configurável — isso
|
||||
NÃO existe hoje e não foi adicionado nesta missão (mudaria o comportamento do Agent/Hub sem
|
||||
necessidade concreta).
|
||||
Reference in New Issue
Block a user