11/**
22 * CL-7938: consecutive duplicate system echoes collapse instead of painting
33 * twice, and a deferred session header flushes first when the landing clears.
4+ *
5+ * The duplicate-collapse and FIFO flush-order contracts hold with synthetic
6+ * strings here: the wording of other modules' notices (model picker, wiring)
7+ * is their own copy to pin, not this suite's.
48 */
59import { describe , expect , test } from "bun:test" ;
10+ import { composeSessionHeader } from "./components/session-header.js" ;
611import { withTestRenderer } from "./harness" ;
712import { appendStreamRow } from "./shell/chrome" ;
813import { createAppShell } from "./shell/index" ;
@@ -15,24 +20,27 @@ const OPTIONS = {
1520 wireKeys : false ,
1621} ;
1722
23+ const DUPLICATE_TEXT = "synthetic duplicate notice." ;
24+ const OTHER_TEXT = "synthetic second startup notice." ;
25+
1826describe ( "startup transcript" , ( ) => {
1927 test ( "consecutive duplicate system rows paint once" , async ( ) => {
2028 await withTestRenderer ( async ( h ) => {
2129 const shell = createAppShell ( h . renderer , OPTIONS ) ;
2230 try {
2331 appendStreamRow ( shell , {
2432 role : "system" ,
25- text : "Chose muse-spark." ,
26- meta : "model picker " ,
33+ text : DUPLICATE_TEXT ,
34+ meta : "synthetic source " ,
2735 } ) ;
2836 appendStreamRow ( shell , {
2937 role : "system" ,
30- text : "Chose muse-spark." ,
31- meta : "model picker " ,
38+ text : DUPLICATE_TEXT ,
39+ meta : "synthetic source " ,
3240 } ) ;
3341 expect ( streamRowCount ( shell ) ) . toBe ( 1 ) ;
3442 expect ( shell . streamLog . map ( ( row ) => row . text ) ) . toEqual ( [
35- "Chose muse-spark." ,
43+ DUPLICATE_TEXT ,
3644 ] ) ;
3745 } finally {
3846 shell . dispose ( ) ;
@@ -47,13 +55,13 @@ describe("startup transcript", () => {
4755 for ( let i = 0 ; i < 3 ; i += 1 ) {
4856 appendStreamRow ( shell , {
4957 role : "system" ,
50- text : "Chose muse-spark." ,
51- meta : "model picker " ,
58+ text : DUPLICATE_TEXT ,
59+ meta : "synthetic source " ,
5260 } ) ;
5361 }
5462 expect ( streamRowCount ( shell ) ) . toBe ( 1 ) ;
5563 expect ( shell . streamLog . map ( ( row ) => row . text ) ) . toEqual ( [
56- "Chose muse-spark." ,
64+ DUPLICATE_TEXT ,
5765 ] ) ;
5866 } finally {
5967 shell . dispose ( ) ;
@@ -65,16 +73,65 @@ describe("startup transcript", () => {
6573 await withTestRenderer ( async ( h ) => {
6674 const shell = createAppShell ( h . renderer , OPTIONS ) ;
6775 try {
68- appendStreamRow ( shell , { role : "system" , text : "Chose muse-spark." } ) ;
76+ appendStreamRow ( shell , { role : "system" , text : DUPLICATE_TEXT } ) ;
6977 appendStreamRow ( shell , { role : "user" , text : "hi" } ) ;
70- appendStreamRow ( shell , { role : "system" , text : "Chose muse-spark." } ) ;
71- appendStreamRow ( shell , { role : "system" , text : "Chose muse-spark." } ) ;
72- appendStreamRow ( shell , { role : "tool" , text : "Chose muse-spark." } ) ;
78+ appendStreamRow ( shell , { role : "system" , text : DUPLICATE_TEXT } ) ;
79+ appendStreamRow ( shell , { role : "system" , text : DUPLICATE_TEXT } ) ;
80+ appendStreamRow ( shell , { role : "tool" , text : DUPLICATE_TEXT } ) ;
7381 expect ( shell . streamLog . map ( ( row ) => row . text ) ) . toEqual ( [
74- "Chose muse-spark." ,
82+ DUPLICATE_TEXT ,
7583 "hi" ,
76- "Chose muse-spark." ,
77- "Chose muse-spark." ,
84+ DUPLICATE_TEXT ,
85+ DUPLICATE_TEXT ,
86+ ] ) ;
87+ } finally {
88+ shell . dispose ( ) ;
89+ }
90+ } ) ;
91+ } ) ;
92+
93+ test ( "same-text rows from different writers both paint" , async ( ) => {
94+ await withTestRenderer ( async ( h ) => {
95+ const shell = createAppShell ( h . renderer , OPTIONS ) ;
96+ try {
97+ appendStreamRow ( shell , {
98+ role : "system" ,
99+ text : DUPLICATE_TEXT ,
100+ agent : "synthetic-agent-a" ,
101+ } ) ;
102+ appendStreamRow ( shell , {
103+ role : "system" ,
104+ text : DUPLICATE_TEXT ,
105+ agent : "synthetic-agent-b" ,
106+ } ) ;
107+ expect ( shell . streamLog . map ( ( row ) => row . text ) ) . toEqual ( [
108+ DUPLICATE_TEXT ,
109+ DUPLICATE_TEXT ,
110+ ] ) ;
111+ expect ( shell . agentVoices . size ) . toBe ( 2 ) ;
112+ } finally {
113+ shell . dispose ( ) ;
114+ }
115+ } ) ;
116+ } ) ;
117+
118+ test ( "same-text rows with different meta both paint" , async ( ) => {
119+ await withTestRenderer ( async ( h ) => {
120+ const shell = createAppShell ( h . renderer , OPTIONS ) ;
121+ try {
122+ appendStreamRow ( shell , {
123+ role : "system" ,
124+ text : DUPLICATE_TEXT ,
125+ meta : "synthetic source a" ,
126+ } ) ;
127+ appendStreamRow ( shell , {
128+ role : "system" ,
129+ text : DUPLICATE_TEXT ,
130+ meta : "synthetic source b" ,
131+ } ) ;
132+ expect ( shell . streamLog . map ( ( row ) => row . text ) ) . toEqual ( [
133+ DUPLICATE_TEXT ,
134+ DUPLICATE_TEXT ,
78135 ] ) ;
79136 } finally {
80137 shell . dispose ( ) ;
@@ -86,20 +143,17 @@ describe("startup transcript", () => {
86143 await withTestRenderer ( async ( h ) => {
87144 const shell = createAppShell ( h . renderer , { ...OPTIONS , run : "idle" } ) ;
88145 try {
146+ const header = composeSessionHeader ( {
147+ essentials : "synthetic profile · synthetic model" ,
148+ } ) ;
89149 expect ( isLanding ( shell ) ) . toBe ( true ) ;
90- surfaceSystemNotice (
91- shell ,
92- "corbits code · thegreataxios · muse-spark · yolo" ,
93- ) ;
94- surfaceSystemNotice (
95- shell ,
96- "Permission prompts are disabled by your saved default (/yolo off to re-enable)." ,
97- ) ;
150+ surfaceSystemNotice ( shell , header ) ;
151+ surfaceSystemNotice ( shell , OTHER_TEXT ) ;
98152 expect ( streamRowCount ( shell ) ) . toBe ( 0 ) ;
99153 appendStreamRow ( shell , { role : "user" , text : "first prompt" } ) ;
100154 expect ( shell . streamLog . map ( ( row ) => row . text ) ) . toEqual ( [
101- "corbits code · thegreataxios · muse-spark · yolo" ,
102- "Permission prompts are disabled by your saved default (/yolo off to re-enable)." ,
155+ header ,
156+ OTHER_TEXT ,
103157 "first prompt" ,
104158 ] ) ;
105159 } finally {
0 commit comments