Skip to content

Commit 4ef1949

Browse files
committed
fix(data): validate packed row graph remapping
1 parent 55c8be2 commit 4ef1949

2 files changed

Lines changed: 132 additions & 0 deletions

File tree

scripts/nanochat_data/pack_enriched_rows.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,43 @@ def _normalize_changed_chunk_spans(value: Any) -> list[tuple[int, int]]:
364364
return spans
365365

366366

367+
def _validate_chunk_graph_references(
368+
*,
369+
source_doc_index: int,
370+
chunk_count: int,
371+
call_edges: list[dict[str, int]],
372+
type_edges: list[dict[str, int]],
373+
changed_chunk_ids: list[int],
374+
) -> None:
375+
has_graph_metadata = bool(call_edges or type_edges or changed_chunk_ids)
376+
if has_graph_metadata and chunk_count == 0:
377+
raise ValueError(
378+
"graph/chunk metadata requires non-empty token_chunk_* layout "
379+
f"for source_doc_index={source_doc_index}"
380+
)
381+
382+
for column, edges in (
383+
(TOKEN_CALL_EDGES_COLUMN, call_edges),
384+
(TOKEN_TYPE_EDGES_COLUMN, type_edges),
385+
):
386+
for edge in edges:
387+
src = int(edge["from"])
388+
dst = int(edge["to"])
389+
if not (0 <= src < chunk_count and 0 <= dst < chunk_count):
390+
raise ValueError(
391+
f"{column} edge out of range for source_doc_index={source_doc_index}: "
392+
f"got ({src}, {dst}) with chunk_count={chunk_count}"
393+
)
394+
395+
for chunk_id in changed_chunk_ids:
396+
if not (0 <= int(chunk_id) < chunk_count):
397+
raise ValueError(
398+
f"{CHANGED_CHUNK_IDS_COLUMN} out of range for "
399+
f"source_doc_index={source_doc_index}: got {chunk_id} "
400+
f"with chunk_count={chunk_count}"
401+
)
402+
403+
367404
def _normalize_chronology(record: dict[str, Any]) -> dict[str, Any]:
368405
chronology: dict[str, Any] = {
369406
REPO_COLUMN: record.get(REPO_COLUMN),
@@ -469,6 +506,13 @@ def _normalize_chunk_meta(
469506
f"for source_doc_index={source_doc_index}: expected equal lengths, got "
470507
f"{len(changed_chunk_ids)} and {len(changed_chunk_spans)}"
471508
)
509+
_validate_chunk_graph_references(
510+
source_doc_index=source_doc_index,
511+
chunk_count=len(starts),
512+
call_edges=call_edges,
513+
type_edges=type_edges,
514+
changed_chunk_ids=changed_chunk_ids,
515+
)
472516
for start, end in changed_chunk_spans:
473517
if not (0 <= start < end <= token_count):
474518
raise ValueError(

tests/test_pack_enriched_rows.py

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
from cppmega_mlx.data.parquet_dataset import TokenParquetDataset
99
from cppmega_mlx.data.nanochat_pipeline.platform_vocab import MAX_PLATFORM_IDS
1010
from cppmega_mlx.data.nanochat_pipeline.tokenized_enriched_schema import (
11+
CHANGED_CHUNK_IDS_COLUMN,
12+
CHANGED_CHUNK_SPANS_COLUMN,
1113
PLATFORM_IDS_COLUMN,
1214
TOKEN_AST_DEPTH_COLUMN,
1315
TOKEN_CALL_EDGES_COLUMN,
@@ -18,6 +20,7 @@
1820
TOKEN_DEP_LEVELS_COLUMN,
1921
TOKEN_IDS_COLUMN,
2022
TOKEN_STRUCTURE_IDS_COLUMN,
23+
TOKEN_TYPE_EDGES_COLUMN,
2124
)
2225
from scripts.nanochat_data.pack_enriched_rows import (
2326
DOC_IDS_COLUMN,
@@ -50,6 +53,9 @@ def _doc(
5053
token_chunk_kinds: list[int] | None = None,
5154
token_chunk_dep_levels: list[int] | None = None,
5255
token_call_edges: list[dict[str, int]] | None = None,
56+
token_type_edges: list[dict[str, int]] | None = None,
57+
changed_chunk_ids: list[int] | None = None,
58+
changed_chunk_spans: list[dict[str, int]] | None = None,
5359
) -> dict[str, object]:
5460
return {
5561
TOKEN_IDS_COLUMN: list(token_ids),
@@ -62,6 +68,9 @@ def _doc(
6268
TOKEN_CHUNK_KINDS_COLUMN: list(token_chunk_kinds or []),
6369
TOKEN_CHUNK_DEP_LEVELS_COLUMN: list(token_chunk_dep_levels or []),
6470
TOKEN_CALL_EDGES_COLUMN: list(token_call_edges or []),
71+
TOKEN_TYPE_EDGES_COLUMN: list(token_type_edges or []),
72+
CHANGED_CHUNK_IDS_COLUMN: list(changed_chunk_ids or []),
73+
CHANGED_CHUNK_SPANS_COLUMN: list(changed_chunk_spans or []),
6574
}
6675

6776

@@ -147,6 +156,8 @@ def test_pack_documents_carries_token_and_chunk_metadata_with_offsets() -> None:
147156
token_chunk_ends=[2],
148157
token_chunk_kinds=[4],
149158
token_chunk_dep_levels=[1],
159+
changed_chunk_ids=[0],
160+
changed_chunk_spans=[{"start": 0, "end": 2}],
150161
),
151162
_doc(
152163
[10, 11, 12],
@@ -159,6 +170,9 @@ def test_pack_documents_carries_token_and_chunk_metadata_with_offsets() -> None:
159170
token_chunk_kinds=[1, 2],
160171
token_chunk_dep_levels=[0, 2],
161172
token_call_edges=[{"from": 1, "to": 0}],
173+
token_type_edges=[{"from": 0, "to": 1}],
174+
changed_chunk_ids=[1],
175+
changed_chunk_spans=[{"start": 1, "end": 3}],
162176
),
163177
]
164178
)
@@ -176,6 +190,80 @@ def test_pack_documents_carries_token_and_chunk_metadata_with_offsets() -> None:
176190
assert row[TOKEN_CHUNK_KINDS_COLUMN] == [4, 1, 2]
177191
assert row[TOKEN_CHUNK_DEP_LEVELS_COLUMN] == [1, 0, 2]
178192
assert row[TOKEN_CALL_EDGES_COLUMN] == [{"from": 2, "to": 1}]
193+
assert row[TOKEN_TYPE_EDGES_COLUMN] == [{"from": 1, "to": 2}]
194+
assert row[CHANGED_CHUNK_IDS_COLUMN] == [0, 2]
195+
assert row[CHANGED_CHUNK_SPANS_COLUMN] == [
196+
{"start": 0, "end": 2},
197+
{"start": 3, "end": 5},
198+
]
199+
200+
201+
@pytest.mark.parametrize(
202+
("edge_column", "edge"),
203+
[
204+
(TOKEN_CALL_EDGES_COLUMN, {"from": 0, "to": 1}),
205+
(TOKEN_TYPE_EDGES_COLUMN, {"from": 1, "to": 0}),
206+
],
207+
)
208+
def test_normalize_document_record_rejects_graph_edges_without_chunk_layout(
209+
edge_column: str,
210+
edge: dict[str, int],
211+
) -> None:
212+
record = _doc([1, 2, 3])
213+
record[edge_column] = [edge]
214+
215+
with pytest.raises(ValueError, match="requires non-empty token_chunk"):
216+
normalize_document_record(record, source_doc_index=0)
217+
218+
219+
@pytest.mark.parametrize(
220+
("edge_column", "edge"),
221+
[
222+
(TOKEN_CALL_EDGES_COLUMN, {"from": 0, "to": 2}),
223+
(TOKEN_TYPE_EDGES_COLUMN, {"from": -1, "to": 0}),
224+
],
225+
)
226+
def test_normalize_document_record_rejects_graph_edges_out_of_chunk_range(
227+
edge_column: str,
228+
edge: dict[str, int],
229+
) -> None:
230+
record = _doc(
231+
[1, 2, 3],
232+
token_chunk_starts=[0],
233+
token_chunk_ends=[3],
234+
token_chunk_kinds=[1],
235+
token_chunk_dep_levels=[0],
236+
)
237+
record[edge_column] = [edge]
238+
239+
with pytest.raises(ValueError, match=f"{edge_column} edge out of range"):
240+
normalize_document_record(record, source_doc_index=0)
241+
242+
243+
def test_normalize_document_record_rejects_changed_chunk_ids_without_chunk_layout() -> None:
244+
record = _doc(
245+
[1, 2, 3],
246+
changed_chunk_ids=[0],
247+
changed_chunk_spans=[{"start": 0, "end": 1}],
248+
)
249+
250+
with pytest.raises(ValueError, match="requires non-empty token_chunk"):
251+
normalize_document_record(record, source_doc_index=0)
252+
253+
254+
def test_normalize_document_record_rejects_changed_chunk_ids_out_of_range() -> None:
255+
record = _doc(
256+
[1, 2, 3],
257+
token_chunk_starts=[0],
258+
token_chunk_ends=[3],
259+
token_chunk_kinds=[1],
260+
token_chunk_dep_levels=[0],
261+
changed_chunk_ids=[1],
262+
changed_chunk_spans=[{"start": 0, "end": 1}],
263+
)
264+
265+
with pytest.raises(ValueError, match=f"{CHANGED_CHUNK_IDS_COLUMN} out of range"):
266+
normalize_document_record(record, source_doc_index=0)
179267

180268

181269
def test_pack_documents_merges_mixed_platform_ids_for_packed_row() -> None:

0 commit comments

Comments
 (0)