@fabricorg/platform-host 6.0.0 → 7.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -0
- package/README.md +51 -0
- package/dist/index.cjs +356 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +115 -7
- package/dist/index.d.ts +115 -7
- package/dist/index.js +356 -26
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# @fabricorg/platform-host
|
|
2
2
|
|
|
3
|
+
## 7.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 4c358ad: The host now reads an action's `completion` mode. Before this the contract could declare `accepted` or `long-running` and nothing in the host behaved differently, so a render job, a financing decision, or an order acknowledgment that arrives by callback had nowhere to land except reconciliation.
|
|
8
|
+
|
|
9
|
+
An adapter that returns `acceptedExternalOperation` has its handoff persisted on the invocation the moment it is accepted, before the adapter step is marked done, so a worker that dies between the two leaves the handoff and not the marker; on re-execution the step is skipped and the handoff kept. Once finalized the invocation is `running` with no lease and a recorded `pendingCompletion`. The recovery worker does not claim it, a direct re-execution returns it as it stands, and an idempotent resubmission reports the pending completion. Domain events still go out at accept time, because the handler's writes committed.
|
|
10
|
+
|
|
11
|
+
`completeExternalInvocation` completes a parked invocation by external reference. Where the store is atomic, the read and write happen under one lock so two callbacks racing cannot both find nothing recorded. A reference the invocation is not waiting on is refused. A repeated identical completion is absorbed. A contradictory completion moves the invocation to `reconciliation_required`, keeps the first outcome on record, logs the second for reconciliation, and emits `ExternalOperationContradicted`. The callback's result is validated against the action's result schema and stripped of private fields. An invocation that ended for another reason while a handoff was pending, because a later step failed or a contract was violated, keeps its status and records the callback as evidence. A handoff under an `immediate` contract, or a second handoff in one invocation, is routed to reconciliation with the reference kept and a reconciliation row written, since the external effect is in flight; if the reconciliation log is unavailable the reference is still kept and the error says so. A callback that arrives before the invocation has parked, whether under a worker's lease, during an inline execution's remaining steps, or before a dispatched invocation runs, is refused rather than settling mid-execution; the handoff carries a `parkedAt` set at finalization and that is what the ingress checks. Refusals throw `ExternalCompletionError`, which carries a `refusal` code and a `retryable` flag; only `still_executing` is retryable and an unknown invocation is `not_found`, so a webhook handler maps refusals to responses without matching strings. Crash recovery between the durable handoff and the step marker replays the accept event by its stable id.
|
|
12
|
+
|
|
13
|
+
`reconcileOverdueCompletions` moves handoffs past their `completionDeadlineMs` to `reconciliation_required` while keeping the handoff, so a late completion can still land; the worker cycle runs the sweep before it claims, and a failure in the sweep is reported rather than stranding claimed work. `ListActionInvocationsInput` gains `awaitingCompletion`, `completionDueBefore`, and `unleased` so the sweep reads only what it needs; the sweep and the contradiction path refuse without a governance-capable store. `PostgresPlatformHostStore` gains migration 3 with the `pending_completion`, `external_completion`, and `completion_due_at` columns and a partial index on the due instant, verified against PostgreSQL 16. The worker accepts `sweepOverdueCompletions: false` for a store without the governance seam. Unsatisfied policy obligations after a handoff route to reconciliation rather than failure.
|
|
14
|
+
|
|
15
|
+
Disclosed as interface growth: `GovernedActionHost` gains two members, `completeExternalInvocation` and `reconcileOverdueCompletions`, which only the host implements in this repository. `PlatformHostStore.updateActionInvocation` and the transaction-scoped sibling accept the wider `ActionInvocationPatch`, which carries `pendingCompletion` and `externalCompletion`. A custom store has new obligations for those fields, documented on `ActionInvocationPatch` and in the README; a store that ignores them lets the worker re-run a handoff. The local certification suite gains an `accepted-completion-callback` case and its contract version moves to 3.
|
|
16
|
+
|
|
17
|
+
## 7.0.0
|
|
18
|
+
|
|
19
|
+
### Patch Changes
|
|
20
|
+
|
|
21
|
+
- Updated dependencies [274d948]
|
|
22
|
+
- @fabricorg/assembly@0.4.0
|
|
23
|
+
|
|
3
24
|
## 6.0.0
|
|
4
25
|
|
|
5
26
|
### Major Changes
|
package/README.md
CHANGED
|
@@ -247,6 +247,57 @@ stores should expose transaction-scoped `getEntityState()` so the guard reads th
|
|
|
247
247
|
snapshot used by the handler and event append. Existing custom stores without that optional
|
|
248
248
|
transaction method fall back to the store-level authoritative read.
|
|
249
249
|
|
|
250
|
+
## External completion
|
|
251
|
+
|
|
252
|
+
An action declaring `completion: "accepted"` or `"long-running"` may hand its work to an external
|
|
253
|
+
system. The adapter returns `acceptedExternalOperation: { externalReference }`; the Host parks the
|
|
254
|
+
invocation as `running` with no lease, emits `ExternalOperationAccepted`, and leaves it for the
|
|
255
|
+
external system to finish. The recovery worker never claims a parked invocation, and re-executing it
|
|
256
|
+
returns it as it stands.
|
|
257
|
+
|
|
258
|
+
```ts
|
|
259
|
+
await host.completeExternalInvocation(actionInvocationId, tenantId, spaceId, {
|
|
260
|
+
externalReference: "vendor-op-123",
|
|
261
|
+
outcome: "completed",
|
|
262
|
+
result: { receipt: "r-1" },
|
|
263
|
+
observedAt: new Date(),
|
|
264
|
+
});
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
Matching is by reference: a completion naming a reference the invocation is not waiting on is
|
|
268
|
+
refused. A repeated identical completion is absorbed. A contradictory one moves the invocation to
|
|
269
|
+
`reconciliation_required`, keeps the first outcome on record, logs the second, and emits
|
|
270
|
+
`ExternalOperationContradicted`. Under an atomic store the read and write happen under one lock. The
|
|
271
|
+
callback's result is validated against the action's result schema and stripped of private fields.
|
|
272
|
+
An invocation that ended for another reason while a handoff was pending keeps its status and records
|
|
273
|
+
the callback as evidence. Declare `completionDeadlineMs` on `long-running` actions;
|
|
274
|
+
`reconcileOverdueCompletions()` moves overdue handoffs to reconciliation while keeping the handoff so
|
|
275
|
+
a late completion can still land, and the worker cycle runs that sweep before it claims.
|
|
276
|
+
|
|
277
|
+
The handoff is persisted the moment it is accepted, before the adapter step is marked done, so a
|
|
278
|
+
worker that dies between the two leaves the handoff and not the marker. A custom store has four
|
|
279
|
+
obligations here, documented on `ActionInvocationPatch`: a patch setting `pendingCompletion` with
|
|
280
|
+
`status: "running"` parks the invocation and clears its lease; one setting it without a status keeps
|
|
281
|
+
the lease; `pendingCompletion: undefined` clears it; and the claim query must never claim a running
|
|
282
|
+
invocation without a lease. The recovery worker's guarantee of never re-running a handoff rests on
|
|
283
|
+
those. A callback that arrives before the invocation has parked, whether a worker still holds the lease
|
|
284
|
+
or an inline execution is still running the steps after the handoff, is refused with
|
|
285
|
+
`ExternalCompletionError` whose `refusal` is `still_executing` and whose `retryable` is true, since
|
|
286
|
+
settling mid-execution would report completion before the remaining steps ran; the handoff carries a
|
|
287
|
+
`parkedAt` set at finalization, and that is what the ingress checks; every other refusal
|
|
288
|
+
is permanent and typed the same way, so a webhook handler maps them to a retryable or a final
|
|
289
|
+
response without matching strings. An expired lease a dead worker left behind refuses the same way
|
|
290
|
+
until the claim loop reclaims the row; the overdue sweep also leaves leased rows alone, so both defer
|
|
291
|
+
to the worker fleet and the health snapshot's expired-lease count is where a stalled fleet shows.
|
|
292
|
+
The contradiction path and the overdue sweep refuse without a governance-capable store, and the
|
|
293
|
+
worker's sweep can be turned off with `sweepOverdueCompletions: false` for such a store; a refused
|
|
294
|
+
handoff keeps its reference on the invocation even when the reconciliation log is unavailable, and
|
|
295
|
+
says so in its error. Unsatisfied policy obligations after a handoff route to reconciliation rather
|
|
296
|
+
than failure, since a recovered handoff cannot attest what died with its worker. `PostgresPlatformHostStore`
|
|
297
|
+
migration 3 adds the `pending_completion`, `external_completion`, and `completion_due_at` columns and
|
|
298
|
+
a partial index on the due instant the overdue sweep uses; the due instant is a real column because a
|
|
299
|
+
cast in an index expression is not immutable and PostgreSQL refuses it.
|
|
300
|
+
|
|
250
301
|
## Runtime observability and health
|
|
251
302
|
|
|
252
303
|
Platform Host exposes vendor-neutral lifecycle telemetry through the optional `telemetry` sink on
|