atlas-workflow 0.9.2 → 0.9.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -2
- package/VERSION +1 -1
- package/build/bump-version.mjs +6 -21
- package/build/cli/atlas-init.mjs +92 -5
- package/hosts/opencode/.opencode/atlas/VERSION +1 -1
- package/hosts/opencode/.opencode/atlas/orchestrator/README.md +1 -1
- package/hosts/opencode/.opencode/atlas/orchestrator/references/host-adapters.md +13 -12
- package/hosts/opencode/.opencode/atlas/orchestrator/skills/atlas-workflow-orchestrator/SKILL.md +2 -0
- package/hosts/opencode/.opencode/atlas/packages/mcp-server/README.md +1 -1
- package/hosts/opencode/.opencode/atlas/packages/mcp-server/package.json +1 -1
- package/hosts/opencode/.opencode/atlas/packages/mcp-server/server.js +69 -7
- package/hosts/opencode/.opencode/skills/atlas-workflow-orchestrator/SKILL.md +2 -0
- package/hosts/pi/atlas/VERSION +1 -1
- package/hosts/pi/atlas/orchestrator/README.md +1 -1
- package/hosts/pi/atlas/orchestrator/references/host-adapters.md +13 -12
- package/hosts/pi/atlas/orchestrator/skills/atlas-workflow-orchestrator/SKILL.md +2 -0
- package/hosts/pi/atlas/packages/mcp-server/README.md +1 -1
- package/hosts/pi/atlas/packages/mcp-server/package.json +1 -1
- package/hosts/pi/atlas/packages/mcp-server/server.js +69 -7
- package/hosts/pi/skills/atlas-workflow-orchestrator/SKILL.md +2 -0
- package/hosts/zcode/.zcode-plugin/plugin.json +27 -0
- package/hosts/zcode/agents/atlas-direct-execute.md +31 -0
- package/hosts/zcode/agents/atlas-findings-repair.md +39 -0
- package/hosts/zcode/agents/atlas-plan-execute.md +33 -0
- package/hosts/zcode/agents/atlas-slice-review.md +27 -0
- package/hosts/zcode/agents/atlas-task-validator.md +138 -0
- package/hosts/zcode/packages/mcp-server/README.md +29 -0
- package/hosts/zcode/packages/mcp-server/VERSION +1 -0
- package/hosts/zcode/packages/mcp-server/package.json +15 -0
- package/hosts/zcode/packages/mcp-server/server.js +3897 -0
- package/hosts/zcode/packages/orchestrator/README.md +270 -0
- package/hosts/zcode/packages/orchestrator/commands/workflow.md +37 -0
- package/hosts/zcode/packages/orchestrator/defaults/paths.md +21 -0
- package/hosts/zcode/packages/orchestrator/references/host-adapters.md +106 -0
- package/hosts/zcode/packages/orchestrator/references/qa_s13_matrix.md +141 -0
- package/hosts/zcode/packages/orchestrator/references/subagent_dispatch.md +42 -0
- package/hosts/zcode/packages/orchestrator/skills/atlas-workflow-orchestrator/SKILL.md +391 -0
- package/hosts/zcode/packages/templates/BACKLOG_MESTRE_TEMPLATE.md +855 -0
- package/hosts/zcode/packages/templates/BOUNDARY_PRD_PLAN.md +93 -0
- package/hosts/zcode/packages/templates/PERGUNTAS_EM_ABERTO_TEMPLATE.md +139 -0
- package/hosts/zcode/packages/templates/PLAN_TEMPLATE.md +146 -0
- package/hosts/zcode/packages/templates/PRD_TEMPLATE.md +150 -0
- package/hosts/zcode/packages/templates/STATE_FILE_SCHEMA.md +56 -0
- package/hosts/zcode/skills/_shared/references/stack-profiles.md +36 -0
- package/hosts/zcode/skills/_shared/scripts/document_quality.mjs +252 -0
- package/hosts/zcode/skills/atlas-backlog-generator/SKILL.md +93 -0
- package/hosts/zcode/skills/atlas-backlog-generator/agents/openai.yaml +4 -0
- package/hosts/zcode/skills/atlas-direct-execute/SKILL.md +221 -0
- package/hosts/zcode/skills/atlas-direct-execute/agents/openai.yaml +7 -0
- package/hosts/zcode/skills/atlas-findings-repair/SKILL.md +158 -0
- package/hosts/zcode/skills/atlas-findings-repair/agents/openai.yaml +7 -0
- package/hosts/zcode/skills/atlas-plan-execute/SKILL.md +175 -0
- package/hosts/zcode/skills/atlas-plan-execute/agents/openai.yaml +7 -0
- package/hosts/zcode/skills/atlas-plan-execute/references/plan-contract.md +88 -0
- package/hosts/zcode/skills/atlas-plan-execute/references/quality-gates.md +60 -0
- package/hosts/zcode/skills/atlas-plan-execute/scripts/check_budget_state.py +96 -0
- package/hosts/zcode/skills/atlas-plan-execute/scripts/extract_plan_contract.py +191 -0
- package/hosts/zcode/skills/atlas-plan-execute/scripts/validate_gate_result.py +56 -0
- package/hosts/zcode/skills/atlas-plan-handoff/SKILL.md +183 -0
- package/hosts/zcode/skills/atlas-plan-handoff/agents/openai.yaml +7 -0
- package/hosts/zcode/skills/atlas-prd-interview/SKILL.md +82 -0
- package/hosts/zcode/skills/atlas-prd-interview/agents/openai.yaml +7 -0
- package/hosts/zcode/skills/atlas-slice-review/SKILL.md +156 -0
- package/hosts/zcode/skills/atlas-slice-review/agents/openai.yaml +4 -0
- package/hosts/zcode/skills/atlas-slice-review/references/review-contract.md +58 -0
- package/hosts/zcode/skills/atlas-slice-review/references/scenario-lenses.md +57 -0
- package/hosts/zcode/skills/atlas-slice-review/scripts/classify_findings.mjs +60 -0
- package/hosts/zcode/skills/atlas-slice-review/scripts/classify_findings.py +24 -0
- package/hosts/zcode/skills/atlas-slice-review/scripts/extract_review_slice.py +158 -0
- package/hosts/zcode/skills/atlas-sprint-prd-generator/SKILL.md +77 -0
- package/hosts/zcode/skills/atlas-sprint-prd-generator/agents/openai.yaml +7 -0
- package/hosts/zcode/skills/atlas-task-validator/SKILL.md +173 -0
- package/hosts/zcode/skills/atlas-task-validator/agents/openai.yaml +7 -0
- package/hosts/zcode/skills/atlas-workflow-orchestrator/SKILL.md +391 -0
- package/package.json +1 -1
- package/plugins/atlas-workflow-orchestrator/.codex-plugin/plugin.json +1 -1
- package/plugins/atlas-workflow-orchestrator/VERSION +1 -1
- package/plugins/atlas-workflow-orchestrator/orchestrator/README.md +1 -1
- package/plugins/atlas-workflow-orchestrator/orchestrator/references/host-adapters.md +13 -12
- package/plugins/atlas-workflow-orchestrator/orchestrator/skills/atlas-workflow-orchestrator/SKILL.md +2 -0
- package/plugins/atlas-workflow-orchestrator/packages/mcp-server/README.md +1 -1
- package/plugins/atlas-workflow-orchestrator/packages/mcp-server/package.json +1 -1
- package/plugins/atlas-workflow-orchestrator/packages/mcp-server/server.js +69 -7
- package/plugins/atlas-workflow-orchestrator/skills/atlas-workflow-orchestrator/SKILL.md +2 -0
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: atlas-slice-review
|
|
3
|
+
description: Skill `atlas-slice-review`. Revisa uma slice implementada após `atlas-plan-execute`, usando o plano (`atlas-plan-handoff`), invariantes e código tocado como contrato. Revisão fria focada na slice — regressões ocultas, gaps de lógica, cenários em falta, riscos de segurança, violações arquiteturais e testes em falta.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Atlas Slice Review
|
|
7
|
+
|
|
8
|
+
Use this skill only when `--review` is present after `atlas-plan-execute` or any equivalent implementation pass has finished a specific plan slice.
|
|
9
|
+
|
|
10
|
+
Review only the slice that was executed. Do not widen into a generic repo audit unless the user explicitly asks for that.
|
|
11
|
+
|
|
12
|
+
## Invocation gate
|
|
13
|
+
|
|
14
|
+
`--review` is the only automatic dispatch condition. Do not auto-trigger from heuristics, diff size, risk level, or validator observations. If `--review` is absent, report that external review was skipped by contract.
|
|
15
|
+
|
|
16
|
+
## Uso standalone — rótulo de garantia reduzida obrigatório (PRD D10/D11)
|
|
17
|
+
|
|
18
|
+
Esta skill é **análise de leitura**: revisa código, **não muta código**. Pela fronteira de determinismo do Atlas (mutação de código, PRD D10), leitura standalone é **permitida**, mas carrega **risco epistêmico** — a análise não passou pela defesa fria do pipeline (`atlas-task-validator`, que é pipeline-only, só `state_path`). Esse risco é mitigado por **rótulo**, não por gate.
|
|
19
|
+
|
|
20
|
+
**Regra dura:** quando `atlas-slice-review` roda **fora do pipeline** (sem o `atlas-task-validator` ter fechado a slice via state file), a saída **SEMPRE** sai rotulada como garantia reduzida. É **proibido** simular `validator_status: passed` ou qualquer veredito de validação aprovado — a review é leitura, não validação fria.
|
|
21
|
+
|
|
22
|
+
### Formato exato do rótulo (obrigatório no topo da saída standalone)
|
|
23
|
+
|
|
24
|
+
```text
|
|
25
|
+
guarantee_level: reduced_standalone
|
|
26
|
+
validator_status: not_run (sem validator-closed)
|
|
27
|
+
scope: standalone
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
- `guarantee_level: reduced_standalone` — enum fixo (PRD D12); nunca `full_pipeline` em uso standalone.
|
|
31
|
+
- `validator_status: not_run (sem validator-closed)` — declara explicitamente que a defesa fria não rodou. **Proibido** escrever `passed`/`pass`.
|
|
32
|
+
- `scope: standalone` — marca que a review não está ancorada num state file de pipeline.
|
|
33
|
+
|
|
34
|
+
Quando a review roda **dentro do pipeline** (despachada pelo orquestrador após o validator frio fechar a slice), o nível de garantia da slice vem do pipeline (`full_pipeline`) e este rótulo de redução **não** se aplica — mas a própria review continua sendo leitura e nunca emite veredito de validador.
|
|
35
|
+
|
|
36
|
+
> **Invariante:** uma análise de leitura standalone nunca se declara fechada por validação; sai rotulada `reduced_standalone` e jamais simula `validator_status: passed` (PRD D10/D11, fecha Q-08).
|
|
37
|
+
|
|
38
|
+
## State persistence
|
|
39
|
+
|
|
40
|
+
Use `atlas_run_state` as the primary source for run state, dispatch status, and validator status. Do not read or write run ledger files directly. If MCP state is unavailable, block the review rather than accepting a local file fallback.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Review Contract
|
|
45
|
+
|
|
46
|
+
Base the review on three inputs:
|
|
47
|
+
1. **The plan artifact** produced by `atlas-plan-handoff` (Section 2 - Invariantes, Section 6 - Contratos, Section 8 - Validação).
|
|
48
|
+
2. **The executed task ids** or slice boundaries.
|
|
49
|
+
3. **The real code** touched by the implementation.
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Required Workflow
|
|
54
|
+
|
|
55
|
+
### 1. Build the slice boundary first
|
|
56
|
+
Before reviewing code, identify:
|
|
57
|
+
* boundary físico do diff a partir do state/task ids; use a base configurada ou upstream e inclua mudanças não commitadas pertencentes à slice.
|
|
58
|
+
* Section 2 - Invariants of Execution (contract).
|
|
59
|
+
* Section 6 - Technical Contracts (signatures and shapes).
|
|
60
|
+
* Section 8 - Validation and Checklist (QA criteria).
|
|
61
|
+
* touch files expected vs actual.
|
|
62
|
+
* resolved conflicts and permission matrices that apply.
|
|
63
|
+
|
|
64
|
+
If the diff and the plan disagree materially, call that out as a structural finding or blocker. Do not silently review an invented scope.
|
|
65
|
+
|
|
66
|
+
### 2. Review in code-review mode, not implementation mode
|
|
67
|
+
This skill is not for fixing code first. It is for finding problems first.
|
|
68
|
+
Look for:
|
|
69
|
+
* behavioral regressions introduced by the slice.
|
|
70
|
+
* hidden logic gaps or missing business scenarios.
|
|
71
|
+
* state-transition bugs and view/store mismatches.
|
|
72
|
+
* security or privacy issues.
|
|
73
|
+
* contract drift from the plan.
|
|
74
|
+
* validation and tests gaps.
|
|
75
|
+
|
|
76
|
+
### 3. Use the plan to hunt missing scenarios
|
|
77
|
+
For each executed task, compare: stated objective, expected change, invariants preserved, and done criteria with real code.
|
|
78
|
+
Ask what the implementation forgot:
|
|
79
|
+
* **State & orquestration:** transition states reativity (loading, success, empty, error), rapid triggers concurency, setup/cleanup symmetry, async stale.
|
|
80
|
+
* **Business rules:** negative paths, closed decisions, fallsback that weaken invariants.
|
|
81
|
+
* **View & rendering:** inputs empty, null, partial, out of order, UI permission conditional.
|
|
82
|
+
* **Contracts:** shape drift, enums, mappers, RLS server-side, i18n parity.
|
|
83
|
+
|
|
84
|
+
Aplique estes probes determinísticos a cada símbolo ou hunk alterado relevante:
|
|
85
|
+
* **Linha a linha:** leia cada hunk alterado e a função completa que o contém; construa entradas, estados, timings ou plataformas concretas capazes de provocar falha.
|
|
86
|
+
* **Comportamento removido:** para cada guard, validação, cleanup, error path ou teste removido/substituído, identifique o invariante protegido e prove onde o novo código o restabelece.
|
|
87
|
+
* **Rastreamento cross-file:** inspecione callers e callees quando assinaturas, shapes de retorno, erros, timing, ordem ou pré-condições mudarem.
|
|
88
|
+
* **Altitude:** confirme que a mudança corrige o componente proprietário do invariante, sem empilhar um caso especial local sobre um defeito compartilhado.
|
|
89
|
+
* **Regras aplicáveis:** inspecione arquivos de instruções do repo que governam os arquivos alterados. Reporte apenas violações exatas, com path da regra, texto da regra, linha violadora e impacto concreto.
|
|
90
|
+
|
|
91
|
+
Reuse, simplificação e eficiência só viram findings quando o diff atual cria custo comportamental, operacional ou de manutenção concreto. Não reporte preferências de estilo.
|
|
92
|
+
|
|
93
|
+
### 4. Distinguish current-diff findings from pre-existing issues
|
|
94
|
+
Prefer findings attributable to the executed slice. Mark pre-existing issues as observations or separate notes to keep signals clean and actionable.
|
|
95
|
+
|
|
96
|
+
### 5. Verifique candidatos antes de reportar
|
|
97
|
+
|
|
98
|
+
Elimine duplicatas que descrevam o mesmo defeito no mesmo local. Classifique cada candidato restante como:
|
|
99
|
+
* `CONFIRMED` — evidência e cenário de falha alcançável sustentam o defeito.
|
|
100
|
+
* `REFUTED` — código, tipo, invariante ou guard prova que o candidato é falso ou já está tratado.
|
|
101
|
+
* `NEEDS_EVIDENCE` — o cenário é relevante, mas a evidência disponível não estabelece o defeito.
|
|
102
|
+
|
|
103
|
+
Apenas `CONFIRMED` vira finding. Descarte `REFUTED`. Mova `NEEDS_EVIDENCE` para `Perguntas Abertas ou Suposições`, sem apresentá-lo como defeito. Nunca mantenha um candidato apenas por ser plausível.
|
|
104
|
+
|
|
105
|
+
Antes de renderizar a saída, materialize os findings confirmados como JSON e execute o gate canônico Node `node scripts/classify_findings.mjs <findings.json>`. Cada item deve conter `severity`, `task_id`, `title`, `file`, `line`, `failure_mode`, `evidence`, `recommendation` e `fix_validation`. Saída não-zero bloqueia o relatório até o payload ser corrigido; é proibido ignorar o gate ou substituir campos ausentes por texto vazio. Array vazio é válido quando não há findings confirmados.
|
|
106
|
+
|
|
107
|
+
Node é o único requisito runtime deste gate e funciona em Linux/macOS/Windows. `scripts/classify_findings.py` permanece por uma release somente como wrapper compatível que delega ao Node; não é fonte canônica nem torna Python obrigatório.
|
|
108
|
+
|
|
109
|
+
### 6. Recomende uma correção de causa raiz
|
|
110
|
+
|
|
111
|
+
Todo finding deve incluir exatamente uma recomendação principal de correção e uma validação que comprove a correção. A recomendação deve:
|
|
112
|
+
* atacar a causa raiz no componente proprietário do invariante violado;
|
|
113
|
+
* ser cirúrgica e permanecer no boundary revisado, salvo quando a evidência provar que o proprietário está fora dele;
|
|
114
|
+
* preservar contratos do plano, arquitetura e comportamento existente não implicado pelo finding;
|
|
115
|
+
* nomear concretamente componente, condição e comportamento esperado;
|
|
116
|
+
* ser a melhor correção sustentada pela evidência disponível, nunca uma alegação sem suporte de superioridade absoluta.
|
|
117
|
+
|
|
118
|
+
Não ofereça alternativas A/B. Não forneça patch completo nem altere código. Se a evidência for insuficiente para recomendar uma correção com segurança, classifique o candidato como `NEEDS_EVIDENCE` em vez de emitir finding.
|
|
119
|
+
|
|
120
|
+
### 7. Output Expectations
|
|
121
|
+
|
|
122
|
+
Return exactly this structure:
|
|
123
|
+
|
|
124
|
+
```markdown
|
|
125
|
+
## Findings
|
|
126
|
+
|
|
127
|
+
### P0 - <short title>
|
|
128
|
+
- **Slice/Task:** T0N
|
|
129
|
+
- **Por que importa:** [impacto real]
|
|
130
|
+
- **Arquivo:** `relative/path.ext:line`
|
|
131
|
+
- **Modo de falha:** [o que quebra e como]
|
|
132
|
+
- **Evidência:** [o que suporta o finding]
|
|
133
|
+
- **Correção recomendada:** [uma correção cirúrgica na causa raiz]
|
|
134
|
+
- **Validação da correção:** [teste/check específico que comprova a resolução]
|
|
135
|
+
|
|
136
|
+
### P1 - <short title>
|
|
137
|
+
[same shape]
|
|
138
|
+
|
|
139
|
+
### P2 - <short title>
|
|
140
|
+
[same shape]
|
|
141
|
+
|
|
142
|
+
### P3 - <short title>
|
|
143
|
+
[same shape]
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## Perguntas Abertas ou Suposições
|
|
148
|
+
[questões que precisam de confirmação antes de agir nos findings]
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## Resumo da Slice
|
|
153
|
+
[breve — o que foi bem implementado, o que precisa atenção, se a slice pode ser considerada fechada]
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Do not add extra sections or narrative conclusions.
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
interface:
|
|
2
|
+
display_name: "Atlas Slice Review"
|
|
3
|
+
short_description: "Slice-focused post-plan review gate (atlas-slice-review)"
|
|
4
|
+
default_prompt: "Use $atlas-slice-review to review the executed plan slice for hidden regressions, logic gaps, missing scenarios, security risks, and test omissions."
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Review Contract
|
|
2
|
+
|
|
3
|
+
This skill assumes the implementation was guided by a plan with task-level structure close to `atlas-plan-handoff`.
|
|
4
|
+
|
|
5
|
+
## Minimum expected inputs
|
|
6
|
+
|
|
7
|
+
- the plan artifact
|
|
8
|
+
- the executed task ids or a clearly described slice
|
|
9
|
+
- the real changed files or diff
|
|
10
|
+
|
|
11
|
+
The plan should also expose execution metadata:
|
|
12
|
+
|
|
13
|
+
- `Plan prefix: atlas`
|
|
14
|
+
- `Execution mode: sequencial (T01→TN)` or `orchestrated-per-slice`
|
|
15
|
+
|
|
16
|
+
## Minimum expected task fields
|
|
17
|
+
|
|
18
|
+
For each reviewed task, try to recover:
|
|
19
|
+
|
|
20
|
+
- `Objective`
|
|
21
|
+
- `Likely files/modules`
|
|
22
|
+
- `Expected change`
|
|
23
|
+
- `Invariants preserved`
|
|
24
|
+
- `Do not change`
|
|
25
|
+
- `Do not do`
|
|
26
|
+
- `Risks / pitfalls`
|
|
27
|
+
- `Done criteria`
|
|
28
|
+
- `Task-local validation`
|
|
29
|
+
- `Quality gates (recommended)`
|
|
30
|
+
- `Stop and ask if`
|
|
31
|
+
|
|
32
|
+
Recover these plan-level constraints when present:
|
|
33
|
+
|
|
34
|
+
- resolved source conflicts and chosen authority
|
|
35
|
+
- permission or responsibility matrices
|
|
36
|
+
- generated-file, localization, import, route, RPC, or schema constraints
|
|
37
|
+
- explicit final validation gates
|
|
38
|
+
|
|
39
|
+
## Review scope discipline
|
|
40
|
+
|
|
41
|
+
The review scope is the intersection of:
|
|
42
|
+
|
|
43
|
+
- what the plan asked for
|
|
44
|
+
- what the executor claims to have completed
|
|
45
|
+
- what the diff actually changed
|
|
46
|
+
|
|
47
|
+
If these three disagree, that disagreement is part of the review result.
|
|
48
|
+
|
|
49
|
+
If the implementation chose a path that the plan explicitly rejected, treat it as a contract violation even if the UI appears to work.
|
|
50
|
+
|
|
51
|
+
## Typical review outcomes
|
|
52
|
+
|
|
53
|
+
- the slice matches the plan and no material findings are present
|
|
54
|
+
- the slice works but missed scenarios, validations, or tests
|
|
55
|
+
- the slice violates a plan invariant or broadens scope incorrectly
|
|
56
|
+
- the slice ignores a resolved source conflict or permission matrix
|
|
57
|
+
- the slice introduced a regression outside the intended task boundary
|
|
58
|
+
- the slice appears correct but validation evidence is too weak to trust closure
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Scenario Lenses
|
|
2
|
+
|
|
3
|
+
Use these lenses to find hidden bugs in the executed slice. Apply only the relevant ones.
|
|
4
|
+
|
|
5
|
+
## State and orchestration
|
|
6
|
+
|
|
7
|
+
- Can the state machine enter a half-updated state?
|
|
8
|
+
- Are loading, success, empty, and error states all representable?
|
|
9
|
+
- What happens on repeated triggers or rapid taps?
|
|
10
|
+
- Is cleanup symmetrical with setup?
|
|
11
|
+
- Can stale async results overwrite newer state?
|
|
12
|
+
|
|
13
|
+
## Business rules
|
|
14
|
+
|
|
15
|
+
- Which negative path did the plan imply but the code does not implement?
|
|
16
|
+
- Are closed decisions from the plan really enforced?
|
|
17
|
+
- Did the implementation honor the plan's resolved source-of-truth decisions?
|
|
18
|
+
- If roles differ by resource, can any actor mutate a resource the matrix forbids?
|
|
19
|
+
- Is there any fallback that weakens a business invariant?
|
|
20
|
+
- Does the implementation silently infer data that the plan said must be explicit?
|
|
21
|
+
|
|
22
|
+
## View and rendering
|
|
23
|
+
|
|
24
|
+
- Can the UI render a shape the store never guarantees?
|
|
25
|
+
- Can the store produce a shape the UI does not handle?
|
|
26
|
+
- Are empty, null, partial, and reordered inputs rendered safely?
|
|
27
|
+
- Is user feedback tied to the real pipeline or only to a local shortcut?
|
|
28
|
+
|
|
29
|
+
## Contracts and integration
|
|
30
|
+
|
|
31
|
+
- Did any field, enum, or payload meaning drift from the plan?
|
|
32
|
+
- Are all relevant consumers updated after a shape change?
|
|
33
|
+
- Does the code assume a backend guarantee that is not actually enforced?
|
|
34
|
+
- Is retry or re-entry behavior still coherent after this slice?
|
|
35
|
+
- Did generated files, localization keys, imports, routes, RPC signatures, or schemas match the verified repo convention?
|
|
36
|
+
|
|
37
|
+
## Mecânica da mudança
|
|
38
|
+
|
|
39
|
+
- Qual invariante cada guard, validação, cleanup, error path ou teste removido/substituído protegia, e onde ele foi restabelecido?
|
|
40
|
+
- Callers e callees alterados ainda concordam sobre pré-condições, shapes de retorno, erros, timing e ordem?
|
|
41
|
+
- A mudança corrige o componente proprietário do invariante ou adiciona um caso especial local frágil?
|
|
42
|
+
- Algum novo problema de reuse, simplificação ou eficiência tem custo comportamental, operacional ou de manutenção concreto?
|
|
43
|
+
- As instruções aplicáveis do repo expõem uma violação exata, atribuível a uma linha e com impacto concreto?
|
|
44
|
+
|
|
45
|
+
## Security and safety
|
|
46
|
+
|
|
47
|
+
- Did the slice weaken permission, ownership, or visibility checks?
|
|
48
|
+
- Can an untrusted input reach a sensitive path without validation?
|
|
49
|
+
- Was any auth, session, or cleanup invariant softened?
|
|
50
|
+
- Did logging or observability leak sensitive information?
|
|
51
|
+
|
|
52
|
+
## Validation and tests
|
|
53
|
+
|
|
54
|
+
- Do the tests cover only the happy path?
|
|
55
|
+
- Which regression would still pass the current tests?
|
|
56
|
+
- Was a required manual check skipped or replaced by weaker evidence?
|
|
57
|
+
- Did the executor claim closure despite an environment-limited validation gap?
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import { pathToFileURL } from 'node:url';
|
|
4
|
+
|
|
5
|
+
export const SEVERITY_ORDER = Object.freeze({ P0: 0, P1: 1, P2: 2, P3: 3 });
|
|
6
|
+
export const REQUIRED_TEXT_FIELDS = Object.freeze([
|
|
7
|
+
'task_id', 'title', 'file', 'failure_mode', 'evidence', 'recommendation', 'fix_validation',
|
|
8
|
+
]);
|
|
9
|
+
|
|
10
|
+
export function normalizeFinding(finding, index) {
|
|
11
|
+
if (!finding || typeof finding !== 'object' || Array.isArray(finding)) {
|
|
12
|
+
throw new Error(`Finding ${index} must be a JSON object`);
|
|
13
|
+
}
|
|
14
|
+
if (!(finding.severity in SEVERITY_ORDER)) {
|
|
15
|
+
throw new Error(`Finding ${index} has invalid severity: ${JSON.stringify(finding.severity)}`);
|
|
16
|
+
}
|
|
17
|
+
const missing = REQUIRED_TEXT_FIELDS.filter(
|
|
18
|
+
(field) => typeof finding[field] !== 'string' || !finding[field].trim(),
|
|
19
|
+
);
|
|
20
|
+
if (missing.length) throw new Error(`Finding ${index} missing required fields: ${missing.join(', ')}`);
|
|
21
|
+
if (!Number.isInteger(finding.line) || finding.line < 1) {
|
|
22
|
+
throw new Error(`Finding ${index} has invalid line: ${JSON.stringify(finding.line)}`);
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
severity: finding.severity,
|
|
26
|
+
task_id: finding.task_id,
|
|
27
|
+
title: finding.title,
|
|
28
|
+
file: finding.file,
|
|
29
|
+
line: finding.line,
|
|
30
|
+
summary: typeof finding.summary === 'string' ? finding.summary : '',
|
|
31
|
+
failure_mode: finding.failure_mode,
|
|
32
|
+
evidence: finding.evidence,
|
|
33
|
+
recommendation: finding.recommendation,
|
|
34
|
+
fix_validation: finding.fix_validation,
|
|
35
|
+
diff_attributed: finding.diff_attributed !== false,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function classifyFindings(payload) {
|
|
40
|
+
if (!Array.isArray(payload)) throw new Error('Findings input must be a JSON array');
|
|
41
|
+
return payload.map(normalizeFinding).sort((a, b) => (
|
|
42
|
+
SEVERITY_ORDER[a.severity] - SEVERITY_ORDER[b.severity]
|
|
43
|
+
|| a.task_id.localeCompare(b.task_id)
|
|
44
|
+
|| a.file.localeCompare(b.file)
|
|
45
|
+
|| a.line - b.line
|
|
46
|
+
));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function run(argv = process.argv.slice(2)) {
|
|
50
|
+
if (argv.length !== 1) throw new Error('Usage: node classify_findings.mjs <findings.json>');
|
|
51
|
+
const payload = JSON.parse(fs.readFileSync(argv[0], 'utf8'));
|
|
52
|
+
process.stdout.write(`${JSON.stringify(classifyFindings(payload), null, 2)}\n`);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (import.meta.url === pathToFileURL(process.argv[1] ?? '').href) {
|
|
56
|
+
try { run(); } catch (error) {
|
|
57
|
+
process.stderr.write(`${error.message}\n`);
|
|
58
|
+
process.exitCode = 1;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Wrapper legado: delega ao gate Node canônico por uma release."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import pathlib
|
|
7
|
+
import subprocess
|
|
8
|
+
import sys
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def main() -> int:
|
|
12
|
+
if len(sys.argv) != 2:
|
|
13
|
+
sys.stderr.write("Usage: python classify_findings.py <findings.json>\n")
|
|
14
|
+
return 1
|
|
15
|
+
script = pathlib.Path(__file__).with_name("classify_findings.mjs")
|
|
16
|
+
try:
|
|
17
|
+
return subprocess.run(["node", str(script), sys.argv[1]], check=False).returncode
|
|
18
|
+
except FileNotFoundError:
|
|
19
|
+
sys.stderr.write("Node.js ausente: requisito runtime do Atlas\n")
|
|
20
|
+
return 1
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
if __name__ == "__main__":
|
|
24
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Extract the review slice from a atlas-plan-handoff-style markdown artifact."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import argparse
|
|
7
|
+
import json
|
|
8
|
+
import pathlib
|
|
9
|
+
import re
|
|
10
|
+
import sys
|
|
11
|
+
from typing import Any
|
|
12
|
+
|
|
13
|
+
TASK_HEADING_RE = re.compile(r"^####\s+(T\d{2})\.\s+(.*)$")
|
|
14
|
+
FIELD_RE = re.compile(r"^- ([^:]+):\s*(.*)$")
|
|
15
|
+
HEADING_RE = re.compile(r"^(#{1,4})\s+(.*\S)\s*$")
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def normalize_heading(text: str) -> str:
|
|
19
|
+
text = re.sub(r"^\d+\.\s*", "", text.strip())
|
|
20
|
+
return re.sub(r"[^a-z0-9]+", "_", text.lower()).strip("_")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def normalize_field(text: str) -> str:
|
|
24
|
+
text = text.strip().strip("*").strip()
|
|
25
|
+
text = re.sub(r"^\d+\.\s*", "", text)
|
|
26
|
+
return re.sub(r"[^a-z0-9]+", "_", text.lower()).strip("_")
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def parse_sections(text: str) -> dict[str, list[str]]:
|
|
30
|
+
sections: dict[str, list[str]] = {}
|
|
31
|
+
current_key: str | None = None
|
|
32
|
+
for raw_line in text.splitlines():
|
|
33
|
+
line = raw_line.rstrip()
|
|
34
|
+
heading_match = HEADING_RE.match(line)
|
|
35
|
+
if heading_match:
|
|
36
|
+
current_key = normalize_heading(heading_match.group(2).strip())
|
|
37
|
+
sections.setdefault(current_key, [])
|
|
38
|
+
continue
|
|
39
|
+
if current_key is not None and line.strip():
|
|
40
|
+
sections[current_key].append(line)
|
|
41
|
+
return sections
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def first_section(sections: dict[str, list[str]], keys: list[str]) -> list[str]:
|
|
45
|
+
for key in keys:
|
|
46
|
+
if key in sections:
|
|
47
|
+
return sections[key]
|
|
48
|
+
return []
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def parse_tasks(text: str) -> list[dict[str, Any]]:
|
|
52
|
+
tasks: list[dict[str, Any]] = []
|
|
53
|
+
current: dict[str, Any] | None = None
|
|
54
|
+
current_field: str | None = None
|
|
55
|
+
for raw_line in text.splitlines():
|
|
56
|
+
line = raw_line.rstrip()
|
|
57
|
+
task_match = TASK_HEADING_RE.match(line)
|
|
58
|
+
if task_match:
|
|
59
|
+
current = {
|
|
60
|
+
"id": task_match.group(1),
|
|
61
|
+
"title": task_match.group(2).strip(),
|
|
62
|
+
"fields": {},
|
|
63
|
+
}
|
|
64
|
+
tasks.append(current)
|
|
65
|
+
current_field = None
|
|
66
|
+
continue
|
|
67
|
+
if current is None:
|
|
68
|
+
continue
|
|
69
|
+
field_match = FIELD_RE.match(line)
|
|
70
|
+
if field_match:
|
|
71
|
+
key = normalize_field(field_match.group(1))
|
|
72
|
+
current["fields"][key] = field_match.group(2).strip().strip("*").strip()
|
|
73
|
+
current_field = key
|
|
74
|
+
continue
|
|
75
|
+
if current_field and line.strip():
|
|
76
|
+
previous = current["fields"].get(current_field, "")
|
|
77
|
+
current["fields"][current_field] = f"{previous}\n{line.strip()}".strip()
|
|
78
|
+
return tasks
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def expected_files_for(task: dict[str, Any]) -> str:
|
|
82
|
+
fields = task["fields"]
|
|
83
|
+
for key in ("likely_files/modules", "files", "arquivos_verificados", "arquivos", "m_dulos"):
|
|
84
|
+
value = fields.get(key)
|
|
85
|
+
if value:
|
|
86
|
+
return value
|
|
87
|
+
return ""
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def main() -> int:
|
|
91
|
+
parser = argparse.ArgumentParser(description=__doc__)
|
|
92
|
+
parser.add_argument("plan", help="Path to the plan markdown file")
|
|
93
|
+
parser.add_argument("--task-id", action="append", dest="task_ids", default=[], help="Task id to extract, repeatable")
|
|
94
|
+
parser.add_argument("--changed-file", action="append", dest="changed_files", default=[], help="Changed file path, repeatable")
|
|
95
|
+
args = parser.parse_args()
|
|
96
|
+
|
|
97
|
+
text = pathlib.Path(args.plan).read_text(encoding="utf-8")
|
|
98
|
+
sections = parse_sections(text)
|
|
99
|
+
tasks = parse_tasks(text)
|
|
100
|
+
selected = [task for task in tasks if not args.task_ids or task["id"] in args.task_ids]
|
|
101
|
+
|
|
102
|
+
payload = {
|
|
103
|
+
"task_ids": args.task_ids,
|
|
104
|
+
"selected_tasks": selected,
|
|
105
|
+
"changed_files": args.changed_files,
|
|
106
|
+
"expected_files": [expected_files_for(task) for task in selected],
|
|
107
|
+
"execution_metadata": {
|
|
108
|
+
"plan_prefix": "",
|
|
109
|
+
"execution_mode": "",
|
|
110
|
+
},
|
|
111
|
+
"plan_constraints": {
|
|
112
|
+
"rules_and_decisions": first_section(
|
|
113
|
+
sections,
|
|
114
|
+
[
|
|
115
|
+
"project_rules_constraints_and_decisions_already_made",
|
|
116
|
+
"regras_e_restri_es_do_projeto",
|
|
117
|
+
"regras_decis_es",
|
|
118
|
+
"decis_es_fechadas",
|
|
119
|
+
],
|
|
120
|
+
),
|
|
121
|
+
"contracts_invariants_quality": first_section(
|
|
122
|
+
sections,
|
|
123
|
+
["contracts_invariants_and_quality_guarantees", "contratos_e_invariantes"],
|
|
124
|
+
),
|
|
125
|
+
"risk_and_regression": first_section(
|
|
126
|
+
sections,
|
|
127
|
+
["risk_and_regression_matrix", "regression_risks", "matriz_de_risco_e_regress_o", "riscos"],
|
|
128
|
+
),
|
|
129
|
+
"validation": first_section(sections, ["validation", "valida_o", "valida_o_final"]),
|
|
130
|
+
},
|
|
131
|
+
"review_focus": [
|
|
132
|
+
"logic gaps",
|
|
133
|
+
"hidden scenarios",
|
|
134
|
+
"regressions",
|
|
135
|
+
"security risks",
|
|
136
|
+
"missing tests",
|
|
137
|
+
"plan contract drift",
|
|
138
|
+
"source conflict drift",
|
|
139
|
+
"permission matrix drift",
|
|
140
|
+
],
|
|
141
|
+
}
|
|
142
|
+
metadata_section = first_section(
|
|
143
|
+
sections,
|
|
144
|
+
["execution_metadata", "metadados_de_execu_o", "metadados_execu_o"],
|
|
145
|
+
)
|
|
146
|
+
for line in metadata_section:
|
|
147
|
+
lowered = line.lower()
|
|
148
|
+
if "plan prefix" in lowered:
|
|
149
|
+
payload["execution_metadata"]["plan_prefix"] = line.split(":", 1)[-1].strip().strip("`")
|
|
150
|
+
elif "execution mode" in lowered:
|
|
151
|
+
payload["execution_metadata"]["execution_mode"] = line.split(":", 1)[-1].strip().strip("`")
|
|
152
|
+
json.dump(payload, sys.stdout, indent=2)
|
|
153
|
+
sys.stdout.write("\n")
|
|
154
|
+
return 0
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
if __name__ == "__main__":
|
|
158
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: atlas-sprint-prd-generator
|
|
3
|
+
description: Skill `atlas-sprint-prd-generator`. Use quando o usuário pedir para criar, gerar, montar ou atualizar um PRD de Sprint a partir de um sprint ID como S01/S02, usando o template de PRD e o backlog/roadmap real do repositório como fonte de escopo, dependências e fase-fonte.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Atlas Sprint PRD Generator
|
|
7
|
+
|
|
8
|
+
Gere PRDs de Sprint em PT-BR ancorados no backlog/roadmap real, no template canônico empacotado e no código real do repositório atual. Não invente contrato.
|
|
9
|
+
|
|
10
|
+
Todo PRD gerado por esta skill deve declarar explicitamente a cadeia de execução Atlas (`atlas-*`) para consumo posterior por `atlas-plan-handoff` e `atlas-plan-execute`.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Entrada Esperada
|
|
15
|
+
|
|
16
|
+
* Sprint ID: `S<NN>` (`S01`, `S02`, etc.).
|
|
17
|
+
* Opcional: app/projeto alvo quando houver mais de uma fonte de backlog/roadmap.
|
|
18
|
+
* Opcional: path de saída.
|
|
19
|
+
* Opcional: path explícito do backlog autoritativo. Quando fornecido, vence qualquer descoberta.
|
|
20
|
+
|
|
21
|
+
*Se faltar o Sprint ID, peça antes de gerar.*
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Workflow Obrigatório
|
|
26
|
+
|
|
27
|
+
1. **Localizar Insumos:** Descubra a raiz do repo com `git rev-parse --show-toplevel`. Localize o template canônico em `<raiz-do-plugin>/packages/templates/PRD_TEMPLATE.md`. Localize backlogs candidatos (`**/BACKLOG_MESTRE*.md`) sem escolher por heurística silenciosa.
|
|
28
|
+
2. **Fechar autoridade:** use `../_shared/scripts/document_quality.mjs#resolveSprintAuthority` com precedência fixa: path explícito → backlog canônico referenciado pelo artefato/input → único candidato contendo o Sprint ID. Zero match bloqueia. Múltiplos matches sem autoridade, mesmo com conteúdo parecido, bloqueiam com paths conflitantes e `next_action` para informar o path.
|
|
29
|
+
3. **Extração da Sprint:** leia somente a fonte autoritativa. Extraia fase-fonte, objetivo, dependências e filename do PRD; registre no PRD o path + anchor exato da linha/seção do backlog.
|
|
30
|
+
4. **Inspecionar Código:** Busque no codebase por contratos reais que influenciam a feature e registre anchors estáveis (`path:símbolo` ou `path:linha`) nas referências; não copie implementação para o PRD.
|
|
31
|
+
5. **Redação/atualização:** siga `PRD_TEMPLATE.md`. Ao atualizar, preserve IDs `D*`, decisões fechadas, anchors e histórico; novos IDs são append-only. Mudança deliberada em D* exige decisão explícita e registro histórico.
|
|
32
|
+
|
|
33
|
+
### Resolução Canônica de Templates
|
|
34
|
+
|
|
35
|
+
* Fonte única: `packages/templates/` empacotado no plugin Atlas Workflow.
|
|
36
|
+
* Resolver `PRD_TEMPLATE.md` a partir da raiz do plugin/bundle, antes de olhar qualquer arquivo do repo consumidor.
|
|
37
|
+
* Template local do repo consumidor nunca sobrepõe o template empacotado.
|
|
38
|
+
* Se `packages/templates/PRD_TEMPLATE.md` não existir, abortar com erro claro: `Template canônico ausente: PRD_TEMPLATE.md`.
|
|
39
|
+
* Não usar fallback silencioso para cópias antigas, vault local ou templates globais.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Metadados Atlas Obrigatórios
|
|
44
|
+
|
|
45
|
+
Todo PRD criado ou atualizado por esta skill deve incluir, perto do topo e sem substituir o template, o seguinte bloco de metadados:
|
|
46
|
+
|
|
47
|
+
```md
|
|
48
|
+
## Metadados de execução
|
|
49
|
+
- Plan prefix: `atlas`
|
|
50
|
+
- Target planner: `atlas-plan-handoff`
|
|
51
|
+
- Target executor: `atlas-plan-execute`
|
|
52
|
+
- Internal validator: `atlas-task-validator`
|
|
53
|
+
- External review: `atlas-slice-review` (optional)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Regras de Conteúdo
|
|
59
|
+
|
|
60
|
+
* **Status final:** `Aprovado para implementação`. Setar **automaticamente** ao finalizar a geração — é o status que o gate TC do orquestrador exige (`required_status=Aprovado para implementação`) para o PRD avançar no pipeline. Não deixar `Draft` (trava o gate e força correção manual). O sinal de determinismo que sustenta o avanço é o `atlas_scan_prd` (varredura de ambiguidade) + entrevista quando houver padrões bloqueantes — não o campo Status, que é marcador documental.
|
|
61
|
+
* **Data:** ISO `YYYY-MM-DD` (hoje).
|
|
62
|
+
* **Autoridade:** `Relacionado`/`Referências` inclui backlog autoritativo + anchor da sprint e anchors de código/contrato usados.
|
|
63
|
+
* **Escopo:** Lista fechada de capacidades funcionais.
|
|
64
|
+
* **UX:** Cobrir caminhos de `loading`, `empty`, `error`, `success` e `permission` sob a perspectiva do usuário.
|
|
65
|
+
* **Critérios de Aceite:** Binários e observáveis, divididos conforme `PRD_TEMPLATE.md` em: **Produto**, **UX**, **Dados** e **Regressão de produto**.
|
|
66
|
+
* **Proibições Estritas:**
|
|
67
|
+
* Não inventar schemas, RPCs, endpoints ou tabelas.
|
|
68
|
+
* Não misturar plano de implementação, classes Dart, imports, clean architecture ou comandos de terminal com o PRD. Seguir estritamente o `BOUNDARY_PRD_PLAN.md`.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Validação Mínima
|
|
73
|
+
|
|
74
|
+
Antes de salvar:
|
|
75
|
+
* Confirme que todas as seções do template estão presentes.
|
|
76
|
+
* Garanta que o bloco de `Metadados de execução` existe e está preenchido com `atlas`.
|
|
77
|
+
* Certifique-se de que não há nomes de classes de código ou arquivos Dart dentro do PRD.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
interface:
|
|
2
|
+
display_name: "Atlas Sprint PRD Generator"
|
|
3
|
+
short_description: "Gera PRDs de Sprint com prefixo atlas-*"
|
|
4
|
+
default_prompt: "Use $atlas-sprint-prd-generator para criar o PRD da sprint S01 com metadados de execução atlas-* a partir do backlog mestre e do PRD template reais."
|
|
5
|
+
|
|
6
|
+
policy:
|
|
7
|
+
allow_implicit_invocation: true
|