Skip to content

[claude] Focus activity diffs on what changed - #2883

Closed
myieye wants to merge 29 commits into
developfrom
claude/activity-5-focused-diff
Closed

myieye wants to merge 29 commits into
developfrom
claude/activity-5-focused-diff

Conversation

@myieye

@myieye myieye commented Oct 31, 2026 •

Copy link
Copy Markdown
Collaborator

[Claude, autonomous]

Stacked on #2882. The activity change preview now shows what a change did, not the whole entity: only the changed fields, under an anchor line that says which entry, sense or example it is. Unchanged fields sit behind a per-change "Show N unchanged fields" toggle.

What each change type shows (activity preview, mode="changes")

Change Shows
Entry edit Anchor: best headword as an inline before → after diff, plus the homograph number as a subscript (a 0 → 1 change shows the added ₁ highlighted). Then the changed fields only (morph type still appears only when it changed).
Sense edit Anchor: best gloss (view's analysis WSs first), or the definition when neither side has a gloss. Then the changed fields.
Example edit Anchor: best sentence (view's vernacular WSs first). Then the changed fields.
Create / delete Every non-empty field. Nothing counts as unchanged, so there's no toggle.
Nothing visible changed (formatting-only rich text, id/deletedAt-style fields) Anchor, a muted "No visible changes" line styled like "Preview not available", and the full entity.
Objects (part of speech, writing system, custom view, ...) Unchanged (see deviations).
  • "Show N unchanged fields" / "Hide unchanged fields" is a button with aria-expanded (DiffCollapsed.svelte). It uses $plural the way the repo does, and it's hidden when N is 0. Its state lives in each primitive instance, so each change in a commit collapses on its own. It isn't persisted, and a change scrolled out of the virtual list resets.
  • The primitives take mode: 'changes' | 'full' and default to 'full'. Existing callers render the same fields as before, plus the anchor, which always shows, as the spec asked.
  • changedFieldIds(fields, before, after, compareAs) sits next to showChangedFields in changed-fields.ts and reuses valueChanged. showChangedFields is now built on it. A small changesOnly helper narrows the fields and counts the hidden ones.
Desktop Expanded Phone (390px)
changes only expanded phone

Deviations from the spec, and why

  • N counts only unchanged fields that have a value. Unchanged empty fields aren't counted, because revealing them shows nothing. That's also what makes creates and deletes come out with N = 0, as the spec expected.
  • "No visible changes" only applies to edits. A create or delete is a visible change even when every field is empty, so an empty create shows its full (empty) form without the note. In 'full' mode the note never shows, so the existing behaviour stays the same.
  • No sense number in the sense anchor. The sense snapshot doesn't carry its position. The only source is the current entry's sense order, which can disagree with the order when the change was made. That isn't cheap and could mislead.
  • DiffFieldRows (objects) has no 'changes' mode. Filtering the rows would be trivial. But without an anchor, a writing-system font change would show only "Font", with nothing saying which writing system it was. Adding anchors per object type goes beyond the trivial case, so I left it for a follow-up.
  • The anchor uses viewBestHeadword, the same headword lists show. When a citation form exists it wins, so a lexeme-form edit can leave the anchor unchanged (visible in the first story).
  • An empty grid is hidden. When no field is left to show (e.g. a homograph-only change), the empty sub-grid is hidden so its gap doesn't leave a blank band.

Homograph numbers in DiffAnchor.svelte now use the shared HomographNumber component from #2881 (now in this stack), wrapped in the diff colouring.

Test plan

  • changed-fields.test.ts: new cases for changedFieldIds (shown and hidden fields, formatting-only edits, compareAs, create/delete) and changesOnly (hiding fields and counting only those with a value).
  • diff-field-coverage.test.ts: every IEntry / ISense / IExampleSentence key is either diffed (a view field, or morphType / homographNumber shown outside the view) or in an explicit not-visible list. A new backend field fails until someone decides.
  • svelte-check, eslint, vitest unit project (261 passed), i18n extract stable (translator comments added for the 3 new msgids).
  • Playwright entry-edit-persists and entries-list, chromium: 17 passed. The demo has no activity data, so no UI test covers the preview itself.
  • Storybook editor/diff/entities: the new "Changes only" story and the existing full story, checked with Playwright at 1100px and 390px. No horizontal scroll; toggling one change leaves the others collapsed; aria-expanded flips.
  • Manual: open Activity in FW Lite on a project with edits, creates, deletes and a formatting-only edit.

Generated by Claude Code

myieye and others added 25 commits October 26, 2026 11:18
Diff counterparts of the editor's entry, sense and example primitives, plus
a row-based diff for objects without an editor layout (parts of speech,
semantic domains, publications, complex form types, morph types, writing
systems, custom views). Nothing renders them yet; the activity detail view
adopts them next.

Every field of every previewed model is listed in diff-fields.ts, typed
against the generated models, so a new backend field fails svelte-check
until it gets a row or is skipped on purpose. Entry fields the editor
doesn't show (morph type, homograph number) are diffed when they change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- A multi-string change in a writing system the view hides now shows
  instead of looking unchanged.
- Part of speech diffs by id, so a snapshot with an id but no object
  still shows the right value.
- Multi-selects drop duplicate ids (they crashed the keyed each) and sort
  labels numerically, so semantic domain 2.1 comes before 10.1.
- Guard missing example translations and string-serialized ws types.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A custom view with no writing-system list shows every writing system, so
diffing it as an empty list hid a switch between "all" and "none". A
reorder-only picture change now marks the pictures that moved.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A custom view's field order and an entry's complex form types keep their
selection order, so a reorder-only change looked unchanged. Pictures and
multi-selects now share one helper for finding what moved.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…eme form

entityConfig is now typed against the generated models: a new entry, sense
or example field fails svelte-check until it gets an editor field or is
listed as not having one. That replaces the diff's near-empty "extra rows"
tables, which guarded the same thing one step removed.

Morph type, which has no editor field yet, shows in the entry diff right
under the lexeme form when it changed, where FLEx has it. Homograph number
is left out: FW Lite doesn't display it anywhere yet.

A test checks every snapshot-able model has a diff or an explicit opt-out.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Like hidden writing systems, a field the current view hides (e.g. literal
meaning in FW Lite) now shows when the change touched it, so an activity
that only edited such a field doesn't render an empty diff. Empty values
count as missing and rich text compares as plain text.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AM78WFRziqVfs4zYnscP7E
A renamed but still selected publication, complex form type or semantic
domain no longer reveals a hidden field that would show nothing changed.
Selections compare by id, pictures by image and caption, and
translations by id and text.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AM78WFRziqVfs4zYnscP7E
DiffMultiString gave each row its own label column so the label stayed beside the value below the lg breakpoint, which left inputs misaligned between rows. Use the editor's row classes instead: the shared subgrid column from lg up, stacked below it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AM78WFRziqVfs4zYnscP7E
Render an entry's homograph number (N > 0) as a FLEx-style subscript after
its headword via a shared HomographNumber component: entry list and search
rows, dictionary preview, entry editor title, task review list, the entry
picker's selection preview and the activity preview. Plain-text contexts
(editor title tooltip, delete prompt, duplicate-check preview names) use
Unicode subscript digits. Headword strings used for logic are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AM78WBzrZB97vduoZFtHSr
LoadChangeContext returns PreviousSnapshot again. GetBeforeCommit and
GetAtCommit both resume from Harmony's nearest snapshot checkpoint,
which is kept at most MaxChangesBetweenSnapshotCheckpoints changes
apart, so a pruned snapshot now costs a short replay instead of one
from the entity's last persisted snapshot.

Tests cover edit, create (no before), delete (deleted after), a sense
edit, and a 10k-commit batch where the edited entity's snapshots are
pruned: content is right and no commit is a checkpoint interval or more
of changes from a checkpoint.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AM78WBzrZB97vduoZFtHSr
Entries, senses and examples render through the diff primitives, the
objects objectDiffRows knows through DiffFieldRows, and everything else
falls back to the old preview. No before snapshot reads as created, a
deleted after snapshot as deleted. The Current version switch still
shows the current entity in the read-only editor.

Intl.Segmenter is now created on first use, so the diff module loads
where it is missing (Firefox < 125) and diffs by code point there.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AM78WBzrZB97vduoZFtHSr
The activity preview now shows only the fields a change touched, under an
anchor line that names the entry, sense or example (headword with homograph
number, gloss, sentence). Unchanged fields collapse behind a per-change
"Show N unchanged fields" toggle, and a change with nothing visible says so
and shows the whole entity. Diff primitives default to the full view, so
other callers are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AM78WBzrZB97vduoZFtHSr
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AM78WBzrZB97vduoZFtHSr
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AM78WBzrZB97vduoZFtHSr
@coderabbitai

coderabbitai Bot commented Oct 31, 2026

Copy link
Copy Markdown
Contributor

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@github-actions github-actions Bot added the 💻 FW Lite issues related to the fw lite application, not miniLcm or crdt related label Oct 31, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AM78WBzrZB97vduoZFtHSr
@myieye
myieye added this pull request to stack #2887 October 31, 2026 10:27
Base automatically changed from claude/activity-4-diff-preview to develop October 31, 2026 14:36

myieye commented Oct 31, 2026

Copy link
Copy Markdown
Collaborator Author

[Claude, autonomous]

Combined into #2889 with #2885 and #2886.


Generated by Claude Code

@myieye myieye closed this Oct 31, 2026
myieye added a commit that referenced this pull request Nov 1, 2026
Activity diffs now narrow to what a change touched, each change gets one header, and a second tab compares the result of the change with the entity's current state.

- Load ChangeContext.CurrentSnapshot with GetLatest, so a deleted entity comes back with DeletedAt set instead of being guessed from the affected entry.
- Second tab reads Later changes, Deleted later (red label, Deleted badge, diffed against the last state before deletion) or No later changes (aria-disabled but still focusable).
- Collapsed diffs also hide unchanged writing systems; "Show unchanged fields" shows the whole form.
- Created or deleted entities show plain values with a green Added or red Deleted badge and an edge rule, not all-green or all-red text.
- A muted "Now called: <headword>" line shows when a later change renamed the entry.
- Fix the stray pink bar on homograph number changes and the n→m spacing.
- Compare picture captions as plain text.

Replaces #2883 and #2885. Homograph numbers on complex form links moved to #2890.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AM78WGasYNwZjGRQswP6JQ
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

💻 FW Lite issues related to the fw lite application, not miniLcm or crdt related

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants