Audit batch 6: B1 zero-gate sentinel, I1 known-to-lack marker, I2 wire error returns row status, M1 max-rounds label, M2 chosen-last convention, M5 escalate write retry, M6/M7 clear/pass CAS tests
This commit is contained in:
1 parent
2adc605373
commit
bc19f09dff
5 files changed
+683
-26
No files matched your search
+121
-19
@@ -508,6 +508,9 @@ def _mark_gate_checked(task, gate):
|
||||
无论哪份拷贝打标记,终局块读到的都是同一份集合。
|
||||
终局时 _audit_loop_gate_results 只列入被标记过的门,
|
||||
不再把没跑过的门硬编码成通过。
|
||||
审计批 6(B1):run_one 入口已初始化该列表为空——零门
|
||||
任务的 [] 与旧直接调用的 None 是两个不同哨兵,终局块
|
||||
传 [] 时零门不列入,传 None(旧直接调用)时才走旧行为。
|
||||
"""
|
||||
if not isinstance(task, dict):
|
||||
return
|
||||
@@ -533,6 +536,14 @@ _GATE_ERROR_MARKERS = (
|
||||
"工具审批声明矛盾",
|
||||
"refusing to dispatch an incapable or unverifiable model",
|
||||
"fails capability",
|
||||
# 审计批 6(I1):显式网关拦与写回复核拒绝共用的措辞
|
||||
# "…refusing to dispatch a model known to lack a required
|
||||
# capability"。选全长措辞而不用较短的 "known to lack":
|
||||
# 全长措辞在全库只出现在上述两处生产方 error 文案里,
|
||||
# 误命中面最小;较短形式可能被执行失败的 error_text
|
||||
# (例如模型输出复述)偶然命中。误命中方向是 escalate
|
||||
# (安全侧、丢一次重试),不是放行,但精度仍优先。
|
||||
"known to lack a required capability",
|
||||
)
|
||||
|
||||
|
||||
@@ -2047,8 +2058,10 @@ class Worker:
|
||||
passed_gates 并持久化——“通过”一词在状态表里失真。
|
||||
现在:调用方传 gates_checked(run_one 派发点用
|
||||
_mark_gate_checked 在 task["_gates_checked"] 里记的
|
||||
本轮实际跑过的门)时,只列入集合内的门;未传
|
||||
(直接调用的旧调用方)时保持旧行为、三门全记 True。
|
||||
本轮实际跑过的门;审计批 6(B1)起 run_one 入口
|
||||
已初始化该列表为空,零门任务传 []、不再传 None)
|
||||
时,只列入集合内的门;未传(直接调用的旧调用方)
|
||||
时保持旧行为、三门全记 True。
|
||||
gate_missing 语义核查:引擎只对“上一轮 passed_gates
|
||||
里有、本轮缺失”的门升级;同一任务的跑过门集合在
|
||||
两轮间是稳定的(显式任务无策略时两轮都不记
|
||||
@@ -2100,6 +2113,27 @@ class Worker:
|
||||
gate_results[gate] = True
|
||||
return gate_results, findings
|
||||
|
||||
def _wire_error_final(self, conn, task_id, final):
|
||||
"""CAS 未命中/存库失败后读回行实际状态(审计批 6,I2)。
|
||||
|
||||
接线 error 时调用方(run_one 终局块)不能再拿输入终局
|
||||
当行状态:CAS 未命中意味着行已被第三方改动(例如重排
|
||||
回 queued),继续按输入终局记终态审计、发 failed 通知
|
||||
会与行状态自相矛盾。同一连接在回滚后仍可读,读到即
|
||||
以行为准;读不到(连接已坏、行已删)时回落输入终局,
|
||||
不比旧行为更差。连接都连不上时调用方无连接可用,
|
||||
不走本方法(行未被接线改动,输入终局即行状态)。
|
||||
"""
|
||||
try:
|
||||
row = conn.execute(
|
||||
"SELECT status FROM tasks WHERE id = ?",
|
||||
(task_id,)).fetchone()
|
||||
except Exception:
|
||||
return final
|
||||
if row and row[0]:
|
||||
return row[0]
|
||||
return final
|
||||
|
||||
def _audit_loop_wire(self, task, final, result, error):
|
||||
"""审计循环调用方接线:把引擎决策变成真实的任务结局。
|
||||
|
||||
@@ -2142,6 +2176,15 @@ class Worker:
|
||||
result,自带连接)仍是提交后的独立写:它失败时只记
|
||||
警告、不再把已 failed 的任务谎报成 error(旧版写回
|
||||
失败会返回 error,尽管状态已是 failed)。
|
||||
审计批 6(I2):CAS 未命中/存库失败返回 error 时,
|
||||
final 不再是输入终局,而是回滚后读回的行实际状态
|
||||
(例如行已被重排回 queued 时返回 queued);run_one
|
||||
终局块据此抑制终态审计与通知,不再按输入终局谎报。
|
||||
连接都连不上时无连接可读,仍返回输入终局(行未被
|
||||
接线改动,输入终局即行状态)。
|
||||
审计批 6(M5):升级成功后的结果写回有界重试一次
|
||||
(仍带 only_if_status="failed" 守卫,幂等),两次
|
||||
都失败时仍只记警告、不谎报成 error。
|
||||
goal 任务(审计批 5,N-12 定性,只文档化、不改行为):
|
||||
推回只改 tasks.status 与包列(+ 轮次状态表),不碰
|
||||
goal / verify_command / goal_max_rounds 列,也不碰宿主
|
||||
@@ -2221,7 +2264,10 @@ class Worker:
|
||||
message="task status changed before packet clear")
|
||||
except Exception:
|
||||
pass
|
||||
return final, error, "error"
|
||||
# 审计批 6(I2):回滚后读回行实际状态,不再
|
||||
# 拿输入终局当行状态返回(行可能已被重排)。
|
||||
return self._wire_error_final(conn, task_id, final), \
|
||||
error, "error"
|
||||
conn.commit()
|
||||
self._audit(project_id, "worker_audit_loop_passed",
|
||||
"%s round=%s" % (task_id, decision.get("round")))
|
||||
@@ -2253,7 +2299,9 @@ class Worker:
|
||||
message="task status changed before pushback")
|
||||
except Exception:
|
||||
pass
|
||||
return final, error, "error"
|
||||
# 审计批 6(I2):回滚后读回行实际状态。
|
||||
return self._wire_error_final(conn, task_id, final), \
|
||||
error, "error"
|
||||
conn.commit()
|
||||
self._audit(project_id, "worker_audit_loop_pushback",
|
||||
"%s round=%s findings=%s" % (
|
||||
@@ -2289,7 +2337,9 @@ class Worker:
|
||||
message="task status changed before escalate")
|
||||
except Exception:
|
||||
pass
|
||||
return final, error, "error"
|
||||
# 审计批 6(I2):回滚后读回行实际状态。
|
||||
return self._wire_error_final(conn, task_id, final), \
|
||||
error, "error"
|
||||
conn.commit()
|
||||
# 升级审计在提交后记(与旧接线“引擎已记”的行同款,
|
||||
# 只是时序从评估提交后挪到接线提交后,绝不出现
|
||||
@@ -2310,13 +2360,27 @@ class Worker:
|
||||
"%s reason=%s round=%s"
|
||||
% (task_id, decision.get("reason"),
|
||||
decision.get("round")))
|
||||
try:
|
||||
self._write_execution_result(
|
||||
task_id, result_text=(result or {}).get("stdout", ""),
|
||||
error_text=esc_error, actual_model=None,
|
||||
started_at=None, finished_at=time.time(),
|
||||
only_if_status="failed")
|
||||
except Exception as exc:
|
||||
# 审计批 6(M5):提交后的结果写回仍是独立写,
|
||||
# 但瞬时失败不再直接认命——有界单次重试(仍带
|
||||
# only_if_status="failed" 守卫,重试是幂等的:
|
||||
# 行被并发重排后守卫挡住,不会覆盖新结果)。
|
||||
# 两次都失败时保持旧行为:只记警告、不把已
|
||||
# failed 的任务谎报成 error,DB error_text
|
||||
# 停留旧文本的残留仍在,见报告。
|
||||
_write_exc = None
|
||||
for _attempt in range(2):
|
||||
try:
|
||||
self._write_execution_result(
|
||||
task_id,
|
||||
result_text=(result or {}).get("stdout", ""),
|
||||
error_text=esc_error, actual_model=None,
|
||||
started_at=None, finished_at=time.time(),
|
||||
only_if_status="failed")
|
||||
_write_exc = None
|
||||
break
|
||||
except Exception as exc:
|
||||
_write_exc = exc
|
||||
if _write_exc is not None:
|
||||
# 结果文本写回是提交后的独立写:失败只记警告,
|
||||
# 任务已是 failed,不再谎报成 error。
|
||||
try:
|
||||
@@ -2325,12 +2389,15 @@ class Worker:
|
||||
"worker_audit_loop_escalate_result_failed",
|
||||
task_id=task_id, project_id=project_id,
|
||||
status="warning",
|
||||
message="escalate result write failed: %s" % exc)
|
||||
message="escalate result write failed: %s"
|
||||
% _write_exc)
|
||||
except Exception:
|
||||
pass
|
||||
return "failed", esc_error, "escalate"
|
||||
conn.rollback()
|
||||
return final, error, "error"
|
||||
# 审计批 6(I2):未知决策同样回滚后读回行实际状态。
|
||||
return self._wire_error_final(conn, task_id, final), \
|
||||
error, "error"
|
||||
except Exception as exc:
|
||||
try:
|
||||
conn.rollback()
|
||||
@@ -2343,7 +2410,10 @@ class Worker:
|
||||
message="audit loop wire store failed: %s" % exc)
|
||||
except Exception:
|
||||
pass
|
||||
return final, error, "error"
|
||||
# 审计批 6(I2):异常后回滚,行未被接线改动时读回
|
||||
# 即输入终局本身;行已被第三方改动时以行为准。
|
||||
return self._wire_error_final(conn, task_id, final), \
|
||||
error, "error"
|
||||
finally:
|
||||
try:
|
||||
conn.close()
|
||||
@@ -7583,6 +7653,17 @@ class Worker:
|
||||
except Exception:
|
||||
pass
|
||||
task = self.get_task(task_id) or task
|
||||
# 审计批 6(B1,批 4 I-10 的 None 哨兵坍塌):run_one
|
||||
# 入口立即初始化 _gates_checked 为空列表,使“本轮零
|
||||
# 门跑过”([])与“旧直接调用”(None)可区分——否则
|
||||
# 零门任务在终局块传 None 时 _audit_loop_gate_results
|
||||
# 走旧行为分支,把没跑过的三门硬编码成通过(批 4
|
||||
# 实测:显式零门任务两轮后 passed_gates 仍是三门)。
|
||||
# 列表对象经后续 dict(task) 浅拷贝共享,标记点与终局
|
||||
# 块读到同一份集合;协调员父任务不走单任务接线,
|
||||
# 初始化对它无害(内存态,不进库、不进审计)。
|
||||
if not isinstance(task.get("_gates_checked"), list):
|
||||
task["_gates_checked"] = []
|
||||
# G10:goal 断点续跑标记——认领后立即清掉库里标记(本轮
|
||||
# 已认领为 running,不会重复触发;本轮若再被杀回
|
||||
# interrupted,用户需重新调 /goal-resume 才会再置标记,
|
||||
@@ -8005,6 +8086,9 @@ class Worker:
|
||||
# tier/source/applied,评估时建议模型只能记
|
||||
# unknown;新格式补 suggested/chosen,旧解析
|
||||
# 器仍能读(见 cloud/routing_shadow.py)。
|
||||
# 审计批 6(M2):chosen 必须是行尾字段——影子
|
||||
# 解析器按行尾锚定 chosen,后续写点不得在其
|
||||
# 后追加字段,否则会被吞进 chosen 而误解析。
|
||||
self._audit(task["project_id"], "worker_routing",
|
||||
"%s tier=%s source=%s applied=%s"
|
||||
" suggested=%s chosen=%s" % (
|
||||
@@ -8061,6 +8145,8 @@ class Worker:
|
||||
# 行:评估函数只计 per-tier explicit_n,不计
|
||||
# routed_n、不占 seen(见 routing_shadow.py),
|
||||
# 父模型语义不变,档模型绝不覆盖它。
|
||||
# 审计批 6(M2):同款行尾约定——chosen 必须是
|
||||
# 行尾字段,后续写点不得在其后追加字段。
|
||||
self._audit(task["project_id"], "worker_routing",
|
||||
"%s tier=%s source=explicit applied=false"
|
||||
" suggested=- chosen=%s" % (
|
||||
@@ -8588,6 +8674,7 @@ class Worker:
|
||||
# 本轮花过的钱照记,推回不等于没花钱。
|
||||
audit_loop_decision = None
|
||||
audit_loop_pushback = False
|
||||
audit_loop_suppress = False
|
||||
if (final_written and not quota_stop
|
||||
and final in ("completed", "failed")
|
||||
and task.get("audit_loop")
|
||||
@@ -8596,6 +8683,17 @@ class Worker:
|
||||
final, error, audit_loop_decision = \
|
||||
self._audit_loop_wire(task, final, result, error)
|
||||
audit_loop_pushback = (audit_loop_decision == "pushback")
|
||||
# 审计批 6(I2):接线 error 且行实际状态已不是
|
||||
# 终态(例如 CAS 未命中后行回 queued)时,终态
|
||||
# 审计/时间线/通知必须随之抑制——按输入终局记
|
||||
# worker_failed 并发 failed 通知会与行状态自相
|
||||
# 矛盾。行仍是终态(回滚情形:failed/completed)
|
||||
# 或已被取消(interrupted,按 interrupted 终局
|
||||
# 处理、不发 failed 通知)时不抑制。
|
||||
audit_loop_suppress = (
|
||||
audit_loop_decision == "error"
|
||||
and final not in ("completed", "failed",
|
||||
"interrupted"))
|
||||
except Exception as exc:
|
||||
try:
|
||||
log_event(self.logger, "worker_audit_loop_wire_failed",
|
||||
@@ -8615,7 +8713,8 @@ class Worker:
|
||||
# 持锁写,否则两个线程共用同一 sqlite 连接会直接报错。
|
||||
cost_id = self._record_usage_cost(
|
||||
task, actual_model, usage_total, stdout, fallback_count)
|
||||
if final_written and not audit_loop_pushback:
|
||||
if final_written and not audit_loop_pushback \
|
||||
and not audit_loop_suppress:
|
||||
# 审计名须与终态一致:interrupted 任务记 worker_failed
|
||||
# 会把“可续跑的中断”误读成失败,误导后续排查。
|
||||
# 终态审计细节(2026-10-29 任务 A 教训):interrupted /
|
||||
@@ -8668,11 +8767,14 @@ class Worker:
|
||||
elif final in ("completed", "failed"):
|
||||
self._notify_task_finished(
|
||||
task_id, task["project_id"], final, error=error)
|
||||
elif audit_loop_pushback:
|
||||
elif audit_loop_pushback or audit_loop_suppress:
|
||||
# 推回已由接线处理(状态 queued、包列已写、推回审计
|
||||
# 已记):这里不跑终态审计、不改 final、不发通知。
|
||||
# 注意不能落入下面的 else——else 会把 final 改成
|
||||
# interrupted,与库里的 queued 自相矛盾。
|
||||
# 审计批 6(I2):接线 error 且行已不是终态时同款
|
||||
# 抑制——这里同样不跑终态审计、不改 final、不发
|
||||
# 通知,final 已是接线读回的行实际状态,返回体
|
||||
# 与行一致。注意不能落入下面的 else——else 会把
|
||||
# final 改成 interrupted,与库里的 queued 自相矛盾。
|
||||
pass
|
||||
else:
|
||||
if goal_converted:
|
||||
|
||||
Reference in new issue
Block a user