@apogeelabs/the-agency 0.1.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -16,6 +16,9 @@ npx the-agency sync
16
16
 
17
17
  # Choose which files to sync
18
18
  npx the-agency sync --pick
19
+
20
+ # Install optional review check plugins
21
+ npx the-agency install-review-plugins
19
22
  ```
20
23
 
21
24
  Files are copied to `.claude/agents/`, `.claude/commands/`, and `.ai/` in the target project. If destination files already exist, you'll be prompted before overwriting.
@@ -39,12 +42,14 @@ Autonomous subagents that run in isolated context windows and communicate throug
39
42
 
40
43
  Slash commands invoked in Claude Code sessions.
41
44
 
42
- | Command | Purpose |
43
- | ------------ | -------------------------------------------------- |
44
- | `/architect` | Interactive architecture design session |
45
- | `/build` | Orchestrates the full dev → review → test pipeline |
46
- | `/pm` | Interactive product requirements discovery |
47
- | `/review-pr` | Structured PR review briefing |
45
+ | Command | Purpose |
46
+ | ----------------- | -------------------------------------------------- |
47
+ | `/architect` | Interactive architecture design session |
48
+ | `/build` | Orchestrates the full dev → review → test pipeline |
49
+ | `/pm` | Interactive product requirements discovery |
50
+ | `/prep-pr` | Pre-submission PR prep and draft creation |
51
+ | `/review-pr` | Structured PR review briefing |
52
+ | `/weekly-summary` | Weekly synthesis of merged PRs |
48
53
 
49
54
  ### AI Context (`.ai/`)
50
55
 
@@ -68,6 +73,43 @@ Reference material automatically available to Claude Code.
68
73
 
69
74
  See `.ai/workflow.md` after syncing for the full workflow guide.
70
75
 
76
+ ## Review Checks (`.ai/review-checks/`)
77
+
78
+ The `/review-pr` command supports pluggable tribal knowledge checks. Place markdown files in `.ai/review-checks/` in your repo, and the review command discovers and evaluates them automatically.
79
+
80
+ ### Check File Format
81
+
82
+ Each file uses YAML frontmatter with two fields:
83
+
84
+ ```markdown
85
+ ---
86
+ name: Display Name for This Check Group
87
+ applies_when: Natural language description of when these checks apply
88
+ ---
89
+
90
+ - [ ] **Check name**: What to look for.
91
+ ```
92
+
93
+ - **`name`** — heading used in the review output
94
+ - **`applies_when`** — evaluated by the LLM against the PR's changed file list. Use plain language (e.g., "Changed files include `.tsx` files" or "Always").
95
+
96
+ ### Pre-packaged Plugins
97
+
98
+ Install review plugins interactively:
99
+
100
+ ```bash
101
+ npx the-agency install-review-plugins
102
+ ```
103
+
104
+ This presents a multi-select of available plugins and copies your selections to `.ai/review-checks/`.
105
+
106
+ | Plugin | Targets | Checks |
107
+ | --------------------- | --------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
108
+ | **react-frontend.md** | `.tsx`, `.jsx`, `.css`, `.scss`, `.styled.ts` files | Hard-coded colors, missing `data-cy` attributes, accessibility gaps |
109
+ | **node-backend.md** | `.ts` files in backend/service directories | `console.log` usage, boundary violations, raw SQL, error swallowing |
110
+ | **general.md** | All PRs (unconditional) | New env vars, dead code, dependency changes, type safety (`any`, `as`, `@ts-ignore`) |
111
+ | **unit-test.md** | `.test.ts`, `.spec.ts` files | Style guide adherence, barrel export testing, test description accuracy, missing `export default {}` |
112
+
71
113
  ## Project-Specific Configuration
72
114
 
73
115
  The sync does **not** copy `settings.local.json` or `settings.json` — those are project-specific. See the [Claude Code docs](https://docs.anthropic.com/en/docs/claude-code) for configuring permissions per-project.
package/dist/cli.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { sync } from "./sync.js";
2
+ import { installReviewPlugins } from "./install-review-plugins.js";
2
3
  const args = process.argv.slice(2);
3
4
  const command = args[0];
4
5
  if (!command || command === "help" || command === "--help") {
@@ -6,14 +7,17 @@ if (!command || command === "help" || command === "--help") {
6
7
  Usage: the-agency <command> [options]
7
8
 
8
9
  Commands:
9
- sync Sync all Claude Code files to the current project
10
- sync --pick Interactively select which files to sync
10
+ sync Sync all Claude Code files to the current project
11
+ sync --pick Interactively select which files to sync
12
+ install-review-plugins Install optional review check plugins
11
13
  `);
