Generic HTTP / Restaurant reservation
One booking. A supported confirmation.
A minimal restaurant adaptation of an existing executable reference. Keep the booking and lookup functions; use AnswerUp's real execution, verifier and claim contracts.
Jump to complete working source →Run the Restaurant HTTP quickstart
Try a local booking application built with a reusable, source-local HTTP helper. It demonstrates one verified reservation and recovery when a booking response is lost. This is a separate example from the selected Generic HTTP reference package described below.
Download restaurant HTTP source Source inventory · SHA-256 file
The source archive contains the application, helper, HTTP utility, README, Apache 2.0 license and notice. It does not contain SDK packages. Get Core rc.1, Runtime preview.5 and Actions preview.8 through your approved Package access, then set ANSWERUP_SDK_DIR to the absolute directory containing those three archives. Use Node 22+, npm, a Bash-compatible shell, a writable directory and localhost access. From the folder containing the source download:
mkdir restaurant-http-source
tar -xzf restaurant-http-source.tar.gz -C restaurant-http-source
cd restaurant-http-source/examples/restaurant-http
: "${ANSWERUP_SDK_DIR:?Set ANSWERUP_SDK_DIR to your approved SDK archive directory}"
mkdir -p packages
cp "$ANSWERUP_SDK_DIR/answerup-core-1.0.0-rc.1.tgz" \
"$ANSWERUP_SDK_DIR/answerup-runtime-0.2.0-preview.5.tgz" \
"$ANSWERUP_SDK_DIR/answerup-actions-0.2.0-preview.8.tgz" packages/
npm ci --offline --ignore-scripts --no-audit --no-fund
npm run demoThe demo shows UNKNOWN → UNKNOWN → UNKNOWN → COMMITTED → COMMITTED across graceful local restarts, with one booking, three independent effect reads and no recovery redispatch. For a direct POST /reserve and adaptation guidance, follow the included examples/restaurant-http/README.md and ADAPTING.md. The application still owns authentication, business authorization, provider write and authoritative verification. This local example uses one trusted filesystem writer; it does not establish multi-writer or arbitrary-crash durability.
Source integration and exact packages
Foundation: @answerup/generic-http-reference 0.2.0-preview.4, specifically try-answerup/01-first-action/src/index.mjs. Its response-loss HTTP fixture, exact-effect verifier, admission and claim-binding pattern are adapted to a synthetic table for two.
@answerup/core@1.0.0-rc.1@answerup/runtime@0.2.0-preview.5@answerup/actions@0.2.0-preview.8
All four archive hashes and byte sizes match the Portal's selected package manifest. The complete hashes and installation commands are in the README below.
Actual SDK interfaces
The code imports two functions from @answerup/actions. Those calls execute through the installed Runtime and Core packages. No new SDK shorthand is introduced.
- defineProtectedAction
- createProtectedActionRuntime
- ProtectedActionDefinitionBase
- TrustedContext
- ProviderDispatchResult
- VerifierResult
- ProtectedActionRuntime
- ClaimView
Exact signatures: Actions preview.8 declarations. The README lists their extracted line numbers and declaration SHA-256.
Action registration and real SDK calls
const runtime = createProtectedActionRuntime();
runtime.register(defineProtectedAction({
name: action, version: '1',
validateProposal(input) {
return typeof input?.requestId === 'string' && /^[a-z0-9-]{1,40}$/.test(input.requestId)
&& typeof input.slot === 'string' && input.partySize === 2
? { valid: true, input: { requestId: input.requestId, slot: input.slot, partySize: input.partySize } }
: { valid: false, kind: 'INVALID_PROPOSAL', code: 'RESERVATION_INPUT' };
},
ground(input, trusted) {
const slot = restaurant.readSlot(input.slot);
if (!slot || slot.capacity < input.partySize) return { kind: 'UNRESOLVED', clarificationRequired: true, reason: 'SLOT_UNAVAILABLE', candidates: [] };
return { kind: 'GROUNDED', grounded: { subject: slot.subject }, scope: trusted.tenant.securityDomainRef,
subject: slot.subject, requestedEffect: { slot: input.slot, partySize: input.partySize, status: 'reserved' },
candidates: [{ referent: slot.subject, source: 'authoritative', attributes: { resource: slot.subject }, evidenceRefs: ['restaurant:synthetic-catalog'] }],
observationRef: 'restaurant:catalog-read' };
},
authorize: () => canBook ? 'PERMIT' : 'DENY',
provider: { adapterIdentity: 'restaurant-local-http-writer', dispatch },
verifier: { verifierIdentity: 'restaurant-exact-effect-reader', verify },
initialExecutionClaimPlan: claimPlan,
}));Supported confirmation: input, identity and claim checks
export function confirmation(result, entry, answeringRequest = entry.input) {
const binding = entry.binding;
const claims = result.claims;
const exact = result.kind === 'COMMITTED' && result.effectTruth?.status === 'PRESENT'
&& binding && sameInput(entry.input, answeringRequest)
&& binding.tenantRef === entry.tenantRef && sameInput(binding, entry.input)
&& entry.claimPlan.propositions.COMMITTED.propositionRef === claimPlan.propositions.COMMITTED.propositionRef
&& result.operation?.actionName === action && result.operation.actionVersion === '1'
&& result.operation.operationIdentity === binding.operationIdentity
&& identityFields.every(field => result.core?.[field] === binding[field])
&& result.effectTruth.effectIdentity === binding.effectIdentity
&& claims?.effectIdentity === binding.effectIdentity && claims.executionIdentity === binding.executionIdentity
&& (claims.subjectRef == null || claims.subjectRef === entry.subject)
&& claims.scope === 'historical_effect' && claims.decision === 'PERMITTED'
&& claims.claimType === 'EFFECT_COMMITTED'
&& claims.safeClaims?.some(claim => claim.claimType === 'EFFECT_COMMITTED');
return exact ? 'Your table for two was verified.' : withheld;
}Required host responsibilities
The host supplies authenticated tenant context and policy, admits each logical request before dispatch, saves exact effect bindings, provides an independent lookup and checks permitted claims before sending a confirmation.
In this exercise, identity and policy are local fixture values. Admission and live reconciliation are process-local. The host must retain pending work and maintain replay after reconciliation in an actual application. For restart recovery and persisted admission, continue with the original Generic HTTP host and its exportRecoveryRecord, rehydrateRecovery and acquire/commit/release implementation.
Focused verification
The executed local run records a real lost HTTP response, then real SDK outcomes. The restaurant, slot, capacity and evidence-availability change are synthetic. No live restaurant provider is involved.
Four focused tests pass: response loss and live reconciliation with admission and claim checks; policy denial and missing slot; inexact evidence withholding; and the baseline using the same functions. Copied and consumed live results, changed input, blocked claims and wrong execution bindings are rejected or withheld.
The final customer message is Your table for two was verified.
It is permitted only after exact read-back and claim checks.
Complete working source
All files below are the source of the shown excerpts and the executed example. Use Node 22 or newer, obtain the three dependency archives through your approved handoff, and follow the README. This source listing contains application code; package implementations remain in the existing private handoff.
without-core.mjs
export async function withoutCore(restaurant, request) {
const binding = {
...request, tenantRef: 'tenant:demo',
effectIdentity: `legacy:${request.requestId}`,
};
try {
await restaurant.bookReservation(binding);
} catch {
try {
const receipt = await restaurant.lookupReservation(
binding.effectIdentity,
);
const exact = Object.keys(binding).every(
field => receipt[field] === binding[field],
);
if (exact && receipt.status === 'reserved') {
return 'Your table for two was verified.';
}
} catch {}
return 'The booking outcome needs a later check. Do not resend.';
}
return 'The booking response needs an independent check.';
}
with-core.mjs
import { createProtectedActionRuntime, defineProtectedAction } from '@answerup/actions';
export const claimPlan = { propositions: {
COMMITTED: { propositionRef: 'the requested restaurant reservation occurred' },
DISPROVED: { propositionRef: 'the requested restaurant reservation did not occur' },
UNKNOWN: { propositionRef: 'this verification did not establish reservation truth' },
} };
const sameInput = (left, right) => left.requestId === right.requestId && left.slot === right.slot && left.partySize === right.partySize;
const action = 'reserve_restaurant';
const identityFields = ['operationIdentity', 'executionIdentity', 'effectIdentity', 'attemptIdentity'];
export const withheld = 'No supported booking confirmation is available.';
export function confirmation(result, entry, answeringRequest = entry.input) {
const binding = entry.binding;
const claims = result.claims;
const exact = result.kind === 'COMMITTED' && result.effectTruth?.status === 'PRESENT'
&& binding && sameInput(entry.input, answeringRequest)
&& binding.tenantRef === entry.tenantRef && sameInput(binding, entry.input)
&& entry.claimPlan.propositions.COMMITTED.propositionRef === claimPlan.propositions.COMMITTED.propositionRef
&& result.operation?.actionName === action && result.operation.actionVersion === '1'
&& result.operation.operationIdentity === binding.operationIdentity
&& identityFields.every(field => result.core?.[field] === binding[field])
&& result.effectTruth.effectIdentity === binding.effectIdentity
&& claims?.effectIdentity === binding.effectIdentity && claims.executionIdentity === binding.executionIdentity
&& (claims.subjectRef == null || claims.subjectRef === entry.subject)
&& claims.scope === 'historical_effect' && claims.decision === 'PERMITTED'
&& claims.claimType === 'EFFECT_COMMITTED'
&& claims.safeClaims?.some(claim => claim.claimType === 'EFFECT_COMMITTED');
return exact ? 'Your table for two was verified.' : withheld;
}
export function createReservationHost(restaurant, { tenantRef = 'tenant:demo', canBook = true } = {}) {
const admissions = new Map();
const bindings = new Map();
async function dispatch({ input, context, operationIdentity, executionIdentity, effectIdentity, attemptIdentity }) {
const entry = admissions.get(input.requestId);
if (!entry || !sameInput(entry.input, input)) return { kind: 'PRECONDITION_FAILED' };
const binding = { ...input, tenantRef: context.tenant.tenantRef, operationIdentity, executionIdentity, effectIdentity, attemptIdentity };
entry.binding = binding;
bindings.set(effectIdentity, binding);
try {
await restaurant.bookReservation(binding);
return { kind: 'ACKNOWLEDGED' };
} catch {
return { kind: 'UNCERTAIN', reason: 'RESPONSE_LOST' };
}
}
async function verify({ input, context, effectIdentity }) {
const binding = bindings.get(effectIdentity);
if (!binding || binding.tenantRef !== context.tenant.tenantRef || !sameInput(binding, input)) {
return { kind: 'INDETERMINATE', observationRef: 'restaurant:unbound' };
}
try {
const receipt = await restaurant.lookupReservation(effectIdentity);
const exact = Object.keys(binding).every(field => receipt[field] === binding[field]);
if (exact && receipt.status === 'reserved') return { kind: 'PRESENT', observationRef: `restaurant:${effectIdentity}` };
} catch {}
return { kind: 'INDETERMINATE', observationRef: 'restaurant:unavailable' };
}
const runtime = createProtectedActionRuntime();
runtime.register(defineProtectedAction({
name: action, version: '1',
validateProposal(input) {
return typeof input?.requestId === 'string' && /^[a-z0-9-]{1,40}$/.test(input.requestId)
&& typeof input.slot === 'string' && input.partySize === 2
? { valid: true, input: { requestId: input.requestId, slot: input.slot, partySize: input.partySize } }
: { valid: false, kind: 'INVALID_PROPOSAL', code: 'RESERVATION_INPUT' };
},
ground(input, trusted) {
const slot = restaurant.readSlot(input.slot);
if (!slot || slot.capacity < input.partySize) return { kind: 'UNRESOLVED', clarificationRequired: true, reason: 'SLOT_UNAVAILABLE', candidates: [] };
return { kind: 'GROUNDED', grounded: { subject: slot.subject }, scope: trusted.tenant.securityDomainRef,
subject: slot.subject, requestedEffect: { slot: input.slot, partySize: input.partySize, status: 'reserved' },
candidates: [{ referent: slot.subject, source: 'authoritative', attributes: { resource: slot.subject }, evidenceRefs: ['restaurant:synthetic-catalog'] }],
observationRef: 'restaurant:catalog-read' };
},
authorize: () => canBook ? 'PERMIT' : 'DENY',
provider: { adapterIdentity: 'restaurant-local-http-writer', dispatch },
verifier: { verifierIdentity: 'restaurant-exact-effect-reader', verify },
initialExecutionClaimPlan: claimPlan,
}));
const context = {
tenant: { tenantRef, securityDomainRef: `domain:${tenantRef}` },
actor: { actorRef: 'actor:demo-host', assurance: 'synthetic-session' },
authorization: { scopeRef: 'policy:restaurant', policyRevision: '1' },
provider: { accountRef: 'restaurant:local-http' },
};
return {
submit(input) {
const prior = admissions.get(input.requestId);
if (prior) {
if (!sameInput(prior.input, input)) {
throw new Error('REQUEST_CONFLICT');
}
return prior.promise;
}
const entry = {
tenantRef, input: structuredClone(input),
claimPlan: structuredClone(claimPlan),
subject: restaurant.readSlot(input.slot)?.subject,
binding: null, promise: null,
};
admissions.set(input.requestId, entry);
entry.promise = runtime.run({
action, input,
context: {
...context,
delivery: {
deliveryId: `delivery:${input.requestId}`,
source: 'restaurant-lesson',
},
hostInvocation: {
invocationId: `${tenantRef}:${input.requestId}`,
},
},
}).then(result => ({
result, entry, message: confirmation(result, entry),
}));
return entry.promise;
},
async reconcile(initial) {
const result = await runtime.reconcile(
initial.result, { claimPlan },
);
return {
result, entry: initial.entry,
message: confirmation(result, initial.entry),
};
},
};
}
restaurant.mjs
import { createServer } from 'node:http';
export const reservation = Object.freeze({ requestId: 'dinner-42', slot: '2026-10-24T19:00:00Z', partySize: 2 });
export async function createRestaurant() {
const receipts = new Map();
let visible = false;
const counters = { bookings: 0, lookups: 0 };
const reply = (response, status, value) => {
response.writeHead(status, { 'content-type': 'application/json' });
response.end(JSON.stringify(value));
};
const server = createServer(async (request, response) => {
if (request.method === 'POST' && request.url === '/book') {
const chunks = [];
for await (const chunk of request) chunks.push(chunk);
const binding = JSON.parse(Buffer.concat(chunks).toString());
counters.bookings++;
receipts.set(binding.effectIdentity, { ...binding, status: 'reserved' });
request.socket.destroy();
return;
}
if (request.method === 'GET' && request.url.startsWith('/effects/')) {
counters.lookups++;
const effectIdentity = decodeURIComponent(request.url.slice('/effects/'.length));
const receipt = receipts.get(effectIdentity);
return visible && receipt ? reply(response, 200, receipt) : reply(response, 503, { status: 'unavailable' });
}
reply(response, 404, { error: 'NOT_FOUND' });
});
await new Promise((resolve, reject) => {
server.once('error', reject);
server.listen(0, '127.0.0.1', resolve);
});
const base = `http://127.0.0.1:${server.address().port}`;
const requestRestaurant = globalThis.fetch.bind(globalThis);
return {
counters,
async bookReservation(binding) {
const response = await requestRestaurant(`${base}/book`, {
method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(binding),
signal: AbortSignal.timeout(2000),
});
if (!response.ok) throw new Error('BOOKING_UNAVAILABLE');
return response.json();
},
async lookupReservation(effectIdentity) {
const response = await requestRestaurant(`${base}/effects/${encodeURIComponent(effectIdentity)}`, { signal: AbortSignal.timeout(2000) });
if (!response.ok) throw new Error('LOOKUP_UNAVAILABLE');
return response.json();
},
readSlot: slot => slot === reservation.slot ? { subject: `restaurant:demo:${slot}`, capacity: 2 } : null,
reveal: () => { visible = true; },
async close() {
server.closeAllConnections();
await new Promise(resolve => server.close(resolve));
},
};
}
demo.mjs
import assert from 'node:assert/strict';
import { createRestaurant, reservation } from './restaurant.mjs';
import { withoutCore } from './without-core.mjs';
import { createReservationHost } from './with-core.mjs';
export async function withCore(restaurant, request) {
const host = createReservationHost(restaurant);
const initial = await host.submit(request);
assert.equal(initial.result.kind, 'UNKNOWN');
assert.equal(initial.result.claims.safeClaims.length, 0);
restaurant.reveal();
const related = await host.reconcile(initial);
assert.equal(related.result.kind, 'COMMITTED');
assert.equal(restaurant.counters.bookings, 1);
return { initial: initial.result.kind, initialMessage: initial.message,
related: related.result.kind, truth: related.result.effectTruth.status,
claimDecision: related.result.claims.decision, message: related.message,
...restaurant.counters, redispatches: restaurant.counters.bookings - 1 };
}
const baseline = await createRestaurant();
const controlled = await createRestaurant();
try {
const before = await withoutCore(baseline, reservation);
const after = await withCore(controlled, reservation);
console.log(JSON.stringify({ syntheticRestaurant: true, realAnswerUpExecution: true,
before: { message: before, ...baseline.counters }, after }, null, 2));
} finally {
await baseline.close();
await controlled.close();
}
reservation.test.mjs
import assert from 'node:assert/strict';
import { test } from 'node:test';
import { createRestaurant, reservation } from './restaurant.mjs';
import { confirmation, createReservationHost, withheld } from './with-core.mjs';
import { withoutCore } from './without-core.mjs';
test('lost response, UNKNOWN, one admitted booking, verifier-only reconciliation and bound claims', async () => {
const restaurant = await createRestaurant();
try {
const host = createReservationHost(restaurant);
const [initial, replay] = await Promise.all([host.submit(reservation), host.submit(reservation)]);
assert.equal(initial, replay);
assert.equal(initial.result.kind, 'UNKNOWN');
assert.equal(initial.result.claims.safeClaims.length, 0);
assert.equal(initial.message, withheld);
assert.throws(() => host.submit({ ...reservation, slot: 'different' }), /REQUEST_CONFLICT/);
await assert.rejects(host.reconcile({ ...initial, result: structuredClone(initial.result) }), /invalid Actions reconciliation result/);
restaurant.reveal();
const related = await host.reconcile(initial);
assert.equal(related.result.kind, 'COMMITTED');
assert.equal(related.result.effectTruth.status, 'PRESENT');
assert.equal(related.result.claims.decision, 'PERMITTED');
assert.equal(related.message, 'Your table for two was verified.');
assert.deepEqual(restaurant.counters, { bookings: 1, lookups: 2 });
assert.equal(confirmation({ ...related.result, claims: { ...related.result.claims, decision: 'BLOCKED' } }, related.entry), withheld);
assert.equal(confirmation({ ...related.result, core: { ...related.result.core, executionIdentity: 'foreign' } }, related.entry), withheld);
assert.equal(confirmation(related.result, related.entry, { ...reservation, slot: 'different' }), withheld);
assert.equal(confirmation(related.result, { ...related.entry, claimPlan: { propositions: { COMMITTED: { propositionRef: 'other' } } } }), withheld);
await assert.rejects(host.reconcile(initial), /invalid Actions reconciliation result/);
assert.equal(restaurant.counters.bookings, 1);
} finally { await restaurant.close(); }
});
test('host policy denial and unavailable slot cause no booking', async () => {
const restaurant = await createRestaurant();
try {
const denied = await createReservationHost(restaurant, { canBook: false }).submit(reservation);
assert.equal(denied.result.kind, 'DENIED');
const missing = await createReservationHost(restaurant).submit({ ...reservation, slot: 'missing' });
assert.equal(missing.result.kind, 'NEEDS_CLARIFICATION');
assert.equal(restaurant.counters.bookings, 0);
} finally { await restaurant.close(); }
});
test('an inexact provider receipt cannot confirm the reservation', async () => {
const restaurant = await createRestaurant();
try {
const host = createReservationHost({ ...restaurant, lookupReservation: async effectIdentity => ({ effectIdentity, status: 'reserved', tenantRef: 'foreign' }) });
const initial = await host.submit(reservation);
restaurant.reveal();
const related = await host.reconcile(initial);
assert.equal(related.result.kind, 'UNKNOWN');
assert.equal(related.message, withheld);
assert.equal(restaurant.counters.bookings, 1);
} finally { await restaurant.close(); }
});
test('the same booking and lookup functions run without Core', async () => {
const restaurant = await createRestaurant();
try {
assert.equal(await withoutCore(restaurant, reservation), 'The booking outcome needs a later check. Do not resend.');
assert.deepEqual(restaurant.counters, { bookings: 1, lookups: 1 });
} finally { await restaurant.close(); }
});
package.json
{
"name": "answerup-restaurant-reservation-lesson",
"private": true,
"type": "module",
"engines": { "node": ">=22" },
"scripts": { "demo": "node demo.mjs", "test": "node --test reservation.test.mjs" },
"dependencies": {
"@answerup/actions": "0.2.0-preview.8",
"@answerup/core": "1.0.0-rc.1",
"@answerup/runtime": "0.2.0-preview.5"
}
}
README.md
# Restaurant reservation: same integration, AnswerUp control
Derived from the selected immutable `@answerup/generic-http-reference@0.2.0-preview.4`, particularly `try-answerup/01-first-action/src/index.mjs`. That source supplies the HTTP response-loss fixture, exact-effect read-back, host admission, identity joins and claim checks. The restaurant vocabulary and two-person slot are synthetic adaptations. No package implementation is copied or changed.
Requires Node 22 or newer and the approved private handoff archives. Copy all files from this directory into a local directory. Obtain packages through your existing approved handoff; this example creates no new package delivery path. Verify these archive SHA-256 values against that handoff's trusted manifest:
| Archive | SHA-256 |
| --- | --- |
| answerup-core-1.0.0-rc.1.tgz | ba20e2b71fd0336505b01c63664c4aade4f023bd77fd9108d773d8bb2546d62b |
| answerup-runtime-0.2.0-preview.5.tgz | 3d1f805f30199c498653a5cdd69d0b9df7bd2563ac79f87bdcb8d2ddda8a9336 |
| answerup-actions-0.2.0-preview.8.tgz | 2f0023f4ada2086e4d52f52149ac9061c5d1f99d4eda82c22ae88f7b46aebc30 |
| answerup-generic-http-reference-0.2.0-preview.4.tgz | 7a95340d0cb02dc2c45ddb2f3a9a1914022cc65e8940845a723e9620fc015708 |
Place the three dependency archives under `packages/`, then run:
```sh
npm install --offline --ignore-scripts --no-audit --no-fund --no-save --package-lock=false ./packages/answerup-core-1.0.0-rc.1.tgz ./packages/answerup-runtime-0.2.0-preview.5.tgz ./packages/answerup-actions-0.2.0-preview.8.tgz
npm test
npm run demo
```
`without-core.mjs` and `with-core.mjs` use the identical `bookReservation` and `lookupReservation` functions from `restaurant.mjs`. The restaurant records the booking and really destroys the localhost HTTP socket. The first lookup is unavailable. The baseline leaves a developer-owned pending check. Real Actions → Runtime → Core execution yields `UNKNOWN` and no terminal safe claim. After the fixture reveals the saved receipt, `runtime.reconcile(initial.result, { claimPlan })` uses verifier-only read-back; it returns `COMMITTED`, `PRESENT` and `PERMITTED` with one booking and two lookups. The message renderer joins the original input, tenant, action/version, all four execution identities and permitted claim before confirming.
Only `createProtectedActionRuntime` and `defineProtectedAction` are imported SDK functions. `createReservationHost`, `submit`, `confirmation`, `readSlot`, `reveal` and the booking/lookup functions are local application code. The actual Actions declaration file is `package/src/index.d.ts`, SHA-256 `a1e1ef1295ea740084b8cd9e1385a8694dfcfa7894247643be49122dcedc1052`: `TrustedContext` line 42, `ProviderDispatchResult` line 93, `VerifierResult` line 99, `ProtectedActionDefinitionBase` line 156, `ProtectedActionRuntime` line 257, `ClaimView` line 331, `defineProtectedAction` line 373 and `createProtectedActionRuntime` line 374. The Portal links to the corresponding public versioned declarations and export anchors.
The focused four-test file verifies response loss, duplicate admission, changed-input conflict, copied/consumed live result rejection, policy denial, missing slot, inexact evidence, and blocked or mismatched confirmations. The local example uses real package execution and loopback HTTP with synthetic reservation evidence; it establishes no live restaurant-provider behavior.
The host owns authentication, trusted tenant context, policy, admission, exact effect bindings, independent verifier evidence and outgoing wording. Admission and live reconciliation here are process-local. The host must retain pending work, serialize continuing observations and maintain replay after reconciliation in an actual application. This exercise does not implement restart recovery, distributed admission or production provider security. For the existing durable single-writer host and `exportRecoveryRecord` / `rehydrateRecovery` / acquire-commit-release contracts, use the complete selected Generic HTTP reference and its documented local limitations.