# V43 候选评分公平性与稳定性监测 API V43 只提供 ADMIN 聚合查询。当前状态为“独立代码复验与真实 MySQL/Docker 验收通过,待 Git 检查点”。响应基于当前数据库中指定月份的评分快照,字段 `basis=CURRENT_STORED_SNAPSHOTS` 表示快照可能被同月重算覆盖,不能解读为历史时点记录。 ## 权限与通用约束 - ADMIN 才能访问;匿名为 401,STUDENT/COMPANY 为 403/2002。 - 时间范围使用 `[from,to)`。评分接口的 `period` 必填,格式为 `yyyy-MM`,不得晚于当前业务月。 - 申诉接口默认最近 30 个完整业务日,`from`、`to` 必须成对出现,跨度最大 90 天。 - 仅允许文档列出的参数;未知参数、非法维度和未来月份返回 400/1001。 - 所有响应为聚合白名单,不包含用户、申请、申诉、答卷、结果、审计 ID,联系方式、简历、题目、答案、规则详情或审计原文。 ## 接口 | 方法 | 路径 | 用途 | |---|---|---| | GET | `/admin/scoring/fairness/overview?period=yyyy-MM` | 现存快照人数、可计算比例、规则版本构成和综合分分布 | | GET | `/admin/scoring/fairness/dimensions?period=yyyy-MM&dimension=ABILITY` | 八维状态、缺行/空分/有效覆盖率和分布 | | GET | `/admin/scoring/fairness/drift` | 返回 `UNAVAILABLE/IMMUTABLE_SCORE_HISTORY_NOT_AVAILABLE` | | GET | `/admin/scoring/fairness/ranking-stability` | 返回 `UNAVAILABLE/RANKING_SNAPSHOT_HISTORY_NOT_AVAILABLE` | | GET | `/admin/scoring/fairness/appeals?from=yyyy-MM-dd&to=yyyy-MM-dd` | 申诉创建队列当前状态、审核通过、回滚和实际变分聚合 | 所有 `sampleSize`、状态/版本/原因计数均按独立候选人计算,`appealCount` 才是事件数。每个统计组均带有明确的 `availability` 与 `reason`:`NO_DATA`、`INSUFFICIENT_SAMPLE`、`SUPPRESSED` 或 `AVAILABLE`,前端不得通过字段缺失猜测状态。0–29 人不返回均值、分位数、极值、标准差、分桶、比例或风险;30–99 标记 `LOW_CONFIDENCE`;100 及以上为 `NORMAL_CONFIDENCE`。任意细分单元或其补集为 1–29 人时整组抑制,避免从总计反推隐藏单元。 规则版本分布按版本单元分别做披露决策:不安全版本只返回 `availability=SUPPRESSED`/`reason=SMALL_CELL_OR_COMPLEMENT_RISK`,其 `sampleSize`、均值、分位数、极值、标准差、分桶和风险均为空;安全兄弟版本(例如70/30)仍可返回正常分布。只要存在版本级受保护单元,`versionCounts`及其可由总体反推的计数隐藏;全局总体触发抑制时,整个版本分布组隐藏。 总览的 `computableSnapshotRatio` 是“至少一个有效维度的候选人数 / 总体人数”,MIXED/UNKNOWN 候选不会被错误地当作无有效分;综合分布通过 `distributionsByRulesVersion` 按单一已知候选整体规则版本分别计算,MIXED/UNKNOWN 不进入版本分布。申诉的 `statusCounts/statusCandidateCounts` 是独立候选人数,`statusEventCounts` 明确保留事件数;重复回滚、空/越界分和跨版本原因均独立计数。回滚可比性按申诉粒度判断:同一 `appeal_id` 的 ROLLBACK 历史恰好一条且分数/规则版本合法才进入 COMPARABLE;同一候选人的另一份合法申诉不因其存在重复历史的申诉而被排除。`comparableRollbackCount` 与 `changedCount` 按可比/变分回滚历史行计数,`comparableRollbackCandidateCount` 与 `changedCandidateCount` 按这些行对应的独立候选人数计数;`actualScoreChangeRate=changedCount/comparableRollbackCount`,零差历史仍在分母中。 维度完整性异常分开返回 `inconsistentRecordCount`(状态与是否有分不一致)、`unknownStatusCount`(未知状态)和 `outOfRangeScoreCount`(非空但不在 0–100 的分数);这些计数与有效分、缺行、空分不互相替代,并受同一独立候选人/补集抑制规则约束。分布发生分桶抑制时连同 `sampleSize`、均值、分位数、极值、标准差、分桶和风险一起隐藏,只保留 `availability/reason`。 回滚不可比原因按互斥优先级归类:重复 `ROLLBACK` 历史优先,其次为空/越界分,最后是规则版本未知或前后不一致;每个申诉只进入一个原因集合,但同一候选人可因不同申诉同时出现在多个原因集合,不能用候选人去重抹掉真实归属。零差回滚仍保留在可比分母中。审核通过率、回滚执行率和实际变分率使用各自独立分母,任何分母或补集不足 30 名独立候选人均不返回该指标。 申诉接口区分 `APPROVED/ROLLED_BACK`、实际 `ROLLBACK` 执行和前后分数变化。它不计算真实曝光申诉率,因为当前系统没有可比的曝光分母。 V43 不写 `candidate_dimension_scores`,不触发评分重算,不修改 V32 排名。历史漂移和历史排名接口返回不可用状态是当前数据模型的真实限制。 实现约束:维度统计使用 `COUNT(DISTINCT student_user_id)` 与 `GROUP BY` 频数查询,分位数/标准差由频数直接计算;申诉回滚按申诉时间窗口 JOIN 查询,不拼接无限增长的 `IN` 参数。每条 JDBC 查询使用独立 5 秒超时,不修改共享 `JdbcTemplate`。真实 MySQL 已完成 30/300/3000 人查询预算与耗时验收;EXPLAIN 中的全表扫描/filesort 作为更大规模容量风险持续观察。 抑制实现由独立的 `FairnessDisclosureGuard` 统一执行:有效集合、每个细分单元及其补集均按独立候选人数判断;当有效集合或补集仅 1–29 人时,可能揭示其大小的综合分布字段(包括 sampleSize、分位数、分桶、均值、极值和风险)一并隐藏。