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
idon each skill, feat, power, attack and attribute that lacks one, on the element's first write (assignCollectionIds, run by the samenormalizeCollectionSlugsevery 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 producesrow.powers[<key>]for a power added or removed androw.powers[<key>].<field>for a field of one that changed; the summary reads "1 power added, 2 powers changed". The stamp itself (anidorslugappearing 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.