Nullability policy: `undefined` inside, `null` at the seams

Nullability policy: undefined inside, null at the seams

Brioso TS code uses a three-tier nullability convention. It is enforced by
unicorn/no-null (error) in the root .oxlintrc.json.

The three tiers

Tier Where Nullable form Enforcement
1 Internal TS code (apps/ server code, React components, CLI, scripts, internal packages) T | undefined only unicorn/no-null at error
2 Wire / DB / contract seams (contract, db, dispatch, select schema files) T | null or T | null | undefined as today Rule off via glob overrides
3 React client state Same as Tier 1 Covered by the same rule

The rule bans the null literal in code, not the type: native APIs that
return string | null (e.g. headers.get()) are consumed with a
?? undefined at the call point.

Why

JSON and SQLite have no undefined, so null is unavoidable at the seams.
But internal code has no null producer: a null in an internal type is
dead-weight union width, and it conflates truthy checks (if (x) treats
null and undefined differently only by accident of habit, not by design).
Restricting internal code to undefined keeps one falsy-absent value and
makes every wire crossing explicit.

Seam exemption globs (rule off)

packages/contract/**
packages/db/**
packages/dispatch/**
packages/verticals/kits/src/schema.ts
packages/verticals/catalog/src/prompt-reuse.ts
packages/verticals/catalog/src/track-checkout.ts
packages/marketing-content/src/schemas.ts
packages/classification/**
videos/youtube/src/schema.ts
apps/web/src/server/admin/schema.ts

How to decide

Does this value cross a wire, a DB row, or a Zod-parse boundary? Then
null is allowed (Tier 2). Otherwise it is undefined (Tier 1).

Crossing a seam from internal code

When internal T | undefined data feeds a contract-typed consumer
(parseJSON, contract schema props, jobResponseSchema fields), convert at
that single call site with ?? null. Every wire crossing is then explicit
and greppable.

Escape hatch

A single Tier-1 file that legitimately passes null into a contract-typed
API (or a vendored T | null React prop, e.g. components on the
do-not-modify list in apps/web/AGENTS.md) uses:

// oxlint-disable-next-line unicorn/no-null -- feeds contract-typed API

with a one-line reason. Prefer this over widening the glob list.