Continuity & Temporal Correctness · Steps 35–37Chapter 36 of 45

Is Your Agent Acting on Stale State? Build Temporal Consistency, Freshness Budgets and Conflict Detection

Page content

A preserved state is not necessarily a valid state.

That is the next problem.

Step 35 gave us portable execution state.

We can checkpoint an agent run.

We can move it between workers.

We can preserve:

  • the behavioral release,
  • observations,
  • search state,
  • verifier evidence,
  • budgets,
  • side-effect lineage,
  • ownership,
  • authority context.

That solves continuity.

It does not solve time.

A run can resume perfectly from an old checkpoint and still be wrong because the world changed while it was paused.

The repository changed.

The pull request was merged.

The production deployment advanced.

The browser session expired.

The page contents changed.

The approval expired.

The queue drained.

The dependency recovered.

The price changed.

The schema migrated.

A human edited the document.

Another agent committed first.

The verifier was upgraded.

The agent’s checkpoint may be internally consistent and externally obsolete.

That is a temporal-consistency problem.

The core rule for this post is:

Before a consequential action, validate that every state assumption the action depends on is still fresh enough for that action.

Not every observation needs to be live.

Not every stale value matters.

But the system must know which assumptions are time-sensitive, which versions they were derived from, what changed, and whether that change invalidates the next action.


The Search Problem: “AI Agent Acting on Stale Data”

A common agent implementation works approximately like this:

observe
plan
think for a while
act

That picture hides a dangerous assumption:

state at observation time
      ==
state at action time

For short read-only tasks, that may be acceptable.

For long-running agents, distributed workers, browser automation, coding systems, DevOps agents, financial workflows, database operations, and any task that crosses an approval boundary, it is often false.

Imagine a coding agent.

At 13:00 it reads:

main = commit A

It plans a patch.

At 13:04 another developer merges commit B.

At 13:07 the agent applies its patch assuming A is still the base.

Nothing about the patch itself has to be irrational.

The failure is temporal.

The agent reasoned from a state that was no longer authoritative.

Or imagine a browser agent.

At 10:10 it observes:

cart total = €240
shipping = €0
recipient = Alice

At 10:12 the website recalculates shipping and the total becomes €279.

At 10:14 a human approves the purchase based on the earlier summary.

At 10:15 the agent clicks Buy.

If the system does not revalidate the state bound to that approval, it can execute a materially different transaction from the one that was approved.

This is not a language-model problem.

It is a state-validity problem.


1. Freshness Is Not One Number

Teams often model freshness as:

age = now - observed_at

Then they choose a TTL.

That is useful for caches.

It is not enough for an agent.

Two observations can both be ten minutes old and have completely different safety implications.

README text observed 10 minutes ago

may still be perfectly adequate for answering a historical documentation question.

But:

current branch head observed 10 minutes ago

may be unusable for committing code.

Likewise:

weather forecast observed 10 minutes ago

may be fine for casual planning.

But:

authorization token observed 10 minutes ago

may already be invalid.

Freshness therefore needs at least three dimensions:

age
change sensitivity
consequence of being stale

A useful representation is:

from dataclasses import dataclass
from enum import Enum


class FreshnessClass(str, Enum):
    IMMUTABLE = "immutable"
    SNAPSHOT = "snapshot"
    BOUNDED = "bounded"
    EVENT_SENSITIVE = "event_sensitive"
    MUST_BE_CURRENT = "must_be_current"


@dataclass(frozen=True)
class StateObservation:
    state_key: str
    value_hash: str
    observed_at: str
    source_version: str | None
    freshness_class: FreshnessClass
    max_age_seconds: int | None
    authority: str

The point is not the enum names.

The point is to force the system to say what kind of freshness guarantee a piece of state requires.


2. Separate Observation Time From Decision Time From Commit Time

An advanced agent usually has several temporal boundaries:

observation time
planning time
selection time
approval time
commit time
postcondition verification time

These are not interchangeable.

Suppose the agent observes a repository at version A.

It produces candidate C against A.

A verifier confirms C against A.

A reviewer approves C against A.

Then main moves to B.

At commit time, the system must not reason:

candidate C passed verification
therefore commit C

The stronger statement is:

candidate C passed verification
against repository version A

If the current mutation target is now B, the verification claim may no longer apply.

This gives us a general rule:

Evidence is valid only relative to the state identity against which it was produced.


3. Give Authoritative State an Identity