12
14
  process.exit(0);
13
15
  }
14
16
  if (command === "sync") {
15
17
  const pick = args.includes("--pick");
16
18
  await sync({ pick });
19
+ } else if (command === "install-review-plugins") {
20
+ await installReviewPlugins();
17
21
  } else {
18
22
  console.error(`Unknown command: ${command}`);
19
23
  process.exit(1);
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Presents an interactive multi-select of available review plugins and
3
+ * copies the selected ones into the consumer's project.
4
+ *
5
+ * This is deliberately separate from `sync` — sync handles core setup
6
+ * (agents, commands, AI context), while review plugins are optional
7
+ * extras that users pick à la carte.
8
+ */
9
+ declare function installReviewPlugins(): Promise<void>;
10
+
11
+ export { installReviewPlugins };
@@ -0,0 +1,67 @@
1
+ import { resolve, dirname, join } from "node:path";
2
+ import { fileURLToPath } from "node:url";
3
+ import { copyFile, mkdir } from "node:fs/promises";
4
+ import prompts from "prompts";
5
+ import { manifest } from "./manifest.js";
6
+ import { fileExists } from "./sync.js";
7
+ const __dirname = dirname(fileURLToPath(import.meta.url));
8
+ const packageRoot = resolve(__dirname, "..");
9
+ const srcDir = join(packageRoot, "src/review-plugins");
10
+ const destDir = ".ai/review-checks";
11
+ async function installReviewPlugins() {
12
+ const choices = manifest.reviewPlugins.map((plugin) => ({
13
+ title: plugin.file,
14
+ description: plugin.description,
15
+ value: plugin.file,
16
+ selected: true
17
+ }));
18
+ const { selected } = await prompts({
19
+ type: "multiselect",
20
+ name: "selected",
21
+ message: "Select review plugins to install",
22
+ choices,
23
+ instructions: false,
24
+ hint: "- Space to toggle, Enter to confirm"
25
+ });
26
+ if (!selected || selected.length === 0) {
27
+ console.log("Nothing selected. Exiting.");
28
+ return;
29
+ }
30
+ const destBase = join(process.cwd(), destDir);
31
+ const existing = [];
32
+ for (const file of selected) {
33
+ const dest = join(destBase, file);
34
+ if (await fileExists(dest)) {
35
+ existing.push(file);
36
+ }
37
+ }
38
+ if (existing.length > 0) {
39
+ console.log(`
40
+ Existing files that will be overwritten:`);
41
+ for (const file of existing) {
42
+ console.log(` - ${destDir}/${file}`);
43
+ }
44
+ const { proceed } = await prompts({
45
+ type: "confirm",
46
+ name: "proceed",
47
+ message: `Overwrite ${existing.length} existing file(s)?`,
48
+ initial: true
49
+ });
50
+ if (!proceed) {
51
+ console.log("Install cancelled.");
52
+ return;
53
+ }
54
+ }
55
+ await mkdir(destBase, { recursive: true });
56
+ for (const file of selected) {
57
+ const src = join(srcDir, file);
58
+ const dest = join(destBase, file);
59
+ await copyFile(src, dest);
60
+ console.log(` \u2713 ${destDir}/${file}`);
61
+ }
62
+ console.log(`
63
+ Installed ${selected.length} review plugin(s).`);
64
+ }
65
+ export {
66
+ installReviewPlugins
67
+ };
@@ -6,6 +6,7 @@ interface Manifest {
6
6
  agents: ManifestItem[];
7
7
  commands: ManifestItem[];
8
8
  ai: ManifestItem[];
9
+ reviewPlugins: ManifestItem[];
9
10
  }
10
11
  declare const manifest: Manifest;
11
12
 
package/dist/manifest.js CHANGED
@@ -11,12 +11,32 @@ const manifest = {
11
11
  { file: "architect.md", description: "Interactive architecture design sessions" },
12
12
  { file: "build.md", description: "Build orchestrator pipeline" },
13
13
  { file: "pm.md", description: "Interactive product requirements discovery" },
14
- { file: "review-pr.md", description: "Structured PR review briefing" }
14
+ { file: "prep-pr.md", description: "Pre-submission PR prep and draft creation" },
15
+ { file: "review-pr.md", description: "Structured PR review briefing" },
16
+ { file: "weekly-summary.md", description: "Weekly synthesis of merged PRs" }
15
17
  ],
16
18
  ai: [
17
19
  { file: "UnitTestGeneration.md", description: "TypeScript/Jest unit testing style guide" },
18
20
  { file: "UnitTestExamples.md", description: "Reference examples for the test style guide" },
19
21
  { file: "workflow.md", description: "Multi-agent development workflow guide" }
22
+ ],
23
+ reviewPlugins: [
24
+ {
25
+ file: "general.md",
26
+ description: "General checks: env vars, type safety, dead code, debugging leftovers, breaking changes, binary assets"
27
+ },
28
+ {
29
+ file: "node-backend.md",
30
+ description: "Node.js backend checks: API design, error handling, security, database patterns"
31
+ },
32
+ {
33
+ file: "react-frontend.md",
34
+ description: "React frontend checks: component design, hooks, rendering, accessibility"
35
+ },
36
+ {
37
+ file: "unit-test.md",
38
+ description: "Unit test checks: test quality, coverage, mocking patterns, assertions"
39
+ }
20
40
  ]
21
41
  };
