Skip to content

feat(frontend): v0.7.0 PR #2 — theme toggle, workspace persistence, profile theme colors - #109

Merged
ohgeeceee merged 1 commit into
mainfrom
feat/v0.7.0-ready-to-claim
Jul 18, 2026
Merged

feat(frontend): v0.7.0 PR #2 — theme toggle, workspace persistence, profile theme colors#109
ohgeeceee merged 1 commit into
mainfrom
feat/v0.7.0-ready-to-claim

Conversation

@ohgeeceee

Copy link
Copy Markdown
Owner

Summary

Second PR from docs/v0.7.0_plan.md — the "Ready-to-Claim pile" (three small, independent features bundled per plan §PR #2):

  • Theme toggle completion — light theme is now the default and is pixel-identical to the previous hard-coded look; dark theme is a full token swap. Toggle persists across restarts.
  • Workspace state persistence — open tabs, active vehicle/profile, and theme save to ~/beeemuu-exports/workspace.json and restore on launch. One new async command (read_export_text; async-command guard now at 45).
  • Per-profile [profile.theme] gauge colors — profiles can override gauge palette (e.g. M-car red/blue). Required a small Rust pass-through — the plan's "already supported" claim was inaccurate. b58.toml ships a reference theme block.

Test plan

  • cargo test — 97 lib + 1 integration green
  • node --test — 57 green
  • pytest — 151 green
  • cargo build warning-clean
  • Manual tauri dev smoke: toggle theme, restart, confirm tabs + theme restore; load b58 profile, confirm gauge colors — flagged for merger

Merge policy

Tier A under CLAUDE.md (frontend-only + docs + one additive non-transport command) — agent may self-merge when CI is green.

Closes part of docs/v0.7.0_plan.md PR #2.

…uge [profile.theme] (plan PR #2)

Ready-to-Claim pile, three items in one Tier A commit:

1. Theme toggle completed: the pre-existing toggle only re-skinned a
   handful of panels; app.css now routes every theme-relevant surface
   through CSS variables with a full body[data-theme=dark] override
   block. The light default stays pixel-identical (:root gains the
   exact literals that were hardcoded before). Persistence moves from
   localStorage to workspace.json (one persistence system).

2. Workspace layout persistence: theme, app mode, active tab,
   connection panel choices, live/log profile selectors, traffic
   auto-refresh, and the per-profile log channel enabled map save
   debounced to ~/beeemuu-exports/workspace.json via the new async
   read_export_text command (writes reuse export_text). First boot
   migrates beeemuu_dark/beeemuu_settings/beeemuu_mode from
   localStorage; corrupt/missing files fall back to defaults. Also
   fixes the legacy connOptsOpen flag, which ANDed the two option
   panels and was effectively always false.

3. Gauge [profile.theme] blocks: ProfileToml/Profile carry an optional
   theme map, surfaced via list_profiles (omitted from JSON when empty)
   and round-tripped by export_profile/import_profiles. gauges.js
   resolves nine colour keys with per-key fallback and CSS.supports
   validation; b58.toml ships the reference block; syntax documented
   in DECODE_FUNCTIONS.md section 9.

Tests: cargo 95 -> 97 lib (+2 community theme parse tests) + 1
integration guard (command count 44 -> 45); node --test 43 -> 57
(+14 workspace round-trip/migration tests). Plan deviations: theme
toggle already existed (completed, not added); light is the default
theme (plan said dark); [profile.theme] needed a minimal Rust
pass-through (plan claimed the TOML format already supported it);
workspace file lives in ~/beeemuu-exports/ (plan said ~/beeemuu/).
@ecc-tools

ecc-tools Bot commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

ECC bundle files are already tracked in this repository. Skipping generation of another bundle PR.

@ohgeeceee
ohgeeceee merged commit afefc32 into main Jul 18, 2026
10 of 11 checks passed
@ohgeeceee
ohgeeceee deleted the feat/v0.7.0-ready-to-claim branch July 18, 2026 08:52

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d75297e78f

ℹ️ 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".

Comment thread src/js/main.js
$("view-" + active.dataset.view).classList.add("active");
}
try { localStorage.setItem("beeemuu_mode", mode); } catch (_) {}
saveSettings(); // persist the mode (v0.7.0 workspace; was beeemuu_mode)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Restore the saved tab before saving mode

When workspace.json contains a non-default activeTab, startup calls applyMode() before restoreActiveTab(). This new saveSettings() call copies the currently active default Vehicle tab into workspaceState.activeTab, so restoreActiveTab() reads the overwritten value and the saved tab is never restored; the following debounced write also persists the wrong tab.

Useful? React with 👍 / 👎.

Comment thread src/js/main.js
Comment on lines +2162 to +2163
buildLogParams();
saveSettings(); // persist the selected log profile (v0.7.0 workspace)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Wait for log rows before saving the new profile

When connected, buildLogParams() awaits read_live_data before replacing #log-params, but this handler calls saveSettings() immediately. Switching the log profile therefore saves the new logProfile together with the old profile's still-rendered checkboxes, storing the old channel map under the new profile key and corrupting the per-profile channel preferences.

Useful? React with 👍 / 👎.

Comment thread src/js/main.js
Comment on lines 1479 to +1481
if (!logSeries.has(v.id)) {
logSeries.set(v.id, new LogSeries(v.label, v.unit, color, i < 3));
const enabled = typeof savedEnabled[v.id] === "boolean" ? savedEnabled[v.id] : i < 3;
logSeries.set(v.id, new LogSeries(v.label, v.unit, color, enabled));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reapply saved channel state for reused log IDs

When switching between log profiles that share channel IDs such as rpm or coolant, the saved per-profile map is only consulted while creating a brand-new LogSeries. Existing series keep the previous profile's enabled value, so a restored preference for the newly selected profile is ignored for every overlapping channel unless the ID has never been seen in this session.

Useful? React with 👍 / 👎.

Comment thread src/js/main.js
function restoreActiveTab() {
const name = workspaceState.activeTab;
if (!name) return;
const tab = document.querySelector(`.tab[data-view="${name}"]`);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Escape the restored tab name before querying

Because parseWorkspace() accepts any non-empty string for activeTab, a hand-edited or forward-version workspace value containing selector syntax like " or ] makes this template string an invalid CSS selector. In that case querySelector() throws during startup instead of ignoring the bad saved tab, so a malformed workspace file can break the init path until the user fixes the file manually.

Useful? React with 👍 / 👎.

github-actions Bot pushed a commit that referenced this pull request Jul 31, 2026
…moved to ✅ Done (#200)

Six items in the v0.3.0 'Real Car' historical section were
marked 🟢 Ready but have actually shipped:

| Item                  | Shipped in      | Reference                |
|-----------------------|-----------------|--------------------------|
| KWP2000 slow timeout  | v0.13.0 (PR #153) | commit fd9efc2          |
| ISO-TP multi-frame    | v0.14.x         | src-tauri/src/transport/isotp.rs (enforced by CLAUDE.md, refreshed in PR #198) |
| Dark/light theme      | v0.7.0 (PR #109) | commit afefc32           |
| Gauge theming         | v0.7.0 (PR #109) | commit afefc32           |
| Save/load workspace   | v0.7.0 (PR #109) | commit afefc32           |
| Export PNG/SVG charts | v0.11.0 (PR #136) | commit 7f92ccb          |

This is the same doc-rot pattern that PR #198 fixed in
CLAUDE.md: items the inventory still claims as 'Ready to land'
have actually shipped, but nobody re-tagged the historical
section afterward. Same 'data over invention' fix as the
CLAUDE.md refresh.

What changed:

- '⭐ Protocol & Transport' table — kept the four genuinely-🟡
  items (ENET/DoIP, BLE, WiFi, CAN-bus listener), removed the
  two stale 🟢 Ready items.
- 'UI / UX' table — kept the only genuinely-🟡 item (Mobile-
  responsive), removed the five stale 🟢 Ready items.
- New '✅ Protocol, Transport, UI/UX — historical (shipped)'
  table — pins the six shipped items with their PR references
  and code locations, following the v0.3.0 'Decode Functions'
  historical pattern that already exists just above.

What this PR does NOT change:

- No CHANGELOG.md edits (the shipped-PR references are in
  CHANGELOG.md already)
- No CLAUDE.md edits (the ISO-TP / keepalive / read_vin
  references there are already accurate post PR #198)
- No code edits
- No test edits (markdown only)

Verified locally (docs-only, no test diff expected):

- node --test src/js/**/*.test.js src/js/**/*.test.cjs: 226/226
- python -m pytest backend/tests/ -q: 166/166
- cd src-tauri && cargo test --lib --offline: 149/149
- npm run build: rc=0, both BeeEmUu_0.14.3 bundles built

Tier A docs-only per CLAUDE.md. Self-merge on CI green.

Cross-references:
- PR #198: 'docs: refresh CLAUDE.md hardware/timing invariants'
  (the same doc-rot sweep on CLAUDE.md)
- PR #183: 'docs(proposal): fix stale NOT YET IMPLEMENTED claims'
  (proposed similar fixes but never applied)

Co-authored-by: ohgeeceee <ohgeeceee@users.noreply.github.com>
github-actions Bot pushed a commit that referenced this pull request Jul 31, 2026
…moved to ✅ Done (#205)

Six items in the v0.3.0 'Real Car' historical section were
marked 🟢 Ready but have actually shipped:

| Item                  | Shipped in      | Reference                |
|-----------------------|-----------------|--------------------------|
| KWP2000 slow timeout  | v0.13.0 (PR #153) | commit fd9efc2          |
| ISO-TP multi-frame    | v0.14.x         | src-tauri/src/transport/isotp.rs (enforced by CLAUDE.md, refreshed in PR #198) |
| Dark/light theme      | v0.7.0 (PR #109) | commit afefc32           |
| Gauge theming         | v0.7.0 (PR #109) | commit afefc32           |
| Save/load workspace   | v0.7.0 (PR #109) | commit afefc32           |
| Export PNG/SVG charts | v0.11.0 (PR #136) | commit 7f92ccb          |

This is the same doc-rot pattern that PR #198 fixed in
CLAUDE.md: items the inventory still claims as 'Ready to land'
have actually shipped, but nobody re-tagged the historical
section afterward. Same 'data over invention' fix as the
CLAUDE.md refresh.

What changed:

- '⭐ Protocol & Transport' table — kept the four genuinely-🟡
  items (ENET/DoIP, BLE, WiFi, CAN-bus listener), removed the
  two stale 🟢 Ready items.
- 'UI / UX' table — kept the only genuinely-🟡 item (Mobile-
  responsive), removed the five stale 🟢 Ready items.
- New '✅ Protocol, Transport, UI/UX — historical (shipped)'
  table — pins the six shipped items with their PR references
  and code locations, following the v0.3.0 'Decode Functions'
  historical pattern that already exists just above.

What this PR does NOT change:

- No CHANGELOG.md edits (the shipped-PR references are in
  CHANGELOG.md already)
- No CLAUDE.md edits (the ISO-TP / keepalive / read_vin
  references there are already accurate post PR #198)
- No code edits
- No test edits (markdown only)

Verified locally (docs-only, no test diff expected):

- node --test src/js/**/*.test.js src/js/**/*.test.cjs: 226/226
- python -m pytest backend/tests/ -q: 166/166
- cd src-tauri && cargo test --lib --offline: 149/149
- npm run build: rc=0, both BeeEmUu_0.14.3 bundles built

Tier A docs-only per CLAUDE.md. Self-merge on CI green.

Cross-references:
- PR #198: 'docs: refresh CLAUDE.md hardware/timing invariants'
  (the same doc-rot sweep on CLAUDE.md)
- PR #183: 'docs(proposal): fix stale NOT YET IMPLEMENTED claims'
  (proposed similar fixes but never applied)

Co-authored-by: ohgeeceee <ohgeeceee@users.noreply.github.com>
ohgeeceee added a commit that referenced this pull request Jul 31, 2026
…e.rs (#201)

* docs(roadmap): audit v0.3.0 historical section — stale 🟢 Ready items moved to ✅ Done

Six items in the v0.3.0 'Real Car' historical section were
marked 🟢 Ready but have actually shipped:

| Item                  | Shipped in      | Reference                |
|-----------------------|-----------------|--------------------------|
| KWP2000 slow timeout  | v0.13.0 (PR #153) | commit fd9efc2          |
| ISO-TP multi-frame    | v0.14.x         | src-tauri/src/transport/isotp.rs (enforced by CLAUDE.md, refreshed in PR #198) |
| Dark/light theme      | v0.7.0 (PR #109) | commit afefc32           |
| Gauge theming         | v0.7.0 (PR #109) | commit afefc32           |
| Save/load workspace   | v0.7.0 (PR #109) | commit afefc32           |
| Export PNG/SVG charts | v0.11.0 (PR #136) | commit 7f92ccb          |

This is the same doc-rot pattern that PR #198 fixed in
CLAUDE.md: items the inventory still claims as 'Ready to land'
have actually shipped, but nobody re-tagged the historical
section afterward. Same 'data over invention' fix as the
CLAUDE.md refresh.

What changed:

- '⭐ Protocol & Transport' table — kept the four genuinely-🟡
  items (ENET/DoIP, BLE, WiFi, CAN-bus listener), removed the
  two stale 🟢 Ready items.
- 'UI / UX' table — kept the only genuinely-🟡 item (Mobile-
  responsive), removed the five stale 🟢 Ready items.
- New '✅ Protocol, Transport, UI/UX — historical (shipped)'
  table — pins the six shipped items with their PR references
  and code locations, following the v0.3.0 'Decode Functions'
  historical pattern that already exists just above.

What this PR does NOT change:

- No CHANGELOG.md edits (the shipped-PR references are in
  CHANGELOG.md already)
- No CLAUDE.md edits (the ISO-TP / keepalive / read_vin
  references there are already accurate post PR #198)
- No code edits
- No test edits (markdown only)

Verified locally (docs-only, no test diff expected):

- node --test src/js/**/*.test.js src/js/**/*.test.cjs: 226/226
- python -m pytest backend/tests/ -q: 166/166
- cd src-tauri && cargo test --lib --offline: 149/149
- npm run build: rc=0, both BeeEmUu_0.14.3 bundles built

Tier A docs-only per CLAUDE.md. Self-merge on CI green.

Cross-references:
- PR #198: 'docs: refresh CLAUDE.md hardware/timing invariants'
  (the same doc-rot sweep on CLAUDE.md)
- PR #183: 'docs(proposal): fix stale NOT YET IMPLEMENTED claims'
  (proposed similar fixes but never applied)

* feat(v0.14.4): story coverage — 52 unit tests for story.rs + anonymize.rs

Two user-facing Rust modules have shipped with **zero unit
tests** since the diagnostic-story + secure-snapshot-share
features landed:

- `src-tauri/src/story.rs` (350 LOC) — the Generate Story
  pipeline that powers the one-click mechanic narrative
  modal in `src/index.html:513` +
  `src/js/main.js:2961` (renderStory).
- `src-tauri/src/anonymize.rs` (113 LOC) — the VIN-stripping
  layer that powers the Secure Snapshot Share feature
  (`src/js/main.js:1071`).

Both are pure-Rust, deterministic, and snapshot-driven —
the right shape for unit tests with fixture-built
`SessionSnapshot` inputs. This PR adds 52 unit tests
covering:

**story.rs (32 tests):**
- `Severity::from_str` bucketing (critical / warning /
  unknown → info).
- `Severity` ordering (Critical > Warning > Info).
- `priority_for` severity → priority number.
- `parse_cost_range` parser: single value, tilde,
  hyphen, **en-dash** (the TOML files use en-dash —
  parser must normalise), whitespace, empty, garbage.
- `format_vehicle` for empty / VIN-only /
  mileage-only / decoded.
- `build_context` freeze-frame string assembly.
- Full `generate` pipeline:
  - empty snapshot → Info story with no findings.
  - unknown DTC → generic Info finding.
  - n55-specific DTC (2A82) → uses engine template.
  - generic DTC fallback when engine-specific missing.
  - severity = max of all findings (sorted critical-first).
  - recommendations sorted ascending by priority.
  - cost range sums across findings.
  - cost-max invariant: max >= min + 50.
  - DTC code case-insensitive lookup (TOML keys are
    uppercased on load).
  - summary text counts critical + warning correctly.
  - title uses manufacturer + VIN prefix.

**anonymize.rs (20 tests):**
- `hash_vin` properties: 16 hex chars, stable for same
  input, distinct for distinct inputs, case-sensitive
  (current behaviour pinned).
- `anonymize` pipeline:
  - VIN never leaks into the anonymized JSON.
  - VIN → fingerprint via hash_vin.
  - Missing VIN → "unknown" fingerprint.
  - engine_family preserved from suggested_profile.
  - engine_family defaults to "generic".
  - Modules / DTCs / freeze frames / ident all preserved.
  - Mileage (mileage_km) stripped (privacy).
  - Empty modules handled.
  - fault_count = None → 0 in the output.
  - recorded_at populated with "(UTC)" suffix.
  - live_data is always empty (current anonymizer
    strips it; pinning the decision).
- `export_json`:
  - No VIN leak in pretty JSON.
  - No mileage leak.
  - Pretty-printed (multi-line + indented).
  - Round-trips through serde.

## Verification

- `cd src-tauri && cargo test --lib --offline` — **201/201
  pass** (149 existing + 52 new).
- `cd src-tauri && cargo test --test async_commands
  --offline` — 1/1 (the CLAUDE.md invariant guard still
  green — no new sync commands).
- `node --test src/js/**/*.test.js src/js/**/*.test.cjs`
  — 226/226 (no JS diff).
- `pytest backend/tests/ -q` — 166/166 (no backend diff).
- `npm run build` — rc=0, 2m32s; both BeeEmUu_0.14.3
  bundles built.

## Tier

**A** — pure additions to existing Rust modules, no
`transport/**` / `protocol/**` / `commands.rs` /
`.claude/**` touches. Self-merge on CI green per
CLAUDE.md rule 2.

## Cross-references

- The Story modal UI is `renderStory` in
  `src/js/main.js:2961`, the button at
  `src/index.html:513`.
- The Secure Snapshot Share wiring is
  `doSecureShare` in `src/js/main.js:1071`, invoking
  `anonymize_snapshot` (sync, in the SYNC_ALLOWLIST).
- The story knowledge base lives in
  `community/stories/{generic,n55}.toml`; tests load it
  via `story::load()`.

* fix(ci): handle stacked PRs in autonomous auto-merge job (#204)

* Initial plan

* fix(v0.14.4): handle stacked PR auto-merge in CI

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>

---------

Co-authored-by: ohgeeceee <ohgeeceee@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
ohgeeceee added a commit that referenced this pull request Jul 31, 2026
* docs(roadmap): audit v0.3.0 historical section — stale 🟢 Ready items moved to ✅ Done

Six items in the v0.3.0 'Real Car' historical section were
marked 🟢 Ready but have actually shipped:

| Item                  | Shipped in      | Reference                |
|-----------------------|-----------------|--------------------------|
| KWP2000 slow timeout  | v0.13.0 (PR #153) | commit fd9efc2          |
| ISO-TP multi-frame    | v0.14.x         | src-tauri/src/transport/isotp.rs (enforced by CLAUDE.md, refreshed in PR #198) |
| Dark/light theme      | v0.7.0 (PR #109) | commit afefc32           |
| Gauge theming         | v0.7.0 (PR #109) | commit afefc32           |
| Save/load workspace   | v0.7.0 (PR #109) | commit afefc32           |
| Export PNG/SVG charts | v0.11.0 (PR #136) | commit 7f92ccb          |

This is the same doc-rot pattern that PR #198 fixed in
CLAUDE.md: items the inventory still claims as 'Ready to land'
have actually shipped, but nobody re-tagged the historical
section afterward. Same 'data over invention' fix as the
CLAUDE.md refresh.

What changed:

- '⭐ Protocol & Transport' table — kept the four genuinely-🟡
  items (ENET/DoIP, BLE, WiFi, CAN-bus listener), removed the
  two stale 🟢 Ready items.
- 'UI / UX' table — kept the only genuinely-🟡 item (Mobile-
  responsive), removed the five stale 🟢 Ready items.
- New '✅ Protocol, Transport, UI/UX — historical (shipped)'
  table — pins the six shipped items with their PR references
  and code locations, following the v0.3.0 'Decode Functions'
  historical pattern that already exists just above.

What this PR does NOT change:

- No CHANGELOG.md edits (the shipped-PR references are in
  CHANGELOG.md already)
- No CLAUDE.md edits (the ISO-TP / keepalive / read_vin
  references there are already accurate post PR #198)
- No code edits
- No test edits (markdown only)

Verified locally (docs-only, no test diff expected):

- node --test src/js/**/*.test.js src/js/**/*.test.cjs: 226/226
- python -m pytest backend/tests/ -q: 166/166
- cd src-tauri && cargo test --lib --offline: 149/149
- npm run build: rc=0, both BeeEmUu_0.14.3 bundles built

Tier A docs-only per CLAUDE.md. Self-merge on CI green.

Cross-references:
- PR #198: 'docs: refresh CLAUDE.md hardware/timing invariants'
  (the same doc-rot sweep on CLAUDE.md)
- PR #183: 'docs(proposal): fix stale NOT YET IMPLEMENTED claims'
  (proposed similar fixes but never applied)

* feat(v0.14.4): story coverage — 52 unit tests for story.rs + anonymize.rs

Two user-facing Rust modules have shipped with **zero unit
tests** since the diagnostic-story + secure-snapshot-share
features landed:

- `src-tauri/src/story.rs` (350 LOC) — the Generate Story
  pipeline that powers the one-click mechanic narrative
  modal in `src/index.html:513` +
  `src/js/main.js:2961` (renderStory).
- `src-tauri/src/anonymize.rs` (113 LOC) — the VIN-stripping
  layer that powers the Secure Snapshot Share feature
  (`src/js/main.js:1071`).

Both are pure-Rust, deterministic, and snapshot-driven —
the right shape for unit tests with fixture-built
`SessionSnapshot` inputs. This PR adds 52 unit tests
covering:

**story.rs (32 tests):**
- `Severity::from_str` bucketing (critical / warning /
  unknown → info).
- `Severity` ordering (Critical > Warning > Info).
- `priority_for` severity → priority number.
- `parse_cost_range` parser: single value, tilde,
  hyphen, **en-dash** (the TOML files use en-dash —
  parser must normalise), whitespace, empty, garbage.
- `format_vehicle` for empty / VIN-only /
  mileage-only / decoded.
- `build_context` freeze-frame string assembly.
- Full `generate` pipeline:
  - empty snapshot → Info story with no findings.
  - unknown DTC → generic Info finding.
  - n55-specific DTC (2A82) → uses engine template.
  - generic DTC fallback when engine-specific missing.
  - severity = max of all findings (sorted critical-first).
  - recommendations sorted ascending by priority.
  - cost range sums across findings.
  - cost-max invariant: max >= min + 50.
  - DTC code case-insensitive lookup (TOML keys are
    uppercased on load).
  - summary text counts critical + warning correctly.
  - title uses manufacturer + VIN prefix.

**anonymize.rs (20 tests):**
- `hash_vin` properties: 16 hex chars, stable for same
  input, distinct for distinct inputs, case-sensitive
  (current behaviour pinned).
- `anonymize` pipeline:
  - VIN never leaks into the anonymized JSON.
  - VIN → fingerprint via hash_vin.
  - Missing VIN → "unknown" fingerprint.
  - engine_family preserved from suggested_profile.
  - engine_family defaults to "generic".
  - Modules / DTCs / freeze frames / ident all preserved.
  - Mileage (mileage_km) stripped (privacy).
  - Empty modules handled.
  - fault_count = None → 0 in the output.
  - recorded_at populated with "(UTC)" suffix.
  - live_data is always empty (current anonymizer
    strips it; pinning the decision).
- `export_json`:
  - No VIN leak in pretty JSON.
  - No mileage leak.
  - Pretty-printed (multi-line + indented).
  - Round-trips through serde.

## Verification

- `cd src-tauri && cargo test --lib --offline` — **201/201
  pass** (149 existing + 52 new).
- `cd src-tauri && cargo test --test async_commands
  --offline` — 1/1 (the CLAUDE.md invariant guard still
  green — no new sync commands).
- `node --test src/js/**/*.test.js src/js/**/*.test.cjs`
  — 226/226 (no JS diff).
- `pytest backend/tests/ -q` — 166/166 (no backend diff).
- `npm run build` — rc=0, 2m32s; both BeeEmUu_0.14.3
  bundles built.

## Tier

**A** — pure additions to existing Rust modules, no
`transport/**` / `protocol/**` / `commands.rs` /
`.claude/**` touches. Self-merge on CI green per
CLAUDE.md rule 2.

## Cross-references

- The Story modal UI is `renderStory` in
  `src/js/main.js:2961`, the button at
  `src/index.html:513`.
- The Secure Snapshot Share wiring is
  `doSecureShare` in `src/js/main.js:1071`, invoking
  `anonymize_snapshot` (sync, in the SYNC_ALLOWLIST).
- The story knowledge base lives in
  `community/stories/{generic,n55}.toml`; tests load it
  via `story::load()`.

* fix(ci): handle stacked PRs in autonomous auto-merge job (#204)

* Initial plan

* fix(v0.14.4): handle stacked PR auto-merge in CI

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>

* Initial plan (#206)

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: ohgeecee <ohjoncurrie@gmail.com>

---------

Co-authored-by: ohgeeceee <ohgeeceee@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
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