tokmd-sensor 1.9.0

EffortlessSensor trait and substrate builder for multi-sensor integration.
Documentation
# tokmd-sensor

## Purpose

Sensor contract and substrate builder. This is a **Tier 1** crate.

## Responsibility

- Define the `EffortlessSensor` trait for multi-sensor integration
- Build `RepoSubstrate` from a single tokei scan (+ optional git diff)
- **NOT** for sensor implementations (those go in their respective crates)
- **NOT** for CLI parsing

## Public API

```rust
/// Trait for effortless code quality sensors.
pub trait EffortlessSensor {
    type Settings: Serialize + DeserializeOwned;
    fn name(&self) -> &str;
    fn version(&self) -> &str;
    fn run(&self, settings: &Self::Settings, substrate: &RepoSubstrate) -> Result<SensorReport>;
}

/// Build a RepoSubstrate from a scan of the given repo root.
pub fn substrate_builder::build_substrate(
    repo_root: &str,
    scan_options: &ScanOptions,
    module_roots: &[String],
    module_depth: usize,
    diff_range: Option<DiffRange>,
) -> Result<RepoSubstrate>
```

## Implementation Details

### Settings / Substrate / Report Separation

1. **Settings** (`Self::Settings`): Each sensor defines its own configuration type
2. **Substrate** (`RepoSubstrate`): Shared context built once, shared across sensors
3. **Report** (`SensorReport`): Standardized envelope from `tokmd-envelope`

### Substrate Builder

- Runs tokei scan once via `tokmd-scan`
- Builds file rows via `tokmd-model`
- Marks files appearing in the diff range as `in_diff`
- Aggregates per-language summary into `BTreeMap` for determinism

### Feature Flags

- `git`: Enables `tokmd-git` dependency for git diff context

## Dependencies

- `tokmd-envelope` (SensorReport contract)
- `tokmd-substrate` (RepoSubstrate types)
- `tokmd-settings` (ScanOptions)
- `tokmd-scan` (tokei wrapper)
- `tokmd-model` (file row aggregation)
- `tokmd-types` (ChildIncludeMode)
- Optional: `tokmd-git` (behind `git` feature)

## Testing

```bash
cargo test -p tokmd-sensor
```

Tests cover:
- Trait implementation with a dummy sensor
- Substrate building from real crate source
- Diff range marking (in_diff selectivity)
- Error on missing repo root

## Do NOT

- Add sensor implementations here (this crate defines the contract only)
- Add CLI argument parsing (belongs in tokmd CLI)
- Skip path normalization in the substrate builder