22
42
  export {
package/dist/sync.d.ts CHANGED
@@ -5,8 +5,26 @@ interface SyncFile {
5
5
  dest: string;
6
6
  label: string;
7
7
  }
8
+ /**
9
+ * Resolves manifest categories into concrete source/destination file paths.
10
+ * Only categories present in `categoryConfig` are valid — passing unknown
11
+ * categories (e.g. `reviewPlugins`) will throw at runtime.
12
+ */
8
13
  declare function getFilesToSync(categories: Record<string, ManifestItem[]>): SyncFile[];
14
+ /**
15
+ * Checks whether a file exists at the given path.
16
+ * Uses `fs.access` rather than `stat` to avoid TOCTOU overhead we don't need.
17
+ */
9
18
  declare function fileExists(path: string): Promise<boolean>;
19
+ /**
20
+ * Copies agent, command, and AI context files from the package into the
21
+ * consumer's project. In pick mode, presents an interactive multi-select;
22
+ * otherwise syncs everything.
23
+ *
24
+ * Review plugins are deliberately excluded — they have their own install
25
+ * flow via `install-review-plugins` since they're opt-in extras, not
26
+ * core setup.
27
+ */
10
28
  declare function sync({ pick }?: {
11
29
  pick?: boolean | undefined;
12
30
  }): Promise<void>;
package/dist/sync.js CHANGED
@@ -35,7 +35,10 @@ async function fileExists(path) {
35
35
  async function sync({ pick = false } = {}) {
36
36
  let selectedCategories;
37
37
  if (pick) {
38
- const choices = Object.entries(manifest).flatMap(
38
+ const syncableCategories = Object.entries(manifest).filter(
39
+ ([category]) => category in categoryConfig
40
+ );
41
+ const choices = syncableCategories.flatMap(
39
42
  ([category, items]) => items.map((item) => ({
40
43
  title: `${categoryConfig[category].dest}/${item.file}`,
41
44
  description: item.description,
@@ -61,7 +64,8 @@ async function sync({ pick = false } = {}) {
61
64
  selectedCategories[category].push(item);
62
65
  }
63
66
  } else {
64
- selectedCategories = { ...manifest };
67
+ const { agents, commands, ai } = manifest;
68
+ selectedCategories = { agents, commands, ai };
65
69
  }
66
70
  const files = getFilesToSync(selectedCategories);
67
71
  const existing = [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apogeelabs/the-agency",
3
- "version": "0.1.1",
3
+ "version": "0.3.0",
4
4
  "description": "Centralized Claude Code agents, commands, and workflows",
5
5
  "type": "module",
6
6
  "bin": {
@@ -10,6 +10,7 @@
10
10
  "bin/",
11
11
  "dist/",
12
12
  "src/templates/",
13
+ "src/review-plugins/",
13
14
  "!src/templates/.claude/settings*.json"
14
15
  ],
15
16
  "dependencies": {
@@ -0,0 +1,12 @@
1
+ ---
2
+ name: General Checks
3
+ applies_when: Always — applies to all PRs regardless of file types
4
+ ---
5
+
6
+ - [ ] **New environment variables**: Are there new `process.env.*` references that need documentation or deployment configuration?
7
+ - [ ] **Type safety**: Are there `any` types, type assertions (`as`), or `@ts-ignore` / `@ts-expect-error` comments that bypass TypeScript's type system?
8
+ - [ ] **Dead code**: Flag new functions, methods, constants, or type definitions that are exported or defined but never referenced by any other code in the diff. Also flag commented-out code blocks and unreachable code after unconditional `return`, `throw`, or `process.exit` statements. If it's not called, imported, or reachable, it shouldn't be merged.
9
+ - [ ] **Dependency changes**: Flag new packages added to `dependencies` or `devDependencies`. For each new dependency, consider: does the project already have a library that does this? Is a full package warranted or would a few lines of code suffice? Also flag removed packages (is anything still importing them?) and major version bumps (check for breaking changes in the upgrade path).
10
+ - [ ] **Leftover debugging**: Flag `debugger` statements, `console.debug`, `.only` on test cases (`describe.only`, `it.only`, `test.only`), artificial delays (`sleep()`, `setTimeout` used as a wait hack), and commented-out code that was clearly used during development (e.g., commented-out `console.log`, toggled feature flags, hardcoded user IDs). These are fine locally — not fine in a merge to main.
11
+ - [ ] **Breaking interface changes**: Flag changes to exported function signatures, type definitions, or shared interfaces that alter the contract — renamed fields, removed parameters, changed return types, narrowed union types. In a monorepo, these can silently break consumers in other packages. Flag when there's no corresponding update to callers visible in the diff, and no migration note or changelog entry.
12
+ - [ ] **Large binary/asset additions**: Flag images, fonts, PDFs, video files, database dumps, or other binary assets added directly to the repo, especially files over 500KB. These inflate the git history permanently and typically belong in a CDN, object store, or asset pipeline. Small icons and favicons are fine.
@@ -0,0 +1,17 @@
1
+ ---
2
+ name: Node Backend Checks
3
+ applies_when: Changed files include .ts files in backend or service directories (excluding test files)
4
+ ---
5
+
6
+ - [ ] **Console.log usage**: Is `console.log` used instead of the project's structured logger?
7
+ - [ ] **Boundary violations**: Is a handler reaching into a repository directly instead of going through a service layer?
8
+ - [ ] **Raw SQL**: Are there string-concatenated queries instead of parameterized queries via the project's query builder?
9
+ - [ ] **Error swallowing**: Are errors being caught and silently discarded without logging or re-throwing?
10
+ - [ ] **Readability at a glance**: Can a developer unfamiliar with this code follow the logic 6 months from now? Flag functions longer than ~40 lines that lack decomposition, deeply nested conditionals (3+ levels), boolean parameters without named constants or descriptive variable assignments, and variable names that are ambiguous or require context to interpret (e.g., `data`, `result`, `temp`, `val`, single-letter names outside of trivial loops).
11
+ - [ ] **Documentation gaps**: Public functions and methods should have JSDoc comments documenting purpose, parameters, and return values. Non-obvious logic — workarounds, business rules, performance trade-offs, "this looks wrong but isn't" patterns — should have inline comments explaining _why_, not _what_. Flag new public functions missing JSDoc and non-trivial logic blocks that would confuse a reader without context.
12
+ - [ ] **N+1 query patterns**: Flag loops that execute a database call (find, findOne, aggregate, query, get, fetch) per iteration instead of batching. This includes `for` loops, `.forEach`, `.map`, and `for...of` over a collection where each iteration hits the DB. The fix is typically a single bulk query (`$in`, `WHERE IN`, `mget`, pipeline) before the loop, then an in-memory lookup. Also flag `Promise.all` wrapping per-item DB calls — it's parallel but still N round-trips.
13
+ - [ ] **Unvalidated external input**: Flag request body fields, query parameters, route parameters, and header values used directly in business logic or DB queries without schema validation (e.g., zod, joi, class-validator). Trusting `req.body.email` without parsing it is an injection and type-safety risk. Internal function-to-function calls within the service layer do NOT need validation — only system boundaries (HTTP handlers, queue consumers, webhook receivers).
14
+ - [ ] **Leaking internals in API responses**: Flag error handlers or response payloads that expose stack traces, raw database error messages, internal collection/table names, internal IDs (like MongoDB `_id` when a public-facing ID exists), or implementation details (library names, file paths). API consumers should get structured error codes and user-safe messages, not a guided tour of your infrastructure.
15
+ - [ ] **Race conditions in async code**: Flag missing `await` on promises whose result or side effects matter (fire-and-forget is only acceptable for truly independent, failure-tolerant operations like analytics). Flag parallel mutations to shared state (e.g., two `await` calls that both read-then-write the same document without guarding against interleaving). Flag `Promise.all` over operations that have implicit ordering dependencies.
16
+ - [ ] **Overly broad try/catch**: Flag `try` blocks spanning more than ~15-20 lines or wrapping multiple distinct operations where the `catch` handles all failures identically. Different failure modes (network error, validation error, auth error, DB constraint violation) usually need different responses. If a single `catch(e)` logs and returns a generic 500 for all of them, flag it. Each distinct failure mode should be catchable and handleable separately.
17
+ - [ ] **Hardcoded magic numbers**: Flag raw numeric literals used for timeouts, retry counts, page sizes, rate limits, cache TTLs, port numbers, or threshold values. These should be named constants or pulled from configuration. `setTimeout(fn, 30000)` is unreadable; `setTimeout(fn, CACHE_TTL_MS)` communicates intent. Exceptions: `0`, `1`, `-1` in obvious arithmetic/index contexts, and HTTP status codes (e.g., `res.status(404)`) are fine.
@@ -0,0 +1,22 @@
1
+ ---
2
+ name: React & Frontend Checks
3
+ applies_when: Changed files include .tsx, .jsx, .css, .scss, or .styled.ts files
4
+ ---
5
+
6
+ - [ ] **Hard-coded colors**: Are there hex values, `rgb()`, or named colors that should use theme variables or design tokens?
7
+ - [ ] **Missing data-cy attributes**: Do new interactive elements (buttons, inputs, links, dropdowns) have `data-cy` attributes for end-to-end testing?
8
+ - [ ] **Accessibility gaps**: Missing `alt` text on images? Click handlers on non-interactive elements (`div`, `span`) without proper roles? Missing `aria-label` on icon-only buttons?
9
+ - [ ] **One public component per file**: Each `.tsx` file should export only one React component. If additional helper components exist in the same file, they must NOT be exported and should have a `/** @private */` JSDoc comment above their declaration. Flag any file that exports multiple components, or has unexported components missing the `@private` pragma.
10
+ - [ ] **No direct component tests**: `.tsx` component files should NOT have corresponding `.test.tsx` or `.spec.tsx` test files. Style-only hooks (e.g., `useStyles`, `useTheme`) also do not need tests UNLESS the hook contains conditional logic that affects code paths beyond styling. Flag any new test file that directly tests a `.tsx` component or a pure-styling hook.
11
+ - [ ] **BEM class naming**: CSS class names must follow BEM (Block Element Modifier) convention: `.block__element--modifier`. Flag class names that use camelCase, generic names without BEM structure, or inconsistent delimiter usage (e.g., single underscores or hyphens where BEM expects doubles).
12
+ - [ ] **Rem units over pixels**: Use `rem` for all sizing and spacing values. `px` is acceptable ONLY for media query breakpoints. Flag any `px` usage in properties like `font-size`, `margin`, `padding`, `width`, `height`, `gap`, `border-radius`, etc.
13
+ - [ ] **Inline styles**: Flag `style={{...}}` props in JSX. Styling should live in stylesheets, styled components, or style hooks — not inline objects. Exceptions: truly dynamic values computed at runtime (e.g., positioning from a calculation) are acceptable, but static visual properties (`color`, `padding`, `fontSize`) are not.
14
+ - [ ] **Missing `key` on dynamic lists**: Flag `.map()` calls that return JSX without a `key` prop. Also flag usage of array index as `key` on lists that can be reordered, filtered, or have items added/removed — index keys cause subtle re-render bugs in those cases. Stable identifiers (IDs, slugs) are required.
15
+ - [ ] **Direct DOM manipulation**: Flag usage of `document.querySelector`, `document.getElementById`, `document.createElement`, `.innerHTML`, `.innerText` assignment, or `.appendChild`. React components should use refs (`useRef`) for DOM access and state for DOM updates. Direct DOM manipulation bypasses React's reconciliation and causes stale UI.
16
+ - [ ] **Inline event handler allocation in lists**: Flag arrow functions defined directly in JSX event props (`onClick={() => handler(id)}`) when they appear inside `.map()` or other list-rendering patterns. These create a new function reference per render per item. Extract to a named handler or use `useCallback`. Single-instance components (not in a loop) are fine.
17
+ - [ ] **Derived state anti-pattern**: Flag `useState` + `useEffect` pairs where the effect's only job is to compute a value from other state or props and store it back into state. This should be `useMemo` (for expensive computations) or a plain `const` (for cheap ones). The pattern creates unnecessary render cycles and is a common source of stale-state bugs.
18
+ - [ ] **Hardcoded user-facing strings**: Flag literal text strings rendered in JSX that a user would see on screen — headings, button labels, tooltips, placeholder text, error messages, `aria-label` values. These should use the project's i18n system (e.g., `t('key')`). Do NOT flag non-user-facing strings like prop names, CSS classes, `data-cy` values, log messages, or enum/constant comparisons.
19
+ - [ ] **Missing error boundaries**: Flag new top-level route components or major feature entry-point components that are not wrapped in an error boundary. An unhandled throw in a component tree without a boundary will unmount the entire app. Leaf components and small utility components do not need their own boundaries.
20
+ - [ ] **Prop drilling**: Flag props being passed through two or more intermediate components that don't use them — they just forward them deeper. This suggests the value should live in a React context, a state management store, or the component tree should be restructured using composition (children/render props). Name the prop and the pass-through chain in your finding.
21
+ - [ ] **Non-memoized context values**: Flag React context providers where the `value` prop is an object literal, array literal, or function created inline (e.g., `<Ctx.Provider value={{ user, setUser }}>`). Every render creates a new reference, forcing all consumers to re-render. Wrap the value in `useMemo` (objects/arrays) or `useCallback` (functions).
22
+ - [ ] **`useEffect` missing cleanup**: Flag `useEffect` hooks that create subscriptions (e.g., `addEventListener`, WebSocket connections, `subscribe()` calls), timers (`setTimeout`, `setInterval`), or `AbortController` instances without returning a cleanup function that tears them down. Also flag `async` operations in effects that set state after completion without checking whether the component is still mounted (missing abort signal or cancelled flag). These are memory leak and state-update-after-unmount bugs.
@@ -0,0 +1,10 @@
1
+ ---
2
+ name: Unit Test Checks
3
+ applies_when: Changed files include .test.ts or .spec.ts files
4
+ ---
5
+
6
+ - [ ] **Style guide adherence**: Test files must follow the conventions in `.ai/UnitTestGeneration.md`. Key rules to verify: method under test is executed in `beforeEach()` with assertions only in `it()` blocks (Critical Rule #1), mock behavior is configured in `beforeEach`/`beforeAll` and never at module level (Critical Rule #2), callbacks are invoked via `mockImplementation` and never via `mock.calls[N][M]()` (Critical Rule #3). Also check for coverage-driven test planning (every branch in the source has a corresponding test scenario) and superfluous test prevention (no duplicate scenarios exercising the same code path with different literal values). Note: the guide's suggestion to use "fun" test data is optional — straightforward data is equally acceptable.
7
+ - [ ] **No testing pure style hooks**: Do not test hooks that simply export a memoized style object or return static style values (e.g., `useStyles`, `useTheme` wrappers that just return a `useMemo` around a style object). If the hook contains conditional logic, branching, or computation that determines _which_ styles to return based on props/state, it should be tested. The distinction: does the hook have code paths a reviewer would want coverage on, or is it just a memoized constant?
8
+ - [ ] **No testing barrel exports**: Flag any new test file that tests an `index.ts` barrel export file (a file whose only purpose is re-exporting from other modules). These files have zero logic and zero branches — testing them adds maintenance cost with no coverage value.
9
+ - [ ] **Test descriptions match assertions**: Flag `describe`/`it` blocks where the text description doesn't match what the `expect` statements actually verify. For example, `it("should return the user")` followed by `expect(mockLogger.warn).toHaveBeenCalled()` is a mismatch — the description claims one behavior but the assertion checks something unrelated. Descriptions should accurately predict what the assertions verify.
10
+ - [ ] **Missing `export default {}`**: Every test file must include `export default {};` near the top of the file (after any eslint pragma comments). This prevents global scope collision between test files. Flag any new or modified test file missing this export — the resulting failures are cryptic and hard to trace back to this cause.