@fabricorg/platform-host 8.5.0 → 8.7.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 CHANGED
@@ -1,5 +1,21 @@
1
1
  # @fabricorg/platform-host
2
2
 
3
+ ## 8.7.0
4
+
5
+ ### Minor Changes
6
+
7
+ - a28154f: Register Host-owned staged invocation principals, persist their names through recovery, and dispatch children through entitlement, admission, and authorization as the registered actor. PostgreSQL migration 14 adds nullable principal evidence columns and is required before deploying 8.7.0 anywhere staged invocations are used, including principal-less stages. Run `ensureSchema()`, deploy 8.7.0 or later to every process that runs the Host (executes staging parent actions, dispatches stages, or runs the Platform worker) without principal declarations, and only then ship modules that declare principals. An older worker can claim a principal-bearing stage and dispatch it as the parent's actor because it does not read or fence the new principal column.
8
+
9
+ ## 8.6.0
10
+
11
+ ### Minor Changes
12
+
13
+ - 019ba30: Add the agent proposal submission envelope and Host HITL evaluator context with durable invocation identity. Snapshot proposals before awaiting authorization; validate strict approval evidence and support `redactAgentProposal` beside parameter redaction, after admission where declared. Persist and evaluate the redacted envelope, including on recovery and approval resume.
14
+
15
+ Idempotency compares redacted proposals and adds the `agent_proposal` conflict reason, including presence changes and legacy records. Consumers with exhaustive conflict-reason switches must handle the new value.
16
+
17
+ Run `ensureSchema()` to apply PostgreSQL migration 13 (`agent_proposal`) before submitting the first proposal. Inserts without proposals omit the new column. Staged and saga children do not inherit their parent's envelope.
18
+
3
19
  ## 8.5.0
4
20
 
5
21
  ### Minor Changes
package/README.md CHANGED
@@ -1478,6 +1478,17 @@ child schema before the parent transaction commits. `redactActionParameters` run
1478
1478
  the redacted, schema-valid parameters are the only parameters written to the stage record and later
1479
1479
  used to create the child invocation.
1480
1480
 
1481
+ A parent action may select a Host-owned dispatch identity by declaring
1482
+ `stagedInvocationPrincipals`, which maps an allowlisted child action ID to a principal name. Host
1483
+ composition registers those names through `PlatformHostOptions.stagedInvocationPrincipals` with an
1484
+ `actorId` and Platform `ActorType`. A registry-backed Host refuses construction when a referenced
1485
+ name is absent; a resolve-only Host refuses the stage when it encounters an absent registration.
1486
+ The request allowlist remains exactly `key`, `actionId`, and `parameters`, so a handler or finalizer
1487
+ cannot supply `principal`, `actorId`, `actorType`, or an authorization binding. Host snapshots its
1488
+ registration at construction, records the principal name in the staged row, and resolves that
1489
+ durable name at dispatch. If a later Host no longer registers it, dispatch definitively rejects the
1490
+ stage instead of using the parent actor.
1491
+
1481
1492
  Staging requires `transactionWithEvents`, a transaction-scoped `stageInvocations`, and a store whose
1482
1493
  `transactionalStagedInvocations` flag is true. Host construction checks the advertised staged-store
1483
1494
  operations and atomic-store capability: scoped origin lookup, lease-fenced child creation, claim,
@@ -1487,8 +1498,9 @@ execution preflight and interrupts that invocation. For `before_adapters`, the h
1487
1498
  commits with the handler mutation. For `after_adapters`, handler and finalizer requests commit with
1488
1499
  events and the completed parent verdict. A finalizing action retains its handler requests in the
1489
1500
  durable finalization checkpoint. Replaying an identical parent batch is a no-op; any changed key,
1490
- action, version evidence, parameter digest, parameter value, batch size, or batch digest moves the
1491
- parent to reconciliation without changing stored requests.
1501
+ action, version evidence, parameter digest, parameter value, principal name, batch size, or batch
1502
+ digest moves the parent to reconciliation without changing stored requests. Principal-less batches
1503
+ retain their earlier canonical identity and digest.
1492
1504
 
1493
1505
  A pending stage is claimable only while its immutable parent scope matches and the parent is
1494
1506
  `completed`. Parents ending `failed`, `blocked_by_policy`, or `validation_failed` have pending stages
