diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,38 @@
 # Changelog
 
+## 1.1.0.0 — 2026-07-13
+
+Major release: this set changes public record field types, renames a public constructor,
+removes an accidentally exposed module, and changes the `check` command syntax.
+
+### Breaking changes
+
+- Changed `ExecutionOptions` to represent absent lock and statement-timeout flags as
+  optional overrides. Applications constructing commands directly must wrap explicit
+  values in `Just`; `Nothing` now preserves `CliEnvironment` runner settings.
+- Renamed `ExitSuccess` to `ExitSucceeded`, avoiding its collision with
+  `System.Exit.ExitSuccess`.
+- Changed `check MANIFEST` to `check --manifest PATH`, matching `new --manifest`.
+- Stopped exposing the internal `PgMigrate.CLI.Prelude` module.
+- Added `CliInputError` to the public `CliError` sum for command-input failures.
+- Updated public report construction for the core package's new `cleanupIssues` fields and
+  mandatory-primary `CleanupFailed` shape.
+
+### Fixes and behavior changes
+
+- Added explicit `--wait` and `--no-statement-timeout` overrides; absent execution flags no
+  longer discard application-configured `RunOptions`.
+- Reject `new --description` values containing control characters before any file is
+  created, including for callers that construct `NewOptions` directly.
+- Classify manifest IO failures from `check` and `new` as execution failures while keeping
+  manifest validation failures as usage failures.
+- Reject unknown inspection filters for `plan`, `list`, `status`, and `verify`; filter
+  report issues as well as migration lists while retaining the full-report verification
+  exit class.
+- Share one checksum renderer between text and JSON output without changing rendered bytes.
+- Render successful migration and repair cleanup observations in text and as an additive
+  `cleanup_issues` array in JSON schema v1; history-import JSON exposes the same field.
+
 ## 1.0.0.0 — 2026-07-10
 
 - Initial stable release of the reusable command tree, typed dispatcher, text output,
diff --git a/pg-migrate-cli.cabal b/pg-migrate-cli.cabal
--- a/pg-migrate-cli.cabal
+++ b/pg-migrate-cli.cabal
@@ -1,6 +1,6 @@
 cabal-version:   3.8
 name:            pg-migrate-cli
-version:         1.0.0.0
+version:         1.1.0.0
 synopsis:        Reusable command parsers and renderers for pg-migrate
 category:        Database
 maintainer:      nadeem@gmail.com
@@ -29,10 +29,7 @@
 library
   import:          common
   hs-source-dirs:  src
-  exposed-modules:
-    Database.PostgreSQL.Migrate.CLI
-    PgMigrate.CLI.Prelude
-
+  exposed-modules: Database.PostgreSQL.Migrate.CLI
   other-modules:
     Database.PostgreSQL.Migrate.CLI.Handler
     Database.PostgreSQL.Migrate.CLI.Json
@@ -40,6 +37,7 @@
     Database.PostgreSQL.Migrate.CLI.Parser
     Database.PostgreSQL.Migrate.CLI.Text
     Database.PostgreSQL.Migrate.CLI.Types
+    PgMigrate.CLI.Prelude
 
   build-depends:
     , aeson                 >=2.2  && <2.3
@@ -48,8 +46,8 @@
     , containers            >=0.7  && <0.8
     , hasql                 >=1.10 && <1.11
     , optparse-applicative  >=0.19 && <0.20
-    , pg-migrate            >=1.0  && <1.1
-    , pg-migrate-embed      >=1.0  && <1.1
+    , pg-migrate            >=1.1  && <1.2
+    , pg-migrate-embed      >=1.1  && <1.2
     , text                  >=2.1  && <2.2
     , time                  >=1.12 && <1.15
 
diff --git a/src/Database/PostgreSQL/Migrate/CLI/Handler.hs b/src/Database/PostgreSQL/Migrate/CLI/Handler.hs
--- a/src/Database/PostgreSQL/Migrate/CLI/Handler.hs
+++ b/src/Database/PostgreSQL/Migrate/CLI/Handler.hs
@@ -18,6 +18,7 @@
     RunOptions,
     StatusReport (..),
     StoredMigration (..),
+    VerificationIssue (..),
     VerificationReport (..),
     connectionProviderFromSettings,
     migrationFingerprint,
