@@ -116,3 +116,157 @@ describe('buildWorkspaceMd - connected integrations / credentials', () => {
116116 expect ( md ) . toContain ( '## Connected Integrations\n(none)' )
117117 } )
118118} )
119+
120+ describe ( 'buildWorkspaceMd - determinism (prompt-cache stability)' , ( ) => {
121+ it ( 'is byte-identical regardless of input row order' , ( ) => {
122+ const a = buildWorkspaceMd (
123+ baseData ( {
124+ members : [
125+ { name : 'Bob' , email : 'bob@x.com' , permissionType : 'admin' } ,
126+ { name : 'Amy' , email : 'amy@x.com' , permissionType : 'write' } ,
127+ ] ,
128+ workflows : [
129+ { id : 'wf-2' , name : 'Zeta' , isDeployed : false , folderPath : null } ,
130+ { id : 'wf-1' , name : 'Alpha' , isDeployed : true , folderPath : null } ,
131+ ] ,
132+ tables : [
133+ { id : 't-2' , name : 'Orders' , description : null , rowCount : 5 } ,
134+ { id : 't-1' , name : 'Customers' , description : null , rowCount : 9 } ,
135+ ] ,
136+ knowledgeBases : [
137+ { id : 'kb-2' , name : 'Docs' , connectorTypes : [ 'notion' , 'github' ] } ,
138+ { id : 'kb-1' , name : 'Articles' , connectorTypes : [ 'github' , 'notion' ] } ,
139+ ] ,
140+ oauthIntegrations : [
141+ { id : 'c-2' , providerId : 'slack' , displayName : null , role : null } ,
142+ { id : 'c-1' , providerId : 'github' , displayName : null , role : null } ,
143+ ] ,
144+ envVariables : [ 'ZED' , 'API_KEY' ] ,
145+ customTools : [
146+ { id : 'ct-2' , name : 'Beta Tool' } ,
147+ { id : 'ct-1' , name : 'Alpha Tool' } ,
148+ ] ,
149+ mcpServers : [
150+ { id : 'mcp-2' , name : 'Zulu' , url : null , enabled : false } ,
151+ { id : 'mcp-1' , name : 'Mike' , url : 'https://x' , enabled : true } ,
152+ ] ,
153+ skills : [
154+ { id : 'sk-2' , name : 'Writer' , description : 'writes' } ,
155+ { id : 'sk-1' , name : 'Editor' , description : 'edits' } ,
156+ ] ,
157+ jobs : [
158+ {
159+ id : 'j-2' ,
160+ title : 'Nightly' ,
161+ prompt : 'run nightly' ,
162+ cronExpression : '0 0 * * *' ,
163+ status : 'active' ,
164+ lifecycle : 'persistent' ,
165+ sourceTaskName : null ,
166+ } ,
167+ {
168+ id : 'j-1' ,
169+ title : 'Hourly' ,
170+ prompt : 'run hourly' ,
171+ cronExpression : '0 * * * *' ,
172+ status : 'active' ,
173+ lifecycle : 'persistent' ,
174+ sourceTaskName : null ,
175+ } ,
176+ ] ,
177+ } )
178+ )
179+ const b = buildWorkspaceMd (
180+ baseData ( {
181+ members : [
182+ { name : 'Amy' , email : 'amy@x.com' , permissionType : 'write' } ,
183+ { name : 'Bob' , email : 'bob@x.com' , permissionType : 'admin' } ,
184+ ] ,
185+ workflows : [
186+ { id : 'wf-1' , name : 'Alpha' , isDeployed : true , folderPath : null } ,
187+ { id : 'wf-2' , name : 'Zeta' , isDeployed : false , folderPath : null } ,
188+ ] ,
189+ tables : [
190+ { id : 't-1' , name : 'Customers' , description : null , rowCount : 9 } ,
191+ { id : 't-2' , name : 'Orders' , description : null , rowCount : 5 } ,
192+ ] ,
193+ knowledgeBases : [
194+ { id : 'kb-1' , name : 'Articles' , connectorTypes : [ 'notion' , 'github' ] } ,
195+ { id : 'kb-2' , name : 'Docs' , connectorTypes : [ 'github' , 'notion' ] } ,
196+ ] ,
197+ oauthIntegrations : [
198+ { id : 'c-1' , providerId : 'github' , displayName : null , role : null } ,
199+ { id : 'c-2' , providerId : 'slack' , displayName : null , role : null } ,
200+ ] ,
201+ envVariables : [ 'API_KEY' , 'ZED' ] ,
202+ customTools : [
203+ { id : 'ct-1' , name : 'Alpha Tool' } ,
204+ { id : 'ct-2' , name : 'Beta Tool' } ,
205+ ] ,
206+ mcpServers : [
207+ { id : 'mcp-1' , name : 'Mike' , url : 'https://x' , enabled : true } ,
208+ { id : 'mcp-2' , name : 'Zulu' , url : null , enabled : false } ,
209+ ] ,
210+ skills : [
211+ { id : 'sk-1' , name : 'Editor' , description : 'edits' } ,
212+ { id : 'sk-2' , name : 'Writer' , description : 'writes' } ,
213+ ] ,
214+ jobs : [
215+ {
216+ id : 'j-1' ,
217+ title : 'Hourly' ,
218+ prompt : 'run hourly' ,
219+ cronExpression : '0 * * * *' ,
220+ status : 'active' ,
221+ lifecycle : 'persistent' ,
222+ sourceTaskName : null ,
223+ } ,
224+ {
225+ id : 'j-2' ,
226+ title : 'Nightly' ,
227+ prompt : 'run nightly' ,
228+ cronExpression : '0 0 * * *' ,
229+ status : 'active' ,
230+ lifecycle : 'persistent' ,
231+ sourceTaskName : null ,
232+ } ,
233+ ] ,
234+ } )
235+ )
236+ expect ( a ) . toBe ( b )
237+ } )
238+
239+ it ( 'ignores volatile workflow run timestamps' , ( ) => {
240+ const withRun = buildWorkspaceMd (
241+ baseData ( {
242+ workflows : [
243+ {
244+ id : 'wf-1' ,
245+ name : 'Alpha' ,
246+ isDeployed : false ,
247+ folderPath : null ,
248+ lastRunAt : new Date ( '2026-06-18T12:00:00Z' ) ,
249+ } ,
250+ ] ,
251+ } )
252+ )
253+ const withoutRun = buildWorkspaceMd (
254+ baseData ( {
255+ workflows : [ { id : 'wf-1' , name : 'Alpha' , isDeployed : false , folderPath : null } ] ,
256+ } )
257+ )
258+ expect ( withRun ) . toBe ( withoutRun )
259+ expect ( withRun ) . not . toContain ( 'last run' )
260+ } )
261+
262+ it ( 'ignores volatile table row counts' , ( ) => {
263+ const a = buildWorkspaceMd (
264+ baseData ( { tables : [ { id : 't-1' , name : 'Customers' , description : null , rowCount : 1 } ] } )
265+ )
266+ const b = buildWorkspaceMd (
267+ baseData ( { tables : [ { id : 't-1' , name : 'Customers' , description : null , rowCount : 9999 } ] } )
268+ )
269+ expect ( a ) . toBe ( b )
270+ expect ( a ) . not . toContain ( 'rows' )
271+ } )
272+ } )
0 commit comments