# Issue 1781 PushToConnector Authority Contract

Date: 2026-06-03

Status: accepted design contract for #1781; implementation consumers are #1726
and the later durable protocol issues #1782/#1784/#1783.

## Decision

`PushToConnector` v1 uses invoking-user FLS projection for outbound source
values.

The connector action may still be pack-authored and pack-owned, but that trust
only authorizes use of connector metadata and connector callout credentials. It
does not authorize reading arbitrary source-record fields into an outbound
payload. Every source value that reaches a connector outbound body must come
from a projection that the originating user can read through the existing
FieldPermissions source of truth.

## Rejected Alternative

System-context pack-authored mapping authority is rejected for v1. It would make
payloads deterministic across triggering users, but it also means a trusted pack
mapping could export fields the originating user cannot read. That is too broad
for the first public-core connector substrate.

No-user or system-originated executions therefore do not silently inherit
system-context source-value authority. They must fail closed until a later issue
adds an explicit service identity or a separate system-authority mode with its
own audit and authorization contract.

## Verified Design Contract

Governing invariant: every source field consulted by `PushToConnector` outbound
payload construction is authorized by the originating user's FLS projection
before it can affect the payload.

Authority surfaces:

- Flow/action trust gate: only trusted pack-owned `PushToConnector` actions may
  use connector callout authority. L2/customized action rows cannot gain pack
  connector authority by copying config shape.
- Trusted metadata read path: connector mapping metadata used by a trusted
  action must come from the pack-authored mapping source of truth, not from
  effective/admin-customized `_System_ObjectFieldMapping` rows.
- Source-value read authority: direct `SourceField` reads and transform
  expressions must all be checked before use. A hidden source field fails closed
  before body construction.
- Async identity: the originating user at enqueue/dispatch boundary is the
  authority identity. A post-commit dispatcher actor is not a substitute for the
  originating user. If the originating user is absent, v1 fails closed.
- Payload determinism: payloads are deterministic for the same user, source
  record, trusted mapping set, connector profile, and create/update config.
  Payloads are intentionally allowed to differ across users with different FLS.
- Pack/profile authority binding: pack trust authorizes connector metadata and
  profile/credential usage only after the pack/profile binding is validated; it
  does not bypass source-value FLS.

### Optional action-scoped payload projection

`PushToConnector` may receive an optional `payloadSourceFields` action input.
After Flow evaluation it is a comma-separated list of source field API names.
Blank or absent input preserves the complete installed mapping closure, so
existing actions retain their current behavior.

The projection is a strict subset selector, never an alternate mapping source:

- each selected field must occur in the pack-resolved outbound mapping closure;
  unknown, blank, or duplicate entries fail closed before any connector I/O;
- a selected payload requires a finalized remote link and therefore can only
  PATCH an existing remote record; it can never silently turn into a partial
  remote create;
- source-field FLS and transform evaluation run only for the selected mapping
  rows, and target fields/transforms are still taken solely from the installed
  mapping metadata;
- durable PATCH attempts persist the selected source fields in the existing
  PATCH dispatch intent. The worker re-resolves the active full closure, applies
  the persisted subset, and validates the sparse mapping fingerprint before it
  dispatches; the finalized remote-link attestation continues to use the full
  closure;
- selection adds no durable action slot, remote lookup, or extra connector
  request. It performs one bounded in-memory filter over the resolved mapping
  rows and can reduce source-field authorization and payload work.

## Authoring / Install / Runtime Matrix

| Surface | Status | Authoritative validator / resolver | Deterministic gate |
|---|---|---|---|
| Pack install/apply | supported | pack-authored action and mapping validators | reject untrusted/customized mapping authority for trusted connector actions |
| Tenant overlay/reapply | supported only as non-authority overlay | pack-authored mapping SSoT remains authoritative for trusted outbound actions | L2 edits cannot become trusted outbound mappings |
| REST/admin authoring | intentionally unsupported for trusted connector authority | admin-authored rows are L2 and cannot self-promote | trusted action gate rejects custom rows |
| Frontend load/save | out of scope for #1781 | frontend may display metadata but cannot create authority | no new frontend authority path in #1781 |
| Shared API/model shape | supported | `ActionTypePushToConnector` points at this contract | code comment links to this SSoT |
| Runtime evaluation | supported by #1726 implementation | PermissionService / FieldPermissions for source fields; `ConnectorTransformReferencedSourceFields` for transform references | hidden direct or transform-referenced source fields fail before payload construction |
| Scheduled/system execution | intentionally fail-closed in v1 | originating-user identity is required | nil/no-user execution has no outbound source-value authority |
| Migration/warm upgrade | out of scope for #1781 | durable connector state belongs to #1782/#1784/#1783 | #1781 introduces no durable connector state |
| Generated/final-pack drift | supported by verification | source-backed pack verification must reuse the pack-authored mapping SSoT | drift blocks readiness before runtime |

## Downstream Boundary

#1726 must consume this authority choice when it implements the
`PushToConnector` executor, but #1781 does not define executor callout/writeback
behavior, retry state, persistence format, or durable migration behavior.

The only reusable runtime helper added here is
`ConnectorTransformReferencedSourceFields`, which lets the later executor ask
the formula package for every flat source field a valid connector transform
expression reads.

## Current Code Anchor

The current tree does not contain the full `PushToConnector` outbound executor.
This PR therefore lands the authority contract and the reusable formula helper
needed by the later executor: `ConnectorTransformReferencedSourceFields`.
Runtime enforcement belongs in #1726 and must cite this document.
