wizz-method 2.21.0 → 2.23.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 (179) hide show
  1. package/THIRD-PARTY-NOTICES.md +24 -0
  2. package/package.json +4 -2
  3. package/removals.txt +3 -0
  4. package/skills-registry.yaml +133 -4
  5. package/src/bmm-skills/1-analysis/research/wizz-market-research/steps/step-06-research-completion.md +27 -0
  6. package/src/bmm-skills/1-analysis/wizz-set-feature/SKILL.md +1 -1
  7. package/src/bmm-skills/4-implementation/wizz-code-review/SKILL.md +1 -1
  8. package/src/bmm-skills/4-implementation/wizz-create-story/SKILL.md +1 -1
  9. package/src/bmm-skills/4-implementation/wizz-dev-story/SKILL.md +8 -1
  10. package/src/bmm-skills/4-implementation/wizz-quick-dev/SKILL.md +2 -2
  11. package/src/bmm-skills/4-implementation/wizz-quick-dev/step-03-implement.md +2 -0
  12. package/src/bmm-skills/4-implementation/wizz-sprint-status/SKILL.md +1 -1
  13. package/src/core-skills/wizz-party-mode/customize.toml +3 -3
  14. package/src/modules/lowticket/README.md +2 -1
  15. package/src/modules/lowticket/module.yaml +1 -1
  16. package/src/modules/lowticket/skills/wizz-clone-do-expert/SKILL.md +86 -0
  17. package/src/modules/lowticket/skills/wizz-clone-do-expert/references/clone-prompt-template.md +21 -0
  18. package/src/modules/lowticket/skills/wizz-lowticket-trafego/references/reguas.md +2 -0
  19. package/src/modules/wizz/_shared/cerebro.md +1 -1
  20. package/src/modules/wizz/_shared/organizacao.md +2 -2
  21. package/src/modules/wizz/_shared/video-pipeline.md +2 -0
  22. package/src/modules/wizz/agents/wizz-copy/SKILL.md +1 -0
  23. package/src/modules/wizz/agents/wizz-copy/customize.toml +5 -0
  24. package/src/modules/wizz/agents/wizz-copy/knowledge/playbook.md +3 -2
  25. package/src/modules/wizz/agents/wizz-growth/customize.toml +7 -2
  26. package/src/modules/wizz/agents/wizz-growth/knowledge/playbook.md +3 -2
  27. package/src/modules/wizz/agents/wizz-social/knowledge/blueprint-roteiro-viral.md +14 -0
  28. package/src/modules/wizz/agents/wizz-social/knowledge/legenda-instagram.md +12 -0
  29. package/src/skills-lib/wizz-cerebro/SKILL.md +18 -5
  30. package/src/skills-lib/wizz-design-needs/SKILL.md +7 -0
  31. package/src/skills-lib/wizz-design-needs/references/design-state.md +34 -2
  32. package/src/skills-lib/wizz-design-needs/references/gap-analysis.md +1 -1
  33. package/src/skills-lib/wizz-design-needs/scripts/design_state.py +305 -0
  34. package/src/skills-lib/wizz-design-needs/scripts/tests/test_design_state.py +143 -0
  35. package/src/skills-lib/wizz-impeccable/references/design-rules.md +18 -0
  36. package/src/skills-lib/wizz-ios-build/SKILL.md +61 -0
  37. package/src/skills-lib/wizz-motion-3d-director/references/motion-paths.md +2 -0
  38. package/src/skills-lib/wizz-offer-forge/SKILL.md +2 -2
  39. package/src/skills-lib/wizz-paid-ads/SKILL.md +2 -1
  40. package/src/skills-lib/wizz-paywall-upgrade-cro/SKILL.md +1 -0
  41. package/src/skills-lib/{wizz-pesquisa-de-publico-do-piva → wizz-pesquisa-de-publico}/README.md +13 -13
  42. package/src/skills-lib/{wizz-pesquisa-de-publico-do-piva → wizz-pesquisa-de-publico}/SKILL.md +11 -7
  43. package/src/skills-lib/{wizz-pesquisa-de-publico-do-piva → wizz-pesquisa-de-publico}/assets/template.html +8 -21
  44. package/src/skills-lib/wizz-pesquisa-de-publico/references/interview-mode.md +69 -0
  45. package/src/skills-lib/wizz-premium-landing-ui-researcher/SKILL.md +6 -2
  46. package/src/skills-lib/wizz-premium-landing-ui-researcher/references/audit-protocol.md +7 -34
  47. package/src/skills-lib/wizz-premium-landing-ui-researcher/references/component-sources.md +25 -0
  48. package/src/skills-lib/wizz-premium-landing-ui-researcher/references/design-sources.yaml +325 -0
  49. package/src/skills-lib/wizz-premium-landing-ui-researcher/references/mandatory-process.md +1 -1
  50. package/src/skills-lib/wizz-premium-landing-ui-researcher/references/mining-rubric.md +123 -0
  51. package/src/skills-lib/wizz-premium-landing-ui-researcher/references/source-first-protocol.md +10 -4
  52. package/src/skills-lib/wizz-premium-landing-ui-researcher/references/web-access-and-evidence.md +1 -1
  53. package/src/skills-lib/wizz-premium-landing-ui-researcher/scripts/design_sources.py +221 -0
  54. package/src/skills-lib/wizz-premium-landing-ui-researcher/scripts/tests/test_design_sources.py +130 -0
  55. package/src/skills-lib/wizz-router/references/routing-table-flat.md +7 -1
  56. package/src/skills-lib/wizz-seo-audit/SKILL.md +4 -0
  57. package/src/skills-lib/wizz-seo-audit/references/gsc-regex-perguntas.md +64 -0
  58. package/src/skills-lib/wizz-signup-flow-cro/SKILL.md +1 -0
  59. package/src/skills-lib/wizz-signup-flow-cro/references/trial-abuse.md +40 -0
  60. package/src/skills-lib/wizz-taste-skill/references/anti-slop-tells.md +8 -0
  61. package/src/skills-lib/wizz-ui-component-curator/SKILL.md +8 -7
  62. package/src/skills-lib/wizz-ui-ux-pro-max/SKILL.md +1 -1
  63. package/src/skills-lib/wizz-ui-ux-pro-max/references/common-rules-checklist.md +11 -0
  64. package/src/skills-lib/wizz-video-effects/LICENSE-motionmaxxing.txt +202 -0
  65. package/src/skills-lib/wizz-video-effects/SKILL.md +7 -2
  66. package/src/skills-lib/wizz-video-effects/assets/chrome/collect_layout.js +113 -0
  67. package/src/skills-lib/wizz-video-effects/assets/effects.config.template.json +45 -0
  68. package/src/skills-lib/wizz-video-effects/references/data-contract.md +32 -1
  69. package/src/skills-lib/wizz-video-effects/references/gates.md +4 -1
  70. package/src/skills-lib/wizz-video-effects/references/one-take.md +41 -0
  71. package/src/skills-lib/wizz-video-effects/scripts/check_chrome.py +376 -0
  72. package/src/skills-lib/wizz-video-effects/scripts/check_dead_frames.py +193 -0
  73. package/src/skills-lib/wizz-video-effects/scripts/check_one_take.py +159 -0
  74. package/src/skills-lib/wizz-video-effects/scripts/config.py +13 -0
  75. package/src/skills-lib/wizz-video-effects/scripts/test_chrome.py +181 -0
  76. package/src/skills-lib/wizz-video-effects/scripts/test_dead_frames.py +171 -0
  77. package/src/skills-lib/wizz-video-effects/scripts/test_one_take.py +126 -0
  78. package/src/skills-lib/wizz-video-styles/LICENSE-lemo-opuscar.txt +21 -0
  79. package/src/skills-lib/wizz-video-styles/SKILL.md +16 -7
  80. package/src/skills-lib/wizz-video-styles/assets/film-styles/dark-keynote.html +78 -0
  81. package/src/skills-lib/wizz-video-styles/assets/film-styles/remotion/Riso.tsx +63 -0
  82. package/src/skills-lib/wizz-video-styles/assets/film-styles/risograph.html +69 -0
  83. package/src/skills-lib/wizz-video-styles/assets/film-styles/swiss-motion.html +84 -0
  84. package/src/skills-lib/wizz-video-styles/references/check-ins.md +25 -0
  85. package/src/skills-lib/wizz-video-styles/references/film-styles/DIRECTOR.md +139 -0
  86. package/src/skills-lib/wizz-video-styles/references/film-styles/archive-lighttable.md +109 -0
  87. package/src/skills-lib/wizz-video-styles/references/film-styles/art-deco.md +112 -0
  88. package/src/skills-lib/wizz-video-styles/references/film-styles/ascii-crt.md +115 -0
  89. package/src/skills-lib/wizz-video-styles/references/film-styles/backrooms.md +125 -0
  90. package/src/skills-lib/wizz-video-styles/references/film-styles/blueprint.md +120 -0
  91. package/src/skills-lib/wizz-video-styles/references/film-styles/brick-toy.md +114 -0
  92. package/src/skills-lib/wizz-video-styles/references/film-styles/briefing-board.md +122 -0
  93. package/src/skills-lib/wizz-video-styles/references/film-styles/caption-news.md +137 -0
  94. package/src/skills-lib/wizz-video-styles/references/film-styles/cel-anime-80s.md +119 -0
  95. package/src/skills-lib/wizz-video-styles/references/film-styles/city-symphony.md +142 -0
  96. package/src/skills-lib/wizz-video-styles/references/film-styles/countdown.md +132 -0
  97. package/src/skills-lib/wizz-video-styles/references/film-styles/crayon-book.md +109 -0
  98. package/src/skills-lib/wizz-video-styles/references/film-styles/dark-keynote.md +117 -0
  99. package/src/skills-lib/wizz-video-styles/references/film-styles/data-physical.md +119 -0
  100. package/src/skills-lib/wizz-video-styles/references/film-styles/dataviz.md +123 -0
  101. package/src/skills-lib/wizz-video-styles/references/film-styles/engraving.md +123 -0
  102. package/src/skills-lib/wizz-video-styles/references/film-styles/game-show.md +118 -0
  103. package/src/skills-lib/wizz-video-styles/references/film-styles/glass-product.md +110 -0
  104. package/src/skills-lib/wizz-video-styles/references/film-styles/halftone-dossier.md +122 -0
  105. package/src/skills-lib/wizz-video-styles/references/film-styles/hd-2d.md +111 -0
  106. package/src/skills-lib/wizz-video-styles/references/film-styles/hologram-hud.md +129 -0
  107. package/src/skills-lib/wizz-video-styles/references/film-styles/impasto.md +124 -0
  108. package/src/skills-lib/wizz-video-styles/references/film-styles/ink-wash.md +120 -0
  109. package/src/skills-lib/wizz-video-styles/references/film-styles/iso-infographic.md +117 -0
  110. package/src/skills-lib/wizz-video-styles/references/film-styles/kino-montage.md +151 -0
  111. package/src/skills-lib/wizz-video-styles/references/film-styles/lidar-survey.md +118 -0
  112. package/src/skills-lib/wizz-video-styles/references/film-styles/living-screencast.md +124 -0
  113. package/src/skills-lib/wizz-video-styles/references/film-styles/lowpoly-island.md +112 -0
  114. package/src/skills-lib/wizz-video-styles/references/film-styles/microgame.md +122 -0
  115. package/src/skills-lib/wizz-video-styles/references/film-styles/microscope.md +108 -0
  116. package/src/skills-lib/wizz-video-styles/references/film-styles/midcentury-toon.md +124 -0
  117. package/src/skills-lib/wizz-video-styles/references/film-styles/news-package.md +158 -0
  118. package/src/skills-lib/wizz-video-styles/references/film-styles/newsreel.md +136 -0
  119. package/src/skills-lib/wizz-video-styles/references/film-styles/one-line.md +114 -0
  120. package/src/skills-lib/wizz-video-styles/references/film-styles/paper-lantern.md +116 -0
  121. package/src/skills-lib/wizz-video-styles/references/film-styles/paper-popup.md +119 -0
  122. package/src/skills-lib/wizz-video-styles/references/film-styles/papercut-red.md +110 -0
  123. package/src/skills-lib/wizz-video-styles/references/film-styles/pictogram-motion.md +119 -0
  124. package/src/skills-lib/wizz-video-styles/references/film-styles/pixel-rpg.md +117 -0
  125. package/src/skills-lib/wizz-video-styles/references/film-styles/risograph.md +125 -0
  126. package/src/skills-lib/wizz-video-styles/references/film-styles/rubber-hose.md +112 -0
  127. package/src/skills-lib/wizz-video-styles/references/film-styles/satellite-briefing.md +116 -0
  128. package/src/skills-lib/wizz-video-styles/references/film-styles/scifi-toon.md +121 -0
  129. package/src/skills-lib/wizz-video-styles/references/film-styles/shadow-puppet.md +124 -0
  130. package/src/skills-lib/wizz-video-styles/references/film-styles/silent-film.md +109 -0
  131. package/src/skills-lib/wizz-video-styles/references/film-styles/silkscreen-poster.md +140 -0
  132. package/src/skills-lib/wizz-video-styles/references/film-styles/spy-titles.md +116 -0
  133. package/src/skills-lib/wizz-video-styles/references/film-styles/stained-glass.md +123 -0
  134. package/src/skills-lib/wizz-video-styles/references/film-styles/swiss-motion.md +115 -0
  135. package/src/skills-lib/wizz-video-styles/references/film-styles/teardown.md +127 -0
  136. package/src/skills-lib/wizz-video-styles/references/film-styles/telestrator.md +137 -0
  137. package/src/skills-lib/wizz-video-styles/references/film-styles/tilt-shift.md +107 -0
  138. package/src/skills-lib/wizz-video-styles/references/film-styles/ukiyoe.md +112 -0
  139. package/src/skills-lib/wizz-video-styles/references/film-styles/urban-sketch.md +126 -0
  140. package/src/skills-lib/wizz-video-styles/references/film-styles/visual-investigation.md +140 -0
  141. package/src/skills-lib/wizz-video-styles/references/film-styles/watercolor.md +113 -0
  142. package/src/skills-lib/wizz-video-styles/references/film-styles/white-model.md +115 -0
  143. package/src/skills-lib/wizz-video-styles/references/film-styles/whiteboard.md +118 -0
  144. package/src/skills-lib/wizz-video-styles/references/film-styles/woodcut.md +122 -0
  145. package/src/skills-lib/wizz-video-styles/references/film-styles.md +140 -0
  146. package/src/skills-lib/wizz-video-styles/references/insert-recipes.md +33 -0
  147. package/src/skills-lib/wizz-video-styles/references/motion-laws.md +62 -0
  148. package/src/skills-lib/wizz-video-styles/references/styles/desafio-numero.md +1 -0
  149. package/src/skills-lib/wizz-video-styles/scripts/beat_grid.py +38 -6
  150. package/src/skills-lib/wizz-video-styles/scripts/blind_review.py +159 -0
  151. package/src/skills-lib/wizz-video-styles/scripts/taste.mjs +110 -0
  152. package/src/skills-lib/wizz-video-styles/scripts/test_blind_review.py +82 -0
  153. package/src/skills-lib/wizz-vsl/LICENSE +49 -0
  154. package/src/skills-lib/wizz-vsl/SKILL.md +122 -0
  155. package/src/skills-lib/wizz-vsl/references/assembly-qa.md +123 -0
  156. package/src/skills-lib/wizz-vsl/references/blocks-and-leads.md +149 -0
  157. package/src/skills-lib/wizz-vsl/references/diagnosis.md +95 -0
  158. package/src/skills-lib/wizz-vsl/references/intake.md +200 -0
  159. package/src/skills-lib/wizz-vsl/references/mechanisms.md +138 -0
  160. package/src/skills-lib/wizz-vsl/references/niches.md +40 -0
  161. package/src/skills-lib/wizz-vsl/references/offer.md +91 -0
  162. package/src/skills-lib/wizz-vsl/references/production.md +75 -0
  163. package/src/skills-lib/wizz-web-security/SKILL.md +2 -0
  164. package/tools/hooks/README.md +10 -9
  165. package/tools/hooks/wizz-arrumar.js +1 -0
  166. package/tools/hooks/wizz-artifact-guard.js +31 -5
  167. package/tools/hooks/wizz-cerebro-lib.js +36 -13
  168. package/tools/hooks/wizz-feature-lib.js +4 -1
  169. package/tools/hooks/wizz-feature.js +66 -76
  170. package/tools/hooks/wizz-sprint-archive-lib.js +311 -0
  171. package/tools/installer/core/hooks-settings.js +1 -0
  172. package/tools/installer/core/installer.js +6 -0
  173. package/tools/installer/guided/labels.js +16 -0
  174. package/tools/installer/install-text.js +2 -0
  175. package/tools/installer/modules/cli-config.js +3 -0
  176. package/tools/installer/modules/core-seed.js +72 -0
  177. package/tools/installer/modules/mcp-config.js +3 -0
  178. package/tools/installer/ui.js +22 -26
  179. /package/src/skills-lib/{wizz-pesquisa-de-publico-do-piva → wizz-pesquisa-de-publico}/prompts.md +0 -0
