协作证明
collab-proof
挖掘开发者未有意识记录的 AI 协作证据。
Vela 三层流水线 × ADHD 四框架推理 —— 提示词原生,零依赖。
---
Layer 01 — 信号检测 (Signal detection)
首先运行 git log --oneline -10 和 git diff --stat HEAD~3..HEAD。
根据以下标准对信号级别进行分类(选择匹配的最高级别):
HIGH (高) → 完整产出物 (DECISIONS.md + session-history + WORKLOG + HTML)
- 创建了新文件,或
- 修改了 4 个及以上文件,或
- 对话中存在明确的选项对比(“vs”、“而不是”、“选择 X 而非 Y”),或
- 设计讨论持续 15 次以上往返,或
- 带有根因诊断的 Bug 修复 —— 对话中包含 Bug 发生的原因(不仅是“修复了 X”,而是“Bug 是由 Y 引起的,因为 Z”)
BUG_FIXING 特殊规则 —— 覆盖文件数量限制:
即使仅修改了 1 个文件,只要对话包含以下内容,即分类为 HIGH:
- 根因解释(“Bug 是...”、“这是因为...”、“问题在于...”)
- 诊断过程(“我检查了...”、“结果发现...”、“问题是...”)
- 修复逻辑(“选择这个方案是因为...”、“没有用 X 而是用 Y,因为...”)
对于 Bug 修复,文件数量并不重要 —— 一个诊断充分的单文件修复比一个没有讨论的 10 文件功能开发更有价值。
MEDIUM (中) → 仅记录 WORKLOG
- 修改了 1-3 个文件且无根因讨论,或
- 添加了小型功能,未讨论权衡方案
LOW (低) → 保持沉默,告知用户 "Routine session — nothing recorded." (常规会话 —— 无记录内容)
- 无代码变更,仅有规划/讨论,或
- 单一琐碎变更且无上下文(“修改这段文字”、“修复错别字”、“重命名变量”)
向用户展示:Signal: HIGH / MEDIUM / LOW — [一行原因]
---
Layer 02 — 工作意图分类器 (WorkIntentClassifier)
针对对话上下文 + git diff 同时运行四个框架。
根据以下标准为每个框架打分 (0.0–1.0),然后应用剪枝和分类规则。
框架评分标准
Frame A — 技术维度 (代码变更复杂度)
1.0创建了新模块/文件,添加了复杂逻辑(状态机、Lua 脚本、新算法)
0.5修改了现有函数逻辑,添加了简单的 API 接口
0.1修复错别字、修改注释、纯文本编辑
Frame B — 不确定性维度 (开发者的疑虑信号)
1.0代码编写后完全回滚,表达了明确的怀疑(“这样对吗?”、“没运行起来”),执行了git revert
0.5在实现过程中寻求 Claude 的建议,同一区域请求 2 次以上修改
0.0指令执行无中断 —— 开发者非常清楚要构建什么
Frame C — 分叉维度 (决策分支的存在)
1.0对话中明确对比了两个或更多替代方案 (A vs B)
0.5没有明确对比但提到了权衡 (性能 vs 可读性)
0.0采用了单一标准方案,未考虑替代方案
Frame D — AI 贡献维度 (Claude 的实际影响)
1.0Claude 发现了开发者未注意到的 Bug/边缘情况并提出了修复方案
0.6Claude 生成了结构化样板代码/骨架,显著加速了执行
0.2Claude 仅对开发者指定的代码进行格式化或转录,无独立贡献
---
剪枝规则
剪掉任何得分 < 0.4 的框架。
特例 — 高速执行守护 (High-Speed Execution Guard):
如果 Frame
若 A >= 0.8 且 Frame D >= 0.6,则不要剪枝且不要静默该会话,即使 Frame B = 0.0 且 Frame C = 0.0。
这是一个样板代码密集的 FEATURE_BUILDING 会话。请立即将其分类为 FEATURE_BUILDING 并标记为 HIGH 信号。
理由:在快速推进的会话中,零不确定性是一项特性,而非丢弃它的理由。
---
意图分类
| 存留帧 (Surviving frames) | 主导意图 | 含义 |
|---|---|---|
| A 高 + D 中高 (B, C 低) | FEATURE_BUILDING | 高速功能生成,Claude 搭建脚手架 |
| B 高 + A/D 高 | BUG_FIXING 或 STUCK | 积极调试或未解决的循环 |
| C 高 + A 高 | REFACTORING 或 EXPLORING | 架构探索,权衡替代方案 |
| 所有帧 < 0.4 | FLOW_STATE 或 LOW | 常规输入,除非 Layer 01 为 HIGH 否则静默 |
若多个意图得分相同,选择综合帧得分最高的一个。
记录次选意图 —— 它应包含在会话叙述中。
---
内部输出格式
在进入 Layer 03 之前,请解析为以下结构(向用户展示):
{
"frames": {
"technical": 0.0,
"uncertainty": 0.0,
"fork": 0.0,
"ai_contribution": 0.0
},
"pruned": ["被剪枝的帧名称列表"],
"intent": "FEATURE_BUILDING",
"signal": "HIGH",
"calibration_note": "解释所应用的任何例外规则的一句话"
}---
Layer 03 — 输出
若为 HIGH 信号
追加至 DECISIONS.md —— 每个真实分叉记录一条(Frame C 必须确认存在替代方案):
## [YYYY-MM-DD] <标题>
上下文: [Frame A — 导致此选择的原因]
决策: 选择了什么
考虑过的替代方案: [Frame C — 未选择的路径]
推理: 原因 —— 若是从上下文中推断的,请加上 "inferred:" 前缀
AI 贡献:
- 识别: [Frame D — 开发者遗漏的点]
- 建议: [Frame D — 方法或替代方案]
- 开发者驱动: [开发者独立决定的内容]
意图类别: [来自 Layer 02]
信号得分: HIGH
结果: 已实现 | 待定 | 已撤销
若不存在真实分叉 $\rightarrow$ 不写任何内容。绝不要伪造决策。
BUG_FIXING 意图:请使用以下格式:
## [YYYY-MM-DD] <Bug 标题>
根本原因: 导致 Bug 的实际原因 —— 是“为什么”,而不仅仅是“是什么”
症状: 开发者观察到的现象
修复方案: 修改了什么
修复理由: 逻辑依据 —— 若未明确说明,请标注为推断 (inferred)
考虑过的替代修复方案: 讨论过的其他方法(如有)
AI 贡献:
- 识别: [Frame D — Claude 是否发现了根本原因?]
- 建议: [Frame D — 修复方法或诊断步骤]
- 开发者驱动: [开发者独立诊断/决定的内容]
意图类别: BUG_FIXING
信号得分: HIGH
结果: 已修复 | 临时方案 | 推迟处理
创建 session-history/YYYY-MM-DD-HHMM.md:
# 会话 [YYYY-MM-DD HH:MM]
意图: [类别] (次选: [如有,请注明类别])
信号: HIGH
激活帧: A ([得分]) / B ([得分]) / C ([得分]) / D ([得分])
已交付内容
[基于 git log]
已理清的问题
[Frame B + C — 推理、权衡、调试 —— 开发者容易遗忘的部分]
本次会话做出的决策
[引用 DECISIONS.md 中的条目]
困难点
[Frame B 发现的内容 — 不确定性、回滚、EXPLORING/STUCK 信号]
AI 贡献总结
[Frame D 综合分析 — 一段客观且经过校准的描述]
推断的后续步骤
[明显尚未完成的部分]追加至 WORKLOG.md
:YYYY-MM-DD HH:MM | [intent] | HIGH | D:[score] | cache:[hit%]% | tok:[total] | <动词短语> — <重要原因>
字段说明:
D:[score]— Frame D AI 贡献分 (0.0–1.0)
cache:[hit%]%— Token 分析得出的缓存命中率 (若无数据则为cache:n/a)
tok:[total]— 本次会话的总 Token 数 (输入 + 缓存读取 + 缓存创建 + 输出,单位 K,例如45K)
- 动词短语 — 基于 git log 的交付内容
收集 Token 使用情况** (bash — 运行此命令并捕获输出):
python3 -c "
import json, sys
from pathlib import Path
projects = Path.home() / '.claude/projects'
files = sorted(projects.rglob('*.jsonl'), key=lambda f: f.stat().st_mtime, reverse=True)
if not files:
print('no_data'); sys.exit()
with open(files[0]) as fp:
lines = [json.loads(l) for l in fp if l.strip()]
ti = to = cr = cc = 0
turns = []
for i, line in enumerate(lines):
if line.get('type') == 'assistant':
u = line.get('message', {}).get('usage', {})
if not u: continue
inp = u.get('input_tokens', 0)
ti += inp; to += u.get('output_tokens', 0)
cr += u.get('cache_read_input_tokens', 0)
cc += u.get('cache_creation_input_tokens', 0)
prompt = ''
for j in range(i-1, -1, -1):
if lines[j].get('type') == 'user':
c = lines[j].get('message', {}).get('content', '')
prompt = (c if isinstance(c, str) else next((x.get('text','') for x in c if isinstance(x,dict) and x.get('type')=='text'), ''))[:80]
break
turns.append((inp, prompt))
total = ti + cr + cc
hit = cr / total * 100 if total else 0
print(f'input={ti} output={to} cache_read={cr} cache_create={cc} hit={hit:.0f} turns={len(turns)}')
turns.sort(reverse=True)
for idx, (tok, p) in enumerate(turns[:3]):
print(f'top{idx+1}={tok}|{p}')
"
解析输出结果并将 Token 统计数据包含在会话叙述中。然后:
生成 session-history/YYYY-MM-DD-HHMM-proof.html — 编写一个独立的 HTML 文件。结构和类名是固定的 —— 请勿重命名或重新排序章节。
固定 CSS Token (必须精确使用):
- 背景色:
#0d1117, 卡片色:#161b22, 边框色:#30363d
- 字体:
font-family: 'Courier New', monospace
- Frame 分数颜色:
high→#3fb950,low→#f85149, pruned →#8b949e
- AI 行颜色:
ai-identified→#a371f7,ai-suggested→#d29922,ai-developer→#3fb950
固定 HTML 结构 (类名必须完全匹配):
<div class="header">
<div class="header-top">
<div class="project-name">
<span class="badge"> <!-- intent 类 -->
<div class="meta-row"> <!-- 日期, 分支, 信号强度文本 -->
<div class="signal-container">
<div class="signal-label">
<div class="signal-track">
<div class="signal-fill"> <!-- 宽度 % 由信号分数驱动 -->
<div class="section"> <!-- frames -->
<div class="section-title"> ... <span class="count">Layer 02 · ADHD tree-of-thought</span>
<div class="frames-grid">
<div class="frame-card"> <!-- 剪枝状态: class="frame-card pruned" -->
<div class="frame-label"> <!-- Frame A / B / C / D -->
<div class="frame-name">
<div class="frame-score high|low"> <!-- 分数值 -->
<div class="section"> <!-- decisions — 若无则跳过此章节 -->
<div class="section-title"> ... <span class="count">N recorded</span>
<div class="deci
sion-card"> <!-- 每个 DECISIONS.md 条目一个 -->
<div class="decision-header">
<div class="decision-title">
<div class="decision-date">
<div class="decision-fields">
<div class="field-row">
<div class="field-label"> <!-- 上下文 / 决策 / 替代方案 / 推理 -->
<div class="field-value">
<div class="field-row"> <!-- AI 贡献行 -->
<div class="field-label">AI contribution</div>
<div class="field-value">
<div class="ai-block">
<div class="ai-line ai-identified|ai-suggested|ai-developer">
<span class="tag">IDENTIFIED|SUGGESTED|DEV-DRIVEN</span>
<div class="field-row"> <!-- 结果行 -->
<div class="field-label">Outcome</div>
<div class="field-value">
<span class="outcome-badge outcome-implemented|outcome-pending|outcome-reversed">
<div class="section"> <!-- 会话叙述 -->
<div class="section-title">Session narrative</div>
<div class="narrative-grid">
<div class="narrative-card"> <!-- 已交付内容 -->
<div class="narrative-card"> <!-- 已明确的问题 -->
<div class="narrative-card"> <!-- 难点所在 -->
<div class="narrative-card"> <!-- 推断的后续步骤 -->
<div class="section"> <!-- AI 贡献总结 -->
<div class="section-title">AI contribution summary</div>
<div class="narrative-card"> <!-- Frame D 综合段落 -->
<div class="section"> <!-- Token 使用情况 -->
<div class="section-title">Token usage</div>
<div class="narrative-card"> <!-- 缓存命中率条 + 最高轮次 + 优化备注 -->
<div class="section"> <!-- 工作日志尾部 -->
<div class="section-title"> ... <span class="count">最后 N 条记录</span>
<div class="worklog-entry"> <!-- 每条最近的 WORKLOG 行一个 -->
<div class="footer"> <!-- 最后一次提交哈希 · "Generated by collab-proof · 时间戳" -->
使用 bash 编写 HTML:cat > session-history/YYYY-MM-DD-HHMM-proof.html << 'HTMLEOF'
<!DOCTYPE html>
... (包含内联 CSS 的完整 HTML,无外部资源)
HTMLEOF
写入后,显示:open session-history/YYYY-MM-DD-HHMM-proof.html
---
如果信号为 MEDIUM
仅向 WORKLOG.md 追加一行:
YYYY-MM-DD HH:MM | [intent] | MEDIUM | D:[score] | cache:[hit%]% | tok:[total] | <动词短语>
---
如果信号为 LOW
告知用户:"Signal: LOW — Routine session, nothing recorded."(信号:低 —— 常规会话,无需记录。)
---
诚实原则
- 绝不虚构对话中未出现或 diff 中未暗示的决策
- 当推理内容为重构时,使用 "inferred:" 前缀
- Frame D 必须经过校准 —— 既不过度夸大,也不轻视
- 如果所有 Frame 的得分均 < 0.4 → 不写入任何内容
---
PreCompact 快照(上下文压缩防御)
当上下文压缩即将发生时(由 PreCompact 钩子触发),在上下文丢失前运行一个轻量级的会话中期检查点:
1. 根据可用上下文计算当前的 Layer 01 信号级别
2. 根据当前可见内容为所有四个 Frame 打分
3. 将快照写入 session-history/.tmp-TIMESTAMP.json:
{
"timestamp": "YYYY-MM-DD HH:MM:SS",
"trigger": "pre-compact",
"signal": "HIGH / MEDIUM / LOW",
"frames": { "technical": 0.0, "uncertainty": 0.0, "fork": 0.0, "ai_contribution": 0.0 },
"inte
"nt": "FEATURE_BUILDING",
"key_moments": [
"截至目前最重要的决策或发现的一句话描述"
]
}当 /collab-proof 在会话结束时运行时:
- 读取所有
session-history/.tmp-*.json文件
- 合并帧分数(取所有快照中每帧的最大值)
- 合并
key_moments数组 —— 这些数组保留了被压缩掉的权衡讨论
- 合并后删除
.tmp-*.json文件