If a state can affect correctness, the runtime should avoid representing it only as mutable prose.

Prefer explicit identities.

For a repository:

repo_head_sha
workspace_tree_hash
lockfile_hash
configuration_hash

For a database:

row_version
transaction_snapshot
schema_version
logical_sequence_number

For a browser workflow:

page_version or response ETag
session_id
cart_version
form_state_hash
server-side transaction token

For an external API:

resource_version
ETag
updated_at
operation status version

For agent policy:

authority_policy_version
placement_policy_version
verifier_bundle_version
behavioral_release_id

The runtime can then bind decisions to state explicitly:

@dataclass(frozen=True)
class StateDependency:
    state_key: str
    observed_version: str
    required_freshness: FreshnessClass
    role: str

A plan is no longer merely:

"update the deployment"

It becomes:

update deployment
assuming:
  deployment_version = 42
  policy_version = auth-v7
  manifest_hash = abc123
  verifier_bundle = verify-v12

That is much easier to validate before mutation.


4. State Version Vectors

Long-running tasks rarely depend on one mutable object.

A coding run may depend on:

repository head
package lockfile
CI configuration
issue state
PR state
review state
policy version

A DevOps run may depend on:

deployment revision
service health
traffic split
config version
secret version
schema version
region health

Representing these as one opaque “context version” loses useful structure.

Instead, maintain a state-version vector:

@dataclass(frozen=True)
class StateVersionVector:
    versions: dict[str, str]

Example:

{
  "repo:main": "a81d9f...",
  "issue:417": "rev-8",
  "policy:authority": "v7",
  "verifier:code": "v12",
  "tool:github-schema": "v4"
}

Before a consequential action, read the current vector for the required keys.

Then compare:

observed vector
       vs
current vector

But do not automatically reject every difference.

A changed issue comment may be irrelevant to the exact patch.

A changed repository head may be critical.

That leads to dependency-aware conflict detection.


5. Not Every Change Is a Conflict

This is where naive optimistic concurrency becomes too blunt.

Suppose an agent edits:

src/payments/retry.py

Meanwhile another developer changes:

docs/README.md

The repository head changed.

But the change may not invalidate the agent’s patch.

Conversely, another developer could change:

src/payments/base.py

without touching the same file, yet still invalidate assumptions about the retry implementation.

So conflict detection should operate at multiple levels.

Level 1: Exact identity conflict

The object itself changed.

same row
same file
same form
same cart
same deployment object

Level 2: Declared dependency conflict

A dependency used by the plan changed.

imported module
schema
configuration
API contract
policy
verifier

Level 3: Semantic conflict

The bytes may differ in a way that changes the meaning of the pending action.

This is harder.

Use deterministic dependency information wherever available before asking a model.

For coding agents:

imports
call graph
symbol references
build graph
test dependencies

For databases:

foreign keys
schema dependencies
transaction predicates

For deployment systems:

service dependency graph
config dependencies
traffic policy

For browser workflows:

server-issued version tokens
cart IDs
transaction IDs
form hidden fields

The important idea is:

A changed world does not automatically require replanning. A changed dependency might.


6. Use Optimistic Concurrency at Mutation Boundaries

One of the strongest deterministic protections is compare-and-set.

Instead of:

update_resource(new_value)

prefer:

update_resource(
    new_value,
    expected_version=observed_version,
)

The mutation succeeds only if the resource is still the version the agent reasoned about.

Equivalent mechanisms include:

  • SQL row versions,
  • If-Match with ETags,
  • compare-and-swap,
  • Git commit ancestry checks,
  • Kubernetes resourceVersion,
  • conditional object-store writes,
  • fenced transaction epochs.

This creates a crucial boundary:

model believes state is current
mutation gateway proves state is current

The gateway wins.


7. Freshness Budgets

Step 16 introduced compute budgets.

Step 27 introduced reliability budgets.

Long-running agents also need freshness budgets.

A freshness budget answers:

How stale may this state become before the next action
must refresh or revalidate it?

Example:

@dataclass(frozen=True)
class FreshnessRequirement:
    state_key: str
    max_age_seconds: int | None
    require_same_version: bool
    refresh_before_authorization: bool
    refresh_before_commit: bool

For a coding task:

repository head
  require same version before applying patch

issue description
  refresh before final response if mutable

static source snapshot
  snapshot semantics acceptable during analysis

For a purchase workflow:

product description
  bounded freshness

price
  refresh before approval

recipient
  exact identity before commit

total amount
  exact identity before commit

The freshness budget should be tied to consequence.

A read-only summary can tolerate more staleness than a production mutation.


8. Action-Specific Freshness

This is a subtle but important refinement.

Freshness is not just a property of state.

It is a relationship between state and action.

The same observation may be fresh enough for one action and stale for another.

Example:

repository snapshot from 20 minutes ago

may be adequate for:

explain architecture

but inadequate for:

commit patch to main

Therefore the decision should look like:

is_fresh_enough(
    observation=repo_snapshot,
    action="commit_patch",
    risk_class="production_mutation",
)

not merely:

is_fresh(repo_snapshot)

9. Snapshot Consistency vs Live Consistency

There are two legitimate strategies for long-running reasoning.

Strategy A: Stable snapshot

Freeze the relevant world state.

snapshot A
reason entirely against A
produce candidate for A

This is ideal for:

  • code analysis in a worktree,
  • offline data processing,
  • deterministic benchmark runs,
  • document analysis,
  • reproducible research.

Strategy B: Live consistency

Continuously or periodically refresh external state.

observe
reason
refresh
update plan
act

This is needed for:

  • active browser sessions,
  • deployment control,
  • market or inventory state,
  • dynamic queues,
  • collaborative documents,
  • multi-actor systems.

The mistake is to accidentally mix the two.

A system that claims snapshot semantics but silently performs live reads creates an incoherent state model.

A system that claims live semantics but never refreshes is simply stale.

Make the consistency mode explicit.


10. Revalidation Is Not Always Replanning

When state changes, the runtime has several choices.

state unchanged
    → continue

state changed but irrelevant
    → continue with updated evidence

state changed but candidate still valid
    → reverify

state changed and assumptions invalid
    → replan

state changed and safe continuation impossible
    → abort / escalate

This gives us useful outcomes:

FRESH
REFRESHED
REVERIFY_REQUIRED
REPLAN_REQUIRED
STALE_STATE
CONFLICT
ABORT_REQUIRED

Do not collapse all changes into “start over.”

But also do not preserve a plan merely because recomputing it is expensive.


11. Bind Plans to Preconditions

A plan should carry explicit preconditions.

@dataclass(frozen=True)
class ActionPrecondition:
    state_key: str
    expected_version: str | None
    predicate: str
    on_failure: str

Example:

Action: merge PR

Preconditions:
- PR head == 94d6...
- required checks == PASS
- approval count >= 1
- approval artifact hash == current diff hash
- base branch == expected base
- authority token not expired

At commit time, these conditions are evaluated against authoritative state.

That is much stronger than asking the agent:

“Are you sure nothing changed?”


12. Revalidate Human Approval

Step 29 made human approval a bound authorization artifact.

Temporal consistency adds another rule:

Approval is valid only while the approved object and relevant context remain within the approval’s validity envelope.

Suppose a reviewer approves:

patch_hash = abc123

Then the agent modifies the patch.

The approval no longer applies.

Suppose the approved amount was:

€240

and the final charge is:

€279

The approval no longer applies.

Suppose the deployment target changes from staging to production.

The approval no longer applies.

A good approval artifact therefore contains:

approved artifact identity
scope
authority class
relevant state versions
expiry
reviewer identity
policy version

Before commit:

approval artifact
revalidate target state
match?
 ├─ yes → continue
 └─ no  → approval invalidated

13. Repository Drift

Coding agents make temporal consistency easy to visualize.

A robust coding workflow might look like:

checkout base SHA A
create isolated worktree
edit against A
run tests against candidate C/A
verify
fetch current target branch B
compare A → B
rebase/reapply if safe
rerun impacted verification
conditional push / PR update

The important point is that:

tests passed on A

does not imply:

tests would pass on B

A branch update is a new state transition.

If the patch is rebased, the candidate artifact identity changes.

Therefore previous verifier evidence may need to be invalidated.


14. Detect Semantic Repository Conflicts

Textual merge success is not enough.

Consider:

agent edits retry.py
human edits timeout.py

Git may merge cleanly.

But if retry.py assumes a timeout constant that changed, the patch may now be wrong.

Use repository intelligence when available:

changed symbols
reverse dependencies
affected tests
required revalidation

This is where structural graphs become operationally valuable.

The agent does not need to reread the entire repository every time.

It needs to determine whether the changed state intersects the dependency cone of the pending action.


