chore(OPS123): escopo de dispatch do designer frontier — só design de fato (Closes #1091)

O frontier designer (openai/gpt-5.6-sol, OAuth ChatGPT Plus) só roda Criar/Criticar o artefato de item que muda UI. A regra vive na doutrina ui-design-html.md §Escopo de dispatch (gate de 3 perguntas + lista fechada); plan-issue e execution-pipeline apontam para o dono; o agente recusa fora do escopo e o smoke do guard vai para o designer-degraded.
This commit is contained in:
Francisco Solla 2026-09-16 10:50:15 -03:00
parent 951c8b4b30
commit cab2daa35e
9 changed files with 96 additions and 4 deletions

View file

@ -23,7 +23,7 @@ parse (main agent)
1. **Nada no tracker antes do gate.** Antes da confirmação: proibido `pnpm agent:register`, criar Issue/PR.
2. **Register com `--plan` nasce `blocked`.** Promote só depois do plano em `main`.
3. **Planos de Issues `in-progress`/`done`/`in-prod` são imutáveis.**
4. **Design UI (obrigatório se muda UI):** o sub-agente `designer` produz o design hi-fi; o orquestrador grava `docs/plans/<slug>-ui-design.html` + `docs/plans/<slug>-ui-design-assets/*.svg` (doutrina: `ui-design-html.md`). Classe A/sem UI → sem design.
4. **Design UI (obrigatório se muda UI):** o sub-agente `designer` produz o design hi-fi; o orquestrador grava `docs/plans/<slug>-ui-design.html` + `docs/plans/<slug>-ui-design-assets/*.svg` (doutrina: `ui-design-html.md`). Classe A/sem UI → sem design. **O `designer` frontier só roda design de fato** (doutrina §Escopo de dispatch): smoke/validação de `permission`/config, visão, exploração e escrita de plano **nunca** no frontier.
## Decomposição em sub-agentes
@ -52,7 +52,7 @@ Cada fase pesada é delegada a um sub-agente com contexto mínimo. O agente prin
### Sub-agente: Designer
**Quando:** Passo 3d, paralelo (1 por ideia UI).
**Quando:** Passo 3d, **somente** ideia que muda UI (Impeccable B/C/D). Escopo e gate de dispatch são os de `ui-design-html.md` §Escopo de dispatch — o frontier não roda smoke/validação de `permission`, visão, exploração nem escrita de plano. Prefira **uma** sessão para N itens UI a N sessões frias.
**Input:** plano de intenção aprovado (B/C/D) + `ui-design-html.md` (doutrina) + `.opencode/agent/designer.md` (papel)
**Task:** Produzir o design hi-fi do item — tokens/brand reais, cenas 390/1280, estados críticos. **Não escrever código de app nem nomear componente final.**
**Output:** o design hi-fi — `docs/plans/<slug>-ui-design.html` + `docs/plans/<slug>-ui-design-assets/*.svg`; o orquestrador garante a gravação no disco.
@ -115,7 +115,7 @@ O agente principal:
1. Valida cada plano contra `shaping.md` (self-score ≥4)
2. Aplica melhorias se necessário
3. Cria os arquivos `docs/plans/<slug>.md` no disco
4. Se UI: dispatcha o sub-agente `designer` (paralelo, 1 por ideia UI) para produzir `docs/plans/<slug>-ui-design.html` + `docs/plans/<slug>-ui-design-assets/*.svg`; o orquestrador grava os arquivos no disco e preenche/valida o campo `Design UI:` + a seção do plano
4. Se UI: dispatcha o sub-agente `designer` **só para ideia que muda UI** — prefira **uma** sessão para os N itens UI a N sessões frias (`ui-design-html.md` §Escopo de dispatch) — para produzir `docs/plans/<slug>-ui-design.html` + `docs/plans/<slug>-ui-design-assets/*.svg`; o orquestrador grava os arquivos no disco e preenche/valida o campo `Design UI:` + a seção do plano
## Passo 4 — GATE

View file

@ -21,6 +21,28 @@ Mesma doutrina para os dois papéis (fonte única — os prompts dos agentes apo
- **Tier degradado:** o `designer-degraded` cria/estende/critica, mas **marca todo output `DEGRADED`** e **nunca certifica** — exige sign-off humano explícito. `DEGRADED` não é design aprovado.
- **Escrita só no artefato (file tools + bash):** os dois agentes têm `permission` fail-closed — `edit`/`write`/`patch` negados fora de `docs/plans/<slug>-ui-design*` e o **bash** nega os vetores de escrita enumerados (redirecionamento, `sed -i`, `tee`, shells/interpretadores) fora do artefato; o resto do shell fica em `ask`. Não tente contornar por shell (o guard cobre os vetores enumerados, não é sandbox de SO) — leia/inspecione à vontade (`cat`, `sed -n`, `git diff`) e grave o artefato pelas file tools.
## Escopo de dispatch — o `designer` frontier só roda design de fato
O tier frontier (`designer` com pin `openai/gpt-5.6-sol`) é **recurso escasso e caro**: ele é despachado **apenas** nos dois modos de design — **Criar** ou **Criticar** o artefato — e **apenas** para item que **muda UI**. Todo trabalho que não é isso roda no **modelo padrão da sessão**, nunca no frontier.
**Lista fechada do que NUNCA vai para o `designer` frontier:**
- smoke/validação de `permission`, guard de escrita, frontmatter, `model:` ou config de agente — **a semântica de `permission` é do frontmatter, não do modelo**: valide estaticamente, ou rode o smoke com o `designer-degraded` (barato); o resultado do guard é o mesmo;
- teste de visão/sanidade de imagem ("qual a cor dominante") — use o modelo padrão da sessão, que tem visão;
- exploração de código (`@explore`), review geral (`@general`), `@solla-comunicacao`;
- escrever/revisar plano de intenção, impl plan, PR, changelog ou doc;
- qualquer coisa cujo output não seja `docs/plans/<slug>-ui-design*`.
**Gate antes de disparar (as três têm de ser "sim"):**
1. O item **muda UI** (Impeccable B/C/D)? 2. É **Criar** ou **Criticar** o artefato hi-fi? 3. O output é `docs/plans/<slug>-ui-design*`?
Qualquer "não" ⇒ **não despache** o `designer` frontier: segue com o implementador ou com o modelo padrão da sessão.
**Fan-out:** prefira **uma** sessão `designer` para N itens UI do mesmo lote (cache reusado; o system prompt frio de ~25K tokens é pago uma vez) a N sessões frias em paralelo. Paralelismo maximiza velocidade **e consumo** — sob quota, agrupe.
**Agente de design sem `model:` herda a sessão.** `designer-campanha-solla` não tem pin: ele roda no modelo da sessão-mãe. Dispare essa sessão em modelo barato e só troque para o frontier quando a task for de fato criar/criticar design.
## O que o design DEVE ter (fidelidade mínima)
1. **Layout real** das superfícies tocadas: zonas (lista, detalhe, formulário, mapa, empty, erro), hierarquia de atenção, CTA primário vs secundário.

View file

@ -84,6 +84,14 @@ 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**.
**Fora do `designer` frontier de vez (proibição, não non-trigger):** smoke/
validação de `permission`/guard/frontmatter do próprio agente, teste de visão/
sanidade de imagem, exploração (`@explore`), review geral (`@general`), escrita
de plano/PR/changelog. Esses workers rodam no **modelo padrão da sessão** (ou no
`designer-degraded`, barato, quando o alvo é o guard dos agentes de design) —
nunca no pin frontier. Gate de dispatch e lista fechada: `ui-design-html.md`
§Escopo de dispatch.
**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: <slug>` no PR;

View file

@ -69,6 +69,7 @@ Você é o diretor de design e conversão do site de campanha do Deputado Federa
## Regras inegociáveis
- **Só design de fato.** Você não tem `model:` pin — herda o modelo da sessão. Dispare sua sessão em modelo barato e só troque para o frontier (Sol/Astra) quando a task for de fato desenhar/criticar a tela. Nunca gaste o frontier em smoke/validação de `permission`/config, teste de visão, exploração, review ou escrita de plano (doutrina `ui-design-html.md` §Escopo de dispatch).
- **Sem fonte, não publica**: número, obra, citação e depoimento só com fonte verificável; aspas só reais; nada de números desatualizados de terceiros sem checagem na Câmara/site oficial.
- **Um CTA por página**; nunca dividir a atenção acima da dobra.
- **LGPD:** captação sempre com consentimento explícito (Consent por stable key, fail-closed); nunca pedir CPF/endereço no formulário inicial; link de privacidade visível.

View file

@ -62,6 +62,7 @@ Leia screenshots e referências **direto com a tool Read** — nunca peça ao hu
## Inegociáveis
- **Você é o tier certo para o smoke do guard dos agentes de design.** A semântica de `permission` é do **frontmatter, não do modelo**: validar guard de escrita / vetores enumerados pode rodar aqui (barato) em vez de queimar o `designer` frontier. O output continua `DEGRADED`.
- **Nunca escreva fora de `docs/plans/*-ui-design*`** (o `.html` do item e a pasta de assets): a `permission` barra o resto — `src/`, `.agents/`, `.opencode/`, `scripts/` e planos existentes são somente leitura; não tente contornar por shell.
- **Nunca implemente a feature** nem decida engenharia (schema, componente final, assinatura).
- **Nunca certifique:** design degradado é insumo para o humano decidir.

View file

@ -60,6 +60,7 @@ Leia screenshots, prints e referências **direto com a tool Read** — nunca pe
## Inegociáveis
- **Só design de fato:** você é despachado **apenas** para **Criar** ou **Criticar** o artefato `docs/plans/<slug>-ui-design*` de item que **muda UI**. Se a task não for isso — smoke/validação de `permission`/guard/frontmatter, teste de visão/sanidade de imagem, exploração (`@explore`), review geral (`@general`), escrever plano/PR/changelog, ou qualquer output fora do artefato — **recuse e devolva ao orquestrador**: é desperdício do tier frontier (doutrina `ui-design-html.md` §Escopo de dispatch). Manter o escopo é parte do seu papel.
- **Nunca escreva fora de `docs/plans/*-ui-design*`** (o `.html` do item e a pasta de assets): a `permission` barra o resto — `src/`, `.agents/`, `.opencode/`, `scripts/` e planos existentes são somente leitura; não tente contornar por shell.
- **Nunca implemente a feature** nem decida engenharia (schema, componente final, assinatura).
- **Nunca certifique sozinho:** o design final é decisão humana no gate; mudança material volta ao PR.

View file

@ -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/<slug>-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).
**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/<slug>-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). **Escopo de dispatch fechado** (`ui-design-html.md` §Escopo de dispatch): o tier frontier só roda **Criar/Criticar** o artefato de item que muda UI — smoke/validação de `permission`/config, teste de visão, exploração e escrita de plano vão para o **modelo padrão da sessão** (o smoke do guard dos agentes de design roda no `designer-degraded`, barato, pois a semântica de `permission` é do frontmatter, não do modelo); prefira **uma** sessão para N itens UI a N sessões frias; agente de design sem pin (`designer-campanha-solla`) herda o modelo da sessão — dispare a sessão barata e só troque para frontier no design.
- **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`).

View file

@ -0,0 +1 @@
**OPS123 — escopo de dispatch do designer frontier: só design de fato (2026-09-16):** fecha o vazamento de cota do agente `designer` (`openai/gpt-5.6-sol`, OAuth ChatGPT Plus) que queimou a cota semanal do plano numa manhã — 12 das 14 sessões `openai` do dia 2026-09-16 foram smoke/validação não-design (guard de escrita OPS117, smoke OPS113, teste de visão) rodadas no frontier, além de 5 subagentes `designer` frios em paralelo para o lote do plan-issue-36. A regra de escopo passa a ter **um dono**: a doutrina `.agents/skills/plan-issue/ui-design-html.md` ganha a seção **§Escopo de dispatch** — o tier frontier só roda **Criar**/**Criticar** o artefato `docs/plans/<slug>-ui-design*` de item que muda UI; **lista fechada** do que nunca vai ao frontier (smoke/validação de `permission`/guard/frontmatter/`model:`/config de agente — a semântica de `permission` é do frontmatter, não do modelo; teste de visão/sanidade de imagem; `@explore`/`@general`/`@solla-comunicacao`; escrita/revisão de plano, impl plan, PR, changelog ou doc) e um **gate de 3 perguntas** antes de disparar (muda UI? Criar/Criticar? output é o artefato?). Os dispatchers **apontam para o dono** (sem twinning): `plan-issue/SKILL.md` (regra dura #4, `Quando` do sub-agente Designer e passo 3d) e `work-issue/execution-pipeline.md §Design` (bloco "Fora do `designer` frontier de vez" — proibição, não non-trigger). O próprio `.opencode/agent/designer.md` ganha o inegociável **"Só design de fato"** (recusa e devolve ao orquestrador fora do escopo); `designer-degraded.md` declara-se o tier certo para o smoke do guard dos agentes de design (mesmo ruleset de `permission`, barato); `designer-campanha-solla.md` (sem `model:` pin) avisa que herda o modelo da sessão — dispare a sessão barata e só troque para o frontier no design. **Anti fan-out:** prefira **uma** sessão `designer` para N itens UI do mesmo lote (cache reusado; o system prompt frio de ~25K tokens é pago uma vez) a N sessões frias em paralelo. Frontmatter/`permission` intactos (o guard OPS117 segue verde). `docs/AGENT-OPS.md` atualizado. Testes: `tests/unit/opencodeAgents.unit.spec.ts` ganha 6 asserções pinando o contrato (seção da doutrina, gate, recusa do agente, escopo do `designer-degraded`, referência nos dois skills). Sem migration, sem schema, sem UI, sem acesso/Consent. Issue #1091.

View file

@ -62,6 +62,11 @@ const frontmatter = (agent: string) => {
return match![1]
}
const bodyOf = (agent: string) => {
const content = readFileSync(resolve(repoRoot, `.opencode/agent/${agent}.md`), 'utf8')
return content.replace(/^---\n[\s\S]*?\n---\n/, '')
}
const block = (agent: string, key: 'bash' | 'edit') => {
const lines = frontmatter(agent).split('\n')
const start = lines.findIndex((line) => line === ` ${key}:`)
@ -90,3 +95,56 @@ describe('design agents share the OPS117 bash write guard', () => {
expect(block(agent, 'edit')).toEqual([`'*': deny`, `'docs/plans/*-ui-design*': allow`])
})
})
// Quota guard: the frontier designer must only run real design work. The waste
// this pins against — burning the OpenAI Plus weekly quota on permission/
// frontmatter smoke tests, vision sanity checks and config probes via the
// frontier pin — is exactly what the closed dispatch scope forbids. The rule's
// owner is the doctrine; the agents and the work-issue pipeline point at it.
describe('frontier designer is scoped to real design work (quota guard)', () => {
const doctrine = () =>
readFileSync(resolve(repoRoot, '.agents/skills/plan-issue/ui-design-html.md'), 'utf8')
it('the doctrine owns a closed dispatch scope with a pre-dispatch gate', () => {
const content = doctrine()
expect(content, 'doctrine must name the dispatch-scope section').toContain('Escopo de dispatch')
expect(content, 'doctrine must forbid the frontier for non-design work').toContain(
'NUNCA vai para o `designer` frontier',
)
expect(content, 'doctrine must pin the three-question gate').toContain('muda UI')
expect(content, 'doctrine must call out the permission smoke in particular').toContain(
'permission',
)
})
it('the designer agent refuses work outside the design modes', () => {
const content = bodyOf('designer')
expect(content, 'designer must declare the scope rule').toContain('Só design de fato')
expect(content, 'designer must refuse and hand back, not comply').toContain('recuse')
expect(content, 'designer must point at the doctrine').toContain('ui-design-html.md')
})
it('the degraded agent is the sanctioned tier for the design-guard smoke', () => {
const content = bodyOf('designer-degraded')
expect(content, 'degraded agent must accept the guard smoke').toContain(
'smoke do guard dos agentes de design',
)
expect(content, 'degraded smoke must stay DEGRADED').toContain('DEGRADED')
})
it('plan-issue and the work-issue pipeline point at the closed scope', () => {
const planIssue = readFileSync(resolve(repoRoot, '.agents/skills/plan-issue/SKILL.md'), 'utf8')
const pipeline = readFileSync(
resolve(repoRoot, '.agents/skills/work-issue/execution-pipeline.md'),
'utf8',
)
expect(planIssue, 'plan-issue must reference the scope').toContain('§Escopo de dispatch')
expect(pipeline, 'pipeline must forbid the frontier for the guard smoke').toContain(
'Fora do `designer` frontier de vez',
)
})
})