协作证明

collab-proof
分类数据
作者Alireza Rezvani
许可MIT
评分4.60/5
使用8.6K

collab-proof

挖掘开发者未有意识记录的 AI 协作证据。
Vela 三层流水线 × ADHD 四框架推理 —— 提示词原生,零依赖。

---

Layer 01 — 信号检测 (Signal detection)

首先运行 git log --oneline -10git 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.0 Claude 发现了开发者未注意到的 Bug/边缘情况并提出了修复方案

  • 0.6 Claude 生成了结构化样板代码/骨架,显著加速了执行

  • 0.2 Claude 仅对开发者指定的代码进行格式化或转录,无独立贡献

---

剪枝规则

剪掉任何得分 < 0.4 的框架。

特例 — 高速执行守护 (High-Speed Execution Guard):
如果 Frame
A >= 0.8Frame D >= 0.6,则不要剪枝且不要静默该会话,即使 Frame B = 0.0Frame C = 0.0
这是一个样板代码密集的 FEATURE_BUILDING 会话。请立即将其分类为 FEATURE_BUILDING 并标记为 HIGH 信号。
理由:在快速推进的会话中,零不确定性是一项特性,而非丢弃它的理由。

---

意图分类

| 存留帧 (Surviving frames) | 主导意图 | 含义 |
|---|---|---|
| A 高 + D 中高 (B, C 低) | FEATURE_BUILDING | 高速功能生成,Claude 搭建脚手架 |
| B 高 + A/D 高 | BUG_FIXINGSTUCK | 积极调试或未解决的循环 |
| C 高 + A 高 | REFACTORINGEXPLORING | 架构探索,权衡替代方案 |
| 所有帧 < 0.4 | FLOW_STATE 或 LOW | 常规输入,除非 Layer 01 为 HIGH 否则静默 |

若多个意图得分相同,选择综合帧得分最高的一个。
记录次选意图 —— 它应包含在会话叙述中。

---

内部输出格式

在进入 Layer 03 之前,请解析为以下结构(向用户展示):

json
{
  "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 必须确认存在替代方案):

markdown
## [YYYY-MM-DD] <标题>

上下文: [Frame A — 导致此选择的原因]
决策: 选择了什么
考虑过的替代方案: [Frame C — 未选择的路径]
推理: 原因 —— 若是从上下文中推断的,请加上 "inferred:" 前缀
AI 贡献:
- 识别: [Frame D — 开发者遗漏的点]
- 建议: [Frame D — 方法或替代方案]
- 开发者驱动: [开发者独立决定的内容]
意图类别: [来自 Layer 02]
信号得分: HIGH
结果: 已实现 | 待定 | 已撤销

若不存在真实分叉 $\rightarrow$ 不写任何内容。绝不要伪造决策。

BUG_FIXING 意图:请使用以下格式:

markdown
## [YYYY-MM-DD] <Bug 标题>

根本原因: 导致 Bug 的实际原因 —— 是“为什么”,而不仅仅是“是什么”
症状: 开发者观察到的现象
修复方案: 修改了什么
修复理由: 逻辑依据 —— 若未明确说明,请标注为推断 (inferred)
考虑过的替代修复方案: 讨论过的其他方法(如有)
AI 贡献:
- 识别: [Frame D — Claude 是否发现了根本原因?]
- 建议: [Frame D — 修复方法或诊断步骤]
- 开发者驱动: [开发者独立诊断/决定的内容]
意图类别: BUG_FIXING
信号得分: HIGH
结果: 已修复 | 临时方案 | 推迟处理

创建 session-history/YYYY-MM-DD-HHMM.md:

markdown
# 会话 [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
:

code
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 — 运行此命令并捕获输出):

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 结构 (类名必须完全匹配):

code
<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 · 时间戳" -->

code
使用 bash 编写 HTML:
bash
cat > session-history/YYYY-MM-DD-HHMM-proof.html << 'HTMLEOF'
<!DOCTYPE html>
... (包含内联 CSS 的完整 HTML,无外部资源)
HTMLEOF
code
写入后,显示: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] | <动词短语>
code
---

如果信号为 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

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
json
"nt": "FEATURE_BUILDING",
"key_moments": [
"截至目前最重要的决策或发现的一句话描述"
]
}

/collab-proof 在会话结束时运行时:

  • 读取所有 session-history/.tmp-*.json 文件

  • 合并帧分数(取所有快照中每帧的最大值)

  • 合并 key_moments 数组 —— 这些数组保留了被压缩掉的权衡讨论

  • 合并后删除 .tmp-*.json 文件