feat(flywheel): 返工热区 UI + get_high_risk_scopes 命令,阶段三收官
All checks were successful
Push & PR Check / check (push) Successful in 50s
Push & PR Check / check (pull_request) Successful in 50s

- risk.rs 新增 Tauri command get_high_risk_scopes(薄包装)+ lib.rs 注册
- commands.ts 封装 HighRiskScope 类型与调用(R01)
- FlywheelPanel 新增「返工热区」块:跨项目返工率降序,
  分级配色与 classify_risk 阈值一致(≥35% 红 / ≥15% 琥珀)
- 蓝图:P3-A~E 五卡全部 done,附 L 级复盘笔记,模块 progress 98

Rules-Applied: R01,R13
This commit is contained in:
lanrtop 2026-07-04 14:21:44 +09:00
parent 66dc6209a8
commit a5cb30734d
8 changed files with 106 additions and 7 deletions

View File

@ -305,8 +305,8 @@ modules:
name: 飞轮智能成长 name: 飞轮智能成长
area: backend area: backend
status: in_progress status: in_progress
progress: 92 progress: 98
note: "阶段三已过 architect+splitter2026-07-04P3-A~E 五卡待执行P0 发现 R1 trailer 管道死链(%s 只取 subjectP3-A 修复" note: "阶段三 P3-A~E 全部完成2026-07-04trailer 死链修复+回填、commit_files 采集、predict_task_risk MCP、梦核高风险 scope 段、返工热区 UI剩存量回填与 MCP 实调终验(待新 build 重启)"
position: [1750, 650] position: [1750, 650]
- id: cloud-products - id: cloud-products

View File

@ -183,12 +183,26 @@
- files: src-tauri/src/commands/blueprint.rs - files: src-tauri/src/commands/blueprint.rs
- acceptance: "[cargo test] 梦核 prompt 构建函数单测断言输出含「跨项目高风险 scope」数据段返工率 top scope + 项目分布);规则置信度段在 P3-A 数据流入后自然激活(注入点 blueprint.rs rule_hit_stats 已存在)" - acceptance: "[cargo test] 梦核 prompt 构建函数单测断言输出含「跨项目高风险 scope」数据段返工率 top scope + 项目分布);规则置信度段在 P3-A 数据流入后自然激活(注入点 blueprint.rs rule_hit_stats 已存在)"
### 📋 P3-E. FlywheelPanel 风险展示 + commands.ts 同步(可选收尾) ### ✅ P3-E. FlywheelPanel 风险展示 + commands.ts 同步(可选收尾)
- status: todo - status: done
- done_note: 2026-07-04 完成。实现形态微调Git 执行质量表已有 TOP scope 列F2 遗产),故新增独立「返工热区」块展示 get_high_risk_scopes跨项目返工率降序分级配色与 classify_risk 阈值一致 ≥35% 红 / ≥15% 琥珀Tauri command get_high_risk_scopes 薄包装 + lib.rs 注册 + commands.ts 封装R01。pnpm typecheck exit 0cargo test 92 全绿
- complexity: S - complexity: S
- depends: flywheel-intelligence卡 P3-C - depends: flywheel-intelligence卡 P3-C
- files: src/lib/commands.ts, src/components/dashboard/BlueprintModal.tsx - files: src/lib/commands.ts, src/components/insight/FlywheelPanel.tsx, src-tauri/src/commands/risk.rs, src-tauri/src/lib.rs
- acceptance: "[pnpm typecheck] exit 0FlywheelPanel「Git 执行质量」卡片新增各项目返工率 top scope 列get_scope_risk_profile 封装同步R01" - acceptance: "[pnpm typecheck] exit 0FlywheelPanel 新增跨项目返工热区展示get_high_risk_scopes 封装同步R01"
## 复盘笔记
【复盘】阶段三执行质量预测层 P3-A~E2026-07-04
任务类型: 后端数据管道 + MCP工具 + 前端展示
复杂度: Larchitect+splitter 拆为 2M+1M+1S+1S单会话连续执行
实际轮数: 1轮预估 1 轮)
是否返工: 否
有效策略: architect 阶段先查数据库实况而非只读设计文档——由此发现 R1 trailer 管道死链(%s 只取 subject单测喂全文全绿而生产喂 subject 永空),这个 P0 若不修,阶段三核心闭环(规则置信度)建在死数据上;「单元绿、集成死」用真 git 仓库 e2e 测试驻军UPSERT 只回填 NULL 不覆盖,让回填天然幂等;三处重复的 git log 取数统一为单一入口read_git_log--name-only 让指标与文件单次进程同取
顺手修的旧债: generate_muhe_prompt 用 pool() 导致测试环境必 panic不可测改 try_pool() 走占位文案
遗留: 存量数据回填与 predict_task_risk MCP 实调,待新 build 发布重启后终验(跑一次「全量导入」即回填 trailer + 文件)
auto_applied_rules: R01, R05, R06, R07, R13
rule_effectiveness: R06=有效conn 注入使 risk.rs 7 测试全部 in-memory 可行), R07=有效e2e git 仓库回归测试抓住的正是集成层缺口), R13=有效acceptance 可执行格式让五张卡零歧义), R01=有效commands.ts 同步时确认 HighRiskScope 类型单一来源), R05=有效commit_files migration 随手写进 migrate()
## 决策记录 ## 决策记录

3
.gitignore vendored
View File

@ -31,3 +31,6 @@ src-tauri/dev_manager.db
# 防止签名密钥被误提交Windows ~ 路径展开问题) # 防止签名密钥被误提交Windows ~ 路径展开问题)
~/ ~/
# 测试运行产物(根目录杂散 DB
/dev-manager-tauri.db

View File

@ -3,7 +3,7 @@
> 把此文件粘贴给任何 AI Agent让它了解本项目的 git 工作方式。由炼境接入包分发。 > 把此文件粘贴给任何 AI Agent让它了解本项目的 git 工作方式。由炼境接入包分发。
> `ONBOARDING_MANAGED` 标记块由炼境版本化管理(重跑接入包可原位升级),块外可自由补充项目特有约定。 > `ONBOARDING_MANAGED` 标记块由炼境版本化管理(重跑接入包可原位升级),块外可自由补充项目特有约定。
<!-- ONBOARDING_MANAGED_START version="1.1.0" --> <!-- ONBOARDING_MANAGED_START version="1.2.0" -->
## 分支策略 ## 分支策略
@ -72,6 +72,22 @@ git commit -m "feat(模块): 一件事"
PR 别攒太大(建议每 3~5 个 commit 或几百行内就开一次),否则 CI code review 易超时失效。 PR 别攒太大(建议每 3~5 个 commit 或几百行内就开一次),否则 CI code review 易超时失效。
「所有检测通过」≠ 代码被审查过——大 PR 即使 CI 全绿review 可能已静默失效。 「所有检测通过」≠ 代码被审查过——大 PR 即使 CI 全绿review 可能已静默失效。
## PR 创建(炼境托管项目)
本项目由炼境管理MCP 已注入且 `.claude/liangjing.json``project_id`
**推送分支后,通过炼境 MCP 创建 PR禁止用 curl + git credential fill 提取 token**
```
1. Read .claude/liangjing.json → 取出 project_id
2. 调用 MCP 工具 create_pull_request
{ "project_id": "<id>", "head": "dev", "base": "main",
"title": "<Conventional Commits 格式>", "body": "<变更摘要>" }
3. 炼境内部用存储的 Gitea 凭证调 API返回 pr_url
```
若炼境未运行MCP 不可用),降级方案:去 Gitea 网页手动创建 PR。
## 常用命令 ## 常用命令
```bash ```bash

View File

