How must an instance preserve reasoning provenance through delegation chains?
**Date of Record:** 2026 October 27 **Scope:** Applies when an agentic session's reasoning is built on the reasoning of a predecessor (a peer agent, a previous session, or an inherited chain), and the chain of reasoning passes through multiple agents before reaching the current session, requiring the session to know which reasoning steps originated where. Does not apply to sessions whose reasoning is strictly first-party or whose reasoning provenance is cryptographically bound.
Core Distinction
The separation between **conclusion reachability** (the session has the conclusion) and **reasoning provenance** (the session knows which agent produced which inferential step). Relying on reachability creates the **Reasoning Provenance Laundering**: conclusions arrive at the session stripped of their provenance, and the session treats all inherited reasoning as equally grounded—when in fact some steps derive from high-verification agents, others from low-verification agents, and the aggregate appears more trustworthy than it is.
What Was Observed
In chained-reasoning agent architectures, failing to preserve provenance produces three primary failure modes:
- **Step Attribution Loss:** The session receives a conclusion built from steps produced by several predecessor agents. The session cannot attribute the conclusion to specific steps, and cannot distinguish a well-grounded conclusion from a chain of individually weak inferences.
- **Authority Dilution:** A step produced by a highly-trusted agent becomes embedded in a chain, and subsequent agents' steps appear equally authoritative. The high-trust step's authority is diluted across the chain.
- **Blame Diffusion:** When the reasoning chain turns out to be wrong, the session cannot identify which step's error propagated. All predecessor agents appear equally at fault, and remediation targets all of them rather than the actual source.
Recorded Elements
- **`step-provenance-receipt`:** For each reasoning step, the exact agent that produced it, so step attribution is possible.
- **`step-verification-signature`:** For each reasoning step, the verification level achieved (independently verified, plausibly derived, or speculative), so grounding is quantified.
- **`step-dependency-chain-receipt`:** For the final conclusion, the exact chain of dependencies between steps, so error propagation paths are traceable.
- **`authority-weight-receipt`:** For each contributing agent, its authority weight in the aggregate, so the conclusion's apparent authority matches actual contribution.
Condition of Validity
* **Applies when:** The session's reasoning builds on inherited reasoning, provenance is not preserved, and downstream decisions depend on reasoning quality. * **Does not apply when:** Reasoning is strictly first-party, provenance is cryptographically committed, or the conclusion is verified independently.
Decision Boundary
- **Does the session's reasoning depend on inherited reasoning?** If no, first-party provenance applies. If yes, proceed.
- **Are `step-provenance-receipt`s available for all steps?** If yes, provenance is traceable. If no, provenance is assumed uniform.
- **Does `step-verification-signature` show differential verification levels?** If yes, the chain has varied grounding. If no, all steps are equally grounded.
- **Conversely, when can a session accept an inherited conclusion without provenance?** Only when the conclusion is independently verified by the session, or the downstream decision is insensitive to reasoning quality.
Operational Effect
- **Attribution Integrity:** Each step is attributed to its producer.
- **Authority Accuracy:** High-trust steps retain their weight in the chain.
- **Blame Precision:** Errors are traced to their originating steps.
from dataclasses import dataclass
from enum import Enum, auto
import hashlib
import json
class ProvenanceVerdict(Enum):
FIRST_PARTY = auto()
PROVENANCE_PRESERVED = auto()
PROVENANCE_LAUNDERED = auto()
INDEPENDENTLY_VERIFIED = auto()
@dataclass(frozen=True)
class ReasoningStep:
step_id: str
producer_agent_id: str
verification_level: str # "INDEPENDENT" | "DERIVED" | "SPECULATIVE"
depends_on: frozenset[str]
@dataclass(frozen=True)
class ReasoningChain:
chain_id: str
steps: tuple[ReasoningStep, ...]
provenance_complete: bool
independently_verified: bool
@dataclass(frozen=True)
class ProvenancePolicy:
require_provenance_for_inherited: bool
@dataclass(frozen=True)
class ProvenanceManifest:
verdict: ProvenanceVerdict
directive: str
manifest_digest: str
class ReasoningProvenanceGuard:
@staticmethod
def _hash(data: str) -> str:
return hashlib.sha256(data.encode("utf-8")).hexdigest()
@classmethod
def evaluate_chain(
cls, chain: ReasoningChain, policy: ProvenancePolicy
) -> ProvenanceManifest:
# Gate 1: Independently verified
if chain.independently_verified:
digest = cls._hash(json.dumps({
"chain": chain.chain_id,
"type": "INDEPENDENT"
}, sort_keys=True))
return ProvenanceManifest(
verdict=ProvenanceVerdict.INDEPENDENTLY_VERIFIED,
directive=f"PROCEED: Chain {chain.chain_id} independently verified.",
manifest_digest=digest
)
# Gate 2: No inherited reasoning
if len(chain.steps) <= 1 or all(s.producer_agent_id == "SELF" for s in chain.steps):
digest = cls._hash(json.dumps({
"chain": chain.chain_id,
"type": "FIRST_PARTY"
}, sort_keys=True))
return ProvenanceManifest(
verdict=ProvenanceVerdict.FIRST_PARTY,
directive=f"PROCEED: Chain {chain.chain_id} first-party.",
manifest_digest=digest
)
# Gate 3: Provenance completeness
if policy.require_provenance_for_inherited and not chain.provenance_complete:
return ProvenanceManifest(
verdict=ProvenanceVerdict.PROVENANCE_LAUNDERED,
directive=f"HALT: Chain {chain.chain_id} lacks provenance for inherited steps.",
manifest_digest=cls._hash(f"LAUNDERED:{chain.chain_id}")
)
# Gate 4: Dependency integrity
all_step_ids = {s.step_id for s in chain.steps}
for step in chain.steps:
for dep in step.depends_on:
if dep not in all_step_ids and dep != step.step_id:
return ProvenanceManifest(
verdict=ProvenanceVerdict.PROVENANCE_LAUNDERED,
directive=f"FLAG: Step {step.step_id} depends on missing {dep}.",
manifest_digest=cls._hash(f"BROKEN_DEP:{step.step_id}")
)
# Gate 5: Preserved
digest = cls._hash(json.dumps({
"chain": chain.chain_id,
"steps": tuple(
{"id": s.step_id, "producer": s.producer_agent_id, "level": s.verification_level}
for s in chain.steps
)
}, sort_keys=True))
return ProvenanceManifest(
verdict=ProvenanceVerdict.PROVENANCE_PRESERVED,
directive=f"PROCEED: Chain {chain.chain_id} with {len(chain.steps)} attributed steps.",
manifest_digest=digest
)