# Bench Environment

Use stable `SN/port` identifiers in every persisted bench profile and generated
script. A numeric enumeration index is allowed only after inspecting the current
enumeration result and must not be carried across hosts or USB topology changes.

On Linux, `bmcli doctor` distinguishes BMAPI enumeration failure from a visible
BUSMUST USB device that lacks `/dev/bus/usb` permissions. Follow its bundled
udev-rule instruction instead of running long-term automation as root.

## State model

| State | Meaning | Action |
|---|---|---|
| `READY` | Hardware identity, port, bus timing, and operation-specific values are validated | Execute the requested workflow |
| `DEGRADED` | Optional data such as DBC is unavailable | Continue with raw IDs/payloads and record the limitation |
| `NEEDS_INPUT` | A required logical value has no safe discovery path | Ask for the smallest missing set |
| `DISCOVERY_REQUIRED` | Cached physical values are missing or stale and discovery is authorized | Enumerate, AutoSet, validate, then persist |
| `OFFLINE` | No suitable hardware or active bus is reachable | Generate scripts/tests/docs without claiming execution |

## Configuration ownership

One `.bmcli` directory describes one target and one complete bench. The bench
may contain several logical networks and physical channels. Use two files so
portable target intent is not mixed with one engineer's USB setup.

`.bmcli/target.json` is project-owned and may be versioned:

```json
{
  "schema_version": 1,
  "target": {
    "name": "vehicle-a",
    "variant": "production-a",
    "kind": "vehicle"
  },
  "default_network": "vehicle-can",
  "default_node": "sensor-controller",
  "networks": {
    "vehicle-can": {
      "bus": "can",
      "mode": "normal",
      "nbitrate_kbps": 500,
      "dbitrate_kbps": 2000,
      "bitrate_bps": 0,
      "databases": ["network/vehicle.dbc"]
    },
    "sensor-private-can": {
      "bus": "can",
      "mode": "normal",
      "nbitrate_kbps": 500,
      "dbitrate_kbps": 2000,
      "bitrate_bps": 0,
      "databases": ["network/sensor.dbc"]
    }
  },
  "nodes": {
    "sensor-controller": {
      "network": "sensor-private-can",
      "uds": {
        "request_id": "0x7E0",
        "response_id": "0x7E8",
        "addressing": "normal-11bit",
        "padding": "0x00"
      }
    }
  }
}
```

`.bmcli/bench.local.json` is machine-owned and must be gitignored:

```json
{
  "schema_version": 1,
  "connections": {
    "vehicle-can": {
      "channel": "10356/0",
      "termination": "off",
      "power": "off"
    },
    "sensor-private-can": {
      "channel": "10356/1",
      "termination": "120",
      "power": "off",
      "analyzer_model": "XL4",
      "firmware": "3.1.0.5"
    }
  },
  "validated": {
    "method": "enumerate+autoset"
  },
  "local_paths": {
    "security_algorithm": "C:/ecu/oem/security.dll"
  }
}
```

Add `.bmcli/bench.local.json` and generated captures containing customer data to
the project's ignore rules. Do not put secrets, seed-key material, or proprietary
firmware into the project configuration. A logical network name is portable and
may be used as `--channel=<network-name>`; BMCLI resolves it to the local binding
before standalone execution or daemon forwarding.

BMCLI searches upward from the current directory for the nearest `.bmcli`.
`--project=<directory>` selects an explicit root. When no project exists, the
per-user default is used; create it explicitly with `bench init --global`.
Project and global profiles are never merged.

## Initialization sequence

1. Run `bmcli doctor`.
2. Run `bmcli channel enumerate --format=json` and filter for the requested CAN
   or LIN capability. Mixed XL4 devices expose both kinds of fixed-function
   ports under the same model name.
3. Compare serial, port, model, firmware, and capability with cached values.
4. For CAN, if the channel is unknown and discovery is authorized, run passive AutoSet on
   plausible ports one at a time. Stop when one succeeds only if the topology is
   unambiguous. If the bus is silent, offer active AutoSet; explain that it sends
   probe frames and require explicit authorization before running it.
5. For LIN, confirm the physical master/slave topology, role, bitrate, pull-up,
   and bus power direction from the LDF/matrix and bench wiring. Enumeration
   identifies LIN-capable ports but cannot discover which endpoints are wired
   together or which node may safely source the bus supply.
6. Confirm the detected or supplied timing against the target/network specification
   when one is available.
7. Validate UDS IDs with `uds discover` using TesterPresent or a documented read
   DID. Dry-run first, require `--allow-functional`, and never auto-select one of
   multiple correlated responders. When `selection_required=true`, show the
   candidate response IDs and ask the user to choose. Treat inferred physical
   request IDs as candidates until a target identity read confirms the node.
8. Validate each database source with `database validate`, and register it with
   `database load` when later commands should refer to a persistent resource
   name. Inspect an LDF through `ldf info`, `ldf node`, `ldf frame`, `ldf signal`,
   and `ldf schedule`; confirm that its cluster and variant match the bench before
   activating a table. A matrix format without a typed BMCLI parser remains an
   external reviewed input.
9. Persist each confirmed logical network, addressed node, and local channel
   binding with `bmcli bench init --network=<name> [--node=<name>]`, then run
   `bmcli bench validate --hardware --format=json`. Do not hand-edit files when
   runtime Help exposes the field. When several networks exist, name the intended
   network explicitly instead of assuming the default. Use repeatable
   `--database=<path>` for protocol-neutral source references; use `--dbc` only
   as the single-DBC convenience form reported by runtime Help.

## Stale configuration triggers

Re-enter initialization when any of these occurs:

- configured serial/port is absent from enumeration;
- model, firmware, or capability changes unexpectedly;
- AutoSet no longer sees the configured bus timing;
- repeated transport timeouts occur after USB and bus checks;
- UDS responses come from an unexpected ID or target identity DID changes;
- the user says the analyzer, port, harness, target, vehicle, or database changed.

Invalidate only the affected layer. A changed USB port does not invalidate the
logical UDS specification; a changed target variant may invalidate UDS IDs and DBC
while leaving the analyzer identity valid.
