Files
codex-app-server/cloud/tests/test_scorecard_mech_tables.py
T
host f8a6a9d258 v7 mech-2: split scorecard into code/production/product tables
(cherry picked from commit 67b7f5e42d001b655aef3e04e1d3c1d98166b98f)

Reconcile-port: handler_admin.py hunks redirected into cloud/server.py _audit_scorecard (target keeps 6-mixin split; scorecard module itself applied cleanly).
2026-11-03 02:49:27 +00:00

295 lines
13 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""v7 机制第 2 项:三张表拆分定向测试。
维分配(与 cloud/audit_scorecard.py 的注释一致):
- 代码表:delivery_quality、gate_audit、arch_contract、test_coverage
(代码证据,不含生产项)。
- 生产表:security_ledger、cost_quota、ops_scale(生产证据)。
- 产品表:全部 7 维 + 真实产品轮门禁;无真实产品轮证据时恒 not_pass,
这只是评分卡输入结构拆分,不代表任何产品功能已落地。
钉住的规则:
- 代码表 overall 独立:生产证据缺失、B/C 用户侧项 pending,
都不拉低代码表。
- 生产表缺项不拉低代码表;生产表 overall 独立,平均分不作依据。
- 三张表各自 average_is_not_pass_criterion=True。
- 阈值默认值一律 test_default_unapproved,未拍板。
- 端点 GET /audit-scorecard 返回的示例卡带 code/production/product
三个子对象(端点已接线,非冒充)。
"""
import http.client
import json
import os
import sys
import tempfile
import threading
import unittest
from pathlib import Path
try:
from cloud.audit_scorecard import (
CODE_DIMENSION_IDS, DEFAULT_THRESHOLDS, PRODUCTION_DIMENSION_IDS,
PRODUCT_DIMENSION_IDS, build_code_scorecard,
build_product_scorecard, build_production_scorecard, build_scorecard,
example_scorecard_as_of_2026_10_31)
from cloud.auth import AuthStore
from cloud.server import create_server
except ImportError:
sys.path.insert(0, str(Path(__file__).resolve().parents[2]))
from cloud.audit_scorecard import (
CODE_DIMENSION_IDS, DEFAULT_THRESHOLDS, PRODUCTION_DIMENSION_IDS,
PRODUCT_DIMENSION_IDS, build_code_scorecard,
build_product_scorecard, build_production_scorecard, build_scorecard,
example_scorecard_as_of_2026_10_31)
from cloud.auth import AuthStore
from cloud.server import create_server
def _code_evidence():
return {
"delivery_quality": {
"first_pass_rate": 0.96, "defect_rate": 0.01,
"rework_rate": 0.04, "first_pass_known": True,
"defect_known": True, "rework_known": True,
"attempts_present": True, "evidence_kind": "real",
},
"gate_audit": {
"hard_gate_enforced": True, "gate_items_passed": 5,
"gate_items_total": 5, "merge_blocked_verified": True,
"loop_end_to_end_verified": True,
"sampling_misjudgment_rate": 0.0,
},
"arch_contract": {
"contract_frozen": True, "arch_violations": 0,
"directory_violations": 0, "import_violations": 0,
"stack_changed_without_approval": False,
},
"test_coverage": {
"prd_coverage_rate": 1.0, "cross_matrix_coverage_rate": 1.0,
"coverage_pct": 0.92, "cross_matrix_kind": "real",
"real_pg": True, "real_service": True,
"agent_six_complete": True,
"lint_items": 0, "mypy_items": 0, "bandit_high": 0,
},
}
def _production_evidence():
return {
"security_ledger": {
"ledger_verify_ok": True, "ledger_coverage_rate": 1.0,
"branch_protection": "protected",
"shell_whitelist_pass_rate": 1.0, "anchor_check_recent": True,
},
"cost_quota": {
"cost_records_complete": True, "unpriced_as_zero": False,
"per_creator_present": True, "quota_cutoff_verified": True,
},
"ops_scale": {
"ci_green_rate": 1.0, "deploy_success_rate": 1.0,
"rollback_drill_done": True, "ha_status": "second_host",
"parallel_scale_proven": 40,
},
}
def _full_evidence():
ev = {}
ev.update(_code_evidence())
ev.update(_production_evidence())
return ev
def _product_evidence():
return {
"real_product_round": True,
"real_app_installed": True,
"real_user_flow_verified": True,
"product_round_as_of": "2026-11-02",
}
class SplitTablesTestCase(unittest.TestCase):
def test_dimension_allocation_is_pinned(self):
self.assertEqual(CODE_DIMENSION_IDS, [
"delivery_quality", "gate_audit", "arch_contract",
"test_coverage"])
self.assertEqual(PRODUCTION_DIMENSION_IDS, [
"security_ledger", "cost_quota", "ops_scale"])
self.assertEqual(PRODUCT_DIMENSION_IDS, [
"delivery_quality", "gate_audit", "arch_contract",
"test_coverage", "security_ledger", "cost_quota", "ops_scale"])
self.assertFalse(set(CODE_DIMENSION_IDS)
& set(PRODUCTION_DIMENSION_IDS))
def test_code_table_passes_on_code_evidence_alone(self):
table = build_code_scorecard(_code_evidence())
self.assertEqual(table["overall"], "pass")
self.assertTrue(table["overall_pass"])
self.assertEqual([d["id"] for d in table["dimensions"]],
CODE_DIMENSION_IDS)
self.assertTrue(table["average_is_not_pass_criterion"])
self.assertEqual(table["thresholds_source"],
"test_default_unapproved")
for dim in table["dimensions"]:
self.assertGreaterEqual(dim["score"], 9.0)
def test_bc_all_pending_code_passes_production_not_pass(self):
# 核心验收:B/C 全 pending 时代码表仍可 pass、生产表 not_pass。
# user_side_items 在此只是占位证据,不依赖第 7 项的代码。
user_side = [{"id": "B", "status": "pending"},
{"id": "C", "status": "pending"}]
code = build_code_scorecard(_full_evidence())
prod = build_production_scorecard(
_full_evidence(), user_side_items=user_side)
self.assertEqual(code["overall"], "pass")
self.assertEqual(prod["overall"], "not_pass")
self.assertFalse(prod["overall_pass"])
self.assertTrue(prod["user_side_blocked"])
self.assertEqual([p["id"] for p in prod["user_side_pending"]],
["B", "C"])
self.assertTrue(any("B" in m for m in prod["missing_items"]))
self.assertTrue(any("C" in m for m in prod["missing_items"]))
# 挡住 overall 但不篡改维分数:生产维本身仍全 >=9。
for dim in prod["dimensions"]:
self.assertGreaterEqual(dim["score"], 9.0)
def test_bc_pending_in_dict_and_string_forms_also_blocks(self):
prod = build_production_scorecard(
_full_evidence(), user_side_items={"B": "pending"})
self.assertEqual(prod["overall"], "not_pass")
prod2 = build_production_scorecard(
_full_evidence(), user_side_items=["B"])
self.assertEqual(prod2["overall"], "not_pass")
def test_production_missing_evidence_does_not_lower_code_table(self):
# 生产证据直接缺失(不传 user_side_items 也一样):生产表
# not_pass,代码表仍 pass——缺项不跨表拉低。
code = build_code_scorecard(_code_evidence())
prod = build_production_scorecard(_code_evidence())
self.assertEqual(code["overall"], "pass")
self.assertEqual(prod["overall"], "not_pass")
for dim in prod["dimensions"]:
self.assertIsNone(dim["score"])
self.assertEqual(dim["status"], "unknown")
def test_production_passes_when_evidence_full_and_user_side_done(self):
prod = build_production_scorecard(
_full_evidence(),
user_side_items=[{"id": "B", "status": "done"},
{"id": "C", "status": "approved"}])
self.assertEqual(prod["overall"], "pass")
self.assertFalse(prod["user_side_blocked"])
self.assertEqual(prod["user_side_pending"], [])
def test_product_table_without_real_round_is_always_not_pass(self):
# 无真实产品轮证据:即使代码+生产证据全满,产品表也恒 not_pass,
# 全部维 None——绝不把代码/生产分数冒充成产品分数。
table = build_product_scorecard(_full_evidence())
self.assertEqual(table["overall"], "not_pass")
self.assertFalse(table["product_gate_passed"])
for dim in table["dimensions"]:
self.assertIsNone(dim["score"])
self.assertEqual(dim["status"], "unknown")
self.assertTrue(table["product_round_missing_fields"])
def test_product_table_with_real_round_scores_same_dimensions(self):
table = build_product_scorecard(_full_evidence(),
product_evidence=_product_evidence())
self.assertTrue(table["product_gate_passed"])
self.assertEqual(table["overall"], "pass")
self.assertEqual(len(table["dimensions"]), 7)
for dim in table["dimensions"]:
self.assertGreaterEqual(dim["score"], 9.0)
def test_product_average_91_with_one_four_still_fails(self):
# 产品表平均分规则:6 维 10 分、1 维 4 分,平均 9.1,仍 not_pass。
ev = _full_evidence()
ev["gate_audit"]["hard_gate_enforced"] = False
table = build_product_scorecard(ev,
product_evidence=_product_evidence())
self.assertEqual(table["average_score"], 9.1)
self.assertTrue(table["average_is_not_pass_criterion"])
self.assertEqual(table["overall"], "not_pass")
def test_build_scorecard_carries_three_subobjects(self):
report = build_scorecard(
_full_evidence(),
user_side_items=[{"id": "B", "status": "pending"},
{"id": "C", "status": "pending"}])
# 旧字段语义不变:7 维全满时旧 overall 仍 pass。
self.assertEqual(report["overall"], "pass")
self.assertEqual(len(report["dimensions"]), 7)
self.assertEqual(report["code"]["overall"], "pass")
self.assertEqual(report["production"]["overall"], "not_pass")
# 产品表无真实产品轮证据,恒 not_pass。
self.assertEqual(report["product"]["overall"], "not_pass")
self.assertEqual([d["id"] for d in report["code"]["dimensions"]],
CODE_DIMENSION_IDS)
self.assertEqual(
[d["id"] for d in report["production"]["dimensions"]],
PRODUCTION_DIMENSION_IDS)
def test_example_card_carries_three_subobjects_all_not_pass(self):
report = example_scorecard_as_of_2026_10_31()
self.assertEqual(report["overall"], "not_pass")
self.assertEqual(report["code"]["overall"], "not_pass")
self.assertEqual(report["production"]["overall"], "not_pass")
self.assertEqual(report["product"]["overall"], "not_pass")
self.assertFalse(report["product"]["product_gate_passed"])
def test_threshold_defaults_still_unapproved_in_all_tables(self):
for entry in DEFAULT_THRESHOLDS.values():
self.assertEqual(entry["source"], "test_default_unapproved")
for table in (build_code_scorecard(_full_evidence()),
build_production_scorecard(_full_evidence()),
build_product_scorecard(_full_evidence(),
product_evidence=_product_evidence())):
self.assertEqual(table["thresholds_source"],
"test_default_unapproved")
class SplitTablesEndpointTestCase(unittest.TestCase):
def setUp(self):
self.tmp = tempfile.TemporaryDirectory()
self.db_path = os.path.join(self.tmp.name, "control.db")
self.auth = AuthStore(self.db_path)
self.owner_id, self.owner_key = self.auth.create_user("owner")
self.server = create_server(self.db_path, "127.0.0.1", 0)
self.port = self.server.server_address[1]
self.thread = threading.Thread(
target=self.server.serve_forever, daemon=True)
self.thread.start()
def tearDown(self):
self.server.shutdown()
self.server.server_close()
self.thread.join(timeout=5)
try:
self.auth.conn.close()
except Exception:
pass
self.tmp.cleanup()
def test_endpoint_returns_three_subobjects(self):
conn = http.client.HTTPConnection("127.0.0.1", self.port, timeout=10)
try:
conn.request("GET", "/audit-scorecard",
headers={"X-API-Key": self.owner_key})
resp = conn.getresponse()
report = json.loads(resp.read().decode("utf-8"))
finally:
conn.close()
self.assertEqual(resp.status, 200)
self.assertEqual(report["overall"], "not_pass")
for key in ("code", "production", "product"):
self.assertIn(key, report)
self.assertEqual(report[key]["overall"], "not_pass")
self.assertEqual(len(report["code"]["dimensions"]), 4)
self.assertEqual(len(report["production"]["dimensions"]), 3)
self.assertEqual(len(report["product"]["dimensions"]), 7)
if __name__ == "__main__":
unittest.main()