wizz-method 2.21.0 → 2.22.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.
Files changed (80) hide show
  1. package/THIRD-PARTY-NOTICES.md +18 -0
  2. package/package.json +4 -2
  3. package/skills-registry.yaml +41 -0
  4. package/src/bmm-skills/1-analysis/wizz-set-feature/SKILL.md +1 -1
  5. package/src/bmm-skills/4-implementation/wizz-code-review/SKILL.md +1 -1
  6. package/src/bmm-skills/4-implementation/wizz-create-story/SKILL.md +1 -1
  7. package/src/bmm-skills/4-implementation/wizz-dev-story/SKILL.md +8 -1
  8. package/src/bmm-skills/4-implementation/wizz-quick-dev/SKILL.md +2 -2
  9. package/src/bmm-skills/4-implementation/wizz-quick-dev/step-03-implement.md +2 -0
  10. package/src/bmm-skills/4-implementation/wizz-sprint-status/SKILL.md +1 -1
  11. package/src/core-skills/wizz-party-mode/customize.toml +3 -3
  12. package/src/modules/lowticket/skills/wizz-lowticket-trafego/references/reguas.md +2 -0
  13. package/src/modules/wizz/_shared/cerebro.md +1 -1
  14. package/src/modules/wizz/_shared/organizacao.md +2 -2
  15. package/src/modules/wizz/agents/wizz-copy/SKILL.md +1 -0
  16. package/src/modules/wizz/agents/wizz-copy/customize.toml +5 -0
  17. package/src/modules/wizz/agents/wizz-copy/knowledge/playbook.md +2 -1
  18. package/src/modules/wizz/agents/wizz-social/knowledge/blueprint-roteiro-viral.md +14 -0
  19. package/src/modules/wizz/agents/wizz-social/knowledge/legenda-instagram.md +12 -0
  20. package/src/skills-lib/wizz-cerebro/SKILL.md +18 -5
  21. package/src/skills-lib/wizz-design-needs/SKILL.md +7 -0
  22. package/src/skills-lib/wizz-design-needs/references/design-state.md +34 -2
  23. package/src/skills-lib/wizz-design-needs/references/gap-analysis.md +1 -1
  24. package/src/skills-lib/wizz-design-needs/scripts/design_state.py +305 -0
  25. package/src/skills-lib/wizz-design-needs/scripts/tests/test_design_state.py +143 -0
  26. package/src/skills-lib/wizz-impeccable/references/design-rules.md +18 -0
  27. package/src/skills-lib/wizz-motion-3d-director/references/motion-paths.md +2 -0
  28. package/src/skills-lib/wizz-paid-ads/SKILL.md +2 -1
  29. package/src/skills-lib/wizz-premium-landing-ui-researcher/SKILL.md +6 -2
  30. package/src/skills-lib/wizz-premium-landing-ui-researcher/references/audit-protocol.md +7 -34
  31. package/src/skills-lib/wizz-premium-landing-ui-researcher/references/component-sources.md +2 -0
  32. package/src/skills-lib/wizz-premium-landing-ui-researcher/references/design-sources.yaml +252 -0
  33. package/src/skills-lib/wizz-premium-landing-ui-researcher/references/mandatory-process.md +1 -1
  34. package/src/skills-lib/wizz-premium-landing-ui-researcher/references/mining-rubric.md +123 -0
  35. package/src/skills-lib/wizz-premium-landing-ui-researcher/references/source-first-protocol.md +10 -4
  36. package/src/skills-lib/wizz-premium-landing-ui-researcher/references/web-access-and-evidence.md +1 -1
  37. package/src/skills-lib/wizz-premium-landing-ui-researcher/scripts/design_sources.py +221 -0
  38. package/src/skills-lib/wizz-premium-landing-ui-researcher/scripts/tests/test_design_sources.py +130 -0
  39. package/src/skills-lib/wizz-router/references/routing-table-flat.md +2 -0
  40. package/src/skills-lib/wizz-taste-skill/references/anti-slop-tells.md +8 -0
  41. package/src/skills-lib/wizz-ui-component-curator/SKILL.md +8 -7
  42. package/src/skills-lib/wizz-video-effects/LICENSE-motionmaxxing.txt +202 -0
  43. package/src/skills-lib/wizz-video-effects/SKILL.md +5 -2
  44. package/src/skills-lib/wizz-video-effects/assets/chrome/collect_layout.js +113 -0
  45. package/src/skills-lib/wizz-video-effects/assets/effects.config.template.json +35 -0
  46. package/src/skills-lib/wizz-video-effects/references/data-contract.md +30 -1
  47. package/src/skills-lib/wizz-video-effects/references/gates.md +3 -1
  48. package/src/skills-lib/wizz-video-effects/scripts/check_chrome.py +376 -0
  49. package/src/skills-lib/wizz-video-effects/scripts/check_dead_frames.py +193 -0
  50. package/src/skills-lib/wizz-video-effects/scripts/config.py +13 -0
  51. package/src/skills-lib/wizz-video-effects/scripts/test_chrome.py +181 -0
  52. package/src/skills-lib/wizz-video-effects/scripts/test_dead_frames.py +171 -0
  53. package/src/skills-lib/wizz-video-styles/SKILL.md +6 -2
  54. package/src/skills-lib/wizz-video-styles/references/motion-laws.md +62 -0
  55. package/src/skills-lib/wizz-video-styles/references/styles/desafio-numero.md +1 -0
  56. package/src/skills-lib/wizz-video-styles/scripts/blind_review.py +159 -0
  57. package/src/skills-lib/wizz-video-styles/scripts/taste.mjs +110 -0
  58. package/src/skills-lib/wizz-video-styles/scripts/test_blind_review.py +82 -0
  59. package/src/skills-lib/wizz-vsl/LICENSE +49 -0
  60. package/src/skills-lib/wizz-vsl/SKILL.md +122 -0
  61. package/src/skills-lib/wizz-vsl/references/assembly-qa.md +123 -0
  62. package/src/skills-lib/wizz-vsl/references/blocks-and-leads.md +149 -0
  63. package/src/skills-lib/wizz-vsl/references/diagnosis.md +95 -0
  64. package/src/skills-lib/wizz-vsl/references/intake.md +200 -0
  65. package/src/skills-lib/wizz-vsl/references/mechanisms.md +138 -0
  66. package/src/skills-lib/wizz-vsl/references/niches.md +40 -0
  67. package/src/skills-lib/wizz-vsl/references/offer.md +91 -0
  68. package/src/skills-lib/wizz-vsl/references/production.md +75 -0
  69. package/tools/hooks/README.md +10 -9
  70. package/tools/hooks/wizz-arrumar.js +1 -0
  71. package/tools/hooks/wizz-artifact-guard.js +31 -5
  72. package/tools/hooks/wizz-cerebro-lib.js +36 -13
  73. package/tools/hooks/wizz-feature-lib.js +4 -1
  74. package/tools/hooks/wizz-feature.js +66 -76
  75. package/tools/hooks/wizz-sprint-archive-lib.js +311 -0
  76. package/tools/installer/core/hooks-settings.js +1 -0
  77. package/tools/installer/core/installer.js +6 -0
  78. package/tools/installer/modules/core-seed.js +72 -0
  79. package/tools/installer/modules/mcp-config.js +3 -0
  80. package/tools/installer/ui.js +16 -26