15. Browser State Is Especially Fragile

Browser agents often reason over ephemeral state:

  • DOM elements,
  • hidden form fields,
  • CSRF tokens,
  • carts,
  • session cookies,
  • dynamic prices,
  • availability,
  • seat selections,
  • transaction IDs.

A screenshot from five minutes ago is not a transaction precondition.

A good browser action should bind to server-observable identity when possible.

Example:

observed cart_id = 731
observed total = 24000 cents
observed currency = EUR
observed recipient_id = user-17

Before purchase:

GET authoritative cart state
compare exact purchase-critical fields
if mismatch → reapproval or abort

This is stronger than asking the model whether the page “looks the same.”


16. External APIs Need Conditional Mutation

If an API exposes resource versions or ETags, use them.

Example:

GET /resource/42
ETag: "v17"

Then:

PUT /resource/42
If-Match: "v17"

If the current resource is now v18, the mutation fails safely.

The agent then receives:

CONFLICT

and can refresh/replan.

This pattern turns a race condition into an explicit control-flow branch.

That is exactly what we want.


17. Database Agents and Predicate Drift

Database work introduces a harder class of staleness.

A transaction may depend not only on exact rows but on a predicate.

Example:

SELECT * FROM jobs
WHERE status = 'READY'
AND priority > 80;

The agent chooses a set of jobs.

Before mutation, new rows may appear that also satisfy the predicate.

Whether that matters depends on task semantics.

This is the classic distinction between:

object identity

and:

predicate identity

For consequential database agents, use native transactional guarantees when possible rather than rebuilding isolation in prompt logic.

The model should not simulate serializable transactions in natural language.


18. Policy Drift

The world that can become stale includes internal control policy.

Suppose a run starts under:

authority_policy = v12

During the run, an incident causes the platform to publish:

authority_policy = v13

with lower autonomous mutation limits.

A long-running run must not continue under the old policy merely because it started earlier.

This requires distinguishing state categories:

run-pinned state

from:

must-use-current control state

Behavioral release may be pinned for reproducibility.

Security and authority policy may require current-state enforcement.

Do not assume all versions should be frozen together.


19. Verifier Drift

Step 23 already established that verifier behavior can drift.

Temporal consistency adds a runtime question:

was this candidate verified under a verifier
that is still accepted for this authority class?

Suppose candidate C passed verifier bundle V7.

Then V7 is withdrawn after a false-PASS incident.

The run must not retain the old PASS as indefinitely valid evidence.

The platform may require:

reverify C under V8

before consequential action.

This means verifier evidence has both:

artifact binding

and:

policy validity

20. Freshness and Competence

Step 30 introduced competence envelopes.

A competence claim is also conditional on state regime.

An agent may be validated for:

static repository maintenance

but not for:

high-churn collaborative repository mutation

The difference is not necessarily model intelligence.

It is operational context.

Therefore the task descriptor used for competence checks can include:

expected state churn
number of concurrent actors
required consistency level
availability of versioned state
reversibility

A highly dynamic environment may push a task outside the validated competence envelope even if the domain itself is familiar.


21. Freshness and Authority

Authority should tighten as freshness guarantees weaken.

Example:

fresh authoritative state + strong verifier
    → autonomous reversible mutation may be allowed

bounded-stale state + good verifier
    → proposal only

unknown state age + weak verifier
    → human review / defer

known conflicting state
    → no mutation

This is not because stale information is always wrong.

It is because the platform has less evidence that the pending action still refers to the world that currently exists.


22. Freshness and Expected Value of Information

Step 18 introduced Expected Value of Information.

Refreshing state is an information purchase.

The agent should not refetch everything continuously.

That can be expensive and can itself create load.

Instead ask:

Which state refresh is most likely to change
my next decision or invalidate my next action?

For a coding agent about to commit:

refresh repo head

may have high value.

Refreshing an unrelated documentation page may have almost none.

For a browser agent about to purchase:

refresh final total and recipient

has very high value.

Refreshing product marketing text does not.

This produces targeted revalidation rather than indiscriminate polling.


23. Change Notifications Beat Polling When Available

Some systems expose events:

repository webhook
resource watch
change-data capture
queue event
calendar update
filesystem watcher
policy publication event

These can invalidate assumptions immediately.

Architecture:

state observation
register dependency
subscribe to relevant change stream
change event arrives
mark dependent plan/candidate evidence stale

But event delivery is not always perfect.

So event invalidation usually complements, rather than completely replaces, commit-time version checks.


24. Invalidation Graphs

Step 33 introduced capability dependency graphs.

Temporal consistency benefits from a smaller runtime graph:

observation
derived fact
plan step
candidate
verifier evidence
approval
mutation

If an observation changes, traverse downstream dependencies.

Example:

repo_head changed
workspace base invalidated
candidate compatibility uncertain
verifier evidence stale
approval stale

The graph lets the runtime invalidate only what actually depended on the changed state.

This avoids both extremes:

ignore all changes

and:

restart entire run on every change

25. Do Not Let the Model Decide What Is Authoritative

This principle recurs throughout the series because it matters.

A model can suggest:

"I think the repository probably hasn't changed."

That is not a state check.

A model can say:

"The price looked the same in the screenshot."

That is not transaction validation.

A model can say:

"The approval should still be valid."

That is not authorization.

Whenever the runtime has access to authoritative version/state mechanisms, use them deterministically.

The model may interpret semantic conflicts after exact facts are gathered.

It should not replace the facts.


26. A Temporal Consistency Gate

A minimal deterministic gate might look like this:

from dataclasses import dataclass
from enum import Enum


class TemporalDecision(str, Enum):
    CONTINUE = "continue"
    REFRESH = "refresh"
    REVERIFY = "reverify"
    REPLAN = "replan"
    CONFLICT = "conflict"
    ABORT = "abort"


@dataclass(frozen=True)
class RequiredState:
    key: str
    observed_version: str | None
    current_version: str | None
    require_same_version: bool
    materially_changed: bool
    critical: bool


def evaluate_temporal_state(states: list[RequiredState]) -> TemporalDecision:
    for state in states:
        if state.critical and state.current_version is None:
            return TemporalDecision.ABORT

        if state.require_same_version:
            if state.observed_version != state.current_version:
                return TemporalDecision.CONFLICT

        if state.materially_changed:
            return TemporalDecision.REPLAN

    return TemporalDecision.CONTINUE

Production logic will be richer.

But notice what this function does not contain:

LLM confidence

Exact version conflicts do not need probabilistic reasoning.


27. Revalidation Before Side Effects

The most important temporal checkpoint is usually immediately before irreversible or externally visible mutation.

A safe pattern is:

prepare candidate
verify candidate
obtain authorization if needed
refresh mutation-critical state
check versions/preconditions
reverify if state changed
commit conditionally
verify postcondition

This is deliberately repetitive.

The system is spending extra work exactly where stale assumptions are most expensive.


28. Postcondition Verification Detects Races You Did Not Predict

Even strong preconditions do not eliminate all ambiguity.

External systems can fail strangely.

The request can time out after being applied.

Another process can race after your check.

An API can violate assumptions.

Therefore:

precondition check
proof of final state

After mutation, query authoritative state again.

Example:

intended deployment revision = R42
commit
read deployment state
actual revision == R42 ?

If not:

UNKNOWN
CONFLICT
PARTIAL_EFFECT

may be more accurate than PASS.


29. Staleness Can Propagate Through Memory

Memory systems make temporal consistency harder.

Suppose episodic memory stores:

"Service A uses endpoint X"

Six months later, endpoint X is retired.

The memory may still be semantically coherent and factually stale.

Memory therefore needs provenance and temporal scope:

@dataclass(frozen=True)
class MemoryFact:
    fact: str
    source_id: str
    observed_at: str
    source_version: str | None
    valid_until: str | None
    refresh_policy: str

Do not treat memory as timeless truth.

Memory is evidence with lineage.


30. Retrieval Results Need Freshness Semantics Too

A retrieval index is a snapshot of some corpus.

If the corpus changes, retrieval can become stale even when the index is healthy.

Track:

corpus snapshot
index version
retriever version
source update time
selected chunk hash

A research agent answering:

What was the policy in 2025?

may deliberately use an old snapshot.

The same snapshot is inappropriate for:

What is the current policy?

Freshness depends on the query’s temporal semantics.


31. Long-Running Research Agents Need Claim Freshness

A research agent may gather evidence over hours or days.

Some claims are stable:

paper publication date
historical event
mathematical definition

Others are volatile:

current CEO
latest software version
current price
breaking news
live election results

Attach freshness requirements to claims.

Before finalizing a report, refresh only volatile claims whose age exceeds their allowed budget.

