Skip to content

v0.101.1 — history diffs a power, not the powers

Shipped 2026-09-20 — built on version/0.101.1, squash-merged to main; the merge hash and tag are in the changelog. A follow-up to v0.101.0 from first use of the History panel.

Adding or deleting one power listed the whole powers array — every power, every field of each — as the change. Three fixes:

  • Every element of a character's sub-collections gets an id. The server stamps a UUID id on each skill, feat, power, attack and attribute that lacks one, on the element's first write (assignCollectionIds, run by the same normalizeCollectionSlugs every character write path already goes through); the zod schemas and the shared types declare it, so zod no longer strips it. Nothing is migrated: an element written before ids existed is stamped the next time its character is saved.
  • The diff engine diffs a keyed array element by element. A JSON column whose elements carry id / slug / name (powers, feats, skills, attacks, attributes, actions, origins, classLevels, artworks) is matched element to element — by id, else slug, else name — and produces row.powers[<key>] for a power added or removed and row.powers[<key>].<field> for a field of one that changed; the summary reads "1 power added, 2 powers changed". The stamp itself (an id or slug appearing on an element that had none) is not a change, so the first save after this release does not list every power as changed. An empty or absent side pairs with a keyed one; an unkeyed array is still one change.
  • The panel and blame follow. The diff view renders each element's changes as an item of its column's section — Blink (power) added, Zap (power) changed with only the changed fields — named from the snapshot; a sheet section's blame hint resolves through its elements' prefixes (row.powers[, row.skills[ …) to the commit that last touched one of its traits.