From 46e5271c98154cd2c3ae1d5714a08a4b97e5cfad Mon Sep 17 00:00:00 2001 From: Pierre Date: Sun, 12 Jul 2026 23:13:37 +0200 Subject: [PATCH] feat: add safe sprint rollback workflows --- .../components/sprints/SprintActionMenu.tsx | 17 + .../src/v2/components/sprints/SprintCell.tsx | 20 +- .../v2/components/sprints/SprintLedger.tsx | 3 + .../v2/components/sprints/SprintLedgerRow.tsx | 17 +- .../sprints/SprintRollbackModal.tsx | 162 ++++++++ .../__tests__/SprintCell.visual.test.tsx | 26 ++ .../SprintLedger.accessibility.test.tsx | 5 + .../__tests__/SprintRollbackModal.test.tsx | 100 +++++ dashboard/src/v2/lib/project-api.ts | 24 ++ .../src/v2/pages/sprints/SprintsPage.tsx | 15 +- dashboard/src/v2/types.ts | 10 +- .../docs/architecture-sprint-rollbacks.mdx | 22 ++ docs-web/content/docs/registry.ts | 9 + .../content/docs/user-dashboard-sprints.mdx | 11 + docs/SUMMARY.md | 1 + docs/architecture/sprint-rollbacks.md | 71 ++++ docs/architecture/system-overview.md | 1 + docs/dashboard/design-system-sprints.md | 2 + docs/index.md | 4 +- docs/sprint-loop/atomic-loop.md | 6 + src/app/dependency-factory.ts | 1 + .../dependency-factory/dashboard-factory.ts | 13 + .../lifecycle/dashboard-lifecycle-service.ts | 4 + src/cli/management-cli.ts | 1 + src/contracts/project-management-types.ts | 33 ++ .../composer/pr-description-composer.ts | 13 +- .../composer/sprint-pr-input-builder.ts | 2 + .../rollback-finalization-policy.ts | 16 + .../sprint/orchestrator/watch-loop-runner.ts | 33 +- src/repositories/db/app-db-migrations.ts | 6 + src/repositories/db/app-db-schema.ts | 5 + .../project-management-repository.ts | 36 +- .../sprint-summary-query.ts | 5 + src/server/code-ux-server.ts | 4 + src/server/dashboard-server.ts | 5 + src/server/sprint-routes.ts | 31 ++ src/services/sprint-rollback-service.ts | 369 ++++++++++++++++++ .../composer/pr-description-composer.test.ts | 14 + .../rollback-finalization-policy.test.ts | 30 ++ .../repositories/db/app-db-schema.test.ts | 8 + .../project-management-repository.test.ts | 32 ++ .../server/sprint-rollback-routes.test.ts | 67 ++++ .../services/sprint-rollback-service.test.ts | 151 +++++++ 43 files changed, 1381 insertions(+), 24 deletions(-) create mode 100644 dashboard/src/v2/components/sprints/SprintRollbackModal.tsx create mode 100644 dashboard/src/v2/components/sprints/__tests__/SprintRollbackModal.test.tsx create mode 100644 docs-web/content/docs/architecture-sprint-rollbacks.mdx create mode 100644 docs/architecture/sprint-rollbacks.md create mode 100644 src/domain/sprint/orchestrator/rollback-finalization-policy.ts create mode 100644 src/services/sprint-rollback-service.ts create mode 100644 tests/backend/domain/sprint/orchestrator/rollback-finalization-policy.test.ts create mode 100644 tests/backend/server/sprint-rollback-routes.test.ts create mode 100644 tests/backend/services/sprint-rollback-service.test.ts diff --git a/dashboard/src/v2/components/sprints/SprintActionMenu.tsx b/dashboard/src/v2/components/sprints/SprintActionMenu.tsx index d3df8ad8a2..bd9a3b8e11 100644 --- a/dashboard/src/v2/components/sprints/SprintActionMenu.tsx +++ b/dashboard/src/v2/components/sprints/SprintActionMenu.tsx @@ -10,6 +10,7 @@ import { Pause, Pencil, Play, + RotateCcw, Sparkles, Square, XCircle, @@ -38,6 +39,7 @@ export interface SprintActionMenuProps { onToggleShowcase?: () => void; onOverrides?: () => void; onMarkCompleted?: () => void; + onRollback?: () => void; onDelete?: () => void; onClose?: () => void; markCompletedIcon?: "square" | "circle"; @@ -68,6 +70,7 @@ export const SprintActionMenu: FunctionComponent = ({ onToggleShowcase, onOverrides, onMarkCompleted, + onRollback, onDelete, onClose, markCompletedIcon = "circle", @@ -301,6 +304,20 @@ export const SprintActionMenu: FunctionComponent = ({ Mark Completed )} + {isCompleted && sprint.kind !== "rollback" && onRollback && ( + + )} + + + +
+ {!assessment && !error && ( +
+ + Inspecting merge history and later sprint work… +
+ )} + + {assessment && ( +
+
+ {assessment.eligible && assessment.recommendedMode === "automatic" ? : } + {assessment.eligible + ? assessment.recommendedMode === "automatic" ? "Safe automatic rollback available" : "Agent-assisted rollback required" + : "Rollback is not available"} +
+
    + {assessment.reasons.map((reason) =>
  • • {reason}
  • )} +
+
+ )} + +