Conventions
The load-bearing repo conventions a contributor must know, each with a pointer to its canon file.
These are the conventions that PR review actually enforces. Each section is a summary; the linked canon file is the authority.
Vocabulary discipline
Two distinct rules share this name:
The leak rule. The consumer surface is Stripe-shaped: money is just money,
and crypto is the substrate, never the vocabulary. A custody term ("Safe",
"address", "Zodiac", "UserOp", "wei", "chain") appearing in the
consumer-facing surface is a leak, and leaks are defects.
CONTEXT.md
at the repo root is the vocabulary authority — check it before naming anything
a consumer will see.
Identifier discipline. Build-cycle metadata never appears in production
identifiers or test helper type aliases: Stage1, Phase2, M1_1-style
names fail review. Stage and phase words are fine in markdown narrative; code
identifiers must name durable architecture concepts. Canon:
canon/conventions/vocabulary-discipline.md
and
canon/rules/vocabulary-discipline.md.
Branded types
Every domain primitive at a port surface is branded in @capxul/types
(AccountId, Email, PublishableKey, EpochMs, …). Constructors like
toAccountId are the only way to create branded values — manual casts
(raw as Address) are banned outside the constructor implementations.
Non-wire seams (DB hydration, env reads, fixtures) use the to* constructors;
wire seams (HTTP/JSON crossing into the SDK) use schemas from @capxul/wire,
which must validate exactly as strictly as their to* counterparts —
shape-only brand schemas are not permitted. Canon:
canon/conventions/branded-types.md
and
canon/rules/branded-types.md.
Error handling and the error catalog
CapxulError is the public error type. Internal code may model errors as
Effect channel variants, but every public SDK method maps them to
CapxulError and returns CapxulResult<T> — internal variants never cross
the boundary, and adapters translate external failures at the edge. The
canonical public catalog contains 21 codes (NOT_AUTHENTICATED,
INVALID_INPUT, INSUFFICIENT_BALANCE, WRONG_STATE, …); every Errors.*
factory must return one of them. Raw provider cause payloads may live on the
native Error.cause chain but do not belong in public message or details
fields. Canon:
canon/conventions/error-handling.md
and
canon/conventions/error-catalog.md.
Test contract & RED test contract
Every slice owns tests at the layer it changes: L1 (pure functions, types,
schemas), L2 (port and adapter behavior — exactly one
<port>.conformance.test.ts matrix file per port), L3 (package
integration without external services), L4 (the real reachable
runtime/service subset for the slice).
Work starts RED: a test that fails because required production behavior is
absent or wrong — not because a file doesn't exist. GREEN means that same
test passes without being skipped, stubbed, weakened, or rewritten. .skip
and .todo after the RED phase, existence checks, and mocking the unit under
test are all rejected; mock only at system boundaries. Every child issue
declares its RED test up front (path, what it proves, mock boundary, why it
fails). Canon:
canon/conventions/test-contract.md,
canon/conventions/red-test-contract.md,
and
canon/conventions/red-green-classifier.md.
Public-surface rule
Public SDK methods return Promise<CapxulResult<T>> — never raw values,
thrown exceptions, actors, state machines, or Effect programs. Consumers
import @capxul/sdk and @capxul/sdk-react only; the backend, @capxul/wire,
and Convex APIs are private. See
Architecture for
the layer picture. Canon:
canon/rules/public-surface.md.
Commit convention
Commit messages follow type(scope): summary — e.g.
feat(sandbox): add canonical operator CLI,
fix(sdk): keep private packages out of runtime manifests,
chore(release): version packages. This is repo practice throughout the
history and the release tooling (the automated version PR commits as
chore(release): version packages); there is no separate canon file for it.
PRs that change a publishable package's consumer-facing behavior must also
include a changeset — see Release flow.