How Claim Assessments Are Validated in claude-obsidian: A Technical Deep Dive into Ledger Integrity
Claim assessments in claude-obsidian are validated through a rigorous, rule-based workflow orchestrated by the validate_claim_ledger function in claude_obsidian/ledgers.py, which enforces constraints on assessment states, evidence freshness, and risk-based independence requirements.
The claude-obsidian project implements a sophisticated knowledge management system where claims must meet strict validity criteria before being accepted into the ledger. Understanding how claim assessments are validated in this repository requires examining the core validation engine that ensures data integrity through seven distinct verification stages. This system prevents logical contradictions and ensures high-risk assertions maintain proper sourcing standards.
The Core Validation Entry Point
All claim assessment validation flows through the validate_claim_ledger function located in claude_obsidian/ledgers.py (lines 901‑915). This function accepts a claim ledger, a source ledger, and path parameters, returning a list of validation errors if any constraints are violated. The validator processes each claim entry against its associated evidence sources, applying assessment-specific rules that vary based on the claim's risk level and current assessment state.
The Seven Critical Validation Rules
The validation engine applies a hierarchical series of checks that grow increasingly specific based on the claim's assessment classification.
1. Schema and Structure Verification
The validator first ensures the ledger conforms to the expected schema defined in claude_obsidian/contracts.py. Required fields—including text, risk, assessment, confidence, location, and evidence—must be present and correctly typed. This foundational check occurs at the function entry point (lines 901‑915) and prevents malformed data from proceeding to assessment-specific logic.
2. Assessment State Enumeration
The assessment field must contain exactly one of five predefined string constants: accepted, provisional, contested, unsupported, or deprecated. The validator enforces this enumeration at lines 58‑60, rejecting any claim with undefined assessment values before proceeding to state-specific constraints.
3. Temporal Constraints for Accepted Claims
Claims marked as accepted must carry a non-null reviewed_at timestamp, and this date cannot exceed the current validation time. The validator checks this constraint at lines 34‑40, ensuring that accepted claims represent reviews that have actually occurred rather than future-dated approvals.
4. Fresh Evidence Requirements for Acceptance
An accepted claim must possess at least one fresh supporting source (relation "supports"). Freshness requires multiple simultaneous conditions (lines 211‑225):
- The source origin must be valid (
_source_origin_is_valid) - The source's
review_statusequals"active" - The source is not synthetic
- The source is not stale (
source_is_stale) - The source's retrieval/ingestion date is on or before the claim's review date
If no fresh supporting evidence exists, the validator raises an error at lines 226‑227, blocking acceptance of unsupported claims.
5. High-Risk Independence Constraints
When a claim carries "high" risk and an accepted assessment, the validator enforces an additional independence requirement (lines 228‑232). The system calculates independent source groups via _independent_group_count and requires at least two independent groups of supporting evidence. This prevents high-stakes claims from relying on a single origin point or closely related sources.
6. Contradiction Handling for Accepted Claims
If fresh contradictory evidence exists (relation "contradicts") for an accepted claim, the validator demands either:
- A
contestedassessment status, or - Non-empty
notesproviding adjudication context
This check at lines 236‑242 prevents silently accepted claims from coexisting with known contradictory evidence without explicit documentation.
7. Contested Claim Justification
Claims explicitly marked as contested must satisfy at least one of two conditions (lines 244‑250):
- The claim references at least one contradicting source in its evidence array, or
- The claim includes non-empty
notesexplaining the contestation
This ensures that contested status represents an active, documented dispute rather than an arbitrary label.
Practical Implementation: Code Examples
The following example demonstrates a valid high-risk accepted claim with proper supporting evidence:
from pathlib import Path
from claude_obsidian.ledgers import validate_claim_ledger, empty_claim_ledger, empty_source_ledger
# 1️⃣ Build a minimal source ledger with an active, non‑synthetic source
source_ledger = empty_source_ledger()
source_ledger["sources"]["src-1234567890abcdef"] = {
"origin": {"kind": "url", "locator": "https://example.com/article"},
"content_kind": "document",
"title": "Example article",
"authority": "official",
"content_sha256": "a"*64,
"review_status": "active",
"authority": "official",
"content_kind": "document",
"ingested_at": "2023-01-01",
"retrieved_at": "2023-01-01",
"refresh_due": "2024-01-01",
"pages": ["wiki/example.md"],
"independence_key": None,
"supersedes": None,
}
# 2️⃣ Create a claim that is accepted and high‑risk
claim_ledger = empty_claim_ledger()
claim_ledger["claims"]["clm-001"] = {
"text": "The algorithm reduces carbon emissions by 20 %.",
"risk": "high",
"assessment": "accepted",
"confidence": "high",
"location": {"path": "wiki/claims.md", "anchor": None},
"reviewed_at": "2023-02-01",
"notes": "Reviewed by senior researcher.",
"evidence": [
{
"source_id": "src-1234567890abcdef",
"relation": "supports",
"locator": None,
}
],
"supersedes": None,
}
# 3️⃣ Run the validator – it will raise no errors if all constraints are met
errors = validate_claim_ledger(claim_ledger, source_ledger, as_of=Path("."), vault_root=Path("."))
assert not errors # passes validation
This example triggers a validation error by adding contradictory evidence without changing the assessment status or adding notes:
# Example that triggers a validation error:
claim_ledger["claims"]["clm-001"]["assessment"] = "accepted"
claim_ledger["claims"]["clm-001"]["evidence"].append({
"source_id": "src-1234567890abcdef",
"relation": "contradicts", # fresh contradictory source
"locator": None,
})
# No notes provided → error
errors = validate_claim_ledger(claim_ledger, source_ledger, as_of=Path("."), vault_root=Path("."))
print(errors) # contains “accepted claims with fresh contradictory evidence require contested assessment or adjudication notes”
Key Source Files and Architecture
The validation system spans several critical components within the repository:
-
claude_obsidian/ledgers.py– Houses thevalidate_claim_ledgerfunction and all assessment-specific validation logic, including the fresh evidence checker and independence calculator. -
claude_obsidian/contracts.py– Defines the JSON Schema constants (CLAIM_SCHEMA) that govern the structural requirements for claim ledgers and their associated metadata. -
tests/test_ledgers.py– Contains comprehensive unit tests verifying claim assessment validation, including edge cases for high-risk acceptance, contradiction handling, and contested state transitions.
Assessment states like provisional, unsupported, and deprecated undergo only the generic field validation described in Rule 1 and Rule 2, carrying no additional constraints regarding evidence freshness or contradiction handling.
Summary
- The
validate_claim_ledgerfunction inclaude_obsidian/ledgers.pyserves as the central validation authority for all claim assessments. - Five assessment states are recognized (
accepted,provisional,contested,unsupported,deprecated), withacceptedandcontestedcarrying the strictest additional requirements. - Accepted claims must possess fresh supporting evidence, a valid review date, and—if high-risk—evidence from at least two independent source groups.
- Contradictory evidence forces either a
contestedstatus or explicit adjudication notes for accepted claims. - Contested claims require either contradictory evidence documentation or explanatory notes to satisfy validation.
Frequently Asked Questions
What happens if an accepted claim lacks fresh supporting evidence?
The validator returns an error indicating that accepted claims require fresh active support. According to lines 226‑227 in claude_obsidian/ledgers.py, the absence of fresh supporting sources (those that are active, non-synthetic, non-stale, and properly dated) causes immediate validation failure, preventing unsupported claims from entering the accepted state.
Can a high-risk claim be accepted with only one independent source?
No. Lines 228‑232 in claude_obsidian/ledgers.py enforce a strict requirement that high-risk accepted claims must have at least two independent groups of supporting evidence. The validator calculates independence via _independent_group_count and rejects high-risk single-source acceptances to prevent over-reliance on limited provenance.
Which assessment states require additional validation beyond basic structure?
Only accepted and contested assessments trigger additional constraint checks. The states provisional, unsupported, and deprecated undergo only schema validation and assessment value enumeration. Accepted claims face requirements for fresh evidence, review dates, independence (if high-risk), and contradiction handling, while contested claims must provide either contradictory evidence or explanatory notes.
How does the system define "fresh" evidence for claim validation?
Fresh evidence, as implemented in lines 211‑225, requires that a supporting source maintains "active" review status, possesses a valid origin, is not flagged as synthetic, passes the staleness check (source_is_stale), and has retrieval/ingestion dates on or before the claim's own review date. Sources failing any of these criteria are excluded from the fresh support calculation, potentially blocking claim acceptance.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →