From d8126fc8bb2057c633b8637fff41a5815056e5dd Mon Sep 17 00:00:00 2001 From: Francisco Solla Date: Wed, 16 Sep 2026 00:59:18 -0300 Subject: [PATCH] =?UTF-8?q?docs(OPS115):=20designer=20em=20qualquer=20toqu?= =?UTF-8?q?e=20de=20design=20+=20cr=C3=ADtica=20visual=20fail-closed=20nas?= =?UTF-8?q?=20skills=20(Closes=20#1058)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .agents/rules/engineering-standards.mdc | 1 + .agents/skills/agent-work-issue/SKILL.md | 13 +- .agents/skills/work-issue/SKILL.md | 20 ++- .../skills/work-issue/engineering-brief.md | 1 + .../skills/work-issue/execution-pipeline.md | 52 +++++- docs/AGENT-OPS.md | 2 +- docs/changelog/2026-09-16-ops115.md | 1 + ...k-issue-designer-em-qualquer-toque-impl.md | 153 ++++++++++++++++++ 8 files changed, 229 insertions(+), 14 deletions(-) create mode 100644 docs/changelog/2026-09-16-ops115.md create mode 100644 docs/plans/ops115-work-issue-designer-em-qualquer-toque-impl.md diff --git a/.agents/rules/engineering-standards.mdc b/.agents/rules/engineering-standards.mdc index 9d8de906..244b757c 100644 --- a/.agents/rules/engineering-standards.mdc +++ b/.agents/rules/engineering-standards.mdc @@ -48,4 +48,5 @@ Established 2026-07-23 by the engineering-standards hardening (tracker: `docs/IM - `src/lib/` = pure logic and static data (client-safe unless marked). `src/utilities/` = Payload/Next-coupled server code (mark `server-only` when server-bound). React components never live in `utilities/`. - Follow the domain prefixes (`campaign*`, `municipality*`, `supporter*`, `actionPlan*`); the access domain has a real folder (`utilities/access/`). - **Edit the owner, don't twin.** New behavior lands in the module that already owns that concern (`CampaignTable`, list URL helpers, form-action wrappers, portfolio/relation cells, access helpers, …). A parallel file that reimplements the same machine is a defect unless the delivery names a deliberate policy fork. Prefer changing existing code over adding beside it; delete what your change supersedes in the same delivery (see "Dead code dies immediately"). Product constraints in `AGENTS.md` and frozen migration files are not a ban on editing application code. +- **Visual structure belongs to the `designer`.** Deciding layout, hierarchy, states and visual tokens is the `designer`'s call (`.opencode/agent/designer.md`; doctrine `.agents/skills/plan-issue/ui-design-html.md`); the implementer ports the approved artifact (`docs/plans/-ui-design.html`) to markup and wires data/routes/queries/copy. A diff that changes visual structure without the designer's verdict is a defect (data/copy wiring on the approved markup is a non-trigger) — the triggers, non-triggers and fail-closed closure live in `execution-pipeline.md` (§Design). This is ownership, not a new module: change the owner, don't improvise the visual structure in code. - **Reuse vs premature abstraction.** Prefer extending the existing owner. Do **not** invent a new shared abstraction for a speculative third use. If you are about to copy an existing path and the knowledge is the same, **edit the owner** (or extract in the same delivery) — waiting for "call site #3" is how twins spawn. Defer only true look-alikes that differ in policy, with an explicit revisit trigger. Named policy wrappers (`runCampaignRedirectFormAction`, `runStaffEntityMutation`) stay justified even at few call sites. diff --git a/.agents/skills/agent-work-issue/SKILL.md b/.agents/skills/agent-work-issue/SKILL.md index a0b917b7..7124b3ee 100644 --- a/.agents/skills/agent-work-issue/SKILL.md +++ b/.agents/skills/agent-work-issue/SKILL.md @@ -27,6 +27,7 @@ Mesmo padrão de `work-issue` — sub-agentes para fases pesadas: - **Explorador** (código) → findings - **Escritor** (impl plan) → plano +- **Designer** (triggers a/b/d antes de implementar; c no fechamento) → artefato estendido ou crítica; dono da estrutura visual (`designer.md`/`designer-degraded.md`, doutrina `ui-design-html.md`) — ver §Design do pipeline - **2 Revisores** (paralelo: estrutural + qualidade) → achados do simplify - **Capturador** (débitos) → tabela de triage @@ -35,11 +36,11 @@ Mesmo padrão de `work-issue` — sub-agentes para fases pesadas: ``` - [ ] 0. Prep: `pnpm i` se preciso; Cloud → §Prep Cloud (sem Docker) - [ ] 1. Sessão: rename_chat + open_resource + carregar camada AGENTS -- [ ] 2. Plan mode → dispatch explorador + escritor → impl plan -- [ ] 3. Executar (main agent iterativo) +- [ ] 2. Plan mode → dispatch explorador + escritor → impl plan; `designer` (trigger a/b) se o design aprovado não cobrir a superfície +- [ ] 3. Executar (main agent iterativo) — `designer` nos triggers (a/b/d) - [ ] 4. Dispatch 2 revisores paralelos → simplify - [ ] 5. Dispatch capturador → triage de débitos -- [ ] 6. PR Ready + auto-merge +- [ ] 6. PR Ready + auto-merge — crítica do `designer` (c); `DEGRADED` ⇒ sem PR (comenta Issue + `blocked`) ``` ## Passo 0 — Prep @@ -76,9 +77,9 @@ Siga `execution-pipeline.md` com deltas do pool: - **Branch:** `agent/-` (worktrees Cursor podem já ter criado). - **E2E local afetado (OPS72):** discricionário (Cloud sem browsers → registre justificativa). -- **UI:** shape → craft → critique → polish. +- **UI:** §Design do pipeline — o `designer` é dono da estrutura visual; dispare nos triggers (a/b/d) e porte o artefato aprovado classe-a-classe (nunca improvise estrutura visual). - **`capture-review-debts`:** autônomo — só `expensive_lock` com score ≥4; resto → defer/descarte. -- **Cloud:** PR via `ManagePullRequest` com `draft: false` no GitHub. +- **Cloud:** PR via `ManagePullRequest` com `draft: false` no GitHub (salvo `DEGRADED`: sem PR — ver Passo 6). ## Passo 4 — Simplify (2 sub-agentes paralelos) @@ -96,6 +97,8 @@ Dispatche capturador com achados + regras de `capture-review-debts`. Receba tria PR Ready `--base main` (GitHub) + auto-merge nativo — `pnpm push -u origin HEAD` → `node scripts/github-pr.mjs` (ou `ManagePullRequest` `draft: false` no Cloud). +Antes do PR, se o diff muda UI, a crítica final do `designer` (trigger c) é obrigatória (§Design) e `Design tier: ` vai no body. Sem tier primário (`DEGRADED`) **não há certificação** — exceção explícita ao contrato "PR Ready + auto-merge": **não abra PR**; comente o resultado na Issue (crítica `DEGRADED` + screenshots + `Design tier: DEGRADED ()`) e flip para `blocked`; o humano decide. `DEGRADED` nunca vira "segue sem". + ## Resumo final Issue · impl plan · simplify + débitos · PR + merge. diff --git a/.agents/skills/work-issue/SKILL.md b/.agents/skills/work-issue/SKILL.md index 01643a8b..bbbe63bc 100644 --- a/.agents/skills/work-issue/SKILL.md +++ b/.agents/skills/work-issue/SKILL.md @@ -28,6 +28,15 @@ Fases pesadas são delegadas a sub-agentes com contexto mínimo. O agente princi **Task:** Escrever `docs/plans/-impl.md` conforme o template. Incluir: abordagem recomendada + alternativas rejeitadas + fases + riscos. Self-score decision-quality ≥4/5. **Output:** conteúdo markdown do plano. +### Sub-agente: Designer + +**Quando:** trigger (a) — superfície/estado visual novo que o design do plano não cobre e trigger (b) — design aprovado não pode ser seguido como está, ambos **antes** de o implementador mexer no markup; trigger (d) — ícones/ilustrações; e trigger (c) — no fechamento, crítica visual do diff que muda UI contra o app renderizado (screenshots 390/1280 + estados). +**Input:** plano de intenção + artefato aprovado `docs/plans/-ui-design.html` + o app renderizado (screenshots). +**Task:** criar/estender o artefato (a/b/d) ou criticar a implementação contra ele (c). Dono da estrutura visual: `.opencode/agent/designer.md` (fallback `designer-degraded.md`), doutrina `ui-design-html.md`. **Não implementa a feature nem decide engenharia.** +**Output:** artefato estendido ou lista numerada de ajustes; `DEGRADED` + sign-off humano quando o tier não for primário. + +Triggers/non-triggers, ladder e o fechamento fail-closed vivem em `execution-pipeline.md` (§Design) — esta skill declara só o delta. + ### Sub-agente: Revisor estrutural **Quando:** Passo 5, reviewer 1 (paralelo). @@ -69,10 +78,11 @@ Fases pesadas são delegadas a sub-agentes com contexto mínimo. O agente princi - [ ] 3a. Dispatch sub-agente explorador → receber findings - [ ] 3b. Dispatch sub-agente escritor → receber impl plan - [ ] 3c. GATE humano: apresentar plano → pausa → confirmação -- [ ] 4. Executar (main agent iterativo) +- [ ] 3d. Designer (trigger a/b): estender o artefato se o design aprovado não cobrir a superfície +- [ ] 4. Executar (main agent iterativo) — `designer` nos triggers (a/b/d) - [ ] 5. Dispatch 2 sub-agentes revisores (paralelo) → receber achados - [ ] 6. Dispatch sub-agente capturador → receber triage -- [ ] 7. PR → merge +- [ ] 7. PR → merge — crítica do `designer` (c); `DEGRADED` ⇒ sign-off humano antes do push ``` ## Passo 1 — Contexto da sessão @@ -140,7 +150,7 @@ Opt-out da pausa por invocação. Detecta-se em `$ARGUMENTS`: `/work-issue --iss - **Sem a flag (ou flag desconhecida):** o Passo 3c GATE vale idêntico — apresente o plano, pare e aguarde confirmação explícita. Proibido pular a pausa. - **Com a flag:** o impl plan do Passo 3b nasce marcado `aprovado` pelo próprio agente; o Passo 3c vira apresentação-no-chat-sem-espera (abordagem + rejeitadas + fases + riscos continuam obrigatórios no chat e no arquivo) e a execução (Passo 4) segue direto até o PR. - **Pode auto-aprovar:** abordagem técnica, cortes de escopo já previstos na skill e os literais de dados que o próprio plano recomenda (registrados como assumidos). -- **Continua parando (vale mesmo com a flag):** Consent/LGPD fail-closed, migração de schema, contrato de URL público, shapes públicos, produção/aprovação humana, merge sem CI green, DB de prod; divergência material de produto → pare, comente na Issue e flipe para `blocked` (precedente do fluxo autônomo). O claim continua contrato do ambiente: este modo nunca claima Issue. +- **Continua parando (vale mesmo com a flag):** Consent/LGPD fail-closed, migração de schema, contrato de URL público, shapes públicos, produção/aprovação humana, certificação visual `DEGRADED` (tier não-primário não certifica — o fluxo `--auto` para e flipa para `blocked`), merge sem CI green, DB de prod; divergência material de produto → pare, comente na Issue e flipe para `blocked` (precedente do fluxo autônomo). O claim continua contrato do ambiente: este modo nunca claima Issue. - **Não confundir:** `--auto` aqui é flag da skill dentro do prompt; o `--auto` do CLI opencode (auto-aprovar permissões de ferramenta) é outro conceito. - **Convivência:** `agent-work-issue` continua sendo o contrato do pool dormente; este modo é opt-in da sessão humana. Consolidação futura é item à parte. @@ -151,7 +161,7 @@ Opt-out da pausa por invocação. Detecta-se em `$ARGUMENTS`: `/work-issue --iss - **Branch:** `-` do worktree — nunca crie branch nova. - **Nível de teste:** unit → int → e2e-com-benefício (dono da definição: `test-driven-development`; ver pipeline). - **E2E local afetado (OPS72):** discricionário — rode os e2e criados + mesma superfície. -- **UI:** shape → craft → critique → polish. +- **UI:** §Design do pipeline — o `designer` é dono da estrutura visual; dispare nos triggers (a/b/d) e porte o artefato aprovado classe-a-classe (nunca improvise estrutura visual). - **Gates:** `pnpm gate:fast` na iteração; entrega com `pnpm push`. ## Passo 5 — Simplify (2 sub-agentes paralelos) @@ -170,6 +180,8 @@ Aplique: registre o aprovado, absorva em plano existente, defira com gatilho, de Siga `execution-pipeline.md`: changelog → `pnpm push` → PR no GitHub `--base main` com `Closes #N` → auto-merge → CI. +Antes do push, se o diff muda UI, a crítica final do `designer` (trigger c) é obrigatória (§Design). Com crítica certificada, registre `Design tier: ` no body. Com `DEGRADED`/tier não-primário, **pare antes do `pnpm push`**, apresente a crítica `DEGRADED` + screenshots e aguarde sign-off humano explícito; só então o PR nasce Ready com `Design tier: DEGRADED ()` + o registro do sign-off — nunca "segue sem". + ## Resumo final Issue · impl plan · simplify + débitos · PR + merge. diff --git a/.agents/skills/work-issue/engineering-brief.md b/.agents/skills/work-issue/engineering-brief.md index 4e09b0a7..cf3e43e6 100644 --- a/.agents/skills/work-issue/engineering-brief.md +++ b/.agents/skills/work-issue/engineering-brief.md @@ -12,6 +12,7 @@ Leia o que for relevante **antes** de travar a abordagem no `*-impl.md`. Não in | Schema Payload | skill `payload-migrations` | | DB local / Cloud sem Docker | skill `local-database` | | KPI/mapa/série na UI | [data-presentation.md](../plan-issue/data-presentation.md) pergunta 3 no impl | +| Item que muda UI (estrutura visual) | agente `designer` (`designer.md`/`designer-degraded.md`) + doutrina `ui-design-html.md`; triggers e fail-closed em `execution-pipeline.md` (§Design) | | Domínio `/campanha` específico | rules `projects/*` se o item tocar aquele projeto | ## Invariantes que o impl plan não pode violar diff --git a/.agents/skills/work-issue/execution-pipeline.md b/.agents/skills/work-issue/execution-pipeline.md index 9365aa0b..62e6b8c7 100644 --- a/.agents/skills/work-issue/execution-pipeline.md +++ b/.agents/skills/work-issue/execution-pipeline.md @@ -12,8 +12,9 @@ Ordem: 1. **Schema/server** — migrations (`payload-migrations`), utilities, actions, testes de domínio. Invariantes do engineering-brief. -2. **UI** — se Impeccable B/C/D: shape → craft → critique → polish. Tokens - `data-theme='campaign'`; shells existentes. +2. **UI** — se Impeccable B/C/D: a estrutura visual é do `designer` (§Design); + porte o artefato aprovado classe-a-classe. Tokens `data-theme='campaign'`; + shells existentes. 3. **E2E local afetado (OPS72, discricionário)** — antes do push, rode localmente os e2e que você **criou** + os da **mesma superfície afetada** (você decide quais). Ver §E2E local afetado. @@ -56,6 +57,49 @@ antes do deploy**. famílias rodam em paralelo) e os runs selecionados filtram por arquivo — quase sempre uma família — então o seed não colide. +## Design (triggers, non-triggers, crítica final) + +Item que **muda UI** (Impeccable B/C/D) tem dono visual: o agente `designer` +(`.opencode/agent/designer.md`), com a doutrina `.agents/skills/plan-issue/ui-design-html.md` +como fonte única do artefato `docs/plans/-ui-design.html` +(+ `-ui-design-assets/*.svg`). O implementador porta o design aprovado +classe-a-classe; **nunca improvisa estrutura visual** (data/routes/queries/copy +seguem com ele). + +**Triggers (dispatch do `designer`) — a lista fechada da intenção:** + +- **(a) Superfície/estado visual novo** que o design do plano não cobre → o + `designer` **estende o artefato antes** de o implementador mexer no markup. + Detectado no impl plan (que lista as superfícies) **e** na execução + (superfície que só aparece no código) — nunca inferir "não precisava". +- **(b) O design aprovado não pode ser seguido como está** → o `designer` + propõe a adaptação; o implementador não decide a estrutura. +- **(c) No fechamento, todo diff que muda a estrutura visual** → crítica do + `designer` contra o app **renderizado** (screenshots 390/1280 + estados + críticos). Os non-triggers abaixo **não** acionam (c). +- **(d) Ícones/ilustrações** próprios → saem do `designer` (SVG na doutrina). + +**Non-triggers (segue com o implementador, sem dispatch):** fiação de +dados/lógica no markup aprovado, hooks/rotas/queries, copy, port mecânico de +seção aprovada, bug que restaura o design aprovado, reuso de +tokens/componentes já especificados. O default é **não despachar**. + +**Crítica final (fail-closed).** Sem tier primário **não há certificação**. A +ladder e a regra do `DEGRADED` são as de `ui-design-html.md` — a +indisponibilidade **desce o tier** e registra `Design tier: ` no PR; +nunca pula o design em silêncio. Tier degradado marca `DEGRADED` no artefato e +no PR e **não certifica**: para em sign-off humano. + +- **`work-issue` (humano presente, sem `--auto`):** com crítica certificada, + registre `Design tier:` no PR e siga. Com `DEGRADED`/tier não-primário, + **pare antes do `pnpm push`** — apresente a crítica `DEGRADED` + screenshots + e aguarde sign-off explícito; só então o PR nasce Ready com + `Design tier: DEGRADED ()` + o registro do sign-off no body. +- **`agent-work-issue` (autônomo) e `work-issue --auto`:** não há humano para o + sign-off ⇒ **não abra PR**; comente o resultado na Issue e flip para + `blocked` (mesmo precedente da divergência material). `DEGRADED` nunca vira + "segue sem". + ## /simplify + débitos 1. Rode o comando `/simplify` completo (2 reviewers paralelos via Task — @@ -88,5 +132,5 @@ antes do deploy**. | Ator | Branch | UI | `capture-review-debts` | Cloud | | ---- | ------ | --- | ---------------------- | ----- | -| **Humano** (`work-issue`) | `-` (worktree; nunca crie branch nova na sessão) | shape → craft → critique → polish | **autônomo** — decide o destino dos achados (registrar/absorver/deferir/descartar) pela triage da skill; sem pausa para o humano | n/a (máquina do humano) | -| **Pool** (`agent-work-issue`) | `agent/-` (worktrees Cursor podem já ter criado) | shape → craft → critique → polish (harden/optimize só sob gatilho) | **autônomo** — só `expensive_lock` com score ≥4 (Issues novas com `depends`); score ≤3 / cheap_polish / defer_trigger → defer no `*-impl.md` ou descarte | `ManagePullRequest` com `draft: false`; Prep Cloud no Passo 0 | +| **Humano** (`work-issue`) | `-` (worktree; nunca crie branch nova na sessão) | §Design — `designer` nos triggers (a/b/d) e crítica final (c); port classe-a-classe; `DEGRADED` ⇒ para antes do push (sign-off humano) | **autônomo** — decide o destino dos achados (registrar/absorver/deferir/descartar) pela triage da skill; sem pausa para o humano | n/a (máquina do humano) | +| **Pool** (`agent-work-issue`) | `agent/-` (worktrees Cursor podem já ter criado) | §Design — `designer` nos triggers (a/b/d) e crítica final (c); port classe-a-classe; `DEGRADED` ⇒ sem PR (comenta Issue + `blocked`) | **autônomo** — só `expensive_lock` com score ≥4 (Issues novas com `depends`); score ≤3 / cheap_polish / defer_trigger → defer no `*-impl.md` ou descarte | `ManagePullRequest` com `draft: false` (salvo `DEGRADED` ⇒ sem PR); Prep Cloud no Passo 0 | diff --git a/docs/AGENT-OPS.md b/docs/AGENT-OPS.md index 2eed8a7b..1bf56bdc 100644 --- a/docs/AGENT-OPS.md +++ b/docs/AGENT-OPS.md @@ -21,7 +21,7 @@ main → push dispara deploy.yml sozinho (ou workflow_dispatch manual) → prefl **Skills:** `plan-issue` (intenção + Issues) → `work-issue` (humano: Issue já claimada → impl plan → confirmação → execução) ou `agent-work-issue` (pool: já claimada → impl plan → execução sem pausa) → `/simplify` → `capture-review-debts` → PR `--base main` (GitHub) → `project-status`. `docs/roadmap.md` = legado congelado; fonte canônica = Issues do GitHub (`github.com/fsolla/teqo/issues`). -**Design hi-fi (OPS113):** item que muda UI passa pelo agente `designer` (`model: openai/gpt-5.6-sol`; crítica contestada/pixel-critical em `openai/gpt-6-astra`, mesmo agente via `/models`); a doutrina `.agents/skills/plan-issue/ui-design-html.md` é a fonte única do artefato `docs/plans/-ui-design.html` (+ `-ui-design-assets/*.svg`), que é a fonte de verdade do port — o implementador porta classe-a-classe. Indisponibilidade/quota desce a ladder — `opencode-go/deepseek-v4.1-flash` (agente `designer-degraded`) → `deepseek/deepseek-flash` (inline pelo orquestrador) — sempre gravando o tier no PR (`Design tier:`); tier degradado marca `DEGRADED`, não certifica e para em sign-off humano (triggers no work-issue: OPS115). Ambos têm `permission` fail-closed: `edit` negado fora de `docs/plans/*-ui-design*` e `bash` com os **vetores de escrita enumerados** negados (redirecionamento, `sed -i`, `tee`, shells/interpretadores — OPS117), preservando leitura e o `prettier --write` do artefato; o resto do shell fica em `ask` (o guard cobre os vetores, não é sandbox de SO). +**Design hi-fi (OPS113):** item que muda UI passa pelo agente `designer` (`model: openai/gpt-5.6-sol`; crítica contestada/pixel-critical em `openai/gpt-6-astra`, mesmo agente via `/models`); a doutrina `.agents/skills/plan-issue/ui-design-html.md` é a fonte única do artefato `docs/plans/-ui-design.html` (+ `-ui-design-assets/*.svg`), que é a fonte de verdade do port — o implementador porta classe-a-classe. Indisponibilidade/quota desce a ladder — `opencode-go/deepseek-v4.1-flash` (agente `designer-degraded`) → `deepseek/deepseek-flash` (inline pelo orquestrador) — sempre gravando o tier no PR (`Design tier:`) — ou na Issue, no fluxo autônomo sem tier primário, que não abre PR e flipa para `blocked`; tier degradado marca `DEGRADED`, não certifica e para em sign-off humano (triggers no `work-issue`/`agent-work-issue`: OPS115). Ambos têm `permission` fail-closed: `edit` negado fora de `docs/plans/*-ui-design*` e `bash` com os **vetores de escrita enumerados** negados (redirecionamento, `sed -i`, `tee`, shells/interpretadores — OPS117), preservando leitura e o `prettier --write` do artefato; o resto do shell fica em `ask` (o guard cobre os vetores, não é sandbox de SO). - **Agente faz sozinho:** claim (pool-supervisor no pool; humano via `pnpm agent:claim` fora da sessão — OPS33: `worktree next` claima) → implementa → **e2e local afetado** (OPS72, discricionário: roda os e2e que criou + os da mesma superfície — `pnpm test:e2e:affected`; ver skill) → **`pnpm push`** (origin = GitHub) → PR via `node scripts/github-pr.mjs` **Ready** (nunca draft) com `Closes #N` → o safety net `agent-pr-ready-automerge.yml` arma o **auto-merge nativo do GitHub** (`enablePullRequestAutoMerge`, rebase) — o servidor mergea quando o required check `CI (PR) / checks` fica verde. Regra always-on: `.agents/rules/agent-pr-workflow.mdc`. Em Cursor Cloud: `ManagePullRequest` com `draft: false` (o default draft da tool **não** vale neste repo) — o merge continua pelo safety net. - **Só humano:** aprovar o environment `production` no run (o único gate de publicação — OPS104 nunca auto-aprova; OPS107: aprove só o run escolhido e rejeite os demais — runs não aprovados não publicam nada), envs de produção no homeserver (`~/stack/teqo-1313.env`, fora do repo — o deploy as lê via BuildKit secrets), `GITHUB_TOKEN` local (PAT) para os scripts GitHub, secrets no repo GitHub, `pnpm configure:branch-protection` (idempotente; reaplicar se o drift voltar), runbook manual/rollback (`docs/ops/teqo-1313-deploy.md`). diff --git a/docs/changelog/2026-09-16-ops115.md b/docs/changelog/2026-09-16-ops115.md new file mode 100644 index 00000000..3308242d --- /dev/null +++ b/docs/changelog/2026-09-16-ops115.md @@ -0,0 +1 @@ +**OPS115 — work-issue/agent-work-issue: designer em qualquer toque de design + crítica visual fail-closed (2026-09-16):** qualquer toque de design nas duas skills de execução passa pelo agente `designer` e todo diff que muda estrutura visual só é certificado com crítica contra o app renderizado (screenshots 390/1280 + estados). `execution-pipeline.md` (dono da mecânica compartilhada) ganha a seção `## Design` com os 4 triggers (a superfície/estado novo que o design do plano não cobre — o designer estende o artefato ANTES de implementar; b — o aprovado não pode ser seguido como está; c — crítica final do diff; d — ícones/ilustrações), os non-triggers que seguem com o implementador (fiação de dados, hooks/rotas/queries, copy, port mecânico, bug que restaura o aprovado, reuso de tokens; default é não despachar) e o fechamento fail-closed: sem tier primário não há certificação — `work-issue` para antes do `pnpm push` e aguarda sign-off humano (só então o PR nasce Ready com `Design tier: DEGRADED`), enquanto o fluxo autônomo (`agent-work-issue` e `work-issue --auto`) **não abre PR**: comenta a Issue + flip `blocked` (ladder/`DEGRADED` citados de `ui-design-html.md`, fonte única, sem duplicar slugs). As duas skills declaram só o delta (sub-agente Designer + checklist + ponteiros de fechamento); `engineering-standards.mdc` ganha o bullet de ownership "Visual structure belongs to the `designer`" vizinho de "Edit the owner, don't twin"; `engineering-brief.md` e `docs/AGENT-OPS.md` ganham o ponteiro. Diff doc-only (`.agents/` + docs), sem `src/`/migration/schema; `pnpm gate:fast` verde e os literais pinados do `--auto` (`tests/unit/skillsAutoFlag.unit.spec.ts`) preservados. diff --git a/docs/plans/ops115-work-issue-designer-em-qualquer-toque-impl.md b/docs/plans/ops115-work-issue-designer-em-qualquer-toque-impl.md new file mode 100644 index 00000000..a1fd578c --- /dev/null +++ b/docs/plans/ops115-work-issue-designer-em-qualquer-toque-impl.md @@ -0,0 +1,153 @@ +# 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 do `designer` contra o app renderizado (screenshots 390/1280 + estados); sem tier primário não há certificação — o item desce para `DEGRADED` e 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); `/impeccable` e a doutrina `ui-design-html.md` referenciadas, nunca duplicadas; `model:` proibido nos commands (OPS101); pool dormente (OPS65); artefato `docs/plans/-ui-design.html` continua 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:24` já cita a OPS115 — conferir que a referência não vira twin. + +## Abordagem recomendada + +```mermaid +flowchart LR + A["Item toca UI (B/C/D)"] --> B{"Superfície/estado coberto
pelo design aprovado?"} + B -- não --> C["Trigger (a): designer estende
o artefato ANTES de implementar"] + B -- sim --> D["Implementador porta
classe-a-classe"] + C --> D + D --> E{"Design aprovado pode
ser seguido como está?"} + E -- não --> F["Trigger (b): designer propõe a adaptação
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
390/1280 + estados"] + H --> I{"Tier do designer"} + I -- primário --> J["Certifica → PR Ready
Design tier: slug primário"] + I -- degradado --> K["DEGRADED + screenshots"] + K -- "work-issue" --> L["Para ANTES do push
sign-off humano no chat"] + L --> M["Após sign-off → PR Ready
Design tier: DEGRADED + registro"] + K -- "agent-work-issue / --auto" --> N["Comenta Issue
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 regra `DEGRADED` e a **referência** à ladder de `ui-design-html.md` (sem repetir slugs por ator); item 2 de `## Executar` passa a apontar para ela; `## Fechar em main` ganha o passo de tier/certificação; `## Deltas por ator` deixa 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 `--auto` ganha a certificação visual `DEGRADED` **preservando 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 quando `DEGRADED`). +- **`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 + flip `blocked` (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 é do `designer` e o implementador só porta. +- **`engineering-brief.md`** (`.agents/skills/work-issue/engineering-brief.md`, tabela `:5-14`): linha opcional apontando o agente `designer` (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 → polish` de 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 + +1. **Ownership** — quota ~0,1 dia. + - `.agents/rules/engineering-standards.mdc`: bullet após "Edit the owner, don't twin" (estrutura visual é do `designer`; o implementador porta). + - Verificação: `grep -n "Visual structure belongs" .agents/rules/engineering-standards.mdc` retorna 1 linha na seção Module organization. +2. **Mecânica + deltas** — quota ~0,4 dia. + - `execution-pipeline.md`: seção `## Design …` com triggers (a)–(d), non-triggers, `DEGRADED`, referência à ladder; `## Executar` item 2 e `## Deltas por ator` atualizados. + - `work-issue/SKILL.md` e `agent-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) e `grep -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). +3. **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-stop `DEGRADED` no `--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) e `grep -n "Design tier:" .agents/skills/work-issue/execution-pipeline.md`. +4. **Gates + walkthrough** — quota ~0,1 dia. + - `pnpm gate:fast` verde; `pnpm exec vitest run --config vitest.unit.config.mts tests/unit/skillsAutoFlag.unit.spec.ts` verde (literais do `--auto` preservados); 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.html` aprovado ⇒ **trigger (a)** ⇒ dispatch do `designer` **antes** de qualquer `src/`; se o frontier estiver sem quota, dispatch `designer-degraded` ⇒ artefato marcado `DEGRADED`. +- **Execução (Passo 4):** o implementador porta classe-a-classe; se o aprovado não pode ser seguido como está ⇒ **trigger (b)** ⇒ o `designer` propõ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 `designer` contra o app renderizado (screenshots 390/1280 + estados). + - Tier primário certifica ⇒ PR Ready com `Design tier: openai/gpt-5.6-sol` e auto-merge normal. + - `DEGRADED`/sem tier primário + `work-issue` (sem `--auto`) ⇒ **para antes do `pnpm push`**, apresenta crítica `DEGRADED` + screenshots, aguarda sign-off humano; só então abre o PR Ready com `Design tier: DEGRADED (opencode-go/deepseek-v4.1-flash)` + registro do sign-off no body. + - `DEGRADED`/sem tier primário + `agent-work-issue` ou `work-issue --auto` ⇒ **sem PR**, comentário na Issue + flip `blocked`. +- **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 `designer` ou o formato do `.html` (OPS113/OPS114, já no repo). +- Reescrever a `/impeccable` ou 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:` em `AGENT-OPS.md` ou `ui-design-html.md` (já são donos). + +## Riscos e mitigação + +- **Quebrar os pins do `--auto`:** `tests/unit/skillsAutoFlag.unit.spec.ts` pina `Consent/LGPD`, `migração de schema`, `URL público`, `produção`, `aprovado`, `nunca claima`, `blocked`. Mitigação: adicionar o hard-stop de `DEGRADED` sem 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". +- **`DEGRADED` fechar por auto-merge:** no `work-issue` **não há push** antes do sign-off; no autônomo **não há PR** (comentário + `blocked`) — logo o safety net nunca vê um PR `DEGRADED` sem 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`) e `designer-degraded.md` (`mode: subagent`) no repo; dispatch por nome, sem pin de modelo em command (OPS101). +- **Interação com `agent-work-issue` Cloud (`:81`, `:97`):** o delta C substitui "`ManagePullRequest` com `draft: 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.md` literal 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 (`ManagePullRequest` incondicional), 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_lock` score ≥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; `/impeccable` citada 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.ts` verde (pins do `--auto` preservados). +- [ ] `pnpm gate:fast` verde; 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 no `work-issue`; `blocked` no 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.