@@ -234,6 +234,15 @@ export interface PerformTableCsvImportParams {
234234 /** IANA zone used to read naive datetimes (Excel/Sheets exports carry no offset). */
235235 timezone : string
236236 requestId ?: string
237+ /**
238+ * The person whose permission group gates any cell this import auto-fires,
239+ * or `null` when no person is behind it. Required with an explicit `null`
240+ * rather than optional, matching `insertDispatch`: an import lands rows, and
241+ * landing rows starts workflow and enrichment cells on the table's workflow
242+ * columns. Threaded from the surface that holds the principal rather than
243+ * re-derived here — the route has already gated the same subject.
244+ */
245+ capabilityGovernedUserId : string | null
237246}
238247
239248export interface TableCsvImportData extends ImportRejectionFields {
@@ -271,8 +280,17 @@ export interface PerformTableCsvImportResult {
271280export async function performTableCsvImport (
272281 params : PerformTableCsvImportParams
273282) : Promise < PerformTableCsvImportResult > {
274- const { table, workspaceId, userId, fileStream, fileName, fallbackDelimiter, mode, timezone } =
275- params
283+ const {
284+ table,
285+ workspaceId,
286+ userId,
287+ fileStream,
288+ fileName,
289+ fallbackDelimiter,
290+ mode,
291+ timezone,
292+ capabilityGovernedUserId,
293+ } = params
276294 const requestId = params . requestId ?? generateRequestId ( )
277295
278296 if ( table . archivedAt ) return fail ( 'Cannot import into an archived table' , 'validation' )
@@ -367,11 +385,11 @@ export async function performTableCsvImport(
367385 workspaceId,
368386 userId,
369387 requestId,
388+ capabilityGovernedUserId,
370389 } )
371390 // Fire trigger + scheduler AFTER the tx commits — both read through the
372391 // global db connection and would otherwise see no rows.
373- /** CSV import is auto-fire: no acting person governs the rows it lands. */
374- dispatchAfterBatchInsert ( finalTable , inserted , requestId , userId , null )
392+ dispatchAfterBatchInsert ( finalTable , inserted , requestId , userId , capabilityGovernedUserId )
375393
376394 logger . info ( `[${ requestId } ] Append CSV imported` , {
377395 tableId : table . id ,
@@ -419,6 +437,16 @@ export async function performTableCsvImport(
419437export interface PerformCreateTableFromCsvParams {
420438 workspaceId : string
421439 userId : string
440+ /**
441+ * The person whose permission group gates any cell this import auto-fires,
442+ * or `null` when no person is behind it. Required with an explicit `null`
443+ * rather than optional, matching `insertDispatch`: an import lands rows, and
444+ * landing rows starts workflow and enrichment cells on the table's workflow
445+ * columns. Threaded from the surface that holds the principal rather than
446+ * re-derived here — the route has already gated the same subject.
447+ */
448+ capabilityGovernedUserId : string | null
449+
422450 /** Multipart file stream. The caller still owns destroying it. */
423451 fileStream : Readable
424452 fileName : string
@@ -462,8 +490,16 @@ export interface PerformCreateTableFromCsvResult {
462490export async function performCreateTableFromCsv (
463491 params : PerformCreateTableFromCsvParams
464492) : Promise < PerformCreateTableFromCsvResult > {
465- const { workspaceId, userId, fileStream, fileName, fallbackDelimiter, folderId, timezone } =
466- params
493+ const {
494+ workspaceId,
495+ userId,
496+ fileStream,
497+ fileName,
498+ fallbackDelimiter,
499+ folderId,
500+ timezone,
501+ capabilityGovernedUserId,
502+ } = params
467503 const requestId = params . requestId ?? generateRequestId ( )
468504
469505 const { delimiter, stream } = await sniffCsvDelimiterFromStream ( fileStream , fallbackDelimiter )
@@ -508,8 +544,7 @@ export async function performCreateTableFromCsv(
508544 rows : coerced as RowData [ ] ,
509545 workspaceId,
510546 userId,
511- /** CSV import is auto-fire: no acting person governs the rows it lands. */
512- capabilityGovernedUserId : null ,
547+ capabilityGovernedUserId,
513548 secretProvenance : coerced . map ( createExactEmptyTableRowSecretProvenance ) ,
514549 } ,
515550 // The created table's rowCount is frozen at 0; pass the running total so the
0 commit comments