# OpenMeter ## Repository tooling - Use the `Makefile` for common development tasks. The `justfile` is secondary. - When tools are missing from the ambient shell, use: ```bash nix develop --impure .#ci -c ``` - Always invoke `nix develop` from the repository root. Entering from a subdirectory writes CWD-relative devenv files and can break formatting or the pre-commit hook. - Never run multiple `nix develop` commands concurrently in one worktree; they mutate shared `.devenv/` state. - Dev shells share downloaded Go modules through `$HOME/go/pkg/mod`. `GOPATH`, `GOCACHE`, and installed tools remain per-worktree under `.devenv/state/go`. Existing worktree module caches are not migrated or removed automatically; clean them up separately after confirming no active shell uses them. - `.nvmrc` is the GitHub Actions source of truth for Node. Keep it aligned with `node -v` in the Nix `.#ci` shell. - For slow or noisy commands, save complete output to a temporary log outside the repository, preserve and report the exit status and log path, inspect bounded slices, and never rerun solely because displayed output was truncated. ## Repository invariants - The repository has four Go modules: the production root, `collector`, the publishable `api/v3/client` SDK, and the test-only `e2e` module. - Shared package imports can expand nested module dependency graphs. Run `make mod` and module-aware checks for affected consumers; root-module checks do not validate `collector` or `e2e` dependency metadata. - The root module must never require `api/v3/client`. The nested SDK is not independently tagged, and local `replace` directives are invisible to downstream consumers. - Root `go build ./...`, `go test ./...`, and `go vet ./...` exclude `e2e`. Use `make etoe` or `go test -C e2e ./...`; `make lint-go` and `make mod` already cover all three modules. ## Go conventions - Name string enum constants ``, for example `InvoiceStatusDraft`. - Prefer methods when behavior is intrinsic to an existing domain type. Use freestanding functions when an operation has no natural receiver. - Do not extract trivial or single-use helpers unless the name captures non-obvious domain intent. Inline pass-through wrappers. - For non-trivial operations with multiple related parameters, define a named `Input` struct that implements `models.Validator` through `Validate() error`. Put field and cross-field validation on the input and validate it at the owning boundary. Prefer this over a multi-argument operation paired with a separate `validate(...)` helper. Do not introduce input structs for trivial single-value operations. - For `Validate() error`, collect field errors and return `models.NewNillableGenericValidationError(errors.Join(errs...))`. Preserve field context with wrapped errors. - Do not introduce `context.Background()` or `context.TODO()` to bypass context propagation. Propagate the caller context or remove an unnecessary context parameter. - Never use `panic` in non-test code. Return and propagate errors. - Map external provider failures to explicitly approved public HTTP messages; never return raw provider error text. Preserve the original cause for internal diagnostics. - Production constructors must receive a `*slog.Logger`; do not fall back to `slog.Default()`. - Prefer standard `slices` and `maps`, then `github.com/samber/lo` where it is clearer. Reuse `pkg/slicesx` and `pkg/syncx.OnceValues`; do not add local `ptr`, `must`, or equivalent wrappers. - Mapping helpers between API, domain, and DB representations follow [Type Translation Naming](docs/development/type-conversions.md). Use `map`/`mapped`, not `project`/`projected`, for representation translation. - `alpacadecimal.Decimal.Div` can round: its fallback uses `DivRound` at `DivisionPrecision` (16 decimal places by default), with ties away from zero. Do not use `Div` before exact floor/ceiling, remainder comparisons, or boundary decisions. For example, dividing decimal `9.99999999999999999` by `10` rounds to `1` while the exact remainder is non-zero. Use `QuoRem(divisor, precision)` for a truncating quotient and exact remainder, accounting for signs when applying floor or ceiling. Apply the intended rounding once at the owning precision; increasing global division precision only moves the boundary and is not a fix. ## Testing conventions - PostgreSQL-backed tests require PostgreSQL and `POSTGRES_HOST=127.0.0.1`; otherwise many suites silently skip. - Root-package tests using `confluent-kafka-go` require `-tags=dynamic`. The standalone `e2e` module does not. - Keep domain test helpers under `openmeter/.../testutils` independent from `app/common`; construct repositories, adapters, services, and locks from their package constructors. - Prefer production-backed/service-backed fixtures when the real path can express the scenario. Hardcode suite-wide behavior into the shared harness instead of exposing per-test knobs. - Use `t.Context()` when a `testing.T` or `testing.TB` is available. - Add a test helper only when reused or when its name captures non-obvious domain semantics. Inline one-use setup/assertion wrappers and remove dead helpers. - Begin non-trivial service/lifecycle subtests with concise `given`, `when`, and `then` intent comments. - Pair `clock.FreezeTime(...)` immediately with `defer clock.UnFreeze()` in the same scope. - When precision permits, compare `alpacadecimal.Decimal` through `InexactFloat64()` with `require.Equal`; inline one-off expected balances. See [Testing](docs/development/testing.md) for harness patterns and examples. ## Documentation conventions - Comments and docstrings explain intent, domain constraints, lifecycle state, and failure consequences that are not obvious from the code. Do not narrate conditions the reader can already see. - Document domain helpers whose names compress important business semantics; describe observable behavior and why excluded cases are excluded. - Preserve explanatory comments during refactors unless the change makes them false or misleading. - Keep project documentation short enough that humans will read it. - Write comments like you're explaining the code to a teammate: plain words, concrete reasons, no formal filler. Keep the useful explanation: Bad: ```go // scopedEntries applies the account, route, provenance, and whole-history // exclusions shared by both branches. AsOf is left to each branch: filtering // here would hide future postings whose balance impact must be preserved. ``` Good: ```go // Apply the shared filters, but keep entries after AsOf: we need those to see // how low the balance gets later. ``` ## Further guidance - TypeSpec and SDK generator work follows [api/spec/AGENTS.md](api/spec/AGENTS.md). - Focused developer guides cover [service packages](docs/development/service-patterns.md), [testing](docs/development/testing.md), [refactoring](docs/development/refactoring.md), [type conversions](docs/development/type-conversions.md), and [collection helpers](docs/development/collection-helpers.md). For changes or reviews that affect domain behavior, use the [`domain-docs`](.agents/skills/domain-docs/SKILL.md) skill after establishing the scope to locate the relevant package documentation. Treat domain docs as intended semantics and code and tests as current behavior; investigate discrepancies instead of automatically preferring either. ## CodeGraph and complex work - Use CodeGraph when it materially shortens symbol, caller, flow, or impact exploration. If the worktree is not initialized, run `nix develop --impure .#ci -c codegraph init -i` from the repository root, then retry. Check `codegraph status`; if initialization left a truncated index, rebuild it with `nix develop --impure .#ci -c codegraph index` before falling back. Its server keeps a healthy index synchronized; do not manually sync it. - Treat graph relationships as navigation hints. Current source and tests are authoritative; fall back to normal source navigation only when initialization fails, CodeGraph is unavailable, or its results are inconclusive. - When planning or implementing ambiguous, design-heavy, or cross-cutting engineering changes, use the [`iterative-engineering-design`](.agents/skills/iterative-engineering-design/SKILL.md) skill. ## Maintaining agent guidance - Keep automatically required repo guidance in this file. Use skills for task-shaped procedures and explicitly linked docs for scoped detail; do not assume root-started agents will discover descendant `AGENTS.md` files. - Fold new guidance into the relevant section and merge or remove duplicates. - `.agents/skills` is the source of truth for skills; `.claude/skills` contains compatibility symlinks. Keep skill text usable by both Codex and Claude.