18 KiB
Impl: OPS115 — work-issue/agent-work-issue: designer em qualquer toque de design + crítica visual fail-closed
Status: aprovado (gate humano 2026-09-16 — B+C doc-only confirmado) Atualizado em: 2026-09-16 Issue: #1058 Intenção: docs/plans/ops115-work-issue-designer-em-qualquer-toque.md Appetite restante: herdado (~0,5–1 dia eng; entrega doc-only)
Leitura da intenção
- Outcome: qualquer toque de design nas duas skills de execução passa pelo agente
designer(extensão do design hi-fi antes de implementar; adaptação quando o aprovado não pode ser seguido; ícones/ilustrações) e qualquer diff que muda UI só é certificado com crítica dodesignercontra o app renderizado (screenshots 390/1280 + estados); sem tier primário não há certificação — o item desce paraDEGRADEDe para em sign-off humano, nunca "segue sem". - O que NÃO negociar: fail-closed do
DEGRADED(não certifica sozinho); designer decide estrutura visual, o implementador porta markup/dados/rotas/queries/copy; non-triggers explícitos (default é não despachar);/impeccablee a doutrinaui-design-html.mdreferenciadas, nunca duplicadas;model:proibido nos commands (OPS101); pool dormente (OPS65); artefatodocs/plans/<slug>-ui-design.htmlcontinua sendo de OPS113/OPS114. - O que reavaliar: (1) a hipótese de que a mecânica de fechamento precisa de veto de plataforma (a intenção recomenda "A" no §Questões em aberto — ver decisão D1); (2) a hipótese de que os 4 triggers/ladder precisam ser literalmente copiados nas duas skills (a própria intenção nomeia o drift como risco e manda a mecânica viver no
execution-pipeline.md); (3)docs/AGENT-OPS.md:24já cita a OPS115 — conferir que a referência não vira twin.
Abordagem recomendada
flowchart LR
A["Item toca UI (B/C/D)"] --> B{"Superfície/estado coberto<br/>pelo design aprovado?"}
B -- não --> C["Trigger (a): designer estende<br/>o artefato ANTES de implementar"]
B -- sim --> D["Implementador porta<br/>classe-a-classe"]
C --> D
D --> E{"Design aprovado pode<br/>ser seguido como está?"}
E -- não --> F["Trigger (b): designer propõe a adaptação<br/>implementador não improvisa"]
F --> D
E -- sim --> G["Fechar: o diff muda UI?"]
G -- não --> O["PR Ready + auto-merge"]
G -- sim --> H["Trigger (c): crítica contra o app renderizado<br/>390/1280 + estados"]
H --> I{"Tier do designer"}
I -- primário --> J["Certifica → PR Ready<br/>Design tier: slug primário"]
I -- degradado --> K["DEGRADED + screenshots"]
K -- "work-issue" --> L["Para ANTES do push<br/>sign-off humano no chat"]
L --> M["Após sign-off → PR Ready<br/>Design tier: DEGRADED + registro"]
K -- "agent-work-issue / --auto" --> N["Comenta Issue<br/>flip blocked, sem PR"]
J --> O
M --> O
Opções consideradas: A (PR Draft como veto estrutural) | B (parar antes do PR, doc-only, work-issue) | C (autônomo bloqueia sem PR)
Recomendação: B + C, doc-only — porque (1) cabe no appetite e na Verificação da intenção ("diff só de docs/skills/regras"); (2) não exige carve-out na regra always-on "nunca Draft" (agent-pr-workflow.mdc) nem mexe em scripts//tests/; (3) reusa o gate que já existe em cada ator — no work-issue o humano é o gate (a skill é humano-supervisionada) e no autônomo o precedente já testado é comentar a Issue + flip blocked (work-issue/SKILL.md:143, agent-work-issue/SKILL.md:71); (4) --auto já para em "aprovação humana" — o DEGRADED entra na mesma lista de hard-stops, sem inventar um mecanismo novo.
Rejeitadas: A — exige --draft em scripts/github-pr.mjs + parâmetro draft em createPullRequest (scripts/lib/github-api.mjs:457) + specs, estourando o diff docs-only da Verificação e criando exceção permanente à regra always-on para um pool dormente; variante de A com prefixo de branch próprio (designer/*) exigiria branch nova (proibida) e novo veto em github-pr-flow.mjs; desarmar auto-merge à la testing-audit-disarm.mjs — é código/teste e o PR seguiria sem certificação de design (o humano ainda seria o gate, mesmo custo com mais superfície); "segue e revisa depois" — é o anti-goal que o item existe para matar.
Componentes / mudanças
execution-pipeline.md(.agents/skills/work-issue/execution-pipeline.md): dono da mecânica compartilhada. Nova seção## Design (triggers, non-triggers, crítica final)com os 4 triggers (a–d), os non-triggers, a regraDEGRADEDe a referência à ladder deui-design-html.md(sem repetir slugs por ator); item 2 de## Executarpassa a apontar para ela;## Fechar em mainganha o passo de tier/certificação;## Deltas por atordeixa de repetir "shape → craft → critique → polish" nas duas linhas e passa a referenciar a seção de design, com o delta de cada ator.work-issue/SKILL.md(.agents/skills/work-issue/SKILL.md): sub-agente Designer na decomposição, por referência a.opencode/agent/designer.md/.opencode/agent/designer-degraded.md/ui-design-html.md; checklist com o passo de design no plan-time (3d), na execução (4) e no fechamento (7); Passo 4 aponta para a seção de design do pipeline; lista de hard-stops do--autoganha a certificação visualDEGRADEDpreservando os literais pinados (Consent/LGPD,migração de schema,URL público,produção,aprovado,nunca claima,blocked); Passo 7 com o fechamento B (para antes do push quandoDEGRADED).agent-work-issue/SKILL.md(.agents/skills/agent-work-issue/SKILL.md): Designer na lista de sub-agentes; checklist (plan-time e fechamento); Passo 3 aponta para o pipeline; Passo 6 com o fechamento C —DEGRADED/sem tier primário ⇒ não abre PR, comenta a Issue + flipblocked(precedente da divergência material).engineering-standards.mdc(.agents/rules/engineering-standards.mdc): linha nova vizinha de:50("Edit the owner, don't twin") declarando que decisão de estrutura visual é dodesignere o implementador só porta.engineering-brief.md(.agents/skills/work-issue/engineering-brief.md, tabela:5-14): linha opcional apontando o agentedesigner(acessório, não aceite).docs/AGENT-OPS.md:24: já declara ladder/DEGRADED/Design tier:e cita OPS115 — não duplicar; ajustar só se algum literal divergir.- Migration: sem migration.
- Access / Consent: N/A (sem coleção, sem PII, sem write path).
- UI: Impeccable A — não há UI de produto; nenhum
shape → craft → critique → polishde produto; o design aqui é o próprio fluxo de agente.
Dados → forma (se aplicável)
N/A — processo de agente, sem superfície de dados de campanha.
Decisões de engenharia (com rejeitadas)
D1 — Mecanismo fail-closed do fechamento DEGRADED (a decisão central).
Opções: A (PR Draft/--draft como veto estrutural) | B (parar antes do PR no work-issue, doc-only) | C (autônomo comenta Issue + blocked, sem PR).
Recomendação: B + C — porque honra a Verificação doc-only da intenção, mantém a regra always-on intacta, reusa precedente e hard-stop existentes e usa o gate que cada ator já tem (humano no work-issue; blocked no autônomo).
Rejeitadas: A — código em scripts/ + carve-out da regra always-on + test novo, tudo fora do appetite/Verificação; A-keyword variant (declarar DEGRADED no body e confiar em heurística do safety net) — não existe veto por body e inferir por texto é frágil; disarm script — overkill; branch prefix novo — proibido. Gatilho de revisitação: reabrir A somente se o pool for reativado e a entrega autônoma de itens UI virar gargalo a ponto de "blocked sem PR" custar throughput — nesse caso a entrega que reabrir é dona do script + spec.
D2 — Onde vivem os 4 triggers, non-triggers e a ladder.
Opções: A (copiados nas duas skills) | B (mecânica no execution-pipeline.md; cada skill só o delta) | C (tudo em ui-design-html.md).
Recomendação: B — o pipeline é o dono já declarado da mecânica compartilhada e a própria intenção nomeia o drift como risco ("cada skill declara só o delta"); a ladder é citada de ui-design-html.md:79-83 (fonte única do artefato/tier), sem reescrever slugs.
Rejeitadas: A — twin que a intenção proíbe (:102) e a rule engineering-standards.mdc:50 condena; C — a doutrina de design não é o lugar das fases de execução do work-issue.
D3 — Detecção do trigger (a) (superfície/estado novo).
Opções: A (só no impl plan) | B (só na execução) | C (os dois — o plan antecipa, a execução não improvisa).
Recomendação: C — fecha o vão do "improviso no meio do código" sem transformar o plan num inventário exaustivo de UI.
Rejeitadas: A — deixa passar superfície que só aparece ao mexer no markup; B — o plan já conhece as superfícies (o gate aprovou o ui-design.html).
D4 — Formato do sub-agente Designer nas duas skills.
Opções: A (inline/transcrição das regras) | B (dispatch por referência).
Recomendação: B — cada skill declara só Quando/Input/Task/Output apontando .opencode/agent/designer.md, .opencode/agent/designer-degraded.md e ui-design-html.md (mesmo padrão já usado por plan-issue/SKILL.md:56-58); a mecânica de dispatch fica no pipeline (D2).
Rejeitadas: A — duplica doutrina/teto/ladder e drifta.
D5 — Linha de ownership na rule.
Opções: A (nova seção "Design") | B (bullet vizinho de "Edit the owner, don't twin").
Recomendação: B — a intenção pede exatamente "vizinha de :50"; uma seção nova para uma linha é cerimônia.
Rejeitadas: A.
D6 — Pin de teste das novas literais (DEGRADED, triggers).
Opções: A (spec unit novo em tests/) | B (nenhum; a asserção vira walkthrough/greps no PR).
Recomendação: B — mantém o diff em docs/skills/regras conforme a Verificação; o skillsAutoFlag já pina os hard-stops existentes e serve de guard contra regressão do --auto.
Rejeitadas: A — um spec para um fluxo sem código é o "teste de prosa" que o appetite não paga; revisitar se a skill drifar sem CI pegar.
Fases verificáveis
- Ownership — quota ~0,1 dia.
.agents/rules/engineering-standards.mdc: bullet após "Edit the owner, don't twin" (estrutura visual é dodesigner; o implementador porta).- Verificação:
grep -n "Visual structure belongs" .agents/rules/engineering-standards.mdcretorna 1 linha na seção Module organization.
- Mecânica + deltas — quota ~0,4 dia.
execution-pipeline.md: seção## Design …com triggers (a)–(d), non-triggers,DEGRADED, referência à ladder;## Executaritem 2 e## Deltas por atoratualizados.work-issue/SKILL.mdeagent-work-issue/SKILL.md: sub-agente Designer + checklist + ponteiros.engineering-brief.md: linha opcional na tabela.- Verificação:
grep -nE "\(a\) Superfície|\(b\) O design aprovado|\(c\) No fechamento|\(d\) Ícones" .agents/skills/work-issue/execution-pipeline.md(4 hits) egrep -nE "designer\.md|designer-degraded\.md|ui-design-html\.md" .agents/skills/work-issue/SKILL.md .agents/skills/agent-work-issue/SKILL.md(≥1 em cada).
- Fail-closed — quota ~0,2 dia.
execution-pipeline.md: passo de tier/certificação no## Fechar em main+ delta por ator.work-issue/SKILL.md: hard-stopDEGRADEDno--auto+ fechamento B no Passo 7.agent-work-issue/SKILL.md: fechamento C no Passo 6.- Verificação:
grep -rn "DEGRADED" .agents/skills/work-issue/SKILL.md .agents/skills/agent-work-issue/SKILL.md .agents/skills/work-issue/execution-pipeline.md(≥3 arquivos) egrep -n "Design tier:" .agents/skills/work-issue/execution-pipeline.md.
- Gates + walkthrough — quota ~0,1 dia.
pnpm gate:fastverde;pnpm exec vitest run --config vitest.unit.config.mts tests/unit/skillsAutoFlag.unit.spec.tsverde (literais do--autopreservados); walkthrough estático no body do PR.
Walkthrough estático (item UI fictício) — onde cada fluxo exige o designer. Item hipotético "OPS999 — painel de cobertura de meta por município":
- Plan-time (checklist 3d): o impl plan identifica uma superfície de estado nova (empty/erro) fora do
ops999-ui-design.htmlaprovado ⇒ trigger (a) ⇒ dispatch dodesignerantes de qualquersrc/; se o frontier estiver sem quota, dispatchdesigner-degraded⇒ artefato marcadoDEGRADED. - Execução (Passo 4): o implementador porta classe-a-classe; se o aprovado não pode ser seguido como está ⇒ trigger (b) ⇒ o
designerpropõe a adaptação (o implementador não improvisa estrutura visual); ícones/ilustrações ⇒ trigger (d). - Fechamento (Passo 7): o diff muda UI ⇒ trigger (c) ⇒ crítica do
designercontra o app renderizado (screenshots 390/1280 + estados).- Tier primário certifica ⇒ PR Ready com
Design tier: openai/gpt-5.6-sole auto-merge normal. DEGRADED/sem tier primário +work-issue(sem--auto) ⇒ para antes dopnpm push, apresenta críticaDEGRADED+ screenshots, aguarda sign-off humano; só então abre o PR Ready comDesign tier: DEGRADED (opencode-go/deepseek-v4.1-flash)+ registro do sign-off no body.DEGRADED/sem tier primário +agent-work-issueouwork-issue --auto⇒ sem PR, comentário na Issue + flipblocked.
- Tier primário certifica ⇒ PR Ready com
- Non-trigger: fiação de dados no markup aprovado, hooks/rotas/queries, copy, port mecânico, bug que restaura o aprovado, reuso de tokens ⇒ segue com o implementador, sem dispatch.
Rabbit holes / Não escopo (engenharia)
- Mecanismo de veto de plataforma (flag
--draft, branch prefix novo, disarm script) — D1, rejeitado por appetite/Verificação. - Spec unit novo pinando prosa — D6, rejeitado; revisitar sob drift.
- Criar/ajustar o agente
designerou o formato do.html(OPS113/OPS114, já no repo). - Reescrever a
/impeccableou criar segunda skill de crítica. - Pinar
model:nos commands; religar o pool supervisor (OPS65). - Migrar/editar planos existentes; tocar
src/, migration, schema, access ou UI de produto. - Replicar ladder/
DEGRADED/Design tier:emAGENT-OPS.mdouui-design-html.md(já são donos).
Riscos e mitigação
- Quebrar os pins do
--auto:tests/unit/skillsAutoFlag.unit.spec.tspinaConsent/LGPD,migração de schema,URL público,produção,aprovado,nunca claima,blocked. Mitigação: adicionar o hard-stop deDEGRADEDsem remover/reescrever esses literais; rodar o spec na fase 4. - Pulo silencioso do design (pior caso): ladder explícita +
DEGRADED+Design tier:no PR + default "superfície nova ⇒ despacha"; nunca inferir "não precisava". DEGRADEDfechar por auto-merge: nowork-issuenão há push antes do sign-off; no autônomo não há PR (comentário +blocked) — logo o safety net nunca vê um PRDEGRADEDsem humano.- Cerimônia em item não-visual: non-triggers listados e default "não despachar"; o trigger (a) exige nomear a superfície nova.
- Bloat/drift das skills: mecânica no pipeline; skills só citam; ladder referenciada de
ui-design-html.md. - Referência a agente inexistente: confirmado
.opencode/agent/designer.md(mode: all) edesigner-degraded.md(mode: subagent) no repo; dispatch por nome, sem pin de modelo em command (OPS101). - Interação com
agent-work-issueCloud (:81,:97): o delta C substitui "ManagePullRequestcomdraft: false" por "sem PR" quando não há certificação; registrar no texto para não deixar ambiguidade.
Débitos da triagem pós-simplify (2026-09-16)
- Já resolvido no simplify (não reabrir): S1 (contradição
--auto+DEGRADED), S2 (AGENT-OPS.mdliteral do autônomo), S3 (escopo do trigger (c) vs non-triggers), S4/Q7 (§Ladder), Q1/Q2 (grep da Verificação), Q3 (ponteiros de linha do plano), Q4 (checklist 3d), Q5 (ManagePullRequestincondicional), Q6 (parêntese do hard-stop). - Descartados: S5 — a posição do bullet de ownership é a pedida pela intenção (D5) e o conteúdo é ownership; Q8 — a redundância "sem tier primário não certifica" nas 3 superfícies é o contrato do pipeline (cada skill declara só o delta).
- Registrado/defer: nenhum — sem
expensive_lockscore ≥4 pendente; o único de peso (S1) está no diff. Issue #1058 intocada.
Aceite de engenharia
- Aceite de produto da intenção ainda coberto: triggers (a)–(d) e non-triggers presentes; ladder referenciada;
DEGRADED+ sign-off;Design tier:no PR; ownership na rule;/impeccablecitada sem duplicação. - Invariantes AGENTS/engineering-standards: "Edit the owner, don't twin" respeitado (mecânica no pipeline, deltas nas skills); sem
src/, sem migration, sem access/Consent, sem UI de produto;model:não pinado. - Testes de domínio previstos (unit/int): nenhum novo write path/access ⇒ sem novos specs;
tests/unit/skillsAutoFlag.unit.spec.tsverde (pins do--autopreservados). pnpm gate:fastverde; diff só em.agents/(e docs, se o brief/AGENT-OPS exigirem).- Walkthrough do item UI fictício no body do PR, incluindo a degradação simulada (
DEGRADED→ humano nowork-issue;blockedno autônomo).
Self-score decision-quality: 5/5 — (1) decisões caras (D1–D3) têm rejeitadas explícitas; (2) abordagem doc-only cabe no appetite e na Verificação; (3) rabbit holes nomeados; (4) depth check: reusa donos existentes (execution-pipeline.md, engineering-standards.mdc, precedente de blocked da divergência material no agent-work-issue, hard-stop do --auto no work-issue, agente designer e doutrina ui-design-html.md); (5) o outcome de produto da intenção permanece intacto — a engenharia só escolhe o mecanismo do fail-closed, sem reescrevê-lo.