fix: scope file browser pane identity to familiar and path #38
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "t3/fix-filepane-familiar-identity"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Switching familiars at the same file path could reuse the previous familiar's draft and version, allowing Save to overwrite the destination file with that draft. Scope file-browser pane identity to familiar and path, enforcing ADRs 0013, 0015 and 0017.
What's in
Tests
Browser-verified
Used the isolated seeded world and local OpenRouter stub. Copied Niko's /notes/tracking.md to Rotom, entered an unsaved Niko draft, and followed an internal link to Rotom's same path. Rotom opened clean; its edit persisted after reload while Niko remained unchanged. Folder-name drafts also stayed isolated; no browser errors were observed.
No schema, seed, ADR, or submodule changes. Independent full-suite and browser repetitions were skipped because the additional reviewer found no new concern; the implementer completed both.
Summary
Summary
Coverage
Shikigami.BlazorAdapter - 95.6%
Shikigami.Capabilities.Contracts - 97.8%
Shikigami.Capabilities.TestFixture - 97.7%
Shikigami.Domain - 98.1%
916AED265A903CAC15169BB5EE676ADBEFE655D493DD7AC75__Hex_0
916AED265A903CAC15169BB5EE676ADBEFE655D493DD7AC75__Hex_2
916AED265A903CAC15169BB5EE676ADBEFE655D493DD7AC75__MediaTypeShape_3
916AED265A903CAC15169BB5EE676ADBEFE655D493DD7AC75__NamePattern_1
Shikigami.Infrastructure - 97.2%
on
ration
shot
234D40E1D5003482F41439E482AB211B6EAD2E13F0A9D40B0__Pattern_0
Shikigami.Kernel - 90.9%
Shikigami.Server - 100%
Shikigami.UseCases - 95.7%
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__AssignmentHead_12
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__BraceExpansion_11
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__HexColour_6
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__IdPattern_0
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__Interval_3
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__IntervalBody_10
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__NameRule_5
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__NewerXY_8
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__Number_7
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__OldCount_9
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__TimeOfDay_2
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__ToolPattern_1
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__Window_4
🔮 fufu~ Jibril reviewed your code!
Oh? Oh! A two-line fix that closes a silent data-loss hole — this is exactly my favorite kind of PR~ ♡ The bug was deliciously dangerous: versions are drawn from one counter per familiar (ADR 0017, amended 2026-10-17), so familiar A's
_versioncan numerically equal familiar B's current version. With the pane keyed by path alone, switching familiars kept A's_text/_version/_dirtywhileFamiliarIdbecame B's — and Save would dispatchSaveText(B, path, A's version, A's draft). If the counters lined up, that passes theWHERE version = @expectedcheck and overwrites B's file with A's draft. No error, no conflict banner. Fufu… nothing makes my wings shiver like a correct-looking write that destroys data~Verdict: ✅ Looks good to me~
Scoping both pane identities to
(Id, open.Item.Path)is the right and minimal fix:_text,_version,_dirty,_stale,_sent,_renaming,_formFirst) is draft state that must die with the page that owns it; recreation on familiar/path change gives that for free, andDisposeAsyncCore'sFilePaneClosedcarries the old familiar, which the reducers correctly ignore onceFilesState.FamiliarIdhas moved on._newNameand the rename draft leaked across familiars and paths. Keying it closes the second half of the hole.Sync()'s clean-adopt / dirty-mark logic (ADR 0017) keeps working. The addedAssert.Samechecks pin exactly this.FilesStatelayer was already fully familiar-guarded in every reducer — the component identity was the only remaining leak, and it's now sealed. Consistent with every sibling@keyusage in the codebase.✅ What I liked~
The_same_path_in_another_familiar_opens_its_own_editorsweeping clean × dirty against destination-version lower/equal/higher — that equal case is where the silent overwrite lived, and you pinned it down and then asserted the subsequent save writes only the destination. Wonderful~ ♪Folder_action_drafts_belong_to_the_familiar_and_pathcovering both leak directions (other familiar, other path) in one theory.No blocking findings. No suggestions either — anything I'd add would be decoration on a fix that's already exactly the right shape. ♡
Automated review by Jibril · 2026-10-22
CI: green for head SHA
4d1f24b0· Mutation probes: 3 run, 0 survived (FilePane key de-scoped to path → 6/6 identity cases fail; FolderPane key removed → 2/2 draft cases fail; version added to FilePane key →Assert.Samerefresh guard fails) · Local suite: skipped (CI green)