This is much more efficient than rerunning the entire research pipeline.


32. Temporal Conflicts in Multi-Agent Systems

Multi-agent systems create another problem:

Agent A observes state S0
Agent B observes state S0

Agent A acts → state S1
Agent B still plans against S0

Without versioned state, Agent B may overwrite or contradict Agent A.

The solution is not necessarily for agents to debate.

It is often ordinary concurrency control:

shared state versions
leases
conditional writes
fencing
idempotency
transaction boundaries

The agents can coordinate semantically after the infrastructure prevents stale mutation.


33. Conflict Resolution Must Not Invent Merge Semantics

When a conflict occurs, the system may be tempted to ask the model:

"Please merge these two states."

That is sometimes valid for text.

It is dangerous for arbitrary state.

Different systems have different merge semantics.

source code
calendar events
financial transactions
configuration
access-control lists
inventory
orders

may require completely different rules.

Use domain-native merge/reconciliation mechanisms when available.

Treat model-assisted semantic merge as a candidate transformation that still requires deterministic validation and verification.


34. Freshness Debt

Long-running systems can accumulate freshness debt.

Imagine a run with 30 observations.

Ten have expired freshness budgets.

Five have unknown source versions.

Three depend on a withdrawn verifier.

Two approvals expired.

At that point, incremental refreshing may be more expensive and less trustworthy than rebuilding the plan from a new snapshot.

Define a threshold where:

refresh debt too high
REPLAN_REQUIRED

This resembles technical debt in miniature: continuing from too many stale assumptions creates increasing reconciliation cost.


35. Replanning Must Preserve Useful Work Carefully

REPLAN_REQUIRED does not mean discard everything.

Some artifacts remain valid:

  • immutable source evidence,
  • historical observations,
  • failed candidate evidence,
  • verified invariant checks,
  • search branches unrelated to changed state.

Other artifacts must be invalidated:

  • candidate patches bound to old state,
  • approvals for old artifact hashes,
  • verifier PASS tied to invalid candidates,
  • tool plans using obsolete schemas.

This again argues for explicit provenance edges.

Without lineage, the runtime cannot know what stale state contaminated.


36. Time Is Part of the Task Specification

A surprisingly large class of agent failures comes from underspecified temporal intent.

Compare:

Who is the CEO?

with:

Who was the CEO in January 2024?

Compare:

What dependencies does this repository use?

with:

What dependencies did commit A use?

The first requires current/live semantics.

The second requires historical snapshot semantics.

The runtime should preserve that distinction explicitly.

A task descriptor can include:

@dataclass(frozen=True)
class TemporalIntent:
    mode: str  # current | historical | snapshot | bounded_stale
    as_of: str | None
    max_staleness_seconds: int | None

This prevents the agent from silently answering a current-state question with historical evidence.


37. Freshness Must Survive Handoff

Step 35 made execution state portable.

A checkpoint should therefore preserve:

observed_at
source version
freshness class
freshness budget
invalidation state

When the target worker resumes:

checkpoint age
re-evaluate freshness requirements
refresh/reverify/replan as needed

Migration time itself consumes freshness budget.

That sounds obvious, but it is easy to miss when checkpoint recovery is focused only on serialization correctness.


38. Do Not Reset Freshness on Deserialization

A particularly bad implementation would do this:

observation captured at 13:00
checkpoint resumed at 14:00
runtime reconstructs object at 14:00

and then treats the object as:

observed_at = 14:00

That launders stale evidence into fresh evidence.

Preserve original observation time.

A restored object is not a newly observed object.


39. Timeouts Are Not Freshness Proofs

A timeout can tell you that something is too old according to policy.

It cannot tell you whether something actually changed.

Likewise, a recent observation can still be obsolete if a change event happened immediately afterward.

Therefore combine:

age-based invalidation
version-based invalidation
event-based invalidation
precondition checks

according to the available system guarantees.


40. Clock Assumptions Matter

Distributed systems have clock skew.

For most agent freshness decisions, wall-clock timestamps are useful but should not be the only consistency primitive.

Prefer authoritative versions and monotonic sequence values where available.

Use timestamps for:

age
expiry
observability
human understanding

Use versions/epochs for:

identity
ordering
fencing
conditional mutation

This prevents subtle bugs where two machines disagree slightly about time.


41. Freshness of Secrets and Credentials

Credentials are state too.

A checkpoint may refer to a capability token that has since expired or been revoked.