@@ -33,6 +34,7 @@
 import Database.PostgreSQL.Migrate.CLI.Types
 import Database.PostgreSQL.Migrate.Embed
   ( AuthoringError (..),
+    ManifestError (..),
     checkMigrationManifest,
     newMigration,
     newMigrationOptions,
@@ -41,8 +43,10 @@
   ( ComponentDescription (..),
     MigrationDescription (..),
     PlanDescription (..),
+    componentNameText,
     migrationIdComponent,
     migrationIdName,
+    migrationNameText,
     planDescription,
   )
 import Hasql.Connection.Settings qualified as Settings
@@ -76,22 +80,19 @@
 runMigrationCommand environment commandValue =
   case commandValue of
     Plan PlanOptions {inspection} ->
-      pure
-        ( success
-            "plan"
-            (PlanPayload (filterPlan inspection (planDescription (migrationPlan environment))))
-        )
+      case validateInspection (migrationPlan environment) inspection of
+        Left inputError -> pure (failure "plan" ExitUsageFailed (CliInputError inputError))
+        Right description ->
+          pure (success "plan" (PlanPayload (filterPlan inspection description)))
     List ListOptions {inspection} ->
-      pure
-        ( success
-            "list"
-            ( ListPayload
-                ( filterMigrations
-                    inspection
-                    (flattenPlanDescription (planDescription (migrationPlan environment)))
-                )
+      case validateInspection (migrationPlan environment) inspection of
+        Left inputError -> pure (failure "list" ExitUsageFailed (CliInputError inputError))
+        Right description ->
+          pure
+            ( success
+                "list"
+                (ListPayload (filterMigrations inspection (flattenPlanDescription description)))
             )
-        )
     Check CheckOptions {manifestPath} -> runCheck manifestPath
     Status StatusOptions {inspection, connection} -> runStatus environment inspection connection
     Verify VerifyOptions {inspection, connection} -> runVerify environment inspection connection
@@ -105,7 +106,7 @@
 runCheck manifestPath = do
   checked <- checkMigrationManifest manifestPath
   pure $ case checked of
-    Left manifestError -> failure "check" ExitUsageFailed (CliManifestError manifestError)
+    Left manifestError -> failure "check" (manifestExitClass manifestError) (CliManifestError manifestError)
     Right entries ->
       success
         "check"
@@ -114,31 +115,37 @@
         )
 
 runStatus :: CliEnvironment -> InspectionOptions -> ConnectionOptions -> IO CliOutcome
-runStatus environment inspection connection = do
-  result <-
-    migrationStatusWith
-      (runnerOptions environment)
-      (selectProvider environment connection)
-      (migrationPlan environment)
-  pure $ case result of
-    Left migrationError -> failure "status" ExitExecutionFailed (CliMigrationError migrationError)
-    Right report -> success "status" (StatusPayload (filterStatus inspection report))
+runStatus environment inspection connection =
+  case validateInspection (migrationPlan environment) inspection of
+    Left inputError -> pure (failure "status" ExitUsageFailed (CliInputError inputError))
+    Right description -> do
+      result <-
+        migrationStatusWith
+          (runnerOptions environment)
+          (selectProvider environment connection)
+          (migrationPlan environment)
+      pure $ case result of
+        Left migrationError -> failure "status" ExitExecutionFailed (CliMigrationError migrationError)
+        Right report -> success "status" (StatusPayload (filterStatus description inspection report))
 
 runVerify :: CliEnvironment -> InspectionOptions -> ConnectionOptions -> IO CliOutcome
-runVerify environment inspection connection = do
-  result <-
-    verifyMigrationPlanWith
-      (runnerOptions environment)
-      (selectProvider environment connection)
-      (migrationPlan environment)
-  pure $ case result of
-    Left migrationError -> failure "verify" ExitExecutionFailed (CliMigrationError migrationError)
-    Right report ->
-      CliOutcome
-        { command = "verify",
-          exitClass = verificationExitClass report,
-          payload = Right (VerifyPayload (filterVerification inspection report))
-        }
+runVerify environment inspection connection =
+  case validateInspection (migrationPlan environment) inspection of
+    Left inputError -> pure (failure "verify" ExitUsageFailed (CliInputError inputError))
+    Right description -> do
+      result <-
+        verifyMigrationPlanWith
+          (runnerOptions environment)
+          (selectProvider environment connection)
+          (migrationPlan environment)
+      pure $ case result of
+        Left migrationError -> failure "verify" ExitExecutionFailed (CliMigrationError migrationError)
+        Right report ->
+          CliOutcome
+            { command = "verify",
+              exitClass = verificationExitClass report,
+              payload = Right (VerifyPayload (filterVerification description inspection report))
+            }
 
 runUp :: CliEnvironment -> ConnectionOptions -> ExecutionOptions -> IO CliOutcome
 runUp environment connection execution = do
@@ -177,17 +184,20 @@
 
 runNew :: FilePath -> Text -> Maybe FilePath -> IO CliOutcome
 runNew manifestPath description requestedName =
-  case newMigrationOptions manifestPath requestedName initialSql of
-    Left authoringError ->
-      pure (failure "new" ExitUsageFailed (CliAuthoringError authoringError))
-    Right options -> do
-      result <- newMigration options
-      pure $ case result of
+  case validateDescription description of
+    Left inputError -> pure (failure "new" ExitUsageFailed (CliInputError inputError))
+    Right validDescription ->
+      case newMigrationOptions manifestPath requestedName (initialSql validDescription) of
         Left authoringError ->
-          failure "new" (authoringExitClass authoringError) (CliAuthoringError authoringError)
-        Right path -> success "new" (NewPayload path)
+          pure (failure "new" ExitUsageFailed (CliAuthoringError authoringError))
+        Right options -> do
+          result <- newMigration options
+          pure $ case result of
+            Left authoringError ->
+              failure "new" (authoringExitClass authoringError) (CliAuthoringError authoringError)
+            Right path -> success "new" (NewPayload path)
   where
-    initialSql = Text.Encoding.encodeUtf8 ("-- " <> description <> "\n\n")
+    initialSql validDescription = Text.Encoding.encodeUtf8 ("-- " <> validDescription <> "\n\n")
 
 selectProvider :: CliEnvironment -> ConnectionOptions -> ConnectionProvider
 selectProvider CliEnvironment {defaultConnection} ConnectionOptions {databaseSettings} =
@@ -200,22 +210,30 @@
 
 applyExecution :: ExecutionOptions -> RunOptions -> RunOptions
 applyExecution ExecutionOptions {lockWait, statementTimeout} =
-  withStatementTimeout statementTimeout . withLockWait lockWait
+  maybe id withStatementTimeout statementTimeout
+    . maybe id withLockWait lockWait
 
 verificationExitClass :: VerificationReport -> ExitClass
 verificationExitClass VerificationReport {issues}
-  | null issues = ExitSuccess
+  | null issues = ExitSucceeded
   | otherwise = ExitVerificationFailed
 
 authoringExitClass :: AuthoringError -> ExitClass
 authoringExitClass authoringError =
   case authoringError of
+    AuthoringManifestError ManifestIoError {} -> ExitExecutionFailed
     AuthoringIoError {} -> ExitExecutionFailed
     AuthoringCleanupError {} -> ExitExecutionFailed
     _ -> ExitUsageFailed
 
+manifestExitClass :: ManifestError -> ExitClass
+manifestExitClass manifestError =
+  case manifestError of
+    ManifestIoError {} -> ExitExecutionFailed
+    _ -> ExitUsageFailed
+
 success :: Text -> CliPayload -> CliOutcome
-success command payload = CliOutcome {command, exitClass = ExitSuccess, payload = Right payload}
+success command payload = CliOutcome {command, exitClass = ExitSucceeded, payload = Right payload}
 
 failure :: Text -> ExitClass -> CliError -> CliOutcome
 failure command exitClass cliError = CliOutcome {command, exitClass, payload = Left cliError}
@@ -239,18 +257,18 @@
 filterMigrations :: InspectionOptions -> [MigrationDescription] -> [MigrationDescription]
 filterMigrations inspection = filter (matchesMigrationDescription inspection)
 
-filterStatus :: InspectionOptions -> StatusReport -> StatusReport
-filterStatus inspection (StatusReport issues applied pending unknown) =
+filterStatus :: PlanDescription -> InspectionOptions -> StatusReport -> StatusReport
+filterStatus description inspection (StatusReport issues applied pending unknown) =
   StatusReport
-    issues
+    (filter (matchesVerificationIssue description inspection) issues)
     (filter (matchesMigrationId inspection) applied)
     (filter (matchesMigrationId inspection) pending)
     (filter (matchesMigrationId inspection . storedMigrationId) unknown)
 
-filterVerification :: InspectionOptions -> VerificationReport -> VerificationReport
-filterVerification inspection (VerificationReport issues applied pending unknown) =
+filterVerification :: PlanDescription -> InspectionOptions -> VerificationReport -> VerificationReport
+filterVerification description inspection (VerificationReport issues applied pending unknown) =
   VerificationReport
-    issues
+    (filter (matchesVerificationIssue description inspection) issues)
     (filter (matchesMigrationId inspection) applied)
     (filter (matchesMigrationId inspection) pending)
     (filter (matchesMigrationId inspection . storedMigrationId) unknown)
@@ -266,3 +284,47 @@
 
 matchesComponent :: InspectionOptions -> ComponentName -> Bool
 matchesComponent InspectionOptions {component} candidate = maybe True (== candidate) component
+
+validateInspection :: MigrationPlan -> InspectionOptions -> Either Text PlanDescription
+validateInspection plan inspection@InspectionOptions {component, migration} = do
+  let description = planDescription plan
+      migrations = flattenPlanDescription description
+  case component of
+    Just requestedComponent
+      | not (any (matchesComponent inspection . migrationIdComponent . migrationId) migrations) ->
+          Left ("unknown component filter: " <> componentNameText requestedComponent)
+    _ -> Right ()
+  case migration of
+    Just requestedMigration
+      | not (any (matchesMigrationDescription inspection) migrations) ->
+          Left ("unknown migration filter: " <> migrationNameText requestedMigration)
+    _ -> Right ()
+  Right description
+
+matchesVerificationIssue :: PlanDescription -> InspectionOptions -> VerificationIssue -> Bool
+matchesVerificationIssue description inspection issue =
+  case issue of
+    DuplicateStoredMigration identifier -> matchesMigrationId inspection identifier
+    DuplicateStoredPosition issueComponent issuePosition ->
+      matchesDuplicateStoredPosition description inspection issueComponent issuePosition
+    StoredMigrationRunning identifier -> matchesMigrationId inspection identifier
+    StoredMigrationFailed identifier -> matchesMigrationId inspection identifier
+    MigrationPositionMismatch identifier _ _ -> matchesMigrationId inspection identifier
+    MigrationChecksumMismatch identifier _ _ -> matchesMigrationId inspection identifier
+    MigrationKindMismatch identifier _ _ -> matchesMigrationId inspection identifier
+    MigrationTransactionModeMismatch identifier _ _ -> matchesMigrationId inspection identifier
+    AppliedMigrationAfterGap identifier missing ->
+      matchesMigrationId inspection identifier || matchesMigrationId inspection missing
+    UnknownStoredMigration identifier -> matchesMigrationId inspection identifier
+    PendingMigration identifier -> matchesMigrationId inspection identifier
+
+matchesDuplicateStoredPosition :: PlanDescription -> InspectionOptions -> ComponentName -> Int -> Bool
+matchesDuplicateStoredPosition description inspection@InspectionOptions {migration} issueComponent issuePosition
+  | not (matchesComponent inspection issueComponent) = False
+  | otherwise =
+      case migration of
+        Nothing -> True
+        Just _ ->
+          any
+            (\MigrationDescription {migrationId, position} -> position == issuePosition && matchesMigrationId inspection migrationId)
+            (flattenPlanDescription description)
diff --git a/src/Database/PostgreSQL/Migrate/CLI/Json.hs b/src/Database/PostgreSQL/Migrate/CLI/Json.hs
--- a/src/Database/PostgreSQL/Migrate/CLI/Json.hs
+++ b/src/Database/PostgreSQL/Migrate/CLI/Json.hs
@@ -7,15 +7,14 @@
 
 import Data.Aeson (Value, object, (.=))
 import Data.Aeson.Types (Pair)
-import Data.ByteString qualified as ByteString
 import Data.List.NonEmpty qualified as NonEmpty
 import Data.Set qualified as Set
 import Data.Text qualified as Text
 import Data.Time (UTCTime, defaultTimeLocale, formatTime)
 import Database.PostgreSQL.Migrate
 import Database.PostgreSQL.Migrate.CLI.Outcome
+import Database.PostgreSQL.Migrate.CLI.Types (checksumText)
 import Database.PostgreSQL.Migrate.Internal
-import Numeric qualified
 import PgMigrate.CLI.Prelude
 
 -- | Supported machine-readable CLI schema version.
@@ -28,7 +27,7 @@
   object
     ( [ "schemaVersion" .= jsonSchemaVersion,
         "command" .= command,
-        "ok" .= (exitClass == ExitSuccess)
+        "ok" .= (exitClass == ExitSucceeded)
       ]
         <> case payload of
           Left cliError -> ["error" .= errorValue cliError]
@@ -37,7 +36,7 @@
 
 -- | Render an adapter import report using JSON schema v1.
 renderHistoryImportJson :: Text -> HistoryImportReport -> Value
-renderHistoryImportJson sourceName HistoryImportReport {importResults} =
+renderHistoryImportJson sourceName HistoryImportReport {importResults, cleanupIssues} =
   object
     [ "schemaVersion" .= jsonSchemaVersion,
       "command" .= ("import" :: Text),
@@ -45,7 +44,8 @@
       "data"
         .= object
           [ "source" .= sourceName,
-            "results" .= (historyImportResultValue <$> NonEmpty.toList importResults)
+            "results" .= (historyImportResultValue <$> NonEmpty.toList importResults),
+            "cleanup_issues" .= (cleanupIssueValue <$> cleanupIssues)
           ]
     ]
 
@@ -197,11 +197,12 @@
   object ["type" .= issueType, "id" .= migrationIdText identifier, expected, actual]
 
 migrationReportValue :: MigrationReport -> Value
-migrationReportValue (MigrationReport startedAt finishedAt results) =
+migrationReportValue MigrationReport {startedAt, finishedAt, results, cleanupIssues} =
   object
     [ "startedAt" .= utcText startedAt,
       "finishedAt" .= utcText finishedAt,
-      "results" .= (migrationResultValue <$> NonEmpty.toList results)
+      "results" .= (migrationResultValue <$> NonEmpty.toList results),
+      "cleanup_issues" .= (cleanupIssueValue <$> cleanupIssues)
     ]
 
 migrationResultValue :: MigrationResult -> Value
@@ -213,14 +214,30 @@
     ]
 
 repairReportValue :: RepairReport -> Value
-repairReportValue (RepairReport identifier operation oldStatus newStatus) =
+repairReportValue RepairReport {repairedMigration, operation, oldStatus, newStatus, cleanupIssues} =
   object
-    [ "id" .= migrationIdText identifier,
+    [ "id" .= migrationIdText repairedMigration,
       "operation" .= repairOperationText operation,
       "oldStatus" .= statusText oldStatus,
-      "newStatus" .= statusText newStatus
+      "newStatus" .= statusText newStatus,
+      "cleanup_issues" .= (cleanupIssueValue <$> cleanupIssues)
     ]
 
+cleanupIssueValue :: CleanupIssue -> Value
+cleanupIssueValue cleanupIssue =
+  case cleanupIssue of
+    AdvisoryUnlockReturnedFalse -> object ["type" .= ("advisoryUnlockReturnedFalse" :: Text)]
+    AdvisoryUnlockFailed sessionError ->
+      object
+        [ "type" .= ("advisoryUnlockFailed" :: Text),
+          "message" .= Text.pack (show sessionError)
+        ]
+    StatementTimeoutRestoreFailed sessionError ->
+      object
+        [ "type" .= ("statementTimeoutRestoreFailed" :: Text),
+          "message" .= Text.pack (show sessionError)
+        ]
+
 errorValue :: CliError -> Value
 errorValue cliError =
   object
@@ -231,6 +248,7 @@
 cliErrorType :: CliError -> Text
 cliErrorType cliError =
   case cliError of
+    CliInputError _ -> "input.invalid"
     CliMigrationError migrationError -> "migration." <> migrationErrorType migrationError
     CliRepairDefinitionError _ -> "repair.definition"
     CliRepairError _ -> "repair.execution"
@@ -240,6 +258,7 @@
 renderCliErrorMessage :: CliError -> String
 renderCliErrorMessage cliError =
   case cliError of
+    CliInputError err -> Text.unpack err
     CliMigrationError err -> show err
     CliRepairDefinitionError err -> show err
     CliRepairError err -> show err
@@ -273,15 +292,6 @@
   componentNameText (migrationIdComponent identifier)
     <> "/"
     <> migrationNameText (migrationIdName identifier)
-
-checksumText :: MigrationChecksum -> Text
-checksumText =
-  Text.pack . concatMap renderByte . ByteString.unpack . migrationChecksumBytes
-  where
-    renderByte byte =
-      case Numeric.showHex byte "" of
-        [digit] -> ['0', digit]
-        digits -> digits
 
 kindText :: MigrationKind -> Text
 kindText kind = case kind of SqlKind -> "sql"; HaskellKind -> "haskell"
diff --git a/src/Database/PostgreSQL/Migrate/CLI/Outcome.hs b/src/Database/PostgreSQL/Migrate/CLI/Outcome.hs
--- a/src/Database/PostgreSQL/Migrate/CLI/Outcome.hs
+++ b/src/Database/PostgreSQL/Migrate/CLI/Outcome.hs
@@ -26,7 +26,7 @@
 
 -- | Stable process-exit classification chosen by the application.
 data ExitClass
-  = ExitSuccess
+  = ExitSucceeded
   | ExitVerificationFailed
   | ExitUsageFailed
   | ExitExecutionFailed
@@ -53,7 +53,8 @@
 
 -- | Structured CLI definition, runner, repair, authoring, or import failure.
 data CliError
-  = CliMigrationError !MigrationError
+  = CliInputError !Text
+  | CliMigrationError !MigrationError
   | CliRepairDefinitionError !RepairDefinitionError
   | CliRepairError !RepairError
   | CliManifestError !ManifestError
diff --git a/src/Database/PostgreSQL/Migrate/CLI/Parser.hs b/src/Database/PostgreSQL/Migrate/CLI/Parser.hs
--- a/src/Database/PostgreSQL/Migrate/CLI/Parser.hs
+++ b/src/Database/PostgreSQL/Migrate/CLI/Parser.hs
@@ -23,7 +23,8 @@
 import PgMigrate.CLI.Prelude
 import Text.Read qualified as Read
 
--- | Build the reusable parser, using the plan for target-aware choices.
+-- | Build the reusable parser. The plan parameter is reserved for future
+-- target-aware completion.
 migrationCommandParser :: MigrationPlan -> Parser MigrationCommand
 migrationCommandParser _ =
   subparser (commandGroup "Inspection" <> inspectionCommands)
@@ -79,7 +80,7 @@
 checkOptionsParser :: Parser CheckOptions
 checkOptionsParser =
   CheckOptions
-    <$> strArgument (metavar "MANIFEST" <> help "Path to the ordered migration manifest")
+    <$> strOption (long "manifest" <> metavar "PATH" <> help "Ordered migration manifest to validate")
     <*> outputOptionsParser
 
 statusOptionsParser :: Parser StatusOptions
@@ -118,7 +119,7 @@
 newOptionsParser =
   NewOptions
     <$> strOption (long "manifest" <> metavar "PATH" <> help "Ordered manifest to append")
-    <*> strOption (long "description" <> metavar "TEXT" <> help "Human description written into the new SQL file")
+    <*> option descriptionReader (long "description" <> metavar "TEXT" <> help "Single-line description written into the new SQL file")
     <*> optional (strOption (long "name" <> metavar "BASENAME" <> help "Explicit SQL basename when numeric inference is unavailable"))
     <*> outputOptionsParser
 
@@ -143,14 +144,7 @@
     "Execution"
     ( ExecutionOptions
         <$> lockWaitParser
-        <*> optional
-          ( option
-              positiveMillisecondsReader
-              ( long "statement-timeout"
-                  <> metavar "MILLISECONDS"
-                  <> help "Positive PostgreSQL statement timeout in milliseconds"
-              )
-          )
+        <*> statementTimeoutParser
     )
 
 outputOptionsParser :: Parser OutputOptions
@@ -172,19 +166,35 @@
           (option migrationNameReader (long "migration" <> metavar "MIGRATION" <> help "Limit inspection output to one migration name"))
     )
 
-lockWaitParser :: Parser LockWait
+lockWaitParser :: Parser (Maybe LockWait)
 lockWaitParser =
-  flag' NoWait (long "no-wait" <> help "Fail immediately when the advisory lock is unavailable")
-    <|> ( WaitFor
-            <$> option
-              positiveMillisecondsReader
-              ( long "lock-timeout"
-                  <> metavar "MILLISECONDS"
-                  <> help "Wait at most this many positive milliseconds for the advisory lock"
-              )
-        )
-    <|> pure WaitIndefinitely
+  optional
+    ( flag' NoWait (long "no-wait" <> help "Fail immediately when the advisory lock is unavailable")
+        <|> ( WaitFor
+                <$> option
+                  positiveMillisecondsReader
+                  ( long "lock-timeout"
+                      <> metavar "MILLISECONDS"
+                      <> help "Wait at most this many positive milliseconds for the advisory lock"
+                  )
+            )
+        <|> flag' WaitIndefinitely (long "wait" <> help "Wait indefinitely for the advisory lock")
+    )
 
+statementTimeoutParser :: Parser (Maybe (Maybe NominalDiffTime))
+statementTimeoutParser =
+  optional
+    ( ( Just
+          <$> option
+            positiveMillisecondsReader
+            ( long "statement-timeout"
+                <> metavar "MILLISECONDS"
+                <> help "Set a positive PostgreSQL statement timeout in milliseconds"
+            )
+      )
+        <|> flag' Nothing (long "no-statement-timeout" <> help "Run without a temporary statement timeout")
+    )
+
 repairOperationParser :: Parser RepairOperation
 repairOperationParser =
   flag' MarkApplied (long "mark-applied" <> help "Record the inspected nontransactional result as applied")
@@ -220,3 +230,9 @@
         Left err -> Left (show err)
         Right validated -> Right validated
     _ -> Left "expected COMPONENT/MIGRATION"
+
+descriptionReader :: ReadM Text
+descriptionReader = eitherReader $ \input ->
+  case validateDescription (Text.pack input) of
+    Left err -> Left (Text.unpack err)
+    Right description -> Right description
diff --git a/src/Database/PostgreSQL/Migrate/CLI/Text.hs b/src/Database/PostgreSQL/Migrate/CLI/Text.hs
--- a/src/Database/PostgreSQL/Migrate/CLI/Text.hs
+++ b/src/Database/PostgreSQL/Migrate/CLI/Text.hs
@@ -3,14 +3,13 @@
   )
 where
 