@@ -1500,29 +1512,56 @@ contains an action with a non-empty `stagesInvocations` allowlist. `dispatchStag
1500
1512
  forces a sweep and `dispatchStagedInvocations: false` disables it. A deployment that has no staging
1501
1513
  declarations therefore does not query the migration-11 tables by default.
1502
1514
 
1503
- The child has a Host-only `stagedOrigin` of parent invocation ID plus stage key, backed by a separate
1504
- unique index. It carries no idempotency key, so a public caller cannot pre-claim its identity with a
1505
- staged-looking string. A crash after parent commit is recovered by a later sweep. A crash after child
1506
- creation but before the stage checkpoint resolves the same child by `stagedOrigin`. PostgreSQL
1507
- migration 11 creates `staged_invocations`, adds the nullable origin columns and partial unique index,
1508
- and adds the claim and parent indexes.
1515
+ The child has a Host-only `stagedOrigin` of parent invocation ID plus stage key and, when selected,
1516
+ the durable principal name. `authorizeExecution` can inspect `invocation.stagedOrigin.principal`
1517
+ alongside the child's durable parameters and actor. Public `SubmitActionInput` has no
1518
+ `stagedOrigin`; Host adds it through the internal staged-dispatch path.
1519
+ The lookup and unique index intentionally remain keyed by tenant, space, parent invocation ID, and
1520
+ stage key: one parent stage key identifies one child, while the principal is evidence for that
1521
+ durable intent rather than a second child identity. The child carries no idempotency key, so a public
1522
+ caller cannot pre-claim its identity with a staged-looking string. A crash after parent commit is
1523
+ recovered by a later sweep. A crash after child creation but before stage settlement resolves the
1524
+ same child, including its principal evidence, by `stagedOrigin`. PostgreSQL migration 11 creates the
1525
+ staged tables and origin index; migration 14 adds nullable `principal` and
1526
+ `staged_origin_principal` columns for the staged record and child invocation.
1527
+
1528
+ Migration 14 is a deployment prerequisite for this Host version wherever staged invocations are
1529
+ used, including stages that do not select a principal: the staging and fenced child-insert SQL name
1530
+ the new nullable columns in both cases. Use this rollout order for a shared PostgreSQL database:
1531
+
1532
+ 1. Run `ensureSchema()` and confirm migration 14 (`staged_invocation_principals`) is recorded.
1533
+ 2. Deploy `@fabricorg/platform-host` 8.7.0 or later to every process that runs this Host: processes
1534
+ that execute staging parent actions (including inline execution inside `submitAction`), run
1535
+ `dispatchStagedInvocations`, or run the Platform worker. Keep module principal declarations
1536
+ disabled during this step. An older Host that executes a parent ignores the declaration and
1537
+ stages the child without a principal, so every later dispatch uses the parent's actor.
1538
+ 3. After those processes are upgraded, ship modules that declare `stagedInvocationPrincipals`.
1539
+
1540
+ An older worker can claim a principal-bearing row because its claim query does not filter on the
1541
+ new column. It then reads no principal evidence and can submit the child as the parent's actor; its
1542
+ older fenced insert also does not compare the principal. Depending on which version handles the stage, it can be
1543
+ rejected after its intent is lost or the child can complete under the wrong actor. Running migration
1544
+ 14 before step 2 also matters for principal-less stages because this Host version names the columns
1545
+ when staging and dispatching them.
1509
1546
 
1510
1547
  Each claimed row goes through one settlement sequence (`dispatchStagedRow` in `src/host.ts`):
1511
1548
 
1512
1549
  1. Host renews the claim's lease, skipping the row if the lease is gone, and looks the child up by
1513
- `stagedOrigin` in the parent's tenant and space. Every claim replaces the lease token, so a
1550
+ `stagedOrigin` in the parent's tenant and space. Each claim replaces the lease token, so a
1514
1551
  creation still in flight from an earlier attempt holds an older token and fails the creation
1515
1552
  fence; this lookup therefore settles what earlier attempts did. A child found here goes to step 4
1516
1553
  without the pre-submission checks or any entitlement, authorization, or admission call.
1517
1554
  2. With no child, Host checks that the parent is still `completed` and that the child action is
1518
1555
  still registered, does not require capture-time authority, and accepts the stored parameters. It
1519
- then submits through the shared submission pipeline under the claim's lease token, bounded by
1520
- `submissionTimeoutMs`.
1556
+ resolves any recorded principal against the current Host registration, then submits through the
1557
+ shared submission pipeline under the claim's lease token, bounded by `submissionTimeoutMs`.
1558
+ Entitlement, submission authorization, admission, and execution authorization all evaluate the
1559
+ registered principal just as they do for any other submission.
1521
1560
  3. If that submission's own fenced create returned the child, Host settles with its ID: `dispatched`
1522
1561
  when the handoff succeeded or no dispatcher is configured, otherwise a retry that records the ID
1523
1562
  (`dead_lettered` once the attempt budget is spent). In every other case (a failed pre-submission
1524
1563
  check, a refusal, an error, or a timeout) Host first rotates the lease token with
1525
- `rotateStagedInvocationLease`. The only other possible creator is this attempt's own timed-out
1564
+ `rotateStagedInvocationLease`. The remaining possible creator is this attempt's own timed-out
1526
1565
  submission, which still holds the old token, so after the rotation it can no longer create the
1527
1566
  child and the lookup that follows is authoritative. A child found there goes to step 4. With none,
1528
1567
  a definitive refusal settles `rejected`, and anything else settles for retry or, at the attempt
@@ -1712,3 +1751,40 @@ This capability lives on `OutboxRequeuePlatformHostStore`, which extends `Outbox
1712
1751
  `MemoryPlatformHostStore` and `PostgresPlatformHostStore` implement it, and a custom outbox store