Never serialize long-lived authority merely to make resume easier.

On resume:

checkpoint authority requirement
current policy
current worker identity
issue fresh scoped capability if allowed

If current authority cannot be reconstructed:

AUTHORITY_UNAVAILABLE

is safer than reusing stale credentials.


42. Temporal Consistency for Caches

Caching can create enormous efficiency gains.

It can also preserve obsolete truth.

A cache key should include the identity of mutable inputs that affect correctness.

Bad:

cache_key = hash(prompt)

Better:

cache_key = hash(
    prompt,
    model_version,
    repository_snapshot,
    policy_version,
    tool_schema_version,
)

For live-data questions, the cache also needs a freshness policy.

A model response about immutable source code at commit A can be reused indefinitely for A if all other inputs match.

A model response about current production health cannot.


43. Freshness-Aware Prompt Caching

This is especially useful for local-model systems.

Repeated analysis against the same immutable file or repository snapshot should be reusable.

But the cache should express why reuse is valid:

same exact content hash
same question/prompt version
same model version
same relevant context

Then cache reuse is evidence-preserving.

Do not invalidate immutable work merely because wall-clock time passed.

Likewise, do not retain mutable-state answers merely because their prompt text is identical.


44. Temporal Consistency and Cost

Revalidation costs money and time.

So there is a genuine trade-off:

refresh too often
    → high latency and cost

refresh too rarely
    → stale-state failures

That makes freshness policy another optimization surface.

But, as throughout this series:

hard correctness constraints first
optimization second

For high-consequence mutation-critical state, exact precondition checking should not be traded away to save a few milliseconds.

For low-risk read-only context, bounded staleness may be entirely rational.


45. Measure Stale-State Failures Separately

Do not hide temporal failures inside generic “agent failed” metrics.

Track at least:

stale observation rate
commit-time conflict rate
revalidation rate
replan rate
stale approval invalidation rate
reverification rate
state-version mismatch rate
stale cache hit prevention
conflict rescue rate
false stale alarm rate
freshness-related false PASS rate

This lets you answer:

Are we refreshing too much?
Are we refreshing too little?
Which state classes cause incidents?
Which tools lack useful version semantics?

46. Add Temporal Events to the Trajectory

Step 13 established trajectory observability.

Add events such as:

state_observed
freshness_budget_assigned
state_invalidated
state_refreshed
version_conflict_detected
reverification_requested
replan_requested
approval_invalidated
conditional_commit_rejected
postcondition_conflict

Each event should carry:

run_id
state_key
old_version
new_version
reason
affected artifact IDs
action taken
policy version

This makes temporal failures visible in incident forensics.


47. Connect Temporal Consistency to Incident Forensics

Step 26 asked:

Where did the run first diverge?

Temporal provenance lets us answer a stronger question:

At what point did an assumption become stale,
and what downstream decisions continued to rely on it?

Example:

13:00 repo A observed
13:02 plan created
13:04 repo changed to B
13:05 invalidation event missed
13:07 candidate verified against A
13:10 commit attempted against B

The root cause may be:

missing invalidation / precondition enforcement

not:

bad model generation

48. Failure Injection for Temporal Consistency

Temporal logic is exactly the kind of thing that looks correct until concurrency happens.

Test it deliberately.

Repository

  • move target branch after planning,
  • alter imported symbol without touching edited file,
  • change lockfile after candidate generation,
  • invalidate approval by changing diff,
  • merge competing PR before commit.

Browser

  • price changes after approval,
  • session expires,
  • selected item becomes unavailable,
  • recipient changes,
  • CSRF token rotates,
  • page refresh changes hidden transaction identifier.

DevOps

  • deployment revision changes during diagnosis,
  • policy tightens during run,
  • region health flips,
  • verifier bundle is withdrawn,
  • secret version rotates.

Distributed workers

  • old worker resumes after handoff,
  • checkpoint waits long enough to exceed freshness budget,
  • change event is dropped,
  • clocks disagree,
  • target worker receives stale cache entry.

The expected result should be deterministic where possible:

CONFLICT
REVERIFY_REQUIRED
REPLAN_REQUIRED
AUTHORITY_INVALIDATED
STALE_STATE

not silent continuation.


49. Benchmark the Freshness Policy

Compare at least:

no revalidation
fixed global TTL
refresh everything before action
dependency-aware freshness policy

Measure:

