Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 8 additions & 39 deletions .claude/skills/CONVENTIONS.md
Original file line number Diff line number Diff line change
@@ -1,44 +1,13 @@
# Shared Conventions

Rules that apply across all skills. Each SKILL.md references this file instead of repeating these.
All shared conventions (testing rules, Fastify 5 gotchas, code style, docs rules, dependency
layout, escalation rules) now live in the repo-root [CLAUDE.md](../../CLAUDE.md), which is
loaded automatically every session.

---
Skills should reference `CLAUDE.md` directly instead of this file. This stub remains only so
older skill texts that point here don't dead-end.

## Scope
## Reference packages

- **Stay inside the target package directory.** Do not read files outside of it unless explicitly told to.
- **Do not invent features.** Only document or test what source code confirms exists.

## Code Examples

- Use **TypeScript** in all code examples.
- Keep examples minimal — just enough to show the point, no boilerplate.

## Testing

- **Use real Fastify instances. Do NOT mock Fastify.** Plugins are side-effect functions — mocking the instance means testing nothing.
- **Do NOT mock base-library plugins** (e.g., `@fastify/swagger`, `@fastify/multipart`). The point of the integration layer tests is to catch breakage from dependency upgrades. Mock only our own modules (migrations, sub-plugins we authored).
- **Always close Fastify instances in `afterEach`** to avoid resource leaks.
- **Use Vitest** (`import from "vitest"`). The project already has it configured.
- **Test what WE wrote, not what third-party libraries do.** Ask: "Does this verify code our team wrote, or that a third-party library works?"
- **Name tests by behavior**, not implementation. GOOD: `"decorates instance with default documentation path"` BAD: `"line 23 sets routePrefix"`

### Known Fastify 5 Gotchas

These patterns have been validated in this monorepo. Follow them to avoid known pitfalls:

1. **`hasContentTypeParser("*")` returns false** even when a `*` catch-all parser is registered in Fastify 5. Use a behavioural test instead: inject a request with an unusual content-type and assert the status is not 415.
2. **Asserting `vi.fn()` plugin calls**: always include `expect.any(Function)` as the third argument — Fastify calls plugins as `plugin(fastify, options, done)`.
3. **`Readable.from(["string"])` emits strings, not Buffers.** `Buffer.concat` will throw. Use `Readable.from([Buffer.from("string")])` instead.
4. **Verify `@fastify/multipart`** with `fastify.hasContentTypeParser("multipart/form-data")`, not `getSchema("fileSchema")` — `sharedSchemaId` does not expose a schema via `fastify.getSchema`.

## Base Library Documentation

- **Do not repeat base library documentation in detail.** Link to their docs.
- **For doc links:** use the library's official docs URL. If unsure, use the npm page: `https://www.npmjs.com/package/{package-name}`.
- **List only the delta** for partial/modified passthroughs — what we change, not what we preserve.

## Reference Packages

- `packages/firebase` — has FEATURES.md and comprehensive tests
- `packages/config` — has GUIDE.md as the format reference
- `packages/firebase` — canonical FEATURES.md, tests, and model slice (`src/model/userDevice/`)
- `packages/config` — canonical GUIDE.md format and minimal package anatomy
Loading
Loading