Current guidance · concepts baseline 0.2.0-preview.1
Safe claims
What may I say about an outcome?
Authoritative verification establishes effect truth. Core derives a bounded claim permission for the exact operation and identity scope. The application chooses wording within that permission. The formal claim types are EFFECT_COMMITTED, EFFECT_DISPROVED, and EFFECT_UNKNOWN.
From evidence to wording
The sequence is:
authoritative verification
→ normalized effect truth
→ bounded claim permission
→ application-selected wordingThe public projection is the protected boundary that exposes the permitted category without exposing private evidence. A provider acknowledgment, local flag, or status label cannot authorize a success claim.
For the current Core/Runtime/Actions package tuple, keep result classification, effect truth, and wording authority separate:
result.kind | result.effectTruth.status | Customer effect wording |
|---|---|---|
COMMITTED | PRESENT | Only the exact EFFECT_COMMITTED proposition when the matching claim is PERMITTED. |
DISPROVED | ABSENT_FINAL | Only the exact EFFECT_DISPROVED proposition when the matching negative claim is PERMITTED. |
UNKNOWN | UNKNOWN | No success or final-absence wording; a permitted observation claim describes only its named historical read. |
Pre-dispatch result such as DENIED | NOT_DISPATCHED | Do not claim an external effect from this result. |
Before rendering an effect statement, the application must join the result and selected claim to its trusted tenant, request, original operation/effect/execution binding, requested effect, and vetted wording. Then require the matching result kind, effect truth, claims.decision === "PERMITTED", and selected safeClaims type. If any join or permission is missing, withhold the effect statement even if a local fixture mutated. The selected HTTP reference performs this host join before rendering. ACKNOWLEDGED is only the provider's observation; a final provider rejection also needs independently supported final absence before negative effect wording.
For a delivery-address change, the following scenario-specific renderer accepts a returned Actions result, a trusted host record saved for the original request, and the host-authenticated request being answered (not an untrusted HTTP body). It assumes the action grounds the exact order with an order: prefix and the trusted order ID and that the host has approved the two fixed sentences below. The host must retain the configured claim-plan branches, subject and exact requested effect, then bind the returned operation, effect, and execution identities to that record before rendering; a missing or conflicting binding withholds effect wording. The action's verifier must have made an independent authoritative read for PRESENT or ABSENT_FINAL; this renderer cannot turn a provider acknowledgment into that evidence.
function addressChangeMessage(result, saved, request) {
const withheld = 'We cannot confirm the requested delivery-address change.';
const exact = saved && request &&
saved.tenantRef && saved.requestId &&
saved.requestedEffect?.orderId && saved.requestedEffect?.address &&
saved.subjectRef === `order:${request.orderId}` &&
saved.actionName === 'change_delivery_address' && saved.actionVersion === '1' &&
saved.tenantRef === request.tenantRef &&
saved.requestId === request.requestId &&
saved.requestedEffect?.orderId === request.orderId &&
saved.requestedEffect?.address === request.address &&
saved.operationIdentity && saved.effectIdentity && saved.executionIdentity &&
result.operation?.actionName === 'change_delivery_address' &&
result.operation?.actionVersion === '1' &&
result.operation?.operationIdentity === saved.operationIdentity &&
result.core?.operationIdentity === saved.operationIdentity &&
result.core?.effectIdentity === saved.effectIdentity &&
result.core?.executionIdentity === saved.executionIdentity &&
result.effectTruth?.effectIdentity === saved.effectIdentity &&
result.claims?.effectIdentity === saved.effectIdentity &&
result.claims?.executionIdentity === saved.executionIdentity &&
(result.claims?.subjectRef == null || result.claims.subjectRef === saved.subjectRef) &&
result.claims?.scope === 'historical_effect';
if (!exact) return withheld;
const type = result.kind === 'COMMITTED' && result.effectTruth.status === 'PRESENT'
? 'EFFECT_COMMITTED'
: result.kind === 'DISPROVED' && result.effectTruth.status === 'ABSENT_FINAL'
? 'EFFECT_DISPROVED' : null;
const propositionRef = type === 'EFFECT_COMMITTED' ? 'delivery-address change recorded'
: type === 'EFFECT_DISPROVED' ? 'delivery-address change not recorded' : null;
if (!type || result.claims.decision !== 'PERMITTED' ||
result.claims.claimType !== type ||
saved.claimPlan?.propositions?.[result.kind]?.propositionRef !== propositionRef ||
!result.claims.safeClaims.some(claim => claim.claimType === type)) return withheld;
return type === 'EFFECT_COMMITTED'
? 'The requested delivery-address change was recorded.'
: 'The requested delivery-address change was not recorded.';
}A matching COMMITTED / PRESENT result with returned EFFECT_COMMITTED permission may use the first sentence. A DISPROVED classification without returned EFFECT_DISPROVED permission gets the withheld sentence. Even with that negative permission, it may say only that this requested change was not recorded; “This order can no longer be changed” is a broader, unsupported claim. The trusted host record and approved wording remain application responsibilities; never manufacture a claim-permission object or derive permission from result.kind.
The initial Actions safeClaims projection guarantees a bounded claim type; it does not expose a separate proposition reference. The initial claims.subjectRef can be null in the privacy-safe projection. This example therefore binds the subject through the trusted saved request and effect identity, rejects any conflicting returned subject when one is present, checks the selected proposition against the host's saved plan, and checks the returned claim type, scope, permission and identities. It is not a universal renderer for other subjects or effects. The executable Lumber quickstart includes negative assertions that withhold wording for a wrong saved subject, changed saved proposition or mismatched execution identity. Adapt those checks to your action's trusted request fields and approved wording.
Result data and claim authority are different
Result data answers, “What authoritative effect state was observed?” Claim authority answers, “May this exact structured proposition be asserted?” DISPROVED therefore does not automatically authorize arbitrary negative natural-language wording, and AnswerUp does not invent every truthful sentence it could formulate. The host supplies one exact proposition or a bounded set of mutually exclusive alternatives; Core authorizes only the exact selected proposition.
ClaimPermission is returned authority, not a structural data recipe. Matching visible fields, copying an object, or reconstructing one does not create authority. Every dimension used by user-facing wording belongs in requestedEffect; missing, extra, or changed fields fail closed.
The closed claim decision values remain PERMITTED, BLOCKED, and INDETERMINATE; they report Core's decision about the exact proposition, not a license to formulate a different proposition.
Three plan boundaries
The current packages support outcome-aware, data-only plans at three distinct boundaries:
| Boundary | Plan | Selection and continuation |
|---|---|---|
| Initial execution | optional InitialExecutionClaimPlan, captured with registration | One provider dispatch and initial authoritative verification; the matching COMMITTED, DISPROVED, or UNKNOWN alternative alone is evaluated. |
| Live reconciliation | optional LiveReconciliationClaimPlan, supplied with the exact Actions-owned UNKNOWN in the same Runtime process | One-shot verifier-only continuation with zero provider redispatch. |
| Durable recovery | RecoveryClaimPlan, supplied with a durable record and accepted recovery authority | Process-loss verifier-only continuation with host-owned persistence, stable verifier binding, source-record digest, lease/fencing/CAS controls, and zero provider redispatch. |
The three entries in each plan are alternatives, not simultaneous permissions. Authoritative truth is established first, then Runtime mechanically selects the matching proposition for Core evaluation. Unused branches never become authority. The legacy claims.build, one-argument live reconcile, and single-claim recovery overloads remain proposition-specific, fail-closed compatibility paths.
Default initial behavior remains success-oriented and proposition-specific. Without an InitialExecutionClaimPlan, a DISPROVED result does not generate arbitrary negative authority and initial UNKNOWN does not create ordinary safe-claim authority. Legacy claims.build is captured at registration; its returned proposition is snapshotted, validated, and frozen before provider dispatch, so later mutation of the definition, callback property, or returned object cannot change what Core evaluates.
Historical UNKNOWN observation scopes
An authorized UNKNOWN alternative is exposed through observationClaims, not ordinary safeClaims:
RELATED_INITIAL_VERIFICATION_OBSERVATION_ONLYmeans only that truth remained unresolved at the exact initial verification.RELATED_LIVE_RECONCILIATION_OBSERVATION_ONLYmeans only that the exact live reconciliation observation did not establish occurrence.RELATED_RECOVERY_OBSERVATION_ONLYmeans only that the exact accepted recovery observation did not establish occurrence.
None says the effect is still unresolved now or establishes success, failure, retry, redispatch, compensation, current truth after later evidence, or future-state truth. Use the latest accepted related result and host-owned durable state for current recovery state.
Result-to-language guide
| Claim permission | Established | The application may say | It must not infer |
|---|---|---|---|
EFFECT_COMMITTED | The authoritative read found the exact effect for the approved operation. | “The requested change was recorded.” | That another operation, record, account, or later state has the same result. |
EFFECT_DISPROVED | Applicable final evidence supports the absence of the exact requested effect. | “The requested change was not recorded.” | That no attempt occurred, or that a new attempt is authorized. |
Historical EFFECT_UNKNOWN observation claim | The exact named initial, live, or recovery observation did not determine whether the effect existed. | “That verification observation did not establish whether the change took effect.” | Current unresolved state, success, final absence, retry, redispatch, compensation, or future truth. |
Example: updating a customer phone number
An account UI sends an authenticated backend an approved phone-number update. An independent CRM verifier reads the authoritative customer record after the CRM update provider attempts the change. The application receives only the bounded claim permission, not a license to repeat the provider’s payload in public copy.
For EFFECT_COMMITTED, the application may say, “The phone number on this account was updated.” For EFFECT_DISPROVED, it may say, “The requested phone-number change was not recorded,” only when that exact negative proposition was supplied and permitted. An EFFECT_UNKNOWN observation claim may describe only the exact historical observation; current pending UX must come from host state, not broadened claim authority. The application should not echo the phone number unless the approved privacy and identity scope expressly permits it.
Scope and privacy
A claim applies only to the exact operation, record or referent, account or tenant, quantity or value where applicable, identity and privacy scope, authoritative read, and relevant time. One verified operation cannot be broadened into a statement about other records, accounts, history, or later state.
Public claims should omit raw evidence, prompts or transcripts, credentials, provider payloads, private Trace, internal counters, unrelated customer identifiers, stack traces, and tenant details. Detailed operational information belongs only in bounded access-controlled views.
Core and application responsibilities
Core derives the permitted effect-claim category, protects the bounded projection and claim boundary, and prevents unsupported success language from being authorized by its result. It does not write or send the final message.
The application owns final copy, localization, audience, timing, notifications, UX, privacy policy, and appropriate freshness or timestamp language. It also owns the decision about how a claim is displayed or communicated to a particular person.
Freshness
Verified truth supports a statement about the exact operation and authoritative read. It does not guarantee that the state can never change later. Durable displays may need timestamp or freshness context. Later reconciliation may produce a new related claim, but a previous COMMITTED result cannot authorize a claim about another operation.