diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index cd46ed72..164b4e67 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -36,6 +36,10 @@ function AppContent() {
+ {/* Portal lives inside LicenseProvider so DeployFeedbackModal can
+ call useLicense() (M-3 atomic-deploy notice depends on isPaid).
+ Outer DeployFeedbackProvider is still an ancestor through App. */}
+
);
@@ -46,7 +50,6 @@ function App() {
-
diff --git a/frontend/src/components/DeployFeedbackModal.tsx b/frontend/src/components/DeployFeedbackModal.tsx
index e5b45dad..d9f1d6bb 100644
--- a/frontend/src/components/DeployFeedbackModal.tsx
+++ b/frontend/src/components/DeployFeedbackModal.tsx
@@ -13,6 +13,7 @@ import { Button } from '@/components/ui/button';
import { StructuredLogRow } from '@/components/log-rendering/StructuredLogRow';
import TerminalComponent from '@/components/Terminal';
import { useDeployFeedback, VERB_LABELS } from '@/context/DeployFeedbackContext';
+import { useLicense } from '@/context/LicenseContext';
const AUTO_CLOSE_SECONDS = 4;
@@ -32,6 +33,7 @@ function formatElapsed(seconds: number): string {
export function DeployFeedbackModal({ isMinimized, onMinimize }: DeployFeedbackModalProps) {
const { panelState, logRows, onTerminalReady, onMessage, onPanelClose } = useDeployFeedback();
+ const { isPaid } = useLicense();
const [showRaw, setShowRaw] = useState(false);
const [elapsedSeconds, setElapsedSeconds] = useState(0);
@@ -213,6 +215,16 @@ export function DeployFeedbackModal({ isMinimized, onMinimize }: DeployFeedbackM
+ {/* Atomic-deploy notice for Community: deploys without auto-rollback. */}
+ {!isPaid && (action === 'deploy' || action === 'update') && (
+
+ Auto-rollback on failure is a Skipper feature.
+
+ )}
+
{/* Body */}