Linha de OS: tabela linhas-os.yaml como fallback quando o SD.md não declara
Decisão de 2026-09-04, revendo a de 2026-09-03 (sem de-para): o .md continua mandando, e a tabela contrato/linhas-os.yaml (OS Mãe × linha × item) só entra quando o entregável não declara `linha_os`. Linha declarada vai como está e não é conferida contra a tabela; existência/item/status seguem sendo do banco. - caminhos.LINHAS_OS; regras_sd: Canonico(itens, linhas_os), carregar_linhas_os (arquivo ausente = fallback desligado), preparar_linhas_os (valida: formato, linha repetida, dois `padrao`, `padrao` não booleano) e linha_da_tabela. - exporta_sd: ausente → padrão do item; 2+ candidatas sem padrão → pendência nomeando-as; item fora da tabela → pendência. CLI informa quantas linhas vieram da tabela. - app: sessao.adotar_linhas_da_tabela grava a linha no frontmatter da sessão com comentário de origem, para o Salvar SD.md deixar a SD autodeclarada; a tela marca `tabela` e mostra a data da tabela. - testes: SD18, SD27, SD31–36 passam a exportar de saída; SD10 só PO+objetivo; casos sintéticos para tabela ausente, ambígua, sem o item e malformada. - deploy: linhas-os.yaml vive em clientes/ (gitignored) — vai por scp ao volume. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
+39
-14
@@ -28,12 +28,15 @@ reajuste. As chaves continuam no JSON, na mesma posição — só o valor é `nu
|
||||
`horas_semanais` e `memoria_calculo`, que só existiam para explicar a conta,
|
||||
saem `null` pelo mesmo motivo.
|
||||
|
||||
O que NÃO é derivado, por decisão da gestão (2026-09-03): `ordem_servico.linha`.
|
||||
OS e linha são cadastro do sistema de gestão e mudam durante o ano; um de-para
|
||||
local envelheceria em silêncio. Quem emite a SD declara `linha_os` no
|
||||
entregável, copiado da tela da OS; aqui só o formato `{OS}-L{n}` é conferido,
|
||||
e ausente é pendência. Existência, item e status quem confere é o banco, na
|
||||
carga — que recusa nomeando o que falta.
|
||||
O que NÃO é derivado: `ordem_servico.linha`. OS e linha são cadastro do sistema
|
||||
de gestão e mudam durante o ano. Quem emite a SD declara `linha_os` no
|
||||
entregável, copiado da tela da OS; aqui só o formato `{OS}-L{n}` é conferido, e
|
||||
existência, item e status quem confere é o banco, na carga — que recusa
|
||||
nomeando o que falta. AUSENTE, a tabela contrato/linhas-os.yaml (se existir)
|
||||
dá a linha padrão do item — fallback, decidido em 2026-09-04, para poupar a
|
||||
digitação; sem padrão é pendência, com as candidatas nomeadas quando a tabela
|
||||
tem mais de uma. A linha declarada nunca é conferida contra a tabela (decisão
|
||||
de 2026-09-03): o .md manda.
|
||||
|
||||
O que este script NÃO faz, por decisão da gestão (2026-09-03): não confere os
|
||||
tetos de texto da §2/§3/§4 (nome ≤ 160, objetivo ≤ 4000 etc.) — o importador
|
||||
@@ -85,6 +88,7 @@ from regras_sd import (
|
||||
enquadramento_tr,
|
||||
janela_dias,
|
||||
ler_sd_arquivo,
|
||||
linha_da_tabela,
|
||||
perfil_do_cadastro,
|
||||
secao,
|
||||
semanas_por_datas,
|
||||
@@ -421,15 +425,31 @@ def _montar(sd: dict, corpo: str, canon: Canonico, pend: list[Pendencia]) -> dic
|
||||
"na carga (time-box × semanas das datas). Apague a declaração.")
|
||||
|
||||
# -- linha de OS -----------------------------------------------------------
|
||||
# Declarada no SD.md por quem emite a SD, e só o formato é conferido
|
||||
# aqui. OS e linha são cadastro do sistema de gestão e mudam durante o
|
||||
# ano; quem sabe se existem é o banco, na carga. Não há de-para local.
|
||||
# Declarada no SD.md: vai como está, só o formato é conferido — OS e
|
||||
# linha são cadastro do sistema de gestão, e quem sabe se existem é o
|
||||
# banco, na carga. Ausente, a tabela contrato/linhas-os.yaml (se houver)
|
||||
# dá a linha padrão do item; sem padrão é pendência, e com mais de uma
|
||||
# candidata a mensagem as nomeia para a pessoa escolher.
|
||||
linha = None
|
||||
queixa = conferir_formato_linha_os(e.get("linha_os"))
|
||||
if queixa:
|
||||
falta("linha_os", queixa)
|
||||
declarada = e.get("linha_os")
|
||||
if declarada in (None, ""):
|
||||
padrao, candidatas = linha_da_tabela(canon.linhas_os, item) if item_ok else (None, [])
|
||||
if padrao:
|
||||
linha = padrao
|
||||
elif len(candidatas) > 1:
|
||||
falta("linha_os", f"`linha_os` ausente, e a tabela linhas-os.yaml tem {len(candidatas)} "
|
||||
f"linhas para {item} sem `padrao` marcado: {', '.join(candidatas)}. "
|
||||
"Escolha uma aqui, ou marque o padrão na tabela", opcoes=candidatas)
|
||||
else:
|
||||
sem_entrada = f" — a tabela linhas-os.yaml não tem linha para {item}" \
|
||||
if canon.linhas_os and item_ok else ""
|
||||
falta("linha_os", conferir_formato_linha_os(None) + sem_entrada)
|
||||
else:
|
||||
linha = str(e.get("linha_os")).strip()
|
||||
queixa = conferir_formato_linha_os(declarada)
|
||||
if queixa:
|
||||
falta("linha_os", queixa)
|
||||
else:
|
||||
linha = str(declarada).strip()
|
||||
|
||||
# -- listas filhas -----------------------------------------------------------
|
||||
for campo in ("atividades", "criterios_aceite"):
|
||||
@@ -695,8 +715,13 @@ def main() -> int:
|
||||
print(f" ERRO {f}: {exc}", file=sys.stderr)
|
||||
falhas.append(f)
|
||||
continue
|
||||
# Se montar() passou com `linha_os` ausente, a linha veio da tabela —
|
||||
# dizer quantas: é a única pista de que o .md ainda não a declara.
|
||||
da_tabela = sum(1 for e in (sd.get("entregaveis") or [])
|
||||
if isinstance(e, dict) and e.get("linha_os") in (None, ""))
|
||||
print(f" {rotulo} → {saida} {len(payload['entregaveis'])} entregável(is) "
|
||||
f"({', '.join(payload['sd']['itens_contratuais'])})")
|
||||
f"({', '.join(payload['sd']['itens_contratuais'])})"
|
||||
+ (f" · {da_tabela} linha(s) de OS da tabela linhas-os.yaml" if da_tabela else ""))
|
||||
|
||||
if falhas:
|
||||
# Isolar sem nomear é pior que o estouro que substitui: o lote
|
||||
|
||||
Reference in New Issue
Block a user