openpencil/crates
Kayshen-X baad7e12fb fix(variables): set_color_hex mirrors resolve's subset matching
Codex stop-gate caught a real correctness bug in the previous
commit (62653659): `set_color_hex` used EQUALITY to match themed
entries against `active_theme`, but `Variable::resolve` uses
SUBSET matching. The mismatch let writes report success without
actually changing the resolved value:

  Entry:  {theme: Some({"mode": "dark"}), value: "#111"}
  Active: {"mode": "dark", "density": "compact"}

  Before: equality check fails (entry's theme has fewer keys), so
  the write pushes a new entry at the end:
    {theme: Some({"mode": "dark", "density": "compact"}), value: NEW}
  resolve() walks first-to-last, picks the ORIGINAL entry (mode=
  dark is a subset of active), returns "#111" — the new entry is
  shadowed and never read.

Fix: `set_color_hex` now mirrors `resolve` exactly. Three-step
lookup matching the resolve walk order:

  1. First themed entry whose `theme` map is a subset of
     active_theme → write there.
  2. Else, the `theme: None` default entry → write there.
  3. Else, push a fresh entry keyed to active_theme (or None when
     active is empty).

The write is now guaranteed to flip the resolved value when it
returns true.

Tests (2 added — direct repros of the codex BLOCK, 287 shell-core
total):

  - `set_color_hex_changes_resolved_value_under_subset_active_theme`
    builds the exact pathological case (entry mode-only, active
    has mode+density), writes, then asserts `resolve_color`
    returns the NEW value. Pre-fix this test would have read the
    untouched "#111" and failed.

  - `set_color_hex_falls_back_to_default_entry_when_no_subset_match`
    covers the second branch — themed entry mismatch + `theme:
    None` default + active that matches neither. The write must
    update the default (which is what resolve falls back to) and
    not append a never-read dark entry.
2026-05-14 18:34:36 +08:00
..
anthropic-agent-sdk chore(crates): move vendored SDKs into workspace as forkable crates 2026-05-14 16:49:17 +08:00
copilot-sdk chore(crates): move vendored SDKs into workspace as forkable crates 2026-05-14 16:49:17 +08:00
openpencil-app feat(openpencil-app): skeleton crate (Stage F entry placeholder) 2026-05-03 22:05:00 +08:00
openpencil-desktop refactor(desktop): extract rotate-cursor builder into cursor_icon.rs 2026-05-14 17:38:16 +08:00
openpencil-shell-core fix(variables): set_color_hex mirrors resolve's subset matching 2026-05-14 18:34:36 +08:00
openpencil-shell-native fix(geometry): canvas_region shrinks for VariablesPanel too (codex BLOCK) 2026-05-14 17:57:55 +08:00
openpencil-shell-web feat(shell): export dialog + multi-format raster (PNG/JPEG/WEBP) + Property-panel preview 2026-05-14 14:02:52 +08:00
pen-codegen chore(workspace): cargo-deny 0.18 activation (Phase 1 Task 1.8 Step 6) 2026-05-03 23:05:00 +08:00
pen-core chore(workspace): cargo-deny 0.18 activation (Phase 1 Task 1.8 Step 6) 2026-05-03 23:05:00 +08:00
pen-engine chore(workspace): cargo-deny 0.18 activation (Phase 1 Task 1.8 Step 6) 2026-05-03 23:05:00 +08:00
pen-figma chore(workspace): cargo-deny 0.18 activation (Phase 1 Task 1.8 Step 6) 2026-05-03 23:05:00 +08:00
pen-types feat(pen-types): skeleton crate (bucket A) 2026-05-03 22:35:00 +08:00
wasm-libc-shim style(shell): cargo fmt --all (rustfmt-clean) 2026-05-10 18:47:33 +08:00
CLAUDE.md feat(shell): canonical .op loader + jian-core layout + visual fidelity pass 2026-05-14 09:26:08 +08:00