1713
1752
  without it makes the operation throw. PostgreSQL adds migration 5, the
1714
1753
  `fabric_platform.event_outbox_requeues` table, which `ensureSchema()` creates.
1754
+
1755
+ ### Agent proposals and Host evaluator context
1756
+
1757
+ Agent callers can submit `SubmitActionInput.agentProposal` separately from action parameters:
1758
+ `{ confidence, riskTier, agentSessionId, agentRunId, reason, evidence }`. Confidence must be
1759
+ finite; risk tier is `low`, `medium`, or `high`. Session/run IDs must contain non-whitespace
1760
+ text and fit within 256 UTF-16 code units; reason may be empty and is limited to 4096 code
1761
+ units. Evidence uses the approval-decision strict JSON object validation and
1762
+ `MAX_APPROVAL_EVIDENCE_BYTES` (16 KiB). Invalid proposals and proposals from other actor
1763
+ types reject submission before invocation creation through the existing Error rejection path.
1764
+
1765
+ For the submission snapshot, Host reads `agentProposal` once and deeply copies it before
1766
+ its first await, including for actions without `admitSubmission`. The sibling
1767
+ `redactAgentProposal(actionId, proposal)` hook runs beside `redactActionParameters`: after
1768
+ admission for actions declaring `admitSubmission`, otherwise before composition resolution.
1769
+ Its result is validated and copied again. A thrown hook or invalid output rejects submission
1770
+ without creating an invocation, like a thrown parameter-redaction hook. Applications should
1771
+ remove secrets and unnecessary sensitive evidence through this hook before durable storage.
1772
+
1773
+ The redacted proposal is stored on `ActionInvocationRecord` and compared canonically on
1774
+ idempotent re-submission. Differences, including absence versus presence, add the
1775
+ `agent_proposal` conflict reason under the configured `enforce` or `audit-only` mode,
1776
+ including legacy records without parameter digests. Exhaustive conflict-reason switches
1777
+ must handle this new value.
1778
+
1779
+ `hitlEvaluator` receives `HostHitlEvaluatorContext`, extending the portable context with
1780
+ `actionInvocationId` and the durable `invocation` read before evaluation. Proposal fields
1781
+ supply confidence, risk tier, session ID, and run ID individually, falling back to parameters
1782
+ for absent fields. Reason and evidence are available through `invocation.agentProposal`.
1783
+ Approval authorization and resumed execution authorization receive that durable proposal too.
1784
+ Staged and saga children do not inherit a parent's proposal. Approval lifecycle event payloads
1785
+ and Host telemetry do not include the envelope.
1786
+
1787
+ Apply PostgreSQL migration 13 (`agent_proposal`) with `ensureSchema()` before the first
1788
+ proposal submission. Inserts without proposals omit the new column, following the
1789
+ `admitted_at` rollout pattern. Existing migration SQL is unchanged; readers accept legacy
1790
+ rows without a proposal. See `src/postgres-store.ts` (`ensureSchema`, `toActionRecord`).