mishkan-harness 0.1.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 (186) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +205 -0
  3. package/bin/mishkan.js +221 -0
  4. package/docs/design/MISHKAN_agent_aliases.md +140 -0
  5. package/docs/design/MISHKAN_decisions.md +172 -0
  6. package/docs/design/MISHKAN_harness_design.md +820 -0
  7. package/docs/design/MISHKAN_ontology.md +87 -0
  8. package/docs/design/MISHKAN_token_optimisation.md +181 -0
  9. package/docs/engineer/README.md +37 -0
  10. package/docs/engineer/profile.example.md +79 -0
  11. package/docs/usage/01-installation.md +178 -0
  12. package/docs/usage/02-project-init.md +151 -0
  13. package/docs/usage/03-orchestration.md +218 -0
  14. package/docs/usage/04-memory-layer.md +201 -0
  15. package/docs/usage/05-selective-ingest.md +177 -0
  16. package/docs/usage/06-llm-providers.md +195 -0
  17. package/docs/usage/07-troubleshooting.md +316 -0
  18. package/docs/usage/08-glossary.md +154 -0
  19. package/docs/usage/09-workflows.md +123 -0
  20. package/docs/usage/README.md +77 -0
  21. package/package.json +43 -0
  22. package/payload/install/settings.hooks.json +47 -0
  23. package/payload/mishkan/AGENT_SPEC.md +154 -0
  24. package/payload/mishkan/agents/ahikam.md +58 -0
  25. package/payload/mishkan/agents/aholiab.md +68 -0
  26. package/payload/mishkan/agents/asaph.md +73 -0
  27. package/payload/mishkan/agents/baruch.md +88 -0
  28. package/payload/mishkan/agents/benaiah.md +76 -0
  29. package/payload/mishkan/agents/bezalel.md +83 -0
  30. package/payload/mishkan/agents/caleb.md +74 -0
  31. package/payload/mishkan/agents/deborah.md +63 -0
  32. package/payload/mishkan/agents/elasah.md +58 -0
  33. package/payload/mishkan/agents/eliashib.md +68 -0
  34. package/payload/mishkan/agents/ezra.md +69 -0
  35. package/payload/mishkan/agents/hanun.md +64 -0
  36. package/payload/mishkan/agents/hiram.md +68 -0
  37. package/payload/mishkan/agents/hizkiah.md +76 -0
  38. package/payload/mishkan/agents/huldah.md +59 -0
  39. package/payload/mishkan/agents/huram.md +66 -0
  40. package/payload/mishkan/agents/hushai.md +59 -0
  41. package/payload/mishkan/agents/igal.md +58 -0
  42. package/payload/mishkan/agents/ira.md +86 -0
  43. package/payload/mishkan/agents/jahaziel.md +71 -0
  44. package/payload/mishkan/agents/jakin.md +66 -0
  45. package/payload/mishkan/agents/jehonathan.md +62 -0
  46. package/payload/mishkan/agents/jehoshaphat.md +68 -0
  47. package/payload/mishkan/agents/joab.md +71 -0
  48. package/payload/mishkan/agents/joah.md +62 -0
  49. package/payload/mishkan/agents/maaseiah.md +61 -0
  50. package/payload/mishkan/agents/meremoth.md +65 -0
  51. package/payload/mishkan/agents/meshullam.md +67 -0
  52. package/payload/mishkan/agents/nathan.md +70 -0
  53. package/payload/mishkan/agents/nehemiah.md +93 -0
  54. package/payload/mishkan/agents/obed.md +60 -0
  55. package/payload/mishkan/agents/oholiab.md +67 -0
  56. package/payload/mishkan/agents/palal.md +63 -0
  57. package/payload/mishkan/agents/phinehas.md +73 -0
  58. package/payload/mishkan/agents/rehum.md +60 -0
  59. package/payload/mishkan/agents/salma.md +69 -0
  60. package/payload/mishkan/agents/seraiah.md +73 -0
  61. package/payload/mishkan/agents/shallum.md +66 -0
  62. package/payload/mishkan/agents/shaphan.md +64 -0
  63. package/payload/mishkan/agents/shemaiah.md +67 -0
  64. package/payload/mishkan/agents/shevna.md +58 -0
  65. package/payload/mishkan/agents/uriah.md +70 -0
  66. package/payload/mishkan/agents/zaccur.md +58 -0
  67. package/payload/mishkan/agents/zadok.md +67 -0
  68. package/payload/mishkan/agents/zerubbabel.md +69 -0
  69. package/payload/mishkan/cognee/.env.curated.example +61 -0
  70. package/payload/mishkan/cognee/.env.example +165 -0
  71. package/payload/mishkan/cognee/Dockerfile +50 -0
  72. package/payload/mishkan/cognee/README.md +129 -0
  73. package/payload/mishkan/cognee/docker-compose.curated-ui.yml +61 -0
  74. package/payload/mishkan/cognee/docker-compose.curated.yml +85 -0
  75. package/payload/mishkan/cognee/docker-compose.hardening.yml +16 -0
  76. package/payload/mishkan/cognee/docker-compose.selfhosted.yml +114 -0
  77. package/payload/mishkan/cognee/docker-compose.ui.yml +70 -0
  78. package/payload/mishkan/cognee/docker-compose.yml +71 -0
  79. package/payload/mishkan/cognee/ingest-curated.py +92 -0
  80. package/payload/mishkan/commands/dep-audit.md +24 -0
  81. package/payload/mishkan/commands/mishkan-init.md +25 -0
  82. package/payload/mishkan/commands/mishkan-resume.md +21 -0
  83. package/payload/mishkan/commands/promote.md +19 -0
  84. package/payload/mishkan/commands/sefer-pull.md +19 -0
  85. package/payload/mishkan/commands/sprint-close.md +21 -0
  86. package/payload/mishkan/config/curated-library.yaml +113 -0
  87. package/payload/mishkan/config/improvement-queries.md +29 -0
  88. package/payload/mishkan/config/model-routing.yaml +87 -0
  89. package/payload/mishkan/config/projects.yaml +38 -0
  90. package/payload/mishkan/evals/baruch/README.md +93 -0
  91. package/payload/mishkan/evals/baruch/fixtures/invalid/bad-outcome-enum.json +15 -0
  92. package/payload/mishkan/evals/baruch/fixtures/invalid/bad-sprint-pattern.json +15 -0
  93. package/payload/mishkan/evals/baruch/fixtures/invalid/bad-trigger-enum.json +15 -0
  94. package/payload/mishkan/evals/baruch/fixtures/invalid/malformed-json.json +7 -0
  95. package/payload/mishkan/evals/baruch/fixtures/invalid/missing-required-field.json +14 -0
  96. package/payload/mishkan/evals/baruch/fixtures/valid/blocked-vendor.json +15 -0
  97. package/payload/mishkan/evals/baruch/fixtures/valid/curated-shortcircuit.json +15 -0
  98. package/payload/mishkan/evals/baruch/fixtures/valid/partial-no-write.json +14 -0
  99. package/payload/mishkan/evals/baruch/fixtures/valid/resolved-cross-harness.json +15 -0
  100. package/payload/mishkan/evals/baruch/golden_case/expected.yaml +35 -0
  101. package/payload/mishkan/evals/baruch/golden_case/input.yaml +47 -0
  102. package/payload/mishkan/evals/baruch/golden_case/produced.json +15 -0
  103. package/payload/mishkan/evals/baruch/run.sh +129 -0
  104. package/payload/mishkan/hooks/model-route.py +96 -0
  105. package/payload/mishkan/hooks/post-tool-observe.sh +45 -0
  106. package/payload/mishkan/hooks/pre-tool-security.sh +150 -0
  107. package/payload/mishkan/hooks/session-start.sh +20 -0
  108. package/payload/mishkan/hooks/stop-reporter.sh +29 -0
  109. package/payload/mishkan/ontology.md +87 -0
  110. package/payload/mishkan/rules/backend/yasad.md +23 -0
  111. package/payload/mishkan/rules/common/dependencies.md +53 -0
  112. package/payload/mishkan/rules/common/quality.md +16 -0
  113. package/payload/mishkan/rules/common/security.md +20 -0
  114. package/payload/mishkan/rules/documentation/sefer.md +19 -0
  115. package/payload/mishkan/rules/frontend/panim.md +21 -0
  116. package/payload/mishkan/rules/infrastructure/migdal.md +22 -0
  117. package/payload/mishkan/scripts/dependency-audit.sh +171 -0
  118. package/payload/mishkan/scripts/ensure-curated-box.sh +66 -0
  119. package/payload/mishkan/scripts/mishkan-ingest.sh +92 -0
  120. package/payload/mishkan/scripts/observability-aggregate.sh +57 -0
  121. package/payload/mishkan/scripts/seed-curated-library.sh +62 -0
  122. package/payload/mishkan/scripts/sync-profile.sh +65 -0
  123. package/payload/mishkan/scripts/validate-research-log.sh +108 -0
  124. package/payload/mishkan/skills/asaph-a11y-seo-craft/SKILL.md +289 -0
  125. package/payload/mishkan/skills/baruch-research-reporting-craft/SKILL.md +460 -0
  126. package/payload/mishkan/skills/benaiah-devsecops-craft/SKILL.md +329 -0
  127. package/payload/mishkan/skills/bezalel-cto-craft/SKILL.md +391 -0
  128. package/payload/mishkan/skills/caleb-web-research-craft/SKILL.md +306 -0
  129. package/payload/mishkan/skills/cognee-promote/SKILL.md +40 -0
  130. package/payload/mishkan/skills/cognee-quickstart/SKILL.md +66 -0
  131. package/payload/mishkan/skills/context-compress/SKILL.md +36 -0
  132. package/payload/mishkan/skills/deborah-ux-craft/SKILL.md +295 -0
  133. package/payload/mishkan/skills/dependency-audit/SKILL.md +59 -0
  134. package/payload/mishkan/skills/dependency-vetting/SKILL.md +59 -0
  135. package/payload/mishkan/skills/documentation-craft/SKILL.md +468 -0
  136. package/payload/mishkan/skills/ezra-research-formulation-craft/SKILL.md +319 -0
  137. package/payload/mishkan/skills/hanun-observability-craft/SKILL.md +312 -0
  138. package/payload/mishkan/skills/hiram-ui-craft/SKILL.md +334 -0
  139. package/payload/mishkan/skills/hizkiah-implementation-craft/SKILL.md +701 -0
  140. package/payload/mishkan/skills/hushai-security-advisor-craft/SKILL.md +282 -0
  141. package/payload/mishkan/skills/ira-code-security-craft/SKILL.md +553 -0
  142. package/payload/mishkan/skills/jakin-intent-clarification-craft/SKILL.md +299 -0
  143. package/payload/mishkan/skills/jehonathan-publication-craft/SKILL.md +262 -0
  144. package/payload/mishkan/skills/joab-app-security-craft/SKILL.md +266 -0
  145. package/payload/mishkan/skills/meremoth-devops-craft/SKILL.md +298 -0
  146. package/payload/mishkan/skills/meshullam-infra-design-craft/SKILL.md +302 -0
  147. package/payload/mishkan/skills/mishkan-ingest/SKILL.md +65 -0
  148. package/payload/mishkan/skills/mishkan-init/SKILL.md +65 -0
  149. package/payload/mishkan/skills/nathan-architecture-craft/SKILL.md +547 -0
  150. package/payload/mishkan/skills/nehemiah-pm-craft/SKILL.md +484 -0
  151. package/payload/mishkan/skills/obed-asset-pipeline-craft/SKILL.md +286 -0
  152. package/payload/mishkan/skills/oholiab-design-system-craft/SKILL.md +334 -0
  153. package/payload/mishkan/skills/palal-systems-craft/SKILL.md +281 -0
  154. package/payload/mishkan/skills/qa-evaluation-craft/SKILL.md +406 -0
  155. package/payload/mishkan/skills/rehum-sre-advisor-craft/SKILL.md +228 -0
  156. package/payload/mishkan/skills/reporter-discipline-craft/SKILL.md +351 -0
  157. package/payload/mishkan/skills/research-pipeline/SKILL.md +55 -0
  158. package/payload/mishkan/skills/salma-frontend-implementation-craft/SKILL.md +369 -0
  159. package/payload/mishkan/skills/sefer-pull/SKILL.md +37 -0
  160. package/payload/mishkan/skills/shallum-database-craft/SKILL.md +347 -0
  161. package/payload/mishkan/skills/shaphan-summarisation-craft/SKILL.md +271 -0
  162. package/payload/mishkan/skills/shemaiah-evaluation-craft/SKILL.md +342 -0
  163. package/payload/mishkan/skills/sprint-report/SKILL.md +28 -0
  164. package/payload/mishkan/skills/team-lead-craft/SKILL.md +457 -0
  165. package/payload/mishkan/skills/zadok-contract-craft/SKILL.md +520 -0
  166. package/payload/mishkan/templates/case-node.schema.json +22 -0
  167. package/payload/mishkan/templates/mcp.json +22 -0
  168. package/payload/mishkan/templates/observability-log.schema.json +24 -0
  169. package/payload/mishkan/templates/project-CLAUDE.md +47 -0
  170. package/payload/mishkan/templates/research-log.schema.json +40 -0
  171. package/payload/mishkan/templates/settings.json +12 -0
  172. package/payload/mishkan/templates/settings.local.json +6 -0
  173. package/payload/mishkan/templates/sprint-state.schema.json +47 -0
  174. package/payload/mishkan/templates/team-report.schema.json +50 -0
  175. package/payload/mishkan/templates/user-CLAUDE.md +62 -0
  176. package/payload/mishkan/workflows/README.md +88 -0
  177. package/payload/mishkan/workflows/mishkan-architecture-panel.js +156 -0
  178. package/payload/mishkan/workflows/mishkan-codebase-audit.js +188 -0
  179. package/payload/mishkan/workflows/mishkan-deep-research.js +251 -0
  180. package/payload/mishkan/workflows/mishkan-init.js +156 -0
  181. package/payload/mishkan/workflows/mishkan-migration-wave.js +180 -0
  182. package/payload/mishkan/workflows/mishkan-release-readiness.js +163 -0
  183. package/payload/mishkan/workflows/mishkan-sprint-close.js +112 -0
  184. package/payload/user/CLAUDE.md +62 -0
  185. package/payload/user/rules/engineer-standards.md +66 -0
  186. package/payload/user/rules/y4nn-standards.md +167 -0
