(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).
295 lines
13 KiB
Python
295 lines
13 KiB
Python
"""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()
|