Răsfoiți Sursa

fix: deduplicate chapter summaries on append and bootstrap

- appendChapterSummary: remove existing rows with same chapter number
  before appending, preventing duplicates from interrupted retries
- state-bootstrap: deduplicate parsed markdown rows by chapter number
  (keep last occurrence), preventing validator from rejecting stale data
Ma 7 luni în urmă
părinte
comite
c182d0c776

+ 15 - 1
packages/core/src/agents/writer.ts

@@ -953,7 +953,21 @@ ${overrides}\n`;
       .join("\n");
 
     if (dataRows) {
-      await writeFile(summaryPath, `${existing.trimEnd()}\n${dataRows}\n`, "utf-8");
+      // Deduplicate: remove existing rows with the same chapter number before appending
+      const newChapterNums = new Set(
+        dataRows.split("\n")
+          .map((line) => line.split("|")[1]?.trim())
+          .filter((ch) => ch && /^\d+$/.test(ch)),
+      );
+      const deduped = existing
+        .split("\n")
+        .filter((line) => {
+          if (!line.startsWith("|")) return true;
+          const chNum = line.split("|")[1]?.trim();
+          return !chNum || !newChapterNums.has(chNum);
+        })
+        .join("\n");
+      await writeFile(summaryPath, `${deduped.trimEnd()}\n${dataRows}\n`, "utf-8");
     }
   }
 

+ 7 - 1
packages/core/src/state/state-bootstrap.ts

@@ -275,8 +275,14 @@ async function loadOrBootstrapSummaries(params: {
   }
 
   const markdown = await readFile(join(params.storyDir, "chapter_summaries.md"), "utf-8").catch(() => "");
+  const rawRows = parseChapterSummariesMarkdown(markdown);
+  // Deduplicate: keep last occurrence per chapter number (latest is most up-to-date)
+  const deduped = new Map<number, (typeof rawRows)[number]>();
+  for (const row of rawRows) {
+    deduped.set(row.chapter, row);
+  }
   const summariesState = ChapterSummariesStateSchema.parse({
-    rows: parseChapterSummariesMarkdown(markdown),
+    rows: [...deduped.values()].sort((a, b) => a.chapter - b.chapter),
   });
   await writeFile(params.statePath, JSON.stringify(summariesState, null, 2), "utf-8");
   params.createdFiles.push("chapter_summaries.json");