# Coding Style Guide
# Cold Bore Ballistics LLC — Internal Reference
# Classification: Confidential

This guide governs code style decisions for all CBB software. It is deliberately scoped to decisions the SDLC does not already make. The master SDLC (`OneDrive/CBB_Corporate/03_-_Confidential/Process/CBB_SDLC.md`) and the ScopeDOPE SDLC (`ScopeDOPE_SDLC.md`) are authoritative for commit format, code hygiene, architecture directives, and the feature development flow — read those there; do not expect them here.

Current scope: Kotlin/Android and Kotlin Multiplatform (`:ballistics` module). Swift/iOS conventions will be added when iOS development begins.

---

## 1. SDLC Cross-References

Consult the SDLC for these topics before writing any code:

| Topic | SDLC section |
|---|---|
| Architecture principles (MVVM, offline-first, no accounts) | §4 |
| Feature development flow and spec-first requirement | §5 |
| Code hygiene (no unguarded debug output, no binaries >5 MB) | §11 |
| Security controls | §11 |
| Testing strategy | §7 |
| Conventional commit format | §5.7 |

---

## 2. Naming

### Rules by kind

| Kind | Convention | Example |
|---|---|---|
| Class / Object / Interface | PascalCase | `BallisticsEngine`, `DopeSummaryScreen` |
| File | PascalCase, match top-level declaration | `BallisticsEngine.kt` |
| Function / property / variable | camelCase | `applyAtmosphericCorrection`, `windSpeedMps` |
| Constant (`const val` in companion object) | SCREAMING_SNAKE_CASE | `MAX_RANGE_M` |
| Package | lowercase, dot-separated | `com.coldboreballisticsllc.scopedope.ballistics` |
| Test file | `<ClassName>Test.kt` | `BallisticsEngineTest.kt` |
| Test function | backtick descriptive sentence | `` `elevation at 500m matches JBM to 0.05 mil` `` |

### Specific rules

- **Domain abbreviations are allowed; generic abbreviations are not.** `mil`, `bc`, `mv`, `mps` are precise domain terms — use them. `tmp`, `val2`, `res`, `obj` are not — expand them.
- **Booleans**: prefix with `is`, `has`, or `can` — `isRealWorld`, `hasJbmSidecar`, `canPrint`.
- **Backing properties**: prefix the private field with underscore — `_uiState` backs the public `uiState`.
- **Composables**: nouns or noun phrases — `DopeSummaryScreen`, `InstrumentPanel`. Not verb phrases like `ShowDopeSummary`.

---

## 3. Kotlin Conventions

### Immutability

- Use `val` over `var` by default. Introduce `var` only when mutation is genuinely required.
- Use `data class` for model/value objects — structural equality, `copy()`, and `toString()` for free.
- Default to `listOf` / `mapOf`; use mutable variants only when mutation is required.

### Null safety

- Never use `!!` (force-unwrap). Use `?.let`, `?: return`, `?: throw`, or an explicit null check.
- Prefer non-nullable types at API boundaries. Absent values are modeled explicitly — use sealed classes or `Optional`-style wrappers rather than nullable returns when the distinction between null and "not found" matters.
- `lateinit var` is acceptable for DI-injected fields only. Comment why construction-time initialization is not possible.

### Sealed classes and `when`

Use sealed classes for state and result types:

```kotlin
sealed class UiState<out T> {
    object Loading : UiState<Nothing>()
    data class Success<T>(val data: T) : UiState<T>()
    data class Error(val message: String) : UiState<Nothing>()
}
```

Use exhaustive `when` over sealed types. Do not add an `else` branch to a `when` on a sealed class — exhaustiveness is the point; `else` defeats it.

### Extension functions

Write extension functions for utility logic on types you own (e.g. `DopeEntry.toDisplayString()`). Avoid extension functions on types you do not own unless there is no reasonable alternative.

### Coroutines