-import Data.ByteString qualified as ByteString
 import Data.List.NonEmpty qualified as NonEmpty
 import Data.Set qualified as Set
 import Data.Text qualified as Text
 import Database.PostgreSQL.Migrate
 import Database.PostgreSQL.Migrate.CLI.Outcome
+import Database.PostgreSQL.Migrate.CLI.Types (checksumText)
 import Database.PostgreSQL.Migrate.Internal
-import Numeric qualified
 import PgMigrate.CLI.Prelude
 
 -- | Render a stable human-oriented outcome.
@@ -22,6 +21,7 @@
 renderCliError :: CliError -> Text
 renderCliError cliError =
   case cliError of
+    CliInputError err -> err
     CliMigrationError err -> Text.pack (show err)
     CliRepairDefinitionError err -> Text.pack (show err)
     CliRepairError err -> Text.pack (show err)
@@ -94,12 +94,13 @@
     )
 
 renderMigrationReport :: MigrationReport -> Text
-renderMigrationReport (MigrationReport startedAt finishedAt results) =
+renderMigrationReport MigrationReport {startedAt, finishedAt, results, cleanupIssues} =
   Text.unlines
     ( [ "started=" <> Text.pack (show startedAt),
         "finished=" <> Text.pack (show finishedAt)
       ]
         <> (renderMigrationResult <$> NonEmpty.toList results)
+        <> (renderCleanupIssue <$> cleanupIssues)
     )
 
 renderMigrationResult :: MigrationResult -> Text
@@ -112,16 +113,21 @@
     ]
 
 renderRepairReport :: RepairReport -> Text
-renderRepairReport (RepairReport identifier operation oldStatus newStatus) =
-  Text.intercalate
-    " "
-    [ renderMigrationId identifier,
-      "operation=" <> renderRepairOperation operation,
-      "old_status=" <> renderStatusName oldStatus,
-      "new_status=" <> renderStatusName newStatus
-    ]
-    <> "\n"
+renderRepairReport RepairReport {repairedMigration, operation, oldStatus, newStatus, cleanupIssues} =
+  Text.unlines
+    ( Text.intercalate
+        " "
+        [ renderMigrationId repairedMigration,
+          "operation=" <> renderRepairOperation operation,
+          "old_status=" <> renderStatusName oldStatus,
+          "new_status=" <> renderStatusName newStatus
+        ]
+        : (renderCleanupIssue <$> cleanupIssues)
+    )
 
+renderCleanupIssue :: CleanupIssue -> Text
+renderCleanupIssue cleanupIssue = "cleanup_issue=" <> Text.pack (show cleanupIssue)
+
 renderStoredMigrationId :: StoredMigration -> Text
 renderStoredMigrationId StoredMigration {storedMigrationId} = renderMigrationId storedMigrationId
 
@@ -130,15 +136,6 @@
   componentNameText (migrationIdComponent identifier)
     <> "/"
     <> migrationNameText (migrationIdName identifier)
-
-checksumText :: MigrationChecksum -> Text
-checksumText =
-  Text.pack . concatMap renderByte . ByteString.unpack . migrationChecksumBytes
-  where
-    renderByte byte =
-      case Numeric.showHex byte "" of
-        [digit] -> ['0', digit]
-        digits -> digits
 
 renderKind :: MigrationKind -> Text
 renderKind kind = case kind of SqlKind -> "sql"; HaskellKind -> "haskell"
diff --git a/src/Database/PostgreSQL/Migrate/CLI/Types.hs b/src/Database/PostgreSQL/Migrate/CLI/Types.hs
--- a/src/Database/PostgreSQL/Migrate/CLI/Types.hs
+++ b/src/Database/PostgreSQL/Migrate/CLI/Types.hs
@@ -13,18 +13,26 @@
     RepairOptions (..),
     NewOptions (..),
     MigrationCommand (..),
+    checksumText,
+    validateDescription,
   )
 where
 
+import Data.ByteString qualified as ByteString
+import Data.Char qualified as Char
+import Data.Text qualified as Text
 import Database.PostgreSQL.Migrate
   ( ComponentName,
     Confirmation,
     LockWait,
+    MigrationChecksum,
     MigrationId,
     MigrationName,
     RepairOperation,
   )
+import Database.PostgreSQL.Migrate.Internal (migrationChecksumBytes)
 import Hasql.Connection.Settings qualified as Settings
+import Numeric qualified
 import PgMigrate.CLI.Prelude
 
 -- | Human-readable or versioned JSON rendering.
@@ -41,8 +49,8 @@
 
 -- | Shared lock and statement-timeout flags.
 data ExecutionOptions = ExecutionOptions
-  { lockWait :: !LockWait,
-    statementTimeout :: !(Maybe NominalDiffTime)
+  { lockWait :: !(Maybe LockWait),
+    statementTimeout :: !(Maybe (Maybe NominalDiffTime))
   }
   deriving stock (Generic, Eq, Show)
 
@@ -136,3 +144,23 @@
   | Repair !RepairOptions
   | New !NewOptions
   deriving stock (Generic, Eq, Show)
+
+checksumText :: MigrationChecksum -> Text
+checksumText =
+  Text.pack . concatMap renderByte . ByteString.unpack . migrationChecksumBytes
+  where
+    renderByte byte =
+      case Numeric.showHex byte "" of
+        [digit] -> ['0', digit]
+        digits -> digits
+
+validateDescription :: Text -> Either Text Text
+validateDescription description =
+  case Text.find Char.isControl description of
+    Nothing -> Right description
+    Just character ->
+      Left
+        ( "invalid --description: control character "
+            <> Text.pack (show character)
+            <> " is not allowed"
+        )
diff --git a/test/golden/help/check.txt b/test/golden/help/check.txt
--- a/test/golden/help/check.txt
+++ b/test/golden/help/check.txt
@@ -1,9 +1,9 @@
-Usage: pg-migrate-cli-help-fixture check MANIFEST [--json]
+Usage: pg-migrate-cli-help-fixture check --manifest PATH [--json]
 
   Validate an ordered SQL manifest without a database
 
 Available options:
-  MANIFEST                 Path to the ordered migration manifest
+  --manifest PATH          Ordered migration manifest to validate
   -h,--help                Show this help text
 
 Output
diff --git a/test/golden/help/new.txt b/test/golden/help/new.txt
--- a/test/golden/help/new.txt
+++ b/test/golden/help/new.txt
@@ -5,7 +5,7 @@
 
 Available options:
   --manifest PATH          Ordered manifest to append
-  --description TEXT       Human description written into the new SQL file
+  --description TEXT       Single-line description written into the new SQL file
   --name BASENAME          Explicit SQL basename when numeric inference is
                            unavailable
   -h,--help                Show this help text
diff --git a/test/golden/help/repair.txt b/test/golden/help/repair.txt
--- a/test/golden/help/repair.txt
+++ b/test/golden/help/repair.txt
@@ -1,7 +1,7 @@
 Usage: pg-migrate-cli-help-fixture repair
          COMPONENT/MIGRATION (--mark-applied | --retry) --reason TEXT --confirm
-         [--database-url URL] [--no-wait | --lock-timeout MILLISECONDS]
-         [--statement-timeout MILLISECONDS] [--json]
+         [--database-url URL] [--no-wait | --lock-timeout MILLISECONDS | --wait]
+         [--statement-timeout MILLISECONDS | --no-statement-timeout] [--json]
 
   Repair one nontransactional migration after operator inspection
 
@@ -24,8 +24,11 @@
   --lock-timeout MILLISECONDS
                            Wait at most this many positive milliseconds for the
                            advisory lock
+  --wait                   Wait indefinitely for the advisory lock
   --statement-timeout MILLISECONDS
-                           Positive PostgreSQL statement timeout in milliseconds
+                           Set a positive PostgreSQL statement timeout in
+                           milliseconds
+  --no-statement-timeout   Run without a temporary statement timeout
 
 Output
   --json                   Emit JSON schema version 1
diff --git a/test/golden/help/up.txt b/test/golden/help/up.txt
--- a/test/golden/help/up.txt
+++ b/test/golden/help/up.txt
@@ -1,6 +1,6 @@
 Usage: pg-migrate-cli-help-fixture up
-         [--database-url URL] [--no-wait | --lock-timeout MILLISECONDS]
-         [--statement-timeout MILLISECONDS] [--json]
+         [--database-url URL] [--no-wait | --lock-timeout MILLISECONDS | --wait]
+         [--statement-timeout MILLISECONDS | --no-statement-timeout] [--json]
 
   Apply the complete migration plan; selective execution is unavailable in v1
 
@@ -14,8 +14,11 @@
   --lock-timeout MILLISECONDS
                            Wait at most this many positive milliseconds for the
                            advisory lock
+  --wait                   Wait indefinitely for the advisory lock
   --statement-timeout MILLISECONDS
-                           Positive PostgreSQL statement timeout in milliseconds
+                           Set a positive PostgreSQL statement timeout in
+                           milliseconds
+  --no-statement-timeout   Run without a temporary statement timeout
 
 Output
   --json                   Emit JSON schema version 1
diff --git a/test/golden/json/import.json b/test/golden/json/import.json
--- a/test/golden/json/import.json
+++ b/test/golden/json/import.json
@@ -13,6 +13,7 @@
         "id": "accounts/0002",
         "outcome": "alreadyImported"
       }
-    ]
+    ],
+    "cleanup_issues": []
   }
 }
diff --git a/test/golden/json/repair.json b/test/golden/json/repair.json
--- a/test/golden/json/repair.json
+++ b/test/golden/json/repair.json
@@ -6,6 +6,7 @@
     "id": "accounts/0001",
     "operation": "markApplied",
     "oldStatus": "failed",
-    "newStatus": "applied"
+    "newStatus": "applied",
+    "cleanup_issues": []
   }
 }
diff --git a/test/golden/json/up-cleanup.json b/test/golden/json/up-cleanup.json
new file mode 100644
--- /dev/null
+++ b/test/golden/json/up-cleanup.json
@@ -0,0 +1,21 @@
+{
+  "schemaVersion": 1,
+  "command": "up",
+  "ok": true,
+  "data": {
+    "startedAt": "2026-07-10T12:00:00Z",
+    "finishedAt": "2026-07-10T12:00:01Z",
+    "results": [
+      {
+        "id": "accounts/0001",
+        "outcome": "appliedNow",
+        "durationMilliseconds": 125
+      }
+    ],
+    "cleanup_issues": [
+      {
+        "type": "advisoryUnlockReturnedFalse"
+      }
+    ]
+  }
+}
diff --git a/test/golden/json/up.json b/test/golden/json/up.json
--- a/test/golden/json/up.json
+++ b/test/golden/json/up.json
@@ -11,6 +11,7 @@
         "outcome": "appliedNow",
         "durationMilliseconds": 125
       }
-    ]
+    ],
+    "cleanup_issues": []
   }
 }
diff --git a/test/integration/Main.hs b/test/integration/Main.hs
--- a/test/integration/Main.hs
+++ b/test/integration/Main.hs
@@ -1,6 +1,8 @@
 module Main (main) where
 
 import Control.Exception qualified as Exception
+import Data.ByteString (ByteString)
+import Data.IORef qualified as IORef
 import Data.Int (Int64)
 import Data.List.NonEmpty (NonEmpty (..))
 import Data.Set qualified as Set
@@ -29,16 +31,22 @@
   testGroup
     "pg-migrate CLI PostgreSQL"
     [ testCase "status verify and full up preserve their contracts" (testCommandLifecycle settings),
-      testCase "confirmed repair dispatches through the shared lifecycle" (testRepairLifecycle settings)
+      testCase "confirmed repair dispatches through the shared lifecycle" (testRepairLifecycle settings),
+      testCase "filtered verification keeps full-report exit classification" (testFilteredVerification settings)
     ]
 
 testCommandLifecycle :: Settings.Settings -> Assertion
 testCommandLifecycle settings =
   withCleanLedger settings "pgmigrate_cli_commands" 0x70676D636C690001 $ \options -> do
-    let environment = cliEnvironment settings commandPlan options
+    observedEvents <- IORef.newIORef []
+    let configuredOptions =
+          withEventHandler (IORef.modifyIORef' observedEvents . (:)) $
+            withStatementTimeout (Just 5) $
+              withLockWait NoWait options
+        environment = cliEnvironment settings commandPlan configuredOptions
 
     statusBefore <- runMigrationCommand environment statusCommand
-    exitClass statusBefore @?= ExitSuccess
+    exitClass statusBefore @?= ExitSucceeded
     case payload statusBefore of
       Right (StatusPayload (StatusReport issues applied pending unknown)) -> do
         issues @?= []
@@ -56,11 +64,13 @@
       other -> assertFailure ("unexpected pre-run verify outcome: " <> show other)
 
     firstUp <- runMigrationCommand environment upCommand
-    exitClass firstUp @?= ExitSuccess
+    exitClass firstUp @?= ExitSucceeded
     assertSingleOutcome AppliedNow firstUp
+    events <- IORef.readIORef observedEvents
+    assertBool "application lock-wait setting survives absent CLI flags" (LockWaitStarted NoWait `elem` events)
 
     verifyAfter <- runMigrationCommand environment verifyCommand
-    exitClass verifyAfter @?= ExitSuccess
+    exitClass verifyAfter @?= ExitSucceeded
     case payload verifyAfter of
       Right (VerifyPayload (VerificationReport issues applied pending unknown)) -> do
         issues @?= []
@@ -70,7 +80,7 @@
       other -> assertFailure ("unexpected post-run verify outcome: " <> show other)
 
     secondUp <- runMigrationCommand environment upCommand
-    exitClass secondUp @?= ExitSuccess
+    exitClass secondUp @?= ExitSucceeded
     assertSingleOutcome AlreadyApplied secondUp
 
 testRepairLifecycle :: Settings.Settings -> Assertion
@@ -95,19 +105,40 @@
                 jsonOutput
             )
         )
-    exitClass repaired @?= ExitSuccess
+    exitClass repaired @?= ExitSucceeded
     case payload repaired of
-      Right (RepairPayload (RepairReport identifier MarkApplied Failed Applied)) ->
+      Right (RepairPayload (RepairReport identifier MarkApplied Failed Applied [])) ->
         identifier @?= failingMigrationId
       other -> assertFailure ("unexpected repair outcome: " <> show other)
 
     verified <- runMigrationCommand environment verifyCommand
-    exitClass verified @?= ExitSuccess
+    exitClass verified @?= ExitSucceeded
 
+testFilteredVerification :: Settings.Settings -> Assertion
+testFilteredVerification settings =
+  withCleanLedger settings "pgmigrate_cli_filters" 0x70676D636C690003 $ \options -> do
+    let originalEnvironment = cliEnvironment settings (filteredPlan "SELECT 2") options
+        changedEnvironment = cliEnvironment settings (filteredPlan "SELECT 3") options
+        selectedInspection = InspectionOptions (Just filterAccounts) Nothing
+        selectedVerification = Verify (VerifyOptions selectedInspection noConnectionOverride jsonOutput)
+
+    applied <- runMigrationCommand originalEnvironment upCommand
+    exitClass applied @?= ExitSucceeded
+
+    filtered <- runMigrationCommand changedEnvironment selectedVerification
+    exitClass filtered @?= ExitVerificationFailed
+    case payload filtered of
+      Right (VerifyPayload (VerificationReport issues appliedMigrations pending unknown)) -> do
+        issues @?= []
+        appliedMigrations @?= [filterAccountsMigration]
+        pending @?= []
+        unknown @?= []
+      other -> assertFailure ("unexpected filtered verification outcome: " <> show other)
+
 assertSingleOutcome :: MigrationOutcome -> CliOutcome -> Assertion
 assertSingleOutcome expected outcome =
   case payload outcome of
-    Right (UpPayload (MigrationReport _ _ (MigrationResult _ actual _ :| []))) ->
+    Right (UpPayload (MigrationReport _ _ (MigrationResult _ actual _ :| []) [])) ->
       actual @?= expected
     other -> assertFailure ("unexpected up outcome: " <> show other)
 
@@ -127,7 +158,7 @@
 noConnectionOverride = ConnectionOptions Nothing
 
 defaultExecution :: ExecutionOptions
-defaultExecution = ExecutionOptions WaitIndefinitely Nothing
+defaultExecution = ExecutionOptions Nothing Nothing
 
 jsonOutput :: OutputOptions
 jsonOutput = OutputOptions JsonOutput
@@ -143,7 +174,16 @@
                 ( expectRight
                     ( sqlMigration
                         "0001"
-                        "CREATE TABLE pgmigrate_cli_commands.cli_command_probe (id bigint PRIMARY KEY)"
+                        """
+                        DO $$
+                        BEGIN
+                          IF current_setting('statement_timeout') <> '5s' THEN
+                            RAISE EXCEPTION 'application statement timeout was overridden';
+                          END IF;
+                        END
+                        $$;
+                        CREATE TABLE pgmigrate_cli_commands.cli_command_probe (id bigint PRIMARY KEY)
+                        """
                     )
                     :| []
                 )
@@ -151,6 +191,32 @@
             :| []
         )
     )
+
+filteredPlan :: ByteString -> MigrationPlan
+filteredPlan billingSql =
+  expectRight
+    ( migrationPlan
+        ( expectRight
+            ( migrationComponent
+                "filter-accounts"
+                Set.empty
+                (expectRight (sqlMigration "0001" "SELECT 1") :| [])
+            )
+            :| [ expectRight
+                   ( migrationComponent
+                       "filter-billing"
+                       (Set.singleton "filter-accounts")
+                       (expectRight (sqlMigration "0001" billingSql) :| [])
+                   )
+               ]
+        )
+    )
+
+filterAccounts :: ComponentName
+filterAccounts = expectRight (componentName "filter-accounts")
+
+filterAccountsMigration :: MigrationId
+filterAccountsMigration = expectRight (migrationId "filter-accounts" "0001")
 
 failingPlan :: MigrationPlan
 failingPlan =
diff --git a/test/unit/Test/Handler.hs b/test/unit/Test/Handler.hs
--- a/test/unit/Test/Handler.hs
+++ b/test/unit/Test/Handler.hs
@@ -7,7 +7,10 @@
 import Data.Text qualified as Text
 import Database.PostgreSQL.Migrate
 import Database.PostgreSQL.Migrate.CLI
-import Database.PostgreSQL.Migrate.Embed (AuthoringError (ExplicitMigrationNameRequired))
+import Database.PostgreSQL.Migrate.Embed
+  ( AuthoringError (..),
+    ManifestError (..),
+  )
 import Hasql.Connection.Settings qualified as Settings
 import System.Directory qualified as Directory
 import System.FilePath ((</>))
@@ -20,10 +23,14 @@
     "handler"
     [ testCase "plan text is stable and preserves component order" testPlanText,
       testCase "list filters narrow output without changing plan order" testListFilter,
+      testCase "unknown inspection filters fail before IO" testUnknownInspectionFilters,
       testCase "check returns exact-byte checksums" testCheck,
       testCase "new creates and appends a migration without applying it" testNew,
+      testCase "new rejects control characters before writing files" testNewRejectsControlCharacters,
       testCase "new reports when a nonnumeric manifest requires an explicit name" testNewRequiresName,
-      testCase "manifest failures are typed usage outcomes" testCheckFailure
+      testCase "manifest IO failures are typed execution outcomes" testCheckIoFailure,
+      testCase "manifest validation failures remain typed usage outcomes" testCheckValidationFailure,
+      testCase "new classifies manifest IO failures as execution outcomes" testNewManifestIoFailure
     ]
 
 testPlanText :: Assertion
@@ -32,7 +39,7 @@
     runMigrationCommand
       fixtureEnvironment
       (Plan (PlanOptions noInspection textOutput))
-  exitClass outcome @?= ExitSuccess
+  exitClass outcome @?= ExitSucceeded
   renderMigrationCommandText outcome
     @?= Text.unlines
       [ "1. accounts depends=[] migrations=1",
@@ -46,7 +53,7 @@
     runMigrationCommand
       fixtureEnvironment
       (List (ListOptions (InspectionOptions (Just billing) Nothing) textOutput))
-  exitClass outcome @?= ExitSuccess
+  exitClass outcome @?= ExitSucceeded
   let rendered = renderMigrationCommandText outcome
   assertBool "billing migration is present" ("billing/0001" `Text.isInfixOf` rendered)
   assertBool "accounts migration is filtered out" (not ("accounts/0001" `Text.isInfixOf` rendered))
@@ -54,6 +61,26 @@
   where
     validOutputCharacter character = not (character >= 'A' && character <= 'F')
 
+testUnknownInspectionFilters :: Assertion
+testUnknownInspectionFilters = do
+  let unknownComponent = expectRight (componentName "missing")
+      unknownMigration = expectRight (migrationName "missing")
+      accounts = expectRight (componentName "accounts")
+      commands =
+        [ Plan (PlanOptions (InspectionOptions (Just unknownComponent) Nothing) textOutput),
+          List (ListOptions (InspectionOptions (Just unknownComponent) Nothing) textOutput),
+          Status (StatusOptions (InspectionOptions (Just unknownComponent) Nothing) (ConnectionOptions Nothing) textOutput),
+          Verify (VerifyOptions (InspectionOptions (Just accounts) (Just unknownMigration)) (ConnectionOptions Nothing) textOutput)
+        ]
+  outcomes <- mapM (runMigrationCommand fixtureEnvironment) commands
+  mapM_ assertUnknownFilter outcomes
+  where
+    assertUnknownFilter outcome = do
+      exitClass outcome @?= ExitUsageFailed
+      case payload outcome of
+        Left (CliInputError message) -> assertBool "diagnostic names the unknown filter" ("unknown" `Text.isInfixOf` message)
+        result -> assertFailure ("expected typed unknown-filter error, received: " <> show result)
+
 testCheck :: Assertion
 testCheck =
   withFixtureDirectory "check" $ \directory -> do
@@ -64,7 +91,7 @@
       runMigrationCommand
         fixtureEnvironment
         (Check (CheckOptions manifest textOutput))
-    exitClass outcome @?= ExitSuccess
+    exitClass outcome @?= ExitSucceeded
     let rendered = renderMigrationCommandText outcome
     assertBool "manifest entry is rendered" ("0001.sql checksum=" `Text.isPrefixOf` rendered)
     Text.length (Text.takeWhileEnd (/= '=') (Text.strip rendered)) @?= 64
@@ -79,22 +106,65 @@
       runMigrationCommand
         fixtureEnvironment
         (New (NewOptions manifest "add profile" Nothing textOutput))
-    exitClass outcome @?= ExitSuccess
+    exitClass outcome @?= ExitSucceeded
     renderMigrationCommandText outcome @?= "created " <> Text.pack (directory </> "0002.sql") <> "\n"
     ByteString.readFile (directory </> "0002.sql") >>= (@?= "-- add profile\n\n")
     ByteString.readFile manifest >>= (@?= "0001.sql\n0002.sql\n")
 
-testCheckFailure :: Assertion
-testCheckFailure =
+testNewRejectsControlCharacters :: Assertion
+testNewRejectsControlCharacters =
+  withFixtureDirectory "new-description" $ \directory -> do
+    let manifest = directory </> "manifest"
+    ByteString.writeFile (directory </> "0001.sql") "SELECT 1;\n"
+    ByteString.writeFile manifest "0001.sql\n"
+    outcome <-
+      runMigrationCommand
+        fixtureEnvironment
+        (New (NewOptions manifest "add profile\nDROP TABLE accounts" Nothing textOutput))
+    exitClass outcome @?= ExitUsageFailed
+    case payload outcome of
+      Left (CliInputError message) -> assertBool "diagnostic names the newline" ("\\n" `Text.isInfixOf` message)
+      result -> assertFailure ("expected typed description error, received: " <> show result)
+    Directory.doesFileExist (directory </> "0002.sql") >>= (@?= False)
+    ByteString.readFile manifest >>= (@?= "0001.sql\n")
+
+testCheckIoFailure :: Assertion
+testCheckIoFailure =
   withFixtureDirectory "missing" $ \directory -> do
     outcome <-
       runMigrationCommand
         fixtureEnvironment
         (Check (CheckOptions (directory </> "missing-manifest") textOutput))
+    exitClass outcome @?= ExitExecutionFailed
+    case payload outcome of
+      Left (CliManifestError ManifestIoError {}) -> pure ()
+      result -> assertFailure ("expected typed manifest IO error, received: " <> show result)
+
+testCheckValidationFailure :: Assertion
+testCheckValidationFailure =
+  withFixtureDirectory "invalid-manifest" $ \directory -> do
+    let manifest = directory </> "manifest"
+    ByteString.writeFile manifest ""
+    outcome <-
+      runMigrationCommand
+        fixtureEnvironment
+        (Check (CheckOptions manifest textOutput))
     exitClass outcome @?= ExitUsageFailed
     case payload outcome of
-      Left (CliManifestError _) -> pure ()
-      result -> assertFailure ("expected typed manifest error, received: " <> show result)
+      Left (CliManifestError EmptyManifest) -> pure ()
+      result -> assertFailure ("expected typed manifest validation error, received: " <> show result)
+
+testNewManifestIoFailure :: Assertion
+testNewManifestIoFailure =
+  withFixtureDirectory "new-missing-manifest" $ \directory -> do
+    outcome <-
+      runMigrationCommand
+        fixtureEnvironment
+        (New (NewOptions (directory </> "missing-manifest") "add profile" Nothing textOutput))
+    exitClass outcome @?= ExitExecutionFailed
+    case payload outcome of
+      Left (CliAuthoringError (AuthoringManifestError ManifestIoError {})) -> pure ()
+      result -> assertFailure ("expected typed authoring manifest IO error, received: " <> show result)
 
 testNewRequiresName :: Assertion
 testNewRequiresName =
diff --git a/test/unit/Test/Json.hs b/test/unit/Test/Json.hs
--- a/test/unit/Test/Json.hs
+++ b/test/unit/Test/Json.hs
@@ -28,6 +28,7 @@
       goldenCase "status" statusOutcome,
       goldenCase "verify" verifyOutcome,
       goldenCase "up" upOutcome,
+      goldenCase "up-cleanup" upCleanupOutcome,
       goldenCase "repair" repairOutcome,
       goldenCase "error" errorOutcome,
       testCase "import matches its golden contract" testImportGolden,
@@ -70,6 +71,7 @@
     statusOutcome,
     verifyOutcome,
     upOutcome,
+    upCleanupOutcome,
     repairOutcome,
     errorOutcome
   ]
@@ -112,14 +114,28 @@
             fixtureStartedAt
             fixtureFinishedAt
             (MigrationResult migrationIdentifier AppliedNow (Just 0.125) :| [])
+            []
         )
     )
 
+upCleanupOutcome :: CliOutcome
+upCleanupOutcome =
+  successful
+    "up"
+    ( UpPayload
+        ( MigrationReport
+            fixtureStartedAt
+            fixtureFinishedAt
+            (MigrationResult migrationIdentifier AppliedNow (Just 0.125) :| [])
+            [AdvisoryUnlockReturnedFalse]
+        )
+    )
+
 repairOutcome :: CliOutcome
 repairOutcome =
   successful
     "repair"
-    (RepairPayload (RepairReport migrationIdentifier MarkApplied Failed Applied))
+    (RepairPayload (RepairReport migrationIdentifier MarkApplied Failed Applied []))
 
 errorOutcome :: CliOutcome
 errorOutcome =
@@ -130,7 +146,7 @@
     }
 
 successful :: Text -> CliPayload -> CliOutcome
-successful command payload = CliOutcome {command, exitClass = ExitSuccess, payload = Right payload}
+successful command payload = CliOutcome {command, exitClass = ExitSucceeded, payload = Right payload}
 
 accounts :: ComponentName
 accounts = expectRight (componentName "accounts")
@@ -150,9 +166,11 @@
 importReport :: HistoryImportReport
 importReport =
   HistoryImportReport
-    ( HistoryImportResult migrationIdentifier Imported
-        :| [HistoryImportResult (expectRight (migrationId "accounts" "0002")) AlreadyImported]
-    )
+    { importResults =
+        HistoryImportResult migrationIdentifier Imported
+          :| [HistoryImportResult (expectRight (migrationId "accounts" "0002")) AlreadyImported],
+      cleanupIssues = []
+    }
 
 expectRight :: (Show error) => Either error value -> value
 expectRight = either (error . show) id
diff --git a/test/unit/Test/Parser.hs b/test/unit/Test/Parser.hs
--- a/test/unit/Test/Parser.hs
+++ b/test/unit/Test/Parser.hs
@@ -21,9 +21,14 @@
       testCase "up has no selective execution filters" testUpRejectsFilters,
       testCase "durations must be positive integer milliseconds" testDurationValidation,
       testCase "lock wait flags conflict" testConflictingWaitFlags,
+      testCase "absent execution flags preserve application options" testAbsentExecutionOverrides,
+      testCase "lock wait flags produce explicit overrides" testLockWaitOverrides,
+      testCase "statement timeout flags produce explicit overrides" testStatementTimeoutOverrides,
+      testCase "description rejects control characters" testDescriptionValidation,
       testCase "repair requires an operation and confirmation" testRepairConfirmation,
       testCase "repair validates the component/migration target" testRepairTarget,
       testCase "parsing does not imply database settings" testNoImplicitDatabaseSettings,
+      testCase "check uses the same manifest flag as new" testCheckManifestFlag,
       testCase "plain completion derives all commands from the parser" testPlainCompletion,
       testCase "enriched completion derives execution flags and descriptions" testEnrichedCompletion,
       testGroup "help goldens" (uncurry goldenHelpCase <$> helpGoldens)
@@ -70,7 +75,30 @@
 testConflictingWaitFlags = do
   failure <- parseFailure ["up", "--no-wait", "--lock-timeout", "100"]
   assertContains "Invalid option" failure
+  statementFailure <- parseFailure ["up", "--statement-timeout", "100", "--no-statement-timeout"]
+  assertContains "Invalid option" statementFailure
 
+testAbsentExecutionOverrides :: Assertion
+testAbsentExecutionOverrides =
+  parsedExecution [] @?= ExecutionOptions Nothing Nothing
+
+testLockWaitOverrides :: Assertion
+testLockWaitOverrides = do
+  parsedExecution ["--no-wait"] @?= ExecutionOptions (Just NoWait) Nothing
+  parsedExecution ["--lock-timeout", "250"] @?= ExecutionOptions (Just (WaitFor 0.25)) Nothing
+  parsedExecution ["--wait"] @?= ExecutionOptions (Just WaitIndefinitely) Nothing
+
+testStatementTimeoutOverrides :: Assertion
+testStatementTimeoutOverrides = do
+  parsedExecution ["--statement-timeout", "250"] @?= ExecutionOptions Nothing (Just (Just 0.25))
+  parsedExecution ["--no-statement-timeout"] @?= ExecutionOptions Nothing (Just Nothing)
+
+testDescriptionValidation :: Assertion
+testDescriptionValidation = do
+  failure <- parseFailure ["new", "--manifest", "manifest", "--description", "add profile\nDROP TABLE accounts"]
+  assertContains "--description" failure
+  assertContains "\\n" failure
+
 testRepairConfirmation :: Assertion
 testRepairConfirmation = do
   missingOperation <- parseFailure ["repair", "accounts/0001", "--reason", "inspected", "--confirm"]
@@ -89,6 +117,14 @@
     Status StatusOptions {connection = ConnectionOptions {databaseSettings = Nothing}} -> pure ()
     result -> assertFailure ("expected status without database settings, received: " <> show result)
 
+testCheckManifestFlag :: Assertion
+testCheckManifestFlag = do
+  case parseSuccess ["check", "--manifest", "migrations/manifest"] of
+    Check CheckOptions {manifestPath = "migrations/manifest"} -> pure ()
+    parsedCommand -> assertFailure ("expected check command, received: " <> show parsedCommand)
+  positionalFailure <- parseFailure ["check", "migrations/manifest"]
+  assertContains "--manifest" positionalFailure
+
 testPlainCompletion :: Assertion
 testPlainCompletion = do
   completion <- completionOutput False 0 []
@@ -102,7 +138,9 @@
   assertContains "--database-url\tPostgreSQL URI" flags
   assertContains "--lock-timeout\tWait at most" flags
   assertContains "--no-wait\tFail immediately" flags
-  assertContains "--statement-timeout\tPositive PostgreSQL" flags
+  assertContains "--wait\tWait indefinitely" flags
+  assertContains "--statement-timeout\tSet a positive PostgreSQL" flags
+  assertContains "--no-statement-timeout\tRun without" flags
   assertContains "--json\tEmit JSON schema version 1" flags
 
 completionOutput :: Bool -> Int -> [String] -> IO String
@@ -158,6 +196,12 @@
       let (message, _) = renderFailure failure "pg-migrate-cli-help-fixture"
        in error message
     CompletionInvoked _ -> error "unexpected completion"
+
+parsedExecution :: [String] -> ExecutionOptions
+parsedExecution arguments =
+  case parseSuccess ("up" : arguments) of
+    Up UpOptions {execution} -> execution
+    parsedCommand -> error ("expected up command, received: " <> show parsedCommand)
 
 parseFailure :: [String] -> IO String
 parseFailure arguments =
