fix(chain): 修评审 CRITICAL+HIGH — 链网关按 session 重建/日志脱敏/resume 原子化+所有权/死导入
- CRITICAL #1:链 write/review 节点经 gateway_builder 按节点自建 session 现建网关,
usage_ledger sink 绑活 session,随节点 commit 持久化;run_chain_job 不再转发请求网关
(其 session 在 BackgroundTask 跑时已关闭,记账行被静默丢弃)。新增 get_chain_gateway_builder
缝(仿 digest builder),get_chain_gateway 退化为纯 503 凭据预检。守不变量 #1。
- HIGH #2:chain_runner 失败日志不再记 str(exc)(可能含 key/连接串/LLM 输出),改记
_classify_job_error 脱敏文案 + exc_type(设计 §5)。
- HIGH #3:resume 端点原子抢占 awaiting→running(JobRepo.claim_awaiting_to_running 条件
UPDATE),抢不到 → 409,防并发 resume 双 Command(resume) 损坏图。
- HIGH #4:resume 校验 job.project_id == project_id(JobView 新增 project_id),不匹配 → 404。
- HIGH #5:resume 返回新 ChainResumeAccepted{job_id,chain_key},去掉无意义哨兵 start/count=0。
- HIGH #6:删 nodes.py 死导入 extract_conflicts(import + __all__)。
- 测试 #7:e2e 断言链跑后 usage_ledger 有行(#1 回归守卫)+ chapter_reviews 每章一行;
新增 claim 原子抢占单测 + resume 跨项目 404 / 并发 409 端点测。
This commit is contained in:
@@ -217,12 +217,15 @@ def _build_app(adapter: _FakeChainAdapter, saver: MemorySaver, e2e_sm: Any) -> A
|
||||
from ww_api.services.chain_deps import get_checkpointer_factory
|
||||
from ww_api.services.project_deps import (
|
||||
get_chain_gateway,
|
||||
get_chain_gateway_builder,
|
||||
get_digest_gateway_builder,
|
||||
get_session_factory,
|
||||
)
|
||||
|
||||
app = create_app()
|
||||
app.dependency_overrides[get_chain_gateway] = _chain_gateway_override(adapter)
|
||||
# 链 write/review 节点经 builder 在节点 session 上现建网关(ledger 绑节点 session,不变量 #1)。
|
||||
app.dependency_overrides[get_chain_gateway_builder] = _digest_builder_override(adapter)
|
||||
app.dependency_overrides[get_session_factory] = lambda: e2e_sm
|
||||
app.dependency_overrides[get_checkpointer_factory] = _memsaver_override(saver)
|
||||
app.dependency_overrides[get_digest_gateway_builder] = _digest_builder_override(adapter)
|
||||
@@ -302,6 +305,35 @@ async def test_chain_two_chapters_no_conflict_full_auto(
|
||||
)
|
||||
assert [d.chapter_no for d in digests] == [1, 2]
|
||||
|
||||
# 回归守卫(审评 #1):链每次 gateway.run 都应落 usage_ledger 行——证明网关 ledger
|
||||
# 绑节点活 session、节点 commit 持久化。
|
||||
# 修复前:请求网关 session 已关闭,行被静默丢弃。
|
||||
ledger_rows = (
|
||||
(
|
||||
await verify.execute(
|
||||
select(UsageLedger).where(UsageLedger.project_id == project_uuid)
|
||||
)
|
||||
)
|
||||
.scalars()
|
||||
.all()
|
||||
)
|
||||
# 两章 × (1 写 + 四审 + 1 digest);至少应有若干条,绝不为空。
|
||||
assert len(ledger_rows) > 0, "chain usage_ledger 行不应为空(成本记账断裂回归守卫)"
|
||||
|
||||
# 每审过一章应在 chapter_reviews 留痕(不变量 #3 只读留痕;审评 #7b)。
|
||||
review_rows = (
|
||||
(
|
||||
await verify.execute(
|
||||
select(ChapterReview)
|
||||
.where(ChapterReview.project_id == project_uuid)
|
||||
.order_by(ChapterReview.chapter_no)
|
||||
)
|
||||
)
|
||||
.scalars()
|
||||
.all()
|
||||
)
|
||||
assert {r.chapter_no for r in review_rows} == {1, 2}
|
||||
|
||||
job_rows = (
|
||||
(await verify.execute(select(Job).where(Job.project_id == project_uuid)))
|
||||
.scalars()
|
||||
|
||||
Reference in New Issue
Block a user