@@ -266,6 +266,69 @@ def test_create_documents_from_splits_with_consecutive_page_breaks(self):
266266 # Should be page 2, not 4, because consecutive page breaks at the end are adjusted
267267 assert documents [1 ].meta ["page_number" ] == 2
268268
269+ def test_create_documents_from_splits_split_idx_start (self ):
270+ """_create_documents_from_splits must set split_idx_start to the character offset of each chunk."""
271+ mock_embedder = Mock ()
272+ splitter = EmbeddingBasedDocumentSplitter (document_embedder = mock_embedder )
273+
274+ text = "First chunk. Second chunk. Third chunk."
275+ splits = ["First chunk. " , "Second chunk. " , "Third chunk." ]
276+ original_doc = Document (content = text )
277+
278+ documents = splitter ._create_documents_from_splits (splits , original_doc )
279+
280+ assert len (documents ) == 3
281+ assert documents [0 ].meta ["split_idx_start" ] == 0
282+ assert documents [1 ].meta ["split_idx_start" ] == len ("First chunk. " )
283+ assert documents [2 ].meta ["split_idx_start" ] == len ("First chunk. " ) + len ("Second chunk. " )
284+ # Cross-check: split_idx_start correctly points into the original text
285+ for doc in documents :
286+ start = doc .meta ["split_idx_start" ]
287+ assert text [start : start + len (doc .content )] == doc .content
288+
289+ def test_run_split_idx_start (self ):
290+ """run() must produce chunks with correct split_idx_start character offsets."""
291+ text = "The sky is blue. The grass is green. The sun is yellow."
292+
293+ # Mock embedder that returns two distinct embedding clusters so the splitter
294+ # finds at least one split point
295+ def mock_run (documents ):
296+ from dataclasses import replace as dc_replace
297+
298+ embeddings = []
299+ for i , doc in enumerate (documents ):
300+ # Two distinct embedding directions — triggers a split
301+ if i < len (documents ) // 2 :
302+ embeddings .append (dc_replace (doc , embedding = [1.0 , 0.0 , 0.0 ]))
303+ else :
304+ embeddings .append (dc_replace (doc , embedding = [0.0 , 1.0 , 0.0 ]))
305+ return {"documents" : embeddings }
306+
307+ mock_embedder = Mock ()
308+ mock_embedder .run = Mock (side_effect = mock_run )
309+
310+ splitter = EmbeddingBasedDocumentSplitter (
311+ document_embedder = mock_embedder , sentences_per_group = 1 , percentile = 0.5 , min_length = 0 , max_length = 10000
312+ )
313+ splitter .warm_up ()
314+
315+ result = splitter .run (documents = [Document (content = text )])
316+ chunks = result ["documents" ]
317+
318+ # All chunks must have split_idx_start
319+ for chunk in chunks :
320+ assert "split_idx_start" in chunk .meta
321+
322+ # split_idx_start must point to the correct position in the original text
323+ for chunk in chunks :
324+ start = chunk .meta ["split_idx_start" ]
325+ assert text [start : start + len (chunk .content )] == chunk .content
326+
327+ # Offsets must be strictly increasing (chunks are non-empty and contiguous)
328+ starts = [c .meta ["split_idx_start" ] for c in chunks ]
329+ assert starts == sorted (starts )
330+ assert starts [0 ] == 0
331+
269332 def test_calculate_embeddings (self ):
270333 mock_embedder = Mock ()
271334
0 commit comments