@fabricorg/platform-host 8.7.0 → 8.9.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 +327 -0
- package/README.md +772 -9
- package/dist/index.cjs +6240 -393
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +560 -36
- package/dist/index.d.ts +560 -36
- package/dist/index.js +6221 -398
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,332 @@
|
|
|
1
1
|
# @fabricorg/platform-host
|
|
2
2
|
|
|
3
|
+
## 8.9.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 7cb17c9: Add `RetryableHandlerError` and cross-copy recognition, plus optional confirmed rollback
|
|
8
|
+
retry inside one Host execution attempt. The default budget is three total tries (1–10).
|
|
9
|
+
Host requires a handler-call throw, identical-cause `ConfirmedTransactionRollback`, no adapter
|
|
10
|
+
or handoff evidence, fresh durable-derived inputs and transaction-scoped ownership fencing.
|
|
11
|
+
Policy evaluations, obligations, approvals and worker claim counts are retained; exhaustion
|
|
12
|
+
settles the last handler error through the existing redactor and statuses. Governance
|
|
13
|
+
`RetryableExecutionError`, returned failures and non-handler callback/commit errors retain
|
|
14
|
+
their existing failure semantics.
|
|
15
|
+
|
|
16
|
+
Expose `handlerRetry` classification, bounded jitter/delay and retry notification options,
|
|
17
|
+
and `isTransientPostgresTransactionError` for candidate SQLSTATE classification. Application
|
|
18
|
+
transaction providers can opt into rollback confirmation after successful rollback of a failed
|
|
19
|
+
callback. Built-in stores expose evidence for Host's internal handler callback request and
|
|
20
|
+
preserve prior error contracts for ordinary application transactions, approval, erasure and
|
|
21
|
+
other Host APIs, including callback-error identity and erasure's SQLSTATE mappings. Memory confirms after a configured provider's successful snapshot/restore
|
|
22
|
+
and ledger undo; commit failures and providerless internal transactions are not confirmed.
|
|
23
|
+
Custom stores exposing confirmation from their public transaction API remain supported through
|
|
24
|
+
normalization at non-handler Host and conformance boundaries. Retried callbacks must keep
|
|
25
|
+
effects inside the supplied transaction.
|
|
26
|
+
|
|
27
|
+
Retry observers run without awaiting them; synchronous throws and asynchronous rejections
|
|
28
|
+
are ignored. Memory rollback failures cannot authorize handler retry.
|
|
29
|
+
|
|
30
|
+
- be0938a: Export runner-independent Host store conformance suites: `stagedInvocationChecks`,
|
|
31
|
+
`runStagedInvocationChecks`, `outboxRequeueChecks`, `runOutboxRequeueChecks`,
|
|
32
|
+
`approvalChecks`, and `runApprovalChecks`, with their subject, check, and result types.
|
|
33
|
+
The destructive probes cover staged lease fencing and dispatch, operator outbox
|
|
34
|
+
requeue, and recorded and inline approval behavior on isolated test stores.
|
|
35
|
+
- db6ca3b: Export runner-independent `outboxRelayChecks` / `runOutboxRelayChecks` and
|
|
36
|
+
`invocationIdempotencyChecks` / `runInvocationIdempotencyChecks`, with subject,
|
|
37
|
+
check and result types. The destructive isolated-store probes pin shared relay
|
|
38
|
+
claim/settlement/renewal fences and first-row-wins invocation key arbitration,
|
|
39
|
+
including admission timestamp retention and optional refusal/admitted winners.
|
|
40
|
+
Document these store contracts without changing store signatures or conflict
|
|
41
|
+
classification, and leave claim result ordering unspecified.
|
|
42
|
+
|
|
43
|
+
The relay checks require numeric lease tokens that increase on each claim,
|
|
44
|
+
including reclaim, despite optional token fields in the general interfaces.
|
|
45
|
+
Use per-run future base times for relay and requeue probes so wall-clock
|
|
46
|
+
settlement guards can refuse expired leases, and set future relay availability
|
|
47
|
+
through retry settlement without requiring it to equal event recording time.
|
|
48
|
+
|
|
49
|
+
- d09f378: Add optional `ErasablePlatformHostStore`, the separate `StoredRecordErasureHost` operator
|
|
50
|
+
and `createStoredRecordErasureHost`, plus erasure conformance checks. Built-in stores
|
|
51
|
+
atomically redact settled invocation/event copies, record scoped markers and append
|
|
52
|
+
sequenced `HostRecordsErased` evidence. Mixed batches can erase settled targets and report
|
|
53
|
+
active/missing ones. Invalid redactors roll the batch back; repeats process stored redacted
|
|
54
|
+
data again. Explicit structure paths protect Host state and identity while application
|
|
55
|
+
values, including reserved-looking keys in policy facts and metadata, remain visible.
|
|
56
|
+
|
|
57
|
+
Erasure requests require trusted `actorId` and `actorType`. `validateErasureInput` rejects
|
|
58
|
+
blank actor fields and NUL/lone-surrogate characters in `actorId`, and checks `actorType`
|
|
59
|
+
with Platform's `isActorType`. `createStoredRecordErasureHost(store, authorization)`
|
|
60
|
+
requires the authorization object; the integrated Host passes its own. The operator awaits
|
|
61
|
+
`authorization.authorizeStoredRecordErasure` after validation and before the store call,
|
|
62
|
+
preserving class receivers and doing no preceding record read. The hook receives exactly
|
|
63
|
+
actor ID/type, tenant, space, request ID and detached validated targets, without `redact`
|
|
64
|
+
or stored payloads. The strict `authorized !== true` guard refuses absent hooks and
|
|
65
|
+
non-`true` results with exported `StoredRecordErasureAuthorizationError`
|
|
66
|
+
(`refusal: "not_authorized"`). The missing-hook message differs from the actor-denied
|
|
67
|
+
message; neither discloses target existence. A thrown hook error propagates unchanged
|
|
68
|
+
before store access, distinguishing a failed check from a denial. Validation errors
|
|
69
|
+
and `ErasureBusyError` remain distinct. Both stores retain the actor in the
|
|
70
|
+
`HostRecordsErased` envelope as identifying metadata outside the redaction view.
|
|
71
|
+
The conformance kit's success probes require exactly one scoped `HostRecordsErased` event
|
|
72
|
+
with the request's actor ID/type, rejecting stores that omit or misattribute the audit.
|
|
73
|
+
The store capability remains an unauthenticated persistence port, not an authorization
|
|
74
|
+
boundary; direct callers enforce authorization themselves. This revises the unreleased
|
|
75
|
+
erasure API rather than preserving its unauthenticated factory signature.
|
|
76
|
+
|
|
77
|
+
Event targets cover canonical and delivery/requeue records. They do not erase copies in
|
|
78
|
+
invocation checkpoints/results because checkpoint events lack event IDs. Use invocation
|
|
79
|
+
targets for those copies. Erasure is the supported exception to append-only event payload
|
|
80
|
+
storage; normal append retains first-write-wins behavior, identity, sequence and order.
|
|
81
|
+
|
|
82
|
+
PostgreSQL erasure requires a transaction provider running READ COMMITTED; it checks
|
|
83
|
+
`SHOW transaction_isolation` and refuses other levels. Ordinary writers at stricter
|
|
84
|
+
isolation levels may receive a serialization failure instead of an erased outcome.
|
|
85
|
+
Apply migration 16, upgrade **all Host instances sharing the database**, then enable
|
|
86
|
+
erasure. Older Host SQL and direct application SQL bypass these guards and are unsupported
|
|
87
|
+
once erasure is enabled. Migration 16 adds metadata columns, markers and erasure-lookup
|
|
88
|
+
indexes without triggers or write-path functions. Like migrations 1–15 it runs in the
|
|
89
|
+
migration runner's transaction and takes table DDL locks; ordinary index builds block
|
|
90
|
+
writes for their duration on large tables. Plan an appropriate maintenance window.
|
|
91
|
+
|
|
92
|
+
`eraseStoredRecords` processes sorted targets inside individual savepoints. An invocation
|
|
93
|
+
target locks its invocation and dependent adapter, governance, staged parent/child, event,
|
|
94
|
+
outbox and requeue rows. It also locks the stage identified by the child's stored
|
|
95
|
+
`staged_parent_invocation_id` and `staged_stage_key`, even before that stage has recorded
|
|
96
|
+
its child ID. A pending or leased origin stage keeps the child active; a settled origin
|
|
97
|
+
stage is redacted with the child. This follows the stage, not the parent invocation's
|
|
98
|
+
payloads or other stages; target the parent separately for its checkpoint copies. An event target locks its event and delivery/requeue rows, without
|
|
99
|
+
locking its invocation owner or sibling rows. Canonical delivery copies are found by event
|
|
100
|
+
ID. Legacy outbox-only rows with null owner columns are found through the indexed envelope
|
|
101
|
+
`actionInvocationId`; new inserts populate the owner column explicitly. No advisory lock
|
|
102
|
+
is taken by erasure. The migration runner retains its separate schema advisory lock.
|
|
103
|
+
|
|
104
|
+
The first existing target lock may wait within `lockTimeoutMs` (default 250 ms, including
|
|
105
|
+
provider acquisition). While retaining target locks, subsequent row locks, including the
|
|
106
|
+
final tenant/space sequence-row lock, use `NOWAIT`; contention rolls back with
|
|
107
|
+
`ErasureBusyError`. The audit allocation and insert are the final SQL statements before
|
|
108
|
+
provider commit. Before opening that transaction, a separate provider transaction commits
|
|
109
|
+
an `event_sequences` row with `next_sequence=0` using `ON CONFLICT DO NOTHING`. It takes no
|
|
110
|
+
target locks. It attempts the insert only when it sees no committed row for the tenant and
|
|
111
|
+
space, so it can wait, within the acquisition budget, only for another transaction's
|
|
112
|
+
uncommitted first insert of that row. The zero seed consumes no event
|
|
113
|
+
sequence: the first allocation returns 1. The erasure transaction then locks the existing
|
|
114
|
+
row with `NOWAIT`; it does not try to insert a missing sequence row while holding targets.
|
|
115
|
+
The seed can remain after a refused or rolled-back erasure without consuming a sequence.
|
|
116
|
+
Steady event appends in the same tenant and space can starve erasure: it can repeatedly
|
|
117
|
+
report busy on this final nonwaiting lock. Each retry repeats callbacks and rewrites before
|
|
118
|
+
attempting that lock; busy rolls those rewrites back.
|
|
119
|
+
|
|
120
|
+
Dependent rows are locked before settlement and callbacks. A claim/renewal committed before
|
|
121
|
+
those locks is observed. Active/missing targets roll back to their savepoints, releasing
|
|
122
|
+
locks acquired for that target before processing the next. Locks retained from an earlier
|
|
123
|
+
overlapping accepted target stay held. Invocation settlement is evaluated on locked rows.
|
|
124
|
+
For an event-only target the owner's status, stages and sibling leases are observed after
|
|
125
|
+
the event closure is locked, but are not themselves locked. A concurrent change to that
|
|
126
|
+
owner/sibling activity can therefore race that observation. Target the invocation when
|
|
127
|
+
settlement of its complete closure must be serialized.
|
|
128
|
+
|
|
129
|
+
Ordinary invocation updates predicate on their own `records_erased_at`. Existing dependent
|
|
130
|
+
updates use their row stamp; insertion paths without a proven transaction-held owner lock
|
|
131
|
+
use a materialized owner read with `FOR KEY SHARE` inside the insertion statement. Host's
|
|
132
|
+
ordinary owner locks change from the released version's `FOR UPDATE` to `FOR NO KEY UPDATE`. Transaction-held owner reads are reused
|
|
133
|
+
for event and reconciliation insertion. Staged creation fences parent and initial child;
|
|
134
|
+
dispatch/failure attachment fences the newly attached child. An erased child cannot acquire
|
|
135
|
+
a stage containing old parameters through these methods. Host terminally rejects an
|
|
136
|
+
unsettled stage if an older/custom store nevertheless returns an erased child by origin,
|
|
137
|
+
so the attachment refusal cannot keep that stage retrying indefinitely. Replay conflict updates preserve
|
|
138
|
+
the stored row, and event reappend remains first-write-wins.
|
|
139
|
+
|
|
140
|
+
Outbox, stage and invocation claims lock actual candidate rows with `SKIP LOCKED`, without
|
|
141
|
+
a blocking parent lock. Stage cancellation also selects candidates with `SKIP LOCKED`; transactional approval
|
|
142
|
+
expiry uses the optional `lockDueApprovals` transaction member for that selection. Delivery of erased outbox records remains usable: claims,
|
|
143
|
+
renewals, publish/fail acknowledgement and requeue use stored redacted envelopes; failure
|
|
144
|
+
withholds supplied error text and requeue withholds supplied reason text while retaining
|
|
145
|
+
stored prior errors. The optional `renewOutboxLeaseAndRead` capability returns the stored
|
|
146
|
+
envelope atomically with renewal. Relays use that envelope and reject expired responses;
|
|
147
|
+
custom stores retain the boolean `renewOutboxLease` API. A custom store implementing
|
|
148
|
+
erasure without optional renew-and-read keeps a window in which the relay can publish an
|
|
149
|
+
envelope claimed before erasure.
|
|
150
|
+
|
|
151
|
+
These row acquisitions keep erasure from waiting on an ordinary row writer while retaining
|
|
152
|
+
its earlier target locks; it cannot supply the waiting edge of such a row-lock deadlock
|
|
153
|
+
cycle. They do not promise freedom from indirect waits in arbitrary application transactions,
|
|
154
|
+
DDL interference, writer-configured timeouts or external transaction-provider behavior.
|
|
155
|
+
Memory mirrors erased outcomes using its transaction queue and synchronous commit; it does
|
|
156
|
+
not provide PostgreSQL's row-level lock footprint.
|
|
157
|
+
|
|
158
|
+
Indexed selection, callbacks, rewrites and audit work use `workTimeoutMs` (default 5000 ms).
|
|
159
|
+
Remaining-budget checks and PostgreSQL statement/idle-transaction timeouts bound SQL and idle
|
|
160
|
+
lock retention. Neither budget preempts synchronous JavaScript or promises a hard real-time
|
|
161
|
+
network deadline. Timeout options accept integer milliseconds from 1 to 60000. Providers
|
|
162
|
+
should commit promptly, preserve original rollback errors and discard failed connections.
|
|
163
|
+
Ordinary query timeouts retain their PostgreSQL identity; database-caused `ErasureBusyError`
|
|
164
|
+
retains its cause.
|
|
165
|
+
|
|
166
|
+
Callers that do not use erasure still pay for the guarded paths. Owned inserts outside a
|
|
167
|
+
supplied mutation transaction take `FOR KEY SHARE` on the owning invocation row. Host adds
|
|
168
|
+
one locking invocation read per transactional event append (`src/host.ts`, `appendEvent`),
|
|
169
|
+
and built-in relays add one renew-and-read round trip per claimed record. A zero-row payload
|
|
170
|
+
write that classifies erasure adds a classification `SELECT`, including retried owned
|
|
171
|
+
duplicate event appends. Conditional boolean/lease writes and ownerless duplicate events
|
|
172
|
+
do not need that classification query.
|
|
173
|
+
|
|
174
|
+
Local PostgreSQL 16.15 measurements of invocation/adapter inserts and updates observed
|
|
175
|
+
approximately +0.05 to +1.6 ms per write, with one 64-KiB adapter-update sample at -0.08 ms.
|
|
176
|
+
The two-client, 600-update case took 842.6 ms baseline and 1135.1 ms with store guards,
|
|
177
|
+
about 35% longer. These compare current store paths with representative migration 1–15
|
|
178
|
+
SQL, including local transport, commit, serialization and hydration; they do not isolate
|
|
179
|
+
lock cost or predict application/cloud latency. Event/outbox write paths and lookup plans
|
|
180
|
+
were not re-measured. Erasure latency is outside these write measurements. Reproduce with
|
|
181
|
+
`FABRIC_ERASURE_MEASURE=1 pnpm test:postgres`; see `tests/erasure-measurements.ts`,
|
|
182
|
+
`measureErasure`.
|
|
183
|
+
|
|
184
|
+
Erasure removes the invocation `parameterDigest` (SQL `NULL`, including
|
|
185
|
+
`submission_refused` rows). Store-owned rewrites replace
|
|
186
|
+
`authorizationBinding.parameterDigest`, `externalCompletion.digest` and the
|
|
187
|
+
`parameterDigest` of rewritten stage rows with exported `ERASED_DIGEST = "erased"`.
|
|
188
|
+
The sentinel is outside the 64-hex SHA-256 output space and preserves required string
|
|
189
|
+
fields and the stage column's `NOT NULL` constraint. `ERASURE_PROTECTED_PATHS` keeps
|
|
190
|
+
these nested fields out of the callback view and rejects their insertion;
|
|
191
|
+
`redactStoredFields` overwrites them after merging protected structure. The stores
|
|
192
|
+
remove or replace top-level digests in the row rewrite, alongside its erasure stamp.
|
|
193
|
+
Repeating erasure leaves these digest fields absent or set to the same sentinel.
|
|
194
|
+
|
|
195
|
+
Private proposal/event comparison columns, memory maps and equality ports are removed.
|
|
196
|
+
Migration 16 is edited in place because it has not been published; migrations 1–15
|
|
197
|
+
retain their SQL. `packages/platform-host/tests/erasure-digest-cases.ts` checks raw records in both stores,
|
|
198
|
+
including repeat erasure, and `erasureChecks` checks the four digest outcomes.
|
|
199
|
+
|
|
200
|
+
Host keyed resubmission and recorded-refusal paths evaluate retained actor, binding ID
|
|
201
|
+
and action-version conflicts first. An enforce-mode conflict raises
|
|
202
|
+
`IdempotencyConflictError`; otherwise an erased row raises `StoredRecordsErasedError`,
|
|
203
|
+
including in audit-only mode, before the legacy callback or redacted-result return.
|
|
204
|
+
A caller that is itself refused while the key holds an erased row is handled separately:
|
|
205
|
+
against an erased recorded refusal, a retained-identity conflict leaves the caller's own
|
|
206
|
+
refusal in place and a matching identity raises `StoredRecordsErasedError`; an erased row
|
|
207
|
+
of any other status leaves the caller's own refusal in place.
|
|
208
|
+
`createDurableSagaParentLifecycle` preserves its event-type conflict check, then refuses
|
|
209
|
+
an erased prior event before comparing payloads. Erasure-capable custom stores expose
|
|
210
|
+
`storedRecordsErased` on the mutation transaction's `getEvent` result.
|
|
211
|
+
Store batch-replay paths refuse erased stage rows before digest comparisons, including
|
|
212
|
+
an origin stage erased with its child before child-ID attachment.
|
|
213
|
+
`packages/platform-host/tests/erasure-digest-cases.ts` pins same/different payload refusals and unchanged events.
|
|
214
|
+
|
|
215
|
+
Host overwrites only the digests it computes itself. A hash that another package or the
|
|
216
|
+
application places inside stored evidence is shown to the redactor and is kept unless the
|
|
217
|
+
redactor removes it. `@fabricorg/policy-opa` stores one by default: `inputHash`, a SHA-256
|
|
218
|
+
of the policy input, in the policy outcome's engine metadata. Remove it in the redactor
|
|
219
|
+
when the policy input can contain erased values, or configure the evaluator's `hashInput`.
|
|
220
|
+
|
|
221
|
+
The staged `batchDigest` formula now covers parent ID and sorted keys, actions,
|
|
222
|
+
versions and optional principals, excluding parameters and parameter digests.
|
|
223
|
+
Migration 16 replaces persisted `batch_digest` values with `LEGACY_BATCH_DIGEST`.
|
|
224
|
+
Custom `PlatformHostStore` implementations persisting stages should overwrite stored
|
|
225
|
+
batch digests with that placeholder and skip only the batch-digest comparison for
|
|
226
|
+
those rows; the remaining request identity and batch-size comparisons still apply.
|
|
227
|
+
`stagedInvocationRequestMatches` and `LEGACY_BATCH_DIGEST` are exported from
|
|
228
|
+
`@fabricorg/platform-host` for this comparison.
|
|
229
|
+
During a rolling upgrade, an old Host can write payload-covering digests after the
|
|
230
|
+
migration runs. Finish the rollout before relying on this guarantee, and replace
|
|
231
|
+
any such late-written digests with the placeholder.
|
|
232
|
+
Erasure replaces external reconciliation IDs with fresh random `rec_` IDs, including
|
|
233
|
+
on repeated erasure, following the existing reapplication of the redactor.
|
|
234
|
+
See `packages/platform-host/tests/erasure-digests.test.ts` and
|
|
235
|
+
`packages/platform-host/tests/staged-invocations.test.ts` for regression coverage.
|
|
236
|
+
|
|
237
|
+
Application hashes outside the protected Host paths remain visible to the redactor.
|
|
238
|
+
|
|
239
|
+
An older Host reading the missing invocation digest treats the erased row as a legacy
|
|
240
|
+
record and can accept a changed request under its existing key. This is an additional
|
|
241
|
+
reason to upgrade Host instances sharing storage before the first erasure; older writers
|
|
242
|
+
also bypass the erasure guards.
|
|
243
|
+
|
|
244
|
+
Store SQL guards fence later writes with typed `StoredRecordsErasedError`. Conditional settled and
|
|
245
|
+
adapter evidence writes return `false` in both stores. Late approval recording retains its
|
|
246
|
+
normal outcome without writing attempt evidence for an erased invocation.
|
|
247
|
+
`ExternalCompletionRefusal` gains `erased`; exhaustive switches must handle it. External
|
|
248
|
+
completion refuses before supplied payload access. Requeue retains redacted prior errors
|
|
249
|
+
and withholds fresh reason text; late publisher error text is discarded. Existing custom
|
|
250
|
+
base stores keep compiling; unsupported erasure checks report skipped.
|
|
251
|
+
|
|
252
|
+
Applications authorize operator calls and supply pure synchronous redactors. Payloads
|
|
253
|
+
handed off before commit cannot be recalled. Backups, downstream systems and application
|
|
254
|
+
data require separate erasure procedures.
|
|
255
|
+
|
|
256
|
+
- 0d4204e: Add the separate `ApprovalDecisionRecordingHost.recordApprovalDecision` capability for HTTP
|
|
257
|
+
approval endpoints. Approved decisions commit to pending without executing handlers or adapters;
|
|
258
|
+
denials retain failed settlement. Scoped locked classification and optional events/outbox writes
|
|
259
|
+
commit together. PostgreSQL requires a transaction provider, with no non-atomic fallback.
|
|
260
|
+
|
|
261
|
+
Persist caller-stable request ids and recording attempt counts in decision JSON. Matching applied
|
|
262
|
+
retries preserve their original verdict after worker execution; contradictory verdicts or approvers
|
|
263
|
+
are already decided. The first post-approval claim uses approval_resume, excludes the earlier
|
|
264
|
+
parking count from that run's recovery budget and permits the approved non-idempotent first run.
|
|
265
|
+
Later claims compare their absolute attempt count to recoveryMaxAttempts, without subtraction,
|
|
266
|
+
and keep recovery checks and attempt history. Computed approval-resume executions retain
|
|
267
|
+
leased governance retry behavior; the existing inline resume override is unchanged.
|
|
268
|
+
|
|
269
|
+
Add opt-in ApprovalDecisionRefused events with invocation identity plus a SHA-256 digest of the
|
|
270
|
+
exact request id (digestParameters), preserving punctuation through lifecycleId sanitization.
|
|
271
|
+
Store event-id deduplication retains a refused request's first event. The factory runs after any
|
|
272
|
+
update with the pre-patch row; payloads carry scoped late approver identity without reason,
|
|
273
|
+
evidence or parameters. Non-applied outcomes omit the stored decision from the API result.
|
|
274
|
+
For different request ids, authorization refusal precedes existing-decision classification.
|
|
275
|
+
Previously expired rows with approvalExpiry and no decision return expired without another patch,
|
|
276
|
+
including authorized late retries and rows expired by a sweep; these remain replayed: false.
|
|
277
|
+
An unresolved waiting action returns unsupported without changing the row, with or without a
|
|
278
|
+
deadline. It skips approval authorization because the invocation remains unchanged; inline resume
|
|
279
|
+
retains its unknown-action settlement. After commit, an applied denial or expiry emits
|
|
280
|
+
invocation.failed telemetry. Recording stores return an applied flag so replays and unchanged
|
|
281
|
+
rows do not emit that transition again. Approval queues pending without a recording-time status
|
|
282
|
+
event; execution telemetry starts when the worker executes it. Keep inline resume and handwritten-host
|
|
283
|
+
compatibility. Saga-parent approvals are unsupported. Authorization still runs before the store
|
|
284
|
+
transaction (#141). Upgrade workers before calling the new API: older workers mishandle recorded
|
|
285
|
+
approvals' attempt/reason semantics. Hosts without a worker must arrange pending-row dispatch;
|
|
286
|
+
executeInvocation is not a concurrent-safe targeted claim.
|
|
287
|
+
|
|
288
|
+
Inline approval persistence allowlists documented decision fields, excluding caller-supplied
|
|
289
|
+
requestId and recordedAtAttempt so an interrupted inline execution cannot acquire the recording
|
|
290
|
+
path's first-claim exemption. Recording takes its attempt marker from the locked invocation row.
|
|
291
|
+
|
|
292
|
+
- 1e46ff0: Add opt-in `idempotency.recordRefusals` to reserve keyed terminal submission refusals.
|
|
293
|
+
The new `submission_refused` status is inert, and refusal identity includes actor type.
|
|
294
|
+
Defaults retain the free-key refusal behavior. Admission-declaring actions omit refusal
|
|
295
|
+
digests to preserve their pre-admission parameter boundary; refusal rows store fixed evidence
|
|
296
|
+
without parameters, proposal or provenance attributes. Recorded errors confirm persistence,
|
|
297
|
+
and store failures surface unchanged. Apply migration 15 and upgrade all hosts sharing a
|
|
298
|
+
database before activation. Unauthorized callers can occupy keys, and callbacks returning
|
|
299
|
+
false during outages can permanently reserve them. Refusal codes must be fixed action codes.
|
|
300
|
+
|
|
301
|
+
With recording enabled, an empty string is a present idempotency key. Stores preserve empty
|
|
302
|
+
key and authorization-binding identities on hydration, and memory insertion arbitrates empty
|
|
303
|
+
keys consistently with PostgreSQL. Default Host submissions keep their keyless empty-string behavior.
|
|
304
|
+
|
|
305
|
+
Generic creation and status-update methods reject `submission_refused` as a write input;
|
|
306
|
+
the narrow refusal insert owns new refusal rows and their fixed payloads.
|
|
307
|
+
|
|
308
|
+
Validate request-only metadata before recording an eligible refusal so malformed submissions
|
|
309
|
+
leave their keys free. The public tenant-isolation kit adds an optional recorded-refusal scope
|
|
310
|
+
check, including ordinary creation against a refusal in another scope. Its result list gains
|
|
311
|
+
`fabric.tenancy.submission-refusal-scoped.v1`; stores without the method skip that check.
|
|
312
|
+
A PostgreSQL store must have migration 15 applied (`ensureSchema()`) before running the kit, or the new check fails.
|
|
313
|
+
|
|
314
|
+
- 8644cc5: Add optional transaction-bound execution and approval authority hooks. Execution checks run after
|
|
315
|
+
state-machine validation directly before handler effects on both atomic and legacy transaction
|
|
316
|
+
paths. Approval checks run after the invocation row is locked and classified directly before a
|
|
317
|
+
decision write. False, thrown and non-boolean results commit nothing; approval stores advertise the
|
|
318
|
+
new transactional authorization capability. Existing pre-transaction callbacks remain unchanged.
|
|
319
|
+
|
|
320
|
+
A throw from the execution hook settles the invocation as `failed` and is not retried, including a
|
|
321
|
+
`RetryableExecutionError`. The execution hook shares the handler's transaction only on a store with
|
|
322
|
+
`transactionWithEvents`, and it does not run before a finalizing action's `finalize` transaction.
|
|
323
|
+
|
|
324
|
+
## 8.8.0
|
|
325
|
+
|
|
326
|
+
### Minor Changes
|
|
327
|
+
|
|
328
|
+
- 385a989: Expose the optional execution lease owner and token in adapter execution context, using the same frozen identity as Host write fencing and omitting the key for unleased execution. Platform Host 8.8.0 is the first Host that supplies it, so with an older Host the key is also absent: an adapter that requires fencing must treat a missing lease as "cannot fence", not as "safe". Every new claim of the invocation, including a takeover by another worker, rotates the token. Adapters can check this evidence in the transaction that claims their domain row immediately before a provider call; Host does not check the lease during the adapter call.
|
|
329
|
+
|
|
3
330
|
## 8.7.0
|
|
4
331
|
|
|
5
332
|
### Minor Changes
|