深入指南:Source / Claim 账本设计、独立性判定与 v1 迁移实战)
claude-obsidian 证据溯源体系Provenance深入指南Source / Claim 账本设计、独立性判定与 v1 迁移实战【免费下载链接】claude-obsidianSelf-organizing AI second brain for Obsidian Claude Code. Drop any source and Claude reads, links, and files it into one connected knowledge graph of plain Markdown you own. AI note-taking, personal knowledge management (PKM), and an open-source Notion alternative. Based on Karpathys LLM Wiki pattern.项目地址: https://gitcode.com/GitHub_Trending/cl/claude-obsidian导读本文基于仓库 skills/wiki/references/provenance.md 展开系统讲解 claude-obsidian 如何用三个职责分离的账本管理摄入状态、来源证据与论断评估并结合 ledgers.py 源码与 test_ledgers.py 测试用例深入剖析 SHA-256 来源身份、权威性与审查状态枚举、来源新鲜度与独立性的可验证判定以及从旧版.raw/.manifest.json无损迁移到 v1 账本的完整实操流程。读完本文你将掌握如何在 vault 中正确初始化、校验和维护来源账本与论断账本并能安全执行一次经过 dry-run 与人工审查的migrate操作。一、核心原则把三类状态彻底分离provenance.md 开篇就给出了一条总纲Keep ingestion state, source evidence, and claim assessment separate.保持摄入状态、来源证据与论断评估彼此分离。在 claude-obsidian 的架构里这三类状态分别对应三个完全不同的存储对象任何一方都不应该被塞进另外一方职责载体内容摄入状态ingestion state.raw/.manifest.json旧版兼容旧版摄入哈希、生成的页面、地址映射、上次处理结果来源证据source evidencewiki/meta/ledgers/source-ledger.json稳定来源身份、权威性、SHA-256、检索/新鲜度、审查状态、关联页面论断评估claim assessmentwiki/meta/ledgers/claim-ledger.json可证伪论断、笔记位置、支持/矛盾证据、置信度、风险、审查状态provenance.md 特别强调Do not overload one ledger with all three jobs.不要用一个账本承担全部三个职责。这既是可维护性要求也是安全要求——若把来源证据混入摄入清单就无法区分这条记录代表我摄入过某个文件与这个文件是某个论断的证据两种完全不同的语义。在源码层面这套分离由 ledgers.py 中的常量直接固化SOURCE_SCHEMA claude-obsidian.source-ledger.v1 CLAIM_SCHEMA claude-obsidian.claim-ledger.v1 SOURCE_PATH wiki/meta/ledgers/source-ledger.json CLAIM_PATH wiki/meta/ledgers/claim-ledger.json两份账本各有一套独立的 JSON Schema 常量交易层claude-obsidian.transaction.v1bundle在应用写入前会按 test_ledgers.py 的test_transaction_rejects_invalid_provenance_pair所示对这对账本做联合校验无效的accepted论断会以INVALID_PROVENANCE_LEDGER错误整体拒绝绝不落盘。二、解析产品根目录从技能自身位置而非用户工作目录provenance.md 强调一个关键的环境处理规则Resolve the installed product root from the invoking skills own location, not from the user-vault working directory.从调用技能自身的位置解析已安装的产品根目录而不是从用户 vault 的工作目录解析。原因很直接当 Agent 在一个用户 vault 目录里工作时当前工作目录是数据而非代码。如果从这里去查找核心脚本可能找不到、或者找到错误的副本。因此 skills/wiki/SKILL.md 与 provenance.md 都要求用绝对路径定位可移植核心PRODUCT_ROOT/absolute/path/to/installed/claude-obsidian CORE$PRODUCT_ROOT/scripts/claude-obsidian.py test -f $COREtest -f $CORE是一道显式存在性检查如果核心脚本缺失后续任何操作都应当直接失败而不是静默走偏。这与仓库把已安装产品当代码、把用户 vault 当数据的整体约定一致——vault 里只应出现用户数据产品核心永远以绝对路径引用。三、账本体系详解3.1 旧版兼容清单.raw/.manifest.json这是旧版pre-v1摄入流程留下的状态文件记录的内容包括旧版兼容的摄入哈希legacy-compatible ingestion hashes已生成的页面generated pages地址映射address map最后一次处理结果last processing result。一份典型的旧版清单结构见 tests/fixtures/migration/legacy-manifest.json{ version: 1, sources: { .raw/legacy.md: { hash: 975c85ff2a6149ef82c8c8ec75039da1899785771fbf73afaa48f3297fd96e00, ingested_at: 2026-01-02, pages_created: [ wiki/sources/Example Source.md ] } }, address_map: {} }注意这里的hash是旧版的哈希表示不能被当作 SHA-256 直接提升为新账本的内容摘要——这正是迁移逻辑要小心处理的边界见第六节。3.2 来源账本wiki/meta/ledgers/source-ledger.json来源账本为每个来源保存稳定身份 证据属性。provenance.md 列出的要素为stable source identities、authority、SHA-256、retrieval/freshness、review state、linked pages。在 ledgers.py 中来源账本的合法取值被枚举常量锁定SOURCE_KINDS {file, url, manual} CONTENT_KINDS { document, webpage, dataset, image, audio, video, code, conversation, synthetic, other, } AUTHORITIES {official, primary, secondary, community, synthetic, unknown} SOURCE_STATUSES {unreviewed, active, superseded, rejected}一份来源记录source record的字段可以从 test_ledgers.py 的构造示例还原{ origin: {kind: url, locator: https://example.com}, content_kind: webpage, title: X, authority: official, content_sha256: null, ingested_at: null, retrieved_at: 2026-01-01, refresh_due: 2026-02-01, review_status: active, independence_key: example, pages: [], supersedes: null }3.3 论断账本wiki/meta/ledgers/claim-ledger.json论断账本保存可证伪的论断及其证据关系falsifiable claims、note locations、support、contradictions、confidence、risk、review state。论断的取值枚举同样在 ledgers.pyCLAIM_RISKS {normal, high} CLAIM_ASSESSMENTS { accepted, provisional, contested, unsupported, deprecated, } CONFIDENCES {high, medium, low, unknown} EVIDENCE_RELATIONS {supports, contradicts, context}一份论断记录示例源自 test_ledgers.py{ text: A falsifiable claim., location: {path: wiki/A.md, anchor: Claim}, risk: high, assessment: accepted, confidence: high, evidence: [{source_id: src-a, relation: supports, locator: null}], reviewed_at: 2026-07-11, supersedes: null, notes: null }四、Source 规则身份、定位、权威与新鲜度4.1 SHA-256 是新来源身份与增量检查的标准provenance.md 规则Use SHA-256 for new source identity and delta checks.源码中来源 ID 由stable_source_id()函数ledgers.py从来源类型 规范化 locator 内容 SHA-256三者确定性生成def stable_source_id(origin_kind: str, locator: str, content_sha256: str | None) - str: normalized_locator _canonical_locator(origin_kind, locator) digest hashlib.sha256( f{origin_kind.casefold()}\0{normalized_locator}\0{(content_sha256 or ).casefold()}.encode(...) ).hexdigest() return fsrc-{digest[:20]}由此得出几个可验证的推论同一 locator、同一内容哈希必然产生同一src-ID确定性身份内容字节变化SHA-256 变化会产生不同的来源 ID增量检查校验器会强制来源 ID 必须等于该记录的规范身份见validate_source_ledger()中的expected_source_id检查ledgers.py文件来源一旦标记ingested_at就必须携带 SHA-256content_sha256不能为 null见 ledgers.py。测试 test_stable_source_ids 还验证了路径空格、Unicode 组合形式café.mdvscafe\u0301.md会产生不同身份防止把两个不同文件误认为同一来源。4.2 Locator 规则文件相对、远程绝对 HTTPSprovenance.md 规则File locators are vault-relative. Remote locators are absolute HTTPS URLs.校验器对三类 origin 分别把关ledgers.pyfile必须是 vault 相对路径非绝对路径、不含..、不使用反斜杠/控制字符、路径必须规范化url必须是绝对 HTTPSURL带有效主机名、不能带 fragment、不能携带凭据user:password并且会拒绝含敏感查询参数的 URL如X-Amz-Signature、X-Amz-Credential、AWSAccessKeyId等见 test_ledgers.pymanual人工登记来源仅保存身份与关联页面。4.3 权威性authority与审查状态review_status权威性只允许六个取值并且synthetic有强制联动约束ledgers.pyofficial | primary | secondary | community | synthetic | unknown源码约束content_kind synthetic与authority synthetic必须同时声明。也就是说合成内容必须显式自认是合成来源不能伪装成一手来源。审查状态同样枚举锁定unreviewed | active | superseded | rejected并且active状态附加强制要求ledgers.pyactive 来源必须有可审计的retrieved_at或ingested_at日期active 来源必须有显式的refresh_due日期refresh_due不得早于检索/摄入日期active 的文件来源必须真实存在、且哈希与当前文件字节一致test_ledgers.py 的test_active_file_source_must_exist_and_match_its_hash验证了哈希不匹配与文件缺失两种失败路径。4.4 新鲜度从refresh_due计算不存第二个 stale 标志provenance.md 规则Compute staleness fromrefresh_due; do not store a second stale flag.源码提供了统一函数source_is_stale()ledgers.pydef source_is_stale(record, *, as_of): due _iso_date(record.get(refresh_due)) observed _iso_date(record.get(retrieved_at)) or _iso_date(record.get(ingested_at)) return due is None or observed is None or observed as_of or due as_of判定逻辑缺refresh_due、缺检索/摄入日期、观测日期晚于审计日、或到期日早于审计日——任一成立即视为过期。结论是计算出来的而不是字段里存着的这避免了字段与事实不一致的经典数据腐坏问题。4.5 独立性independence_key与规范化 URLprovenance.md 规则Sources sharing anindependence_keydo not count as independent corroboration.Sources that resolve to the same canonical URL origin do not count as independent merely because IPv6, IDN, Unicode, dot-segment, default-port, or percent-encoding spelling differs. Escaped reserved path/query bytes remain distinct.这两条规则在源码中有完整实现。validate_claim_ledger()计算fresh_support新鲜且 active、非 synthetic 的支持证据然后调用_independent_group_count()ledgers.py用并查集把支持证据聚成独立组相同 source ID 归为一组规范化后相同的 originkind locator归为一组相同内容 SHA-256 归为一组即使 URL 不同如镜像站也不算独立相同independence_key按 NFC casefold 规范化归为一组。URL 规范化由_canonical_url()ledgers.py和_canonical_url_host()ledgers.py实现覆盖IPv6 压缩形式、默认端口省略:443、点段解析/a/../doc、百分号编码的非保留字符%64oc、IDN 国际化域名café.example与xn--caf-dma.example、Unicode NFC 规范化等。但保留字节的转义%2Fvs/保持不同因为它们可能指向不同资源。test_ledgers.py 的test_temporal_identity_and_contradiction_rules_fail_closed用大量断言逐一验证了这些规范化等价关系例如canonical stable_source_id(url, https://EXAMPLE.com:443/doc, None) assert canonical stable_source_id(url, https://example.com/doc, None) assert canonical stable_source_id(url, https://example.com/a/../doc, None) assert canonical stable_source_id(url, https://example.com/%64oc, None) assert stable_source_id(url, https://example.com/a%2Fb, None) ! \ stable_source_id(url, https://example.com/a/b, None)测试 test_independence_cannot_override_duplicate_origin_or_content 则证明即使两条来源声明了不同的independence_key只要 origin 或内容字节相同高风险的accepted论断依然会因为不足两个独立来源而被拒绝。五、Claim 规则可证伪、可追溯、诚实失败5.1 五种评估状态accepted | provisional | contested | unsupported | deprecated5.2 accepted 的硬性门槛Accepted 论断至少需要一个新鲜的、active 的、非 synthetic 来源fresh, active, non-synthetic。高风险highaccepted 论断需要两个独立来源two independent sources。这两条在 ledgers.py 中被严格实现fresh_support [ (source_id, source) for source_id, source in supporting if _source_origin_is_valid(source) and source.get(review_status) active and source.get(authority) ! synthetic and source.get(content_kind) ! synthetic and not source_is_stale(source, as_oftoday) and reviewed_date is not None and source_date is not None and source_date reviewed_date ] if assessment accepted and not fresh_support: _error(errors, f{prefix}.assessment, accepted claims require fresh active support) if (assessment accepted and risk high and _independent_group_count(fresh_support) 2): _error(errors, f{prefix}.evidence, high-risk acceptance requires two independent sources)注意时间维度的细节支持证据的来源观测日期retrieved/ingested不得晚于论断的reviewed_at——即评审时该证据必须已存在。同时accepted论断强制要求reviewed_at为 ISO 日期ledgers.py。5.3 保留矛盾证据不静默选边provenance.md 规则Preserve contradictory evidence. Do not silently select a winner.源码将其落地为三条强制约束accepted论断若存在新鲜矛盾证据contradicts则必须有 adjudication notes 或改为contestedledgers.pycontested论断必须有矛盾证据或 notes 支撑ledgers.py证据关系枚举只有supports/contradicts/context三种且每条证据的source_id必须能解析到来源账本中的记录ledgers.py。测试 test_claim_acceptance_requires_fresh_independent_support 验证单一来源 重复来源 被拒/合成来源都不会让高风险的accepted通过只有加入真正独立的第二来源后才通过校验。5.4 unsupported 是规范的无数据状态unsupportedis the canonical no-data state. A grounded refusal is better than confident invention.unsupported是规范的无数据状态。有依据的拒绝比自信的捏造更好。这意味着一份论断在没有任何证据时评估状态应当是unsupported而不是accepted或留空。这与 skills/wiki/SKILL.md 中Unsupported evidence stays unsupported; never invent a source, quote, date, locator, or confidence不支持的证据保持不支持绝不编造来源、引文、日期、定位符或置信度完全一致。5.5 锚点与位置的可验证性论断的位置不是自由文本location.path必须是规范化的wiki/相对路径location.anchor可选必须是页面中真实存在的标题或块 ID。校验器会用_markdown_anchor_sets()ledgers.py解析页面实际标题与^block-id并剔除 frontmatter、代码块与 HTML 注释中的假锚点。测试 test_code_and_comment_examples_are_not_claim_anchors 专门验证了这一点。5.6 绝不虚构provenance.md 收尾规则Never fabricate quotations, page numbers, dates, or evidence locators.绝不虚构引文、页码、日期或证据定位符。这是整套证据体系的行为底线也是迁移逻辑诚实默认honest defaults设计思想的来源。六、旧版迁移Migration实战先 dry-run再 apply6.1 命令形态与 CLI 参数provenance.md 给出的标准迁移流程两步走python3 $CORE migrate --vault VAULT \ --generated-at ISO-UTC --operation-id migrate-reviewed python3 $CORE migrate --vault VAULT \ --generated-at ISO-UTC --operation-id migrate-reviewed \ --approved-plan-sha256 reviewed-sha256 --apply第一步生成迁移计划dry-run第二步在人工审查计划、拿到approved_plan_sha256之后才真正应用。CLI 侧的参数定义见 cli.py参数说明--vault PATH目标 vault也支持环境变量与配置文件选择解析顺序见 skills/wiki/SKILL.md--generated-at ISO-UTC固定的 ISO UTC 时间戳用于可复现迁移缺省自动取当前 UTC--operation-id操作 ID用于交易记录与审计缺省由时间戳派生migration-...--apply应用计划默认是 dry-run必须显式传入才执行写入--approved-plan-sha256人工审查后批准的计划哈希apply阶段校验计划未漂移command_migrate()的实现cli.py逻辑是先构建migration_bundle若writes为空则输出status: noop直接返回否则非--apply时输出claude-obsidian.migration-plan.v1含 operation 与 changed_paths--apply时调用apply_bundle(root, operation, approved_plan_sha256approval)执行事务化应用。整套流程与仓库一次逻辑操作 一个被检查且可恢复的交易 bundle的变更契约skills/wiki/references/operation-transactions.md一致。6.2 迁移语义无损、诚实、不臆测provenance.md 对迁移行为给出了严格定义源码实现于migrate_legacy_manifest()ledgers.py与migration_bundle()ledgers.py.raw/.manifest.json字节级不变迁移是纯新增additive对旧文件只读不写。test_migration_preserves_manifest_and_is_idempotent 用legacy_path.read_bytes() before断言验证并验证重复迁移writes []幂等。只创建缺失的账本source-ledger.json、claim-ledger.json以及.claude-obsidian.jsonworkspace v1仅在不存在时创建已存在的规范文件是用户/vault 状态迁移绝不覆盖或刷新ledgers.py。诚实的默认值新记录authority: unknown、review_status: unreviewed、content_sha256为实际计算的 SHA-256文件来源或null无 payload 的手工来源。绝不从旧版 prose 自动抽取论断claim 账本初始为空claims[claims] {}旧版文本里的论断不会被机器猜测为 claim。6.3 文件来源 vs 手工来源的判定迁移对每个旧版来源键的处理规则ledgers.py旧版来源键解析为常规文件→ 保持文件来源origin.kind filecontent_sha256为现场计算的 SHA-256旧版来源键无对应文件→ 保留为unreviewed的手工来源origin.kind manualauthority: unknown、content_sha256: null、content_kind: other。provenance.md 强调这种未解析记录保留旧版身份、日期与页面链接但绝不证明批次到文件的关系。迁移不会枚举 raw payloads 去发明这种关系也不会把旧版短哈希提升为 SHA-256test_migration_preserves_unresolved_legacy_batch_as_manual_source断言52ffa724ac942c32 not in json.dumps(sources)。实现上还通过守卫测试保证迁移进程不得枚举.raw下的原始 payload 目录测试在listdir/scandir上注入守卫一旦枚举即抛AssertionError见 test_ledgers.py。6.4 apply 的失败条件fail-closedprovenance.md 规则Apply fails if an unresolved label appears, becomes unsafe, cannot be inspected, or if a file source changes after review.即应用阶段若出现以下任一情况整个迁移事务失败回滚审查后某个未解析标签batch label突然出现了对应文件→ 原批准计划manual 来源与新事实file 来源不一致抛出READ_PRECONDITION_MISMATCH见 test_migration_plan_changes_if_batch_locator_appears_before_applylocator 位置变成不安全节点目录、符号链接、断链、socket→ 拒绝并回滚test_migration_original_plan_rejects_unsafe_locator_state_changeslocator 变得不可检查如权限被拒→ 抛出UNSAFE_READ_PRECONDITIONtest_migration_original_plan_rejects_uninspectable_locator文件来源内容在审查后发生变化锁定后的前置条件复查发现漂移→ 抛出READ_PRECONDITION_MISMATCH并整体回滚test_migration_locked_recheck_rolls_back_and_allows_clean_retry。交易实现还会拒绝符号链接的旧清单防止把清单重定向到 vault 外、拒绝重复 JSON 键、拒绝畸形清单记录与非法 Unicode 路径全部 fail-closed见 test_ledgers.py 一系列用例。一旦失败回滚修复条件后可以带着相同的批准哈希干净重试——这正是可恢复交易设计的价值所在。七、与周边机制的配合provenance.md 不是孤立文档它与 skills/wiki/SKILL.md 的变更契约配套使用任何自定义 scaffold 或变更前先读 operation-transactions.md一次逻辑操作必须产出一个被检查、可恢复的claude-obsidian.transaction.v1bundle初始化或修改来源/论断账本时遵循 provenance.md 的规则unsupported证据保持unsupported绝不发明来源、引文、日期、定位符或置信度每次成功 apply 后报告 operation ID 与精确变更路径如需 Git 检查点单独执行python3 $CORE checkpoint OPERATION_ID --vault /absolute/path/to/vault在 README.md 中这套机制被描述为Ground every important claim. Source and claim ledgers retain authority, research, and rollups share one provenance-aware model——即所有重要论断都要有据可查研究、检索与汇总共享同一套溯源感知模型。README.md 也对migrate命令做了对应说明Add v1 ledgers and configuration without rewriting legacy data只增加 v1 账本与配置不重写旧数据。八、最佳实践清单综合 provenance.md 规则与源码实现在 claude-obsidian 中维护证据溯源体系时应遵守三账本分离摄入状态.raw/.manifest.json、来源证据source-ledger.json、论断评估claim-ledger.json各司其职禁止混装。绝对路径解析核心从技能安装位置解析$CORE并用test -f $CORE显式确认绝不从用户 vault 工作目录猜路径。身份用 SHA-256新来源身份与增量检查统一使用 SHA-256文件来源一旦摄入必须有 64 位十六进制小写哈希。locator 规范化文件 locator 一律 vault 相对远程 locator 一律绝对 HTTPS禁 fragment、禁凭据、禁敏感查询参数。枚举不越界authority、review_status、assessment、confidence、risk、relation全部使用枚举取值synthetic内容与synthetic权威必须同真同假。新鲜度只算不存过期与否一律从refresh_due与观测日期计算不维护冗余 stale 标志。独立性从严同independence_key、同规范 origin、同内容字节都不构成独立佐证高风险的 accepted 论断必须有 ≥2 个独立来源。矛盾不掩盖保留矛盾证据accepted 新鲜矛盾必须有 adjudication notes否则改为contested。诚实默认无数据即unsupported迁移时未知字段一律诚实默认unknown/unreviewed/null绝不自动从旧文抽取论断、绝不提升旧短哈希、绝不枚举 raw payload 臆造批次关系。迁移先审后施先 dry-run 拿到approved_plan_sha256审查 changed_paths 后再--apply任何前置条件漂移都会事务化回滚修复后可安全重试。这套以可证伪、可追溯、可审计为核心的证据溯源体系让 claude-obsidian 的知识库在 AI 生成内容之外保留了一条从论断到原始来源的完整证据链——这正是它区别于普通笔记工具的关键能力所在。【免费下载链接】claude-obsidianSelf-organizing AI second brain for Obsidian Claude Code. Drop any source and Claude reads, links, and files it into one connected knowledge graph of plain Markdown you own. AI note-taking, personal knowledge management (PKM), and an open-source Notion alternative. Based on Karpathys LLM Wiki pattern.项目地址: https://gitcode.com/GitHub_Trending/cl/claude-obsidian创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考