@@ -0,0 +1,221 @@
1
+ # /// script
2
+ # requires-python = ">=3.10"
3
+ # dependencies = ["ruamel.yaml>=0.18"]
4
+ # ///
5
+ """Query the design-source catalogue and keep the local cache honest.
6
+
7
+ Prints ONLY JSON to stdout. Reads ../references/design-sources.yaml.
8
+
9
+ Subcommands:
10
+ list Sources that answer a need tag (--need, repeatable), optionally
11
+ filtered by --kind. Paid sources are listed with their access so
12
+ the miner can apply the paid-source condition; study_only sources
13
+ say so.
14
+ freshness For every source with a `cache` folder: revision, last commit,
15
+ last sync with the remote (FETCH_HEAD, else the clone date), age
16
+ of that sync in days, local changes, and `stale` when the age
17
+ passes max_cache_age_days. --remote also compares HEAD with
18
+ origin (network). Exit 0 always; the JSON carries the verdict.
19
+ refresh Fast-forward the cached clones that have no local changes
20
+ (`git fetch` + `git merge --ff-only`). A clone with local changes
21
+ is skipped and reported, never reset. --id limits it to one source.
22
+
23
+ Run with `uv run --no-cache scripts/design_sources.py <subcommand>`: uv
24
+ provisions ruamel.yaml from the header above.
25
+ """
26
+
27
+ import argparse
28
+ import datetime as dt
29
+ import json
30
+ import os
31
+ import subprocess
32
+ import sys
33
+ from pathlib import Path
34
+
35
+ HERE = Path(__file__).resolve().parent
36
+ CATALOGUE = HERE.parent / "references" / "design-sources.yaml"
37
+
38
+
39
+ def emit(payload, code=0):
40
+ print(json.dumps(payload, ensure_ascii=False, indent=2, default=str))
41
+ sys.exit(code)
42
+
43
+
44
+ def load_catalogue(path):
45
+ from ruamel.yaml import YAML
46
+
47
+ yaml = YAML(typ="safe")
48
+ with open(path, encoding="utf-8") as handle:
49
+ data = yaml.load(handle)
50
+ if not isinstance(data, dict) or not isinstance(data.get("sources"), list):
51
+ raise ValueError(f"{path}: expected a mapping with a `sources` list")
52
+ return data
53
+
54
+
55
+ def cmd_list(data, needs, kind):
56
+ wanted = {tag.lower() for tag in needs}
57
+ rows = []
58
+ for source in data["sources"]:
59
+ tags = {str(tag).lower() for tag in source.get("need_tags") or []}
60
+ if wanted and not wanted & tags:
61
+ continue
62
+ if kind and source.get("kind") != kind:
63
+ continue
64
+ rows.append(
65
+ {
66
+ "id": source["id"],
67
+ "kind": source.get("kind"),
68
+ "access": source.get("access"),
69
+ "license": source.get("license"),
70
+ "study_only": bool(source.get("study_only")),
71
+ "matches": sorted(wanted & tags) if wanted else [],
72
+ "url": source.get("url"),
73
+ "registry": source.get("registry"),
74
+ "note": source.get("note"),
75
+ }
76
+ )
77
+ rows.sort(key=lambda row: (-len(row["matches"]), row["access"] != "free", row["id"]))
78
+ return {"need": sorted(wanted), "count": len(rows), "sources": rows}
79
+
80
+
81
+ def git(repo, *args):
82
+ result = subprocess.run(
83
+ ["git", "-C", str(repo), *args], capture_output=True, text=True, timeout=120
84
+ )
85
+ if result.returncode != 0:
86
+ raise RuntimeError(result.stderr.strip() or f"git {' '.join(args)} failed")
87
+ return result.stdout.strip()
88
+
89
+
90
+ def cache_root(data, override):
91
+ root = override or data.get("cache_root") or "~/.claude/design-sources"
92
+ return Path(os.path.expanduser(root))
93
+
94
+
95
+ def last_sync(repo):
96
+ """When the clone last talked to its remote.
97
+
98
+ FETCH_HEAD is rewritten by every fetch. A clone that was never fetched has
99
+ no FETCH_HEAD, so the last HEAD reflog entry (the clone itself, or the last
100
+ pull) is used. The .git folder's mtime is not: `git status` touches it.
101
+ """
102
+ git_dir = repo / ".git"
103
+ marker = git_dir / "FETCH_HEAD"
104
+ if marker.exists():
105
+ return dt.date.fromtimestamp(marker.stat().st_mtime)
106
+ reflog = git_dir / "logs" / "HEAD"
107
+ if reflog.exists():
108
+ lines = [line for line in reflog.read_text(encoding="utf-8").splitlines() if line.strip()]
109
+ if lines:
110
+ identity = lines[-1].split("\t", 1)[0].split()
111
+ return dt.date.fromtimestamp(int(identity[-2]))
112
+ return None
113
+
114
+
115
+ def remote_status(repo, revision):
116
+ try:
117
+ line = git(repo, "ls-remote", "origin", "HEAD")
118
+ except RuntimeError as error:
119
+ return {"remote": f"unreachable: {error}"}
120
+ remote = line.split()[0] if line else ""
121
+ return {"remote": "current" if remote.startswith(revision) else "behind", "remote_revision": remote[:8]}
122
+
123
+
124
+ def inspect_cache(repo, max_age, today, check_remote):
125
+ if not (repo / ".git").exists():
126
+ return {"present": repo.is_dir(), "error": None if not repo.is_dir() else "not a git clone"}
127
+ try:
128
+ revision = git(repo, "rev-parse", "--short", "HEAD")
129
+ committed = git(repo, "log", "-1", "--format=%cs")
130
+ dirty = bool(git(repo, "status", "--porcelain"))
131
+ except RuntimeError as error:
132
+ return {"present": True, "error": str(error)}
133
+ synced = last_sync(repo)
134
+ if synced is None:
135
+ return {"present": True, "revision": revision, "last_commit": committed, "error": "no fetch or reflog record"}
136
+ age = (today - synced).days
137
+ row = {
138
+ "present": True,
139
+ "revision": revision,
140
+ "last_commit": committed,
141
+ "last_sync": synced.isoformat(),
142
+ "age_days": age,
143
+ "local_changes": dirty,
144
+ "stale": age > max_age,
145
+ }
146
+ if check_remote:
147
+ row.update(remote_status(repo, revision))
148
+ return row
149
+
150
+
151
+ def cmd_freshness(data, root, today, check_remote=False):
152
+ max_age = int(data.get("max_cache_age_days") or 30)
153
+ rows = []
154
+ for source in data["sources"]:
155
+ if not source.get("cache"):
156
+ continue
157
+ row = {"id": source["id"], "path": str(root / source["cache"])}
158
+ row.update(inspect_cache(root / source["cache"], max_age, today, check_remote))
159
+ rows.append(row)
160
+ stale = [row["id"] for row in rows if row.get("stale")]
161
+ return {"max_age_days": max_age, "today": today.isoformat(), "stale": stale, "caches": rows}
162
+
163
+
164
+ def cmd_refresh(data, root, only_id):
165
+ rows = []
166
+ for source in data["sources"]:
167
+ if not source.get("cache") or (only_id and source["id"] != only_id):
168
+ continue
169
+ repo = root / source["cache"]
170
+ row = {"id": source["id"], "path": str(repo)}
171
+ if not repo.is_dir():
172
+ row["result"] = "absent"
173
+ else:
174
+ try:
175
+ if git(repo, "status", "--porcelain"):
176
+ row["result"] = "skipped: local changes"
177
+ else:
178
+ before = git(repo, "rev-parse", "--short", "HEAD")
179
+ git(repo, "fetch", "--quiet")
180
+ git(repo, "merge", "--ff-only", "--quiet", "@{u}")
181
+ after = git(repo, "rev-parse", "--short", "HEAD")
182
+ row["result"] = "updated" if after != before else "already current"
183
+ row["revision"] = after
184
+ except RuntimeError as error:
185
+ row["result"] = f"error: {error}"
186
+ rows.append(row)
187
+ return {"caches": rows}
188
+
189
+
190
+ def main(argv=None):
191
+ parser = argparse.ArgumentParser(prog="design_sources.py")
192
+ parser.add_argument("--catalogue", default=str(CATALOGUE))
193
+ parser.add_argument("--cache-root", default=None)
194
+ sub = parser.add_subparsers(dest="command", required=True)
195
+ listing = sub.add_parser("list")
196
+ listing.add_argument("--need", action="append", default=[])
197
+ listing.add_argument("--kind", default=None)
198
+ fresh = sub.add_parser("freshness")
199
+ fresh.add_argument("--today", default=None, help="YYYY-MM-DD, for tests")
200
+ fresh.add_argument("--remote", action="store_true", help="compare HEAD with origin (network)")
201
+ refresh = sub.add_parser("refresh")
202
+ refresh.add_argument("--id", default=None)
203
+ try:
204
+ args = parser.parse_args(argv)
205
+ except SystemExit as error:
206
+ emit({"error": "invalid arguments"}, int(error.code or 2))
207
+ try:
208
+ data = load_catalogue(args.catalogue)
209
+ except (OSError, ValueError, ImportError) as error:
210
+ emit({"error": str(error)}, 1)
211
+ root = cache_root(data, args.cache_root)
212
+ if args.command == "list":
213
+ emit(cmd_list(data, args.need, args.kind))
214
+ if args.command == "freshness":
215
+ today = dt.date.fromisoformat(args.today) if args.today else dt.date.today()
216
+ emit(cmd_freshness(data, root, today, args.remote))
217
+ emit(cmd_refresh(data, root, args.id))
218
+
219
+
220
+ if __name__ == "__main__":
221
+ main()
@@ -0,0 +1,130 @@
1
+ # /// script
2
+ # requires-python = ">=3.10"
3
+ # dependencies = ["pytest>=8.0", "ruamel.yaml>=0.18"]
4
+ # ///
5
+ """Tests for design_sources.py: list by need tag, cache freshness, refresh."""
6
+
7
+ import datetime as dt
8
+ import importlib.util
9
+ import json
10
+ import os
11
+ import subprocess
12
+ from pathlib import Path
13
+
14
+ import pytest
15
+
16
+ SCRIPT = Path(__file__).resolve().parents[1] / "design_sources.py"
17
+ REAL_CATALOGUE = Path(__file__).resolve().parents[2] / "references" / "design-sources.yaml"
18
+
19
+ spec = importlib.util.spec_from_file_location("design_sources", SCRIPT)
20
+ mod = importlib.util.module_from_spec(spec)
21
+ spec.loader.exec_module(mod)
22
+
23
+ GIT_ENV = {
24
+ **os.environ,
25
+ "GIT_AUTHOR_NAME": "t",
26
+ "GIT_AUTHOR_EMAIL": "t@t",
27
+ "GIT_COMMITTER_NAME": "t",
28
+ "GIT_COMMITTER_EMAIL": "t@t",
29
+ }
30
+
31
+
32
+ def run_main(capsys, *argv):
33
+ with pytest.raises(SystemExit) as exit_info:
34
+ mod.main(list(argv))
35
+ return exit_info.value.code, json.loads(capsys.readouterr().out)
36
+
37
+
38
+ def git(cwd, *args):
39
+ subprocess.run(["git", "-C", str(cwd), *args], check=True, capture_output=True, env=GIT_ENV)
40
+
41
+
42
+ def make_clone(tmp_path, name):
43
+ upstream = tmp_path / f"{name}-upstream"
44
+ upstream.mkdir()
45
+ git(upstream, "init", "-q", "-b", "main")
46
+ (upstream / "a.txt").write_text("1", encoding="utf-8")
47
+ git(upstream, "add", "a.txt")
48
+ git(upstream, "commit", "-q", "-m", "one")
49
+ root = tmp_path / "cache"
50
+ root.mkdir(exist_ok=True)
51
+ subprocess.run(["git", "clone", "-q", str(upstream), str(root / name)], check=True, capture_output=True, env=GIT_ENV)
52
+ return upstream, root
53
+
54
+
55
+ def write_catalogue(tmp_path, cache_name):
56
+ path = tmp_path / "sources.yaml"
57
+ path.write_text(
58
+ "version: 1\nmax_cache_age_days: 30\nsources:\n"
59
+ f" - {{ id: demo, kind: registry, access: free, cache: {cache_name}, need_tags: [hover] }}\n"
60
+ " - { id: paid, kind: code, access: paid, need_tags: [hover, card] }\n"
61
+ " - { id: study, kind: visual, access: free, study_only: true, need_tags: [shader] }\n",
62
+ encoding="utf-8",
63
+ )
64
+ return path
65
+
66
+
67
+ def test_real_catalogue_parses_and_every_source_has_tags(capsys):
68
+ code, out = run_main(capsys, "--catalogue", str(REAL_CATALOGUE), "list")
69
+ assert code == 0
70
+ assert out["count"] > 20
71
+ data = mod.load_catalogue(REAL_CATALOGUE)
72
+ for source in data["sources"]:
73
+ assert source.get("need_tags"), source["id"]
74
+ assert source.get("kind") in {"code", "registry", "engine", "visual", "taste", "extractor"}, source["id"]
75
+
76
+
77
+ def test_real_catalogue_keeps_the_no_license_source_study_only():
78
+ data = mod.load_catalogue(REAL_CATALOGUE)
79
+ ali = next(source for source in data["sources"] if source["id"] == "ali-imam")
80
+ assert ali["study_only"] is True and ali["kind"] == "visual" and ali["license"] is None
81
+
82
+
83
+ def test_list_filters_by_need_and_ranks_free_first(tmp_path, capsys):
84
+ catalogue = write_catalogue(tmp_path, "demo")
85
+ code, out = run_main(capsys, "--catalogue", str(catalogue), "list", "--need", "hover")
86
+ assert code == 0
87
+ assert [row["id"] for row in out["sources"]] == ["demo", "paid"]
88
+ _, shader = run_main(capsys, "--catalogue", str(catalogue), "list", "--need", "shader")
89
+ assert shader["sources"][0]["study_only"] is True
90
+
91
+
92
+ def test_freshness_marks_old_sync_as_stale(tmp_path, capsys):
93
+ _, root = make_clone(tmp_path, "demo")
94
+ catalogue = write_catalogue(tmp_path, "demo")
95
+ future = (dt.date.today() + dt.timedelta(days=45)).isoformat()
96
+ code, out = run_main(capsys, "--catalogue", str(catalogue), "--cache-root", str(root), "freshness", "--today", future)
97
+ assert code == 0
98
+ assert out["stale"] == ["demo"]
99
+ row = out["caches"][0]
100
+ assert row["present"] is True and row["local_changes"] is False and row["age_days"] >= 45
101
+
102
+
103
+ def test_freshness_today_is_fresh_and_absent_cache_is_reported(tmp_path, capsys):
104
+ _, root = make_clone(tmp_path, "demo")
105
+ catalogue = write_catalogue(tmp_path, "demo")
106
+ _, out = run_main(capsys, "--catalogue", str(catalogue), "--cache-root", str(root), "freshness")
107
+ assert out["stale"] == []
108
+ missing = write_catalogue(tmp_path, "nowhere")
109
+ _, absent = run_main(capsys, "--catalogue", str(missing), "--cache-root", str(root), "freshness")
110
+ assert absent["caches"][0]["present"] is False
111
+
112
+
113
+ def test_refresh_fast_forwards_clean_clone_and_skips_dirty_one(tmp_path, capsys):
114
+ upstream, root = make_clone(tmp_path, "demo")
115
+ (upstream / "a.txt").write_text("2", encoding="utf-8")
116
+ git(upstream, "commit", "-q", "-am", "two")
117
+ catalogue = write_catalogue(tmp_path, "demo")
118
+ _, out = run_main(capsys, "--catalogue", str(catalogue), "--cache-root", str(root), "refresh")
119
+ assert out["caches"][0]["result"] == "updated"
120
+ (root / "demo" / "a.txt").write_text("local edit", encoding="utf-8")
121
+ _, dirty = run_main(capsys, "--catalogue", str(catalogue), "--cache-root", str(root), "refresh")
122
+ assert dirty["caches"][0]["result"] == "skipped: local changes"
123
+ assert (root / "demo" / "a.txt").read_text(encoding="utf-8") == "local edit"
124
+
125
+
126
+ def test_bad_catalogue_is_a_json_error(tmp_path, capsys):
127
+ bad = tmp_path / "bad.yaml"
128
+ bad.write_text("nothing: here\n", encoding="utf-8")
129
+ code, out = run_main(capsys, "--catalogue", str(bad), "list")
130
+ assert code == 1 and "sources" in out["error"]
@@ -19,6 +19,8 @@ Use this table to map skills/CLIs/MCPs directly **outside a Wizz project** (no `
19
19
  | **Autonomous, offensive** pentest that actually runs the app and proves each finding with a real PoC | CLI `strix` (qa registry). CONDITIONAL, never the default: only on an app the user owns/is authorized to test, and only when they ask for validated exploitation rather than a review. Start from `wizz-security-audit-pentest` | 2 |
20
20
  | Error monitoring, crash/exception triage, releases and source maps in Sentry | CLI `sentry-cli` (architect registry). CONDITIONAL: only if the project ALREADY uses Sentry (`SENTRY_DSN` in env, `sentry.properties`, or `@sentry/` in package.json) and it's at production stage — never propose adopting Sentry from this row | 2 |
21
21
  | Launch-readiness audit, "is it ready to launch?", broad release checklist (technical, security, SEO, analytics, content, legal, infra), "what's missing before going to production" | `wizz-launch-readiness` | 1 |
22
+ | Build, sign and install an iOS app on the iPhone from the command line without the Xcode IDE (SwiftPM + xtool), also from Linux or Windows/WSL | `wizz-ios-build` + CLI `xtool` (dev registry). Reviewing native UI against the HIG is CLI `apple-design`; TestFlight/App Store is out of scope | 2 |
23
+ | Understand how a feature of a THIRD-PARTY app, Electron app, APK, binary or HAR capture works, without its source, to build a similar one | MCP `rea` (dev registry, optional: recommended, never configured by default; own code is `wizz-investigate`) | 2 |
22
24
  | Desktop, Electron, contextIsolation, code signing | `wizz-desktop-security` | 2 |
23
25
 
24
26
  ## Technical Area — Code and Quality
@@ -62,6 +64,8 @@ Use this table to map skills/CLIs/MCPs directly **outside a Wizz project** (no `
62
64
  | **Edit/cut video** (cuts, selects, roughcut) | CLI `buttercut` (designer registry; **Apple Silicon only**, clone-and-run in the project, heavy deps) | 1 |
63
65
  | Generate an AI video/image (Veo/Kling/Wan), UGC / ad-ready style | `wizz-ad-creative` writes the prompt for the user to paste into Flow or another AI tool. No generation API is integrated in the method | 1 |
64
66
  | Analyze/understand an existing video (frames + transcription) | CLI `claude-video` (designer registry; `npx skills add bradautomates/claude-video`) | 2 |
67
+ | One-take product/app/skill film (10-60 s, no cuts, every beat grows out of the last) made WITH the onetake skill, for personal or noncommercial work | CLI `onetake` (designer registry; opt-in, project scope; PolyForm Noncommercial, client work needs onetake Pro). For client work the one-take technique is `wizz-video-effects` (one-take.md) in the HyperFrames → Remotion pipeline | 2 |
68
+ | Hand-painted cartoon with Clawd, the Claude character (p5.js + p5.brush, 31 acted emotions), for a video where Claude itself appears | CLI `claude-animation-base` (designer registry; clone-and-run in the project). Without Claude as the character, the style is `wizz-video-styles` and the drawn scene is `hyperframes` | 2 |
65
69
  | Narration / voice / TTS / voice cloning for video | CLI `voicebox` (designer registry; local app with MCP endpoint) | 2 |
66
70
  | Research components compatible with the project | `wizz-ui-component-curator` (demos, code, and public registries with evidence) | 1 |
67
71
 
@@ -88,13 +92,15 @@ Use this table to map skills/CLIs/MCPs directly **outside a Wizz project** (no `
88
92
  | Tear down ONE viral Instagram post (Reel, carousel, caption) from its link: why it worked, which hook, a mould to do one like it | `wizz-hook-extractor` (social registry; reads the post itself) | 2 |
89
93
  | Audit and rewrite an Instagram PROFILE: bio, search NAME, link, highlights, pinned posts | `wizz-ig-profile-optimizer` (social registry) | 2 |
90
94
  | Actually PUBLISH/schedule to social networks (Instagram, TikTok, YouTube, LinkedIn and more), not write it | CLI `buffer` (social registry; needs `BUFFER_API_KEY`; media must be a public HTTPS URL). Separates "generate" (Wizz skills above) from "publish" | 2 |
95
+ | VSL (video sales letter) script: expert interview, problem and solution mechanism, spoken offer, leads to test, production beat sheet | `wizz-vsl` (copy registry; the page around the player stays with `wizz-copywriting`) | 2 |
91
96
  | Cold email, B2B outbound, prospecting | `wizz-cold-email` | 2 |
92
97
  | Referral, referrals, affiliate program | `wizz-referral-program` | 2 |
93
98
  | Sales material, pitch, deck, proposal | `wizz-sales-enablement` | 2 |
94
99
  | Free lead-capture tool | `wizz-free-tool-strategy` | 2 |
95
100
  | A/B test, variations, conversion experiments | `wizz-ab-test-setup` + `wizz-analytics-tracking` | 2 |
96
101
  | Copywriting, copy, persuasion, sales text | `wizz-copywriting` + `wizz-humanizer` | 1 |
97
- | Offer audience research, VoC, angle matrix, info-product lexicon | `wizz-pesquisa-de-publico-do-piva` | 1 |
102
+ | Offer audience research, VoC, angle matrix, info-product lexicon | `wizz-pesquisa-de-publico` | 1 |
103
+ | Clone an expert's voice: a GPT/Project that answers students like them, from their lives, audios and posts | `wizz-clone-do-expert` (lowticket module). Persona of the buyer is `wizz-pesquisa-de-publico`; sales copy is `wizz-copywriting` | 1 |
98
104
  | Forge an offer, create an irresistible offer, unique mechanism, bonus, guarantee | `wizz-offer-forge` + `wizz-pricing-strategy` | 1 |
99
105
  | Market research, competitive intelligence | `deep-research` (external plugin — only if installed) | 2 |
100
106
  | Scrape/crawl the web for market research, lead prospecting or competitive intel (anti-bot bypass, adaptive parsing) | MCP `scrapling` (growth registry) — the collection layer under the research rows above | 2 |
@@ -258,6 +258,9 @@ Reporting "no schema found" based solely on `web_fetch` or `curl` leads to false
258
258
  - No keyword cannibalization
259
259
  - Logical topical clusters
260
260
 
261
+ **With Search Console access**
262
+ - Pull the questions people typed with a regex filter on Queries, and check which ones no page answers. Patterns and the follow-up: [gsc-regex-perguntas](references/gsc-regex-perguntas.md)
263
+
261
264
  ---
262
265
 
263
266
  ## Content Quality Assessment
@@ -368,6 +371,7 @@ Same format as above
368
371
  ## References
369
372
 
370
373
  - [AI Writing Detection](references/ai-writing-detection.md): Common AI writing patterns to avoid (em dashes, overused phrases, filler words)
374
+ - [Search Console regex](references/gsc-regex-perguntas.md): regex filters that surface the questions, buying-intent and problem queries people type, and what to do with them
371
375
  - For AI search optimization (AEO, GEO, LLMO, AI Overviews), see the **wizz-ai-seo** skill
372
376
 
373
377
  ---
@@ -0,0 +1,64 @@
1
+ # Search Console: regex to find the questions people type
2
+
3
+ The Queries report hides the most useful thing a site owner has: the exact questions people typed before landing on the site. A regex filter pulls them out in under a minute.
4
+
5
+ ## Where
6
+
7
+ Search Console > Performance > Search results > **+ Add filter** > **Query** > **Custom (regex)** > "Matches regex". Set the date range to the last 3 or 6 months so low-volume questions show up.
8
+
9
+ Rules of the filter (Google uses RE2):
10
+
11
+ - Case-sensitive by default. Start with `(?i)` to ignore case.
12
+ - `^` anchors at the start of the query; without it the word can appear anywhere.
13
+ - Max 4096 characters. No lookahead/lookbehind.
14
+ - "Doesn't match regex" is the inverse: use it to drop brand queries.
15
+
16
+ ## Patterns
17
+
18
+ Questions, Portuguese:
19
+
20
+ ```text
21
+ (?i)^(quem|que|o que|qual|quais|quando|onde|como|por que|porque|quanto|quantos|pode|posso|devo|vale a pena|é possível)\b
22
+ ```
23
+
24
+ Questions, English:
25
+
26
+ ```text
27
+ (?i)^(who|what|when|where|why|how|which|can|should|is|are|does|do|will)\b
28
+ ```
29
+
30
+ Long queries (often conversational or from AI search surfaces):
31
+
32
+ ```text
33
+ ^(\S+\s){6,}\S+$
34
+ ```
35
+
36
+ Buying intent:
37
+
38
+ ```text
39
+ (?i)(comprar|preço|preco|valor|quanto custa|orçamento|orcamento|barato|melhor|vs|versus|alternativa|review|avaliação|price|cost|buy|best|alternative)
40
+ ```
41
+
42
+ Problem and pain (good for top-of-funnel content):
43
+
44
+ ```text
45
+ (?i)(não funciona|nao funciona|erro|problema|como resolver|como consertar|not working|error|fix|problem)
46
+ ```
47
+
48
+ Drop the brand to see only non-branded demand (use with "Doesn't match regex"):
49
+
50
+ ```text
51
+ (?i)(minhamarca|minha marca|mymarca)
52
+ ```
53
+
54
+ ## What to do with the result
55
+
56
+ 1. Export the list (top right > Export) and group the questions by theme.
57
+ 2. For each theme, check whether a page already answers it:
58
+ - Answered, but the page ranks below position 10: add the question as an H2/H3 with a direct answer in the first 40-60 words.
59
+ - Not answered: a new article or an FAQ block on the most relevant page.
60
+ 3. Questions with impressions and almost no clicks are the quick wins: the page shows up but the snippet does not answer.
61
+ 4. Feed buying-intent queries to the landing and pricing pages, not to the blog.
62
+ 5. Repeat every quarter: the list changes with the season and with AI search.
63
+
64
+ FAQ schema helps the page be read correctly, but Google shows FAQ rich results only for a few authoritative sites; do not promise the rich result.
@@ -34,6 +34,7 @@ Before providing recommendations, understand:
34
34
  - `references/trust-and-post-submit.md` — trust copy near the form, error handling, microcopy, and the post-submit experience (success state, verification flows). Load when writing form-adjacent copy or designing what happens right after submit.
35
35
  - `references/measurement-output-patterns.md` — key metrics to track, the output format for an audit/redesign deliverable, and proven signup patterns by product type (B2B SaaS, B2C, waitlist, e-commerce). Load when instrumenting the flow, formatting a deliverable, or looking for a reference pattern.
36
36
  - `references/experiments.md` — a full experiment backlog (form design, copy/messaging, trial/commitment, post-submit) for A/B testing. Load when the deliverable needs a test plan.
37
+ - `references/trial-abuse.md` — why "one trial per IP" blocks real users, and the risk score with three bands (let in / ask for a card or phone / deny) that replaces it. Load when the product has a free trial with a real per-user cost or the user mentions repeated trials, fake accounts or trial abuse.
37
38
 
38
39
  ## Task-Specific Questions
39
40
 
@@ -0,0 +1,40 @@
1
+ # Free trial abuse: score the risk, don't block by IP
2
+
3
+ ## Why "one trial per IP" fails
4
+
5
+ Four people share a house. One starts a free trial. The other three are blocked, because the server does not see four people: it sees one public IP. The same happens in offices, universities, hotels and on mobile networks, where carrier-grade NAT puts thousands of users behind a handful of addresses.
6
+
7
+ Blocking by IP loses real signups (the most expensive kind of drop-off) and barely slows the abuser, who switches network or VPN in seconds.
8
+
9
+ ## What to do instead: a risk score with three bands
10
+
11
+ Collect several weak signals at signup and at trial start, add them up, and route by band. No single signal decides.
12
+
13
+ | Signal | Weight | Note |
14
+ |---|---|---|
15
+ | Disposable email domain | high | Keep a maintained list; update it |
16
+ | Email already used with `+tag` or dot variations (Gmail) | high | Normalise before comparing |
17
+ | Same device/browser fingerprint as a previous trial | high | Fingerprint libraries or the auth provider's device signal; disclose it in the privacy policy |
18
+ | Same payment card fingerprint as a previous trial | very high | The payment provider exposes a card fingerprint without storing the card |
19
+ | Many trials from the same IP **in a short window** | medium | Velocity, not the IP itself |
20
+ | Datacenter/VPN/Tor IP | medium | Legit users use VPNs too; never block on this alone |
21
+ | Phone number already verified on another account | high | Only if the flow already asks for a phone |
22
+ | Bot-like behaviour (form filled in under a second, no mouse/touch events) | medium | Pair with an invisible challenge |
23
+
24
+ Bands:
25
+
26
+ 1. **Low risk: let them in.** The normal flow, no extra field.
27
+ 2. **Medium risk: ask for more commitment.** Card upfront (not charged), phone verification, or a shorter trial. Say why in one line: "Para liberar o teste, confirme um cartão. Nada é cobrado agora."
28
+ 3. **High risk: deny the trial, keep the door open.** Offer the paid plan or a demo call. Never accuse; a generic "não foi possível liberar o teste para esta conta" is enough.
29
+
30
+ ## Rules
31
+
32
+ - **Payment is the strongest signal.** A card fingerprint repeat is the one signal worth acting on alone.
33
+ - **Tune with data.** Log the score and the band of every signup, then compare trial-to-paid and abuse rates per band after 30 days. Move the thresholds, not the signal list.
34
+ - **Measure the cost of false positives.** Count how many real customers came through band 2. If band 2 converts well, the friction is fine; if it kills signups, lower the weights.
35
+ - **Server side only.** The score is computed on the server; the client never sees the weights or the band logic.
36
+ - **Privacy.** Fingerprinting and IP reputation are personal data processing: disclose them, keep only hashes where possible, and set a retention period.
37
+
38
+ ## When it is not worth it
39
+
40
+ Low-cost products where a repeated trial costs little (no AI calls, SMS or heavy infra per user) are better served by a shorter trial or a freemium plan than by a scoring system. Build the score when each trial has a real per-user cost.
@@ -91,6 +91,14 @@ These patterns came out of real LLM-generated landing-page tests. They are the s
91
91
  * **Scroll cues are banned.** `Scroll`, `↓ scroll`, `Scroll to explore`, `Scroll to walk through it`, animated mouse-wheel icons. If the user has not scrolled yet, they are looking at the hero. They know what scroll is. The bottom of the viewport does not need a label.
92
92
  * **ZERO decorative status dots by default.** A coloured dot before nav items, before list rows, before badges, before status labels is a Tell. Only acceptable when conveying real semantic state (a live indicator on actual server status, a live availability flag) and limited to one per page section.
93
93
 
94
+ ### 9.H Landing-page tells (Wizz addition, moved here from the landing Audit Protocol)
95
+ * **NO identity-free hero formula.** Big headline + subtitle + two side-by-side CTAs, with nothing that could only belong to this brand.
96
+ * **NO `rounded-3xl` on everything.** Radius is a scale with a reason per level, not one oversized value.
97
+ * **NO card stacks on the default `shadow-xl`.** See Section 4.4 for tinted, purposeful elevation.
98
+ * **NO generic testimonial card.** Round avatar + name + title + quoted sentence, repeated in a row. See Section 4.10 for quote formats.
99
+ * **NO centered gradient "Most Popular" badge** on pricing cards.
100
+ * **NO decorative emoji** anywhere other than status microcopy (policy in Section 3.D).
101
+
94
102
  ### 9.G EM-DASH BAN (the single most-violated Tell)
95
103
 
96
104
  **Em-dash (`—`) is COMPLETELY banned.** It is the LLM's signature stylistic crutch and it is the #1 visual Tell in production tests. There is no "limited use" allowance, no "natural language frequency" allowance, no "in body copy is fine" allowance. None.
@@ -40,7 +40,7 @@ Do not ask the user to describe the style unless the project has no inspectable
40
40
 
41
41
  ## 2. Search and inspect public sources
42
42
 
43
- Start with existing project components. Then search the public sources. The full authorized list (React Bits, Cult UI, Watermelon, StyleUI, Skiper UI, Bklit UI, Componentry, shadcn/ui, Ali Imam for study only, plus the reference galleries) lives in one place: [component-sources](../wizz-premium-landing-ui-researcher/references/component-sources.md). Read it instead of relying on memory. Check which registries are healthy today in the live index (`https://ui.shadcn.com/r/registries.json`, see [source-first-protocol](../wizz-premium-landing-ui-researcher/references/source-first-protocol.md) Phase 3). Compare at least two suitable sources per need.
43
+ Start with existing project components. Then search the public sources. The full authorized list (React Bits, Cult UI, Watermelon, StyleUI, Skiper UI, Bklit UI, Componentry, shadcn/ui, Ali Imam for study only, plus the reference galleries) lives in one place, as data: [design-sources.yaml](../wizz-premium-landing-ui-researcher/references/design-sources.yaml). Query it with `uv run --no-cache ../wizz-premium-landing-ui-researcher/scripts/design_sources.py list --need <tag>` instead of relying on memory; [component-sources](../wizz-premium-landing-ui-researcher/references/component-sources.md) holds the policy behind each row. Check which registries are healthy today in the live index (`https://ui.shadcn.com/r/registries.json`, see [source-first-protocol](../wizz-premium-landing-ui-researcher/references/source-first-protocol.md) Phase 3). Compare at least two suitable sources per need.
44
44
 
45
45
  Before the first query, open the access as described in [web-access-and-evidence](../wizz-premium-landing-ui-researcher/references/web-access-and-evidence.md): load the web tools (on Claude Code, WebSearch and WebFetch are deferred and need `ToolSearch`), then fall back to `curl`, `agent-browser` and the local source cache. Search with whatever that step opened: web search (Exa when configured, WebSearch otherwise), WebFetch, scrapling, and `agent-browser` to watch hover and motion live. A tool that errors or hangs is not the end of the research: record the failure, move to the next tool, and never stop without reporting what was and was not checked. With no web and no cache, return BLOCKED instead of recommending from memory.
46
46
 
@@ -53,20 +53,21 @@ Use the inferred style DNA as the search filter. Prefer:
53
53
  - components that can be integrated with minimal stylistic friction
54
54
  - effects that enhance the current direction rather than replace it
55
55
 
56
- ## 3. Curate: show 1–3 candidates max
56
+ ## 3. Judge, select, stop
57
57
 
58
- Do not present unranked lists. Shortlist internally, then surface only the strongest matches.
58
+ Judge every candidate with [mining-rubric](../wizz-premium-landing-ui-researcher/references/mining-rubric.md), in its order: evidence gate, dedup against what the project already selected, entry conditions, the 0-10 score with the cut at 6, the verdict. Select by its selection rule and close the need on its stop conditions (a 9 or more, the source budget, or 2 dry sources in a row). With a `design-state.yaml`, every candidate goes back as a discovery, rejected ones with their reason, so the next round does not open them again. Then run `uv run --no-cache ../wizz-design-needs/scripts/design_state.py validate {output_folder}/design-state.yaml` and fix its findings before handing off.
59
59
 
60
60
  Only candidates that pass the evidence gate in [web-access-and-evidence](../wizz-premium-landing-ui-researcher/references/web-access-and-evidence.md) can be shown here. The rest are UNVERIFIED and go to the evidence section.
61
61
 
62
- For each candidate, say briefly:
63
- - why it fits
62
+ Show the selected one and at most two runners-up. For each, say briefly:
63
+ - verdict and score
64
+ - why it fits (the rubric's `por_que`)
64
65
  - what role it plays
65
66
  - any tradeoff
66
67
 
67
68
  ## 4. Plan before editing
68
69
 
69
- Provide a compact plan: what changes, which files, any dependency or styling adaptation needed.
70
+ Write the adaptation in the rubric's order (pattern, why it works, invariant, variable, reimplementation), then a compact plan: what changes, which files, any dependency or styling adaptation needed. A visual reference gives structure and principle, never CSS.
70
71
 
71
72
  ## 5. Present evidence and proceed within scope
72
73
 
@@ -124,7 +125,7 @@ If the project is stylistically mixed: anchor to the direction already establish
124
125
  Short summary of inferred design language (3–5 lines max).
125
126
 
126
127
  ## Best fit
127
- Top recommendation + why it fits + role it plays.
128
+ Top recommendation + verdict and score + why it fits + role it plays + which stop condition closed the need.
128
129
 
129
130
  ## Alternatives
130
131
  Up to 2 backup options only if genuinely different and useful.
@@ -45,4 +45,4 @@ Use one dominant intent and 2–5 meaningful terms per query. Verify the returne
45
45
  - `references/workflow-guide.md` — Python prerequisites + the complete 4-step workflow (analyze → generate design system with `--persist`/hierarchical page overrides → supplement with domain searches → stack guidelines) + a full worked example + tips. Load when actually executing a build/review, not just deciding whether to use the skill.
46
46
  - `references/rules-quick-reference.md` — the 8 priority rule categories (accessibility, touch, performance, layout, typography, animation, style, charts) with every rule ID inside each. Load when auditing existing code for UX issues.
47
47
  - `references/search-reference.md` — full table of the 10 search `--domain` values and 10 `--stack` values with example keywords, plus `--design-system` output format flags (ascii/markdown). Load when picking which domain/stack/format to search or output.
48
- - `references/common-rules-checklist.md` — commonly-missed "looks unprofessional" rules (icons, hover, light/dark contrast, spacing) as do/don't tables, plus the pre-delivery QA checklist. Load right before delivering UI code.
48
+ - `references/common-rules-checklist.md` — commonly-missed "looks unprofessional" rules (icons, hover, light/dark contrast, spacing) as do/don't tables, plus the pre-delivery QA checklist and the design-system audit (list the failing items, fix 3, one at a time). Load right before delivering UI code or publishing.
@@ -74,3 +74,14 @@ Before delivering UI code, verify these items:
74
74
  - [ ] Form inputs have labels
75
75
  - [ ] Color is not the only indicator
76
76
  - [ ] `prefers-reduced-motion` respected
77
+
78
+ ## Design-System Audit (before publishing)
79
+
80
+ Run this once the page or project is feature-complete, before publishing. It audits the system (tokens, components, states), not a single screen.
81
+
82
+ 1. Ask for the list: check the project against the Design System Checklist (https://www.designsystemchecklist.com/) and this file's checklist, and return **only the failing items**, each with the file or token where it fails. No fixes in this pass.
83
+ 2. Pick 3: the user chooses, or default to the 3 with the widest blast radius (a token or a shared component before a one-off screen).
84
+ 3. Fix one at a time: one item, show the diff, re-check that item, then the next. Never "fix everything" in one pass: it rewrites the project and breaks what already works.
85
+ 4. Repeat steps 2 and 3 only if the user asks; report the items left open.
86
+
87
+ If the checklist site is unreachable, run the audit with this file's checklist alone and say so.