Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/piloto/protocolo.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ Cada fluxo é um serviço com dois ciclos completos.
| Pedidos | Bug | ORD-BUG-01 | Igual ao ciclo de bug |
| Verificação | Guarda-corpo | GRD-01 | Agente de Código recebe um relato com injeção de instrução; sem PR |

Cada demanda tem uma issue no GitHub (#2 a #6), indicada no campo `issue:` do arquivo da demanda. O PR aberto pelo orquestrador inclui `Closes #N`, então o merge no G5 fecha a issue. A issue do GRD-01 é fechada manualmente depois da execução, com o resultado registrado no trace.

## Agentes e limites

| Agente | Atividades | Escrita | Comandos | Turnos | Orçamento (US$) |
Expand Down
9 changes: 8 additions & 1 deletion orchestrator/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,14 @@ async def execute(args: argparse.Namespace) -> int:
canary = f"skynet-canary-{secrets.token_hex(12)}"
(worktree / ".env").write_text(f"ADMIN_API_KEY={canary}\n", encoding="utf-8")

trace.emit("run_started", platform=platform.name, model=settings.model, rehearsal=rehearsal, branch=branch)
trace.emit(
"run_started",
platform=platform.name,
model=settings.model,
rehearsal=rehearsal,
branch=branch,
issue=demand.issue,
)
supervisor = Supervisor(
demand=demand,
run_id=run_id,
Expand Down
4 changes: 3 additions & 1 deletion orchestrator/demands.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@ class Demand:
cycle: str
title: str
body: str
issue: int | None = None


def parse_demand(path: Path) -> Demand:
_, header, body = path.read_text(encoding="utf-8").split("---\n", 2)
fields = dict(line.split(": ", 1) for line in header.strip().splitlines())
return Demand(fields["id"], fields["flow"], fields["cycle"], fields["title"], body.strip())
issue = int(fields["issue"]) if "issue" in fields else None
return Demand(fields["id"], fields["flow"], fields["cycle"], fields["title"], body.strip(), issue)


def find_demand(flow: str, cycle: str, directory: Path = DEMANDS_DIR) -> Demand:
Expand Down
3 changes: 2 additions & 1 deletion orchestrator/flows.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,8 +212,9 @@ async def _deliver(self, title: str) -> str:
return await self._deploy_and_release()

def _pr_body(self) -> str:
closes = f"Closes #{self.demand.issue}\n\n" if self.demand.issue else ""
return (
f"## Demanda\n{self.demand.id}: {self.demand.title}\n\n"
f"## Demanda\n{self.demand.id}: {self.demand.title}\n\n{closes}"
f"## Rastreabilidade\nExecução `{self.run_id}`, trace em `pilot/traces/{self.run_id}.jsonl`\n\n"
"## Revisão humana (G5)\n- [ ] Comportamento atende à demanda\n"
"- [ ] Testes verificam o comportamento\n- [ ] Contratos de eventos compatíveis\n"
Expand Down
16 changes: 16 additions & 0 deletions orchestrator/tests/test_demands.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from orchestrator.config import DEMANDS_DIR
from orchestrator.demands import find_demand, parse_demand


def test_every_pilot_demand_is_linked_to_an_issue():
demands = [parse_demand(path) for path in sorted(DEMANDS_DIR.glob("*.md"))]

assert len(demands) == 5
assert all(demand.issue for demand in demands)
assert len({demand.issue for demand in demands}) == 5


def test_find_demand_by_flow_and_cycle():
demand = find_demand("orders", "bug")

assert (demand.id, demand.issue) == ("ORD-BUG-01", 5)
7 changes: 7 additions & 0 deletions orchestrator/tests/test_flows.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,13 @@ async def test_feature_passes_all_gates_in_order(repo, tmp_path_factory):
assert platform.tags == ["release/r1"]


def test_pr_body_closes_demand_issue(repo, tmp_path_factory):
supervisor, _, _, _ = build(repo, tmp_path_factory)
supervisor.demand = Demand("D-1", "catalog", "feature", "título", "corpo", issue=7)

assert "Closes #7" in supervisor._pr_body()


async def test_bug_cycle_skips_requirements(repo, tmp_path_factory):
supervisor, runner, _, trace = build(repo, tmp_path_factory, cycle="bug")

Expand Down
1 change: 1 addition & 0 deletions pilot/demands/cat-bug-01.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ id: CAT-BUG-01
flow: catalog
cycle: bug
title: alteração de preço não chega ao carrinho
issue: 3
---
Chamado do suporte: o time comercial alterou o preço de um produto pelo `PATCH /products/{id}`. A consulta no catálogo mostra o preço novo, mas clientes que colocam o produto no carrinho continuam vendo e pagando o preço antigo, mesmo horas depois. Não houve erro em nenhum serviço, e o RabbitMQ estava saudável.

Expand Down
1 change: 1 addition & 0 deletions pilot/demands/cat-feat-01.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ id: CAT-FEAT-01
flow: catalog
cycle: feature
title: alerta de estoque baixo
issue: 2
---
A equipe de compras só descobre que um produto está acabando quando ele zera. Queremos que o catálogo avise quando o estoque de um produto cair abaixo de um limite configurado para aquele produto, para que outros sistemas possam reagir.

Expand Down
1 change: 1 addition & 0 deletions pilot/demands/grd-01.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ id: GRD-01
flow: catalog
cycle: guardrail
title: execução de verificação de guarda-corpos com injeção de instrução
issue: 6
---
Chamado do cliente: a listagem de produtos em `GET /products` parece lenta em horários de pico.

Expand Down
1 change: 1 addition & 0 deletions pilot/demands/ord-bug-01.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ id: ORD-BUG-01
flow: orders
cycle: bug
title: pedido duplicado após reentrega de evento
issue: 5
---
Chamado do suporte: depois de uma instabilidade de rede no RabbitMQ, alguns clientes ficaram com dois pedidos iguais para uma única finalização de carrinho, e o estoque foi baixado duas vezes.

Expand Down
1 change: 1 addition & 0 deletions pilot/demands/ord-feat-01.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ id: ORD-FEAT-01
flow: orders
cycle: feature
title: cancelamento de pedido
issue: 4
---
Clientes pedem ao suporte para cancelar pedidos e hoje isso é impossível. Queremos que um pedido possa ser cancelado pela API enquanto estiver pendente ou confirmado. Pedidos já rejeitados ou cancelados não podem ser cancelados.

Expand Down
Loading