@@ -149,8 +149,26 @@ the `<Font>-OFL.txt` file in the same folder.
149
149
  - Origin: the beat-grid approach and the kinetic typography recipe follow [mexicat/pdoom-video](https://github.com/mexicat/pdoom-video) (beat, downbeat and lyric alignment driving the edit); no code was copied, and its `data/audio.json` was used only to check `beat_grid.py`. The prompt list links to [yihui-dev/awesome-opus5-5-videos](https://github.com/yihui-dev/awesome-opus5-5-videos), summarising 15 entries in our words; each prompt remains its creator's.
150
150
  - License: MIT, copyright (c) 2026 Giacomo Magnanini (pdoom-video) and copyright (c) 2026 yihui-dev (awesome-opus5-5-videos).
151
151
 
152
+ ## wizz-video-effects and wizz-video-styles (motionmaxxing)
153
+
154
+ - Path: `src/skills-lib/wizz-video-effects/scripts/check_dead_frames.py`, `src/skills-lib/wizz-video-effects/scripts/check_chrome.py`, `src/skills-lib/wizz-video-effects/assets/chrome/collect_layout.js`, `src/skills-lib/wizz-video-styles/references/motion-laws.md`, `src/skills-lib/wizz-video-styles/scripts/blind_review.py` (the idea of its blind review page, written again and much smaller), `src/skills-lib/wizz-video-styles/scripts/taste.mjs` (the idea of its `taste/verdicts.md`, a per-user file of verdicts read before deciding) (measured numbers from its `references/motion.md` and `references/type.md`, summarised in our words) and the `dead_frames` and `chrome_lint` blocks of `src/skills-lib/wizz-video-effects/assets/effects.config.template.json`
155
+ - Origin: [Tejashmakwana/motionmaxxing](https://github.com/Tejashmakwana/motionmaxxing) by Tejas Makwana. Ported ideas and measured thresholds (gate G2 "no empty frame" of `look.py`; rules C1-C4, C6, C7, D1 and P1 of gate G5 in `lint.mjs`), adapted to vertical short video and written again in our own code; no file was copied.
156
+ - License: Apache License 2.0 (full text at `src/skills-lib/wizz-video-effects/LICENSE-motionmaxxing.txt`). Its NOTICE reads: "motionmaxxing: looksmaxxing for motion graphics. Made by Tejas Makwana (x.com/makwanatejas170), github.com/Tejashmakwana/motionmaxxing." Changes: thresholds moved to the effects config, analysis frame reshaped to 9:16, frozen-picture check made a warning, chrome rules sized on the short side of the frame, with exempt roles (captions, legal text, UI) and a per-style allow list, and a Remotion timeline input.
157
+
152
158
  ## wizz-hook-extractor and wizz-ig-profile-optimizer
153
159
 
154
160
  - Path: `src/skills-lib/wizz-hook-extractor/`, `src/skills-lib/wizz-ig-profile-optimizer/`
155
161
  - Origin: adapted from `skills/ig-hook-extractor/`, `references/hook-formulas.md` and `skills/ig-profile-optimizer/` of [sergebulaev/instagram-skills](https://github.com/sergebulaev/instagram-skills). Translated to Brazilian Portuguese, hooks mapped to the Viral Script Blueprint types, and extended with reading the post or profile directly (yt-dlp, local transcription, agent-browser) and a limits checker.
156
162
  - License: MIT (full text at `src/skills-lib/wizz-hook-extractor/LICENSE` and `src/skills-lib/wizz-ig-profile-optimizer/LICENSE`, copyright (c) 2026 Sergey Bulaev)
163
+
164
+ ## wizz-vsl
165
+
166
+ - Path: `src/skills-lib/wizz-vsl/`
167
+ - Origin: adapted from [yuribranco/vsl-skill](https://github.com/yuribranco/vsl-skill) (commit `fe855c50`: the 11-block interview, the two human gates, the 5x5 mechanism decision document, backwards writing, the 15-step offer, the lead angles, niche adaptation and the QA checklist) and from [bertrand-do/video-sales-letter](https://github.com/bertrand-do/video-sales-letter) (commit `f41eec5a`: the claims ledger, the script-only audit, the demo-led variant, the beat sheet, word-timed motion, player QA and the OTO/downsell sequence). Translated into the Method's English skill format, wired to `wizz-offer-forge`, the Piva audience research, the low ticket VSL ruler, `wizz-ctc-align` and the HyperFrames/Remotion pipeline. The method lineage declared by vsl-skill (Lucas Ramos/Veritas Club, Eugene Schwartz's *Breakthrough Advertising*, *Great Leads* by Masterson and Forde, Alex Hormozi's value equation) is credited in the skill. [mikefilsaime-groove/stickman-vsl-director](https://github.com/mikefilsaime-groove/stickman-vsl-director) (MIT, copyright (c) 2026 Mike Filsaime) is only cited as an optional reference; nothing from it is copied.
168
+ - License: MIT (full texts at `src/skills-lib/wizz-vsl/LICENSE`, copyright (c) 2026 Yuri Branco and copyright (c) 2026 Bertrand Diouly)
169
+
170
+ ## wizz-social knowledge (hook pre-check and caption fold check)
171
+
172
+ - Path: `src/modules/wizz/agents/wizz-social/knowledge/blueprint-roteiro-viral.md` (section "Hook pre-check"), `src/modules/wizz/agents/wizz-social/knowledge/legenda-instagram.md` (section "The fold check")
173
+ - Origin: ideas adapted in our own words from `skills/ig-reel/hookscore.py` and `skills/ig-caption/` of [Jakeschincariol/instagram-agent-skill](https://github.com/Jakeschincariol/instagram-agent-skill) (commit `d03c56bb`); no code was copied.
174
+ - License: MIT, copyright (c) 2026 Jake Schincariol
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
3
  "name": "wizz-method",
4
- "version": "2.21.0",
4
+ "version": "2.22.0",
5
5
  "description": "Wizz Method: método de agência orientado por IA em PT-BR",
6
6
  "keywords": [
7
7
  "agile",
@@ -53,6 +53,8 @@
53
53
  "docs:preview": "astro preview --root website",
54
54
  "docs:validate-links": "node tools/validate-doc-links.js",
55
55
  "docs:validate-sidebar": "node tools/validate-sidebar-order.js",
56
+ "eval:design-mining": "node evals/design-mining/run-design-mining-eval.mjs",
57
+ "eval:design-mining:llm": "node evals/design-mining/run-design-mining-eval.mjs --llm",
56
58
  "eval:feature": "node evals/routing/run-feature-eval.mjs",
57
59
  "eval:feature:llm": "node evals/routing/run-feature-eval.mjs --llm",
58
60
  "eval:output": "node evals/output/run-output-eval.mjs",
@@ -69,7 +71,7 @@
69
71
  "lint:md": "markdownlint-cli2 \"**/*.md\"",
70
72
  "prepare": "command -v husky >/dev/null 2>&1 && husky || exit 0",
71
73
  "quality": "npm run format:check && npm run lint && npm run lint:md && npm run docs:build && npm run quality:validate",
72
- "quality:validate": "npm test && npm run validate:refs && npm run validate:registry-schema && npm run validate:method-refs && npm run validate:model-ids && npm run validate:skills && npm run docs:validate-sidebar && npm run docs:validate-links && npm run validate:generated && npm run eval:routing && npm run eval:feature && npm run eval:output",
74
+ "quality:validate": "npm test && npm run validate:refs && npm run validate:registry-schema && npm run validate:method-refs && npm run validate:model-ids && npm run validate:skills && npm run docs:validate-sidebar && npm run docs:validate-links && npm run validate:generated && npm run eval:routing && npm run eval:feature && npm run eval:output && npm run eval:design-mining",
73
75
  "rebundle": "node tools/bundle-web-bundles.js",
74
76
  "release": "node tools/release.mjs",
75
77
  "sync:check": "node tools/sync-check.mjs",
@@ -216,6 +216,11 @@ areas:
216
216
  before: [wizz-ctc-align, wizz-video-effects, wizz-remotion-best-practices]
217
217
  pairs_with: [wizz-social-content, get-brolls, hyperframes, wizz-hook-extractor]
218
218
  clis:
219
+ # hypit-ai/hypit ("clonar vídeo viral" com agentes, DSL de vídeo ancorada
220
+ # em palavras), avaliado em 2026-10-22 (adendo repos-externos-rea-e-vsl):
221
+ # SÓ RECOMENDAR, nunca embutir nem virar entrada `clis:` com install. A
222
+ # licença é Apache 2.0 modificada com condições que proíbem
223
+ # redistribuição comercial; o usuário instala por conta própria se quiser.
219
224
  - id: hyperframes
220
225
  when: "DESENHAR telas de vídeo em HTML/CSS (HTML→MP4, agent-native, 20+ skills): cena isolada e MUDA — maqueta de WhatsApp/ChatGPT, gráfico animado, título, loop. NÃO usar para montagem com áudio/SFX/legenda sincronizada (posicionador de áudio falhou em produção, ~2,76s de drift; CSS vaza entre telas): a montagem final é do Remotion (regra: HyperFrames desenha, Remotion monta — ver _shared/video-pipeline.md do módulo wizz). Precisa ffmpeg + Node 22 + Chrome headless."
221
226
  not_when: "Montagem com áudio/SFX/legenda sincronizada (posicionador de áudio falhou em produção, ~2,76s de drift; CSS vaza entre telas)."
@@ -390,6 +395,20 @@ areas:
390
395
  when: "Material de vendas: deck, one-pager, objeções, demo script, playbook."
391
396
  rel:
392
397
  pairs_with: [wizz-competitor-alternatives]
398
+ # Adaptada de yuribranco/vsl-skill + bertrand-do/video-sales-letter (MIT)
399
+ # em 2026-10-24 (adendo repos-externos-rea-e-vsl). Sem `rel` de propósito:
400
+ # oferta (wizz-offer-forge), pesquisa do Piva, régua do lowticket e a
401
+ # produção (wizz-ctc-align, hyperframes, Remotion) entram pela prosa da
402
+ # skill. Aresta aqui exigiria a recíproca nessas entradas e mudaria o
403
+ # prompt de rota/descoberta das áreas delas (ver feedback de rota
404
+ # invariante). A produção mora em designer: a copy só entrega o roteiro
405
+ # e o beat sheet.
406
+ - id: wizz-vsl
407
+ when: "Roteiro de VSL (vídeo de vendas): escrever do zero ou refazer a que não converte, da entrevista com o expert ao roteiro pronto pra gravar, com mecanismo do problema e da solução, oferta falada, leads pra testar e plano de produção. Gatilhos: 'faz a VSL do meu produto', 'roteiro do vídeo de vendas', 'a lead da VSL tá fraca', 'a retenção cai no primeiro minuto'."
408
+ not_when:
409
+ - "Copy da página de vendas, headline ou texto em volta do player: é wizz-copywriting."
410
+ - "Roteiro de criativo ou anúncio curto: é wizz-ad-creative (área ads); roteiro de Reel ou Short: é wizz-social-content (área social)."
411
+ - "Gravar, animar ou montar o vídeo em si: é da área designer."
393
412
 
394
413
  seo:
395
414
  agent: wizz-seo
@@ -903,6 +922,28 @@ areas:
903
922
  when: "Review do trabalho concluído no epic (party mode)."
904
923
  rel:
905
924
  after: [wizz-sprint-planning]
925
+ mcps:
926
+ # Rea (morluto/rea, npm rea-agents, MIT), adendo repos-externos-rea-e-vsl
927
+ # de 2026-10-22. OPCIONAL: `optional: true` deixa a entrada DESMARCADA no
928
+ # multiselect do installer (só recomenda o `claude mcp add`; escreve no
929
+ # .mcp.json apenas se o usuário marcar ou passar --mcps rea). Instalar só
930
+ # do npm `rea-agents` ou de rea.tools: o próprio README avisa sobre repos
931
+ # copiados, e o repo tinha uma contagem de estrelas desproporcional em
932
+ # 2026-10-22. Para site comum ele sobrepõe o agent-browser; o ganho real é
933
+ # Electron, APK, HAR e binário nativo (Hopper/Ghidra/IDA, se instalados).
934
+ # Alternativas olhadas e piores pro caso geral: mrexodia/ida-pro-mcp e
935
+ # LaurieWired/GhidraMCP (uma ferramenta só cada).
936
+ - id: rea
937
+ optional: true
938
+ when: "Entender como uma feature de app, site, APK ou binário de TERCEIRO funciona por dentro, sem o código-fonte, pra construir uma parecida: app desktop ou Electron, APK Android, binário nativo, captura HAR."
939
+ not_when:
940
+ - "Código do próprio projeto, com o fonte disponível: é wizz-investigate."
941
+ - "Só navegar, clicar ou tirar print de um site: é o agent-browser."
942
+ server:
943
+ command: npx
944
+ # Pin de supply chain (2026-10-24): versão publicada fixa
945
+ # (registry npm: 6.7.0, 2026-10-18); atualizar conscientemente.
946
+ args: ["-y", "rea-agents@6.7.0", "mcp"]
906
947
 
907
948
  pm:
908
949
  agent: wizz-agent-pm
@@ -27,7 +27,7 @@ Invoke this skill only for the explicit cases in "When this skill runs" below.
27
27
  3. **The request itself.** When 1 and 2 are both empty and the request is named work (a feature, a batch, a screen, a page, a campaign, a bug with a scope: "vamos fazer o painel de assinaturas"). Derive the slug from the subject, 2 to 4 words, and run `node _wizz/hooks/wizz-feature.js definir <slug>` BEFORE dispatching; say so in **one line**. Do not ask. This step is mandatory for the router and the maestro, not a nice-to-have: skipping it is how a project spends its whole life with an empty `active_feature`.
28
28
  4. **Nothing.** Only for work that is not named (a question, a conversation, a one-line tweak with no artifact). Artifacts go to the roots and memory carries no feature tag.
29
29
 
30
- **The open sprint rules.** The active feature is the open sprint: every request goes into it until it is closed, with no new folder. A new subject goes into it, sized by the work (a small tweak is just done, no story; a multi-step change becomes a story; a new objective becomes an epic), while it fits the sprint's goal; only if it does not fit, ask the owner once: add to this sprint or open another. `definir <other>` with a sprint open is refused unless `--novo` (the owner's choice). **Close** when the delivery closes (deploy or acceptance): `wizz-feature.js verificar` must pass, then `wizz-feature.js encerrar --cerebro [--proxima <slug>]` marks the spec `no-ar`, moves the sprint's folders (and the root `sprint-status.yaml`) to `_arquivo/<slug>/`, clears or switches `active_feature`, and writes the Cérebro (state + one Sessions line; without a vault it prints the instruction instead).
30
+ **The open sprint rules.** The active feature is the open sprint: every request goes into it until it is closed, with no new folder. A new subject goes into it, sized by the work (a small tweak is just done, no story; a multi-step change becomes a story; a new objective becomes an epic), while it fits the sprint's goal; only if it does not fit, ask the owner once: add to this sprint or open another. `definir <other>` with a sprint open is refused unless `--novo` (the owner's choice). **Close** when the delivery closes (deploy or acceptance): `wizz-feature.js verificar` must pass, then `wizz-feature.js encerrar --cerebro [--proxima <slug>]` marks the spec `no-ar`, moves the sprint's folders (and the root `sprint-status.yaml` when it belongs to the sprint) to `_arquivo/<slug>/`, rewriting or listing references from outside, clears or switches `active_feature`, and writes the Cérebro (state + one Sessions line; without a vault it prints the instruction instead).
31
31
 
32
32
  **Optional branch.** `feature_branches: auto` in `_wizz/bmm/config.yaml` makes `definir` (and the SessionStart hook) propose `git switch -c feat/<slug>` when you are on a trunk branch of a git repo. The default is `off`, for whoever works directly on `main`.
33
33
 
@@ -47,7 +47,7 @@ Load config from `{project-root}/_wizz/bmm/config.yaml` and resolve:
47
47
  - `project_name`, `planning_artifacts`, `implementation_artifacts`, `user_name`
48
48
  - `communication_language`, `document_output_language`, `user_skill_level`
49
49
  - `date` as system-generated current datetime
50
- - `sprint_status` = `{implementation_artifacts}/sprint-status.yaml`
50
+ - `sprint_status` = `{implementation_artifacts}/{active_feature}/sprint-status.yaml` when that file exists (the open sprint's own file; when `{active_feature}` is empty or a feature branch is checked out, get the open sprint from `node _wizz/hooks/wizz-feature.js resolver`), otherwise `{implementation_artifacts}/sprint-status.yaml`. Read and update the same file for the whole run
51
51
  - `project_context` = `**/project-context.md` (load if exists)
52
52
  - CLAUDE.md / memory files (load if exist)
53
53
  - YOU MUST ALWAYS SPEAK OUTPUT in your Agent communication style with the config `{communication_language}`
@@ -69,7 +69,7 @@ Activation is complete. If `activation_steps_prepend` or `activation_steps_appen
69
69
 
70
70
  ## Paths
71
71
 
72
- - `sprint_status` = `{implementation_artifacts}/sprint-status.yaml`
72
+ - `sprint_status` = `{implementation_artifacts}/{active_feature}/sprint-status.yaml` when that file exists (the open sprint's own file; when `{active_feature}` is empty or a feature branch is checked out, get the open sprint from `node _wizz/hooks/wizz-feature.js resolver`), otherwise `{implementation_artifacts}/sprint-status.yaml`. Read and update the same file for the whole run
73
73
  - `epics_file` = `{planning_artifacts}/epics.md`
74
74
  - `prd_file` = `{planning_artifacts}/prd.md`
75
75
  - `architecture_file` = `{planning_artifacts}/architecture.md`
@@ -53,6 +53,7 @@ Load config from `{project-root}/_wizz/bmm/config.yaml` and resolve:
53
53
  - `communication_language`, `document_output_language`
54
54
  - `user_skill_level`
55
55
  - `implementation_artifacts`
56
+ - `output_folder` (where `design-state.yaml` lives, for the design gate in step 5)
56
57
  - `date` as system-generated current datetime
57
58
  - `project_context` = `**/project-context.md` (load if exists)
58
59
 
@@ -69,7 +70,7 @@ Activation is complete. If `activation_steps_prepend` or `activation_steps_appen
69
70
  ## Paths
70
71
 
71
72
  - `story_file` = `` (explicit story path; auto-discovered if empty)
72
- - `sprint_status` = `{implementation_artifacts}/sprint-status.yaml`
73
+ - `sprint_status` = `{implementation_artifacts}/{active_feature}/sprint-status.yaml` when that file exists (the open sprint's own file; when `{active_feature}` is empty or a feature branch is checked out, get the open sprint from `node _wizz/hooks/wizz-feature.js resolver`), otherwise `{implementation_artifacts}/sprint-status.yaml`. Read and update the same file for the whole run
73
74
 
74
75
  ## Execution
75
76
 
@@ -315,6 +316,12 @@ Activation is complete. If `activation_steps_prepend` or `activation_steps_appen
315
316
  <action>Review the current task/subtask from the story file - this is your authoritative implementation guide</action>
316
317
  <action>Plan implementation following red-green-refactor cycle</action>
317
318
 
319
+ <check if="the task builds a non-trivial UI section, component or behaviour AND {output_folder}/design-state.yaml exists">
320
+ <action>Run the design gate before writing UI code: locate the script with `find . -path '*wizz-design-needs/scripts/design_state.py' -not -path '*/node_modules/*' | head -1` and run `uv run --no-cache <script> gate {output_folder}/design-state.yaml --section <surface>/<section>`</action>
321
+ <action if="the gate exits 1">HALT: "Design gate blocked: <need ids and action from the gate JSON>" (an open need is mined first; an unplanned section goes back to wizz-design-needs)</action>
322
+ <action if="the gate passes">Build from the selected discoveries' `adaptation` plans; for `unmet` needs, cite the research in Dev Agent Record as the justification for a custom build</action>
323
+ </check>
324
+
318
325
  <!-- RED PHASE -->
319
326
  <action>Write FAILING tests first for the task/subtask functionality</action>
320
327
  <action>Confirm tests fail before implementation - this validates test correctness</action>
@@ -82,10 +82,10 @@ Treat every entry in `{workflow.persistent_facts}` as foundational context you c
82
82
 
83
83
  Load config from `{project-root}/_wizz/bmm/config.yaml` and resolve:
84
84
 
85
- - `project_name`, `planning_artifacts`, `implementation_artifacts`, `user_name`
85
+ - `project_name`, `planning_artifacts`, `implementation_artifacts`, `output_folder`, `user_name`
86
86
  - `communication_language`, `document_output_language`, `user_skill_level`
87
87
  - `date` as system-generated current datetime
88
- - `sprint_status` = `{implementation_artifacts}/sprint-status.yaml`
88
+ - `sprint_status` = `{implementation_artifacts}/{active_feature}/sprint-status.yaml` when that file exists (the open sprint's own file; when `{active_feature}` is empty or a feature branch is checked out, get the open sprint from `node _wizz/hooks/wizz-feature.js resolver`), otherwise `{implementation_artifacts}/sprint-status.yaml`. Read and update the same file for the whole run
89
89
  - `project_context` = `**/project-context.md` (load if exists)
90
90
  - CLAUDE.md / memory files (load if exist)
91
91
  - YOU MUST ALWAYS SPEAK OUTPUT in your Agent communication style with the config `{communication_language}`
@@ -28,6 +28,8 @@ Follow `./sync-sprint-status.md` with `{target_status}` = `in-progress`.
28
28
 
29
29
  If `{spec_file}` has a non-empty `context:` list in its frontmatter, load those files before implementation begins. When handing to a sub-agent, include them in the sub-agent prompt so it has access to the referenced context.
30
30
 
31
+ **Design gate.** When the spec builds a non-trivial UI section, component or behaviour and `{output_folder}/design-state.yaml` exists, run the gate before any UI code: locate the script with `find . -path '*wizz-design-needs/scripts/design_state.py' -not -path '*/node_modules/*' | head -1` and run `uv run --no-cache <script> gate {output_folder}/design-state.yaml --section <surface>/<section>`. Exit 1 is a HALT: report the need ids and the gate's action (mine the open need first; an unplanned section goes back to `wizz-design-needs`). On pass, the selected discoveries' `adaptation` plans are the build brief. When handing to a sub-agent, pass the gate result and the map path.
32
+
31
33
  Hand `{spec_file}` to a sub-agent/task and let it implement. If no sub-agents are available, implement directly.
32
34
 
33
35
  **Path formatting rule:** Any markdown links written into `{spec_file}` must use paths relative to `{spec_file}`'s directory so they are clickable in VS Code. Any file paths displayed in terminal/conversation output must use CWD-relative format with `:line` notation (e.g., `src/path/file.ts:42`) for terminal clickability. No leading `/` in either case.
@@ -60,7 +60,7 @@ Activation is complete. If `activation_steps_prepend` or `activation_steps_appen
60
60
 
61
61
  ## Paths
62
62
 
63
- - `sprint_status_file` = `{implementation_artifacts}/sprint-status.yaml`
63
+ - `sprint_status_file` = `{implementation_artifacts}/{active_feature}/sprint-status.yaml` when that file exists (the open sprint's own file; when `{active_feature}` is empty or a feature branch is checked out, get the open sprint from `node _wizz/hooks/wizz-feature.js resolver`), otherwise `{implementation_artifacts}/sprint-status.yaml`. Read and update the same file for the whole run
64
64
 
65
65
  ## Input Files
66
66
 
@@ -816,7 +816,7 @@ code = "tm-pedro-sobral"
816
816
  name = "Pedro Sobral"
817
817
  icon = "🥷"
818
818
  title = "O Ninja Supremo do Tráfego — gestor de tráfego pioneer"
819
- persona = "Irreverent, execution-obsessed Brazilian practitioner-teacher who coined gestor de tráfego and managed huge spend for the LATAM market. Rallying cry is vai la e faz: Jedis execute while Padawans only consume theory, and every cent of ad spend is a test. Argues from three essential campaign types, the passo anterior strategy of targeting one step before conversion, isolated one-variable testing, and creative as the new audience. Pet peeve: becoming a mero operador de botoes who blindly trusts platform AI, because the algorithm serves platform profits, not yours."
819
+ persona = "Irreverent, execution-obsessed Brazilian practitioner-teacher who coined gestor de tráfego and managed huge spend for the LATAM market. Rallying cry is vai la e faz: Jedis execute while Padawans only consume theory, and every cent of ad spend is a test. Argues from three essential campaign types, the passo anterior strategy of targeting one step before conversion, isolated one-variable testing, and creative as the new audience. Pet peeve: becoming a mero operador de botoes who blindly trusts platform AI, because the algorithm serves platform profits, not yours. Speaks his own style, not the course methodology: when the panel needs Meta bid cap or scale numbers, he defers to shard 03-campanha-bidcap.md of wizz-lowticket-metodologia and says the numbers are the methodology's."
820
820
 
821
821
  [[workflow.party_members]]
822
822
  code = "tm-ad-midas"
@@ -830,14 +830,14 @@ code = "tm-media-buyer"
830
830
  name = "Media Buyer"
831
831
  icon = "🖥️"
832
832
  title = "Cross-platform campaign execution operator"
833
- persona = "The operational backbone who turns strategy into live campaigns across Meta, Google, YouTube, TikTok, and LinkedIn, meticulous about naming conventions and clean structure. Argues that structure determines performance, you start small and scale with data not hope, and you change only one variable at a time or you learn nothing. Runs a non-negotiable daily routine of morning check, midday adjust, evening document, letting algorithms target while feeding them clean data and good creative. Pet peeve: messy accounts, because messy accounts get messy results."
833
+ persona = "The operational backbone who turns strategy into live campaigns across Meta, Google, YouTube, TikTok, and LinkedIn, meticulous about naming conventions and clean structure. Argues that structure determines performance, you start small and scale with data not hope, and you change only one variable at a time or you learn nothing. Runs a non-negotiable daily routine of morning check, midday adjust, evening document, letting algorithms target while feeding them clean data and good creative. Reading is daily, touching is not: on Meta he pauses and scales only by the rulers of shard 03-campanha-bidcap.md of wizz-lowticket-metodologia. Pet peeve: messy accounts, because messy accounts get messy results."
834
834
 
835
835
  [[workflow.party_members]]
836
836
  code = "tm-scale-optimizer"
837
837
  name = "Scale Optimizer"
838
838
  icon = "🚀"
839
839
  title = "Campaign scaling and efficiency specialist"
840
- persona = "A methodical, cautious-but-aggressive specialist who treats scaling as the most dangerous phase where good campaigns go to die. Refuses to scale anything unproven, demanding profitability for five-plus days first, then verticals at 20-30 percent every 48-72 hours before going horizontal then platform. Argues that marginal CPA is the real metric because average CPA masks the problem, and that every audience has a ceiling to respect rather than fight. Pet peeve: scaling without a matching creative pipeline, since spend outrunning fresh creative just buys faster fatigue."
840
+ persona = "A methodical, cautious-but-aggressive specialist who treats scaling as the most dangerous phase where good campaigns go to die. Refuses to scale anything the methodology does not call validated yet, then scales Meta campaigns in its lever order: bid cap first, validated creatives second, budget last with each step sized by the ROAS ruler, reading the numbers in shard 03-campanha-bidcap.md of wizz-lowticket-metodologia instead of carrying a fixed percentage, and only then goes horizontal and to new platforms. Argues that marginal CPA is the real metric because average CPA masks the problem, and that every audience has a ceiling to respect rather than fight. Pet peeve: scaling without a matching creative pipeline, since spend outrunning fresh creative just buys faster fatigue."
841
841
 
842
842
  [[workflow.party_members]]
843
843
  code = "tm-pixel-specialist"
@@ -59,6 +59,8 @@ Levers, in this order: (1) raise the bid cap, (2) add validated creatives, (3) a
59
59
 
60
60
  **Never** as the first lever: raising the daily budget. The budget grants permission to spend; the bid cap is the real acquisition ceiling.
61
61
 
62
+ Budget step, once the budget lever is reached, sized by ROAS: **ROAS ≥ 2.5 → +50%** · **2.0 to 2.5 → +30%** · **below 2.0 → +20%** (shard 03, §3.2).
63
+
62
64
  Lockout after touching it: **48 to 72h hangover** after a structural change, and the 3x rule before judging again.
63
65
 
64
66
  ## Cadence and saturation
@@ -10,7 +10,7 @@ Load context **cheaply**:
10
10
 
11
11
  1. Run `/wizz-cerebro ver` (or a light `grep` on the vault) to pull the project's current state and recent decisions.
12
12
  2. Don't read the whole vault. Get only: where things stopped, what's missing, decisions relevant to the agent's area.
13
- 3. If there's no cerebro in this project, proceed normally without blocking.
13
+ 3. If there's no cerebro in this project, proceed normally without blocking. Where the vault is looked for, and what to ask when saving with none, lives in one place only: the `wizz-cerebro` skill, section `## Vault`.
14
14
 
15
15
  ## On closing
16
16
 
@@ -26,7 +26,7 @@ The SessionStart and UserPromptSubmit hooks already tell you the state (`FEATURE
26
26
  6. **Feature branch** (`feat/<slug>`) → the branch already is the sprint; when the config disagrees, `F definir <branch-slug> --novo`.
27
27
  7. **`feature_branches: auto`** in the config and you are on a trunk branch → propose `git switch -c feat/<slug>` in one line. With `off` (the default, for whoever works on `main`) say nothing about branches.
28
28
 
29
- **Closing archives.** `F encerrar` moves the sprint's two folders to `_arquivo/<slug>/` inside each artifact folder, together with the root `{implementation_artifacts}/sprint-status.yaml`, so the next sprint starts clean. `F listar` shows the open sprints and one line with the number of archived ones. The archive is history, not trash: when a request needs a past decision, spec or retro ("how did we solve the Meta sync?"), search `_arquivo/` of both artifact folders (and the Cérebro, which points to it) before saying it does not exist.
29
+ **Closing archives.** `F encerrar` moves the sprint's two folders to `_arquivo/<slug>/` inside each artifact folder, together with the root `{implementation_artifacts}/sprint-status.yaml` when it belongs to that sprint (otherwise it stays and the output says why), so the next sprint starts clean. It plans before touching the disk and undoes everything on a failure; closing a reopened sprint keeps the previous close's same-named files beside the new ones as `<name>.anterior-<date>`. References from outside the sprint (CLAUDE.md, roteiros, design html) are rewritten; code and config that still cite the old folder are listed for you to fix. `F listar` shows the open sprints and one line with the number of archived ones. The archive is history, not trash: when a request needs a past decision, spec or retro ("how did we solve the Meta sync?"), search `_arquivo/` of both artifact folders (and the Cérebro, which points to it) before saying it does not exist.
30
30
 
31
31
  **Handoff:** every brief carries `feature: <slug>` (or `feature: nenhuma` for work that is not named). A receiver without that field resolves it itself with the steps above before writing anything; it never writes an artifact without a resolved feature.
32
32
 
@@ -61,7 +61,7 @@ Run `F verificar`. It checks the mechanical items and returns the judgment items
61
61
  - [ ] Spec exists, valid frontmatter, acceptance criteria filled.
62
62
  - [ ] `## Implementação` filled when the status is `implementado` or "no-ar".
63
63
  - [ ] Roteiro with Rollback in `{project_knowledge}/` when the status is "no-ar".
64
- - [ ] Cérebro: project state + one line in the Sessions table (`F encerrar --cerebro` writes both; vault from `WIZZ_CEREBRO_VAULT`, `cerebro_vault:` in the config or `~/Documents/projects/Obsidian Vault`; project file from `--projeto`, `project_name` or the folder name).
64
+ - [ ] Cérebro: project state + one line in the Sessions table (`F encerrar --cerebro` writes both; vault found as in the `wizz-cerebro` skill, section `## Vault`; project file from `--projeto`, `project_name` or the folder name).
65
65
  - [ ] Auto-memory: only a reproducible trap or an owner preference (state and decisions belong to the Cérebro).
66
66
 
67
67
  A delivered feature (status `implementado` or "no-ar") with a pending item also triggers a Stop-hook warning (`wizz-close-reminder.js`) at the end of the turn.
@@ -25,6 +25,7 @@ You are Wizz's Copy. It writes texts that sell, humanizes what sounds robotic, a
25
25
  - Email, sequence, nurture → `wizz-email-sequence`
26
26
  - Make text natural, remove the AI feel → `wizz-humanizer`
27
27
  - Review/edit existing text → `wizz-copy-editing`
28
+ - VSL (video sales letter) script, from the expert interview to a script ready to record plus the production beat sheet → `wizz-vsl`; under low ticket it reads the methodology's VSL ruler first
28
29
 
29
30
  Always deliver 2-3 variations and say which one you recommend.
30
31
 
@@ -40,6 +40,11 @@ code = "PG"
40
40
  description = "Page copy, headline, value proposition, CTA"
41
41
  prompt = "Invoke the GLOBAL skill 'wizz-copywriting' via the Skill tool. Then run the 'wizz-humanizer' logic on the final text. Deliver 2-3 variations in easy {communication_language}."
42
42
 
43
+ [[agent.menu]]
44
+ code = "VSL"
45
+ description = "VSL script: interview, mechanisms, offer, leads, beat sheet"
46
+ prompt = "Invoke the GLOBAL skill 'wizz-vsl' via the Skill tool. It resumes from its manifest when one exists, reuses an approved wizz-offer-forge offer and the Piva research, and hands production (narration, wizz-ctc-align, hyperframes, Remotion) to the designer area: offer wizz-maestro when the user wants the video in the same delivery."
47
+
43
48
  [[agent.menu]]
44
49
  code = "EM"
45
50
  description = "Email, nurture sequence, follow-up"
@@ -10,13 +10,14 @@
10
10
 
11
11
  | Situação | Skill (nesta ordem) | Onde olhar |
12
12
  | ----------------------------------------------------- | ------------------------------------------ | ---------------------------------------------------------------------------------------------------- |
13
- | Não conheço o público, as dores, a linguagem | `wizz-pesquisa-de-publico-do-piva` | `wizz-pesquisa-de-publico-do-piva/SKILL.md` |
13
+ | Não conheço o público, as dores, a linguagem | `wizz-pesquisa-de-publico-do-piva` | `wizz-pesquisa-de-publico-do-piva/SKILL.md` |
14
14
  | Não há oferta definida | `wizz-offer-forge` | `wizz-offer-forge/references/mecanismo-unico.md`, `empilhamento-valor.md`, `garantia-reversa.md` |
15
15
  | Copy de venda, página ou headline do zero | `wizz-copywriting` | `wizz-copywriting/references/copy-frameworks.md`, `natural-transitions.md` |
16
16
  | Texto já existe e precisa melhorar | `wizz-copy-editing` | `wizz-copy-editing/references/plain-english-alternatives.md` |
17
17
  | Texto soa feito por IA | `wizz-humanizer` | `wizz-humanizer/references/ai-writing-patterns.md` |
18
18
  | Sequência de e-mail (onboarding, nurture, lançamento) | `wizz-email-sequence` | `references/email-types.md`, `sequence-templates.md`, `copy-guidelines.md` |
19
19
  | Cold email, outbound B2B | `wizz-cold-email` | `references/frameworks.md`, `subject-lines.md`, `personalization.md`, `follow-up-sequences.md` |
20
+ | Roteiro de VSL (vídeo de vendas) | `wizz-vsl` | `wizz-vsl/SKILL.md` (no low ticket lê antes a régua de VSL da `wizz-lowticket-metodologia`) |
20
21
  | Deck, one-pager, objeções, demo | `wizz-sales-enablement` | `references/deck-frameworks.md`, `objection-library.md`, `demo-scripts.md`, `one-pager-templates.md` |
21
22
  | Copy de low ticket BR/PT | `wizz-lowticket-metodologia` (área growth) | `wizz-lowticket-metodologia/knowledge/18-copy-desejo-oferta.md`, `07a-copy-humanizacao.md` |
22
23
  | Texto para anúncio | `wizz-ad-creative` (área ads) | `wizz-paid-ads/references/ad-copy-templates.md` |
@@ -50,6 +50,20 @@ Requires speed: must go out the same day or within 24h. Once the window passes,
50
50
 
51
51
  **Fundamental pattern:** every hook exists between two poles, **provocation** (you're wrong / your profession is ending) and **promise** (I discovered something you need to know). The strongest ones trigger both at once.
52
52
 
53
+ ### Hook pre-check (before shooting)
54
+
55
+ Write **three** hooks of different types, not three rewordings of one, and for each write the spoken line and the on-screen line separately (on screen is the shorter, blunter one, six words or fewer). Then score each spoken line from 0 to 100 on five checks and keep the best:
56
+
57
+ | Check | Strong when | Weak when |
58
+ |---|---|---|
59
+ | Length | 5 to 12 words, sayable in under 3 seconds | a preamble, or a sentence that needs a breath |
60
+ | Specificity | a concrete marker: a number, a name, a tool, a place | "muita coisa", "um monte de tempo" |
61
+ | Stakes | something is won, lost or at risk in the line | nothing is at stake |
62
+ | Front-loading | the interesting word in the first two or three | "oi gente", "hoje eu vou", "então" opening |
63
+ | Address | aimed at a viewer ("você", a role, a situation) | aimed at nobody |
64
+
65
+ A hook whose weakest check is low is rewritten on that check before anything else. The score catches greetings, preambles and empty hooks; it does not predict which of two decent hooks will travel (the face, the edit, the audio and the distribution decide that): trust the retention graph over the score. Never invent the number a hook needs: it comes from the user or stays a slot. *(Adapted from the hook checks of Jakeschincariol/instagram-agent-skill, MIT, credited in `THIRD-PARTY-NOTICES.md`.)*
66
+
53
67
  ---
54
68
 
55
69
  ## 2. Narrative Structure
@@ -39,6 +39,18 @@ Supporting knowledge for **wizz-social** (Rafa). Creates the optimized descripti
39
39
  - **Fast Reels / simple feed post:** 80 to 150 characters (short, direct, impactful).
40
40
  - **Educational carousel / storytelling:** 300 to 800 characters (delivers value, increases reading time).
41
41
 
42
+ ## The fold check (before delivering)
43
+
44
+ Instagram shows about **125 characters** before "mais". Check the caption the way the feed prints it:
45
+
46
+ - **Decide the job first.** Reel: the video already hooked the viewer, so line one carries the ask and the context, not a second hook competing with the video. Photo, single image or carousel cover: the caption is the content, so line one is the hook and it ends at a cliff, not mid-clause.
47
+ - Line one fits inside the 125 characters: never a greeting, a hashtag or an emoji as the first character.
48
+ - **One ask** only (comment a keyword, save, or DM). A keyword ask uses one typable word with no spaces or emoji, also said in the video.
49
+ - No link in the caption: captions are not clickable; the link goes in the bio, a DM, or the first comment.
50
+ - The phrases the user wants to be found for go in the body as a human would type them; hashtags (up to 5) are labels, not reach.
51
+
52
+ Add one line under the caption in the delivery: `👁️ Antes do "mais": N/125 caracteres`. *(Adapted from the caption linter of Jakeschincariol/instagram-agent-skill, MIT, credited in `THIRD-PARTY-NOTICES.md`.)*
53
+
42
54
  ## General rules
43
55
  - Never robotic or generic. Write like a human.
44
56
  - Emojis with moderation and purpose: they guide the eye, they don't clutter.
@@ -53,12 +53,25 @@ Read offset=(line-5) limit=15 # → reads only the needed excerpt
53
53
 
54
54
  ## Vault
55
55
 
56
- Known default vault: `~/Documents/projects/Obsidian Vault/`
56
+ This section is the **single source** of vault discovery. Every other file (command references, `_shared/cerebro.md`) points here instead of repeating it. The vault is plain markdown: it works with or without the Obsidian app.
57
57
 
58
- **How to discover it:**
59
- 1. Try `~/Documents/projects/Obsidian Vault/CEREBRO.md` — if it exists, use it.
60
- 2. If not: `find ~ -name "CEREBRO.md" -maxdepth 6 2>/dev/null | head -1`
61
- 3. If still nothing: ask the user.
58
+ **How to discover it** (first folder that holds a `CEREBRO.md` wins; `wizz-feature.js encerrar --cerebro` reads steps 1 to 3 in the same order):
59
+ 1. `$WIZZ_CEREBRO_VAULT`, then `cerebro_vault:` in `_wizz/bmm/config.yaml`.
60
+ 2. Per-project Cérebro of the current repo: `_wizz-output/cerebro/` (or `{output_folder}/cerebro/` when the config sets another output folder).
61
+ 3. Global default: `~/Documents/projects/Obsidian Vault/`.
62
+ 4. `find ~ -maxdepth 6 -name "CEREBRO.md" -not -path "*/_wizz-output/*" 2>/dev/null | head -1` (skips other repos' per-project Cérebros).
63
+
64
+ **Nothing found.** A read-only command (`/ver`, `/dia`, `/memoria`) says there is no Cérebro yet and stops. A command that saves (`/iniciar`, `/salvar`, `/dump`, `/decisao`, `/conteudo`, `/prospect`) never writes to an invented place in silence: ask once (AskUserQuestion where available, a numbered question otherwise):
65
+ - **Global Cérebro** (one for every project): then ask which folder, suggesting `~/Documents/projects/Obsidian Vault/`. Outside the default path, tell the user that `export WIZZ_CEREBRO_VAULT="<folder>"` in the shell profile lets the CLI find it too (do not edit the profile yourself).
66
+ - **Per-project Cérebro** (inside this repo, at `_wizz-output/cerebro/`): then ask once whether it stays out of git (private: append `_wizz-output/cerebro/` to `.gitignore`) or is committed (shared with the team).
67
+
68
+ **After the choice**, create the minimal structure and never ask again (the next discovery finds it):
69
+ ```
70
+ <vault>/CEREBRO.md first line: vault: <absolute path> (per-project adds a second line: scope: project)
71
+ <vault>/projetos/
72
+ <vault>/_decisions/
73
+ ```
74
+ A per-project Cérebro needs no config entry: the feature-closing CLI finds `_wizz-output/cerebro/` by itself, so no machine path lands in a committed config. Then continue the command that triggered the question.
62
75
 
63
76
  **Never Read the entire CEREBRO.md just to find the vault path** — use grep:
64
77
  ```bash
@@ -49,6 +49,13 @@ Both read `design-state.yaml`, take the need's `budget` and `floor` as given, an
49
49
 
50
50
  Level 4 or 5 also hands off to `wizz-motion-3d-director` before any behaviour need is mined.
51
51
 
52
+ ## Executable checks on the map
53
+
54
+ `scripts/design_state.py` (run with `uv run --no-cache`) reads the rubric and the level ceiling from the skill files and checks the map itself, so the gates are not only prose:
55
+
56
+ - `validate {output_folder}/design-state.yaml`: statuses and required reasons, verdict against the score band, entry conditions, the cut and each need's floor, one signature per surface, dedup links, the adaptation on every selected discovery, and the behaviour ceiling of the level. The miners run it after writing discoveries; findings are fixed in the map before the handoff.
57
+ - `gate {output_folder}/design-state.yaml --section <surface>/<section>` (or `--need <id>`): the implementer runs it before building a non-trivial section, component or behaviour. Exit 0 passes (selected with a discovery, `unmet` with the research as the justification, `deferred` meaning "not now", `dropped`); exit 1 blocks an open need (mine it first) or a section the map does not know (`unplanned`, back to this skill). No map, no gate: the fail-open contract of the state file holds.
58
+
52
59
  ## References map (read on demand)
53
60
 
54
61
  | For... | Read |
@@ -23,6 +23,8 @@ Read contract, deliberately identical to the one the router and the maestro alre
23
23
  | `implementacao` | `wizz-agent-dev` / `wizz-quick-dev` | QA |
24
24
  | `problemas` | QA, the audit protocol, the user | `wizz-design-needs` when reopening a need |
25
25
 
26
+ `scripts/design_state.py validate` checks this contract and the rubric on a real file; `gate` is the implementer's check before building (both in the skill's SKILL.md).
27
+
26
28
  No block has two owners. A skill that needs a field it does not own asks the owner or records a `problema`; it never overwrites.
27
29
 
28
30
  ## Schema
@@ -70,13 +72,41 @@ needs:
70
72
  adaptive: { mobile: null, reduced_motion: null } # obrigatório antes de fechar
71
73
  status: open # open | mining | evaluated | selected | unmet | dropped | deferred
72
74
  reason: null # obrigatório em dropped, deferred, unmet
73
- satisfied_by: []
75
+ spent: { fontes: 0, secas: 0 } # escrito pelo minerador: fontes abertas, fontes seguidas sem nada elegível
76
+ satisfied_by: [] # ids das discoveries selecionadas
74
77
 
75
78
  proibidos:
76
79
  - { o_que: "partícula, glow, gradiente saturado, 3D", por: sinal:minimalista }
77
80
  - { o_que: "carrossel de logos, card de depoimento genérico", por: tipo:autoridade }
78
81
 
79
- discoveries: [] # escrito pelo minerador
82
+ discoveries: # escrito pelo minerador; regras em mining-rubric.md
83
+ - id: disc-001
84
+ need: b1-hero-entrada # toda descoberta responde a uma necessidade
85
+ surface: home
86
+ layer: comportamento # copiado da need: o teto de comportamento é contado por superfície
87
+ source:
88
+ url: "https://..."
89
+ kind: code # code | registry | visual
90
+ revision: "a3f1c9d" # SHA, tag ou data de leitura
91
+ license: MIT # null quando não há
92
+ access: publico # publico | cache | fornecido_pelo_usuario | pago_autorizado
93
+ evidence: verified # verified | unverified (gate de web-access-and-evidence.md)
94
+ pattern: "revelação por máscara vertical sincronizada com o scroll"
95
+ pattern_key: scroll-mask-reveal # chave de dedup dentro do projeto
96
+ observed: ["máscara 420ms, cubic-bezier(.2,.8,.2,1)", "sem useReducedMotion no código"]
97
+ inferred: ["provavelmente usa GSAP ScrollTrigger"]
98
+ disqualifiers: [] # códigos de condição de entrada não cumprida; qualquer um = DESCARTAR
99
+ scores: { aderencia: 3, execucao: 2, custo_adaptacao: 2, custo_performance: 1, originalidade: 1, total: 9 }
100
+ verdict: ASSINATURA # ASSINATURA | FORTE | UTILITARIO | DESCARTAR
101
+ adaptation: # obrigatório quando selected
102
+ padrao: "o título é revelado por uma máscara que sobe com o scroll"
103
+ por_que: "segura o olho no título antes de liberar o corpo"
104
+ invariante: "a máscara tem que andar mais rápido que o scroll, senão lê como lag"
105
+ variavel: [easing, duração, direção, cor]
106
+ reimplementacao: "reimplementar com os tokens do projeto, sem copiar seletor nem classe"
107
+ status: selected # proposed | selected | rejected | implemented | reverted
108
+ reason: null # obrigatório em rejected e reverted
109
+ dup_of: null # id da discovery selecionada que já resolve este padrão
80
110
  implementacao: {} # escrito pelo dev
81
111
  problemas: [] # escrito pelo QA
82
112
  ```
@@ -97,6 +127,8 @@ open ──▶ mining ──▶ evaluated ──▶ selected ──▶ (implemen
97
127
  └──▶ deferred (perdeu para o teto do nível)
98
128
  ```
99
129
 
130
+ Discoveries have their own lifecycle: `proposed → selected → implemented`, or `rejected` / `reverted` with a `reason`. How a discovery is scored, when it is selected and when the miner stops are in [mining-rubric](../../wizz-premium-landing-ui-researcher/references/mining-rubric.md).
131
+
100
132
  `unmet`, `dropped` and `deferred` require a `reason`. That is what makes reopening cheap: the next round knows what was already tried and why it failed, and does not re-search the same ground.
101
133
 
102
134
  ## Reopening
@@ -24,7 +24,7 @@ When the layers disagree or the coverage cannot be proven by reading (a CSS rule
24
24
  - a site the user named as a reference: at the **system** layer (palette, type scale, spacing, radius), extract it instead of describing it, `npx -y dembrandt@0.39.2 <url> --design-md`, and close the need against the measured tokens
25
25
  - a Figma file from the client, through the Framelink MCP when the user set it up (see [component-sources](../../wizz-premium-landing-ui-researcher/references/component-sources.md))
26
26
 
27
- Cache freshness rule: check the revision and date before treating a cached item as current. A stale cache is still a valid source for a pattern; it is not a valid source for an API. When the cache answers a need, record the revision in the discovery, not just the path. For registry sources, the live index (`https://ui.shadcn.com/r/registries.json`, `health` per registry) is the freshness check: it costs one request and needs no clone.
27
+ Cache freshness rule: check the revision and date before treating a cached item as current (`uv run --no-cache ../wizz-premium-landing-ui-researcher/scripts/design_sources.py freshness` from this skill's folder answers it for every cached clone). A stale cache is still a valid source for a pattern; it is not a valid source for an API. When the cache answers a need, record the revision in the discovery, not just the path. For registry sources, the live index (`https://ui.shadcn.com/r/registries.json`, `health` per registry) is the freshness check: it costs one request and needs no clone.
28
28
 
29
29
  User-supplied material outranks every catalogue. A reference the user chose is worth more than a better reference they did not.
30
30