Package: @objectstack/spec (packages/spec/src/integration/connector-descriptor.ts)
Found while wiring #4354's per-run summaries into connector_action.
The gap
ConnectorActionDescriptor describes an action's shape and nothing about its effect:
export interface ConnectorActionDescriptor {
readonly key: string;
readonly label: string;
readonly description?: string;
readonly inputSchema?: Record<string, unknown>;
readonly outputSchema?: Record<string, unknown>;
}
So crm.push_opportunity and crm.lookup_account are indistinguishable to the runtime. Nothing in the authorable Connector schema fills this in either — registerConnector reads actions for dispatch only.
Why it matters now
#4354 makes every flow run report selected / acted, and selected > 0 AND acted = 0 over consecutive runs is the broken-sweep alert. For a connector_action the platform has to pick one of three answers, and two of them are wrong:
That is correct but weaker than it needs to be. A connector-driven flow currently contributes no signal at all: it can neither confirm work happened nor be flagged for doing none. Every ObjectStack app whose automation runs through connectors is in that blind spot.
Proposal
Let the action declare its effect, and let the runtime count it:
export interface ConnectorActionDescriptor {
readonly key: string;
readonly label: string;
readonly description?: string;
readonly inputSchema?: Record<string, unknown>;
readonly outputSchema?: Record<string, unknown>;
/**
* What the action does upstream. `read` never mutates; `write` does.
* Absent keeps today's behaviour — the run reports the effect as uncountable.
*/
readonly effect?: 'read' | 'write';
}
Then connector_action reports acted: 1 for a successful write, acted: 0 for a read, and falls back to unmeasuredEffect only when the connector declared nothing. Optional on purpose: existing connectors keep working and lose nothing, and declaring it is a strict improvement rather than a migration.
Worth considering alongside it: a count rather than a boolean, for bulk actions that report how many upstream records they touched (outputSchema often already carries one). That can follow — the read/write split is the part that unblocks the alert.
Note the ADR-0076 D12 angle: this is a machine-readable surface that is currently silent rather than wrong, which is the right failure. The proposal is to let it be accurate.
Related: #4354 (the summaries this feeds), #4347 (the silent-failure class both exist to surface).
Package:
@objectstack/spec(packages/spec/src/integration/connector-descriptor.ts)Found while wiring #4354's per-run summaries into
connector_action.The gap
ConnectorActionDescriptordescribes an action's shape and nothing about its effect:So
crm.push_opportunityandcrm.lookup_accountare indistinguishable to the runtime. Nothing in the authorableConnectorschema fills this in either —registerConnectorreadsactionsfor dispatch only.Why it matters now
#4354 makes every flow run report
selected/acted, andselected > 0 AND acted = 0over consecutive runs is the broken-sweep alert. For aconnector_actionthe platform has to pick one of three answers, and two of them are wrong:acted: 0understates a Salesforce create. Every healthy connector-driven sweep then trips the alert, and operators learn to ignore it — which disables the detector for the flows that really are dead.acted: 1overstates a lookup. A sweep whose only "action" is a connector read then looks busy forever, so the alert never fires. That is Surface flow run summaries (selected / acted / skipped) — a scheduled flow that does nothing is currently indistinguishable from one with nothing to do #4354's original bug restored, one layer out.metrics: { unmeasuredEffect: true }, the run summary carries anunmeasuredtally, and the documented alert becameselected > 0 AND acted = 0 AND unmeasured = 0.That is correct but weaker than it needs to be. A connector-driven flow currently contributes no signal at all: it can neither confirm work happened nor be flagged for doing none. Every ObjectStack app whose automation runs through connectors is in that blind spot.
Proposal
Let the action declare its effect, and let the runtime count it:
Then
connector_actionreportsacted: 1for a successfulwrite,acted: 0for aread, and falls back tounmeasuredEffectonly when the connector declared nothing. Optional on purpose: existing connectors keep working and lose nothing, and declaring it is a strict improvement rather than a migration.Worth considering alongside it: a count rather than a boolean, for bulk actions that report how many upstream records they touched (
outputSchemaoften already carries one). That can follow — the read/write split is the part that unblocks the alert.Note the ADR-0076 D12 angle: this is a machine-readable surface that is currently silent rather than wrong, which is the right failure. The proposal is to let it be accurate.
Related: #4354 (the summaries this feeds), #4347 (the silent-failure class both exist to surface).