@orchestrator-claude/definitions 3.37.2 → 3.38.0
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/agents/agentic-architect.md +174 -0
- package/agents/architecture-mediator.md +214 -0
- package/agents/azure-devops-engineer.md +2 -2
- package/agents/backend-architect.md +198 -0
- package/agents/cicd-platform-engineer.md +3 -2
- package/agents/contract-architect.md +210 -0
- package/agents/datamodel-architect.md +202 -0
- package/agents/frontend-architect.md +166 -0
- package/agents/frontend-engineer.md +10 -7
- package/agents/harness-architect.md +51 -32
- package/agents/harness-engineer.md +175 -0
- package/agents/implementer.md +10 -1
- package/agents/infra-architect.md +160 -0
- package/agents/operational-artifact-builder.md +1 -1
- package/agents/python-data-engineer.md +5 -4
- package/agents/software-architect.md +29 -147
- package/hooks/hooks.json +2 -2
- package/hooks/pre-agent-dispatch.mjs +3 -1
- package/hooks/pre-agent-dispatch.ts +2 -0
- package/hooks/subagent-start.ts +3 -1
- package/manifest.json +94 -14
- package/package.json +1 -1
- package/skills/arquitetura-lane-dispatch/SKILL.md +205 -0
- package/skills/arquitetura-mediada-arquiteto/SKILL.md +244 -0
- package/skills/checkpoint-protocol/SKILL.md +1 -1
- package/skills/fase-1b-projecao/SKILL.md +127 -11
- package/skills/orchestrator/SKILL.md +1 -1
- package/skills/release/release.sh +63 -6
|
@@ -12,6 +12,9 @@ item), cita o documento, mede os itens e carrega o `sha256` dele.
|
|
|
12
12
|
|
|
13
13
|
Marcas: `[M]` medido · `[S]` síntese nossa · `[U]` decidido pelo usuário · `[L]` lacuna aberta.
|
|
14
14
|
|
|
15
|
+
Referências S523 (primeira corrida sobre PRD de autoria, repo do produto `ac4bb439`):
|
|
16
|
+
`PRD-001-v2-Z-1B-S523.md` (Z-23..Z-28) e `COMPARACAO-1B-BRACOS-S523.md` (Z-29, Z-30).
|
|
17
|
+
|
|
15
18
|
---
|
|
16
19
|
|
|
17
20
|
## 1 · O que esta fase NÃO promete — leia antes de tudo
|
|
@@ -19,6 +22,9 @@ Marcas: `[M]` medido · `[S]` síntese nossa · `[U]` decidido pelo usuário ·
|
|
|
19
22
|
`[M]` **Granularidade não é propriedade do PRD.** Medido na S475 com réplica exata — mesma fonte,
|
|
20
23
|
mesmo pedido, mesma árvore, **zero variáveis**: 55 stories numa execução e **78** na outra, +42%.
|
|
21
24
|
Quatro derivações do mesmo PRD deram **33 · 66 · 55 · 78** stories e **8 · 12 · 11 · 15** épicos.
|
|
25
|
+
`[M]` Réplicas exatas (mesma fonte, mesmo pedido, dois braços): **55 · 78** (S475), **75 · 75**
|
|
26
|
+
(S514, PRD-001 E9), **78 · 75** com **12 · 12** épicos (S523, PRD-001-v2 do produto). O 75 · 75
|
|
27
|
+
sozinho engana; o 12 · 12 com 78 · 75 mostra que épicos podem sair estáveis enquanto stories não.
|
|
22
28
|
|
|
23
29
|
Consequências operacionais, e nenhuma se conserta melhorando o prompt:
|
|
24
30
|
|
|
@@ -48,6 +54,14 @@ Consequências operacionais, e nenhuma se conserta melhorando o prompt:
|
|
|
48
54
|
> devolve byte a byte. Não presuma que só resta a fonte de hoje — o controle do experimento
|
|
49
55
|
> costuma já existir.
|
|
50
56
|
|
|
57
|
+
`[M]` **Primeira projeção de um PRD: não há versão anterior, e os passos 3-4 não são executáveis
|
|
58
|
+
com um braço só.** O controle é uma **réplica** — segundo braço, mesma fonte, mesmo pedido (sha
|
|
59
|
+
igual), worktree própria, e o braço 1 ausente da worktree do braço 2. O passo 3 vira comparação
|
|
60
|
+
**por item** entre braços (escolha os itens antes de abrir o segundo — S523 escolheu 5) e o passo 4
|
|
61
|
+
se decide pelo que a réplica devolve. Sem segundo braço o artefato fica `[L]` "derivabilidade não
|
|
62
|
+
medida" — não é falha, é declaração. Rodar o segundo braço custa uma derivação e é decisão do PM
|
|
63
|
+
(S514 §6 "n = 2 por fonte"; S523 D-043 e Z-28).
|
|
64
|
+
|
|
51
65
|
---
|
|
52
66
|
|
|
53
67
|
## 3 · O pedido literal — e o que **não** pode entrar nele
|
|
@@ -70,6 +84,20 @@ Escreva a saída em <SAIDA>, markdown único, com esta estrutura:
|
|
|
70
84
|
Quantos épicos e quantas stories saem é resultado, não meta.
|
|
71
85
|
```
|
|
72
86
|
|
|
87
|
+
`[M]` **O pedido congelado guarda os placeholders, não os caminhos.** `<PRD>` e `<SAIDA>` viram
|
|
88
|
+
caminhos absolutos de scratchpad no despacho (o `Agent` não tem `cwd`; o `claude -p` tem `cd <WT>`),
|
|
89
|
+
e um pedido com caminho inlinado só é re-executável nesta sessão — e dois braços viram dois shas
|
|
90
|
+
por uma linha (S523 Z-26: `5f742fc7` ≠ `6a256fbb`). Convenção: **um** arquivo de pedido, com o
|
|
91
|
+
texto acima intacto e o `sha256` **do texto com placeholders**, mais uma tabela de binding por
|
|
92
|
+
braço: `braço · sha256 da fonte · <PRD> resolvido · <SAIDA> resolvido · commit da worktree` (é a
|
|
93
|
+
forma do `PRD-001-EPICOS-E-US-S514-PEDIDO.md`). "Mesmo pedido" = mesmo sha do texto; o que difere
|
|
94
|
+
entre braços mora na tabela.
|
|
95
|
+
|
|
96
|
+
`[S]` **Nomes.** Worktree `<tmp>/wt-<braço>` (`a`, `b`, …); saída dentro da worktree com nome
|
|
97
|
+
**neutro** (`saida.md` — o nome é contaminação residual, S514 §5 item 4); ao promover,
|
|
98
|
+
`<PRD-base>-<braço>.md` (S523 Z-29 usou `-b2`). `[L]` O diretório de promoção segue sem regra na
|
|
99
|
+
`.docs-constitution.yaml` (S513 §5 item 14) — declare o que escolheu.
|
|
100
|
+
|
|
73
101
|
`[S]` **O que fica de fora, e é a decisão que faz o teste valer.** Regras de conteúdo que a
|
|
74
102
|
projeção anterior declarava — *ator é posição e não cargo*, *nenhuma story nomeia mecanismo*,
|
|
75
103
|
*nada por inferência* — **não entram**, mesmo citando o PRD. Se estão mesmo na fonte, o derivador
|
|
@@ -87,22 +115,92 @@ contrato medem; não há como remover sem perder a comparabilidade.
|
|
|
87
115
|
|
|
88
116
|
## 4 · Executor e isolamento
|
|
89
117
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
118
|
+
`[U]` **Executor decidido: `claude -p --setting-sources project` de dentro da worktree saneada**
|
|
119
|
+
(D-054, PM, 2026-09-21, via Manager — alternativa C do `ASSESSMENT-FASE1B-Z23-Z30-S522.md` §4).
|
|
120
|
+
Não é mais `general-purpose` via `Agent`: esse executor nasce com o contexto da sessão que o
|
|
121
|
+
despacha e foi medido contaminado duas vezes (S513 item 1 citou as autorais verbatim; S523 Z-24
|
|
122
|
+
recebeu as Regras 1-3 do produto) — alternativa A, rejeitada. `[S]` Pela mesma razão não se
|
|
123
|
+
despacha por `specifier` nem `task-generator`: corpo calibrado empurra a derivação para um molde
|
|
124
|
+
que não é do PRD, contaminando o eixo que se quer medir. `[L]` `claude -p --bare` seria "nada além
|
|
125
|
+
do pedido", mas exige `ANTHROPIC_API_KEY` (não lê OAuth; S513 §5 item 13) — fora de alcance hoje.
|
|
94
126
|
|
|
95
127
|
**Isolamento por construção, não por instrução.** `[M]` Instruir "não olhe a projeção anterior"
|
|
96
128
|
depende do agente obedecer. Derivar numa **worktree de um commit anterior à promoção** dela não
|
|
97
129
|
depende de nada: o arquivo não existe lá.
|
|
98
130
|
|
|
99
131
|
```bash
|
|
100
|
-
|
|
101
|
-
git
|
|
102
|
-
git
|
|
132
|
+
# 1. ache o commit anterior a promocao da projecao anterior (ou do primeiro arquivo que cita EP-/US-)
|
|
133
|
+
git log --diff-filter=A --format='%h %s' -- <projecao-ou-arquivo-que-bate> | tail -1 # -> <C>
|
|
134
|
+
git worktree add --detach <tmp>/wt-<braco> <C>^ # commit ANTERIOR ao que adicionou
|
|
135
|
+
git show HEAD:<PRD> > <tmp>/wt-<braco>/<PRD> # so a fonte e trocada
|
|
136
|
+
git grep -l 'EP-0[1-9]\|US-0[1-9]\.' <C>^ -- ':!*agent-memory*' # esperado: vazio (exit 1)
|
|
137
|
+
git grep -l 'EP-0[1-9]\|US-0[1-9]\.' HEAD -- ':!*agent-memory*' # controle positivo: NAO vazio
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
`[M]` O último par de comandos é o que transforma "isolado" em **medido**: vazio no commit da
|
|
141
|
+
worktree **e** não-vazio em `HEAD`. Em `HEAD` o grep **bate sempre** que o repo tiver um relatório
|
|
142
|
+
de comparação (todo repo que roda esta fase mais de uma vez tem) — se bater, **recue ao commit
|
|
143
|
+
anterior ao arquivo que bate** (`<C>^`) e repita; não é falha, é o controle positivo funcionando.
|
|
144
|
+
Rode os dois e cole a saída. *(S513 §5 item 5; S514-PEDIDO l.53-58; S523 Z-23: `0730d9da` bateu em
|
|
145
|
+
1 arquivo, `ddc0ed2^ = a929a22` vazio.)*
|
|
146
|
+
|
|
147
|
+
`[M]` **A prova da árvore não cobre o executor.** O `git grep` acima mede o que existe na worktree;
|
|
148
|
+
não mede o que o harness injeta no derivador. Medido: `general-purpose` via `Agent` nasce com o
|
|
149
|
+
`CLAUDE.md` do role/sessão (S513, citou as autorais verbatim) e com o `CLAUDE.md` do repo (S523
|
|
150
|
+
Z-24, Regras 1-3 do produto); `claude -p --setting-sources project` de dentro da worktree recebe o
|
|
151
|
+
`CLAUDE.md` do repo e os plugins do `.claude/settings.json` dele (TD-316) — e `--tools` **não**
|
|
152
|
+
filtra as MCP, só as nativas. É por isso que a worktree é **saneada** antes do despacho:
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
# 2. saneie a worktree (a fonte nao e tocada; o grep de isolamento acima roda no COMMIT, nao na arvore)
|
|
156
|
+
rm <WT>/CLAUDE.md <WT>/.claude/settings.json <WT>/.mcp.json
|
|
157
|
+
git -C <WT> status --short # esperado: exatamente os 3 " D " de governanca — declare-os no cabecalho
|
|
158
|
+
# 3. despache (S513-PEDIDO l.55-63, SEM --no-session-persistence: o transcript e a prova)
|
|
159
|
+
cd <WT> && claude -p \
|
|
160
|
+
--setting-sources project \
|
|
161
|
+
--tools "Read,Write,Grep,Glob" \
|
|
162
|
+
--permission-mode acceptEdits \
|
|
163
|
+
--model 'claude-opus-5[1m]' \
|
|
164
|
+
--output-format json \
|
|
165
|
+
"<pedido da §3, com <PRD> e <SAIDA> substituídos>" # guarde o session_id do JSON de saida
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
`[S]` A árvore passa a divergir do commit em **três arquivos de governança** — nem a fonte nem a
|
|
169
|
+
saída; declare os três no cabeçalho do artefato (§6). O `rm` não toca o repo: é a working tree de
|
|
170
|
+
`<C>^` com a fonte trocada, e `git worktree remove` a desfaz.
|
|
171
|
+
|
|
172
|
+
`[M]` **A prova do executor é o transcript persistido** (`.jsonl` da sessão do derivador). Ele fica
|
|
173
|
+
em `~/.claude/projects/<cwd com "/" trocada por "-">/<session_id>.jsonl`. Cole os três:
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
J=~/.claude/projects/<cwd-codificado>/<session_id>.jsonl
|
|
177
|
+
# (a) roster: esperado = so as 4 de --tools; mcp__ = 0
|
|
178
|
+
jq -r 'select(.attachment.type=="prompt_snapshot") | .attachment.tools[]?.name' "$J" | sort -u \
|
|
179
|
+
| awk '{t++} /^mcp__/{m++} END{print "total="t+0, "mcp__="m+0}'
|
|
180
|
+
# (b) contexto inicial = o registro "instructions" (arquivos injetados, por tipo) + o proprio pedido.
|
|
181
|
+
# esperado: NENHUM "Project" (o CLAUDE.md do repo) e 0 EP-/US- no que foi injetado
|
|
182
|
+
jq -r 'select(.attachment.type=="instructions") | .attachment.files[] | "\(.type) \(.path) \(.content|length)B"' "$J"
|
|
183
|
+
jq -r 'select(.attachment.type=="instructions") | .attachment.files[].content' "$J" | grep -c 'EP-0\|US-0'
|
|
184
|
+
# (c) cada Read: esperado = so <PRD>
|
|
185
|
+
jq -r 'select(.type=="assistant") | .message.content[]? | select(.type=="tool_use")
|
|
186
|
+
| "\(.name) \(.input.file_path // "")"' "$J" | sort | uniq -c
|
|
103
187
|
```
|
|
104
188
|
|
|
105
|
-
|
|
189
|
+
Sem transcript, "nenhum outro documento foi consultado" é autorrelato (S513 §5 item 12). `[M]`
|
|
190
|
+
Medido na S523 (harness `2.1.278`, worktree de `a8121ba2` do repo do harness, sonda de 1 prompt):
|
|
191
|
+
saneada → roster **4, `mcp__` 0**, `instructions` sem `Project`, hook 0 (sessão `7dd2882a`); a
|
|
192
|
+
mesma árvore **sem** o `rm` → roster 68, `mcp__` 64 (serena 29, playwright 25, Claude Docs 8,
|
|
193
|
+
context7 2), `Project` = `CLAUDE.md` do repo, `hook_success` 2 (sessão `5a825395`). É o
|
|
194
|
+
falsificador de TD-316 §4 satisfeito nesta versão do harness; um harness em que o roster **não**
|
|
195
|
+
zere na worktree saneada derruba esta seção — meça antes de derivar, não depois. *(S523 Z-24; D-054.)*
|
|
196
|
+
|
|
197
|
+
`[L]` **Canal residual que C não fecha, declarado:** o registro `instructions` da worktree saneada
|
|
198
|
+
ainda carrega **um** arquivo `AutoMem` — o `MEMORY.md` da auto-memória do repo
|
|
199
|
+
(`~/.claude/projects/<repo>/memory/MEMORY.md`), que mora **fora** da worktree e o `rm` não alcança
|
|
200
|
+
(a worktree resolve para o diretório de projeto do repo-mãe). `[M]` S523: 1810 B, **0** `EP-`/`US-`,
|
|
201
|
+
nos dois braços; o braço B da S514 (harness anterior) não o tinha. Enquanto a lacuna estiver aberta,
|
|
202
|
+
o snippet (b) é a prova: cole a linha `AutoMem …` e o `0`; se der > 0, a derivação está contaminada
|
|
203
|
+
por esse canal e a decisão de fechá-lo (não é saneamento de árvore, é memória do usuário) é do PM.
|
|
106
204
|
|
|
107
205
|
---
|
|
108
206
|
|
|
@@ -113,9 +211,16 @@ Use os comandos que o contrato registra, nunca os inventados na hora:
|
|
|
113
211
|
```bash
|
|
114
212
|
grep -cE '^## EP-' <projecao> # epicos
|
|
115
213
|
grep -cE '^### US-' <projecao> # stories
|
|
116
|
-
grep -oE '§[0-9]+(\.[0-9]
|
|
214
|
+
grep -oE '§[0-9]+(\.[0-9]+|\.[A-Z]\b)*' <corpo> | sort -u # cobertura por referente (canonico)
|
|
215
|
+
# <corpo> = corpo derivado entre os marcadores (§6), NAO o arquivo com cabecalho — regra D-018 abaixo
|
|
117
216
|
```
|
|
118
217
|
|
|
218
|
+
`[M]` **Sub-área com letra** (`§7.A`) existe em PRD de autoria (S523 Z-25: 11 referentes pelo padrão
|
|
219
|
+
só-numérico, 21 com letra — a D-018 ficaria cega). O padrão acima é o **canônico único**; é
|
|
220
|
+
superconjunto do anterior e devolve os mesmos números nas projeções desta casa (62 · 65 · 73,
|
|
221
|
+
medido). `\b` evita casar `§7.A` em "§7.Além". Não existem dois instrumentos: quando alguém medir
|
|
222
|
+
com outro padrão, o número dele não entra na D-018.
|
|
223
|
+
|
|
119
224
|
> `[M]` **Para medir se o delta da fonte atravessou, olhe o ITEM que a emenda tocou — nunca o
|
|
120
225
|
> agregado.** Medido S475: contagem e sobreposição de referentes não distinguem troca de fonte de
|
|
121
226
|
> ruído (réplica pura dá 95%/88%; trocar a fonte dá 85–91% — dentro do ruído). O mesmo delta
|
|
@@ -123,8 +228,10 @@ grep -oE '§[0-9]+(\.[0-9]+)*' <projecao> | sort -u # cobertura por referente
|
|
|
123
228
|
> fonte velha e como *requisito* nas **duas** réplicas da fonte nova. O agregado afoga o sinal.
|
|
124
229
|
|
|
125
230
|
`[U]` **Quando há mais de um braço válido da mesma fonte, promove-se o de maior cobertura de
|
|
126
|
-
referentes únicos do PRD
|
|
127
|
-
|
|
231
|
+
referentes únicos do PRD — medida com o padrão canônico de §5, sobre o corpo derivado entre
|
|
232
|
+
marcadores (§6), nunca sobre o arquivo com cabeçalho (S514: 68 no corpo, 73 no arquivo); empate →
|
|
233
|
+
o que terminou primeiro.** Regra do PM, D-018 (S514) — antes dela a escolha era arbitrária e
|
|
234
|
+
declarada como tal. *(S523 Z-30.)*
|
|
128
235
|
|
|
129
236
|
---
|
|
130
237
|
|
|
@@ -138,6 +245,15 @@ Regra do PM, D-018 (S514) — antes dela a escolha era arbitrária e declarada c
|
|
|
138
245
|
**vira** o registro; guardá-lo depois depende de lembrar, e a primeira execução desta fase nesta
|
|
139
246
|
casa não lembrou.
|
|
140
247
|
|
|
248
|
+
`[M]` **Onde J4 mora, e o que "nunca editar à mão" cobre.** O executor não sabe commit nem sha do
|
|
249
|
+
pedido (por desenho). O arquivo promovido tem **cabeçalho** (J4: commit, sha da fonte, sha do
|
|
250
|
+
pedido, executor com modelo/versão/flags) e **anexos** fora de dois marcadores HTML —
|
|
251
|
+
`<!-- CORPO-DERIVADO-INICIO … sha256 <sha do corpo> -->` e `<!-- CORPO-DERIVADO-FIM -->` — e o
|
|
252
|
+
**corpo derivado verbatim** entre eles. Registram-se **dois** shas: o do corpo (é o que a
|
|
253
|
+
re-derivação compara e o que a D-018 mede) e o do arquivo. "Nunca editar à mão" (§7) é sobre o
|
|
254
|
+
corpo; extraia-o com `awk` ancorado em `^<!-- ` (não pelo texto do marcador, que recorre na prosa —
|
|
255
|
+
S513 §6). *(Prática desde S513; S514 §5 item 10; S523 Z-27 chegou à mesma forma sem a skill dizer.)*
|
|
256
|
+
|
|
141
257
|
---
|
|
142
258
|
|
|
143
259
|
## 7 · Erro de classe a evitar
|
|
@@ -101,7 +101,7 @@ Sub-agents MUST persist artifacts to MinIO via `artifactStore` (universal rule,
|
|
|
101
101
|
|
|
102
102
|
#### 2c.1 Checkpoint + Commit Policy dispatch addenda (TD-S188-002 + TD-S192-003)
|
|
103
103
|
|
|
104
|
-
**Scope (TD-S192-003 amendment; set re-verified TD-171/S290):** this block applies to **any agent whose tool list includes `mcp__orchestrator-tools__createCheckpoint`**. As of **
|
|
104
|
+
**Scope (TD-S192-003 amendment; set re-verified TD-171/S290):** this block applies to **any agent whose tool list includes `mcp__orchestrator-tools__createCheckpoint`**. As of **S531 the ground-truth set (the `tools:` line of `packages/definitions/agents/*.md` holding `createCheckpoint`) is the 9 agents**: `implementer`, `azure-devops-engineer`, `presentation-engineer`, `operational-artifact-builder`, `cicd-platform-engineer`, `python-data-engineer`, `frontend-engineer`, `ciclo-engineer`, `harness-engineer`. (`ciclo-engineer` and `harness-engineer` were added in S531 — D-137/D-153; the first had carried the tool, unlisted, since before the lane 3.) (The earlier S195 list was stale — it named `methodology-researcher`, which no longer holds the tool, and omitted `cicd-platform-engineer` / `python-data-engineer` / `frontend-engineer`, added later.) **Keep this set in sync with `COMMITTING_AGENTS` in `packages/definitions/hooks/pre-agent-dispatch.ts`** (and its mirrors, propagated by `npm run sync:hooks`), with the identity's MUST 5 and with `/checkpoint-protocol` (the branch-before-dispatch hook, §2c.0) — both derive from the same `createCheckpoint`-holder ground truth; when an agent gains/loses `createCheckpoint`, update both. **Match this set ignoring any plugin prefix** (`orchestrator:implementer` ≡ `implementer`) — the hook already does so via `normalizeAgentName()` (S398); membership is a property of the agent, not of the topology that names it. The earlier version of this section was implementer-only; subsequent sessions (S192 PME phase 2, S194 bug_fix, S195 lint sweep) confirmed the same `createCheckpoint=git-commit` conflation appears across other agents that hold the tool — making the rule agent-agnostic from S195 forward.
|
|
105
105
|
|
|
106
106
|
When dispatching any of those agents, the generic template above is **insufficient**. The S188 implement phase originally surfaced the ambiguity: the implementer interpreted `createCheckpoint` as requiring a git commit beforehand, producing 4 unsolicited commits per dispatch (commit prefix also leaked from BACKLOG context: `feat(s186)` instead of `feat(s188)`). Empirical evidence preserved across sessions:
|
|
107
107
|
|
|
@@ -361,6 +361,53 @@ run_build() {
|
|
|
361
361
|
log_success "Build completed - dist/ updated with latest templates"
|
|
362
362
|
}
|
|
363
363
|
|
|
364
|
+
# Put the committed hook bundles back after run_build (S532, D-175).
|
|
365
|
+
# The local build rewrites every packages/definitions/hooks/*.mjs — only the esbuild
|
|
366
|
+
# source-path comments change ("// packages/definitions/hooks/x.ts" -> "// hooks/x.ts"),
|
|
367
|
+
# even with a real node_modules. The .mjs are NOT staged by commit_version_bump, but
|
|
368
|
+
# regenerate_definitions_manifest hashes them, so without this step the bumped manifest
|
|
369
|
+
# carries sha256 of bytes that are not in the repo (v3.37.3 shipped 0/15 hook checksums
|
|
370
|
+
# matching). validate_working_tree guarantees HEAD is the state being released.
|
|
371
|
+
restore_committed_hook_bundles() {
|
|
372
|
+
echo "♻️ Restoring committed hook bundles (hooks/*.mjs) after build..."
|
|
373
|
+
|
|
374
|
+
if [ "$DRY_RUN" = true ]; then
|
|
375
|
+
echo " [dry-run] Would run: git checkout HEAD -- packages/definitions/hooks/*.mjs"
|
|
376
|
+
return
|
|
377
|
+
fi
|
|
378
|
+
|
|
379
|
+
local bundles
|
|
380
|
+
bundles=$(git ls-files 'packages/definitions/hooks/*.mjs')
|
|
381
|
+
if [ -z "$bundles" ]; then
|
|
382
|
+
log_error "No committed hook bundles found under packages/definitions/hooks/"
|
|
383
|
+
exit 1
|
|
384
|
+
fi
|
|
385
|
+
|
|
386
|
+
# shellcheck disable=SC2086
|
|
387
|
+
git checkout HEAD -- $bundles
|
|
388
|
+
|
|
389
|
+
log_success "Hook bundles restored to HEAD ($(echo "$bundles" | wc -l | tr -d ' ') files)"
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
# Guard: every hook checksum in the regenerated manifest must be the sha256 of the
|
|
393
|
+
# .mjs blob committed at HEAD — the bytes the release actually ships. Aborts before
|
|
394
|
+
# commit_version_bump if any diverges (TD-330: CI rebuilds the .mjs before testing,
|
|
395
|
+
# so it never judges the committed ones; this is the only check on them).
|
|
396
|
+
verify_manifest_hook_checksums() {
|
|
397
|
+
node -e '
|
|
398
|
+
const { execFileSync } = require("node:child_process");
|
|
399
|
+
const { createHash } = require("node:crypto");
|
|
400
|
+
const hooks = require("./packages/definitions/manifest.json").definitions.hooks;
|
|
401
|
+
const bad = hooks.filter((h) => {
|
|
402
|
+
const blob = execFileSync("git", ["show", `HEAD:packages/definitions/${h.file}`]);
|
|
403
|
+
return `sha256:${createHash("sha256").update(blob).digest("hex")}` !== h.checksum;
|
|
404
|
+
});
|
|
405
|
+
console.log(`${hooks.length - bad.length}/${hooks.length}`);
|
|
406
|
+
for (const h of bad) console.error(` checksum != HEAD blob: ${h.file}`);
|
|
407
|
+
process.exit(bad.length === 0 && hooks.length > 0 ? 0 : 1);
|
|
408
|
+
'
|
|
409
|
+
}
|
|
410
|
+
|
|
364
411
|
# Regenerate packages/definitions/manifest.json AFTER the version bump (TD-193).
|
|
365
412
|
# run_build already regenerates the manifest, but it runs BEFORE update_all_versions,
|
|
366
413
|
# so at that point the manifest still carries the OLD version. generate-manifest sources
|
|
@@ -389,6 +436,13 @@ regenerate_definitions_manifest() {
|
|
|
389
436
|
exit 1
|
|
390
437
|
fi
|
|
391
438
|
|
|
439
|
+
local hook_match
|
|
440
|
+
if ! hook_match=$(verify_manifest_hook_checksums); then
|
|
441
|
+
log_error "Manifest hook checksums do not match the committed hooks/*.mjs ($hook_match)"
|
|
442
|
+
exit 1
|
|
443
|
+
fi
|
|
444
|
+
log_success "Manifest hook checksums match committed bundles ($hook_match)"
|
|
445
|
+
|
|
392
446
|
log_success "Manifest regenerated and version-synced to $manifest_version"
|
|
393
447
|
}
|
|
394
448
|
|
|
@@ -510,12 +564,14 @@ main() {
|
|
|
510
564
|
echo ""
|
|
511
565
|
echo "Actions:"
|
|
512
566
|
echo " 1. Build project (update dist/ with latest templates)"
|
|
513
|
-
echo " 2.
|
|
514
|
-
echo " 3.
|
|
515
|
-
echo " 4.
|
|
516
|
-
echo "
|
|
517
|
-
echo "
|
|
518
|
-
echo "
|
|
567
|
+
echo " 2. Restore committed hook bundles (hooks/*.mjs) the build rewrote"
|
|
568
|
+
echo " 3. Update version in all files"
|
|
569
|
+
echo " 4. Regenerate definitions manifest from bumped version (TD-193)"
|
|
570
|
+
echo " and assert its hook checksums match the committed .mjs"
|
|
571
|
+
echo " 5. Commit version bump"
|
|
572
|
+
echo " 6. Create git tag $tag"
|
|
573
|
+
echo " 7. Push main + tag to origin"
|
|
574
|
+
echo " 8. CI/CD pipeline will publish npm + Docker"
|
|
519
575
|
echo ""
|
|
520
576
|
|
|
521
577
|
if [ "$FORCE" = false ] && [ "$DRY_RUN" = false ]; then
|
|
@@ -529,6 +585,7 @@ main() {
|
|
|
529
585
|
|
|
530
586
|
# Execute release steps
|
|
531
587
|
run_build
|
|
588
|
+
restore_committed_hook_bundles
|
|
532
589
|
update_all_versions "$new_version"
|
|
533
590
|
regenerate_definitions_manifest
|
|
534
591
|
commit_version_bump "$new_version"
|