@@ -89,7 +89,8 @@ describe('executeFunctionExecute table mounts', () => {
8989 mockExecuteTool . mockResolvedValue ( { success : true } )
9090 mockGetTableById . mockResolvedValue ( table )
9191 mockIsFeatureEnabled . mockResolvedValue ( false )
92- mockQueryRows . mockResolvedValue ( { rows : [ { data : { name : 'Ada' } } ] } )
92+ // Row data is keyed by stable column id at rest, not display name.
93+ mockQueryRows . mockResolvedValue ( { rows : [ { data : { col_name : 'Ada' } } ] } )
9394 mockHasCloudStorage . mockReturnValue ( true )
9495 mockGeneratePresignedDownloadUrl . mockResolvedValue ( 'https://s3.example/presigned?sig=abc' )
9596 } )
@@ -104,6 +105,53 @@ describe('executeFunctionExecute table mounts', () => {
104105 expect ( files [ 0 ] . content ) . toBe ( 'name\nAda' )
105106 } )
106107
108+ it ( 'mounts CSV with display-name headers and id-keyed values, never column ids' , async ( ) => {
109+ mockGetTableById . mockResolvedValue ( {
110+ id : 'tbl_2' ,
111+ workspaceId : 'ws_1' ,
112+ rowCount : 2 ,
113+ schema : {
114+ columns : [
115+ { id : 'col_name' , name : 'name' , type : 'string' } ,
116+ { id : 'col_company' , name : 'company' , type : 'string' } ,
117+ ] ,
118+ } ,
119+ } )
120+ mockQueryRows . mockResolvedValue ( {
121+ rows : [
122+ { data : { col_name : 'Ada' , col_company : 'Analytical Engine' } } ,
123+ { data : { col_name : 'Grace' , col_company : 'Navy, Inc' } } ,
124+ ] ,
125+ } )
126+
127+ await executeFunctionExecute ( { inputTables : [ 'tbl_2' ] } , context as never )
128+
129+ const csv = mountedFiles ( ) [ 0 ] . content as string
130+ const lines = csv . split ( '\n' )
131+ expect ( lines [ 0 ] ) . toBe ( 'name,company' )
132+ expect ( lines [ 1 ] ) . toBe ( 'Ada,Analytical Engine' )
133+ // Value containing a comma is quoted.
134+ expect ( lines [ 2 ] ) . toBe ( 'Grace,"Navy, Inc"' )
135+ // No stable column id leaks into the mounted file.
136+ expect ( csv ) . not . toContain ( 'col_name' )
137+ expect ( csv ) . not . toContain ( 'col_company' )
138+ } )
139+
140+ it ( 'reads values by column id for legacy name-keyed rows too' , async ( ) => {
141+ // Legacy column with no id: getColumnId falls back to name, so name-keyed data is correct.
142+ mockGetTableById . mockResolvedValue ( {
143+ id : 'tbl_legacy' ,
144+ workspaceId : 'ws_1' ,
145+ rowCount : 1 ,
146+ schema : { columns : [ { name : 'email' , type : 'string' } ] } ,
147+ } )
148+ mockQueryRows . mockResolvedValue ( { rows : [ { data : { email : 'a@b.com' } } ] } )
149+
150+ await executeFunctionExecute ( { inputTables : [ 'tbl_legacy' ] } , context as never )
151+
152+ expect ( mountedFiles ( ) [ 0 ] . content ) . toBe ( 'email\na@b.com' )
153+ } )
154+
107155 it ( 'flag ON + cloud storage: mounts by presigned URL, no bytes through web' , async ( ) => {
108156 mockIsFeatureEnabled . mockImplementation ( snapshotCacheOn )
109157 mockGetOrCreateTableSnapshot . mockResolvedValue ( {
0 commit comments