Skip to content

fix(review): #1258 review findings, round 3 - #1272

Merged
SudoThijn merged 5 commits into
feature/1254-share-savefrom
review/pr-1258-fixes-r3
Oct 15, 2026
Merged

SudoThijn merged 5 commits into
feature/1254-share-savefrom
review/pr-1258-fixes-r3

Conversation

@rjzondervan

Copy link
Copy Markdown
Member

Fixes for the round-3 review of #1258 (#1258 (review)). Merge into feature/1254-share-save, then re-request the review; nothing here is merged by the reviewer.

Findings → commits

Finding Commit What changed
N1 🟡 A stale copy's 409 names a source version the conflict never showed ebdf3758 open() names the source's current version on a stale 409 only when it equals the copy's version, and the edit's own sourceBaseUpdatedAt otherwise; two ShareSaveServiceTest cases, one per branch
N1 (pre-push) 794089b6 user-sharing spec, plus the staleBody/staleRow/StaleWriteException docblocks, say which source version a stale copy's 409 names; new Scenario "A stale copy does not name a source that moved alone"
N1 (pre-push) 862ae320 offline-edit-queue spec: a copy written after its source can cost one more choice ("keep mine" first gets stale_source), which is safe and documented, not changed
N1 (pre-push) 2d2e8964 testAStaleCopyNamesTheSourceVersionItFound renamed to testAStaleCopyWhoseSourceStayedNamesTheSourceBase, the case it checks
N1 (pre-push) 78fad4a2 spec and docblocks say "equals the copy's", matching movedOn()'s !==

Left to the author (threads stay open)

  • None.

Checks run on this branch

  • phpunit -c phpunit-unit.xml --filter 'ShareSaveServiceTest|ShareSaveControllerTest|ShareServiceTest' (dev container, PHP 8.4) → OK, 130 tests, 352 assertions
  • The new testAStaleCopyDoesNotNameASourceVersionThatMovedAlone before the fix → red (-'2026-10-01T10:00:00+00:00' / +'2026-10-01T10:00:09+00:00')
  • Mutations of the new condition (flip it / always the base / always the current source) → each turns one of the two new tests red
  • npx vitest run tests/store/offlineQueue.spec.js tests/vitest/offline-snapshot.spec.js (node 24) → 32 passed, including the "keep mine" case
  • phpcs --standard=phpcs.xml on the touched lib/ files → 0 errors; phpmd and phpstan on ShareSaveService.php → clean
  • git grep -n "moved past" → empty
  • Pre-push adversarial check: three passes, the last with no findings
  • not run: the full PHPUnit suite and the hydra gates on this branch (CI runs both on this PR)

🤖 Generated with Claude Code

rjzondervan and others added 5 commits October 15, 2026 12:53
… conflict never showed

On the copy-editor path, open()'s `stale` refusal named the source's
current version even when the source had moved alone past the edit's
sourceBaseUpdatedAt. The client keeps that as conflictSourceUpdatedAt,
so "keep mine" passed both locks and overwrote a source change the user
never saw. The refusal now names the source's current version only when
the copy was written with it (the source has not moved past the copy's
updatedAt), and otherwise the edit's own sourceBaseUpdatedAt, so the
replay gets `stale_source` and the user chooses again.

Thread: #1258 (comment)

Class sweep: no other place names a source version that moved alone.
lockVersions() already names sourceBase; `stale_source` names the
source move that is its own conflict; `incomplete` and the write
context do not feed a conflict replay.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…opy's 409 names

The user-sharing spec promised both copy-editor 409s carry "the
source's version". A `stale` answer now names the source's current
version only when the copy was written with it, and otherwise the
edit's own sourceBaseUpdatedAt. The Requirement says so, a new
Scenario covers the source that moved alone, and the docblocks of
staleRow(), StaleWriteException and ShareSaveController::staleBody
that repeated the old promise now match.

Thread: #1258 (comment)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…n cost one more choice

The "Keeping mine after the copy moved" scenario promised the replay
saves when neither version moved again. When a copy-only write moved
the copy past the source, the stale 409 now names the edit's source
base, so "keep mine" can first meet a `stale_source` refusal. That is
safe; the scenario now states the extra choice.

Thread: #1258 (comment)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ase it checks

testAStaleCopyNamesTheSourceVersionItFound now runs through the
source-base branch: only the copy moved and the source stayed at the
edit's base. It is kept, apart from the source-moved-alone case, under
the name testAStaleCopyWhoseSourceStayedNamesTheSourceBase.

Thread: #1258 (comment)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nly when its version equals the copy's

movedOn() compares versions for equality, so a stale copy's 409 names
the source's current version only when the source's updatedAt equals
the copy's; a copy written after its source gets the edit's base. The
user-sharing Requirement said "has not moved past"; it and the
docblocks of staleRow() and StaleWriteException::getSourceUpdatedAt()
now say the versions are equal.

Thread: #1258 (comment)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@SudoThijn
SudoThijn merged commit 03898f9 into feature/1254-share-save Oct 15, 2026
2 checks passed
@SudoThijn
SudoThijn deleted the review/pr-1258-fixes-r3 branch October 15, 2026 12:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants