feat(onboarding): 接入包数据可信度提示(commit 规范化比例)
get_commit_stats 暴露项目 commit 规范化统计(total/conventional/rework);治理面板常驻展示规范化比例 + 返工数,比例 <60% 提示种 lefthook。接入包 A/B/C1/C2/D 全部完成。
This commit is contained in:
parent
150535ffcf
commit
58d2c79c74
@ -93,8 +93,8 @@ git 是「过去时 + 量化」(做了什么),蓝图是「将来时 + 语
|
|||||||
- files: src-tauri/src/commands/buff.rs, src-tauri/src/commands/blueprint.rs
|
- files: src-tauri/src/commands/buff.rs, src-tauri/src/commands/blueprint.rs
|
||||||
- acceptance: check_project 用 `last_commit..HEAD` 取 commit message(git log,复用现有 WSL 路径处理)→ 调 C1 解析写 commit_metrics;首次接入(last_commit 空)限解析最近 N 条;append_usage_snapshot 的 rework_count 改查 commit_metrics(is_rework=1 AND is_ci_auto=0)取代 parse_notes_metrics
|
- acceptance: check_project 用 `last_commit..HEAD` 取 commit message(git log,复用现有 WSL 路径处理)→ 调 C1 解析写 commit_metrics;首次接入(last_commit 空)限解析最近 N 条;append_usage_snapshot 的 rework_count 改查 commit_metrics(is_rework=1 AND is_ci_auto=0)取代 parse_notes_metrics
|
||||||
|
|
||||||
### 🔵 D 数据可信度提示
|
### ✅ D 数据可信度提示
|
||||||
- status: planned
|
- status: done
|
||||||
- complexity: S
|
- complexity: S
|
||||||
- depends: onboarding-pack(卡 C1、卡 B)
|
- depends: onboarding-pack(卡 C1、卡 B)
|
||||||
- files: src-tauri/src/commands/onboarding.rs, src-tauri/src/commands/commit_metrics.rs
|
- files: src-tauri/src/commands/onboarding.rs, src-tauri/src/commands/commit_metrics.rs
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
//! 取代枯竭的「复盘笔记解析」路径。纯解析逻辑(`parse_conventional`)与 DB 无关,可独立单测。
|
//! 取代枯竭的「复盘笔记解析」路径。纯解析逻辑(`parse_conventional`)与 DB 无关,可独立单测。
|
||||||
|
|
||||||
use rusqlite::Connection;
|
use rusqlite::Connection;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
/// 一条 commit 的解析结果。
|
/// 一条 commit 的解析结果。
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
@ -114,7 +115,6 @@ pub fn rework_count(conn: &Connection, project_id: &str) -> Result<u32, String>
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// commit 规范化统计:(总数, conventional 数)。供数据可信度提示(卡 D)使用。
|
/// commit 规范化统计:(总数, conventional 数)。供数据可信度提示(卡 D)使用。
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn conventional_stats(conn: &Connection, project_id: &str) -> Result<(u32, u32), String> {
|
pub fn conventional_stats(conn: &Connection, project_id: &str) -> Result<(u32, u32), String> {
|
||||||
let total: i64 = conn
|
let total: i64 = conn
|
||||||
.query_row(
|
.query_row(
|
||||||
@ -133,6 +133,27 @@ pub fn conventional_stats(conn: &Connection, project_id: &str) -> Result<(u32, u
|
|||||||
Ok((total as u32, conv as u32))
|
Ok((total as u32, conv as u32))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 项目 commit 执行质量统计(供前端数据可信度展示)。
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
|
pub struct CommitStats {
|
||||||
|
pub total: u32,
|
||||||
|
pub conventional: u32,
|
||||||
|
pub rework: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 查询某项目的 commit 执行质量统计(总数 / conventional 数 / 有效返工数)。
|
||||||
|
#[tauri::command]
|
||||||
|
pub fn get_commit_stats(project_id: String) -> Result<CommitStats, String> {
|
||||||
|
let conn = crate::db::pool().get().map_err(|e| e.to_string())?;
|
||||||
|
let (total, conventional) = conventional_stats(&conn, &project_id)?;
|
||||||
|
let rework = rework_count(&conn, &project_id)?;
|
||||||
|
Ok(CommitStats {
|
||||||
|
total,
|
||||||
|
conventional,
|
||||||
|
rework,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|||||||
@ -267,6 +267,7 @@ pub fn run() {
|
|||||||
list_buffed_projects,
|
list_buffed_projects,
|
||||||
// onboarding pack
|
// onboarding pack
|
||||||
commands::onboarding::apply_onboarding_pack,
|
commands::onboarding::apply_onboarding_pack,
|
||||||
|
commands::commit_metrics::get_commit_stats,
|
||||||
// mentor
|
// mentor
|
||||||
get_mentor_context,
|
get_mentor_context,
|
||||||
get_project_notes,
|
get_project_notes,
|
||||||
|
|||||||
@ -23,6 +23,7 @@ import {
|
|||||||
generateMuhePrompt,
|
generateMuhePrompt,
|
||||||
archiveProjectDocs,
|
archiveProjectDocs,
|
||||||
applyOnboardingPack,
|
applyOnboardingPack,
|
||||||
|
getCommitStats,
|
||||||
removeBlueprintBuff,
|
removeBlueprintBuff,
|
||||||
getBuffStatus,
|
getBuffStatus,
|
||||||
getUserConventionsStatus,
|
getUserConventionsStatus,
|
||||||
@ -39,6 +40,7 @@ import {
|
|||||||
type StalledProject,
|
type StalledProject,
|
||||||
type BuffStatus,
|
type BuffStatus,
|
||||||
type TemplateResult,
|
type TemplateResult,
|
||||||
|
type CommitStats,
|
||||||
type UserConventionsStatus,
|
type UserConventionsStatus,
|
||||||
} from "../../lib/commands";
|
} from "../../lib/commands";
|
||||||
|
|
||||||
@ -1061,6 +1063,13 @@ function GovernancePanel({
|
|||||||
staleTime: 5000,
|
staleTime: 5000,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { data: commitStats } = useQuery<CommitStats | null>({
|
||||||
|
queryKey: ["commit-stats-governance", projectId],
|
||||||
|
queryFn: () => (projectId ? getCommitStats(projectId) : Promise.resolve(null)),
|
||||||
|
enabled: !!projectId,
|
||||||
|
staleTime: 5000,
|
||||||
|
});
|
||||||
|
|
||||||
const [syncing, setSyncing] = useState(false);
|
const [syncing, setSyncing] = useState(false);
|
||||||
const [syncResult, setSyncResult] = useState<SyncResult | null>(null);
|
const [syncResult, setSyncResult] = useState<SyncResult | null>(null);
|
||||||
const [syncError, setSyncError] = useState<string | null>(null);
|
const [syncError, setSyncError] = useState<string | null>(null);
|
||||||
@ -1521,6 +1530,19 @@ function GovernancePanel({
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{buffStatus?.status === "active" && commitStats && commitStats.total > 0 && (
|
||||||
|
<div className="pt-1.5 border-t border-gray-100 space-y-0.5">
|
||||||
|
<p className="text-[10px] text-gray-500">
|
||||||
|
commit 规范化 {commitStats.conventional}/{commitStats.total}(
|
||||||
|
{Math.round((commitStats.conventional / commitStats.total) * 100)}%) · 返工 {commitStats.rework}
|
||||||
|
</p>
|
||||||
|
{commitStats.conventional / commitStats.total < 0.6 && (
|
||||||
|
<p className="text-[10px] text-amber-600 leading-relaxed">
|
||||||
|
⚠ 规范化偏低,飞轮数据可信度低——种 lefthook(接入包已含)后逐步转准
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 项目信息 */}
|
{/* 项目信息 */}
|
||||||
|
|||||||
@ -1615,6 +1615,15 @@ export interface OnboardingReport {
|
|||||||
export const applyOnboardingPack = (projectPath: string, projectId: string) =>
|
export const applyOnboardingPack = (projectPath: string, projectId: string) =>
|
||||||
invoke<OnboardingReport>("apply_onboarding_pack", { projectPath, projectId });
|
invoke<OnboardingReport>("apply_onboarding_pack", { projectPath, projectId });
|
||||||
|
|
||||||
|
export interface CommitStats {
|
||||||
|
total: number;
|
||||||
|
conventional: number;
|
||||||
|
rework: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getCommitStats = (projectId: string) =>
|
||||||
|
invoke<CommitStats>("get_commit_stats", { projectId });
|
||||||
|
|
||||||
// ── Beast Global Status (read-only) ───────────────────────────────────────────
|
// ── Beast Global Status (read-only) ───────────────────────────────────────────
|
||||||
|
|
||||||
export interface BeastGlobalStatus {
|
export interface BeastGlobalStatus {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user