feat: architecture conformance checks in CI and metrics feedback loop

- cloud/arch_conformance.py: contract-version (+1 only, approved
  change record), forbidden-directory (own dir only, .. and symlink
  escapes resolved), forbidden-import layer bans audited against the
  baseline (foundation/execution/driver, server sqlite3 Row adapters
  deliberately allowed), G2 frozen-stack swap guard; skill-project
  one-call check.
- cloud/metrics.py: first-pass/defect/rework rates over terminal
  tasks, unknown rates as None (never 0), #212 dual-column per-task
  cost (total None when incomplete), pure feedback rules
  (tighten/route-with-extra-audit/recalibrate, auto_apply False),
  golden-set gate: unapproved sample set is never decision-ready.
- GET /metrics-report (authenticated, member-scoped, same as
  /metrics): attempts/defects are None until an attempt ledger
  exists, so rates stay unknown rather than fabricated.
- Tests: 29 arch + 15 metrics + 3 endpoint, each check with
  positive and negative cases; repo-level scan pins zero layer
  violations on the baseline so a future violation fails CI via the
  existing host-verify discover run (no workflow change).
This commit is contained in:
host committed 2026-11-03 02:49:25 +00:00
1 parent 382ec6d62e
commit dba6536ac2
7 files changed
+1201

No files matched your search

+56
View File
@@ -158,6 +158,8 @@ from cloud.auto_memory import process_due_tasks as _auto_process_due
from cloud.identity import IdentityStore
from cloud.kb import KBStore
from cloud.memory import MemoryStore
from cloud.metrics import build_report as _build_metrics_report
from cloud.metrics import compute_metrics as _compute_metrics
from cloud.pr import PrSkipped, PrStepError
from cloud.uploads import (
BUNDLE_TTL_SECONDS,
@@ -3008,6 +3010,8 @@ class CloudControlPlaneHandler(BaseHTTPRequestHandler):
self._workers_heartbeat(user_id)
elif path == "/metrics" and method == "GET":
self._metrics(user_id)
elif path == "/metrics-report" and method == "GET":
self._metrics_report(user_id)
elif path == "/models" and method == "GET":
self._models_overview(user_id)
elif path == "/relay/models" and method == "GET":
@@ -9629,6 +9633,58 @@ pid 须为整数、address 须为字符串,否则 400(注册表里的
},
})
def _metrics_report(self, user_id):
"""指标闭环报告:首过绿灯率 / 缺陷率 / 返工率 / 每任务成本。
权限与 /metrics 同款:只统计调用者是成员的项目。
诚实边界:当前 tasks 表没有 attempts/defects 列,所以
attempts/defects 一律传 None,首过/缺陷/返工率回 None
(未知,不报 0);金任务集未经人工审定,报告恒为
pending_human_approval、decision_ready False。等任务尝试
台账落库、金任务人工审定后,这两处再接真实输入——
在此之前绝不把样本集或未知率包装成可决策数字。
成本走 #212 双列口径:有价合计与无价 actual token 分开,
总额在成本不完整时为 None,不把无价折成 0。
"""
conn = self._db()
try:
member_ids = {
row["project_id"]
for row in conn.execute(
"SELECT project_id FROM project_members WHERE user_id = ?",
(user_id,),
).fetchall()
}
rows = conn.execute(
"SELECT id, project_id, status FROM tasks").fetchall()
records = [{"id": row["id"], "status": row["status"],
"attempts": None, "defects": None}
for row in rows
if row["project_id"] in member_ids]
try:
cost_rows = conn.execute(
"SELECT task_id, project_id, source, total_tokens,"
" usd_micros FROM cost_records").fetchall()
except (sqlite3.OperationalError, _PgOperationalError):
cost_rows = []
costs = {}
for row in cost_rows:
if row["project_id"] not in member_ids:
continue
entry = costs.setdefault(row["task_id"], {
"priced_usd_micros": 0, "unpriced_actual_tokens": 0,
"has_rows": True})
if row["source"] == "actual" \
and row["usd_micros"] is None:
entry["unpriced_actual_tokens"] += \
row["total_tokens"] or 0
elif row["usd_micros"] is not None:
entry["priced_usd_micros"] += row["usd_micros"]
finally:
conn.close()
metrics = _compute_metrics(records, costs)
self._send_json(200, _build_metrics_report(metrics))
# -- OAuth(pre-auth,靠 state + secret,不走 X-API-Key)-----------
def _oauth_provider(self, path):
parts = [p for p in path.split("/") if p]