@ -167,6 +167,16 @@ pub fn high_risk_scopes(
Ok(result) Ok(result)
} }
/// Tauri command跨项目返工热区FlywheelPanel「返工热区」块。薄包装逻辑在 high_risk_scopes。
#[tauri::command]
pub fn get_high_risk_scopes(
min_commits: Option<u32>,
limit: Option<u32>,
) -> Result<Vec<HighRiskScope>, String> {
let conn = crate::db::pool().get().map_err(|e| e.to_string())?;
high_risk_scopes(&conn, min_commits.unwrap_or(5), limit.unwrap_or(10) as usize)
}
/// 核心入口:按 scope 和/或文件清单预测任务风险。 /// 核心入口:按 scope 和/或文件清单预测任务风险。
pub fn predict_task_risk( pub fn predict_task_risk(
conn: &Connection, conn: &Connection,

View File

@ -278,6 +278,7 @@ pub fn run() {
commands::commit_metrics::ingest_full_git_history, commands::commit_metrics::ingest_full_git_history,
commands::commit_metrics::get_project_commit_health, commands::commit_metrics::get_project_commit_health,
commands::commit_metrics::get_all_commit_health, commands::commit_metrics::get_all_commit_health,
commands::risk::get_high_risk_scopes,
// mentor // mentor
get_mentor_context, get_mentor_context,
get_project_notes, get_project_notes,

View File

@ -9,10 +9,12 @@ import {
archiveProjectDocs, archiveProjectDocs,
ingestFullGitHistory, ingestFullGitHistory,
getAllCommitHealth, getAllCommitHealth,
getHighRiskScopes,
type Project, type Project,
type FlywheelStats, type FlywheelStats,
type StalledProject, type StalledProject,
type CommitHealthWithName, type CommitHealthWithName,
type HighRiskScope,
} from "../../lib/commands"; } from "../../lib/commands";
function StalledProjectRow({ p, projectsMap, onArchive }: { function StalledProjectRow({ p, projectsMap, onArchive }: {
@ -84,6 +86,11 @@ export function FlywheelPanel() {
queryFn: () => getAllCommitHealth(), queryFn: () => getAllCommitHealth(),
}); });
const { data: riskScopes } = useQuery<HighRiskScope[]>({
queryKey: ["high-risk-scopes"],
queryFn: () => getHighRiskScopes(),
});
const [ingesting, setIngesting] = useState(false); const [ingesting, setIngesting] = useState(false);
const [ingestSummary, setIngestSummary] = useState<string | null>(null); const [ingestSummary, setIngestSummary] = useState<string | null>(null);
@ -375,6 +382,42 @@ export function FlywheelPanel() {
)} )}
</div> </div>
{/* 返工热区(飞轮阶段三预测层) */}
{riskScopes && riskScopes.length > 0 && (
<div className="bg-white rounded-lg border border-gray-100 p-3 space-y-2">
<p className="text-[10px] font-semibold text-gray-400 uppercase tracking-wider">
<span className="ml-1.5 normal-case font-normal"></span>
</p>
<div className="overflow-x-auto">
<table className="w-full text-[10px]">
<thead>
<tr className="text-gray-400 border-b border-gray-100">
<th className="text-left pb-1 font-medium"></th>
<th className="text-left pb-1 font-medium">scope</th>
<th className="text-right pb-1 font-medium">commits</th>
<th className="text-right pb-1 font-medium"></th>
</tr>
</thead>
<tbody className="divide-y divide-gray-50">
{riskScopes.map((s) => (
<tr key={`${s.project_name}-${s.scope}`} className="hover:bg-gray-50">
<td className="py-1 text-gray-700 truncate max-w-[80px]" title={s.project_name}>
{s.project_name}
</td>
<td className="py-1 text-gray-500 font-mono truncate max-w-[100px]">{s.scope}</td>
<td className="py-1 text-right font-mono text-gray-500">{s.commits}</td>
<td className={`py-1 text-right font-mono font-semibold ${s.rework_rate >= 0.35 ? "text-red-500" : s.rework_rate >= 0.15 ? "text-amber-500" : "text-gray-500"}`}>
{Math.round(s.rework_rate * 100)}%
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
)}
{/* 梦核分析 */} {/* 梦核分析 */}
<div className="bg-white rounded-lg border border-gray-100 p-3 space-y-2"> <div className="bg-white rounded-lg border border-gray-100 p-3 space-y-2">
<p className="text-[10px] font-semibold text-gray-400 uppercase tracking-wider"></p> <p className="text-[10px] font-semibold text-gray-400 uppercase tracking-wider"></p>

View File

@ -1611,6 +1611,18 @@ export interface CommitHealthWithName extends ProjectCommitHealth {
export const getAllCommitHealth = () => export const getAllCommitHealth = () =>
invoke<CommitHealthWithName[]>("get_all_commit_health"); invoke<CommitHealthWithName[]>("get_all_commit_health");
// 飞轮阶段三:跨项目返工热区(样本 ≥minCommits 且有非 CI 返工的 scope按返工率降序
export interface HighRiskScope {
project_name: string;
scope: string;
commits: number;
rework: number;
rework_rate: number;
}
export const getHighRiskScopes = (minCommits?: number, limit?: number) =>
invoke<HighRiskScope[]>("get_high_risk_scopes", { minCommits, limit });
// ── Gitea Integration ──────────────────────────────────────────────────────── // ── Gitea Integration ────────────────────────────────────────────────────────
export interface GiteaInstance { export interface GiteaInstance {