feat(v2): 完善配置中心与可替换轨迹质检并联动预审依据

This commit is contained in:
2026-10-01 17:13:02 +08:00
parent 1adbe16cb3
commit e604d177cb
42 changed files with 1285 additions and 83 deletions
+8 -8
View File
@@ -815,9 +815,9 @@ def propose_knowledge_candidate(project_id: str, payload: CandidateInput, reques
return blocked
def action():
role(request, ("admin",))
with _db() as db:
project = _project(db, project_id)
# 组件 id 由服务端生成:调用方不该靠自报 id 影响治理(03 §9.4 同口径)
body = dict(payload.content, kind=payload.kind, name=payload.title,
id=store.uid(payload.kind + ".card"), version=payload.version,
scope=project["data_domain"])
@@ -840,13 +840,13 @@ def revise_knowledge_candidate(card_id: str, payload: ReviseInput, request: Requ
不该占着 SQLite 连接。
"""
def action():
role(request, ("admin",))
with _db() as db:
draft = knowledge_cards.current_draft(db, card_id)
card = knowledge_cards.draft_card(db, draft["id"])
blocked = scope(request, draft["project_id"])
if blocked is not None:
return blocked
# 模型调用放在数据库连接之外:自然语言解释可能耗时数十秒,不该占着 SQLite 连接
changes, note = experience_extraction.edit_changes(card, payload.model_dump())
with _db() as db:
return knowledge_cards.revise(db, card_id, changes, _actor(request), note,
@@ -872,13 +872,13 @@ def transition_knowledge_candidate(card_id: str, payload: TransitionInput, reque
if blocked is not None:
return blocked
if payload.action == "evaluate":
# 角色门禁与既有 /components/{id}/actions 一致:新路由不得比既有入口宽松
role(request, ("admin", "reviewer"))
# 新版配置仅管理员处理;独立发布人与提议人须不同
role(request, ("admin",))
from services.component_evaluation import evaluate
with _db() as db:
return evaluate(db, draft["id"], _actor(request))
if payload.action == "publish":
role(request, ("admin", "reviewer"))
role(request, ("admin",))
with _db() as db:
return knowledge_cards.publish(db, draft["id"], _actor(request),
request.state.identity.get("preview", False))
@@ -909,7 +909,6 @@ def list_review_plans(project_id: str, request: Request):
def propose_review_plan(project_id: str, payload: ReviewPlanInput, request: Request):
"""装配一份方案草稿。
这是"已发布卡片被选入方案"的入口:`skills`/`rules` 里填卡片组件 id 即可,
但草稿或已撤回的组件会在装配与发布两处被拒(BR-27 / AC-28)。
"""
blocked = scope(request, project_id)
@@ -917,6 +916,7 @@ def propose_review_plan(project_id: str, payload: ReviewPlanInput, request: Requ
return blocked
def action():
role(request, ("admin",))
with _db() as db:
project = _project(db, project_id)
body = dict(payload.model_dump(), kind="plan", scope=project["data_domain"],
@@ -938,12 +938,12 @@ def transition_review_plan(plan_ref: str, payload: TransitionInput, request: Req
if blocked is not None:
return blocked
if payload.action == "evaluate":
role(request, ("admin", "reviewer"))
role(request, ("admin",))
from services.component_evaluation import evaluate
with _db() as db:
return evaluate(db, draft["id"], _actor(request))
if payload.action == "publish":
role(request, ("admin", "reviewer"))
role(request, ("admin",))
with _db() as db:
return registry.release(db, draft["id"], _actor(request),
request.state.identity.get("preview", False))