claudecode-omc 5.6.8 → 5.9.1

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 (121) hide show
  1. package/.local/skills/prompt-optimizer/SKILL.md +262 -19
  2. package/.omc-curation/ecc-selection.json +80 -0
  3. package/.omc-curation/governance.json +113 -0
  4. package/.omc-curation/sources.lock.json +25 -0
  5. package/README.md +69 -4
  6. package/bundled/manifest.json +5 -5
  7. package/bundled/upstream/anthropic-skills/.omc-source/bundle.json +18 -0
  8. package/bundled/upstream/anthropic-skills/.omc-source/provenance.json +399 -0
  9. package/bundled/upstream/anthropic-skills/skills/claude-api/SKILL.md +18 -17
  10. package/bundled/upstream/anthropic-skills/skills/claude-api/curl/examples.md +9 -9
  11. package/bundled/upstream/anthropic-skills/skills/claude-api/curl/managed-agents.md +4 -4
  12. package/bundled/upstream/anthropic-skills/skills/claude-api/go/managed-agents/README.md +2 -2
  13. package/bundled/upstream/anthropic-skills/skills/claude-api/java/claude-api.md +2 -2
  14. package/bundled/upstream/anthropic-skills/skills/claude-api/java/managed-agents/README.md +2 -2
  15. package/bundled/upstream/anthropic-skills/skills/claude-api/php/claude-api.md +10 -10
  16. package/bundled/upstream/anthropic-skills/skills/claude-api/php/managed-agents/README.md +2 -2
  17. package/bundled/upstream/anthropic-skills/skills/claude-api/python/claude-api/README.md +16 -16
  18. package/bundled/upstream/anthropic-skills/skills/claude-api/python/claude-api/batches.md +3 -3
  19. package/bundled/upstream/anthropic-skills/skills/claude-api/python/claude-api/files-api.md +3 -3
  20. package/bundled/upstream/anthropic-skills/skills/claude-api/python/claude-api/streaming.md +7 -7
  21. package/bundled/upstream/anthropic-skills/skills/claude-api/python/claude-api/tool-use.md +19 -19
  22. package/bundled/upstream/anthropic-skills/skills/claude-api/python/managed-agents/README.md +3 -3
  23. package/bundled/upstream/anthropic-skills/skills/claude-api/ruby/claude-api.md +4 -4
  24. package/bundled/upstream/anthropic-skills/skills/claude-api/ruby/managed-agents/README.md +2 -2
  25. package/bundled/upstream/anthropic-skills/skills/claude-api/shared/error-codes.md +5 -5
  26. package/bundled/upstream/anthropic-skills/skills/claude-api/shared/live-sources.md +3 -1
  27. package/bundled/upstream/anthropic-skills/skills/claude-api/shared/managed-agents-api-reference.md +10 -4
  28. package/bundled/upstream/anthropic-skills/skills/claude-api/shared/managed-agents-core.md +19 -1
  29. package/bundled/upstream/anthropic-skills/skills/claude-api/shared/managed-agents-environments.md +6 -2
  30. package/bundled/upstream/anthropic-skills/skills/claude-api/shared/managed-agents-multiagent.md +1 -1
  31. package/bundled/upstream/anthropic-skills/skills/claude-api/shared/managed-agents-onboarding.md +3 -3
  32. package/bundled/upstream/anthropic-skills/skills/claude-api/shared/managed-agents-overview.md +3 -2
  33. package/bundled/upstream/anthropic-skills/skills/claude-api/shared/managed-agents-self-hosted-sandboxes.md +173 -0
  34. package/bundled/upstream/anthropic-skills/skills/claude-api/shared/managed-agents-tools.md +10 -4
  35. package/bundled/upstream/anthropic-skills/skills/claude-api/shared/model-migration.md +113 -13
  36. package/bundled/upstream/anthropic-skills/skills/claude-api/shared/models.md +14 -11
  37. package/bundled/upstream/anthropic-skills/skills/claude-api/shared/prompt-caching.md +2 -2
  38. package/bundled/upstream/anthropic-skills/skills/claude-api/shared/tool-use-concepts.md +4 -4
  39. package/bundled/upstream/anthropic-skills/skills/claude-api/typescript/claude-api/README.md +15 -15
  40. package/bundled/upstream/anthropic-skills/skills/claude-api/typescript/claude-api/batches.md +2 -2
  41. package/bundled/upstream/anthropic-skills/skills/claude-api/typescript/claude-api/files-api.md +1 -1
  42. package/bundled/upstream/anthropic-skills/skills/claude-api/typescript/claude-api/streaming.md +5 -5
  43. package/bundled/upstream/anthropic-skills/skills/claude-api/typescript/claude-api/tool-use.md +15 -15
  44. package/bundled/upstream/anthropic-skills/skills/claude-api/typescript/managed-agents/README.md +3 -3
  45. package/bundled/upstream/ecc/.omc-source/bundle.json +2 -1
  46. package/bundled/upstream/ecc/.omc-source/last-plan-apply.json +108 -24
  47. package/bundled/upstream/ecc/.omc-source/manifests/.claude-plugin/marketplace.json +3 -3
  48. package/bundled/upstream/ecc/.omc-source/provenance.json +563 -0
  49. package/bundled/upstream/ecc/agents/marketing-agent.md +159 -0
  50. package/bundled/upstream/ecc/agents/react-build-resolver.md +215 -0
  51. package/bundled/upstream/ecc/agents/react-reviewer.md +167 -0
  52. package/bundled/upstream/ecc/agents/typescript-reviewer.md +3 -0
  53. package/bundled/upstream/ecc/commands/harness-audit.md +17 -10
  54. package/bundled/upstream/ecc/commands/marketing-campaign.md +129 -0
  55. package/bundled/upstream/ecc/commands/react-build.md +187 -0
  56. package/bundled/upstream/ecc/commands/react-review.md +170 -0
  57. package/bundled/upstream/ecc/commands/react-test.md +265 -0
  58. package/bundled/upstream/ecc/skills/benchmark-optimization-loop/SKILL.md +69 -0
  59. package/bundled/upstream/ecc/skills/blender-motion-state-inspection/SKILL.md +164 -0
  60. package/bundled/upstream/ecc/skills/canary-watch/SKILL.md +9 -1
  61. package/bundled/upstream/ecc/skills/continuous-learning-v2/hooks/observe.sh +31 -9
  62. package/bundled/upstream/ecc/skills/continuous-learning-v2/scripts/detect-project.sh +38 -4
  63. package/bundled/upstream/ecc/skills/continuous-learning-v2/scripts/instinct-cli.py +319 -12
  64. package/bundled/upstream/ecc/skills/data-throughput-accelerator/SKILL.md +72 -0
  65. package/bundled/upstream/ecc/skills/dynamic-workflow-mode/SKILL.md +123 -0
  66. package/bundled/upstream/ecc/skills/frontend-a11y/SKILL.md +446 -0
  67. package/bundled/upstream/ecc/skills/ito-basket-compare/SKILL.md +63 -0
  68. package/bundled/upstream/ecc/skills/ito-data-atlas-agent/SKILL.md +63 -0
  69. package/bundled/upstream/ecc/skills/ito-market-intelligence/SKILL.md +60 -0
  70. package/bundled/upstream/ecc/skills/ito-trade-planner/SKILL.md +67 -0
  71. package/bundled/upstream/ecc/skills/latency-critical-systems/SKILL.md +73 -0
  72. package/bundled/upstream/ecc/skills/marketing-campaign/SKILL.md +113 -0
  73. package/bundled/upstream/ecc/skills/nextjs-turbopack/SKILL.md +13 -0
  74. package/bundled/upstream/ecc/skills/parallel-execution-optimizer/SKILL.md +72 -0
  75. package/bundled/upstream/ecc/skills/prediction-market-oracle-research/SKILL.md +63 -0
  76. package/bundled/upstream/ecc/skills/prediction-market-risk-review/SKILL.md +60 -0
  77. package/bundled/upstream/ecc/skills/react-patterns/SKILL.md +341 -0
  78. package/bundled/upstream/ecc/skills/react-performance/SKILL.md +574 -0
  79. package/bundled/upstream/ecc/skills/react-testing/SKILL.md +423 -0
  80. package/bundled/upstream/ecc/skills/recsys-pipeline-architect/SKILL.md +114 -0
  81. package/bundled/upstream/ecc/skills/recursive-decision-ledger/SKILL.md +79 -0
  82. package/bundled/upstream/ecc/skills/social-publisher/SKILL.md +115 -0
  83. package/bundled/upstream/ecc/skills/team-agent-orchestration/SKILL.md +110 -0
  84. package/bundled/upstream/ecc/skills/uncloud/SKILL.md +343 -0
  85. package/bundled/upstream/ecc/skills/windows-desktop-e2e/SKILL.md +99 -0
  86. package/bundled/upstream/oh-my-claudecode/.omc-source/bundle.json +2 -1
  87. package/bundled/upstream/oh-my-claudecode/.omc-source/provenance.json +116 -0
  88. package/bundled/upstream/oh-my-claudecode/skills/autopilot/SKILL.md +7 -0
  89. package/bundled/upstream/oh-my-claudecode/skills/cancel/SKILL.md +1 -0
  90. package/bundled/upstream/oh-my-claudecode/skills/deep-interview/SKILL.md +39 -5
  91. package/bundled/upstream/oh-my-claudecode/skills/hud/SKILL.md +1 -0
  92. package/bundled/upstream/oh-my-claudecode/skills/local-build-reminder/SKILL.md +78 -0
  93. package/bundled/upstream/oh-my-claudecode/skills/omc-doctor/SKILL.md +1 -1
  94. package/bundled/upstream/oh-my-claudecode/skills/omc-setup/SKILL.md +26 -10
  95. package/bundled/upstream/oh-my-claudecode/skills/omc-setup/phases/01-install-claude-md.md +3 -3
  96. package/bundled/upstream/oh-my-claudecode/skills/omc-setup/phases/02-configure.md +6 -4
  97. package/bundled/upstream/oh-my-claudecode/skills/omc-setup/phases/03-integrations.md +1 -1
  98. package/bundled/upstream/oh-my-claudecode/skills/omc-setup/phases/04-welcome.md +2 -2
  99. package/bundled/upstream/oh-my-claudecode/skills/omc-teams/SKILL.md +6 -6
  100. package/bundled/upstream/oh-my-claudecode/skills/plan/SKILL.md +44 -32
  101. package/bundled/upstream/oh-my-claudecode/skills/ralph/SKILL.md +45 -21
  102. package/bundled/upstream/oh-my-claudecode/skills/ralplan/SKILL.md +1 -1
  103. package/bundled/upstream/oh-my-claudecode/skills/self-improve/SKILL.md +7 -0
  104. package/bundled/upstream/oh-my-claudecode/skills/self-improve/scripts/resolve-paths.mjs +39 -15
  105. package/bundled/upstream/oh-my-claudecode/skills/team/SKILL.md +132 -90
  106. package/bundled/upstream/oh-my-claudecode/skills/ultragoal/SKILL.md +93 -0
  107. package/bundled/upstream/oh-my-claudecode/skills/ultraqa/SKILL.md +28 -13
  108. package/bundled/upstream/oh-my-claudecode/skills/ultrawork/SKILL.md +7 -0
  109. package/bundled/upstream/superpowers/.omc-source/bundle.json +2 -1
  110. package/bundled/upstream/superpowers/.omc-source/provenance.json +63 -0
  111. package/package.json +2 -1
  112. package/src/catalog/source-catalog.js +10 -4
  113. package/src/cli/index.js +4 -0
  114. package/src/cli/plan.js +14 -2
  115. package/src/cli/setup.js +52 -13
  116. package/src/cli/skill.js +1 -1
  117. package/src/cli/source.js +265 -14
  118. package/src/config/sources.js +67 -1
  119. package/src/merge/content-patch.js +84 -0
  120. package/templates/merge-config.json +1 -8
  121. package/bundled/upstream/ecc/skills/strategic-compact/suggest-compact.sh +0 -54
@@ -0,0 +1,423 @@
1
+ ---
2
+ name: react-testing
3
+ description: React component testing with React Testing Library, Vitest/Jest, MSW for network mocking, accessibility assertions with axe, and the decision boundary between component tests and Playwright/Cypress end-to-end runs. Use when writing or fixing tests for React components, hooks, or pages.
4
+ origin: ECC
5
+ ---
6
+
7
+ # React Testing
8
+
9
+ Comprehensive React testing patterns for behavior-focused component tests, custom hook tests, accessibility assertions, and network-level mocking.
10
+
11
+ ## When to Activate
12
+
13
+ - Writing tests for React components, custom hooks, or pages
14
+ - Adding test coverage to legacy untested components
15
+ - Migrating from Enzyme or class-component-era patterns to React Testing Library
16
+ - Setting up Vitest or Jest for a new React project
17
+ - Mocking HTTP requests in tests
18
+ - Asserting accessibility violations
19
+ - Deciding which tests belong in RTL vs Playwright Component Testing vs full E2E
20
+
21
+ ## Core Principle
22
+
23
+ Test what the user sees and does, not implementation details.
24
+
25
+ A test should:
26
+
27
+ - Render the component with the same providers it has in production
28
+ - Interact with it via accessible queries (role, label) and `userEvent`
29
+ - Assert visible output and observable side effects (callback fired, request sent)
30
+
31
+ A test should NOT:
32
+
33
+ - Inspect component state, props passed to children, or which hooks were called
34
+ - Mock React itself or framework hooks
35
+ - Assert on the number of renders or DOM structure beyond what affects users
36
+
37
+ ## Library Choice
38
+
39
+ | Runner | When | Note |
40
+ |---|---|---|
41
+ | **Vitest** | Vite, Remix, modern setups | Faster, native ESM, Jest-compatible API |
42
+ | **Jest** | Next.js, CRA, established repos | Default for many React projects |
43
+ | **Playwright Component Testing** | Real browser engine needed | Use when JSDOM lacks the required feature |
44
+ | **Cypress Component Testing** | Real browser, Cypress already in use | Alternative to Playwright CT |
45
+
46
+ Pick one. Do not run RTL + Vitest AND Playwright CT in the same repo unless you have a clear lane separation.
47
+
48
+ ## Query Priority
49
+
50
+ React Testing Library exposes queries in three tiers — use top-down:
51
+
52
+ 1. **Accessible to everyone**: `getByRole`, `getByLabelText`, `getByPlaceholderText`, `getByText`, `getByDisplayValue`
53
+ 2. **Semantic**: `getByAltText`, `getByTitle`
54
+ 3. **Test IDs (escape hatch)**: `getByTestId`
55
+
56
+ ```tsx
57
+ // Best
58
+ screen.getByRole("button", { name: /save/i });
59
+
60
+ // OK for inputs
61
+ screen.getByLabelText("Email");
62
+
63
+ // Last resort
64
+ screen.getByTestId("save-btn");
65
+ ```
66
+
67
+ Variants:
68
+
69
+ - `getBy*` — throws if no match
70
+ - `queryBy*` — returns `null` (use for "assert absence")
71
+ - `findBy*` — async, returns a Promise (use for elements that appear after async work)
72
+
73
+ ## User Interaction with `userEvent`
74
+
75
+ ```tsx
76
+ import userEvent from "@testing-library/user-event";
77
+
78
+ test("submits the form", async () => {
79
+ const user = userEvent.setup();
80
+ const onSubmit = vi.fn();
81
+ render(<UserForm onSubmit={onSubmit} />);
82
+
83
+ await user.type(screen.getByLabelText("Email"), "user@example.com");
84
+ await user.click(screen.getByRole("button", { name: /save/i }));
85
+
86
+ expect(onSubmit).toHaveBeenCalledWith({ email: "user@example.com" });
87
+ });
88
+ ```
89
+
90
+ - Always `await` userEvent calls
91
+ - Call `userEvent.setup()` once per test, reuse the returned `user`
92
+ - `userEvent` simulates a real browser sequence; `fireEvent` dispatches a single synthetic event — prefer `userEvent`
93
+
94
+ ## Async Patterns
95
+
96
+ ```tsx
97
+ // Element that appears after async work
98
+ expect(await screen.findByText("Loaded")).toBeInTheDocument();
99
+
100
+ // Side effect assertion
101
+ await waitFor(() => expect(saveSpy).toHaveBeenCalled());
102
+
103
+ // Element that should disappear
104
+ await waitForElementToBeRemoved(() => screen.queryByText("Loading"));
105
+ ```
106
+
107
+ Never `setTimeout` + assertion — flaky. Use the matchers above.
108
+
109
+ ## Network Mocking with MSW
110
+
111
+ Mock Service Worker mocks at the network layer. The component, hooks, and fetch library all behave exactly as in production.
112
+
113
+ ### Setup
114
+
115
+ ```ts
116
+ // test/setup.ts
117
+ import { setupServer } from "msw/node";
118
+ import { http, HttpResponse } from "msw";
119
+
120
+ export const handlers = [
121
+ http.get("/api/users/:id", ({ params }) =>
122
+ HttpResponse.json({ id: params.id, name: "Alice" }),
123
+ ),
124
+ http.post("/api/users", async ({ request }) => {
125
+ const body = await request.json();
126
+ return HttpResponse.json({ id: "new-id", ...body }, { status: 201 });
127
+ }),
128
+ ];
129
+
130
+ export const server = setupServer(...handlers);
131
+
132
+ beforeAll(() => server.listen({ onUnhandledRequest: "error" }));
133
+ afterEach(() => server.resetHandlers());
134
+ afterAll(() => server.close());
135
+ ```
136
+
137
+ Configure `onUnhandledRequest: "error"` so any unmocked request fails the test loudly — silent passes are worse than red.
138
+
139
+ ### Per-test override
140
+
141
+ ```tsx
142
+ test("renders error on 500", async () => {
143
+ server.use(
144
+ http.get("/api/users/:id", () => new HttpResponse(null, { status: 500 })),
145
+ );
146
+ render(<UserPage id="1" />);
147
+ expect(await screen.findByText(/something went wrong/i)).toBeInTheDocument();
148
+ });
149
+ ```
150
+
151
+ ## Provider Wrapping
152
+
153
+ Wrap providers once in a `test-utils.tsx`:
154
+
155
+ ```tsx
156
+ // test-utils.tsx
157
+ import { render, RenderOptions } from "@testing-library/react";
158
+ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
159
+
160
+ export function renderWithProviders(
161
+ ui: React.ReactElement,
162
+ options?: RenderOptions,
163
+ ) {
164
+ const queryClient = new QueryClient({
165
+ defaultOptions: { queries: { retry: false } },
166
+ });
167
+
168
+ return render(
169
+ <QueryClientProvider client={queryClient}>
170
+ <ThemeProvider theme={lightTheme}>
171
+ <MemoryRouter>{ui}</MemoryRouter>
172
+ </ThemeProvider>
173
+ </QueryClientProvider>,
174
+ options,
175
+ );
176
+ }
177
+
178
+ export * from "@testing-library/react";
179
+ ```
180
+
181
+ Then `import { renderWithProviders, screen } from "test-utils"` in every test file.
182
+
183
+ ## Custom Hook Testing
184
+
185
+ ```tsx
186
+ import { renderHook, act } from "@testing-library/react";
187
+
188
+ test("useCounter increments and decrements", () => {
189
+ const { result } = renderHook(() => useCounter(0));
190
+
191
+ expect(result.current.count).toBe(0);
192
+
193
+ act(() => result.current.increment());
194
+ expect(result.current.count).toBe(1);
195
+
196
+ act(() => result.current.decrement());
197
+ expect(result.current.count).toBe(0);
198
+ });
199
+
200
+ test("useCounter accepts initial value", () => {
201
+ const { result } = renderHook(() => useCounter(10));
202
+ expect(result.current.count).toBe(10);
203
+ });
204
+
205
+ test("useUser fetches user data", async () => {
206
+ // Instantiate QueryClient ONCE per test outside the wrapper so it survives re-renders.
207
+ // Creating it inside the wrapper closure resets cache state on every render, producing flaky tests.
208
+ const queryClient = new QueryClient({
209
+ defaultOptions: { queries: { retry: false } },
210
+ });
211
+ const wrapper = ({ children }: { children: React.ReactNode }) => (
212
+ <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
213
+ );
214
+
215
+ const { result } = renderHook(() => useUser("1"), { wrapper });
216
+
217
+ await waitFor(() => expect(result.current.isSuccess).toBe(true));
218
+ expect(result.current.data).toEqual({ id: "1", name: "Alice" });
219
+ });
220
+ ```
221
+
222
+ - Wrap state-changing calls in `act`
223
+ - Test through the hook's public API only
224
+ - For hooks that use context, pass a `wrapper`
225
+
226
+ ## Accessibility Assertions
227
+
228
+ ```tsx
229
+ import { axe, toHaveNoViolations } from "jest-axe"; // or vitest-axe
230
+ expect.extend(toHaveNoViolations);
231
+
232
+ test("UserCard has no a11y violations", async () => {
233
+ const { container } = render(<UserCard user={mockUser} />);
234
+ expect(await axe(container)).toHaveNoViolations();
235
+ });
236
+ ```
237
+
238
+ Run axe in component tests for every interactive component. Catches:
239
+
240
+ - Missing labels on form inputs
241
+ - Invalid ARIA usage
242
+ - Poor color contrast (limited — JSDOM has no real CSS engine, so this works for inline styles only; visual contrast belongs in Playwright)
243
+ - Missing alt text on images
244
+ - Heading order violations
245
+
246
+ Cross-link: [skills/accessibility/SKILL.md](../accessibility/SKILL.md) for the broader a11y testing playbook.
247
+
248
+ ## When NOT to Use Snapshot Tests
249
+
250
+ Snapshots of rendered output:
251
+
252
+ - Break on every styling change
253
+ - Get rubber-stamped during review
254
+ - Test implementation detail (DOM structure), not behavior
255
+
256
+ Acceptable snapshot uses:
257
+
258
+ - Pure data serialization functions (`formatInvoice(invoice)` -> stable string)
259
+ - Generated config files (e.g., webpack config output)
260
+
261
+ For visual regression on components, use Playwright/Cypress screenshots or Percy/Chromatic — actual visual diffs, not DOM strings.
262
+
263
+ ## When to Reach for Playwright / Cypress
264
+
265
+ JSDOM (used by Vitest/Jest) cannot:
266
+
267
+ - Render real layout (flexbox, grid, viewport queries)
268
+ - Run native browser animation, CSS transitions
269
+ - Test scrolling behavior, drag-and-drop, paste from clipboard
270
+ - Handle iframes, popups, downloads, cross-origin flows
271
+ - Run real network in a controlled environment with full DevTools support
272
+
273
+ For any of those, use Playwright Component Testing (component test in real browser) or full E2E. See [e2e-testing skill](../e2e-testing/SKILL.md).
274
+
275
+ Decision boundary:
276
+
277
+ - A hook, a presentational component, a form with logic -> RTL
278
+ - A component whose layout matters or that uses browser APIs not in JSDOM -> Playwright CT
279
+ - A full user flow across multiple pages -> Playwright/Cypress E2E
280
+
281
+ ## Coverage Targets
282
+
283
+ | Layer | Target |
284
+ |---|---|
285
+ | Pure utilities | >=90% |
286
+ | Custom hooks | >=85% |
287
+ | Presentational components | >=80% — behavior, not lines |
288
+ | Container components | >=70% — golden paths + error states |
289
+ | Pages | E2E covered separately; smoke test minimum |
290
+
291
+ Configure via `vitest.config.ts` / `jest.config.js`:
292
+
293
+ ```ts
294
+ // vitest.config.ts
295
+ test: {
296
+ coverage: {
297
+ provider: "v8",
298
+ reporter: ["text", "html", "lcov"],
299
+ thresholds: {
300
+ lines: 80,
301
+ functions: 80,
302
+ branches: 70,
303
+ statements: 80,
304
+ },
305
+ },
306
+ }
307
+ ```
308
+
309
+ ## Anti-Patterns
310
+
311
+ - `container.querySelector("...")` — bypasses accessibility queries, lets tests pass when real users would fail
312
+ - Asserting on number of renders — implementation detail
313
+ - `jest.mock("react", ...)` — never mock React. Refactor the component instead
314
+ - Mocking child components by default — tests the integration, not isolation. Mock only when the child has heavy side effects
315
+ - Ignoring `act()` warnings — they signal real bugs (state update after unmount, missing async wrapping)
316
+ - Sharing mutable state across tests — flakes when test order changes
317
+ - Tests that pass with `it.skip()` removed — your test does not actually assert what you think
318
+
319
+ ## TDD Workflow
320
+
321
+ ```
322
+ RED -> Write failing test for the next requirement
323
+ GREEN -> Write minimal component code to pass
324
+ REFACTOR -> Improve the component, tests stay green
325
+ REPEAT -> Next requirement
326
+ ```
327
+
328
+ For new components:
329
+
330
+ 1. Define the component's prop type and signature
331
+ 2. Write the first test for the simplest case
332
+ 3. Verify it fails for the right reason
333
+ 4. Implement just enough to pass
334
+ 5. Add the next test case
335
+ 6. Refactor when the third similar test reveals a pattern
336
+
337
+ ## Test Commands
338
+
339
+ ```bash
340
+ # Vitest
341
+ vitest # watch
342
+ vitest run # one-shot
343
+ vitest run --coverage # with coverage
344
+ vitest run path/to/file.test.tsx # single file
345
+
346
+ # Jest
347
+ jest --watch
348
+ jest --coverage
349
+ jest path/to/file.test.tsx
350
+
351
+ # CI mode
352
+ CI=true vitest run --coverage
353
+ ```
354
+
355
+ ## Related
356
+
357
+ - Rules: [rules/react/testing.md](../../rules/react/testing.md)
358
+ - Skills: [react-patterns](../react-patterns/SKILL.md), [accessibility](../accessibility/SKILL.md), [e2e-testing](../e2e-testing/SKILL.md), [tdd-workflow](../tdd-workflow/SKILL.md)
359
+ - Agents: `react-reviewer` (reviews test quality during code review), `tdd-guide` (enforces TDD process)
360
+ - Commands: `/react-test`, `/react-review`
361
+
362
+ ## Examples
363
+
364
+ ### Form submission with MSW and userEvent
365
+
366
+ ```tsx
367
+ test("submits user form and shows success", async () => {
368
+ server.use(
369
+ http.post("/api/users", () =>
370
+ HttpResponse.json({ id: "1", name: "Alice" }, { status: 201 }),
371
+ ),
372
+ );
373
+
374
+ const user = userEvent.setup();
375
+ renderWithProviders(<UserForm />);
376
+
377
+ await user.type(screen.getByLabelText("Name"), "Alice");
378
+ await user.type(screen.getByLabelText("Email"), "alice@example.com");
379
+ await user.click(screen.getByRole("button", { name: /save/i }));
380
+
381
+ expect(await screen.findByText(/saved successfully/i)).toBeInTheDocument();
382
+ });
383
+ ```
384
+
385
+ ### Testing an error boundary
386
+
387
+ ```tsx
388
+ function Broken() {
389
+ throw new Error("boom");
390
+ }
391
+
392
+ test("error boundary renders fallback", () => {
393
+ // Suppress React's console.error noise for the expected throw, then restore so
394
+ // the spy does not leak across tests and hide real errors elsewhere.
395
+ const errorSpy = vi.spyOn(console, "error").mockImplementation(() => {});
396
+ try {
397
+ render(
398
+ <ErrorBoundary fallback={<div>Something went wrong</div>}>
399
+ <Broken />
400
+ </ErrorBoundary>,
401
+ );
402
+
403
+ expect(screen.getByText("Something went wrong")).toBeInTheDocument();
404
+ } finally {
405
+ errorSpy.mockRestore();
406
+ }
407
+ });
408
+ ```
409
+
410
+ ### Testing a Suspense boundary
411
+
412
+ ```tsx
413
+ test("shows loading then content", async () => {
414
+ renderWithProviders(
415
+ <Suspense fallback={<div>Loading...</div>}>
416
+ <UserDetail id="1" />
417
+ </Suspense>,
418
+ );
419
+
420
+ expect(screen.getByText("Loading...")).toBeInTheDocument();
421
+ expect(await screen.findByText("Alice")).toBeInTheDocument();
422
+ });
423
+ ```
@@ -0,0 +1,114 @@
1
+ ---
2
+ name: recsys-pipeline-architect
3
+ description: Design composable recommendation, ranking, and feed pipelines using the six-stage Source→Hydrator→Filter→Scorer→Selector→SideEffect framework popularized by xAI's open-sourced For You algorithm. Use this skill whenever the user is building any system that picks "the top K items for a (user, context)" — social feeds, content CMSs, RAG rerankers, task prioritizers, notification triage, search reranking, ad ranking.
4
+ origin: community
5
+ ---
6
+
7
+ # recsys-pipeline-architect
8
+
9
+ A spec-and-scaffold skill for building composable recommendation, ranking, and feed pipelines. It encodes the **six-stage pattern** — Source → Hydrator → Filter → Scorer → Selector → SideEffect — popularized by xAI's open-sourced [For You algorithm](https://github.com/xai-org/x-algorithm) (Apache 2.0). This skill is an independent reimplementation of the pattern (MIT) — no code copied from the original.
10
+
11
+ Upstream: <https://github.com/mturac/recsys-pipeline-architect>
12
+
13
+ ## When to Use
14
+
15
+ - User wants to build any system that picks "the top K items for a user/context"
16
+ - User asks "how should I rank X" or describes a feed/personalization problem
17
+ - User has a scoring function and needs the pipeline plumbing around it
18
+ - User wants to migrate from a single relevance score to multi-action prediction with tunable weights
19
+ - User is wrapping an LLM/ML scorer and needs filters, hydrators, side-effects, and a runnable scaffold in their stack (TypeScript / Go / Python)
20
+ - Triggers: "recommendation system", "feed algorithm", "ranking pipeline", "for you feed", "candidate pipeline", "content recommender", "pipeline architecture for recsys", "RAG retrieval reranker"
21
+
22
+ ## When NOT to Use
23
+
24
+ - Model architecture work (transformer design, two-tower retrieval, embedding training) — this skill is plumbing *around* the model, not the model itself
25
+ - Pure ML training pipelines — the scoring function is the user's responsibility
26
+ - Operating a deployed pipeline (monitoring, autoscaling) — out of scope
27
+
28
+ ## The six-stage framework
29
+
30
+ | # | Stage | Job | Parallel? |
31
+ |---|---|---|---|
32
+ | 1 | **Source** | Fetch candidates from one or more origins | Yes — multiple sources run in parallel |
33
+ | 2 | **Hydrator** | Enrich each candidate with metadata needed for filtering and scoring | Yes — independent hydrators run in parallel |
34
+ | 3 | **Filter** | Drop candidates that should never be shown (blocked, expired, duplicate, ineligible) | Sequential — each filter sees fewer items |
35
+ | 4 | **Scorer** | Assign each surviving candidate one or more scores | Sequential — later scorers see earlier scores |
36
+ | 5 | **Selector** | Sort by final score, return top K | Single op |
37
+ | 6 | **SideEffect** | Cache served IDs, log impressions, emit events, update counters | Async — must never block the response |
38
+
39
+ ### Why this exact order
40
+
41
+ - Sources before hydration: know what candidates exist before paying to enrich them
42
+ - Hydration before filtering: many filters need metadata the source did not provide
43
+ - Filtering before scoring: scoring is the expensive stage; drop the ineligible first
44
+ - Scorer chain (not single scorer): real systems compose ML scoring + diversity reranking + business rules
45
+ - Selector after scoring: keeps scoring deterministic and cacheable
46
+ - SideEffects last and async: side effects must never block the user response
47
+
48
+ ## Workflow when invoked
49
+
50
+ Walk the user through these eight steps:
51
+
52
+ 1. **Clarify the use case** (one round, three questions): items being ranked? input context? language/runtime?
53
+ 2. **Identify the candidate sources**: usually in-network (followed/owned/subscribed) + out-of-network (ML retrieval / trending / similar-to-liked)
54
+ 3. **List required hydrations**: for each filter and scorer, what data does it need that the source did not provide?
55
+ 4. **List the filters**: duplicate, self, age, block/mute, previously-served, eligibility. Order matters — cheap before expensive.
56
+ 5. **Design the scorer chain**: primary (ML) → combiner (multi-action with weights) → diversity → business rules
57
+ 6. **Selector**: sort descending by final score, take top K (or stratified mix for in-network/out-of-network)
58
+ 7. **SideEffects**: cache served IDs, emit impression events, update counters, log analytics — all fire-and-forget
59
+ 8. **Generate the scaffold** in the user's stack
60
+
61
+ ## Key trade-offs to surface (don't default silently)
62
+
63
+ ### 1. Single score vs multi-action prediction
64
+
65
+ - **Single score**: train one model to predict relevance. To change behavior → retrain.
66
+ - **Multi-action**: predict `P(action)` for many actions (read, like, share, skip, report), combine with weights at serving time. To change behavior → change weights. No retraining.
67
+
68
+ The X For You system uses multi-action with both positive and negative weights. Recommend multi-action when the user expects to tune frequently.
69
+
70
+ ### 2. Candidate isolation in scoring
71
+
72
+ - **Isolated**: each candidate scored independently. Deterministic, cacheable.
73
+ - **Joint**: candidates attend to each other during scoring (e.g., transformer over batch). More expressive but non-deterministic across batches.
74
+
75
+ Default to isolation. Joint only when there's a specific reason (e.g., explicit batch-aware diversity).
76
+
77
+ ### 3. Online vs offline
78
+
79
+ - **Request-time (online)**: pipeline runs on each request. Latency budget: 100–300ms. Default.
80
+ - **Pre-computed (offline batch)**: pipeline runs periodically, results cached. Lower latency, lower freshness.
81
+ - **Hybrid**: candidate retrieval offline, ranking online.
82
+
83
+ ## Hard rules
84
+
85
+ 1. **Do not invent benchmark numbers.** "How much faster?" → "depends on workload, run it yourself."
86
+ 2. **Attribution discipline.** When the pattern is referenced, attribute as "popularized by xAI's open-sourced For You algorithm" / `github.com/xai-org/x-algorithm` (Apache 2.0).
87
+ 3. **No trademark use.** Do not name the user's artifact "X-like" or use "For You" branding. Pattern is free; brand is not. Suggested naming: "candidate pipeline", "feed pipeline", "ranking pipeline", "recsys pipeline".
88
+ 4. **Surface trade-offs.** Multi-action vs single, isolation vs joint, online vs offline — never default silently.
89
+ 5. **The generated scaffold must run.** No pseudocode passing as code.
90
+ 6. **Filter order matters.** Cheap before expensive. Universal before user-specific.
91
+ 7. **Side effects never block.** Wrap in fire-and-forget patterns (goroutines / promises without await / asyncio tasks).
92
+
93
+ ## Anti-Patterns
94
+
95
+ - Scoring before filtering (wastes compute on candidates that will be dropped anyway)
96
+ - Synchronous side effects (cache writes / impression emits blocking the response)
97
+ - A single "relevance" score when the product needs to tune for multiple objectives (engagement vs safety vs diversity vs ads)
98
+ - Joint scoring as default (non-deterministic, harder to cache, doesn't compose with reranking stages)
99
+ - Generating pseudocode "for illustration" — the scaffold must actually run
100
+
101
+ ## Upstream contents
102
+
103
+ The upstream repository at <https://github.com/mturac/recsys-pipeline-architect> ships:
104
+
105
+ - Full `SKILL.md` with the complete 8-step workflow
106
+ - 5 load-on-demand reference docs: interfaces in 4 languages (TS/Go/Python/Rust), multi-action scoring pattern, candidate isolation, filter cookbook (12 patterns), scorer cookbook (weighted sum, MMR, diversity penalty, position debiasing)
107
+ - 3 runnable example scaffolds, every one green on its test suite:
108
+ - Strapi v5 plugin (TypeScript / Jest — 3/3 pass)
109
+ - Zentra-compatible pipeline (Go with generics — 3/3 pass)
110
+ - PMAI task prioritizer (Python / FastAPI / pytest — 3/3 pass)
111
+ - v0.1.0 release tagged
112
+ - MIT license; pattern attributed to xAI X For You algorithm (Apache 2.0)
113
+
114
+ Install via skills.sh: `npx skills add mturac/recsys-pipeline-architect`
@@ -0,0 +1,79 @@
1
+ ---
2
+ name: recursive-decision-ledger
3
+ description: Use when the user asks for repeated rollouts, marked decision processes, high-dimensional search, stochastic optimization, local-optima exploration, ensemble comparison, or recursive reasoning with a visible evidence trail.
4
+ origin: ECC
5
+ tools: Read, Write, Edit, Bash, Grep, Glob
6
+ ---
7
+
8
+ # Recursive Decision Ledger
9
+
10
+ Use this skill when the user is trying to force deeper computation through
11
+ repeated rollouts or "Prime Gauss" style recursive prompting. Preserve the useful
12
+ part: repeated trials, prior memory, fresh information, and explicit marks.
13
+ Remove the unsafe part: pretending the loop proves certainty.
14
+
15
+ ## Ledger Contract
16
+
17
+ Every rollout should record:
18
+
19
+ - rollout id and timestamp;
20
+ - prior accepted winner and prior watchlist;
21
+ - fresh information ingested;
22
+ - search space size;
23
+ - model families or heuristics used;
24
+ - trial count and effective trial count;
25
+ - top candidates;
26
+ - decision marks;
27
+ - coherence marks against the prior ledger;
28
+ - promotion gate result.
29
+
30
+ Prefer JSONL for append-only ledgers and Markdown for human summaries.
31
+
32
+ ## Rollout Loop
33
+
34
+ 1. Load the prior ledger.
35
+ 2. Capture new information at time-step zero.
36
+ 3. Run the bounded search.
37
+ 4. Mark each candidate: accept, watch, reject, decay watch, or needs replay.
38
+ 5. Compare winners against prior winners and latest marked rollout.
39
+ 6. Downgrade candidates when drift, tail risk, stale data, or failed replay
40
+ invalidates the previous mark.
41
+ 7. Append artifacts before summarizing.
42
+
43
+ ## Coherence Mark
44
+
45
+ Include a compact coherence mark:
46
+
47
+ ```text
48
+ Ensemble matches prior winner: true
49
+ Recursive matches prior winner: false
50
+ Latest rollout match: true
51
+ Live promotion allowed: false
52
+ Reason: replay and freshness gates not satisfied
53
+ ```
54
+
55
+ ## Promotion Rules
56
+
57
+ For trading, capital allocation, production deploys, migrations, or destructive
58
+ ops, recursive confidence is not approval.
59
+
60
+ Default to paper, dry-run, read-only, preview, or staged mode unless the user
61
+ explicitly approves the live action and the repo/service gate supports it.
62
+
63
+ Promote only when:
64
+
65
+ - the candidate beats the prior accepted winner on the chosen metric;
66
+ - correctness and replay checks pass;
67
+ - risk limits are explicit;
68
+ - the evidence is durable;
69
+ - the user has approved the live step when needed.
70
+
71
+ ## Summary Shape
72
+
73
+ Lead with the decision, not the drama:
74
+
75
+ ```text
76
+ Rollout 15 complete. The prior winner still holds, but edge deteriorated 17%.
77
+ Status: watch, not live. Next gate: 20 replay fills with fresh orderbook age
78
+ below threshold.
79
+ ```