Treat an applied patch as a named layer, not an undo blob - #318
Conversation
e1c9daf to
8e44701
Compare
|
Rebased onto #313 and retargeted at its branch. Both changes add to The combination needed a decision rather than a mechanical merge, so it is stated here: a failed revert is asked about first, ahead of the pull-request framing. A revert only fails because the contributor's own edits are on the layer's lines, so "this pull request is behind trunk" is never the right sentence for it. The non-revert path keeps #313's Suite on the combined branches: 984 pass, 0 fail; lint clean. |
8e44701 to
ecc03b2
Compare
|
Rebased into the stack: #313 → #317 → #318. All three rewrite the same two places — Two combinations needed a decision rather than a mechanical merge, and both are in the last commit:
Suite on the stacked branches: 999 pass, 0 fail; lint clean. |
ecc03b2 to
4a72c54
Compare
|
Final integration review found one ownership mismatch: a second PR failure could call a file the contributor's even when its only known provenance was the previously applied layer. Fixed in d90eb07 by carrying that layer into the failure framing; the regression names the first PR and preserves uncertainty. Full branch suite: 980 passing. |
|
A further final-review pass found two truthfulness issues and both are fixed in 90d2bad: all-applied changes are now described as already in the checkout when ticket/layer provenance makes trunk unprovable, and a stale Revert record is cleared through writeWorkMeta so the active branch actually loses the banner/slot. Regressions cover both; Node and Electron suites pass. |
A ticket is a branch (#108): trunk, at most one applied patch or pull request, and the contributor's own edits. The branch holds that faithfully; the app's bookkeeping did not. `appliedPatch` was remembered only as something to undo, so everything the UI said about the ticket was read off the bare diff — and every file the applied pull request brought was announced as the contributor's own writing. Attribution. The record already stores which paths the patch touched, so the pre-apply warning now names two owners instead of one: a file the layer brought and nobody has edited over is described as coming from it, and a file the contributor has also worked on keeps naming their work, which is the answer that decides what they do next. Neither is dropped from the warning. The same split reaches the failure narration: a revert that will not come back out is the contributor's own edits sitting on lines they applied, never a pull request its author should rebase. Absorption. `revertable` used to mean "we stored the text". It now means what the banner actually asks — can this layer still be lifted out of this checkout, right now — measured by `diagnoseRemoval`, which reverses the stored patch through the same `resolveFile`/`diagnoseHunks` machinery the apply path uses and writes nothing. Once the contributor's edits are on the patch's own lines it is absorbed: Revert stands down, and the honest exits are saving a copy of the work and discarding the ticket to its base, which on this project is a normal way forward rather than a defeat. Nothing persists an "absorbed" flag, so undoing the overlapping edit brings Revert back on its own — and absorption never frees the one-patch slot, because the record survives as provenance. The banner's decision lives in `src/renderer/applied-layer.cjs`, unit tested directly; the patch text still never crosses IPC. Fixes #306 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
90d2bad to
4fe4d87
Compare
## Why After a contributor chooses **Discard this ticket to its base** from a failed Revert, the discard succeeds but the old red patch error remains on screen. The checkout is clean, yet the interface still claims the operation failed. The original #325 belonged to the stale stack that GitHub closed while #324 was being recovered, so this PR lands the already approved fix directly on `trunk`. ## What changes After a successful discard, clear the stale apply error and related preview state. If discard fails, retain all of that state so the contributor can still understand and recover from the failure. ## How to test this **Platforms:** macOS and Windows. **Starting state:** ticket #65819 linked, PR #13017 applied, with this contributor edit on an applied line in `tests/phpunit/tests/customize/widgets.php`: ```php $this->assertIsCallable( $args['sanitize_callback'], 'sanitize_callback is callable' ); // Mi cambio. ``` 1. Click **Revert this patch**. Revert must be rejected, the checkout must remain unchanged, and the red error must offer **Save a copy of your work** and **Discard this ticket to its base**. 2. Click **Discard this ticket to its base**. 3. The applied PR, contributor edit, applied-layer card, and red error must all disappear. Ticket #65819 must remain linked. **What must not have happened:** - A failed discard must not clear the error or preview state. - The ticket itself must not be unlinked. - No unrelated ticket work may be removed. This flow passed in the approved integration artifact at commit `012d7df` on macOS and Windows. ## Risks and limitations The final Git tree is exactly the tree manually approved for the release candidate. Self-review: 0 [fix here] · 0 [follow-up]. ## Related Replacement landing for #325. Follow-up to #318 and #330. --- <details> <summary>Design decisions and alternatives considered</summary> The cleanup is derived in the existing pure reducer and only committed after `outcome.ok`. Keeping failure state unchanged avoids hiding recovery information after an unsuccessful destructive operation. A standalone PR avoids reusing the closed stack topology that caused #324 not to land on `trunk`. </details> <details> <summary>Review outcome (required — see AGENTS.md)</summary> 0 [fix here] · 0 [follow-up]. Lint, 1010/1010 tests, and `git diff --check` pass. The branch resolves to approved tree `d3904782d5e434df8591e99d3ccf2a49a52ebcc9`. </details> <details> <summary>Implementation notes</summary> Recovery head before squash: `6a88a26`. It contains one commit directly on #330's squash commit. </details> <details> <summary>Screenshots or recording</summary> The user-visible flow was manually validated on both target platforms in the approved integration artifact. </details>
Why
An applied PR remains part of a ticket’s work, but the app described every touched file as the contributor’s own and a failed Revert could blame the PR author. That attribution is misleading and makes the safe exit hard to find.
What changes
The applied patch is retained as a named layer:
Routine
site:statusno longer reads and diffs patch files synchronously. The proactive “absorbed” classifier/state and categorical “not by you” copy have been removed.How to test this
Platforms: any.
Expected: its named banner appears with Revert this patch.
Expected: the warning says the file includes changes from the applied PR and may also contain your edits; it never says “not by you”.
Expected: Revert fails without touching anything and explains the overlap, offering save-a-copy/discard rather than asking the author for a rebase.
Expected: it succeeds and clears the named layer.
What must not have happened: routine refreshes must not synchronously scan patch files; a failed Revert must not partially edit the tree or free the one-patch slot.
Risks and limitations
The banner does not predict whether a retained patch is still reversible; it answers only when the user requests Revert. This keeps routine main-process status reads cheap and keeps error details attached to the action they explain.
The desktop flow remains to be driven from the integration artifact.
Related
Fixes #306. Part of #309. Builds on #317 and sharpens #313.
Design decisions and alternatives considered
The previous version diagnosed every applied layer during
site:status, adding synchronous file reads and an “absorbed” state. The simplified version uses the reverse apply operation as the diagnostic only when Revert is pressed.Review outcome
2 [fix here] — both fixed: synchronous status-path diagnosis was removed, and same-file ownership now preserves uncertainty. Lint is clean and the branch’s full suite passes 979 tests.
Implementation notes
The simplification removed 310 net lines from the reviewed version. Patch text remains in the main process and never crosses IPC.
Screenshots or recording
No new layout. The existing applied-layer and failure banners render the revised copy/actions.