audit: task-attempt ledger feeds real first-pass/defect/rework rates (gap 3)

- cloud/attempt_ledger.py: separate task_attempts table (not tasks
  columns) with per-attempt rows, MAX+1 attempt_no, append-only
  intent; interrupted rows kept but never counted; is_defect is
  explicit, never inferred from failure; first defect category
  wins; no-ledger tasks stay unknown (None), never backfilled.
  SQLite DDL is CREATE TABLE IF NOT EXISTS (idempotent); PG_DDL
  is the verbatim manual step for production Postgres, kept out
  of POSTGRES_SCHEMA on purpose (migrations coverage untouched).
- cloud/server.py GET /metrics-report: aggregates the ledger
  into compute_metrics records; missing ledger table degrades to
  unknown rates, not an error. Cost dual-column code untouched.
- cloud/metrics.py: docstring only (ledger is now the source);
  compute_metrics logic and all #238 semantics unchanged.
- Tests: 16 ledger tests (store/aggregate/metrics/PG adapter
  evidence) + 3 endpoint tests (real rates, old task beside
  ledger task, interrupted status non-terminal).
This commit is contained in:
host committed 2026-11-04 20:56:06 +00:00
1 parent 8a4e80c20d
commit d303dedf32
6 files changed
+639 -22

No files matched your search

+19 -6
View File
@@ -169,6 +169,9 @@ from cloud.approvals import ensure_approvals_table as _appr_ensure
from cloud.approvals import expire_overdue as _appr_expire
from cloud.approvals import get_approval as _appr_get
from cloud.approvals import list_approvals as _appr_list
from cloud.attempt_ledger import aggregate_attempts as _aggregate_attempts
from cloud.attempt_ledger import apply_to_records as _apply_attempts
from cloud.attempt_ledger import read_attempt_rows as _read_attempt_rows
from cloud.auto_memory import AutoMemoryStore
from cloud.auto_memory import process_due_tasks as _auto_process_due
from cloud.identity import IdentityStore
@@ -10129,12 +10132,14 @@ pid 须为整数、address 须为字符串,否则 400(注册表里的
"""指标闭环报告:首过绿灯率 / 缺陷率 / 返工率 / 每任务成本。
权限与 /metrics 同款:只统计调用者是成员的项目。
诚实边界:当前 tasks 表没有 attempts/defects 列,所以
attempts/defects 一律传 None,首过/缺陷/返工率回 None
(未知,不报 0);金任务集未经人工审定,报告恒为
pending_human_approval、decision_ready False。等任务尝试
台账落库、金任务人工审定后,这两处再接真实输入——
在此之前绝不把样本集或未知率包装成可决策数字。
台账(audit gap 3,见 ``cloud/attempt_ledger.py``):任务的
attempts/defects 来自 ``task_attempts`` 台账的聚合,不再
恒为 None;台账里只有中断行的任务、以及台账里根本没有
行的老任务,仍传 None——未知率回 None(未知,不报 0),
老任务绝不被算成首过或无缺陷。台账表尚不存在(老库、
或生产 PG 未手动执行 ``PG_DDL``)时与无台账行同等处理,
不因此让端点报错;金任务集未经人工审定,报告恒为
pending_human_approval、decision_ready False。
成本走 #212 双列口径:有价合计与无价 actual token 分开,
总额在成本不完整时为 None,不把无价折成 0。
"""
@@ -10153,6 +10158,14 @@ pid 须为整数、address 须为字符串,否则 400(注册表里的
"attempts": None, "defects": None}
for row in rows
if row["project_id"] in member_ids]
try:
aggregates = _aggregate_attempts(
_read_attempt_rows(conn))
except (sqlite3.OperationalError, _PgOperationalError):
# No ledger table yet (old DB, or production PG
# before the manual PG_DDL step): same as no rows.
aggregates = {}
records = _apply_attempts(records, aggregates)
try:
cost_rows = conn.execute(
"SELECT task_id, project_id, source, total_tokens,"