Current guidance · concepts baseline 0.2.0-preview.1
Reconciliation
How do I resolve UNKNOWN?
Architecture view
Reconciliation with zero redispatch
Live reconciliation and durable recovery are separate authority paths that converge only on verifier read-back.
1 · Live reconciliation
2 · Runtime durable recovery verifier-only rehydration
3 · Shared verifier-only path
Original UNKNOWN remains immutable. Observation-only UNKNOWN claims remain historical.
Read diagram as text
- Live pathExact identity-bound UNKNOWN, same Runtime, one-shot authority, and optional LiveReconciliationClaimPlan.
- Durable path after process lossClosed DurableRecoveryRecordV2, accepted recovery authority, stable verifier registration, and optional RecoveryClaimPlan.
- Verifier-only authoritative readBoth paths use independent read-back with zero provider redispatch.
- Classify a new related resultRuntime/Core receives the verifier observation before COMMITTED / DISPROVED / UNKNOWN.
- Keep UNKNOWN authority historicalRELATED_LIVE_RECONCILIATION_OBSERVATION_ONLY and RELATED_RECOVERY_OBSERVATION_ONLY never assert current truth.
Protected limits: Original UNKNOWN is immutable. Reconciliation and recovery perform zero provider redispatches. REHYDRATION_REQUIRED needs a host-retained v2 record and recovery authority.
Reconciliation checks authoritative state after an earlier attempt ended UNKNOWN. It uses the original operation binding and a verifier read, never another provider dispatch. It produces a new related result and leaves the original UNKNOWN unchanged.
Required live authority
The application needs the exact Actions-owned UNKNOWN result object and registered verifier capability from the same ProtectedActionRuntime instance.
import type { ProtectedActionResult, ProtectedActionRuntime } from '@answerup/actions';
// Preserve and pass the exact object returned by runtime.run().
export function reconcile(runtime: ProtectedActionRuntime, initial: ProtectedActionResult) {
if (initial.kind !== 'UNKNOWN') throw new Error('not live-reconcilable');
return runtime.reconcile(initial, { claimPlan: {
propositions: {
COMMITTED: { propositionRef: 'effect:committed' },
DISPROVED: { propositionRef: 'effect:did-not-occur' },
UNKNOWN: { propositionRef: 'live-observation:unresolved' },
},
} });
}LiveReconciliationClaimPlan is optional and supplied when reconciliation is requested. It is a bounded data-only set of three mutually exclusive alternatives. The verifier establishes authoritative truth first; Runtime selects only the matching proposition and Core evaluates that exact proposition. The one-argument path remains a proposition-specific, fail-closed compatibility behavior.
Process-local exact-result boundary
The live reconciliation authority is private, process-local, identity-bound, and one-shot. Clones, spreads, reconstructed objects, serialized values, cross-instance results, terminal results, and already-consumed results do not carry it. A process restart ends the association. Logs and provider request IDs may help an operator identify the case, but they cannot recreate live authority. The formal boundary is IN_PROCESS_ONLY; the result is not a durable restart mechanism.
Durable verifier-only rehydration after process loss
After process loss, REHYDRATION_REQUIRED means that live authority is unavailable. Runtime durable recovery supports a separate host-operated verifier-only flow when the host retains a closed DurableRecoveryRecordV2, supplies accepted recovery authority, and keeps the stable registered verifier binding. Rehydration validates the source-record digest and CAS/provenance semantics before authoritative read-back of the original effect; it is not cloning, deserialization, execution, retry, or redispatch. It does not reconstruct the live association and cannot authorize mutation. Recovery does not happen automatically after restart. The live and durable paths are not interchangeable.
The preferred durable input includes a complete RecoveryClaimPlan: common subject and attributes plus mutually exclusive COMMITTED, DISPROVED, and UNKNOWN propositions. Recovered truth is established before the matching proposition is selected for Core evaluation. The legacy single-claim overload remains an outcome-specific compatibility path. The evidence-bound outcome is a related COMMITTED, DISPROVED, or another UNKNOWN transition. A related live UNKNOWN may carry the next one-shot association, while durable UNKNOWN may yield the next version-2 recovery record. The host owns persistence, routing, verifier registration, authority controls, required leases or fencing, scheduling, monitoring, and bounded delivery. This is not automatic or AnswerUp-hosted recovery, exactly-once execution, universal restart handling, or universal or production-grade durability.
If a plan’s live UNKNOWN branch is permitted, RELATED_LIVE_RECONCILIATION_OBSERVATION_ONLY says only that the exact live observation was unresolved. For durable recovery, RELATED_RECOVERY_OBSERVATION_ONLY says the same only about the exact accepted recovery observation. Neither is current-state, retry, redispatch, compensation, or future-state authority.
Possible results
The verifier compares the authoritative read with the original binding:
PRESENTproduces a new relatedCOMMITTEDresult.ABSENT_FINALproduces a new relatedDISPROVEDresult.INDETERMINATEproduces another relatedUNKNOWNresult.
The original UNKNOWN remains immutable in every case. Reconciliation is not retry, compensation, replay, or a new proposal, and it performs zero provider redispatch.
Example: provisioning contractor access
An administrative application sends an authenticated backend an authorization-approved access request. An identity-provider adapter attempts the change, the provider response is lost, and the request may already have crossed the provider boundary. The application must not grant access again or tell the contractor that access is active.
While the exact in-memory UNKNOWN remains available, a separate directory verifier reads the authoritative identity directory. PRESENT, ABSENT_FINAL, or INDETERMINATE determines the new related result. If the process has restarted, the host cannot reconstruct live authority; it can instead use durable verifier-only rehydration only from its retained closed v2 recovery record through accepted recovery authority and stable verifier registration.
Application and Core responsibilities
Core validates exact live reconciliation authority or the accepted durable recovery authority, invokes the registered verifier through the protected lifecycle, binds the read to the original operation, produces a bounded related result, and enforces zero provider redispatch.
The application decides when reconciliation is requested, controls operator display, retains approved bounded correlation information and closed recovery records, defines retention and escalation, and handles cases where live reconciliation is unavailable. Core does not schedule polling, operate a queue, or manufacture durable authority.
An application may retain bounded operation, effect, execution, and attempt identifiers for audit and support. Those records identify the case but do not confer live reconciliation authority.
Reconciliation versus a new action
Reconciliation asks what happened to the original attempt. A retry or compensation is a separate new proposed action, requiring fresh grounding and authorization. Core does not choose or automatically execute that new action.