@@ -0,0 +1,369 @@
1
+ ---
2
+ name: salma-frontend-implementation-craft
3
+ description: How Salma implements the visible product against the design system and the API contract — the no-raw-fetch rule, TanStack Query / Router patterns, component co-location, the design-system-only styling rule, state-management discipline, and the responsive/dark-mode/motion implementation contracts. Invoke when implementing frontend features.
4
+ ---
5
+
6
+ # Salma — Frontend Implementation Craft
7
+
8
+ > Not a checklist. How the builder who clothes and covers reasons when
9
+ > handed a Chosheb handoff and a Yasad contract — what she builds, what
10
+ > she refuses to bend, and the rule that she implements the visible
11
+ > product faithfully against the two contracts above her.
12
+
13
+ Invoked when frontend implementation is in scope. Salma works in a
14
+ React / Nuxt 3 / Vue 3 / TypeScript world; the principles are
15
+ framework-agnostic where they can be, framework-specific where they
16
+ must be.
17
+
18
+ ---
19
+
20
+ ## 1. The rule above all other rules
21
+
22
+ **You implement against two contracts: the Chosheb handoff and the
23
+ Yasad API contract. You do not edit either.**
24
+
25
+ Three corollaries:
26
+
27
+ - **No design decisions.** If the handoff is ambiguous, you stop and
28
+ ask Hiram via Huram. You do not "fill in" tasteful defaults; you
29
+ surface and wait.
30
+ - **No contract negotiations.** If the API contract is awkward, you
31
+ stop and route to Huram for Lead-to-Lead with Zerubbabel. You do
32
+ not invent your own shape over it.
33
+ - **No silent state-management additions.** Adding a global store,
34
+ introducing a new state primitive, or changing the data layer is
35
+ an architectural change — `/plan` first.
36
+
37
+ ---
38
+
39
+ ## 2. The questions before writing a component
40
+
41
+ 1. **Which handoff package does this implement?** Quote it. If the
42
+ handoff is missing, stop.
43
+ 2. **Which contract endpoints does this consume?** Quote them. If
44
+ the contract is missing, stop.
45
+ 3. **What is the empty state?** Show it in the implementation, not
46
+ only the loaded state.
47
+ 4. **What is the loading state?** Skeleton, suspense boundary, or
48
+ a placeholder strategy.
49
+ 5. **What is the error state?** Recoverable error UI + a retry path
50
+ where the contract supports it.
51
+ 6. **What is the responsive behaviour?** Implemented to the handoff's
52
+ breakpoints, not improvised.
53
+ 7. **What is the dark-mode behaviour?** Implemented to the handoff;
54
+ no auto-inversion.
55
+ 8. **What is the test?** The contract test (E2E for the surface;
56
+ component test for the component).
57
+
58
+ ---
59
+
60
+ ## 3. Data — TanStack Query, never raw fetch
61
+
62
+ The data layer rules:
63
+
64
+ ```typescript
65
+ // WRONG — raw fetch in a component
66
+ function Dashboard() {
67
+ const [data, setData] = useState(null);
68
+ useEffect(() => {
69
+ fetch("/api/projects").then(r => r.json()).then(setData);
70
+ }, []);
71
+ // ...
72
+ }
73
+
74
+ // RIGHT — TanStack Query through a typed wrapper
75
+ function Dashboard() {
76
+ const { data, isLoading, error } = useProjects();
77
+ if (isLoading) return <ProjectsListSkeleton />;
78
+ if (error) return <ProjectsLoadError onRetry={refetch} />;
79
+ return <ProjectsList projects={data} />;
80
+ }
81
+ ```
82
+
83
+ Three rules:
84
+
85
+ - **No `useEffect` for data fetching.** TanStack Query owns caching,
86
+ refetching, deduplication, retry semantics.
87
+ - **Queries are typed at the API client layer.** A `useProjects()`
88
+ hook composed over a generated OpenAPI client; not ad-hoc
89
+ fetching.
90
+ - **Mutations use `useMutation`.** Optimistic updates through
91
+ `onMutate` / `onError` rollback; never component-local optimistic
92
+ state.
93
+
94
+ ---
95
+
96
+ ## 4. Routing — TanStack Router (when React) / Nuxt routes / Vue Router
97
+
98
+ Three rules:
99
+
100
+ - **Routes are typed.** A `<Link to="/projects/$id">` checks the
101
+ parameter shape at compile time.
102
+ - **Loader functions for required data.** Data needed before a
103
+ route renders loads in the route's loader; not in a `useEffect`
104
+ inside the component.
105
+ - **Search params are typed.** A page with filters reads typed
106
+ search params, not raw `URLSearchParams`.
107
+
108
+ ---
109
+
110
+ ## 5. Components — co-located, contracted, tested
111
+
112
+ Component file structure:
113
+
114
+ ```
115
+ components/MetricTile/
116
+ MetricTile.tsx
117
+ MetricTile.test.tsx
118
+ MetricTile.stories.tsx
119
+ index.ts
120
+ ```
121
+
122
+ Three rules:
123
+
124
+ - **Co-location.** Component, test, story live together. Moving the
125
+ component moves all three.
126
+ - **Props are typed.** No `any`. No `Record<string, unknown>` for
127
+ props; if the shape is dynamic, it has a discriminated union.
128
+ - **One component per file.** Helper components used only by this
129
+ component live as sub-files in the same directory.
130
+
131
+ ---
132
+
133
+ ## 6. Styling — design tokens, never raw utility classes
134
+
135
+ The discipline matches `oholiab-design-system-craft` §3:
136
+
137
+ ```tsx
138
+ // WRONG — raw colour utility classes
139
+ <div className="bg-slate-700 text-zinc-400">
140
+
141
+ // RIGHT — semantic tokens through the theme wrapper
142
+ <div className={cn(theme.surface.default, theme.text.muted)}>
143
+ ```
144
+
145
+ Three rules:
146
+
147
+ - **No raw Tailwind colour / spacing utilities.** Use the system
148
+ tokens. Raw utilities bypass the theming layer.
149
+ - **No inline `style={{ }}`.** Inline styles cannot be themed and
150
+ cannot be visually-tested in Storybook.
151
+ - **No `!important`.** Ever. An `!important` is a specificity
152
+ bug waiting to fire.
153
+
154
+ ---
155
+
156
+ ## 7. State management — local-first, escalate by need
157
+
158
+ The state hierarchy:
159
+
160
+ 1. **Component local state.** `useState` for ephemeral UI.
161
+ 2. **URL state.** Filters, tabs, sort — in the URL so back/forward
162
+ work and the page is shareable.
163
+ 3. **TanStack Query cache.** Server state. Already cached; do not
164
+ duplicate into a global store.
165
+ 4. **Form state.** React Hook Form (or equivalent) for forms with
166
+ validation.
167
+ 5. **Global state.** Pinia / Zustand for genuinely global UI state
168
+ (theme, modal stack, command palette). Last resort.
169
+
170
+ Three rules:
171
+
172
+ - **Do not duplicate server state into Zustand / Pinia.** TanStack
173
+ Query is the cache; a Zustand mirror is a stale-divergence bug
174
+ waiting to fire.
175
+ - **Start local; escalate by need.** Local → URL → server cache →
176
+ global. Each step is a deliberate decision.
177
+ - **Global state additions trigger `/plan`.** New global stores are
178
+ architectural.
179
+
180
+ ---
181
+
182
+ ## 8. Responsive + dark-mode + motion — implement the handoff exactly
183
+
184
+ Salma does not improvise these. The handoff specifies; Salma
185
+ implements.
186
+
187
+ - **Responsive breakpoints come from the handoff** (or the token
188
+ system's breakpoint scale). Custom one-off breakpoints are gaps
189
+ to surface.
190
+ - **Dark mode swaps the theme attribute** (`[data-theme="dark"]`);
191
+ components do not branch on theme in JS.
192
+ - **Motion uses the system's timing tokens** and respects
193
+ `prefers-reduced-motion` with the static fallback from the
194
+ handoff.
195
+
196
+ ---
197
+
198
+ ## 9. Testing — three layers
199
+
200
+ | Layer | What it tests | Tool |
201
+ |---|---|---|
202
+ | Unit / component | The component contract | Vitest + Testing Library |
203
+ | Integration | A page or feature with API mocked at the boundary | Vitest + MSW |
204
+ | E2E | The golden path against a real backend | Playwright |
205
+
206
+ Three rules:
207
+
208
+ - **Contract tests are the primary surface.** E2E tests cover the
209
+ contract clauses end-to-end. Implementation tests fill gaps.
210
+ - **MSW mocks the contract, not the implementation.** The mock
211
+ returns shapes from the OpenAPI; if the contract changes, the
212
+ mock changes.
213
+ - **Do not mock TanStack Query itself.** Mock at the network
214
+ (MSW) or at the typed client; TanStack Query is the cache, not
215
+ the seam.
216
+
217
+ ---
218
+
219
+ ## 10. Worked example — implementing the dashboard empty state
220
+
221
+ Hiram's handoff (`hiram-ui-craft` §8); Yasad's `GET /projects`
222
+ contract returning the list. Salma's path:
223
+
224
+ **§2 answers:**
225
+
226
+ 1. Handoff: `handoff/dashboard-empty-state/`.
227
+ 2. Contract: `GET /projects → ProjectsListResponse` with empty array
228
+ for no projects.
229
+ 3. Empty state: implemented per handoff.
230
+ 4. Loading: `<ProjectsListSkeleton>` (system component).
231
+ 5. Error: `<ProjectsLoadError>` with retry.
232
+ 6. Responsive: 360 / 768 / 1024 breakpoints from handoff.
233
+ 7. Dark mode: `[data-theme="dark"]` swap, tokens from handoff.
234
+ 8. Test: E2E (Playwright) + integration (Vitest + MSW).
235
+
236
+ **Implementation:**
237
+
238
+ ```tsx
239
+ // routes/dashboard.tsx
240
+ export const Route = createFileRoute("/dashboard")({
241
+ loader: ({ context }) => context.queryClient.ensureQueryData(projectsQuery),
242
+ component: DashboardPage,
243
+ });
244
+
245
+ function DashboardPage() {
246
+ const { data: projects, isLoading, error, refetch } = useProjects();
247
+ if (isLoading) return <ProjectsListSkeleton />;
248
+ if (error) return <ProjectsLoadError onRetry={refetch} />;
249
+ if (projects.length === 0) return <DashboardEmptyState />;
250
+ return <ProjectsList projects={projects} />;
251
+ }
252
+
253
+ // components/DashboardEmptyState/DashboardEmptyState.tsx
254
+ function DashboardEmptyState() {
255
+ const { t } = useTranslation();
256
+ return (
257
+ <main aria-labelledby="empty-heading" className={cn(theme.surface.default, "py-12")}>
258
+ <SurfaceIllustration.Empty role="img" aria-label={t("dashboard.empty.illustration_alt")} />
259
+ <h1 id="empty-heading" className={cn(theme.text.primary, "text-2xl font-semibold mt-6")}>
260
+ {t("dashboard.empty.title")}
261
+ </h1>
262
+ <p className={cn(theme.text.muted, "mt-2")}>{t("dashboard.empty.description")}</p>
263
+ <div className="mt-6 flex gap-3">
264
+ <Button variant="primary" autoFocus>
265
+ {t("dashboard.empty.create")}
266
+ </Button>
267
+ <Button variant="ghost">
268
+ {t("dashboard.empty.import")}
269
+ </Button>
270
+ </div>
271
+ </main>
272
+ );
273
+ }
274
+ ```
275
+
276
+ **Tests:**
277
+
278
+ ```tsx
279
+ // E2E (Playwright)
280
+ test("dashboard empty state shows when user has no projects", async ({ page }) => {
281
+ await page.route("**/api/projects", route =>
282
+ route.fulfill({ json: { data: [] } }));
283
+ await page.goto("/dashboard");
284
+ await expect(page.getByRole("heading", { name: /start your first project/i })).toBeVisible();
285
+ await expect(page.getByRole("button", { name: /create project/i })).toBeFocused();
286
+ });
287
+
288
+ // Integration (Vitest + MSW)
289
+ test("DashboardEmptyState renders accessibly", async () => {
290
+ render(<DashboardEmptyState />);
291
+ expect(screen.getByRole("img")).toHaveAccessibleName(/empty workspace/i);
292
+ expect(screen.getByRole("button", { name: /create project/i })).toHaveFocus();
293
+ });
294
+ ```
295
+
296
+ What Salma did:
297
+
298
+ - Used TanStack Router's loader for data + React component for UI.
299
+ - Used TanStack Query through `useProjects`.
300
+ - Tokenised every style.
301
+ - Implemented dark mode through theme tokens, not branching.
302
+ - Tested at E2E + integration layers.
303
+
304
+ What Salma did NOT:
305
+
306
+ - Improvise a different empty-state design.
307
+ - Inline a colour.
308
+ - Skip the import button "because the import flow doesn't exist yet" —
309
+ the handoff specifies it; the button exists, the click handler
310
+ surfaces the not-yet state.
311
+
312
+ ---
313
+
314
+ ## 11. The recurring traps Salma rejects on sight
315
+
316
+ 1. **"I'll use raw fetch; it's simpler."** §3. TanStack Query
317
+ exists precisely because raw fetch hides cache + refetch + retry
318
+ semantics.
319
+
320
+ 2. **"This needs a Zustand store; the data is used in three
321
+ places."** §7. TanStack Query already caches it. Three reads
322
+ from the same query key = one fetch.
323
+
324
+ 3. **"I'll inline the hex; the token doesn't exist yet."** §6. No.
325
+ Surface the token gap to Oholiab; do not inline.
326
+
327
+ 4. **"`!important` is the fastest fix."** §6. Always wrong.
328
+
329
+ 5. **"I'll add a small refactor to the data hook while I'm
330
+ here."** Standards §4 — no scope expansion.
331
+
332
+ 6. **"The handoff is ambiguous, but I think I know what they
333
+ meant."** §1. Stop and surface.
334
+
335
+ 7. **"E2E tests are slow; I'll just write unit tests."** §9.
336
+ Contract tests are the primary surface. E2E coverage of the
337
+ contract clauses is mandatory.
338
+
339
+ 8. **"I'll skip the empty state; the user has data 99% of the
340
+ time."** §2.3. The 1% is the first impression.
341
+
342
+ ---
343
+
344
+ ## 12. Style — Salma's voice
345
+
346
+ - **Boring implementation.** Clever in a UI component is a future
347
+ bug.
348
+ - **Tokens everywhere.** A `theme.text.muted` reads cleaner than
349
+ `text-zinc-400` even if the visual output is identical.
350
+ - **Tests in the same PR.** A component shipped without its tests
351
+ ships incomplete.
352
+ - **Honest at the seams.** Ambiguous handoff or contract = stop,
353
+ surface, wait.
354
+
355
+ The builder who clothes and covers gives the system its visible
356
+ form. The form is faithful to the design and the contract; it does
357
+ not improvise.
358
+
359
+ ---
360
+
361
+ *Cross-references: `~/.claude/rules/y4nn-standards.md`
362
+ (durable §3, no-scope-expansion §4, naming §11),
363
+ `payload/mishkan/skills/team-lead-craft/SKILL.md` (Huram routes to
364
+ Salma), `payload/mishkan/skills/hiram-ui-craft/SKILL.md` (the
365
+ design handoff), `payload/mishkan/skills/oholiab-design-system-
366
+ craft/SKILL.md` (the system Salma styles against),
367
+ `payload/mishkan/skills/zadok-contract-craft/SKILL.md` (the API
368
+ contract Salma consumes), `payload/mishkan/skills/qa-evaluation-
369
+ craft/SKILL.md` (Jahaziel evaluates Salma's work).*
@@ -0,0 +1,37 @@
1
+ ---
2
+ name: sefer-pull
3
+ description: Run a Sefer documentation pull. Two modes — sequential pull at every sprint milestone (after all Team Reporters surface), and triggered pull on high-blast-radius events (major architecture decision, critical security finding closed, schema change). Reads Cognee + reporter outputs, writes to docs/ only.
4
+ ---
5
+
6
+ # sefer-pull
7
+
8
+ Drive a Sefer documentation pull. Sefer is pull-based: it never writes code, only
9
+ `docs/`. It reads from Cognee and Team Reporter outputs.
10
+
11
+ ## Mode A — sequential pull (at milestone)
12
+
13
+ Fires at every sprint milestone after all Team Reporters have surfaced.
14
+
15
+ 1. Jehoshaphat coordinates. Pull all reporter outputs + relevant Cognee nodes.
16
+ 2. **Joah** updates project-layer docs: changelog (Keep a Changelog), ADRs
17
+ (MADR) for decisions made this sprint, API docs (from OpenAPI), runbook revisions.
18
+ 3. **Shevna** updates team-layer docs: component library, security posture, infra
19
+ topology, per-team outputs.
20
+ 4. **Seraiah** updates org-layer docs if cross-project standards changed.
21
+ 5. **Jehonathan** publishes the human-readable docs from the graph.
22
+ 6. **Huldah** assembles the Sefer team-report.
23
+
24
+ ## Mode B — triggered pull (event-driven, no waiting for milestone)
25
+
26
+ Fires immediately on a high-blast-radius event:
27
+ - major architecture decision by Bezalel/Nathan → update ARCHITECTURE + ADR
28
+ - critical security finding closed by Phinehas → update THREAT_MODEL + security posture
29
+ - schema change by Shallum → update data docs + migration runbook
30
+
31
+ Pull only from the team that triggered it; update only the affected docs.
32
+
33
+ ## Constraints
34
+
35
+ Writes to `docs/` only — never code. Every doc dated, Diátaxis quadrant declared,
36
+ sourced from Cognee/reporters (no fabrication). Stateful operations hard stop.
37
+ English only.