feat(qualification): 资质库和资质匹配(查标第 4 步,规则集 2026.11-r4)
- 资质库(FR-M6-08):增删改、证书扫描件(PDF/JPG/PNG,企业级密钥加密、签名下载)、 late_for 按进行中项目的投标截止日提醒、审计;前端资质库页和对话框,侧栏入口 - 资质匹配(FR-M3-05):证书类别词表(16 类,产品证书、人员证书不进匹配), QUAL.EXPIRED / LEVEL_LOW / NOT_COVERED;投标文字层按清单项定级,只有资质库记录的降一级, 出处显示「依据:资质库记录」(查标页、报告模板 v2);一类证书一个问题;评分项不逐条找响应的也查 - 响应错位规则不再把资质表的证书名称格当成照抄的要求 - 评测:qual_defects.py 派生资质情况表,D12 3/3、D18 2/2、规矩的资质表 0 误报;开发集不退化 - 决策 QL1–QL7;方案和落地记录 docs/architecture/qualification-plan.md,评测 check-eval.md §13 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -58,6 +58,8 @@ RULE_CODES = {
|
||||
"P11": "FORM.MISSING_DOC",
|
||||
"P12": "PRICE.MULTIPLE_QUOTES",
|
||||
"P13": "PRICE.ITEM_MISSING",
|
||||
"D12": "QUAL.EXPIRED", # 资质匹配(qualification-plan §5):按资质情况表那一行的出处对照
|
||||
"D18": "QUAL.LEVEL_LOW",
|
||||
}
|
||||
|
||||
|
||||
@@ -68,7 +70,7 @@ def squash(t: str) -> str:
|
||||
def score_rules(manifest: dict[str, Any], res: dict[str, Any]) -> dict[str, Any]:
|
||||
"""规则问题(P 类):规则编号对上、投标侧出处里有注入的那段原文才算查出;没对上任何注入问题的规则问题算误报。
|
||||
D10(符合性条件响应表)按表级问题记在 rule_defects 里,它由响应匹配查(negative_deviation),这里一起对照。"""
|
||||
hits = list(res.get("rules") or [])
|
||||
hits = list(res.get("rules") or []) + list(res.get("qualification") or [])
|
||||
used: set[int] = set()
|
||||
found: Counter[str] = Counter()
|
||||
total: Counter[str] = Counter()
|
||||
@@ -104,6 +106,9 @@ def score_rules(manifest: dict[str, Any], res: dict[str, Any]) -> dict[str, Any]
|
||||
found[kind] += 1
|
||||
if ok >= 0:
|
||||
used.add(ok)
|
||||
# 清单里同一要求抽成几条时,规则(资质匹配)对每条各报一个、出处相同:算同一个,不算误报(同响应问题的按单元去重)
|
||||
same = (hits[ok]["code"], tuple(e["text"] for e in hits[ok]["evidence"]))
|
||||
used |= {i for i, h in enumerate(hits) if (h["code"], tuple(e["text"] for e in h["evidence"])) == same}
|
||||
# 响应表规则报的「负偏离」对上了响应问题(D05 / D06)的注入位置:算那个单元查出(rule_units),不算规则误报
|
||||
rule_units: set[str] = set()
|
||||
for i, h in enumerate(hits):
|
||||
|
||||
Reference in New Issue
Block a user