Skip to content

Post-port feature completion: persistence, taxonomy, images, DTC, security providers, CAN/DBC, leases - #31

Merged
turinglambdaai merged 8 commits into
mainfrom
feat/roadmap-batch
Oct 2, 2026
Merged

turinglambdaai merged 8 commits into
mainfrom
feat/roadmap-batch

Conversation

@turinglambdaai

Copy link
Copy Markdown
Owner

What

Implements the remaining software-side roadmap features after the v0.6.0
port, per ADR 0002's own revisit list:

  1. Persistent evidence/artifact store — completed operation and
    observation records (+ evidence) append to JSONL under
    ~/.benchpilot/store and seed the runtime at startup, so team/CI
    history survives daemon restarts; larger evidence lands as artifacts
    (size + SHA-256 references) instead of LLM context.
  2. Device error taxonomy — vendor failure messages classify at the
    fault site into six stable classes; faulted operations carry a
    device.error evidence item (no vendor types reach Core).
  3. Image model — Intel HEX + Motorola S-record parse into segments
    (checksums enforced); flash plans flash HEX/S-record images as one
    segment per contiguous region automatically.
  4. UDS DTC — ReadDTCInformation/ClearDiagnosticInformation builders +
    parser, simulated-ECU coverage, CLI uds dtc read|clear.
  5. Security Provider abstraction — command:<id> deriver names run
    external vendor binaries (<cmd> --seed <hex>), keeping algorithms
    out of Core.
  6. CAN capture + DBC — bounded newest-first capture sessions per bus,
    JSONL artifact rows, DBC BO_/SG_ decode/encode (Intel + Motorola,
    factors/offsets/signedness), CLI can send|capture|frames|decode.
  7. Team benches — target leases (TTL, token-hash ownership,
    acquire/renew/release/check; safety.leasesRequired per profile) +
    persistent JSONL audit trail; CLI lease ....

Found and fixed on the way: every mutex helper in the codebase used
begin0 to post its semaphore — begin0 never runs the post on raise, so
any failed call while holding a gate deadlocked the next caller. All
helpers are dynamic-wind now (found by the lease deadlock test).

Tests

120 → 127+ (persist round trip, taxonomy, images golden, DTC channel,
security provider shell round trip, CAN/DBC golden incl. signed decode
and Intel round trip, lease ownership/conflict/expiry/renew/audit).
Full suite green locally; CI validates ubuntu + windows.

Deliberately not here

  • voltage/current monitoring during programming, explicit recovery
    strategies, CAN FD FDF variants, preflight fingerprint — flash engine
    refinements, listed open in ROADMAP;
  • physical bench validation (hardware), Studio GUI, remote transport
    (TLS/auth roles) — unchanged roadmap gates.

- core/persist: append-only JSONL store (~/.benchpilot/store; env
  BENCHPILOT_STORE_DIR / BENCHPILOT_STORE=0) holding completed operation
  and observation records with their evidence; artifacts live as files
  with size + SHA-256 references so larger evidence stays out of LLM
  context (roadmap: persistent evidence/artifact storage + artifact
  references)
- the runtime appends on every completed record and seeds its bounded
  in-memory history/evidence from the store at startup; serialization
  happens before the file write so a failure never tears a line
- daemon routes: GET /store/operations|observations|artifacts and
  /store/artifact (base64 content); CLI: benchpilot store evidence |
  observations | artifacts | artifact <id> [--out]
- 4 store tests including a cross-session seed round trip
- core/device-errors: vendor SDK failure messages classify into six
  stable classes (timeout/transport/device-state/permission/not-found/
  protocol) at the fault site; faulted operations gain a bounded
  device.error evidence item naming the class and matched pattern —
  agents branch on behavior, vendor types never reach Core
- diagnostics/flash/image: Intel HEX (types 00/01/02/04, checksum
  enforced, extended linear/segment bases) and Motorola S-record
  (S1/S2/S3 data, S7-S9 stop, one's-complement checksums) parse into
  address/data segments; adjacent records merge into contiguous regions
- flash plans: .hex/.ihex/.s19/.srec firmware becomes one segment per
  contiguous region automatically; BIN stays explicit-address
- protocol: uds-read-dtcs (ReadDTCInformation 0x19 subfunction 0x02) and
  uds-clear-dtcs (ClearDiagnosticInformation 0x14) request builders plus
  a DTC response parser (3-byte DTC + status records)
- the simulated ECU answers both services and keeps DTC state across a
  session (canned fault 0x010870, status 0x2f)
- CLI: uds dtc read [--mask XX] / uds dtc clear [--group XXXXXX] over
  the existing /uds/request route; clear answers with the bare positive
  SID so responseHex is empty by design
- 3 channel-level tests
- diagnostics/security-provider: command:<id> deriver names run an
  external executable with the seed as hex; failures surface as failed
  security-access steps
- flash engine: unknown deriver names fall back through the provider
  resolver after the builtin table
- 3 tests incl. a real shell script round trip
…capture, bounded artifacts, DBC decoding, signal observations)

- diagnostics/can/capture: capture sessions with a bounded newest-first
  frame ring per bus; JSON row emission (id/data/timestamp) for capture
  artifacts; frames survive nothing unbounded
- DBC subset: BO_/SG_ message + signal headers, Intel (@1) and Motorola
  (@0) layouts, factors/offsets/signedness; decode applies scaling,
  encode packs Intel signals and rejects Motorola packing + out-of-range
  values instead of guessing
- 8 golden tests: parse, decode (incl. signed), encode round trip,
  bounded ring, JSON rows
…tex helpers are exception-safe

- core/leases: target leases with TTL, ownership by token hash (FNV-1a,
  self-contained), acquire/renew/release/check; a conflicting live lease
  raises the typed error (409 at the API); leases optionally required
  per profile (safety.leasesRequired); audit trail appends JSONL events
  into the store directory
- the store/registry/etc. mutex helpers now use dynamic-wind — begin0
  never posted the semaphore on raise, so any mutating call that failed
  while holding a gate deadlocked the next caller (found by the lease
  deadlock test; fix applied to every helper in the codebase)
- 7 lease tests: ownership, conflict, takeover after expiry, renew
  permission, audit persistence
- daemon: /lease/acquire|renew|release|list (mutations honor
  safety.leasesRequired through lease-check at the mutation gate when a
  profile enables it), /can/capture/start|stop, /can/frames,
  /can/decode (DBC), /can/send; capture sessions register per-bus with
  bounded rings; diag channels expose their bus via a new provider
  generic (real CAN yes, simulated no)
- CLI: can send|capture|frames|decode and lease
  acquire|renew|release|list
- roadmap: mark the shipped software features; remaining open items are
  CAN FD variants, programming power monitoring, recovery strategies,
  physical validation, Studio, remote transport
@turinglambdaai
turinglambdaai merged commit 757a7b0 into main Oct 2, 2026
2 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant