AGENTS.md
Rama main · réplica de lectura del repositorio original.
# 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 <command>
```
- 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 `<Type><Value>`, 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
`<Operation>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<Operation>(...)` 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.