Skip to content

[finding] ImportRequest.runAutomations declares .default(false) and documents "off by default for bulk", but POST /data/:object/import defaults it ON #6704

Description

@qq9340100

Observation-class finding, recorded while documenting the import dry-run hook boundary (#6537, PR for it links back here). Not fixed there: the fix is a contract call, not a docs edit.

What was measured

packages/spec/src/api/export.zod.ts (ImportRequestSchema, the body schema of POST /api/v1/data/:object/import and of CreateImportJobRequest):

runAutomations: z.boolean().default(false)
  .describe('Fire triggers/hooks for each imported row (off by default for bulk)'),

packages/rest/src/import-prepare.ts:262, the code that actually decides:

// Default ON: automations always ran historically (the engine ignored the
// flag until #2922), so opt-out must be explicit — matches platform
// convention (Salesforce runs triggers on import by default).
const runAutomations = body?.runAutomations !== false;

So an omitted runAutomations runs automations. The declared default and the prose next to it both say the opposite, and both ship: the describe text renders into the published reference page (content/docs/references/api/export.mdx, ImportRequest + CreateImportJobRequest tables), and .default(false) ships in @objectstack/spec's JSON Schema.

Why it is not merely cosmetic

The route never parses its body through ImportRequestSchemaprepareImport reads the raw body — so nothing reconciles the two today. The divergence bites in two directions:

  1. A client or SDK that does parse the request through the schema materializes runAutomations: false from the declared default and sends it explicitly. The server then honours it: automations off, silently, for a caller who set nothing. Same request body in, opposite behaviour, decided by whether the caller validated it.
  2. An author reading the reference page is told bulk import does not fire triggers by default. It does.

This is the declared-versus-enforced shape of Prime Directive #10, on a flag that decides whether user-authored hooks run over a whole spreadsheet.

Dispositions (a contract call — deliberately not guessed here)

  • A. Move the spec to the runtime: .default(true) plus corrected prose. Zero runtime change, but it flips the declared default of a shipped published schema, so it needs a version/level decision and possibly a note for parsing clients.
  • B. Move the runtime to the spec: body?.runAutomations === true. A real behaviour change on a documented-since-数据导入:批量 insert 给 Hook 的输入形状与单条不一致(installFlatInput 失效);「运行自动化与触发器」开关是摆设且默认值应为选中 #2922 default, and it contradicts the reasoning recorded in the import-prepare.ts comment above; almost certainly wrong, listed for completeness.
  • C. Keep both and remove the ambiguity: drop .default() (leave it optional with no declared default) and state the server-side default in the describe text, so the schema stops asserting a default it does not own.

No recommendation is offered without the maintainer's read on who is allowed to parse this schema — that is the fact that decides between A and C.

Not touched by #6537's PR

That PR documents the dry-run boundary on ImportRequest.dryRun and deliberately phrases it as "a dry run with runAutomations: true" rather than naming a default, precisely so it does not have to take a side here.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions