Jelajahi Sumber

feat: 移除保存前自动审稿拦截 + 版本号升级至 v3.1.0

- 删除「保存为大纲」和「保存为正式章节」时自动弹出审稿对话框的拦截逻辑
- 删除 reviewBeforeSave 配置项及设置界面开关
- 清理 outline-chat-panel 中大纲质量检查死代码(状态、回调、UI、对话框)
- 清理 outline-quality-check 中未使用的质量反馈函数
- 保留审稿中心手动审稿功能不受影响
- 版本号 3.0.9 → 3.1.0
Mochocyang 1 bulan lalu
induk
melakukan
b92fc0fe9f

+ 1 - 1
package.json

@@ -1,7 +1,7 @@
 {
   "name": "qmai",
   "private": true,
-  "version": "3.0.9",
+  "version": "3.1.0",
   "license": "GPL-3.0-or-later",
   "type": "module",
   "scripts": {

+ 1 - 1
src-tauri/Cargo.lock

@@ -5825,7 +5825,7 @@ checksum = "e0c5ccf5294c6ccd63a74f1565028353830a9c2f5eb0c682c355c471726a6e3f"
 
 [[package]]
 name = "qmai"
-version = "3.0.9"
+version = "3.1.0"
 dependencies = [
  "arrow-array",
  "arrow-schema",

+ 1 - 1
src-tauri/Cargo.toml

@@ -1,6 +1,6 @@
 [package]
 name = "qmai"
-version = "3.0.9"
+version = "3.1.0"
 description = "QMAI - AI writing system for long-form novels"
 authors = ["Mochocyang"]
 edition = "2021"

+ 1 - 1
src-tauri/tauri.conf.json

@@ -1,7 +1,7 @@
 {
   "$schema": "https://schema.tauri.app/config/2",
   "productName": "QMaiWrite",
-  "version": "3.0.9",
+  "version": "3.1.0",
   "identifier": "com.qingmuai.writer",
   "build": {
     "beforeDevCommand": "npm run dev",

+ 0 - 38
src/components/layout/preview-panel.tsx

@@ -4,7 +4,6 @@ import { Check, MoreHorizontal, X } from "lucide-react"
 import { useWikiStore } from "@/stores/wiki-store"
 import { resolveDefaultModel, resolveNovelModel, formatResolvedModelLabel } from "@/lib/novel/model-resolver"
 import type { FinalChapterSavePhase } from "@/stores/wiki-store"
-import { useReviewStore } from "@/stores/review-store"
 import { deleteFile, fileExists, readFile, writeFileAtomic, writeFileIfAbsent, listDirectory } from "@/commands/fs"
 import { normalizePath } from "@/lib/path-utils"
 import { getFileCategory, isBinary } from "@/lib/file-types"
@@ -664,18 +663,14 @@ export function PreviewPanel() {
 
   const phaseLabelMap: Record<FinalChapterSavePhase, string> = {
     saving: t("novel.chapter.savingAsFinal"),
-    reviewing: t("novel.chapter.reviewInProgress"),
     saved: t("novel.chapter.savedAsFinal"),
     reingesting: t("novel.chapter.savingAsFinal"),
     ingested: t("novel.chapter.ingestSuccess"),
-    blocked_by_review: t("novel.chapter.reviewBlockedWithErrors"),
     ingest_failed: t("novel.chapter.ingestFailedRetry"),
     ingest_no_llm: t("novel.chapter.ingestNoLlmKey"),
     ingest_no_chapter_number: "章节已保存为正式章节,但快照生成失败:章节编号无效。请在章节2栏中重命名章节以修正编号。",
     ingest_not_final: "章节已保存为正式章节,但快照生成失败:章节状态异常,请检查章节是否正确标记为终稿。",
     ingest_extract_failed: "章节已保存为正式章节,但快照生成失败:LLM 生成超时或返回格式错误,请重试。",
-    review_warnings: t("novel.chapter.reviewWarningsButProceeding"),
-    review_failed_proceed: t("novel.chapter.reviewFailedProceeding"),
   }
 
   const visibleSaveStatus = (() => {
@@ -831,39 +826,6 @@ export function PreviewPanel() {
 
     const novelConfig = useWikiStore.getState().novelConfig
 
-    if (novelConfig.reviewBeforeSave) {
-      updatePhase(true, "reviewing")
-      try {
-        const chapterNumber = chapterFrontmatter.chapterNumber as number | undefined
-        const { reviewChapter } = await import("@/lib/novel/review-adapter")
-        const results = await reviewChapter(project.path, currentContent, chapterNumber)
-        if (results.length > 0) {
-          const reviewStore = useReviewStore.getState()
-          reviewStore.addNovelReviewEntry({
-            id: `chapter-${chapterNumber}-${Date.now()}`,
-            chapterNumber: chapterNumber ?? 0,
-            results,
-            createdAt: new Date().toISOString(),
-            resolved: false,
-          })
-        }
-        const errors = results.filter(r => r.severity === "error")
-        const warnings = results.filter(r => r.severity === "warning")
-
-        if (errors.length > 0) {
-          updatePhase(false, "blocked_by_review", { count: errors.length, warnings: warnings.length })
-          setIsSavingFinal(false)
-          return
-        }
-
-        if (warnings.length > 0) {
-          updatePhase(true, "review_warnings", { count: warnings.length })
-        }
-      } catch {
-        updatePhase(true, "review_failed_proceed")
-      }
-    }
-
     try {
       if (saveTimerRef.current) {
         clearTimeout(saveTimerRef.current)

+ 0 - 20
src/components/settings/sections/novel-section.tsx

@@ -389,26 +389,6 @@ export function NovelSection({ draft, setDraft }: Props) {
             </button>
           </div>
 
-          <div className="flex items-center justify-between gap-3">
-            <div className="flex items-center gap-1.5">
-              <Label>{t("novel.settings.reviewBeforeSave")}</Label>
-              {settingTooltip("reviewBeforeSaveHint")}
-            </div>
-            <button
-              type="button"
-              onClick={() => updateNovelConfig({ reviewBeforeSave: !draft.novelConfig.reviewBeforeSave })}
-              className={`relative inline-flex h-6 w-11 shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors ${
-                draft.novelConfig.reviewBeforeSave ? "bg-primary" : "bg-input"
-              }`}
-            >
-              <span
-                className={`pointer-events-none inline-block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform ${
-                  draft.novelConfig.reviewBeforeSave ? "translate-x-5" : "translate-x-0"
-                }`}
-              />
-            </button>
-          </div>
-
           <div className="flex items-center justify-between gap-3">
             <div className="flex items-center gap-1.5">
               <Label>{t("novel.settings.deepPreviousChaptersAnalysis")}</Label>

+ 0 - 154
src/components/sources/outline-chat-panel.tsx

@@ -56,15 +56,6 @@ import { OutlineWizardDialog } from "@/components/sources/outline-wizard-dialog"
 import { NovelGenerationRequestMessage } from "@/components/sources/novel-generation-request-message";
 import { OutlineMultiAgentPanel } from "@/components/sources/outline-multi-agent-panel";
 import { TooltipProvider } from "@/components/ui/tooltip";
-import { Button } from "@/components/ui/button";
-import {
-  Dialog,
-  DialogContent,
-  DialogDescription,
-  DialogFooter,
-  DialogHeader,
-  DialogTitle,
-} from "@/components/ui/dialog";
 import { OUTLINE_SECTION_GENERATION_CONFIGS } from "@/lib/novel/outline-section-configs";
 import {
   buildOutlineWizardPrompt,
@@ -109,13 +100,6 @@ import {
   type CharacterAgentResult,
 } from "@/lib/novel/character-multi-agent";
 import { classifyOutlineSaveTarget } from "@/lib/novel/outline-save-classifier";
-import {
-  buildOutlineGenerationQualityFeedback,
-  formatChapterOutlineQualityReport,
-  isLikelyChapterOutline,
-  type OutlineGenerationQualityFeedback,
-  summarizeChapterOutlineQuality,
-} from "@/lib/novel/outline-quality-check";
 import {
   characterDraftsToSaveRequests,
   extractBodyContent,
@@ -1470,15 +1454,6 @@ export function OutlineChatPanel({ onClose }: { onClose: () => void }) {
       dedupeKey: `outline-operation:${message}`,
     });
   }, []);
-  const [qualityFeedbackStates, setQualityFeedbackStates] =
-    useState<Record<string, OutlineGenerationQualityFeedback>>({});
-  type QualityConfirmState = {
-    feedback: OutlineGenerationQualityFeedback;
-    requests: OutlineSaveRequest[];
-  };
-  const [qualityConfirmStates, setQualityConfirmStates] = useState<Record<string, QualityConfirmState>>({});
-  const qualityFeedbackState = activeConversationId ? qualityFeedbackStates[activeConversationId] ?? null : null;
-  const qualityConfirmState = activeConversationId ? qualityConfirmStates[activeConversationId] ?? null : null;
   const [saveConfirmState, setSaveConfirmState] = useState<{
     title: string;
     mode: "normal" | "character";
@@ -1490,7 +1465,6 @@ export function OutlineChatPanel({ onClose }: { onClose: () => void }) {
   const scrollRef = useRef<HTMLDivElement>(null);
   const userScrolledUpRef = useRef(false);
   const lastScrollTopRef = useRef(0);
-  const pendingRepairMetaRef = useRef<Record<string, OutlineSaveRequest[]>>({});
   const pendingNormalSaveRequestsRef = useRef<OutlineSaveRequest[]>([]);
 
   // Auto-scroll
@@ -1608,32 +1582,11 @@ export function OutlineChatPanel({ onClose }: { onClose: () => void }) {
       if (!project || !canApply()) return;
       const parsed = parseOutlineSaveRequests(assistantContent);
       if (parsed.requests.length === 0) {
-        const repairMeta = pendingRepairMetaRef.current[conversationId];
-        if (repairMeta && repairMeta.length > 0) {
-          const body = extractBodyContent(assistantContent);
-          if (body && isLikelyChapterOutline(body, repairMeta[0].fileName)) {
-            const fallbackRequests: OutlineSaveRequest[] = repairMeta.map((meta) => ({
-              ...meta,
-              content: body,
-            }));
-            delete pendingRepairMetaRef.current[conversationId];
-            if (!canApply()) return;
-            setSaveConfirmState({
-              title: "请确认要保存的修订大纲",
-              mode: "normal",
-              requests: fallbackRequests,
-              characterDrafts: [],
-            });
-            setSaveStatus("检测到可保存大纲,请确认后写入。");
-            return;
-          }
-        }
         if (parsed.errors.length > 0) {
           showOutlineAutoSaveError(formatOutlineSaveParseFeedback(parsed.errors));
         }
         return;
       }
-      delete pendingRepairMetaRef.current[conversationId];
 
       if (!canApply()) return;
       try {
@@ -2119,7 +2072,6 @@ export function OutlineChatPanel({ onClose }: { onClose: () => void }) {
 
         let finalText = "";
         let capturedSuccessfulResults: OutlineSubAgentResult[] = [];
-        let capturedCharacterResults: CharacterAgentResult[] = [];
 
         const currentIntentContext = intentContextsRef.current[capturedConvId];
         const isCharacterMultiAgentTask =
@@ -2219,8 +2171,6 @@ export function OutlineChatPanel({ onClose }: { onClose: () => void }) {
               },
             });
 
-            capturedCharacterResults = multiAgentResult.characters;
-
             if (multiAgentResult.characters.length === 0) {
               finalText = await runSingleAgentFallback();
             } else {
@@ -3693,55 +3643,6 @@ export function OutlineChatPanel({ onClose }: { onClose: () => void }) {
     void useOutlineChatStore.getState().saveToDisk();
   }, []);
 
-  const handleRepairQualityFeedback = useCallback(() => {
-    if (!activeConversationId) return;
-    const capturedConvId = activeConversationId;
-    const repairPrompt = qualityFeedbackState?.repairPrompt;
-    if (!repairPrompt) return;
-    setQualityFeedbackStates((states) => setOutlineSessionValue(states, capturedConvId, null));
-    void handleSend(repairPrompt, [], { conversationId: capturedConvId, clearDraft: false, forceRefresh: true });
-  }, [activeConversationId, handleSend, qualityFeedbackState]);
-
-  const handleSaveAsIs = useCallback(async () => {
-    if (!project || !qualityConfirmState || !activeConversationId) return;
-    const capturedConvId = activeConversationId;
-    const { requests } = qualityConfirmState;
-    setQualityConfirmStates((states) => setOutlineSessionValue(states, capturedConvId, null));
-    setQualityFeedbackStates((states) => setOutlineSessionValue(states, capturedConvId, null));
-    if (requests.length === 0) return;
-    setSaveStatus("正在保存大纲...");
-    try {
-      const projectPath = normalizePath(project.path);
-      const saveResult = await saveOutlineSaveRequests({
-        outlineRoot: `${projectPath}/wiki/outlines`,
-        requests,
-        createDirectory,
-        fileExists,
-        readFile,
-        writeFile,
-      });
-      if (saveResult.saved.length > 0) {
-        await refreshProjectState(projectPath);
-        const names = saveResult.saved.map((item) => item.fileName).join("、");
-        setSaveStatus(`已保存 ${saveResult.saved.length} 个大纲文件:${names}`);
-      } else if (saveResult.errors.length > 0) {
-        setSaveStatus(`保存失败:${saveResult.errors.slice(0, 2).join(";")}`);
-      }
-    } catch (error) {
-      setSaveStatus(`保存失败:${error instanceof Error ? error.message : String(error)}`);
-    }
-  }, [activeConversationId, project, qualityConfirmState, createDirectory, fileExists, readFile, writeFile]);
-
-  const handleAutoFixFromModal = useCallback(() => {
-    if (!activeConversationId) return;
-    const capturedConvId = activeConversationId;
-    const repairPrompt = qualityConfirmState?.feedback.repairPrompt;
-    if (!repairPrompt) return;
-    pendingRepairMetaRef.current[capturedConvId] = qualityConfirmState.requests;
-    setQualityConfirmStates((states) => setOutlineSessionValue(states, capturedConvId, null));
-    setQualityFeedbackStates((states) => setOutlineSessionValue(states, capturedConvId, null));
-    void handleSend(repairPrompt, [], { conversationId: capturedConvId, clearDraft: false, forceRefresh: true });
-  }, [activeConversationId, handleSend, qualityConfirmState]);
 
   const requestDeleteConversation = useCallback((conversationId: string) => {
     if (runStates[conversationId]?.status === "running") {
@@ -3941,18 +3842,6 @@ export function OutlineChatPanel({ onClose }: { onClose: () => void }) {
             : null}
         </div>
         <div className="ml-auto flex shrink-0 items-center gap-1">
-          {qualityFeedbackState && qualityFeedbackState.status !== "pass" ? (
-            <button
-              type="button"
-              disabled={isStreaming}
-              onClick={handleRepairQualityFeedback}
-              aria-label="修订生成后质量检查发现的问题"
-              className="rounded-md border border-amber-300 bg-amber-50 px-2 py-1 text-xs text-amber-800 hover:bg-amber-100 disabled:cursor-not-allowed disabled:opacity-50"
-              title={qualityFeedbackState.summary}
-            >
-              修订质量问题
-            </button>
-          ) : null}
           <button
             onClick={onClose}
             className="rounded p-1 text-muted-foreground hover:bg-accent"
@@ -4151,49 +4040,6 @@ export function OutlineChatPanel({ onClose }: { onClose: () => void }) {
             onConfirm={executeConfirmedOutlineSave}
           />
         ) : null}
-        {qualityConfirmState ? (
-          <Dialog open onOpenChange={(open) => {
-            if (!open && activeConversationId) {
-              setQualityConfirmStates((states) => setOutlineSessionValue(states, activeConversationId, null));
-            }
-          }}>
-            <DialogContent className="max-w-lg">
-              <DialogHeader>
-                <DialogTitle>大纲质量检查发现可修复项</DialogTitle>
-                <DialogDescription className="text-left">
-                  {qualityConfirmState.feedback.summary}
-                </DialogDescription>
-              </DialogHeader>
-              <div className="max-h-48 overflow-y-auto space-y-1 py-2">
-                {qualityConfirmState.feedback.issues.slice(0, 10).map((issue, index) => (
-                  <div key={index} className="flex items-start gap-2 text-sm">
-                    <span className="mt-0.5 shrink-0 text-amber-600">·</span>
-                    <span className="text-muted-foreground">{issue}</span>
-                  </div>
-                ))}
-                {qualityConfirmState.feedback.issues.length > 10 ? (
-                  <div className="text-xs text-muted-foreground">
-                    另有 {qualityConfirmState.feedback.issues.length - 10} 项未列出
-                  </div>
-                ) : null}
-              </div>
-              <DialogFooter className="gap-2">
-                <Button
-                  variant="outline"
-                  onClick={handleSaveAsIs}
-                >
-                  按当前内容保存
-                </Button>
-                <Button
-                  onClick={handleAutoFixFromModal}
-                  disabled={isStreaming}
-                >
-                  自动修复
-                </Button>
-              </DialogFooter>
-            </DialogContent>
-          </Dialog>
-        ) : null}
       </div>
     </div>
   );

+ 0 - 83
src/lib/novel/outline-quality-check.ts

@@ -27,14 +27,6 @@ export interface ChapterOutlineQualitySummary {
   items: QualityCheckItem[];
 }
 
-export interface OutlineGenerationQualityFeedback {
-  status: "pass" | "warn" | "error";
-  title: string;
-  summary: string;
-  issues: string[];
-  repairPrompt: string;
-}
-
 /**
  * 对卷纲 Markdown 内容执行全部质量检查。
  *
@@ -107,81 +99,6 @@ export function summarizeChapterOutlineQuality(content: string): ChapterOutlineQ
   };
 }
 
-export function formatChapterOutlineQualityReport(
-  summary: ChapterOutlineQualitySummary,
-  options: { maxIssues?: number; includeWarnings?: boolean } = {},
-): string {
-  const maxIssues = Math.max(1, options.maxIssues ?? 5);
-  const errors = Array.from(new Set(summary.errors));
-  const warnings = Array.from(new Set(summary.warnings));
-
-  if (errors.length === 0) {
-    if (warnings.length === 0) return "章纲质量检查通过。";
-    const warningPreview = warnings.slice(0, maxIssues).join(";");
-    const remainingWarnings = warnings.length - Math.min(warnings.length, maxIssues);
-    return [
-      `章纲质量检查通过,但有 ${warnings.length} 项提醒。`,
-      `建议完善:${warningPreview}${remainingWarnings > 0 ? `;另有 ${remainingWarnings} 项未列出` : ""}。`,
-    ].join("");
-  }
-
-  const issuePreview = errors.slice(0, maxIssues).join(";");
-  const remainingIssues = errors.length - Math.min(errors.length, maxIssues);
-  const warningText =
-    options.includeWarnings && warnings.length > 0
-      ? `,另有 ${warnings.length} 项提醒`
-      : "";
-
-  return [
-    `章纲质量检查未通过:${errors.length} 项错误${warningText}。`,
-    `主要缺失:${issuePreview}${remainingIssues > 0 ? `;另有 ${remainingIssues} 项未列出` : ""}。`,
-    "请让 AI 按章纲标准补齐后重新输出完整章纲,再保存。",
-  ].join("");
-}
-
-export function buildOutlineGenerationQualityFeedback(input: {
-  fileType: string;
-  fileName: string;
-  content: string;
-}): OutlineGenerationQualityFeedback | null {
-  if (input.fileType !== "chapter-outline" && !isLikelyChapterOutline(input.content, input.fileName)) {
-    return null;
-  }
-
-  const summary = summarizeChapterOutlineQuality(input.content);
-  const issues = Array.from(new Set([...summary.errors, ...summary.warnings]));
-  if (issues.length === 0) {
-    return {
-      status: "pass",
-      title: "生成后质量检查",
-      summary: `${input.fileName} 章纲质量检查通过。`,
-      issues: [],
-      repairPrompt: "",
-    };
-  }
-
-  const status: "warn" | "error" = summary.valid ? "warn" : "error";
-  const preview = issues.slice(0, 5).join(";");
-  const remaining = issues.length > 5 ? `;另有 ${issues.length - 5} 项未列出` : "";
-  return {
-    status,
-    title: "生成后质量检查",
-    summary: `${input.fileName} 存在 ${issues.length} 个可修复项:${preview}${remaining}。`,
-    issues,
-    repairPrompt: [
-      `请按章纲标准修订「${input.fileName}」。`,
-      "必须补齐以下可修复项,不要改变已确认的剧情方向:",
-      ...issues.slice(0, 12).map((issue, index) => `${index + 1}. ${issue}`),
-      "",
-      "重要要求:",
-      "1. 必须输出修订后的完整章纲正文(使用标准 Markdown 格式),不能只输出修改摘要或说明。",
-      "2. 在回复末尾附加 outlineSaveRequest JSON,必须包含完整 content,以及 targetFolder、fileName、fileType、writeMode、referencedSkills、sourceIntent。fileType 只能用英文枚举(outline/volume-outline/chapter-outline/character/setting/foreshadowing/organization/quality-report),writeMode 只能用英文枚举(create/append/replace/patch),targetFolder 必须是相对路径(如「章纲」),禁止绝对路径。",
-      "3. 系统解析后会弹出确认,用户确认后才写入文件;禁止省略 content。",
-      "4. 正文中必须包含完整的章纲所有必填章节,不能省略未修改的部分。",
-    ].join("\n"),
-  };
-}
-
 export function isLikelyChapterOutline(content: string, fileName = ""): boolean {
   const text = `${fileName}\n${content}`;
   return /章纲|细纲|章节细纲|章节计划|本章目标|核心事件|场景顺序|章尾钩子/.test(text);

+ 0 - 2
src/lib/project-store.integration.test.ts

@@ -59,7 +59,6 @@ function makeNovelConfig(overrides: Partial<NovelConfig> = {}): NovelConfig {
     chapterTargetChars: 3000,
     autoIngestOnSave: true,
     autoExtractOnImport: true,
-    reviewBeforeSave: false,
     deepPreviousChaptersAnalysis: false,
     deepChapterReview: true,
     reviewReasoningEffort: "high",
@@ -198,7 +197,6 @@ describe("novelConfig — project-directory persistence", () => {
       recentSummaryWindow: 6,
       searchTopK: 8,
       autoIngestOnSave: false,
-      reviewBeforeSave: true,
       writingModel: "writer",
       reviewModel: "reviewer",
       summaryModel: "summarizer",

+ 0 - 1
src/lib/project-store.ts

@@ -716,7 +716,6 @@ function normalizeNovelConfig(
     chapterTargetChars: Math.max(500, Math.min(20000, config.chapterTargetChars ?? DEFAULT_NOVEL_CONFIG.chapterTargetChars)),
     autoIngestOnSave: config.autoIngestOnSave ?? DEFAULT_NOVEL_CONFIG.autoIngestOnSave,
     autoExtractOnImport: config.autoExtractOnImport ?? DEFAULT_NOVEL_CONFIG.autoExtractOnImport,
-    reviewBeforeSave: config.reviewBeforeSave ?? DEFAULT_NOVEL_CONFIG.reviewBeforeSave,
     deepPreviousChaptersAnalysis: config.deepPreviousChaptersAnalysis ?? DEFAULT_NOVEL_CONFIG.deepPreviousChaptersAnalysis,
     deepChapterReview: config.deepChapterReview ?? DEFAULT_NOVEL_CONFIG.deepChapterReview,
     reviewReasoningEffort: config.reviewReasoningEffort ?? DEFAULT_NOVEL_CONFIG.reviewReasoningEffort,

+ 0 - 6
src/stores/wiki-store.ts

@@ -306,7 +306,6 @@ export interface NovelConfig {
   chapterTargetChars: number
   autoIngestOnSave: boolean
   autoExtractOnImport: boolean
-  reviewBeforeSave: boolean
   /** 深度生成阶段0:读取并 LLM 分析前几章完整正文。关闭可省一次调用,记忆库的近期摘要与上一章结尾仍会注入(默认关)。 */
   deepPreviousChaptersAnalysis: boolean
   /** 深度生成阶段4-5:AI 审稿 + 自动返修。关闭则初稿直接进入简单审查与去AI味,省审稿与返修调用(默认开)。 */
@@ -340,7 +339,6 @@ export const DEFAULT_NOVEL_CONFIG: NovelConfig = {
   chapterTargetChars: 3000,
   autoIngestOnSave: true,
   autoExtractOnImport: true,
-  reviewBeforeSave: false,
   deepPreviousChaptersAnalysis: false,
   deepChapterReview: true,
   reviewReasoningEffort: "high",
@@ -471,18 +469,14 @@ interface AsyncTaskState extends BaseTaskState {
 
 export type FinalChapterSavePhase =
   | "saving"
-  | "reviewing"
   | "saved"
   | "reingesting"
   | "ingested"
-  | "blocked_by_review"
   | "ingest_failed"
   | "ingest_no_llm"
   | "ingest_no_chapter_number"
   | "ingest_not_final"
   | "ingest_extract_failed"
-  | "review_warnings"
-  | "review_failed_proceed"
 
 export interface FinalChapterSaveState extends BaseTaskState {
   filePath: string