- ViewModel: `viewModelScope.launch { }` for UI-triggered operations.
- Data/repository layer: `Dispatchers.IO` for I/O. Keep `withContext` at the layer boundary — do not scatter it through the call chain.
- The `:ballistics` KMP module is a pure computation library and must not expose `Flow`. Return values directly; callers wrap in coroutines as needed.
- Catch exceptions at the ViewModel boundary and propagate as `UiState.Error`. Do not swallow exceptions silently.

---

## 4. Jetpack Compose

- **State hoisting**: lift state to the smallest subtree that needs it. Pass state down as parameters; pass events up as lambdas.
- **No side effects in composable bodies.** Use `LaunchedEffect`, `SideEffect`, or `DisposableEffect`.
- **No business logic in composables.** A composable receives data and emits events. It does not compute, transform, or make decisions.
- **Previews**: add a `@Preview`-annotated function in the same file, named `<ComposableName>Preview`. Wrap in the app's dark-mode theme to exercise the instrument aesthetic.
- **Theming**: use design tokens from `ui/theme/` for all colors, typography, and spacing. Never hardcode hex values or font sizes in a composable. See `UI_DESIGN_STYLE_GUIDE.md` for the full token reference.

---

## 5. Architecture

See SDLC §4 for the authoritative architecture directive. Layer responsibilities:

| Layer | Owns | Does not own |
|---|---|---|
| ViewModel | UI state, user event handling, use-case calls | Repository calls, business logic |
| Use Case | One operation; orchestrates repositories; owns domain business rules | Data source details, UI state |
| Repository | Data source abstraction; maps to domain types at boundary | Business rules, UI concerns |
| Data source | Room DAOs, DataStore, BLE drivers | Domain types (map at repository boundary) |

The `:ballistics` KMP module is outside this stack. It is a pure computation library: inputs in, outputs out, no Android dependencies, no coroutines, testable on the JVM.

---

## 6. Testing Conventions

See SDLC §7 for the testing strategy. Conventions this guide adds:

- Test file in the same package as the subject, in the corresponding `test/` or `jvmTest/` source set.
- Test function names are backtick sentences — they become the failure message. Write them so the failure message is informative without reading the test body.
- Structure: arrange → act → assert. Separate phases with a blank line.
- Test observable behavior, not implementation details. If a refactor breaks tests without changing behavior, the tests are wrong.
- For the `:ballistics` module: physics claims belong as test cases in `ballistics-test-data/test_cases/`, not inline in code. The validation harness is the record.

---

## 7. Trade Secret Guard

`entryBias`, `applyBias`, and `interpolateDopeAll` are `internal` to the `:ballistics` module. Do not:

- Expose them via any public API surface
- Describe their algorithm in comments, test names, or commit messages
- Reference the DOPE-Blend methodology in any content that could be committed to a repo or filed in a public issue tracker

Git history and Jira are third-party-hosted infrastructure. Treat them as if they are public.

---

## Document Control

| Field | Value |
|---|---|
| **Document owner** | `jschwefel@coldboreballisticsllc.com` |
| **Classification** | Confidential (03_-_Confidential/) |
| **Location** | `OneDrive/CBB_Corporate/03_-_Confidential/Style_Guides/CODING_STYLE_GUIDE.md` |
| **Cross-references** | `BRAND_LEGAL_LANGUAGE_GUIDE.md`; `TECHNICAL_DOCUMENTATION_GUIDE.md` |
| **Created** | 2026-06-04 |
| **Last updated** | 2026-06-09 |
| **Next full review due** | 2027-06-04 |

---

## Revision Control Block

| Rev | Date | Changed By | Reviewed By | Approved By | Summary |
|-----|------|------------|-------------|-------------|---------|
| 0.9 | 2026-06-04 | jschwefel | — | — | Initial release |
| DRAFT | 2026-06-09 | Claude Code | — | — | Removed non-standard `# Last Updated` header line (per TECHNICAL_DOCUMENTATION_GUIDE §7). No content changes. NOTE (not edited): §7 lists `interpolateDopeAll` as `internal`, but in the live `BallisticsEngine.kt` it is declared without an access modifier (effectively public) — flagged as a code-vs-policy gap for separate resolution; the guide is left as the intended policy. |
