L2文档三大板块重构+评分细则不公开化;系统对齐:一键三轮评审、受验者注册表映射、提交状态探测工具

- 文档重构为 考核目的(1.x)/提交要求(2.x,含成果物需求)/考核内容(3.x) 板块编号体系
- 删除公开评分细则(7维表/合格线/难度赋分/功能拆分),保留验收基准与提交要求
- 自选题取消事前登记,改由 AGENTS.md 记录核心内容;前端同步移除登记字段
- 新增 l2-participants 注册表服务与 teams-config L2 URL 自动映射
- 新增 startReviewRounds 一键N轮评审(自动续跑+快照聚合中位数),前端「重新评审×3」
- 新增 check-repos.mjs 提交状态探测(API四态判定:已提交/空仓/未创建/未授权)
- 文档措辞与实现对齐(AI辅助评审)、修复引用/残片/格式问题
This commit is contained in:
hangshuo652
2026-08-26 10:52:23 +08:00
parent 6a2419d4a4
commit 040808ef6b
10 changed files with 510 additions and 554 deletions
+1
View File
@@ -56,6 +56,7 @@ Phase 3: 确定性校准(computeCalibration) + 硬规则引擎
| `review.service.ts` (~1500行) | 评审引擎:clone→tryBuild→tryBrowse→AI→校准(computeCalibration)→硬规则→出分 |
| `standards.ts` | `parseDimensions` 解析标准 MD 为维度列表 |
| `l2-topics.ts` | L2考核选题元数据(11命题题+自选题,`config/l2-topics.json`):难度赋分 cap、功能完整性拆分、验收要点注入 |
| `l2-participants.ts` | L2受验者注册表(`config/l2-participants.json`):员工编号↔Gitea账号↔仓库映射,自动生成拉取 URL;拉取认证走全局评审账号只读协作者权限 |
| `entries.ts` | 条目 CRUD + 触发评审 + PDF 导出 |
| `projects.ts` | 项目 CRUD + 汇总排名 |
| `db.ts` | SQLite 初始化 + migrationsALTER TABLE try/catch |
+14
View File
@@ -0,0 +1,14 @@
{
"note": "L2考核受验者注册表:受验者自行注册 Gitea 账号(用户名=员工编号)并创建私有仓库 L2-assessment,将本表信息登记给组委会后,评审系统按下述映射自动生成拉取 URL。拉取认证使用组委会评审账号对该仓库的只读协作者权限(受验者负责授权)。",
"gitteaUrl": "https://gittea.dev",
"reviewPullAccount": "",
"participants": [
{
"no": "SD0102",
"name": "张三",
"gitteaUser": "sd0102",
"repo": "L2-assessment",
"remark": ""
}
]
}
+216 -492
View File
@@ -1,4 +1,4 @@
# L2考核成果物提交规范 · AI人才育成L2认证
# L2考核成果物提交规范 · AI人才育成认证——L2
> 适用范围:AI人才育成 L2 考核全部受验者(个人考核)
>
@@ -12,41 +12,30 @@
>
> 超过截止时间未提交,按以下迟交规则处理:迟交 1~3 个工作日扣 5 分,4~7 个工作日扣 10 分,超过 7 个工作日**按 0 分处理、不再评审**。
>
> 请务必在截止前完成:账号登录 → 成果物放入仓库 → `git push` 到 main 分支,并确认服务器上能看到最新提交。
> 请务必在截止前完成:**注册账号(用户名=员工编号)→ 授权评审拉取账号(只读协作者)→ 提交登记 → 成果物放入仓库 → `git push` 到 main 分支**,并确认服务器上能看到最新提交。
---
## 📑 目录
**第一部分 · 考核说明**
- **§1 考核目的、方式与内容** —— 目的定位 / 方式一览 / 三层目标 / 双轨选题制 / 命题题一览 / 自选题约束 / 选题声明
**第一部分 · 考核目的**
- §1.1 考核目的与定位 | §1.2 考核方式与合格标准 | §1.3 选题路径
**第二部分 · 开发与提交规范**
- §2 开发工具与模型 §3 Gitea账号规范 §4 仓库规范
- §5 成果物清单与放置规则 §6 README编写要求 §7 设计文档要求
- §8 AI协作过程留痕 | §9 通用命名与内容红线
- §10 独立完成与查重红线 | §11 源码可运行前提
**第二部分 · 提交要求**
- §2.1 开发工具与模型 §2.2 Gitea账号与仓库(注册→授权→仓库名)
- **成果物需求**:§2.3 成果物清单与放置规则 §2.4 README编写要求 §2.5 设计文档要求 | §2.6 AI协作过程留痕 | §2.7 命名红线与信息安全 | §2.8 独立完成与查重红线 | §2.9 源码可运行前提
- §2.10 提交前自查清单 | §2.11 违规后果
**第三部分 · 考核标准与纪律**
- §12 考核标准(7维评审要点 / 合格线与赋分 / 结果申诉
- §13 提交前自查清单 | §14 违规后果
**第四部分 · 命题题详细需求(选定题目后细读对应章节)**
- §15 第一组:业务系统开发题(01~06)
- 题01 满意度调查数据分析 ★★ | 题02 面谈问卷生成 ★★★ | 题03 制度RAG检索 ★★★★
- 题04 合同智能审查 ★★★ | 题05 法规收集爬虫 ★★★ | 题06 外部风险收集 ★★★
- §16 第二组:开发阶段AI评审工具题(07~11,含组内共通硬性要求)
- 题07 需求文档评审 ★★★ | 题08 设计书评审 ★★★★ | 题09 代码评审 ★★★
- 题10 测试用例评审 ★★★★ | 题11 成果物评审 ★★
**第五部分 · 自选题路径**
- 见 §1.7(事前登记制 / ≥3个功能模块闭环 / 数据脱敏或虚构)
**第三部分 · 考核内容**
- **结果与流程**:§3.1 结果申诉
- **命题题**:§3.2 命题题共通要求 | §3.3 命题题·第一组(01~06)| §3.4 命题题·第二组(07~11)
- **自选题**:见 §1.3.4 自选题路径要求(AGENTS.md 记录核心内容 / ≥3个功能模块闭环 / 数据脱敏或虚构)
---
## 1. 考核目的、方式与内容
# 第一部分 · 考核目的
### 1.1 考核目的与定位
## 1.1 考核目的与定位
L2Level 2)是 AI 人才育成体系中的能力等级,定义为:**能独立使用 AI 编码工具完成实际业务任务**。
@@ -54,21 +43,7 @@ L2Level 2)是 AI 人才育成体系中的能力等级,定义为:**能
**通过本考核 = 获得 L2 能力认证**,代表持证者具备独立运用 AI 编码工具、按工程化范式完成实际任务并留下可追溯协作记录的能力。
### 1.2 考核方式一览
| 项目 | 内容 |
|------|------|
| 形式 | 个人独立考核,禁止代做 |
| 对象 | 完成 L2 课程学习的全部受验者 |
| 选题 | 双轨制:命题题(01~11 选一)或自选题,**任选其一** |
| 周期 | 提交截止 **2026年9月30日(9月底)**,以仓库最后推送时间为准 |
| 平台 | 组委会 Giteagittea.dev)私有仓库 `l2-assessment`main 分支 |
| 开发工具 | 推荐 OpenCode / Claude Code / GitHub Copilot(不作强制);LLM API 自备 |
| 评审流程 | 系统自动拉取仓库 → 成果物齐全性自动检测 + 跨仓库查重初筛 → 评审者按 7 维框架人工评分 → 结果反馈 |
| 合格标准 | 合格线 **≥60 分**(命题题含难度赋分,满分最高110) |
| 未达标处理 | 评审结论为不合格(总分<60 或 功能完整性<15 地板线);结果申诉见 §12.4 |
### 1.3 考核目标:验证什么
### 1.1.1 考核目标:验证什么
L2 考核验证的是**落地能力**而非概念理解,具体分三个层次:
@@ -78,18 +53,36 @@ L2 考核验证的是**落地能力**而非概念理解,具体分三个层次
| 检验范式运用 | AI 编码工具真实用于开发全程,过程可追溯 | AGENTS.md + `_AI_USAGE_LOG.md` 全程留痕 |
| 产生实际价值 | 成果服务本职工作或日常场景,效能提升可感知 | README 中的痛点与效果说明 |
### 1.4 双轨选题制(任选其一)
## 1.2 考核方式与合格标准
### 1.2.1 考核方式一览
| 项目 | 内容 |
|------|------|
| 形式 | 个人独立考核,禁止代做 |
| 对象 | 完成 L2 课程学习的全部受验者 |
| 选题 | 双轨制:命题题(01~11 选一)或自选题,**任选其一** |
| 周期 | 提交截止 **2026年9月30日(9月底)**,以仓库最后推送时间为准 |
| 平台 | 组委会 Giteagittea.dev)私有仓库 `L2-assessment`,main 分支;账号**自行注册**(见 §2.2),仓库名统一,评审拉取账号需授权(见 §2.2) |
| 开发工具 | 推荐 OpenCode / Claude Code / GitHub Copilot(不作强制);LLM API 自备 |
| 评审流程 | 系统自动拉取仓库 → 成果物齐全性自动检测 + 跨仓库查重初筛 → 系统评审(AI 辅助,支持人工修正)→ 结果反馈 |
| 合格标准 | 合格线 **≥60 分** |
| 未达标处理 | 评审结论为不合格;结果申诉见 §3.1 |
## 1.3 选题路径
### 1.3.1 双轨选题制(任选其一)
| 路径 | 内容 | 适用 |
|------|------|------|
| **A 命题题** | 从下方 1.5 的两组共11道命题题中任选 1 题 | 希望按统一命题与验收基准完成 |
| **A 命题题** | 从下方 1.3.2 的两组共11道命题题中任选 1 题 | 希望按统一命题与验收基准完成 |
| **B 自选题** | 结合日常工作/生活中的效率痛点,实现一个提效工具或 Skill | 已有明确痛点,希望解决自己的实际问题 |
两条路径共用同一评分框架,合格线均为 **≥60 分**。差异仅在得分上限:命题题按所选题目难度追加赋分(★★★满分105 / ★★★★满分110),自选题按基准100分计——即高难度命题拥有更大的失分容错空间,这是有意的难度补偿设计,选择前请知悉。
两条路径共用同一套评审要求,合格标准均为 **≥60 分**。差异仅在得分上限:命题题按所选题目难度追加赋分(★★★满分105 / ★★★★满分110),自选题按基准100分计——即高难度命题拥有更大的失分容错空间,这是有意的难度补偿设计,选择前请知悉。
### 1.5 命题题内容一览
### 1.3.2 命题题内容一览
命题题共两组 11 道(下方 §15、§16 为完整权威定义):
命题题共两组 11 道(下方 §3.3、§3.4 为完整权威定义):
**第一组|业务系统开发题(01~06)**
@@ -114,42 +107,50 @@ L2 考核验证的是**落地能力**而非概念理解,具体分三个层次
| 10 | 测试用例AI评审工具 | 测试设计 | ★★★★ | 110 |
| 11 | 成果物AI评审工具 | 交付验收 | ★★ | 100 |
> 各题的业务需求、验收基准、样本数据与植入问题要求的完整定义各题完整需求定义见 §15、§16(本文档最后两章),无需查阅其他文档。
> 各题的业务需求、验收基准、样本数据与植入问题要求的完整定义见 §3.3、§3.4(本文档最后两章),无需查阅其他文档。
### 1.6 命题题路径要求
### 1.3.3 命题题路径要求
- 从两组共11道题中任选 1 题,按该题的业务需求、验收基准、样本数据要求执行
- README 首页标注「**选题路径:命题**」及「**选题编号与标题**」(如:命题 08|设计书AI评审工具)
### 1.7 自选题路径要求
### 1.3.4 自选题路径要求
自选题须满足以下三条约束:
1. **事前登记制**:开工前向组委会提交题目登记(一句话题目名称 + 痛点描述 + 预期功能清单),经确认后方可开始开发。登记同时用于避免与他人撞题。提交渠道与登记模板由组委会另行通知。登记的功能清单具有约束力:README 功能声明不得低于登记范围的核心功能;确需缩减的,须在截止日前向组委会更新登记并说明理由,未经更新的缩减部分按未实现计分。开发起始时间以登记确认后的首次 git commit 为准,早于确认的开发记录不影响评审,但须在 AGENTS.md 中说明。
1. **AGENTS.md 记录自选题核心内容**:自选题须在 AGENTS.md 中讲清楚以下核心内容——
- **选题名称与痛点背景**:一句话概括选题 + 解决什么痛点、给谁用
- **预期功能清单**:计划实现的核心功能模块(不低于「规模下限」要求)
- **功能边界**:明确哪些功能已实现、哪些不实现(诚实声明)
- **开发起始时间**:以首次 `git commit` 时间为准,早于确认的开发记录不影响评审
AGENTS.md 中的功能清单具有约束力:README 功能声明不得低于其记录的核心功能;确需缩减的,须在 AGENTS.md 中说明缩减范围与理由,未说明的缩减部分按未实现计分。
2. **规模下限**:至少包含「输入处理 → 核心逻辑 → 结果呈现」的完整闭环,功能模块不少于 **3 个**。功能模块指用户可感知的独立功能单元(如「文件导入」「规则配置」「报告导出」各计一个),纯工具函数与界面装饰不计入模块数;整体规模应明显超出单脚本范畴(通常数百行及以上)。
3. **信息安全红线**:禁止使用真实业务数据、客户数据、公司内部代码作为样本或素材;示例数据必须脱敏或虚构。
README 首页标注「**选题路径:自选**」,并附痛点背景与预期效果说明。
### 1.8 选题声明(必填)
### 1.3.5 选题声明(必填)
无论哪条路径,README 首页须包含:
```
选题路径:命题 / 自选
选题名称:(命题题填编号与标题;自选题填登记的题目名称)
选题名称:(命题题填编号与标题;自选题填 AGENTS.md 中记录的题目名称)
使用AI工具:(实际使用的AI编码工具,如 OpenCode / Claude Code / Copilot
```
---
## 2. 开发工具与模型
# 第二部分 · 提交要求
## 2.1 开发工具与模型
| 项目 | 要求 |
|------|------|
| AI编码工具 | **不作强制指定**,推荐使用 **OpenCode / Claude Code / GitHub Copilot** 之一,也可自行选择其他同类工具 |
| 工具记录 | 实际使用的工具及版本须在 README「使用AI工具」处声明,并在 AGENTS.md 中记录运用方式 |
| LLM 模型/API | 由受验者自备(推荐 DeepSeek 等免费方案);海外服务使用注意信息安全(见 §9 |
| LLM 模型/API | 由受验者自备(推荐 DeepSeek 等免费方案);海外服务使用注意信息安全(见 §2.7 |
| 课程技术 | VibeCoding / Superpowers / SpecKit / Skill / MCP自动化测试中**至少选 1 项**运用于开发过程,并在 AGENTS.md 记录运用方式 |
| LLM异常处理 | 凡涉及 LLM/API 调用的功能,必须具备以下至少一项防护:超时设置、异常捕获、降级或显式错误提示。缺失将在功能完整性维度扣分 |
| 评审期LLM支持 | 组委会为评审环节统一提供 DeepSeek API Key;同时受验者须在 `data/` 中留存关键 LLM 功能的真实响应样例,保证无 Key 环境也能核验核心逻辑 |
@@ -158,49 +159,59 @@ README 首页标注「**选题路径:自选**」,并附痛点背景与预期
---
## 3. Gitea 账号规范
## 2.2 Gitea账号与仓库
> **本次考核由受验者自行注册 Gitea 账号**,组委会不统一下发账号。请按下述规则注册并完成授权登记,评审系统才能正常拉取你的仓库。
| 项目 | 要求 |
|------|------|
| 用户名 | 使用组委会下发的**独立账号**,**禁止修改、禁止换绑** |
| 密码 | 使用组委会下发的初始密码,**请勿修改**。修改后评审系统将无法拉取仓库,影响评审结果 |
| 注册方式 | 受验者**自行注册**组委会 Gitea(`gittea.dev`)账号 |
| 用户名 | **统一使用本人员工编号**(如 `SD0102`),便于身份识别与系统拉取;**注册后禁止修改、禁止换绑** |
| 用户名格式注意 | Gitea 用户名**不能以数字开头**;若员工编号以数字开头(如 `0102`),请使用小写前缀形式(如 `sd0102`)注册 |
| 密码 | 注册后自行保管,**请勿忘记**;密码修改不影响评审(评审系统使用授权协作者方式拉取,见下) |
| 账号用途 | 仅用于本次 L2 考核成果物存放,禁止外借、禁止多账号混用 |
| **授权登记** | 注册完成后,须将以下信息提交组委会登记(登记方式与渠道由组委会另行通知):**员工编号、Gitea 用户名、仓库名**。未登记将无法拉取,按未提交处理 |
> 评审系统使用每人的账号凭据自动拉取仓库;凭据被修改即拉取失败,按未提交处理。
> **拉取机制(重要)**:评审系统使用组委会专用的**评审拉取账号**(只读)克隆各受验者仓库。请每位受验者**将自己仓库的「只读(Reporter)」协作权限授予评审拉取账号**。评审拉取账号名与操作指引随**报名确认通知**一并公布(未收到请联系组委会)。未授权 → 系统无法克隆 → 按未提交处理。
---
## 4. 仓库规范
### 2.2.1 仓库规范
| 项目 | 要求 |
|------|------|
| 平台 | 统一使用组委会 Gitea(`gittea.dev` |
| **仓库名称** | **统一为 `l2-assessment`**(连字符,无空格) |
| 可见性 | **Private(私有)**;评审系统使用下发凭据拉取,无需公开 |
| 平台 | 统一使用组委会 Gitea(`gittea.dev`**自注册账号**(见 §2.2 |
| **仓库名称** | **统一为 `L2-assessment`**(连字符,无空格,英文 |
| 可见性 | **Private(私有)**;评审系统使用评审拉取账号(协作者只读权限)克隆,无需公开 |
| 默认分支 | **`main`** |
| 提交方式 | 截止前 `git push` 到 main 分支,评审以仓库最新提交为准 |
| 提交历史 | 鼓励小步多次 commit、保留完整演进历史(见 §10 过程真实性) |
| 提交历史 | 鼓励小步多次 commit、保留完整演进历史(见 §2.8 过程真实性) |
| **授权协作者** | **必须**将评审拉取账号(见 §2.2)添加为本仓库**只读(Reporter)**协作者;未授权将无法拉取,按未提交处理 |
> 拉取 URL 格式:`https://gittea.dev/<你的用户名>/L2-assessment.git`(用户名 = 员工编号,见 §2.2)。评审系统将按此格式 + 登记信息自动拉取。
---
## 5. 成果物清单与放置规则
## 成果物需求
`l2-assessment` 仓库 main 分支下放入下列文件 → `git add .``git commit``git push origin main`
## 2.3 成果物清单与放置规则
`L2-assessment` 仓库 main 分支下放入下列文件 → `git add .``git commit``git push origin main`
| # | 成果物 | 放置位置(命名) | 内容要求 |
|---|--------|----------------|---------|
| 01 | 项目说明 | 根目录 `README.md` | 按 §6 要求详细编写:选题声明、痛点背景、功能说明、效果总结、安装运行方法 |
| 01 | 项目说明 | 根目录 `README.md` | 按 §2.4 要求详细编写:选题声明、痛点背景、功能说明、效果总结、安装运行方法 |
| 02 | 设计文档 | 根目录 `DESIGN.md`,或 `docs/``design/` 目录内 | 场景与价值、开发范式流程图、架构图、关键设计决策 |
| 03 | 源码 | 仓库根目录,或 `src/` 目录内 | 可安装、可一键运行;安装步骤、运行方法写在 README.md |
| 04 | 测试 | `tests/` 目录内,附测试执行日志或结果截图 | 测试用例清单 + 执行结果,覆盖核心逻辑的正常与异常路径;至少 3 个用例(命题题从其题目约定) |
| 05 | AI 使用日志 | 根目录 `_AI_USAGE_LOG.md` | 覆盖需求/设计/编码/测试全环节,格式见 §8 |
| 06 | AI 协作记录 | 根目录 `AGENTS.md` | 技术运用过程、prompt原文、人工修正点、问题与对策(见 §8 |
| 05 | AI 使用日志 | 根目录 `_AI_USAGE_LOG.md` | 覆盖需求/设计/编码/测试全环节,格式见 §2.6 |
| 06 | AI 协作记录 | 根目录 `AGENTS.md` | 技术运用过程、prompt原文、人工修正点、问题与对策(见 §2.6 |
| 07 | 样本数据 | `data/``sample/``fixtures/` 目录 | 运行所需样例数据;命题题须含该题要求的缺陷标注清单等;全部数据须脱敏或虚构 |
**仓库目录结构**
```
l2-assessment/ # 仓库根目录(main 分支)
L2-assessment/ # 仓库根目录(main 分支)
├── README.md # 01 项目说明
├── DESIGN.md # 02 设计文档(含架构图、范式图)
├── src/ # 03 源码
@@ -216,41 +227,41 @@ l2-assessment/ # 仓库根目录(main 分支)
> 放置规则:
> - 成果物须位于根目录或上表约定目录;评审系统不递归到任意深层目录。
> - 文件名/目录名用 ASCII 小写字母、数字、连字符、下划线,禁止空格与中文。
> - **不要求提交演示视频**,亦不接收仓库外的任何补充材料;Web 类作品按 §11 登记 service_url,供评审实测验证。
> - **不要求提交演示视频**,亦不接收仓库外的任何补充材料;Web 类作品按 §2.9 登记 service_url,供评审实测验证。
---
## 6. README 编写要求(重点)
## 2.4 README 编写要求(重点)
README 是评审者了解作品的第一个入口,**必须尽可能说清楚**。以下内容缺一项即视为项目说明不完整,对应维度扣分:
### 6.1 痛点背景(为什么做)
### 2.4.1 痛点背景(为什么做)
- 解决什么问题、给谁用(目标用户/场景)
- 现状是怎么做的、低效在哪里(自选题必须有此节,命题题为该题业务场景的理解分析)
### 6.2 功能说明(做了什么)
### 2.4.2 功能说明(做了什么)
- 功能清单逐条列出,每条说明:功能是什么、怎么用、输入输出是什么
- 有界面/命令行交互的,给出操作示例(示例命令、调用方式均可)
- 明确说明哪些功能已实现、哪些未实现(诚实声明优于含糊其辞)
### 6.3 效果总结(带来了什么价值)
### 2.4.3 效果总结(带来了什么价值)
- 提效对比:改造前后耗时对比、错误率变化等,能用简单数字说明最好(如「原来人工核对一份需 30 分钟,现在 2 分钟」)
- **提效数字须附测量方式**(如何计时、对比的场景与步骤说明),关键原始记录建议放入 `tests/``data/`;无测量依据的夸大数据将在可信度上扣分
- **命题题无真实历史基线时的诚实做法**:基于模拟场景做小样本试用并如实记录测得数据(试用步骤+计时即可);**禁止凭空编造未经实测的数字**
- 无法量化的,说明解决了的具体痛点和实际使用反馈
### 6.4 安装与运行(怎么跑起来)
### 2.4.4 安装与运行(怎么跑起来)
- 环境要求(OS、语言版本、依赖)
- 安装步骤(逐步可复制执行)
- 运行方法(启动命令、参数说明)
- 规则配置说明:涉及检查规则/标准配置的工具,说明配置文件位置与修改方法
### 6.5 效果与功能的一致性
### 2.4.5 效果与功能的一致性
- README 声称的功能须能在代码和运行中找到对应实现;评审存在「声称 vs 实测」交叉验证,不符将扣分
---
## 7. 设计文档要求
## 2.5 设计文档要求
| 内容项 | 说明 |
|--------|------|
@@ -261,9 +272,9 @@ README 是评审者了解作品的第一个入口,**必须尽可能说清楚**
---
## 8. AI 协作过程留痕(评审重点)
## 2.6 AI 协作过程留痕(评审重点)
### 8.1 AI 使用日志(`_AI_USAGE_LOG.md`
### 2.6.1 AI 使用日志(`_AI_USAGE_LOG.md`
每条记录包含以下字段:
@@ -282,7 +293,7 @@ README 是评审者了解作品的第一个入口,**必须尽可能说清楚**
每次创建或修改代码文件后,在项目根目录的 `_AI_USAGE_LOG.md` 中追加一条记录,必须包含:日期时间、范式步骤、修改摘要、涉及文件、使用模型
```
### 8.2 AI 协作记录(`AGENTS.md`
### 2.6.2 AI 协作记录(`AGENTS.md`
记录内容:
@@ -319,7 +330,7 @@ README 是评审者了解作品的第一个入口,**必须尽可能说清楚**
---
## 9. 通用命名与内容红线
## 2.7 通用命名与内容红线
1. **文件名**:统一使用 ASCII 小写字母、数字、连字符(-)或下划线(_);禁止空格、中文、全角字符、特殊符号。**例外**:本规范约定的固定命名文件(`README.md``DESIGN.md``_AI_USAGE_LOG.md``AGENTS.md` 等)不受小写限制。
2. **禁止提交**:密钥/token/密码/`.env` 等敏感文件;构建产物(`node_modules/``dist/``build/``target/``__pycache__/`);单个 >50MB 的二进制文件。
@@ -329,7 +340,7 @@ README 是评审者了解作品的第一个入口,**必须尽可能说清楚**
---
## 10. 独立完成与查重红线
## 2.8 独立完成与查重红线
**本次考核为个人独立考核。** 评审系统将对全部提交做跨仓库相似度初筛,以下情形将被标记并进入人工认定:
@@ -347,14 +358,14 @@ README 是评审者了解作品的第一个入口,**必须尽可能说清楚**
- 初筛告警由评审者人工复核认定;单次全量 push 等行为信号本身**不构成违规认定**,仅作为复核参考——被标记者应能在 AGENTS.md 与 git 历史中给出独立完成的依据
- **查实抄袭:本题按 0 分处理,处理结果记入考核档案**
- 允许查阅公开资料与使用 AI 生成,但须如实记录(见 §8);未记录的他人代码片段视为抄袭
- 允许查阅公开资料与使用 AI 生成,但须如实记录(见 §2.6);未记录的他人代码片段视为抄袭
- 组委会保留对可疑情形**约谈核实**的权利:可要求受验者现场讲解任意一段核心实现的思路与取舍;拒绝配合或讲解与提交代码明显不符的,按查实抄袭处理
---
## 11. 源码可运行前提(强制)
## 2.9 源码可运行前提(强制)
**源码无法按 README 启动运行的,属重大缺陷:功能完整性维度最高计 10 分、测试用例与测试结果维度最高计 5 分,并在评语中标注「不可运行」。仅当失败原因明确属于评审环境所致(如内网专用依赖),登记后改期复验。**
**源码无法按 README 启动运行的,属重大缺陷,并在评语中标注「不可运行」。仅当失败原因明确属于评审环境所致(如内网专用依赖),登记后改期复验。**
- 依赖随仓库可复现(含依赖清单/锁文件),不依赖外部不可达资源
- Web 类作品建议在 README 登记 service_url,供评审实测验证
@@ -364,45 +375,17 @@ README 是评审者了解作品的第一个入口,**必须尽可能说清楚**
---
## 12. 考核标准
## 2.10 提交前自查清单
### 12.1 评分维度与评审要点
评审基于共通 7 维框架,满分 100 分:
| 维度 | 分值 | 评审要点 |
|------|:---:|---------|
| 功能完整性 | 30 | 核心需求是否全部实现、主要功能路径可运行;命题题按该题验收基准表逐项评定,自选题按README声明功能清单核对实现情况 |
| 设计文档 | 10 | 架构图清晰完整、范式流程图与AI日志逐步对应、关键设计决策有理由有取舍 |
| 测试用例与测试结果 | 10 | 用例覆盖正常与异常路径、数量达标、执行结果真实可复现 |
| AI协作过程记录 | 15 | prompt原文完整可追溯、人工修正点如实记录、AI日志字段齐全且与git历史一致(日志造假直接扣分) |
| 技术选型与范式运用 | 15 | 课程技术至少1项真实运用且深度合理(非表面套用)、工具链选型有理由 |
| 代码质量 + README | 10 | 结构清晰、命名规范、无硬编码密钥;README四部分(痛点/功能/效果/运行)完整说清 |
| 业务场景理解与需求分析 | 10 | 对痛点理解准确、需求分析到位、效果总结可信不自夸 |
### 12.2 合格线与赋分
- **合格线:≥60 分**;命题题另按所选题目的难度赋分(★★★+5 / ★★★★+10),自选题按基准 100 分计(差异说明见 §1.4)
- **功能完整性评分锚点**:命题题按该题验收基准表逐项评定;自选题按 README 声明的功能清单逐项核对实现情况评定(结合「声称 vs 实测」验证,未实现或与声明不符的功能不计分)
- **功能完整性地板线**:该维度得分低于 15 分(不足满分一半)时,无论总分多少均判为**不合格**——防止「文档精美、功能空壳」的提交过线
### 12.3 结果申诉
- 对评分结果或查重认定有异议的,可在收到结果之日起 **3 个工作日内**向组委会提交一次复核申请(列明异议点与依据)
- 由**未参与原评审**的人员进行复核,**5 个工作日内**书面答复;复核结论为最终结论
- 复核仅核查评分是否与本规范及所选题目验收基准相符,不进行整体重新评审
---
## 13. 提交前自查清单
- [ ] 已在截止时间前 `git push``l2-assessment` 的 main 分支
- [ ] 已用组委会账号登录 Gitea,密码未修改
- [ ] 已在截止时间前 `git push``L2-assessment` 的 main 分支
- [ ] 已用**自注册**账号登录 Gitea(用户名 = 员工编号,见 §2.2)
- [ ] 已将员工编号 / Gitea 用户名 / 仓库名**提交登记**给组委会
- [ ] 已将**评审拉取账号**添加为本仓库**只读(Reporter)协作者**(见 §2.2),并确认其可访问
- [ ] README 首页有选题声明(路径/名称/使用AI工具)
- [ ] (自选题)已完成事前登记,且README功能声明不低于登记范围的核心功能
- [ ] (自选题)AGENTS.md 已记录选题名称、痛点背景、功能清单与功能边界,README 功能声明不低于其中核心功能
- [ ] README 含完整的痛点背景、功能说明、效果总结、安装运行四部分
- [ ] 效果总结中的提效数字已附测量方式与原始记录
- [ ] 成果物齐全且按 §5 放置:README、DESIGN.md(含范式图与架构图)、src/、tests/、`_AI_USAGE_LOG.md`、AGENTS.md、data/ 样本数据
- [ ] 成果物齐全且按 §2.3 放置:README、DESIGN.md(含范式图与架构图)、src/、tests/、`_AI_USAGE_LOG.md`、AGENTS.md、data/ 样本数据
- [ ] `_AI_USAGE_LOG.md` 字段完整,范式步骤与范式图一致
- [ ] AGENTS.md 含 prompt原文、人工修正点、问题与对策
- [ ] 课程技术(VibeCoding/Skill/Superpowers/SpecKit/MCP)至少 1 项已运用于开发过程并在 AGENTS.md 记录运用方式
@@ -413,12 +396,12 @@ README 是评审者了解作品的第一个入口,**必须尽可能说清楚**
---
## 14. 违规后果
## 2.11 违规后果
| 情形 | 后果 |
|------|------|
| 超过截止时间未提交/未push | 迟交 1~3 个工作日扣 5 分,4~7 个工作日扣 10 分;超 7 个工作日按 0 分处理、不再评审 |
| 仓库名、分支、凭据不符合规范 | 评审系统无法拉取,按未提交处理 |
| 仓库名、分支不符合规范,或**未登记 / 未授权评审拉取账号** | 评审系统无法拉取,按未提交处理 |
| 必填成果物缺失或命名不符 | 对应成果物判定为未提交,相关维度扣分 |
| README 声称功能与实测不符 | 真实性扣分 |
| AI 日志缺失或空白 | 相关维度扣分 |
@@ -428,18 +411,39 @@ README 是评审者了解作品的第一个入口,**必须尽可能说清楚**
---
# 第三部分 · 考核内容
## 3.1 结果申诉
- 对评分结果或查重认定有异议的,可在收到结果之日起 **3 个工作日内**向组委会提交一次复核申请(列明异议点与依据)
- 由**未参与原评审**的人员进行复核,**5 个工作日内**书面答复;复核结论为最终结论
- 复核仅核查评分是否与本规范及所选题目验收基准相符,不进行整体重新评审
---
## 15. 命题题详细需求 · 第一组:业务系统开发题(01~06
## 3.2 命题题共通要求(每题均适用
> 本组6道题为「业务系统」类选题(数据统计/RAG检索/合同审查/爬虫/风险监控)。选定某题后,依次细读该题的【业务场景 → 考核技术 → 业务需求 → 验收基准 → 提交物清单 → 评分标准】六节
> 各题【提交物清单】为该题专属补充项;通用7项成果物(README / DESIGN / src / tests / `_AI_USAGE_LOG.md` / `AGENTS.md` / data样本数据)以 §5 为准,每题均须提交。> 各类**评分型指标**(置信度、影响度、准确率、「高频」阈值等)的具体计算口径由受验者自行定义,但必须在设计文档中写明;验收时以「口径清晰 + 结果可复现」为准,不要求与任何标准答案一致。涉及「与公司业务相关性」评估的题目,受验者须在 README 中给出虚构的公司画像(行业、规模、主要业务范围)作为统一评估基准。
**成果物**:通用 7 项成果物(README / DESIGN / src / tests / `_AI_USAGE_LOG.md` / `AGENTS.md` / data 样本数据)以 §2.3 为准,每题均须提交。各题仅在「本题专属要求」中列差异项,未列出的均按 §2.3 通用要求执行
**考核技术(至少选 1 项)**:从以下 5 种课程技术中至少选 1 项真实运用于开发,并在 AGENTS.md 中记录运用方式(各技术通用的记录要求见 §2.1 与 §2.6):
| 技术 | 通用要求 |
|------|---------|
| **VibeCoding** | 记录 prompt 原文 / 生成过程 / 人工修正点 / 遇到的问题与对策 |
| **SpecKit** | 先编写规格文档再实现;记录规格定义过程 / spec 与实现的对应关系 / 边界情况处理策略 |
| **Skill** | 将功能封装为独立 Skill;记录各 Skill 接口定义 / 调用链路 / 复用方式 |
| **Superpowers** | 用 Superpowers 组合构建管道;记录注册与组合逻辑 / 各 Superpower 职责边界 |
| **MCP自动化测试** | 关键路径用 MCP Server 自动测试;记录 Server 配置 / 测试用例定义 / 执行结果与覆盖率 |
> 本组6道题为「业务系统」类选题(数据统计/RAG检索/合同审查/爬虫/风险监控)。选定某题后,依次细读该题的【业务场景 → 考核技术 → 业务需求 → 验收基准 → 提交物清单 → 评分标准】六节
> 各题【提交物清单】为该题专属补充项;通用7项成果物(README / DESIGN / src / tests / `_AI_USAGE_LOG.md` / `AGENTS.md` / data样本数据)以 §5 为准,每题均须提交。> 各类**评分型指标**(置信度、影响度、准确率、「高频」阈值等)的具体计算口径由受验者自行定义,但必须在设计文档中写明;验收时以「口径清晰 + 结果可复现」为准,不要求与任何标准答案一致。涉及「与公司业务相关性」评估的题目,受验者须在 README 中给出虚构的公司画像(行业、规模、主要业务范围)作为统一评估基准。
> **技术组合规则**:鼓励在同一题中组合多项技术(如 VibeCoding 做前端 + Skill 做统计引擎 + MCP 做测试),组合使用在评分中会有加分。各题「考核技术」一节仅列出**本题推荐运用**的技术与示例,不代表限定
**评分型指标**:各类**评分型指标**(置信度、影响度、准确率、「高频」阈值等)的具体计算口径由受验者自行定义,但必须在设计文档中写明;验收时以「口径清晰 + 结果可复现」为准,不要求与任何标准答案一致。涉及「与公司业务相关性」评估的题目,受验者须在 README 中给出虚构的公司画像(行业、规模、主要业务范围)作为统一评估基准。
## 3.3 命题题 · 第一组:业务系统开发题(01~06)
### 3.3.1 组定位
本组 6 道题为「业务系统」类选题(数据统计/RAG检索/合同审查/爬虫/风险监控)。选定某题后,依次细读该题的【业务场景 → 业务需求 → 验收基准 → 本题专属要求】各节。
### 题01|年度满意度调查数据的自动处理与分析
@@ -456,15 +460,10 @@ README 是评审者了解作品的第一个入口,**必须尽可能说清楚**
#### 考核技术(至少选1项)
| 技术 | 本题中的运用示例 | AGENTS.md中需记录的内容 |
|------|----------------|------------------------|
| **VibeCoding** | 通过提示词直接生成模板解析+统计+看板的全套功能 | 使用的prompt原文 / 生成过程 / 人工修正点 / 遇到的问题与对策 |
| **SpecKit** | 先编写规格文档再实现,覆盖所有边界情况 | 规格定义过程 / spec与实现的对应关系 / 边界情况处理策略 |
| **Skill** | 将「模板解析」「统计引擎」「图表生成」封装为独立Skill | 各Skill的接口定义 / 调用链路 / 复用方式 |
| **Superpowers** | 用Superpowers组合方式构建统计管道 | Superpower的注册与组合逻辑 / 各Superpower的职责边界 |
| **MCP自动化测试** | 关键路径通过MCP Server自动测试验证 | MCP Server配置 / 测试用例定义 / 执行结果与覆盖率 |
> **技术组合规则**:至少选择1项技术。鼓励在同一题中组合多项技术(如:VibeCoding做前端 + Skill做统计引擎 + MCP做测试),组合使用在评分中会有加分。
> 课程技术共同要求见 §3.2 前言(VibeCoding/SpecKit/Skill/Superpowers/MCP 五选一,鼓励组合加分)。本题推荐运用:
> - **VibeCoding**:通过提示词直接生成模板解析+统计+看板的全套功能
> - **Skill**:将「模板解析」「统计引擎」「图表生成」封装为独立Skill
> - **MCP自动化测试**:关键路径通过MCP Server自动测试验证
#### 业务需求
@@ -498,7 +497,8 @@ README 是评审者了解作品的第一个入口,**必须尽可能说清楚**
- 根据分析结论自动提出改善建议(如「XX部门的沟通满意度连续两年下降,建议加强部门内定期的1on1面谈」)
- 改善建议应可量化、可执行、针对具体部门
- 实现方式不限:规则引擎或 LLM 生成均可;若使用 LLM,须包含超时与异常降级处理(见 §2)。
- 实现方式不限:规则引擎或 LLM 生成均可;若使用 LLM,须包含超时与异常降级处理(见 §2.1)。
#### 验收基准
| 验收项 | 最低合格线 | 满分标准 | 验证方式 |
@@ -509,31 +509,11 @@ README 是评审者了解作品的第一个入口,**必须尽可能说清楚**
| 权限隔离 | 部门管理员看不到其他部门数据 | 纯前端方案说明生产替代方案 | 检查AGENTS.md中的权限说明 |
| 分析深度 | 能标识得分最低的1-2个维度 | 能识别下降趋势、给出具体改善建议 | 在样本数据中植入下降维度,验证分析结果 |
#### 提交物清单
#### 本题专属要求(其余按 §3.2 通用要求)
| # | 提交物 | 内容要求 | 必须/可选 |
|---|--------|---------|----------|
| 1 | 源代码 | 完整可运行的项目代码 | **必须** |
| 2 | README | 环境要求(OS、语言版本、依赖)、安装步骤、运行方法、功能说明 | **必须** |
| 3 | 设计文档 | 架构图 / 数据流图 / 技术选型理由 / 关键设计决策 | **必须** |
| 4 | 测试用例 + 测试结果 | 至少3个测试用例,覆盖核心逻辑的正常路径和异常路径,附执行结果 | **必须** |
| 5 | AGENTS.md | 技术运用过程记录、设计决策理由、遇到的问题与解决方案 | **必须** |
| 6 | 样本数据 | 至少2个年度的模拟Excel数据(多Sheet),包含正常数据和边界数据(边界数据指:空值或缺失字段、重复记录、维度名前后不一致、评分超出合理范围等异常情形) | **必须** |
**测试用例与测试结果**:至少 3 个测试用例,覆盖核心逻辑的正常路径和异常路径,附执行结果。
#### 评分标准(100分)
| 评审项 | 分值 | 评审方式 |
|--------|:---:|---------|
| 功能完整性 | 30分 | 模板管理5分(上传+自动识别+确认)/ 数据导入与统计10分(导入+多维度统计+年度对比)/ 权限区分5分(两种角色隔离)/ 看板展示5分(图表+下钻)/ 智能分析5分(薄弱维度识别+改善建议) |
| 设计文档 | 10分 | 架构合理、图表达清晰、设计决策有依据 |
| 测试用例与测试结果 | 10分 | 测试覆盖核心逻辑、测试结果可复现 |
| AI协作过程记录(AGENTS.md) | 15分 | 技术运用过程记录完整、prompt原文和人工修正点可追溯 |
| 技术选型与范式运用 | 15分 | 选型理由充分,VibeCoding/Skill等运用记录合理 |
| 代码质量 + README | 10分 | 结构清晰、命名规范、README完整可运行 |
| 业务场景理解与需求分析 | 10分 | 对满意度调查场景理解准确,需求分析到位 |
| **合计** | **100分** | |
> 本题为★★难度,满分100分,合格条件:≥60分。功能完整性30分中,模板管理(5分)+数据导入与统计(10分)+权限区分(5分)+看板展示(5分)+智能分析(5分)合计30分为必达项,为所有题目的基准难度。
**样本数据**:至少 2 个年度的模拟 Excel 数据(多 Sheet),包含正常数据和边界数据(边界数据指:空值或缺失字段、重复记录、维度名前后不一致、评分超出合理范围等异常情形)。
---
@@ -553,13 +533,10 @@ README 是评审者了解作品的第一个入口,**必须尽可能说清楚**
#### 考核技术(至少选1项)
| 技术 | 本题中的运用示例 | AGENTS.md中需记录的内容 |
|------|----------------|------------------------|
| **Skill** | 将「规则引擎」「问卷生成」「话题分类」「共性问题提取」「改善建议生成」封装为独立Skill | 各Skill的接口定义 / 规则与LLM的分工 / 准确率验证 |
| **MCP自动化测试** | 对规则判定逻辑和LLM输出质量进行自动化测试验证 | MCP Server配置 / 测试用例设计 / 准确率基准 |
| **VibeCoding** | 用提示词直接实现导入→规则配置→分析→问卷生成→看板的完整流程 | 使用的prompt原文 / 生成过程 / 规则与LLM的分工策略 |
| **Superpowers** | 用Superpowers组合构建分析管道(规则引擎 + LLM分析 + 报告生成) | Superpower的注册与组合逻辑 / 各Superpower的职责边界 |
| **SpecKit** | 先定义规则配置规范、分析策略、输出格式规格 | 规格定义过程 / 规则与spec的对应关系 |
> 课程技术共同要求见 §3.2 前言(VibeCoding/SpecKit/Skill/Superpowers/MCP 五选一,鼓励组合加分)。本题推荐运用:
> - **Skill**:将「规则引擎」「问卷生成」「话题分类」「共性问题提取」「改善建议生成」封装为独立Skill
> - **MCP自动化测试**:对规则判定逻辑和LLM输出质量进行自动化测试验证
> - **VibeCoding**:用提示词直接实现导入→规则配置→分析→问卷生成→看板的完整流程
#### 业务需求
@@ -617,32 +594,11 @@ README 是评审者了解作品的第一个入口,**必须尽可能说清楚**
| 共性问题提取 | 植入5个高频话题,至少检出3个 | 全部检出且噪音少 | mock数据中控制话题分布,验证提取结果 |
| 改善建议相关性 | 建议与发现的问题主题相关 | 建议可量化、可执行、针对具体部门 | 检查建议是否针对特定部门、有具体行动描述 |
#### 提交物清单
#### 本题专属要求(其余按 §3.2 通用要求)
| # | 提交物 | 内容要求 | 必须/可选 |
|---|--------|---------|----------|
| 1 | 源代码 | 完整可运行的项目代码 | **必须** |
| 2 | README | 环境要求(含LLM配置)、安装步骤、运行方法、功能说明 | **必须** |
| 3 | 设计文档 | 架构图 / 规则引擎设计 / 规则与LLM的分工策略 / 分析模型选择依据 | **必须** |
| 4 | 测试用例 + 测试结果 | 至少3个测试用例,覆盖规则配置、话题分类、共性问题提取 | **必须** |
| 5 | AGENTS.md | 技术运用过程记录、规则调优过程、分类调优过程、LLM调优日志 | **必须** |
| 6 | 样本数据 | 至少2个年度的满意度调查模拟Excel(用于验证「前年比下降」规则) + 至少30条模拟面谈记录(覆盖5个话题分类、3个部门) | **必须** |
**测试用例与测试结果**:至少 3 个测试用例,覆盖规则配置、话题分类、共性问题提取。
#### 评分标准(100分 + 难度赋分5分)
| 评审项 | 分值 | 评审方式 |
|--------|:---:|---------|
| 功能完整性 | 30分 | 规则配置与低分识别10分 / 问卷生成10分 / 面谈数据导入5分 / 看板展示5分(智能分析的分数含在上述各项中:话题分类准确率→规则配置分、共性问题提取→问卷生成分、改善建议→看板展示分,不单独计分) |
| 设计文档 | 10分 | 架构合理,规则与LLM分工策略清晰,选型有依据 |
| 测试用例与测试结果 | 10分 | 覆盖规则配置、话题分类、共性问题提取,结果可复现 |
| AI协作过程记录(AGENTS.md) | 15分 | 过程记录完整,规则调优、分类调优、LLM调优日志可追溯 |
| 技术选型与范式运用 | 15分 | Skill/Superpowers/VibeCoding等选型理由充分 |
| 代码质量 + README | 10分 | 结构清晰、命名规范、README完整 |
| 业务场景理解与需求分析 | 10分 | 对面谈调查场景理解准确,需求分析到位 |
| 难度赋分 | 5分 | ★★★难度追加 |
| **合计** | **105分** | |
> 本题为★★★难度,满分105分,合格条件:≥60分。
**样本数据**:至少 2 个年度的满意度调查模拟 Excel(用于验证「前年比下降」规则)+ 至少 30 条模拟面谈记录(覆盖 5 个话题分类、3 个部门)。
---
@@ -663,15 +619,10 @@ README 是评审者了解作品的第一个入口,**必须尽可能说清楚**
#### 考核技术(至少选1项)
| 技术 | 本题中的运用示例 | AGENTS.md中需记录的内容 |
|------|----------------|------------------------|
| **Superpowers** | 用Superpowers组合构建RAG管道(文档加载 + 文本分割 + 向量化 + 检索 + 生成回答 + 质量评估) | Superpower的注册与组合逻辑 / 各环节参数调优 / 检索策略切换逻辑 |
| **MCP自动化测试** | 对检索准确率、检索策略切换、质量评估逻辑进行自动化测试 | MCP Server配置 / 测试集构建 / 评估指标设计 / 各策略对比测试 |
| **Skill** | 将「文档解析」「多种检索策略」「chunk管理」「质量评估」「制度关联」「分析看板」封装为独立Skill | 各Skill的接口定义 / embedding模型选择理由 / chunk策略 / 检索策略对比 |
| **VibeCoding** | 用提示词直接实现文档上传→多种检索→质量评估→分析看板的完整流程 | 使用的prompt原文 / 生成过程 / chunk大小调优 / 检索策略切换的prompt设计 |
| **SpecKit** | 先定义文档格式规范、多检索策略规格、质量评估标准、分析指标规格 | 规格定义过程 / 各检索策略与spec的对应关系 / 质量评估标准定义 |
> **难度说明**:本题为★★★★难度,满分110分(含难度赋分10分),合格线60分。功能完整性30分中,基础检索(10分)+文档管理(5分)+无法回答处理(5分)+追问(5分)合计25分为基础必达项,在此基础上实现检索策略切换、质量可视化、Chunk管理、制度关联、分析看板中的任意1~2项即可达到合格线。
> 课程技术共同要求见 §3.2 前言(VibeCoding/SpecKit/Skill/Superpowers/MCP 五选一,鼓励组合加分)。本题推荐运用:
> - **Superpowers**:用Superpowers组合构建RAG管道(文档加载 + 文本分割 + 向量化 + 检索 + 生成回答 + 质量评估)
> - **MCP自动化测试**:对检索准确率、检索策略切换、质量评估逻辑进行自动化测试
> - **Skill**:将「文档解析」「多种检索策略」「chunk管理」「质量评估」封装为独立Skill
#### 业务需求
@@ -754,34 +705,13 @@ README 是评审者了解作品的第一个入口,**必须尽可能说清楚**
| 制度间关联 | 关联提示与检索内容相关 | 关联准确,管理员可手动管理关联 | 检查关联条款的准确性 |
| 分析看板 | 显示高频搜索词 | 高频词+无法回答+质量趋势+文档热度全部显示 | 提交多个查询后验证看板数据 |
> 注:上表中「检索策略切换」「检索质量可视化」「Chunk管理」「制度间关联」「分析看板」5 项为**加分项(任选其一,计 5 分**,其余各项为基础必达项。
> 注:上表中「检索策略切换」「检索质量可视化」「Chunk管理」「制度间关联」「分析看板」5 项为**加分项(任选其一)**,其余各项为基础必达项。
#### 提交物清单
#### 本题专属要求(其余按 §3.2 通用要求)
| # | 提交物 | 内容要求 | 必须/可选 |
|---|--------|---------|----------|
| 1 | 源代码 | 完整可运行的项目代码 | **必须** |
| 2 | README | 环境要求(含向量数据库/LLM配置)、安装步骤、运行方法、检索策略说明 | **必须** |
| 3 | 设计文档 | RAG架构图、chunk策略设计、多种检索策略设计、质量评估方案、制度关联策略 | **必须** |
| 4 | 测试用例 + 测试结果 | 至少5个测试问题,覆盖常见制度查询,附各检索策略对比结果 | **必须** |
| 5 | AGENTS.md | 技术运用过程记录、chunk大小调优过程、检索策略对比、检索准确率改善记录、质量评估设计 | **必须** |
| 6 | 样本数据 | 至少3份模拟制度文档(中/日文各至少1份),含多级章节结构,含可关联的交叉引用 | **必须** |
**测试用例与测试结果**:至少 5 个测试问题,覆盖常见制度查询,附各检索策略对比结果。
#### 评分标准(100分 + 难度赋分10分)
| 评审项 | 分值 | 评审方式 |
|--------|:---:|---------|
| 功能完整性 | 30分 | 必达项(25分):文档上传与解析5分 / 基础检索功能10分 / 无法回答处理5分 / 追问功能5分。加分项(5分,任选其一):检索策略切换5分 / 检索质量可视化5分 / Chunk管理5分 / 制度间关联提示5分 / 检索分析看板5分 |
| 设计文档 | 10分 | RAG架构清晰、检索策略设计合理、质量评估方案有依据 |
| 测试用例与测试结果 | 10分 | 至少5个测试问题,覆盖常见制度查询,结果可复现 |
| AI协作过程记录(AGENTS.md | 15分 | 过程记录完整、chunk大小调优、检索策略对比、准确率改善记录 |
| 技术选型与范式运用 | 15分 | Superpowers/Skill/MCP等选型理由充分,RAG管道设计合理 |
| 代码质量 + README | 10分 | 结构清晰、命名规范、README包含LLM/向量库配置说明 |
| 业务场景理解与需求分析 | 10分 | 对人事制度检索场景理解准确,需求分析到位 |
| 难度赋分 | 10分 | ★★★★难度追加 |
| **合计** | **110分** | |
> 本题为★★★★难度,满分110分,合格条件:≥60分。
**样本数据**:至少 3 份模拟制度文档(中/日文各至少 1 份),含多级章节结构,含可关联的交叉引用。
---
@@ -804,12 +734,10 @@ README 是评审者了解作品的第一个入口,**必须尽可能说清楚**
#### 考核技术(至少选1项)
| 技术 | 本题中的运用示例 | AGENTS.md中需记录的内容 |
|------|----------------|------------------------|
| **Superpowers** | 用Superpowers组合构建审查管道(文件解析 + 条款提取 + 风险分析 + 审批流程 + 报告生成) | Superpower的注册与组合逻辑 |
| **MCP自动化测试** | 对条款提取准确率、审查等级判断、审批流程逻辑进行自动化测试 | MCP Server配置 / 测试用例设计 / 准确率基准 |
| **Skill** | 将「合同解析」「条款提取」「风险规则库」「审批流程」「盖章管理」「提醒引擎」封装为独立Skill | 各Skill的接口定义 / 风险规则设计 / 审批流程状态管理 |
| **VibeCoding** | 用提示词直接实现合同上传→审查→审批→盖章→签约的全流程 | 使用的prompt原文 / 生成过程 / 审批状态管理设计 |
> 课程技术共同要求见 §3.2 前言(VibeCoding/SpecKit/Skill/Superpowers/MCP 五选一,鼓励组合加分)。本题推荐运用:
> - **Superpowers**:用Superpowers组合构建审查管道(文件解析 + 条款提取 + 风险分析 + 审批流程 + 报告生成)
> - **Skill**:将「合同解析」「条款提取」「风险规则库」「审批流程」「盖章管理」「提醒引擎」封装为独立Skill
> - **MCP自动化测试**对条款提取准确率、审查等级判断、审批流程逻辑进行自动化测试
#### 业务需求
@@ -865,32 +793,11 @@ README 是评审者了解作品的第一个入口,**必须尽可能说清楚**
| 签约与到期提醒 | 到期前30天正确标识 | 签约提醒+到期提醒+禀议提醒三种均正常触发 | 设置不同金额和到期日验证提醒逻辑 |
| 分析报告 | 统计报告内容完整 | 统计报告和签署注意点报告均正确生成 | 对比报告内容与合同数据的一致性 |
#### 提交物清单
#### 本题专属要求(其余按 §3.2 通用要求)
| # | 提交物 | 内容要求 | 必须/可选 |
|---|--------|---------|----------|
| 1 | 源代码 | 完整可运行的项目代码 | **必须** |
| 2 | README | 环境要求(含LLM配置)、安装步骤、运行方法、审批流程说明 | **必须** |
| 3 | 设计文档 | 架构图、审查等级判定逻辑、风险规则库设计、审批状态机设计 | **必须** |
| 4 | 测试用例 + 测试结果 | 至少5份合同测试用例,覆盖不同审查等级和审批流程 | **必须** |
| 5 | AGENTS.md | 技术运用过程记录、风险规则调优过程、审批状态管理设计 | **必须** |
| 6 | 样本数据 | 至少5份模拟合同PDF(含正常合同和有问题合同),含不同金额场景,且必须包含「距到期日 ≤30 天」与「已过期」样本各至少1份,用于当场验证待续签标识与过期状态 | **必须** |
**测试用例与测试结果**:至少 5 份合同测试用例,覆盖不同审查等级和审批流程。
#### 评分标准(100分 + 难度赋分5分)
| 评审项 | 分值 | 评审方式 |
|--------|:---:|---------|
| 功能完整性 | 30分 | 合同上传与信息提取5分 / 审查等级判断5分 / 条款提取与风险标记10分 / 审批流程5分 / 盖章审批5分(签约与到期提醒、分析报告的分数含在上述各项中,不单独计分) |
| 设计文档 | 10分 | 风险规则库设计合理、审批状态机设计清晰 |
| 测试用例与测试结果 | 10分 | 至少5份合同测试用例,覆盖不同审查等级和审批流程 |
| AI协作过程记录(AGENTS.md) | 15分 | 过程记录完整、风险规则调优过程可追溯 |
| 技术选型与范式运用 | 15分 | Superpowers/Skill/MCP等选型理由充分,审查管道设计合理 |
| 代码质量 + README | 10分 | 结构清晰、命名规范、README包含LLM配置说明 |
| 业务场景理解与需求分析 | 10分 | 对合同审查场景理解准确,需求分析到位 |
| 难度赋分 | 5分 | ★★★难度追加 |
| **合计** | **105分** | |
> 本题为★★★难度,满分105分,合格条件:≥60分。
**样本数据**:至少 5 份模拟合同 PDF(含正常与有问题合同、不同金额场景),必须含「距到期日 ≤30 天」与「已过期」样本各至少 1 份。
---
@@ -910,15 +817,10 @@ README 是评审者了解作品的第一个入口,**必须尽可能说清楚**
#### 考核技术(至少选1项)
| 技术 | 本题中的运用示例 | AGENTS.md中需记录的内容 |
|------|----------------|------------------------|
| **Skill** | 将「爬虫引擎」「内容解析」「关键词筛选」「报告生成」封装为独立Skill | 各Skill的接口定义 / 爬虫策略 / 解析规则 |
| **MCP自动化测试** | 对爬虫结果解析准确率和筛选逻辑进行自动化测试 | MCP Server配置 / 测试用例设计 / 解析准确率验证 |
| **VibeCoding** | 用提示词直接实现爬虫+解析+筛选+报告的完整流程 | 使用的prompt原文 / 生成过程 / 反爬应对策略 |
| **Superpowers** | 用Superpowers组合构建信息收集管道 | Superpower的注册与组合逻辑 |
| **SpecKit** | 先定义数据源、解析规则、筛选条件的规格 | 规格定义过程 / 解析规则设计 |
> **爬虫合规提示**:爬虫行为需遵守目标网站的 robots.txt 规定。AGENTS.md 中需说明爬虫策略(采集频率、并发数、User-Agent 设置)及反爬应对方案。
> 课程技术共同要求见 §3.2 前言(VibeCoding/SpecKit/Skill/Superpowers/MCP 五选一,鼓励组合加分)。本题推荐运用:
> - **Skill**:将「爬虫引擎」「内容解析」「关键词筛选」「报告生成」封装为独立Skill
> - **MCP自动化测试**:对爬虫结果解析准确率和筛选逻辑进行自动化测试
> - **SpecKit**:先定义数据源、解析规则、筛选条件的规格
#### 业务需求
@@ -975,32 +877,11 @@ README 是评审者了解作品的第一个入口,**必须尽可能说清楚**
| 风险判别与通知 | 高/中/低三级可区分,系统内突出显示 | 评估结果与人工评估一致率≥70%,通知自动发送 | 受验者自行标注20条模拟法规的影响度作为ground truth,对比系统评估结果,验证通知触发 |
| 错误处理 | 数据源不可达时记录日志 | 自动重试3次后跳过,不影响其他数据源 | 故意配置无效URL验证 |
#### 提交物清单
#### 本题专属要求(其余按 §3.2 通用要求)
| # | 提交物 | 内容要求 | 必须/可选 |
|---|--------|---------|----------|
| 1 | 源代码 | 完整可运行的项目代码 | **必须** |
| 2 | README | 环境要求、安装步骤、运行方法、爬取频率说明 | **必须** |
| 3 | 设计文档 | 架构图、爬虫策略设计、解析规则设计、反爬应对方案 | **必须** |
| 4 | 测试用例 + 测试结果 | 至少3个测试用例,覆盖不同网站结构和解析场景 | **必须** |
| 5 | AGENTS.md | 技术运用过程记录、解析规则调优过程、反爬应对经验 | **必须** |
| 6 | 样本数据 | 模拟目标网页(至少3个不同结构的页面HTML) | **必须** |
**测试用例与测试结果**:至少 3 个测试用例,覆盖不同网站结构和解析场景。
#### 评分标准(100分 + 难度赋分5分)
| 评审项 | 分值 | 评审方式 |
|--------|:---:|---------|
| 功能完整性 | 30分 | 数据源管理5分 / 信息自动收集10分 / 增量采集5分 / 结果展示5分 / 定期报告5分 |
| 设计文档 | 10分 | 爬虫策略合理、解析规则设计清晰 |
| 测试用例与测试结果 | 10分 | 至少3个测试用例,覆盖不同网站结构和解析场景 |
| AI协作过程记录(AGENTS.md) | 15分 | 过程记录完整、反爬应对经验可追溯 |
| 技术选型与范式运用 | 15分 | Skill/MCP等选型理由充分,爬虫引擎设计合理 |
| 代码质量 + README | 10分 | 结构清晰、命名规范、README包含爬虫策略说明 |
| 业务场景理解与需求分析 | 10分 | 对法规收集场景理解准确,需求分析到位 |
| 难度赋分 | 5分 | ★★★难度追加 |
| **合计** | **105分** | |
> 本题为★★★难度,满分105分,合格条件:≥60分。
**样本数据**:模拟目标网页(至少 3 个不同结构的页面 HTML)。
---
@@ -1021,15 +902,10 @@ README 是评审者了解作品的第一个入口,**必须尽可能说清楚**
#### 考核技术(至少选1项)
| 技术 | 本题中的运用示例 | AGENTS.md中需记录的内容 |
|------|----------------|------------------------|
| **Skill** | 将「爬虫引擎」「风险分类」「影响度评估」「报告生成」封装为独立Skill | 各Skill的接口定义 / 分类策略 / 评估模型 |
| **MCP自动化测试** | 对分类准确率和风险判定逻辑进行自动化测试 | MCP Server配置 / 测试用例设计 |
| **VibeCoding** | 用提示词直接实现收集→分类→分析→报告的完整流程 | 使用的prompt原文 / 生成过程 / 分类策略调优 |
| **Superpowers** | 用Superpowers组合构建风险情报收集管道 | Superpower的注册与组合逻辑 |
| **SpecKit** | 先定义风险分类体系、影响度评估标准、报告格式规格 | 规格定义过程 / 风险分类与spec的对应关系 |
> **爬虫合规提示**:爬虫行为需遵守目标网站的 robots.txt 规定。AGENTS.md 中需说明爬虫策略(采集频率、并发数、User-Agent 设置)及反爬应对方案。
> 课程技术共同要求见 §3.2 前言(VibeCoding/SpecKit/Skill/Superpowers/MCP 五选一,鼓励组合加分)。本题推荐运用:
> - **Skill**:将「爬虫引擎」「风险分类」「影响度评估」「报告生成」封装为独立Skill
> - **MCP自动化测试**:对分类准确率和风险判定逻辑进行自动化测试
> - **SpecKit**:先定义风险分类体系、影响度评估标准、报告格式规格
#### 业务需求
@@ -1091,56 +967,26 @@ README 是评审者了解作品的第一个入口,**必须尽可能说清楚**
| 定期报告 | 报告自动生成、格式规范 | 报告含本期采集的全部数据(不限高关注法规),支持日报和周报两种粒度,Markdown报告内容完整、历史报告可查 | 检查报告内容与仪表盘数据一致 |
| 全局关键词 | 高关注关键词能正确标记 | 包含/排除规则同时生效 | 配置关键词后验证过滤和标记结果 |
#### 提交物清单
#### 本题专属要求(其余按 §3.2 通用要求)
| # | 提交物 | 内容要求 | 必须/可选 |
|---|--------|---------|----------|
| 1 | 源代码 | 完整可运行的项目代码 | **必须** |
| 2 | README | 环境要求、安装步骤、运行方法 | **必须** |
| 3 | 设计文档 | 架构图、风险分类体系设计、影响度评估标准、爬虫策略 | **必须** |
| 4 | 测试用例 + 测试结果 | 至少3个测试用例,覆盖不同风险类型和影响度评估 | **必须** |
| 5 | AGENTS.md | 技术运用过程记录、分类策略调优、影响度评估调整 | **必须** |
| 6 | 样本数据 | 模拟信息源HTML/RSS(至少3个,覆盖不同风险领域),条目须包含不同发布日期以支撑趋势对比;若实现API类型信息源,附mock服务脚本 | **必须** |
**测试用例与测试结果**:至少 3 个测试用例,覆盖不同风险类型和影响度评估。
#### 评分标准(100分 + 难度赋分5分)
| 评审项 | 分值 | 评审方式 |
|--------|:---:|---------|
| 功能完整性 | 30分 | 信息源管理5分 / 自动信息收集5分 / 增量采集5分 / 智能分类10分 / 风险仪表盘5分 |
| 设计文档 | 10分 | 风险分类体系和评估标准设计合理 |
| 测试用例与测试结果 | 10分 | 至少3个测试用例,覆盖不同风险类型和影响度评估 |
| AI协作过程记录(AGENTS.md) | 15分 | 过程记录完整、分类策略调优过程可追溯 |
| 技术选型与范式运用 | 15分 | Skill/MCP等选型理由充分,情报收集管道设计合理 |
| 代码质量 + README | 10分 | 结构清晰、命名规范、README完整 |
| 业务场景理解与需求分析 | 10分 | 对风险情报收集场景理解准确,需求分析到位 |
| 难度赋分 | 5分 | ★★★难度追加 |
| **合计** | **105分** | |
> 本题为★★★难度,满分105分,合格条件:≥60分。
**样本数据**:模拟信息源 HTML/RSS(至少 3 个,覆盖不同风险领域),条目须包含不同发布日期以支撑趋势对比;若实现 API 类型信息源,附 mock 服务脚本。
---
## 3.4 命题题 · 第二组:开发阶段AI评审工具题(07~11)
---
> 本组 5 道题统一实现「瀑布式各阶段的AI评审工具」。先读下方【组定位与背景】【组内共通硬性要求】(四条硬性要求对本组每道题都强制生效),再进入所选题目章节。
> 各题【本题专属要求】为该题补充项;通用 7 项成果物(README / DESIGN / src / tests / `_AI_USAGE_LOG.md` / `AGENTS.md` / data 样本数据)以 §3.2 为准,每题均须提交。各类**评分型指标**(置信度、影响度、准确率、「高频」阈值等)的具体计算口径由受验者自行定义,但必须在设计文档中写明;验收时以「口径清晰 + 结果可复现」为准,不要求与任何标准答案一致。涉及「与公司业务相关性」评估的题目,受验者须在 README 中给出虚构的公司画像(行业、规模、主要业务范围)作为统一评估基准。
## 16. 命题题详细需求 · 第二组:开发阶段AI评审工具题(07~11)
> 本组5道题统一实现「瀑布式各阶段的AI评审工具」。先读下方【组定位与背景】【组内共通硬性要求】(四条硬性要求对本组每道题都强制生效),再进入所选题目章节。
> 各题【提交物清单】为该题专属补充项;通用7项成果物(README / DESIGN / src / tests / `_AI_USAGE_LOG.md` / `AGENTS.md` / data样本数据)以 §5 为准,每题均须提交。> 各类**评分型指标**(置信度、影响度、准确率、「高频」阈值等)的具体计算口径由受验者自行定义,但必须在设计文档中写明;验收时以「口径清晰 + 结果可复现」为准,不要求与任何标准答案一致。涉及「与公司业务相关性」评估的题目,受验者须在 README 中给出虚构的公司画像(行业、规模、主要业务范围)作为统一评估基准。
> 本组5道题统一实现「瀑布式各阶段的AI评审工具」。先读下方【组定位与背景】【组内共通硬性要求】(四条硬性要求对本组每道题都强制生效),再进入所选题目章节。
> 各题【提交物清单】为该题专属补充项;通用7项成果物(README / DESIGN / src / tests / `_AI_USAGE_LOG.md` / `AGENTS.md` / data样本数据)以 §5 为准,每题均须提交。> 各类**评分型指标**(置信度、影响度、准确率、「高频」阈值等)的具体计算口径由受验者自行定义,但必须在设计文档中写明;验收时以「口径清晰 + 结果可复现」为准,不要求与任何标准答案一致。涉及「与公司业务相关性」评估的题目,受验者须在 README 中给出虚构的公司画像(行业、规模、主要业务范围)作为统一评估基准。
### 组定位与背景
### 3.4.1 组定位与背景
公司推行AI辅助开发后,文档与代码的生成速度大幅提升,但人工review成为新的瓶颈——全量人审则速度优势归零,放弃审查则质量风险失控。
本组题目围绕瀑布式开发的各个阶段,受验者**根据自身项目的实际痛点选择一个阶段**,实现该阶段的AI评审工具/Skill。目标是让工具承担全量预检并给出证据定位,人只复核被标记的例外,在不牺牲质量的前提下保持开发速度。
### 组内共通硬性要求(07~11每道题都必须满足)
### 3.4.2 组内共通硬性要求(07~11每道题都必须满足)
| # | 要求 | 说明 |
|---|------|------|
@@ -1173,13 +1019,10 @@ README 是评审者了解作品的第一个入口,**必须尽可能说清楚**
#### 考核技术(至少选1项)
| 技术 | 本题中的运用示例 | AGENTS.md中需记录的内容 |
|------|----------------|------------------------|
| **Skill** | 将「歧义检测」「一致性检查」「可测试性评估」「报告生成」封装为独立Skill | 各Skill接口定义 / 规则配置方式 / 检出率调优过程 |
| **SpecKit** | 先定义规则配置规范和报告格式spec再实现 | 规格定义过程 / 规则与spec的对应关系 |
| **MCP自动化测试** | 用缺陷标注清单对检出率做自动化回归验证 | MCP Server配置 / 检出率基准与回归结果 |
| **VibeCoding** | 提示词直接实现解析→检查→报告全流程 | prompt原文 / 生成过程 / 误报调优记录 |
| **Superpowers** | 组合构建评审管道(解析→各检查器→汇总报告) | Superpower注册与组合逻辑 / 各检查器职责边界 |
> 课程技术共同要求见 §3.2 前言(VibeCoding/SpecKit/Skill/Superpowers/MCP 五选一,鼓励组合加分)。本题推荐运用:
> - **Skill**:将「歧义检测」「一致性检查」「可测试性评估」「报告生成」封装为独立Skill
> - **MCP自动化测试**:用缺陷标注清单对检出率做自动化回归验证
> - **SpecKit**先定义规则配置规范和报告格式spec再实现
#### 业务需求
@@ -1222,32 +1065,11 @@ README 是评审者了解作品的第一个入口,**必须尽可能说清楚**
| 报告规范 | 分级+章节定位完整 | 定位含条目原文摘录 | 抽查报告中定位是否准确 |
| 规则外置生效 | 规则在独立配置文件中维护 | 新增1条规则不改代码生效,有自动化脚本+运行日志佐证 | 运行提交的验证脚本核验 |
#### 提交物清单
#### 本题专属要求(其余按 §3.2 通用要求)
| # | 提交物 | 内容要求 | 必须/可选 |
|---|--------|---------|----------|
| 1 | 源代码 | 完整可运行的项目代码 | **必须** |
| 2 | README | 环境要求(含LLM配置)、安装步骤、运行方法、规则配置说明 | **必须** |
| 3 | 设计文档 | 架构图、各检查器设计、规则与标准配置文件结构说明、误报控制策略 | **必须** |
| 4 | 测试用例 + 测试结果 | 至少3个测试用例(含基于标注清单的检出率回归对比) | **必须** |
| 5 | AGENTS.md | 技术运用过程记录、歧义词词典调优过程、LLM判断改善记录 | **必须** |
| 6 | 样本数据 | 2份模拟需求说明书(1份正常,含约10条编号需求;1份植入至少20处已知问题:歧义词≥10处、矛盾≥2组、不可测试需求≥3处、量化缺失≥2处、编写规范违规≥3处)+ 缺陷标注清单(问题位置/类型/级别)+ 《需求文档编写标准》配置A/B两套 | **必须** |
**测试用例与测试结果**:至少 3 个测试用例(含基于标注清单的检出率回归对比)。
#### 评分标准(100分 + 难度赋分5分)
| 评审项 | 分值 | 评审方式 |
|--------|:---:|---------|
| 功能完整性 | 30分 | 文档导入与解析4分 / 歧义检测8分 / 一致性检查5分 / 编写规范检查5分 / 可测试性评估4分 / 评审报告与规则外置4分 |
| 设计文档 | 10分 | 架构合理,规则引擎与LLM分工策略清晰,企业标准配置化设计有依据 |
| 测试用例与测试结果 | 10分 | 检出率回归对比可复现,含标准A/B切换验证 |
| AI协作过程记录(AGENTS.md) | 15分 | 过程记录完整、误报调优过程可追溯 |
| 技术选型与范式运用 | 15分 | 选型理由充分,Skill/MCP等运用合理 |
| 代码质量 + README | 10分 | 结构清晰、命名规范、README含规则配置说明 |
| 业务场景理解与需求分析 | 10分 | 对需求评审痛点理解准确 |
| 难度赋分 | 5分 | ★★★难度追加 |
| **合计** | **105分** | |
> 本题为★★★难度,满分105分,合格条件:≥60分。
**样本数据**:2 份模拟需求说明书(1 份正常含约 10 条编号需求;1 份植入至少 20 处已知问题:歧义词≥10 处、矛盾≥2 组、不可测试需求≥3 处、量化缺失≥2 处、编写规范违规≥3 处)+ 缺陷标注清单 + 《需求文档编写标准》配置 A/B 两套。
---
@@ -1270,15 +1092,10 @@ README 是评审者了解作品的第一个入口,**必须尽可能说清楚**
#### 考核技术(至少选1项)
| 技术 | 本题中的运用示例 | AGENTS.md中需记录的内容 |
|------|----------------|------------------------|
| **SpecKit** | 先定义必备章节规范、追溯矩阵规格、报告格式spec再实现 | 规格定义过程 / 追溯映射规则与spec对应关系 |
| **Skill** | 将「规范检查」「追溯矩阵构建」「接口一致性检查」封装为独立Skill | 各Skill接口定义 / 语义匹配策略 |
| **MCP自动化测试** | 用缺陷标注清单对矩阵映射正确率做自动化验证 | MCP Server配置 / 映射正确率基准 |
| **VibeCoding** | 提示词直接实现解析→检查→矩阵→报告流程 | prompt原文 / 语义匹配prompt迭代记录 |
| **Superpowers** | 组合构建预审管道 | Superpower注册与组合逻辑 |
> **难度说明**:本题为★★★★难度,满分110分(含难度赋分10分),合格线60分。设计书解析、规范符合性检查、评审报告为基础必达项;需求追溯矩阵与接口一致性检查为本题核心考察点,其中需求追溯矩阵(10分)权重最高,建议优先实现。
> 课程技术共同要求见 §3.2 前言(VibeCoding/SpecKit/Skill/Superpowers/MCP 五选一,鼓励组合加分)。本题推荐运用:
> - **SpecKit**:先定义必备章节规范、追溯矩阵规格、报告格式spec再实现
> - **Skill**:将「规范检查」「追溯矩阵构建」「接口一致性检查」封装为独立Skill
> - **MCP自动化测试**:用缺陷标注清单对矩阵映射正确率做自动化验证
#### 业务需求
@@ -1319,32 +1136,11 @@ README 是评审者了解作品的第一个入口,**必须尽可能说清楚**
| 矩阵可视化 | 表格形式展示完整映射关系 | 支持点击跳转到对应位置 | 运行提交的脚本/截图验证 |
| 规则外置生效 | 必备章节清单在配置文件中维护 | 调整清单后重新评审生效,有自动化脚本+运行日志佐证 | 运行提交的验证脚本核验 |
#### 提交物清单
#### 本题专属要求(其余按 §3.2 通用要求)
| # | 提交物 | 内容要求 | 必须/可选 |
|---|--------|---------|----------|
| 1 | 源代码 | 完整可运行的项目代码 | **必须** |
| 2 | README | 环境要求(含LLM配置)、安装步骤、运行方法、规范清单配置说明 | **必须** |
| 3 | 设计文档 | 架构图、追溯映射算法设计、语义匹配策略、误报控制方案 | **必须** |
| 4 | 测试用例 + 测试结果 | 至少3个测试用例(含映射正确率回归对比) | **必须** |
| 5 | AGENTS.md | 技术运用过程记录、语义匹配prompt迭代过程、映射正确率改善记录 | **必须** |
| 6 | 样本数据 | 需求清单1份(10条编号需求)+ 模拟设计书1份(含正常内容,植入2处必备章节缺失、2条需求未覆盖、1处孤儿设计、2处接口矛盾、图表/编号格式违规≥2处)+ 缺陷标注清单 + 《设计书格式标准》配置A/B两套 | **必须** |
**测试用例与测试结果**:至少 3 个测试用例(含映射正确率回归对比)。
#### 评分标准(100分 + 难度赋分10分)
| 评审项 | 分值 | 评审方式 |
|--------|:---:|---------|
| 功能完整性 | 30分 | 导入与解析5分 / 规范符合性检查5分 / 需求追溯矩阵10分 / 接口一致性检查5分 / 矩阵可视化与报告5分 |
| 设计文档 | 10分 | 架构合理,追溯映射算法设计有依据 |
| 测试用例与测试结果 | 10分 | 映射正确率回归对比可复现 |
| AI协作过程记录(AGENTS.md) | 15分 | 过程记录完整、语义匹配prompt迭代可追溯 |
| 技术选型与范式运用 | 15分 | 选型理由充分,SpecKit/Skill等运用合理 |
| 代码质量 + README | 10分 | 结构清晰、命名规范、README完整 |
| 业务场景理解与需求分析 | 10分 | 对设计书评审痛点理解准确 |
| 难度赋分 | 10分 | ★★★★难度追加 |
| **合计** | **110分** | |
> 本题为★★★★难度,满分110分,合格条件:≥60分。
**样本数据**:需求清单 1 份(10 条编号需求)+ 模拟设计书 1 份(植入章节缺失×2、未覆盖×2、孤儿设计×1、接口矛盾×2、格式违规≥2 处)+ 缺陷标注清单 + 格式标准 A/B 两套。
---
@@ -1367,13 +1163,10 @@ AI生成代码大量合入代码库后,出现特有的高频缺陷模式:
#### 考核技术(至少选1项)
| 技术 | 本题中的运用示例 | AGENTS.md中需记录的内容 |
|------|----------------|------------------------|
| **Skill** | 将「secrets检测」「LLM调用检查」「空值防护检查」「报告生成」封装为独立Skill | 各Skill接口定义 / 正则规则库设计 / 误报白名单机制 |
| **SpecKit** | 先定义规则格式规范、分级标准、报告格式spec | 规格定义过程 / 规则分级与spec对应关系 |
| **MCP自动化测试** | 用缺陷标注清单对检出率和误报率做自动化验证 | MCP Server配置 / 检出率与误报率基准 |
| **VibeCoding** | 提示词直接实现扫描引擎和规则匹配 | prompt原文 / 规则调优过程 |
| **Superpowers** | 组合构建扫描管道(遍历→各检查器→汇总) | Superpower注册与组合逻辑 |
> 课程技术共同要求见 §3.2 前言(VibeCoding/SpecKit/Skill/Superpowers/MCP 五选一,鼓励组合加分)。本题推荐运用:
> - **Skill**:将「secrets检测」「LLM调用检查」「空值防护检查」「报告生成」封装为独立Skill
> - **SpecKit**:先定义规则格式规范、分级标准、报告格式spec
> - **MCP自动化测试**:用缺陷标注清单对检出率和误报率做自动化验证
#### 业务需求
@@ -1413,32 +1206,11 @@ AI生成代码大量合入代码库后,出现特有的高频缺陷模式:
| 扫描范围控制 | 配置的排除目录不被扫描 | 白名单机制生效 | 故意配置后运行验证 |
| 报告规范与规则外置 | 分级+file:line定位完整 | 修复建议含示例代码;新增规则不改代码生效,有脚本佐证 | 抽查报告+运行验证脚本 |
#### 提交物清单
#### 本题专属要求(其余按 §3.2 通用要求)
| # | 提交物 | 内容要求 | 必须/可选 |
|---|--------|---------|----------|
| 1 | 源代码 | 完整可运行的项目代码 | **必须** |
| 2 | README | 环境要求、安装步骤、运行方法、规则库与白名单配置说明 | **必须** |
| 3 | 设计文档 | 架构图、规则匹配引擎设计、分级标准定义、误报控制策略 | **必须** |
| 4 | 测试用例 + 测试结果 | 至少3个测试用例(含检出率/误报率回归对比) | **必须** |
| 5 | AGENTS.md | 技术运用过程记录、正则规则调优过程、误报处理经验 | **必须** |
| 6 | 样本数据 | 1个小型模拟项目代码包(至少10个源码文件,植入硬编码密钥×8、LLM调用无保护×3、空值裸访问×4、编码规约违规×4)+ 缺陷标注清单 + 《编码规约》配置A/B两套 | **必须** |
**测试用例与测试结果**:至少 3 个测试用例(含检出率/误报率回归对比)。
#### 评分标准(100分 + 难度赋分5分)
| 评审项 | 分值 | 评审方式 |
|--------|:---:|---------|
| 功能完整性 | 30分 | 扫描配置与执行3分 / secrets检测6分 / LLM调用专项检查7分 / 空值防护检查5分 / 编码规约检查4分 / 报告与门禁5分 |
| 设计文档 | 10分 | 规则引擎设计合理、分级标准定义清晰、企业规约配置化设计有依据 |
| 测试用例与测试结果 | 10分 | 检出率/误报率回归对比可复现,含规约A/B切换验证 |
| AI协作过程记录(AGENTS.md) | 15分 | 过程记录完整、规则调优过程可追溯 |
| 技术选型与范式运用 | 15分 | 选型理由充分,Skill/MCP等运用合理 |
| 代码质量 + README | 10分 | 结构清晰、命名规范、README含规则配置说明 |
| 业务场景理解与需求分析 | 10分 | 对AI生成代码特有缺陷模式理解准确 |
| 难度赋分 | 5分 | ★★★难度追加 |
| **合计** | **105分** | |
> 本题为★★★难度,满分105分,合格条件:≥60分。
**样本数据**:小型模拟项目代码包(≥10 个源码文件,植入硬编码密钥×8、LLM 无保护×3、空值裸访问×4、规约违规×4)+ 缺陷标注清单 + 规约 A/B 两套。
---
@@ -1461,15 +1233,10 @@ AI辅助生成测试用例后,测试数量激增但质量参差:
#### 考核技术(至少选1项)
| 技术 | 本题中的运用示例 | AGENTS.md中需记录的内容 |
|------|----------------|------------------------|
| **Skill** | 将「测试集解析」「覆盖分析」「断言强度审查」「评级报告」封装为独立Skill | 各Skill接口定义 / 断言强度判定标准设计 |
| **SpecKit** | 先定义评级标准和覆盖矩阵规格再实现 | 规格定义过程 / 评级标准与spec对应关系 |
| **MCP自动化测试** | 用缺陷标注清单对弱断言检出率做自动化验证 | MCP Server配置 / 检出率基准与回归结果 |
| **VibeCoding** | 提示词直接实现解析→分析→评级全流程 | prompt原文 / 断言判断prompt迭代记录 |
| **Superpowers** | 组合构建测试评审管道 | Superpower注册与组合逻辑 |
> **难度说明**:本题为★★★★难度,满分110分(含难度赋分10分),合格线60分。测试集解析、评级报告为基础必达项;需求覆盖分析(7分)与断言强度审查(9分)为本题核心考察点,其中断言强度审查依赖LLM对业务语义的理解,权重最高;测试基准符合性检查(4分)体现企业标准定制化能力。
> 课程技术共同要求见 §3.2 前言(VibeCoding/SpecKit/Skill/Superpowers/MCP 五选一,鼓励组合加分)。本题推荐运用:
> - **Skill**:将「测试集解析」「覆盖分析」「断言强度审查」「评级报告」封装为独立Skill
> - **MCP自动化测试**:用缺陷标注清单对弱断言检出率做自动化验证
> - **SpecKit**先定义评级标准和覆盖矩阵规格再实现
#### 业务需求
@@ -1510,32 +1277,11 @@ AI辅助生成测试用例后,测试数量激增但质量参差:
| 用例评级 | 每个测试用例有A/B/C评级 | C级用例附针对性改进建议 | 抽查评级合理性 |
| 报告规范与规则外置 | 评级结果+覆盖矩阵完整展示 | 评级标准在配置文件中可调整,有脚本佐证 | 运行验证脚本核验 |
#### 提交物清单
#### 本题专属要求(其余按 §3.2 通用要求)
| # | 提交物 | 内容要求 | 必须/可选 |
|---|--------|---------|----------|
| 1 | 源代码 | 完整可运行的项目代码 | **必须** |
| 2 | README | 环境要求(含LLM配置)、安装步骤、运行方法、评级标准配置说明 | **必须** |
| 3 | 设计文档 | 架构图、断言强度判定标准设计、覆盖映射算法、评级体系说明 | **必须** |
| 4 | 测试用例 + 测试结果 | 至少3个测试用例(含弱断言检出率回归对比) | **必须** |
| 5 | AGENTS.md | 技术运用过程记录、断言判断prompt迭代过程、检出率改善记录 | **必须** |
| 6 | 样本数据 | 需求清单1份(10条编号需求)+ 测试代码集1份(至少20个测试用例,植入无断言测试×3、弱断言×8、用例要素缺失或命名违规×3)+ 缺陷标注清单 + 《测试基准》配置A/B两套 | **必须** |
**测试用例与测试结果**:至少 3 个测试用例(含弱断言检出率回归对比)。
#### 评分标准(100分 + 难度赋分10分)
| 评审项 | 分值 | 评审方式 |
|--------|:---:|---------|
| 功能完整性 | 30分 | 测试集导入与解析3分 / 需求覆盖分析7分 / 断言强度审查9分 / 边界完整性提示2分 / 基准符合性检查4分 / 质量评级报告5分 |
| 设计文档 | 10分 | 架构合理,断言强度判定标准设计有依据,测试基准配置化设计合理 |
| 测试用例与测试结果 | 10分 | 检出率回归对比可复现 |
| AI协作过程记录(AGENTS.md) | 15分 | 过程记录完整、断言判断prompt迭代可追溯 |
| 技术选型与范式运用 | 15分 | 选型理由充分,Skill/MCP等运用合理 |
| 代码质量 + README | 10分 | 结构清晰、命名规范、README完整 |
| 业务场景理解与需求分析 | 10分 | 对AI生成测试的质量风险理解准确 |
| 难度赋分 | 10分 | ★★★★难度追加 |
| **合计** | **110分** | |
> 本题为★★★★难度,满分110分,合格条件:≥60分。
**样本数据**:需求清单 1 份(10 条编号需求)+ 测试代码集(≥20 个用例,植入无断言×3、弱断言×8、要素缺失或命名违规×3)+ 缺陷标注清单 + 基准 A/B 两套。
---
@@ -1554,12 +1300,10 @@ AI辅助生成测试用例后,测试数量激增但质量参差:
#### 考核技术(至少选1项)
| 技术 | 本题中的运用示例 | AGENTS.md中需记录的内容 |
|------|----------------|------------------------|
| **VibeCoding** | 提示词直接实现清单核对要素检查→报告生成全流程 | prompt原文 / 生成过程 / 人工修正点 |
| **Skill** | 将「清单核对」「要素检查」「交叉一致性」封装为独立Skill | 各Skill接口定义 / 清单模板设计 |
| **SpecKit** | 先定义清单模板格式和报告格式spec | 规格定义过程 / 清单与spec对应关系 |
| **MCP自动化测试** | 对核对逻辑做自动化测试 | MCP Server配置 / 核对准确性验证 |
> 课程技术共同要求见 §3.2 前言(VibeCoding/SpecKit/Skill/Superpowers/MCP 五选一,鼓励组合加分)。本题推荐运用:
> - **VibeCoding**:提示词直接实现清单核对→要素检查→报告生成全流程
> - **Skill**:将「清单核对」「要素检查」「交叉一致性」封装为独立Skill
> - **SpecKit**:先定义清单模板格式和报告格式spec
#### 业务需求
@@ -1593,31 +1337,11 @@ AI辅助生成测试用例后,测试数量激增但质量参差:
| 清单可切换 | 加载另一套清单模板能正常工作 | 模板格式有文档说明 | 切换模板演示 |
| 报告与结论 | 核对表+缺失明细完整 | 结论判定逻辑正确(Critical缺失→不通过) | 构造场景验证 |
#### 提交物清单
#### 本题专属要求(其余按 §3.2 通用要求)
| # | 提交物 | 内容要求 | 必须/可选 |
|---|--------|---------|----------|
| 1 | 源代码 | 完整可运行的项目代码 | **必须** |
| 2 | README | 环境要求、安装步骤、运行方法、清单模板格式说明 | **必须** |
| 3 | 设计文档 | 架构图、清单模板设计、要素匹配与一致性检查逻辑 | **必须** |
| 4 | 测试用例 + 测试结果 | 至少3个测试用例,覆盖核对正常路径和异常路径 | **必须** |
| 5 | AGENTS.md | 技术运用过程记录、清单模板设计决策、遇到的问题与解决方案 | **必须** |
| 6 | 样本数据 | 1个残缺的模拟项目提交包(故意缺失部分文件、README缺要素、技术栈声明与依赖不一致)+ 缺陷标注清单 + 另一套备用清单模板 | **必须** |
#### 评分标准(100分)
| 评审项 | 分值 | 评审方式 |
|--------|:---:|---------|
| 功能完整性 | 30分 | 成果物清单配置5分 / 存在性核对8分 / 要素齐全性检查8分 / 交叉一致性检查5分 / 准入报告与结论4分 |
| 设计文档 | 10分 | 架构合理、清单模板设计规范 |
| 测试用例与测试结果 | 10分 | 覆盖核对正常和异常路径、可复现 |
| AI协作过程记录(AGENTS.md) | 15分 | 过程记录完整、设计决策可追溯 |
| 技术选型与范式运用 | 15分 | 选型理由充分,VibeCoding/Skill运用合理 |
| 代码质量 + README | 10分 | 结构清晰、命名规范、README完整 |
| 业务场景理解与需求分析 | 10分 | 对交付核对痛点理解准确 |
| **合计** | **100分** | |
> 本题为★★难度,满分100分,合格条件:≥60分。组内共通硬性要求(证据型报告 / 规则外置 / 分级判定 / 企业标准外置)同样适用于本题,未满足将在对应维度扣分。
**测试用例与测试结果**:至少 3 个测试用例,覆盖核对正常路径和异常路径。
**样本数据**:1 个残缺的模拟项目提交包(故意缺失部分文件、README 缺要素、技术栈声明与依赖不一致)+ 缺陷标注清单 + 另一套备用清单模板。
> **注意**:本题同样须遵守 §3.4.2 组内共通硬性要求(证据型报告 / 规则外置 / 分级判定 / 企业标准外置)。
+172
View File
@@ -0,0 +1,172 @@
/**
* 参赛/受验者仓库提交状态探测工具
* 用法:node server/scripts/check-repos.mjs [赛道一|赛道二|L2考核|all]
*
* 通过 Gitea API 快速判定四种状态(无需克隆):
* SUBMITTED 仓库存在且非空(已提交)
* EMPTY 仓库存在但为空(建仓未推送)
* NOT_CREATED 仓库不存在(或全局评审账号无权限且无备用凭据可区分)
* NO_ACCESS 仓库存在(队伍自身凭据可见)但评审账号未被授权协作者
* AUTH_FAIL 队伍自身凭据失效
*/
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const ROOT = path.resolve(__dirname, '..', '..');
// ---------- 加载 .env ----------
function loadEnv() {
const p = path.join(ROOT, 'server', '.env');
const out = {};
for (const line of fs.readFileSync(p, 'utf8').split(/\r?\n/)) {
const m = line.match(/^([A-Z_]+)=(.*)$/);
if (m && !line.trim().startsWith('#')) out[m[1]] = m[2].trim();
}
return out;
}
const env = loadEnv();
const G_USER = env.GITEA_USERNAME || '';
const G_TOKEN = env.GITEA_TOKEN || '';
if (!G_USER || !G_TOKEN) {
console.error('缺少 GITEA_USERNAME / GITEA_TOKENserver/.env');
process.exit(1);
}
const filterArg = process.argv[2] || 'all';
// ---------- 组装探测目标 ----------
const targets = [];
if (filterArg === 'all' || filterArg === '赛道一' || filterArg === '赛道二') {
const teams = JSON.parse(fs.readFileSync(path.join(ROOT, 'config', 'teams.json'), 'utf8')).teams || [];
for (const t of teams) {
if (filterArg !== 'all' && t.track !== filterArg) continue;
targets.push({
kind: t.track,
label: `${t.team || t.dept || ''}${t.leader ? '/' + t.leader : ''}`,
user: t.gittea.user,
repo: t.gittea.repo,
// 备用凭据:队伍自己的 token/密码(用于区分"未创建"与"未授权"
altAuth: t.gittea.token
? { type: 'token', value: t.gittea.token }
: (t.gittea.password ? { type: 'basic', value: t.gittea.password } : null),
});
}
}
if (filterArg === 'all' || filterArg === 'L2考核') {
try {
const l2 = JSON.parse(fs.readFileSync(path.join(ROOT, 'config', 'l2-participants.json'), 'utf8'));
for (const p of l2.participants || []) {
targets.push({
kind: 'L2考核',
label: `${p.no}${p.name ? '/' + p.name : ''}`,
user: p.gitteaUser,
repo: p.repo || 'L2-assessment',
altAuth: null, // 自注册模式无个人 token404 无法与"未授权"区分
});
}
} catch { /* 注册表不存在则跳过 */ }
}
if (targets.length === 0) {
console.error('没有匹配的探测目标。用法: node server/scripts/check-repos.mjs [赛道一|赛道二|L2考核|all]');
process.exit(1);
}
// ---------- 探测 ----------
async function probeRepo(base, user, repo, auth) {
const url = `${base.replace(/\/+$/, '')}/api/v1/repos/${encodeURIComponent(user)}/${encodeURIComponent(repo)}`;
const headers = {};
if (auth?.type === 'token') headers.Authorization = `token ${auth.value}`;
else if (auth?.type === 'basic') headers.Authorization = 'Basic ' + Buffer.from(`${G_USER}:${auth.value}`).toString('base64');
else headers.Authorization = 'Basic ' + Buffer.from(`${G_USER}:${G_TOKEN}`).toString('base64');
for (let attempt = 1; attempt <= 2; attempt++) {
try {
const ctrl = new AbortController();
const timer = setTimeout(() => ctrl.abort(), 12000);
const res = await fetch(url, { headers, signal: ctrl.signal });
clearTimeout(timer);
if (res.status === 200) {
const j = await res.json();
return { code: 'ok', empty: !!j.empty, defaultBranch: j.default_branch || '', updatedAt: j.updated_at || '' };
}
if (res.status === 404) return { code: 'miss' };
if (res.status === 401 || res.status === 403) return { code: 'denied' };
return { code: 'http', detail: res.status };
} catch (e) {
if (attempt === 2) return { code: 'net', detail: (e.message || '').slice(0, 60) };
await new Promise(r => setTimeout(r, 800));
}
}
}
async function classify(t, base) {
const g = await probeRepo(base, t.user, t.repo, null);
if (g.code === 'ok') {
if (g.empty) return { state: 'EMPTY', icon: '🟡', text: '空仓库(已建仓,未推送任何内容)' };
const branchWarn = g.defaultBranch && g.defaultBranch !== 'main' ? `,注意默认分支=${g.defaultBranch}` : '';
return { state: 'SUBMITTED', icon: '✅', text: `已提交(${g.defaultBranch}${branchWarn},更新 ${String(g.updatedAt).slice(0, 10)}` };
}
if (g.code === 'denied') return { state: 'NO_ACCESS', icon: '⚠️ ', text: '评审账号无权限(403' };
if (g.code === 'miss') {
if (t.altAuth) {
const a = await probeRepo(base, t.user, t.repo, t.altAuth);
if (a.code === 'ok') {
const extra = a.empty ? '(且为空仓库)' : '';
return { state: 'NO_ACCESS', icon: '⚠️ ', text: `仓库存在${extra},但评审账号未被授权协作者` };
}
if (a.code === 'miss') return { state: 'NOT_CREATED', icon: '🔴', text: '仓库未创建(两队凭据均确认 404)' };
if (a.code === 'denied') return { state: 'AUTH_FAIL', icon: '🔴', text: '队伍自身凭据失效(token/密码不可用)' };
return { state: 'ERR', icon: '❓', text: '队伍凭据探测异常' };
}
return { state: 'NOT_CREATED', icon: '🔴', text: '未创建 或 未授权(无备用凭据,无法区分)' };
}
return { state: 'ERR', icon: '❓', text: `探测失败 ${g.detail || ''}` };
}
// 小并发池
async function pool(items, worker, size = 6) {
const results = new Array(items.length);
let i = 0;
async function run() {
while (i < items.length) {
const idx = i++;
results[idx] = await worker(items[idx]);
}
}
await Promise.all(Array.from({ length: Math.min(size, items.length) }, run));
return results;
}
// ---------- 主流程 ----------
const l2cfg = (() => { try { return JSON.parse(fs.readFileSync(path.join(ROOT, 'config', 'l2-participants.json'), 'utf8')); } catch { return {}; } })();
const BASE = l2cfg.gitteaUrl || 'https://gittea.dev';
console.log(`探测目标 ${targets.length} 个(base=${BASE}, 评审账号=${G_USER}`);
console.log('='.repeat(100));
const results = await pool(targets, async (t) => ({ t, r: await classify(t, BASE) }));
const ORDER = ['SUBMITTED', 'EMPTY', 'NO_ACCESS', 'NOT_CREATED', 'AUTH_FAIL', 'ERR'];
const STATE_TEXT = {
SUBMITTED: '已提交', EMPTY: '空仓库', NO_ACCESS: '未授权',
NOT_CREATED: '未创建', AUTH_FAIL: '凭据失效', ERR: '探测异常',
};
const counts = {};
for (const { t, r } of results) {
counts[r.state] = (counts[r.state] || 0) + 1;
console.log(`[${t.kind}] ${t.label.padEnd(24)} ${r.icon} ${STATE_TEXT[r.state].padEnd(6)} ${r.text}`);
}
console.log('='.repeat(100));
console.log('汇总:');
for (const s of ORDER) {
if (counts[s]) console.log(` ${STATE_TEXT[s]}: ${counts[s]}`);
}
const notDone = (counts.EMPTY || 0) + (counts.NO_ACCESS || 0) + (counts.NOT_CREATED || 0) + (counts.AUTH_FAIL || 0);
console.log(`\n结论:已提交 ${counts.SUBMITTED || 0} / 总数 ${results.length};未完成 ${notDone} 个(见上方明细)。`);
+6 -3
View File
@@ -11,7 +11,7 @@ import { parseDimensions } from './standards';
import { computePassLine, computeLatePenalty, aggregateEntryScores, computeL2Result } from '../services/standard-utils';
import { isPrivateAddress } from '../ip-security';
import { REVIEW_CONSTANTS } from '../services/review-constants';
import { startReview, startReviewB, resolveWebMode, averageDimensions } from '../services/review.service';
import { startReview, startReviewB, startReviewRounds, resolveWebMode, averageDimensions } from '../services/review.service';
import { generateEntryPdf } from '../services/pdf.service';
import { resolveRepoUrlFromConfig } from '../services/teams-config';
import { findL2Topic } from '../services/l2-topics';
@@ -399,8 +399,11 @@ router.post('/:entryId/start', (req: Request, res: Response) => {
// §2.4 重评:清空旧结果,attempt+1(保留 review_snapshots 历史)
db.prepare("UPDATE entries SET status = 'pending', ai_report = NULL, raw_score = NULL, final_score = NULL, score_a = 0, score_b = 0, stage_b_status = '', project_understanding = '', final_level = NULL, attempt = attempt + 1, updated_at = datetime('now') WHERE id = ?").run(eid(req));
startReview(eid(req));
res.json({ success: true });
// 一键多轮:rounds>1 时连续完成 N 轮后自动聚合(中位数)为正式分
const rounds = Math.max(1, Math.min(5, parseInt(req.body?.rounds, 10) || 1));
if (rounds > 1) startReviewRounds(eid(req), rounds);
else startReview(eid(req));
res.json({ success: true, rounds });
});
// §2.5 阶段 B 触发端点:a_done → 接收 build_statusdone/failed)→ hasWeb 校验 service_url → startReviewB(复用 queue,受 MAX_CONCURRENT
+56
View File
@@ -0,0 +1,56 @@
import fs from 'fs';
import path from 'path';
/**
* L2考核受验者注册表(config/l2-participants.json)。
* 受验者自行注册 Gitea 账号(用户名=员工编号)并建仓 L2-assessment
* 登记后由本表映射拉取 URL,避免手动填写仓库地址出错。
* 拉取认证走组委会评审账号的只读协作者权限(cloneRepo 全局凭据),本表不含任何密钥。
*/
export interface L2Participant {
no: string;
name: string;
gitteaUser: string;
repo: string;
remark?: string;
}
export interface L2ParticipantsFile {
note: string;
gitteaUrl: string;
reviewPullAccount: string;
participants: L2Participant[];
}
const CONFIG_PATH = path.resolve(__dirname, '../../../config/l2-participants.json');
let cached: L2ParticipantsFile | null = null;
export function loadL2Participants(): L2ParticipantsFile {
if (cached) return cached;
try {
cached = JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf-8')) as L2ParticipantsFile;
} catch {
cached = { note: '', gitteaUrl: 'https://gittea.dev', reviewPullAccount: '', participants: [] };
}
return cached;
}
/** 按员工编号/姓名/Gitea用户名匹配受验者(精确或包含) */
export function findL2Participant(query: string): L2Participant | undefined {
const q = query?.trim();
if (!q) return undefined;
const { participants } = loadL2Participants();
return participants.find(p =>
p.no === q || p.name === q || p.gitteaUser === q ||
q.includes(p.name) || q.includes(p.no) || (p.name && q.includes(p.gitteaUser))
);
}
/** 生成受验者仓库拉取 URLhttps://gittea.dev/<gitteaUser>/<repo>.git */
export function buildL2RepoUrl(p: L2Participant): string {
const { gitteaUrl } = loadL2Participants();
const base = (gitteaUrl || 'https://gittea.dev').replace(/\/+$/, '');
return `${base}/${encodeURIComponent(p.gitteaUser)}/${encodeURIComponent(p.repo || 'L2-assessment')}.git`;
}
+6 -23
View File
@@ -54,7 +54,7 @@ export function findL2Topic(id: string): L2Topic | null {
* 组装「功能完整性」维度子 Agent 的选题验收基准上下文(extraContext 注入)。
* 非命题/无匹配时返回空串。
*/
export function buildL2FuncContext(topicId: string, selfRegistration?: string): string {
export function buildL2FuncContext(topicId: string): string {
const t = findL2Topic(topicId);
if (!t || !topicId) return '';
const lines: string[] = [
@@ -68,28 +68,11 @@ export function buildL2FuncContext(topicId: string, selfRegistration?: string):
if (t.minTests) lines.push(`最少测试用例数:${t.minTests}`);
if (t.sampleData) lines.push(`题目专属样本数据要求:${t.sampleData}`);
if (t.id === 'self') {
const reg = parseRegistration(selfRegistration);
lines.push(`自选题登记编号:${reg.no || '(未登记)'}`);
if (reg.features) {
lines.push('登记功能清单快照(README 声明低于该范围核心功能的缩减部分按未实现计):');
for (const f of reg.features) lines.push(`- ${f}`);
} else {
lines.push('登记功能清单:未提供,按 README 声明功能清单核对');
}
lines.push(
'自选题核对基准(规范 §1.3.4):以仓库 AGENTS.md「自选题核心内容」记录的选题名称、痛点背景、预期功能清单与功能边界为准;',
'README 功能声明不得低于其中核心功能,未经说明的缩减部分按未实现计。',
'评审时先读取 AGENTS.md 提取功能清单,再逐项核对实现情况。'
);
}
return '\n' + lines.join('\n');
}
/** 解析自选题登记字段(JSON 字符串 {no, features}),容错 */
export function parseRegistration(raw?: string | null): { no: string; features: string[] } {
if (!raw) return { no: '', features: [] };
try {
const obj = typeof raw === 'string' ? JSON.parse(raw) : raw;
const features = Array.isArray(obj?.features)
? obj.features.map((f: any) => String(f).trim()).filter(Boolean)
: String(obj?.features || '').split(/[\n;]/).map(s => s.trim()).filter(Boolean);
return { no: String(obj?.no || ''), features };
} catch {
return { no: '', features: [] };
}
}
+25 -2
View File
@@ -10,7 +10,7 @@ import { parseDimensions } from '../routes/standards';
import { matchDimKey, computeLatePenalty, computeCalibration, parseDimResponse, resolveSubmitTime, computeLateDays, classifyVerifiability, detectStructuralContradictions, neutralizeTestEvidence, computeL2Result, computeL2LatePenalty } from './standard-utils';
import { isPathInside } from '../path-security';
import { applyHardRules, applyTrackHardRules } from './hard-rules';
import { findL2Topic, buildL2FuncContext, parseRegistration } from './l2-topics';
import { findL2Topic, buildL2FuncContext } from './l2-topics';
import { detectPlagiarism, readRepoFiles, detectCommitBehavior, PlagiarismReport } from './plagiarism-detect';
import {
REVIEW_CONSTANTS,
@@ -56,6 +56,28 @@ export function startReview(entryId: string) {
runReview(entryId, 'A');
}
// 一键多轮评审(2026-08-26):同一提交连续完成 N 轮,聚合取中位数,避免单次 AI 误判
const roundChain = new Map<string, { remain: number }>();
/** 一键 N 轮评审:第 1 轮立即启动,后续轮在每轮 review_done 后自动续跑(attempt 递增、各自落快照),全部完成后聚合成正式分 */
export function startReviewRounds(entryId: string, rounds: number) {
const n = Math.max(1, Math.min(5, Math.floor(rounds) || 1));
if (n > 1) roundChain.set(entryId, { remain: n - 1 });
startReview(entryId);
}
/** 轮次链推进:仅在本轮成功 review_done 且还有剩余轮次时续跑下一轮;失败/两段式(a_done)即中止 */
function maybeRunNextRound(entryId: string) {
const chain = roundChain.get(entryId);
if (!chain) return;
const st = (db.prepare('SELECT status FROM entries WHERE id = ?').get(entryId) as any)?.status;
if (st !== 'review_done' || chain.remain <= 0) { roundChain.delete(entryId); return; }
chain.remain--;
db.prepare("UPDATE entries SET status = 'pending', attempt = attempt + 1, updated_at = datetime('now') WHERE id = ?").run(entryId);
addLog(entryId, 'pending', `自动启动下一轮评审(剩余 ${chain.remain} 轮)`);
runReview(entryId, 'A');
}
// B 阶段启动??verify 触发):复???queue 机制,受 MAX_CONCURRENT 并发限制
export function startReviewB(entryId: string, buildStatus: 'done' | 'failed' = 'done') {
const entry = db.prepare('SELECT * FROM entries WHERE id = ?').get(entryId) as any;
@@ -172,7 +194,7 @@ function buildL2ExtraContexts(entry: any): Record<string, string> | undefined {
if (getProjectTrack(entry.project_id) !== 'L2考核') return undefined;
const topicId = entry.selected_topic || 'self';
if (!findL2Topic(topicId)) return undefined;
const block = buildL2FuncContext(topicId, entry.self_registration);
const block = buildL2FuncContext(topicId);
if (!block) return undefined;
return { '功能完整性': '\n' + block };
}
@@ -196,6 +218,7 @@ async function runReview(entryId: string, stage: 'A' | 'B', buildStatus?: 'done'
toStatus, stage === 'B' ? 'failed' : '', JSON.stringify([{ time: new Date().toISOString(), status: toStatus, msg }]), entryId);
} finally {
activeCount--;
try { maybeRunNextRound(entryId); } catch (e: any) { console.error('[rounds] chain error:', e.message); }
processQueue();
}
}
+6
View File
@@ -1,5 +1,6 @@
import fs from 'fs';
import path from 'path';
import { findL2Participant, buildL2RepoUrl } from './l2-participants';
export interface GitteaConfig {
url: string;
@@ -51,5 +52,10 @@ export function resolveRepoUrlFromConfig(title: string, track: string, fallback:
const team = findTeamByTitle(title);
if (team) return buildRepoUrl(team);
}
// L2考核:按受验者注册表(员工编号/姓名)映射拉取 URL,避免手动填写出错
if (track === 'L2考核') {
const p = findL2Participant(title);
if (p) return buildL2RepoUrl(p);
}
return fallback;
}
+8 -34
View File
@@ -205,7 +205,7 @@ function EntryManager({ projectId, track }: { projectId: string; track?: string
const [importResult, setImportResult] = useState<any>(null);
const [editEntry, setEditEntry] = useState<any>(null);
const [showAdd, setShowAdd] = useState(false);
const [addForm, setAddForm] = useState({ title: '', repo_url: '', participant: '', sub_type: '', branch: '', selected_topic: 'self', reg_no: '', reg_features: '' });
const [addForm, setAddForm] = useState({ title: '', repo_url: '', participant: '', sub_type: '', branch: '', selected_topic: 'self' });
const [l2Topics, setL2Topics] = useState<any[]>([]);
const [offset, setOffset] = useState(0);
const PAGE_LIMIT = 50;
@@ -246,9 +246,9 @@ function EntryManager({ projectId, track }: { projectId: string; track?: string
setSelected(next);
};
const doAction = async (action: string, entryId: string) => {
const doAction = async (action: string, entryId: string, body: any = {}) => {
try {
if (action === 'start') await api.request('POST', `/projects/${projectId}/entries/${entryId}/start`);
if (action === 'start') await api.request('POST', `/projects/${projectId}/entries/${entryId}/start`, { rounds: 3, ...body });
else if (action === 'cancel') await api.request('POST', `/projects/${projectId}/entries/${entryId}/cancel`);
else if (action === 'retry') await api.request('POST', `/projects/${projectId}/entries/${entryId}/retry`);
await load();
@@ -282,9 +282,6 @@ function EntryManager({ projectId, track }: { projectId: string; track?: string
};
if (track === 'L2考核') {
payload.selected_topic = editEntry.selected_topic || 'self';
if (payload.selected_topic === 'self') {
payload.self_registration = { no: editEntry.reg_no, features: editEntry.reg_features };
}
}
await api.request('PUT', `/projects/${projectId}/entries/${editEntry.id}`, payload);
setEditEntry(null);
@@ -293,30 +290,23 @@ function EntryManager({ projectId, track }: { projectId: string; track?: string
};
const openEdit = (e: any) => {
let reg = { no: '', features: '' };
try { const p = JSON.parse(e.self_registration || '{}'); reg = { no: p.no || '', features: Array.isArray(p.features) ? p.features.join('\n') : (p.features || '') }; } catch { }
setEditEntry({
id: e.id, title: e.title, repo_url: e.repo_url, participant: e.participant || '',
sub_type: e.sub_type || '', branch: e.branch || '',
service_url: e.service_url || '', build_status: e.build_status || '',
selected_topic: e.selected_topic || 'self', reg_no: reg.no, reg_features: reg.features,
selected_topic: e.selected_topic || 'self',
});
};
const doAdd = async () => {
if (!addForm.title.trim() || !addForm.repo_url.trim()) return;
const payload: any = { ...addForm };
delete payload.reg_no;
delete payload.reg_features;
if (track === 'L2考核') {
payload.selected_topic = addForm.selected_topic || 'self';
if (payload.selected_topic === 'self') {
payload.self_registration = { no: addForm.reg_no, features: addForm.reg_features };
}
}
try {
await api.request('POST', `/projects/${projectId}/entries`, payload);
setAddForm({ title: '', repo_url: '', participant: '', sub_type: '', branch: '', selected_topic: 'self', reg_no: '', reg_features: '' });
setAddForm({ title: '', repo_url: '', participant: '', sub_type: '', branch: '', selected_topic: 'self' });
setShowAdd(false);
await load();
} catch (err: any) { alert(err.message || '添加失败'); }
@@ -439,20 +429,12 @@ function EntryManager({ projectId, track }: { projectId: string; track?: string
</select>
)}
{track === 'L2考核' && (
<>
<select value={addForm.selected_topic} onChange={e => setAddForm({ ...addForm, selected_topic: e.target.value })} className="select-field">
<option value="self"></option>
<option value="self"></option>
{l2Topics.map(t => (
<option key={t.id} value={t.id}> {t.id}{t.title}{'★'.repeat(t.difficulty)} {t.maxScoreCap}</option>
))}
</select>
{addForm.selected_topic === 'self' && (
<>
<input value={addForm.reg_no} onChange={e => setAddForm({ ...addForm, reg_no: e.target.value })} placeholder="登记编号(组委会登记确认后获得)" className="input-field" />
<textarea value={addForm.reg_features} onChange={e => setAddForm({ ...addForm, reg_features: e.target.value })} placeholder="登记功能清单(每行一条;低于该范围核心功能的缩减按未实现计)" rows={3} className="input-field" />
</>
)}
</>
)}
<div className="form-actions">
<button onClick={doAdd} disabled={!addForm.title.trim() || !addForm.repo_url.trim()}></button>
@@ -528,7 +510,7 @@ function EntryManager({ projectId, track }: { projectId: string; track?: string
{e.status === 'verifying' && <button className="btn-action warn" onClick={() => doAction('cancel', e.id)}></button>}
{['clone_fail', 'analysis_fail', 'failed'].includes(e.status) && <button className="btn-action" onClick={() => doAction('retry', e.id)}></button>}
{['review_done', 'admin_reviewed'].includes(e.status) && <button className="btn-action" onClick={() => openDetail(e.id)}></button>}
{['review_done', 'admin_reviewed'].includes(e.status) && <button className="btn-action" onClick={() => doAction('start', e.id)}></button>}
{['review_done', 'admin_reviewed'].includes(e.status) && <button className="btn-action" onClick={() => doAction('start', e.id)}>×3</button>}
</td>
</tr>
))}
@@ -576,20 +558,12 @@ function EntryManager({ projectId, track }: { projectId: string; track?: string
</select>
)}
{track === 'L2考核' && (
<>
<select value={editEntry.selected_topic || 'self'} onChange={e => setEditEntry({ ...editEntry, selected_topic: e.target.value })} className="select-field">
<option value="self"></option>
<option value="self"></option>
{l2Topics.map(t => (
<option key={t.id} value={t.id}> {t.id}{t.title}{'★'.repeat(t.difficulty)} {t.maxScoreCap}</option>
))}
</select>
{editEntry.selected_topic === 'self' && (
<>
<input value={editEntry.reg_no || ''} onChange={e => setEditEntry({ ...editEntry, reg_no: e.target.value })} placeholder="登记编号" className="input-field" />
<textarea value={editEntry.reg_features || ''} onChange={e => setEditEntry({ ...editEntry, reg_features: e.target.value })} placeholder="登记功能清单(每行一条)" rows={3} className="input-field" />
</>
)}
</>
)}
<div className="form-actions">
<button onClick={doEditSave}></button>