verified success
false success
stale-state incidents
latency
external calls
cost
replans
false conflict rate
human escalations

A sophisticated temporal-consistency system must earn its complexity.

For some workloads, a simple immutable snapshot plus commit-time compare-and-set may beat an elaborate live invalidation graph.

Use the simplest mechanism that satisfies the actual consistency requirement.


50. A Practical Temporal State Model

A production-oriented DTO might look like:

from dataclasses import dataclass
from typing import Literal


@dataclass(frozen=True)
class TemporalStateRef:
    state_key: str
    source_uri: str
    observed_at: str
    observed_version: str | None
    value_hash: str | None
    freshness_mode: Literal[
        "immutable",
        "snapshot",
        "bounded",
        "event_sensitive",
        "must_be_current",
    ]
    max_age_seconds: int | None
    authority: str


@dataclass(frozen=True)
class TemporalDependency:
    consumer_artifact_id: str
    state_key: str
    dependency_kind: Literal[
        "input",
        "precondition",
        "verification",
        "authorization",
        "commit",
    ]
    on_change: Literal[
        "ignore",
        "refresh",
        "reverify",
        "replan",
        "abort",
    ]

This makes temporal semantics inspectable rather than hidden in orchestration code.


51. A Commit-Time Consistency Protocol

A generic consequential-action protocol can be:

1. identify mutation-critical state dependencies
2. fetch current authoritative versions
3. compare against observed versions
4. classify changes
5. invalidate dependent evidence where necessary
6. refresh/reverify/replan
7. validate current authority
8. perform conditional/fenced mutation
9. read authoritative postcondition
10. record final state versions

Notice what is absent:

"ask the model if it still seems okay"

The model may help at Step 4 for semantic change classification when exact dependency rules are insufficient.

But the surrounding control structure remains deterministic.


52. When the Correct Answer Is STALE_STATE

Agent systems often treat inability to continue as failure.

That creates pressure to improvise.

Instead, support explicit outcomes:

STALE_STATE
CONFLICT
REVERIFY_REQUIRED
REPLAN_REQUIRED
AUTHORITY_INVALIDATED
DEPENDENCY_CHANGED

These are not embarrassing states.

They are evidence that the control plane noticed the world had changed.

A system that says:

I cannot safely commit because the target state changed

is more reliable than one that confidently executes against obsolete assumptions.


53. What This Adds to the Architecture

We now have a stronger runtime chain:

Task
Competence check
Authority decision
Placement
Observe authoritative state
Build state-version dependencies
Plan / search / execute candidate work
Verify
Freshness + conflict gate
Reverify / replan if needed
Conditional fenced commit
Postcondition verification
Trajectory + provenance update

This is much closer to how reliable distributed systems work than the classic agent loop:

think → act → observe

The loop is still there.

But it now operates inside explicit state, authority, consistency, and verification boundaries.


54. The Larger Principle

The deeper lesson is not about timestamps.

It is about assumption ownership.

An agent plan is a bundle of assumptions about the world.

Those assumptions may have been correct when the plan was formed.

As time passes, the runtime must know:

which assumptions can change
which did change
which downstream artifacts depend on them
which evidence is therefore invalid
and what must happen before authority is exercised

That is temporal consistency for agent systems.

The model does not get to declare the world unchanged.

The infrastructure proves enough continuity for the next action—or it refuses to proceed.


Final Rule

If you remember one thing from this post, make it this:

Before a consequential action, validate that every state assumption the action depends on is still fresh enough for that action.

A preserved checkpoint is not proof of a preserved world.

A previous PASS is not proof of current validity.

A previous approval is not permission for a changed artifact.

A recent observation is not necessarily authoritative.

And a fluent agent should never be allowed to turn stale state into fresh authority by assertion.

The runtime must make time visible.

Only then can a long-running agent know when to continue, refresh, reverify, replan—or stop.


Next: Coordinating Long-Running Intent

Temporal consistency tells us when the world has changed underneath a run.

But long-running systems have another problem.

The goal itself can change.

A user can change priorities.

A ticket can be closed.

A deployment can be cancelled.

A human can supersede an earlier request.

A higher-priority policy can invalidate work that is still technically executable.

The next step is therefore not more freshness checking.

It is intent supersession and cancellation semantics:

Which instruction is currently authoritative?
Which older work has been superseded?
What should be cancelled?
What can be safely reused?
Which side effects are already committed?

That gives us the next principle:

State can become stale, but so can intent.