docs(v0.12.0): DTC history user-facing guide (slice 6) - #148
Conversation
Slice 6 of v0.12.0 Fault Memory (docs/v0.12.0_plan.md):
docs/validation/dtc-history.md — the user-facing guide for the
opt-in DTC history added in slices 2-5. Same shape as
testplans.md and service-functions.md:
- Purpose / Time required / Risk honesty blockquotes at top
- Section 1: Where the file lives (~/beeemuu-exports/dtc-history.jsonl)
- Section 2: File format — one JSON object per line, every field
explained in a table
- Section 3: The 60-second dedup window (why re-reads don't
double-count)
- Section 4: 'No VIN' entries — why slice 5 doesn't merge them
with VIN-tagged ones
- Section 5: Clearing the history — three ways (terminal rm,
untick toggle, hand-edit JSONL)
- Section 6: Storage growth — ~250 bytes per line, years of use
before any concern
- Section 7: What this file is NOT (not a backup, not shareable,
not a substitute for diagnosis, not a write to the car)
- Section 8: How to verify the file is being written
- Section 9: Privacy note (local-only, no cloud, no telemetry)
Tier A — docs only. Self-merge when CI green.
|
🤖 Doc-only change — auto-merge enabled. Will merge once required checks pass. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 900762f0c8
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| The recurring-DTC callout (slice 5) does **not** merge no-VIN | ||
| entries with VIN-tagged ones. So a "2A82" recorded before the VIN | ||
| read will not count toward the "seen before" banner after you | ||
| read the VIN. This is intentional: an unknown VIN could mean a | ||
| different car, and silently merging across cars would produce |
There was a problem hiding this comment.
Correct the no-VIN isolation claim
When the VIN is unavailable, main.js calls queryDtcHistory(null, ...), and the Rust grouping function applies no VIN filter for None, so no-VIN and VIN-tagged records are grouped together by code/address. A repo-wide search also finds no element defining the info-vin ID that main.js reads, meaning the current renderer always takes this unfiltered path. This assurance therefore hides cross-vehicle mixing that can produce misleading recurrence counts; remove it or fix the VIN wiring/filtering before documenting histories as isolated.
Useful? React with 👍 / 👎.
| 3. **Hand-edit the file.** The JSONL is plain text. `grep -v '"code":"2A82"'` | ||
| keeps every line except the one you want to forget, redirected | ||
| back into the same file. Power users only; see §2 for the |
There was a problem hiding this comment.
Avoid redirecting grep output onto its input file
If a user follows this instruction with the natural command grep -v ... dtc-history.jsonl > dtc-history.jsonl, the shell truncates the history file before grep reads it, deleting every entry rather than only the selected code. Direct users to write to a temporary file and then replace the original, or use a tool designed for in-place filtering.
Useful? React with 👍 / 👎.
| 2. `wc -l ~/beeemuu-exports/dtc-history.jsonl` increases by 1 | ||
| for each non-empty read (the dedup window collapses duplicates). |
There was a problem hiding this comment.
Describe line growth per DTC instead of per read
For a read returning multiple distinct DTCs, record_dtc_read_impl appends one line for each DTC, while an empty successful read appends no line at all. Therefore this verification step grows by the number of non-deduplicated DTCs, not by one per non-empty read, and users reading several faults will incorrectly conclude that recording is malfunctioning.
Useful? React with 👍 / 👎.
| 30 × 52 × 250 = ~390 KB. The slice-5 callout only looks at lines | ||
| within the past 14 days, so an old file is fine to keep — older | ||
| lines just don't surface. |
There was a problem hiding this comment.
Stop describing the occurrence count as a 14-day total
renderHistoryCallout calls queryDtcHistory(vin, null), so Rust groups all historical lines before JavaScript merely checks whether each bucket's latest timestamp is within 14 days. If a code appeared 50 times last year and once today, the banner reports 51 occurrences in the past 14 days; older lines therefore still affect the surfaced result. Pass the cutoff into the query or document this as an all-time count for codes observed recently.
Useful? React with 👍 / 👎.
| | `status` | Raw status byte from UDS `0x19 02`. The displayed `status_text` is derived from this. | | ||
| | `status_text` | Human-readable status (e.g. `"confirmed"`, `"pending"`, `"intermittent"`). | |
There was a problem hiding this comment.
Document the status byte's actual KWP source
The production read_dtcs path sends KWP 18 02 FF FF, not UDS 0x19 02, and its formatter emits combinations of test failed, confirmed, stored, and current (or logged), rather than the documented pending and intermittent examples. Users comparing this file with a transport capture or interpreting status bits will therefore use the wrong protocol and labels; describe the KWP response and the actual formatter output.
Useful? React with 👍 / 👎.
| One JSON object per line. Forward-compatible: serde ignores unknown | ||
| fields on read, so a future schema bump won't break old files. |
There was a problem hiding this comment.
Qualify the forward-compatibility guarantee
Serde's unknown-field tolerance only lets an older reader ignore extra fields; it does not let a future HistoryLine with a new required field deserialize existing records. Because every current field is required and malformed records are silently counted as skipped, such a schema change would make the user's old history disappear from queries despite this guarantee. Require defaults or migration for future fields, or narrow the documented promise accordingly.
Useful? React with 👍 / 👎.
| |---|---| | ||
| | `ts_iso` | UTC timestamp of the read (zero-padded, ISO-8601, sortable as a string). | | ||
| | `vin` | VIN of the car when the read happened, or `null` if no VIN was known. | | ||
| | `address` | UDS target id of the module that reported the fault (e.g. `0x12` for DME, `0x18` for EGS). | |
There was a problem hiding this comment.
Clarify that serialized module addresses are decimal
Serde serializes the u8 address as a decimal JSON number, so the sample's literal 18 represents 0x12 (DME), not the 0x18 EGS address presented in this table. A user filtering or hand-editing the JSONL for EGS based on the documented hexadecimal examples would select the wrong module; state the decimal encoding or include both forms, such as 24 (0x18) for EGS.
Useful? React with 👍 / 👎.
What
Slice 6 of v0.12.0 Fault Memory (
docs/v0.12.0_plan.md):docs/validation/dtc-history.md— the user-facing guide for the opt-in DTC history added in slices 2–5.Same harness-doc shape as
testplans.md(slice 6 of v0.9.0) andservice-functions.md(slice 6 of v0.8.0):~/beeemuu-exports/dtc-history.jsonl, same home-dir resolution asexport_text(CLAUDE.md §3)commands.rs::DTC_DEDUP_WINDOW_SECS)rm, untick the toggle, hand-edit the JSONL), plus a note that no in-app "Clear" button exists yetwc -l+tail -1sanity checkWhy
The slice 1 plan (
docs/v0.12.0_plan.mdslice 6) explicitly says: "Same shape asdocs/validation/testplans.mdanddocs/validation/service-functions.md: file location, line format, clear procedure, dedup window, 'no VIN' caveat." This PR delivers that.The user-facing guide answers the questions that the slice-5 callout will inevitably raise: "where did this file come from?", "how do I delete it?", "is this private?". Without it, the recurring-DTC feature ships blind.
What changed
docs/validation/dtc-history.md— new, 179 lines.Verification
git diff --stat origin/main→docs/validation/dtc-history.md | 179 +++(single new file, no churn).docs/v0.12.0_plan.md) and that file exists atdocs/v0.12.0_plan.md.docs/validation/: opening blockquote triplet (> **Purpose.**,> **Time required.**,> **Risk honesty.**), numbered sections with## N. Title, practical examples (grep | wc -l,rm,jq).rmis the supported path; the UI button is a follow-up.Tier
A — docs only, no Rust / commands.rs / transport / protocol change. Self-merge once required CI is green.
v0.12.0 progress — cycle complete
All 6 v0.12.0 "Fault Memory" slices shipped. The cycle closed in 7 PRs (1 plan + 1 Rust + 4 frontend + 1 docs). The recurring-DTC callout is live in the app; the JSONL log is in place; the documentation explains it all.
Unrelated working-tree noise (not in this PR)
Three files are modified locally but staged only my one intended file:
CLAUDE.md— your own rewrite (Tier C, yours to land)frontend/index.html,frontend/schematics.html— the recurring third-party "network bar" injection (untrusted, not propagated)