feat(orchestrator): 续写链前一章无已验收终稿发 warning——静默丢前文引子可观测(CR-L1)

This commit is contained in:
Yaojia Wang
2026-07-08 13:02:30 +02:00
parent 832ab7dfa1
commit c9ffada503
2 changed files with 63 additions and 1 deletions

View File

@@ -13,6 +13,7 @@ from collections.abc import AsyncIterator
from contextlib import asynccontextmanager
from typing import Any
import structlog
from langchain_core.runnables import RunnableConfig
from langgraph.checkpoint.memory import MemorySaver
from langgraph.types import Command
@@ -446,6 +447,57 @@ async def test_write_chapter_continue_volume_injects_prior_accepted_text() -> No
assert "前文正文" in write_input # build_continuation_context 的小节标题
async def test_continue_volume_warns_when_prior_chapter_unaccepted() -> None:
"""continue_volume 写第 2 章但第 1 章无已验收终稿 → 静默丢前文引子须发 warningCR-L1"""
h = _make_harness(conflicts=[])
# accepted_store 故意留空:第 1 章尚无已验收正文 → 续写丢失前文引子(静默降级)。
state = initial_chain_state(
project_id=PROJECT,
user_id=USER,
start_chapter_no=2,
count=1,
chain_key="continue_volume",
)
with structlog.testing.capture_logs() as logs:
await write_chapter(
state,
gateway_builder=h["gateway_builder"],
session_factory=h["session_factory"],
memory_repos_factory=h["memory_repos_factory"],
chapter_repo_factory=h["chapter_repo_factory"],
assemble=h["assemble"],
)
warning = next(e for e in logs if e["event"] == "chain_prior_accepted_missing")
assert warning["log_level"] == "warning"
assert warning["chapter_no"] == 2
async def test_continue_volume_first_chapter_does_not_warn() -> None:
"""第 1 章前一章号 < 1无前文属预期非降级→ 不应发缺前文 warning。"""
h = _make_harness(conflicts=[])
state = initial_chain_state(
project_id=PROJECT,
user_id=USER,
start_chapter_no=1,
count=1,
chain_key="continue_volume",
)
with structlog.testing.capture_logs() as logs:
await write_chapter(
state,
gateway_builder=h["gateway_builder"],
session_factory=h["session_factory"],
memory_repos_factory=h["memory_repos_factory"],
chapter_repo_factory=h["chapter_repo_factory"],
assemble=h["assemble"],
)
assert not [e for e in logs if e["event"] == "chain_prior_accepted_missing"]
async def test_continue_volume_chain_second_chapter_sees_first_chapter_text() -> None:
"""全图 E2Econtinue_volume 两章——第 2 章请求上下文含第 1 章正文(不变量 #1/#5"""
h = _make_harness(conflicts=[])

View File

@@ -325,7 +325,17 @@ async def _read_prior_accepted(
if chapter_no <= 1:
return ""
view = await chapter_repo.latest_accepted(project_id, chapter_no - 1)
return view.content if view is not None else ""
if view is None:
# 静默降级须可观测CR-L1续写式链本章续接的前一章尚无已验收终稿——续写会丢失
# 前文引子(降级为 build_continuation_context 的占位)。发 warning 便于查错,勿静默吞。
log.warning(
"chain_prior_accepted_missing",
project_id=str(project_id),
chapter_no=chapter_no,
prior_chapter_no=chapter_no - 1,
)
return ""
return view.content
async def _commit(session: CommitSession) -> None: