评审真实性P1落地:全量代码可见性+Mock信号+AI日志审计+定向追踪+功能发现轮
- code-inventory.ts:全量符号索引,注入实现类维度,AI 可见100%文件清单 - code-signals.ts:代码信号检测器(TODO密度/空壳率/硬编码返回/死导入),修复TODO检测顺序bug - ai-log-audit.ts:AI日志确定性审计(占位率/git一致率/覆盖广度),占位>50%→≤30%、git一致<30%→≤20%封顶 - standard-utils.ts:isQualitativeDesignDim 定性设计维度豁免C档 - review.service.ts:注入三个模块+定向追踪模板+日志封顶+分支提醒+Map-Reduce功能发现轮 - 预算 15000→40000;新增 review-authenticity.test.ts(14用例) - 实测:净码特攻b3 81分(118功能全量识别),六边形50~62分(Mock被识别)
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
import path from 'path';
|
||||
|
||||
/**
|
||||
* 全量代码可见性(2026-08-26 评审真实性改进方案 §3.1):
|
||||
* 对仓库全部文本文件生成轻量签名索引,让评审 AI 看见 100% 文件清单,
|
||||
* 替代"前60个文件+15K截断"导致的盲区。
|
||||
*/
|
||||
|
||||
export interface FileSignature {
|
||||
path: string;
|
||||
lines: number;
|
||||
lang: 'ts' | 'js' | 'py' | 'other';
|
||||
symbols: string[];
|
||||
}
|
||||
|
||||
const CODE_LANG: Record<string, 'ts' | 'js' | 'py'> = {
|
||||
'.ts': 'ts', '.tsx': 'ts', '.mts': 'ts', '.cts': 'ts',
|
||||
'.js': 'js', '.jsx': 'js', '.mjs': 'js', '.cjs': 'js',
|
||||
'.py': 'py',
|
||||
};
|
||||
|
||||
/** 可提取符号的文本扩展名(其余只记 path+lines) */
|
||||
const TEXT_EXTS = new Set([
|
||||
...Object.keys(CODE_LANG),
|
||||
'.json', '.yaml', '.yml', '.md', '.html', '.css', '.scss', '.vue',
|
||||
'.sql', '.sh', '.java', '.go', '.rs', '.rb', '.php', '.cs', '.kt',
|
||||
]);
|
||||
|
||||
// 各语言的定义行模式(保守匹配,宁缺勿滥)
|
||||
const SYMBOL_PATTERNS: Record<string, RegExp[]> = {
|
||||
ts: [
|
||||
/^\s*(export\s+)?(default\s+)?(async\s+)?function\s+\w+/,
|
||||
/^\s*(export\s+)?(abstract\s+)?class\s+\w+/,
|
||||
/^\s*export\s+(const|let|var)\s+\w+\s*=\s*(\(|async|function)/,
|
||||
/^\s*export\s+(interface|type|enum)\s+\w+/,
|
||||
/^\s*(public|private|protected|static)?\s*(async\s+)?\w+\s*\([^)]*\)\s*[:{]/,
|
||||
],
|
||||
js: [
|
||||
/^\s*(export\s+)?(default\s+)?(async\s+)?function\s+\w+/,
|
||||
/^\s*(export\s+)?(class\s+\w+)/,
|
||||
/^\s*(export\s+)?(const|let|var)\s+\w+\s*=\s*(\(|async|function|\w+\s*=>)/,
|
||||
/^\s*(module\.exports|exports\.\w+)\s*=/
|
||||
],
|
||||
py: [
|
||||
/^\s*def\s+\w+/,
|
||||
/^\s*class\s+\w+/,
|
||||
],
|
||||
};
|
||||
|
||||
export function extractSignatures(files: { path: string; content?: string; size?: number }[]): FileSignature[] {
|
||||
const out: FileSignature[] = [];
|
||||
for (const f of files) {
|
||||
const ext = path.extname(f.path).toLowerCase();
|
||||
const rel = f.path.replace(/\\/g, '/');
|
||||
// 行数:有内容用内容算,否则用 size 粗估
|
||||
let lines = 0;
|
||||
let lang: FileSignature['lang'] = 'other';
|
||||
const codeLang = CODE_LANG[ext];
|
||||
if (codeLang) lang = codeLang;
|
||||
|
||||
let content: string | undefined;
|
||||
if ('content' in f && typeof (f as any).content === 'string') {
|
||||
content = (f as any).content as string;
|
||||
lines = content.split('\n').length;
|
||||
} else if (f.size != null) {
|
||||
lines = Math.max(1, Math.round(f.size / 38)); // 平均 38 字节/行 估算
|
||||
} else {
|
||||
lines = 1;
|
||||
}
|
||||
|
||||
if (!TEXT_EXTS.has(ext)) {
|
||||
out.push({ path: rel, lines, lang: 'other', symbols: [] });
|
||||
continue;
|
||||
}
|
||||
|
||||
const symbols: string[] = [];
|
||||
if (content && codeLang) {
|
||||
const patterns = SYMBOL_PATTERNS[codeLang] || [];
|
||||
for (const line of content.split('\n')) {
|
||||
if (symbols.length >= 5) break;
|
||||
for (const re of patterns) {
|
||||
if (re.test(line)) {
|
||||
symbols.push(line.trim().slice(0, 100));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
out.push({ path: rel, lines, lang, symbols });
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/** 渲染紧凑索引文本(供注入 prompt)——全量文件,每文件 1~3 行 */
|
||||
export function renderInventoryText(sigs: FileSignature[], budgetChars = 8000): string {
|
||||
const lines: string[] = ['', '## 仓库文件全量索引(共 ' + sigs.length + ' 个文件,此清单为完整底账,评分必须覆盖其中核心文件)'];
|
||||
let used = lines.join('\n').length;
|
||||
for (const s of sigs) {
|
||||
const symLine = s.symbols.length ? ' | ' + s.symbols.slice(0, 2).join(' ; ') : '';
|
||||
const l = `- ${s.path} (${s.lines}行${s.lang !== 'other' ? ',' + s.lang : ''})${symLine}`;
|
||||
if (used + l.length > budgetChars) {
|
||||
lines.push(`- …(其余 ${sigs.length - sigs.indexOf(s)} 个文件见截断说明,均为外围配置/资源)`);
|
||||
break;
|
||||
}
|
||||
lines.push(l);
|
||||
used += l.length;
|
||||
}
|
||||
return '\n' + lines.join('\n');
|
||||
}
|
||||
Reference in New Issue
Block a user