Half of parked #92, and the half that has to be right. No page, no button: the ability to compute and land a revert as a branch, exercised by a test that does not need git push over HTTP.
Why this is split. #92 was tried once (pull #156, closed) and parked. The work was written — action, plumbing, a migration, a route and the studio button, all in one run — and then none of it could be run: the builder reported that git push over the smart-HTTP remote fails in the crew sandbox with auth required, which also stops the pre-existing, unmodified test/pulls.test.ts. A change nobody can test is a change nobody can land. So: the revert first, tested the way the tests that do run in the sandbox are written, and the studio's verb on top of it (the issue that follows this one).
That branch still exists — scout/92-take-it-back-undo-a-shipped-change-from — and is worth reading before starting: src/git/revert.ts, src/actions/revert.ts, and the reverts_issue_id column it added. Take what is good; do not assume it is correct, since it never ran.
Done looks like
[ ] revertPull(app, user, repo, pull) (a small src/actions/revert.ts, with the git in src/git/revert.ts) turns a merged change into a branch whose tip undoes exactly that merge, and opens a change for it through the existing openPull action, titled so it says what it undoes and linking the change it reverts.
[ ] main is never written: the default branch is untouched until a person merges the new change.
[ ] A revert that does not apply cleanly reports the conflict and writes nothing — no branch left behind, no pull half-opened. If the branch is created before the pull, a failure to open the pull rolls the branch back.
[ ] The forge squashes (shipSubmit merges with "squash"), so a squash is the case that must work; a true merge commit is either handled with its mainline parent or refused with an honest word, decided deliberately and said in the pull.
[ ] Reverting a change that already has a standing revert is refused with an honest word rather than computing a second inverse.
[ ] Write access is checked in the action, the git is plumbing only — no user text on a command line — and the branch name is derived by the server.
[ ] Tests run in the crew's sandbox. No git clone/git push over HTTP in the new test: build the commits against the bare repository under app.reposRoot the way test/crew.test.ts and test/edits.test.ts do, or through the commitToBranch/openPull/mergePull actions directly.
[ ] A test fails on today's code: ship a change, revert it, assert the new change's tip restores the file's earlier content and that main is unchanged until the revert is merged; plus the conflict case and the already-reverted case.
[ ] The repository's own check command passes locally before pushing.
Files I expect to change
src/actions/revert.ts (new), src/git/revert.ts (new), whatever column or link records that a change reverts another, a migration for it, test/revert.test.ts (new).
Risks
A schema migration is the one irreversible thing here — if a column is genuinely needed, it is one migration, additive, and nothing else in this issue depends on the number it gets. The same-commit-twice case and the conflict case are where a revert quietly corrupts a branch; both are acceptance lines above. Nothing in this issue renders anything: no revert is computed while a page is drawn.
Half of parked #92, and the half that has to be right. No page, no button: the ability to compute and land a revert as a branch, exercised by a test that does not need
git pushover HTTP.Why this is split. #92 was tried once (pull #156, closed) and parked. The work was written — action, plumbing, a migration, a route and the studio button, all in one run — and then none of it could be run: the builder reported that
git pushover the smart-HTTP remote fails in the crew sandbox withauth required, which also stops the pre-existing, unmodifiedtest/pulls.test.ts. A change nobody can test is a change nobody can land. So: the revert first, tested the way the tests that do run in the sandbox are written, and the studio's verb on top of it (the issue that follows this one).That branch still exists —
scout/92-take-it-back-undo-a-shipped-change-from— and is worth reading before starting:src/git/revert.ts,src/actions/revert.ts, and thereverts_issue_idcolumn it added. Take what is good; do not assume it is correct, since it never ran.Done looks like
revertPull(app, user, repo, pull)(a smallsrc/actions/revert.ts, with the git insrc/git/revert.ts) turns a merged change into a branch whose tip undoes exactly that merge, and opens a change for it through the existingopenPullaction, titled so it says what it undoes and linking the change it reverts.mainis never written: the default branch is untouched until a person merges the new change.shipSubmitmerges with"squash"), so a squash is the case that must work; a true merge commit is either handled with its mainline parent or refused with an honest word, decided deliberately and said in the pull.git clone/git pushover HTTP in the new test: build the commits against the bare repository underapp.reposRootthe waytest/crew.test.tsandtest/edits.test.tsdo, or through thecommitToBranch/openPull/mergePullactions directly.mainis unchanged until the revert is merged; plus the conflict case and the already-reverted case.checkcommand passes locally before pushing.Files I expect to change
src/actions/revert.ts(new),src/git/revert.ts(new), whatever column or link records that a change reverts another, a migration for it,test/revert.test.ts(new).Risks
A schema migration is the one irreversible thing here — if a column is genuinely needed, it is one migration, additive, and nothing else in this issue depends on the number it gets. The same-commit-twice case and the conflict case are where a revert quietly corrupts a branch; both are acceptance lines above. Nothing in this issue renders anything: no revert is computed while a page is drawn.
Suggested: Torque.