xngg1021

decision-ledger

Deterministic ledger of decisions and negative results.

xngg1021 1 Updated 1mo ago

Resources

1
GitHub

Install

npx skillscat add xngg1021/academic-research-kernel/decision-ledger

Install via the SkillsCat registry.

SKILL.md

decision-ledger: Research Decision Log (研究决策与失败记录)

Research Decision Log (研究决策与失败记录):记录科研过程中做过什么选择、为什么放弃某条路线、哪些尝试失败、后来为什么改变结论,并把每条记录连接到原始证据(内部内核协议:decision-ledger-1.0,对齐状态变更历史 Primitive 3)。

直接消费与 Claim-Evidence Graph 内核字节兼容的 LineageReceipt 与 AcademicEvidenceReceipt 证据记录契约(schemas/decision-ledger-receipt.schema.json)。纯 Python 标准库实现、零外部大模型依赖、零网络调用。判定结论一律为离散枚举,严禁任何伪置信分与主观数值打分。

When to Use

  • 需要记录研究中的关键选择与路线分叉(探索、采纳、放弃、修正与失败尝试);
  • 需要说明“为什么当初放弃这条路线”:被放弃路线的原因、取代它的决策及依据;
  • 需要把失败尝试与负结果(negative result)正式记录在案,防止重复踩坑;
  • 需要以纯追加事件方式修正历史结论:结论变更按内容与顺序追加新事件,从不原地改写历史。

核心设计纪律

  1. 状态变更历史纯追加 (Event Sourcing):决策、依据、分支、状态事件与结果修正均为不可变记录;生命周期状态(active/pruned/reopened)由追加式状态事件重放派生,结论变化以新的修正事件入账,从不原地改写历史。
  2. 客观离散裁决,不做主观数值打分:无伪置信分、无效用分;裁决为离散枚举(positive/negative/inconclusive/unverifiable),客观记录研究者的选择与证据链。
  3. 失败尝试与负结果必须附带证据:negative_result 决策必须携带至少一条决策依据边(basis_kind="decision");仅由其他负结果支撑的负结果无法通过校验(E405)。
  4. 路线放弃与终止原因明确且严格无环:放弃路线以状态事件入账,记录封闭词表原因(resource_exhausted、superseded、contradicted 等)与主导决策、备选路径;caused_by 因果链严格无环(E304);trace_prune_cause 递归返回完整原因链。
  5. 强类型收据引用与严格互斥:lineage 引用要求 receipt_id 与 receipt_digest;academic_evidence 引用要求 claim_digest 与 payload_sha256;契约与 CEG 内核逐字节兼容。
  6. 物理级收据校验:学术收据负载 SHA256 物理重算断言,注册表键无法绕过哈希校验;谱系收据正向断言协议、收据 ID 与摘要。
  7. 构造期深度冻结与 JSON-domain 失败关闭:所有记录为 frozen dataclass,元数据为 FrozenDict;构造期严厉拦截 NaN/Inf、非字符串键与非法对象;注册收据深拷贝。
  8. 待核实事项清单 (Items Needing Review):decision_without_basis、unsupported_negative_result、missing_receipt、unsupported_pruning 以内容寻址确定性 ID 入队,不阻断结构校验。
  9. 顺序无关内容身份摘要:ledger_digest 只覆盖台账记录(决策、依据、分支、状态事件、修正),本地收据注册表(验证缓存)不进入内容身份;验证态另计 verification_digest。修正与状态事件的 sequence 计数器记录真实追加历史。
  10. 词汇级规范化:NFC 与空白压缩,绝不语义改写决策标题。

Verification

离线冒烟测试:

# smoke-test: true
import os, sys
sys.path.insert(0, os.path.join(os.environ.get('SKILL_DIR', os.getcwd()), 'scripts'))
from ledger import DecisionLedger, ReceiptRef

ledger = DecisionLedger(ledger_id="smoke-dl")

# 决策图谱:探索 → 依据 → 采纳
ledger.add_decision(id="d-explore", title="Try estimator A on corpus X.", decision_type="explore")
ledger.add_decision(id="d-commit", title="Adopt estimator A", decision_type="commit")
ledger.add_basis("d-commit", basis_kind="decision", basis_id="d-explore")
ledger.add_fork("d-commit", "d-explore", relation="considered")

# 负结果:必须携带证据依据,否则校验失败
ledger.add_decision(id="nr-baseline", title="Estimator B fails on long documents", decision_type="negative_result")
ledger.add_basis("nr-baseline", basis_kind="decision", basis_id="d-explore")

# 路线放弃与终止:封闭词表原因 + 主导决策 + 备选路径
ledger.add_decision(id="d-branch-c", title="Branch C: heuristic segmentation")
ledger.set_prune("d-branch-c", status="pruned", prune_reason="resource_exhausted",
                 pruned_by="d-commit", alternative_ref="d-explore")
trace = ledger.trace_prune_cause("d-branch-c")
assert trace["prune_state"]["status"] == "pruned"
assert trace["pruned_by_bases"] and trace["alternative_decision"]["id"] == "d-explore"

# 结果修正:按顺序与内容寻址追加新事件
c1 = ledger.add_outcome_correction("d-explore", verdict="negative", rationale="Did not replicate on held-out data.")
c2 = ledger.add_outcome_correction("d-explore", verdict="negative", rationale="Did not replicate on held-out data.")
assert c1.correction_id == c2.correction_id

# 结构校验与顺序无关摘要
valid, errors = ledger.validate_ledger()
assert valid is True and not errors
d = ledger.to_dict()
assert d["protocol"] == "decision-ledger-1.0"
assert len(d["ledger_digest"]) == 64

# 待核实事项清单:缺依据的负结果进入待核实队列
ledger.add_decision(id="nr-lonely", title="No evidence recorded", decision_type="negative_result")
uncertainties = ledger.export_uncertainties()
assert any(u.kind == "decision_without_basis" and u.needs_human for u in uncertainties)

print("decision-ledger smoke PASS")