# Conventions Report — output of convention-scanner Task: Add a per-wave concurrency cap to trekexecute headless launches. ## Summary Mature, consistent conventions. New code should imitate the existing `lib/` validators almost mechanically. ## Naming | Element | Convention | Example | |---------|-----------|---------| | Files | kebab-case `.mjs` | `lib/profiles/profile-resolver.mjs` | | Functions | camelCase, verb-first | `validateFindings`, `extractDigestBlock` | | Error codes | UPPER_SNAKE, domain-prefixed | `FINDING_BAD_LINE`, `DIGEST_NOT_OBJECT` | | Tests | `.test.mjs` mirroring `lib/` tree | `tests/lib/profile-resolver.test.mjs` | ## Module shape (must follow) Every `lib/` module is the **3-layer pattern**: 1. exported pure functions (validate/resolve/compute); 2. they return `{valid, errors, warnings, parsed}` via `lib/util/result.mjs` `issue()`/`fail()`/`ok()`; 3. a CLI shim `if (import.meta.url === \`file://${process.argv[1]}\`)` for Bash. A `max-parallel-resolver.mjs` must replicate this exactly (pure resolver + `issue()` errors + CLI shim). ## Error handling - Never coerce bad input — return a `{valid:false}` Result with a stable code and a `hint`. Throwing is reserved for genuine programmer error (see `mainContextTokens` "unknown arm" throw). - Unknown/extra fields are tolerated (forward-compat), load-bearing fields are hard errors. Mirror this: clamp/validate the cap, tolerate extra profile keys. ## Imports / tests / commits - Named ESM imports, relative paths, no path aliases, no barrels. - Conventional Commits, `type(scope): description`, e.g. `feat(voyage): …`. - New behavior is TDD'd: failing `node:test` first, then minimal code.