onec-interactive-runtime-core 0.1.19__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. onec_interactive_runtime_core-0.1.19.dist-info/METADATA +12 -0
  2. onec_interactive_runtime_core-0.1.19.dist-info/RECORD +87 -0
  3. onec_interactive_runtime_core-0.1.19.dist-info/WHEEL +4 -0
  4. onec_interactive_runtime_core-0.1.19.dist-info/licenses/COPYRIGHT +9 -0
  5. onec_interactive_runtime_core-0.1.19.dist-info/licenses/LICENSE +232 -0
  6. onec_interactive_runtime_core-0.1.19.dist-info/licenses/THIRD_PARTY_NOTICES.txt +32 -0
  7. onec_runtime/AGENTS.md +7 -0
  8. onec_runtime/__init__.py +3 -0
  9. onec_runtime/artifacts.py +59 -0
  10. onec_runtime/bootstrap.py +310 -0
  11. onec_runtime/breakpoint_workspace.py +249 -0
  12. onec_runtime/bsl/__init__.py +139 -0
  13. onec_runtime/bsl/diagnostics.py +1046 -0
  14. onec_runtime/bsl/full_ast_worker_projection.py +522 -0
  15. onec_runtime/bsl/generated_semantic_parser.py +6322 -0
  16. onec_runtime/bsl/lexer.py +164 -0
  17. onec_runtime/bsl/module_catalog.py +420 -0
  18. onec_runtime/bsl/module_delta.py +1079 -0
  19. onec_runtime/bsl/module_universe.py +1877 -0
  20. onec_runtime/bsl/notebook_cells.py +232 -0
  21. onec_runtime/bsl/notebook_method_globals.py +74 -0
  22. onec_runtime/bsl/notebook_methods.py +175 -0
  23. onec_runtime/bsl/parser_artifact_identity.py +119 -0
  24. onec_runtime/bsl/parser_target.py +388 -0
  25. onec_runtime/bsl/preprocessor.py +16 -0
  26. onec_runtime/bsl/semantic_lowering.py +1539 -0
  27. onec_runtime/bsl/source_maps.py +2411 -0
  28. onec_runtime/bsl/worker_dependency_resolver.py +289 -0
  29. onec_runtime/bsl/worker_preprocessor.py +247 -0
  30. onec_runtime/bsl/worker_projection_model.py +137 -0
  31. onec_runtime/bsl/worker_reload_source_map.py +1697 -0
  32. onec_runtime/capture.py +113 -0
  33. onec_runtime/capture_source.py +453 -0
  34. onec_runtime/compact_table.py +376 -0
  35. onec_runtime/compact_table_backend.py +500 -0
  36. onec_runtime/config.py +198 -0
  37. onec_runtime/configurator_agent.py +520 -0
  38. onec_runtime/controller_worker.py +400 -0
  39. onec_runtime/credentials.py +18 -0
  40. onec_runtime/epf_container.py +196 -0
  41. onec_runtime/errors.py +205 -0
  42. onec_runtime/experiment.py +130 -0
  43. onec_runtime/extension_bundle.py +944 -0
  44. onec_runtime/extension_lifecycle.py +402 -0
  45. onec_runtime/extension_state.py +222 -0
  46. onec_runtime/fault_injection.py +30 -0
  47. onec_runtime/kernel.py +179 -0
  48. onec_runtime/lease.py +123 -0
  49. onec_runtime/observation.py +287 -0
  50. onec_runtime/performance_profile.py +245 -0
  51. onec_runtime/privacy.py +263 -0
  52. onec_runtime/processes.py +265 -0
  53. onec_runtime/prototype_runtime.py +2644 -0
  54. onec_runtime/rdbg/__init__.py +1 -0
  55. onec_runtime/rdbg/models.py +130 -0
  56. onec_runtime/rdbg/reconnect.py +59 -0
  57. onec_runtime/rdbg/session.py +913 -0
  58. onec_runtime/rdbg/transport.py +138 -0
  59. onec_runtime/rdbg/xml_codec.py +980 -0
  60. onec_runtime/recovery.py +106 -0
  61. onec_runtime/recovery_journal.py +79 -0
  62. onec_runtime/resources/extension/OnecInteractiveRuntime.cfe +0 -0
  63. onec_runtime/resources/extension/extension-manifest.json +108 -0
  64. onec_runtime/runtime_api.py +5272 -0
  65. onec_runtime/runtime_contracts.py +196 -0
  66. onec_runtime/server_worker.py +2034 -0
  67. onec_runtime/session.py +2123 -0
  68. onec_runtime/startup_diagnostics.py +45 -0
  69. onec_runtime/stop_routing.py +65 -0
  70. onec_runtime/supervised_processes.py +232 -0
  71. onec_runtime/supervised_runtime.py +512 -0
  72. onec_runtime/supervisor.py +363 -0
  73. onec_runtime/supervisor_model.py +148 -0
  74. onec_runtime/supervisor_protocol.py +77 -0
  75. onec_runtime/table_materialization.py +471 -0
  76. onec_runtime/table_transfer_backend.py +203 -0
  77. onec_runtime/table_value.py +311 -0
  78. onec_runtime/toolchain.py +730 -0
  79. onec_runtime/value_materialization.py +432 -0
  80. onec_runtime/value_transfer_backend.py +199 -0
  81. onec_runtime/worker_breakpoints.py +1431 -0
  82. onec_runtime/worker_epf.py +313 -0
  83. onec_runtime/worker_epf_template.py +53 -0
  84. onec_runtime/worker_stage_protocol.py +516 -0
  85. onec_runtime/worker_universe.py +3772 -0
  86. onec_runtime_build/__init__.py +1 -0
  87. onec_runtime_build/parser_target_development.py +116 -0
@@ -0,0 +1,2411 @@
1
+ """Immutable identities and coordinate helpers for BSL source maps."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from bisect import bisect_right
6
+ from dataclasses import dataclass, field
7
+ from enum import StrEnum
8
+ from hashlib import sha256
9
+ from hmac import compare_digest, new as hmac_new
10
+ import json
11
+ import re
12
+ from secrets import token_bytes
13
+ from threading import Lock
14
+
15
+
16
+ _SHA256_RE = re.compile(r"^[0-9a-fA-F]{64}$")
17
+ _TEXT_WORK_OBSERVER = None
18
+ _RETAINED_PROOF_KEY = token_bytes(32)
19
+ _SOURCE_MAP_PROOF_KEY = token_bytes(32)
20
+ _WORKER_TEXT_PROOF_KEY = token_bytes(32)
21
+ _RETAINED_CONSTRUCTION_AUTHORITY = object()
22
+ _TRUSTED_TEXT_PROOF_AUTHORITY = object()
23
+ _NORMALIZED_WORKER_AUTHORITY = object()
24
+ _TRUSTED_TEXT_PROOFS: dict[int, _TrustedTextProof] = {}
25
+ _TRUSTED_TEXT_PROOFS_LOCK = Lock()
26
+
27
+
28
+ def _observe_text_work(event: str, width: int) -> None:
29
+ observer = _TEXT_WORK_OBSERVER
30
+ if observer is not None:
31
+ observer(event, width)
32
+
33
+
34
+ def _validate_sha256(value: str) -> None:
35
+ if not isinstance(value, str) or _SHA256_RE.fullmatch(value) is None:
36
+ raise ValueError("source_sha256 must be a 64-character hexadecimal SHA-256 string")
37
+
38
+
39
+ def _require_int(value: object, name: str) -> None:
40
+ if type(value) is not int:
41
+ raise ValueError(f"{name} must be an integer")
42
+
43
+
44
+ def _require_str(value: object, name: str, *, nonempty: bool = False) -> None:
45
+ if type(value) is not str or (nonempty and not value):
46
+ suffix = " and must not be empty" if nonempty else ""
47
+ raise ValueError(f"{name} must be a string{suffix}")
48
+
49
+
50
+ def source_sha256(text: str) -> str:
51
+ """Return the SHA-256 digest of *text* encoded as UTF-8."""
52
+ _require_str(text, "text")
53
+ return sha256(text.encode("utf-8")).hexdigest()
54
+
55
+
56
+ class SourceUnitKind(StrEnum):
57
+ NOTEBOOK_CELL = "notebook_cell"
58
+ MODULE = "module"
59
+ TEST_MODULE = "test_module"
60
+
61
+
62
+ class SourceArtifactKind(StrEnum):
63
+ VISIBLE = "visible"
64
+ WORKER_PROJECTION = "worker_projection"
65
+ STATEMENT_PROJECTION = "statement_projection"
66
+ SEMANTIC_LOWERING = "semantic_lowering"
67
+ COLLECTOR_WRAPPER = "collector_wrapper"
68
+ WORKER_MODULE = "worker_module"
69
+ EXECUTED_BSL = "executed_bsl"
70
+
71
+
72
+ @dataclass(frozen=True, slots=True, order=True)
73
+ class SourceSpan:
74
+ start: int
75
+ end: int
76
+
77
+ def __post_init__(self) -> None:
78
+ _require_int(self.start, "span start")
79
+ _require_int(self.end, "span end")
80
+ if self.start < 0 or self.end < self.start:
81
+ raise ValueError("span must be a nonnegative half-open interval")
82
+
83
+
84
+ @dataclass(frozen=True, slots=True)
85
+ class SourceUnitRef:
86
+ kind: SourceUnitKind
87
+ unit_id: str
88
+ revision: int
89
+ source_sha256: str
90
+
91
+ def __post_init__(self) -> None:
92
+ if type(self.kind) is not SourceUnitKind:
93
+ raise ValueError("kind must be a SourceUnitKind")
94
+ _require_str(self.unit_id, "unit_id", nonempty=True)
95
+ _require_int(self.revision, "revision")
96
+ _validate_sha256(self.source_sha256)
97
+ if self.revision < 0:
98
+ raise ValueError("revision must be nonnegative")
99
+
100
+
101
+ @dataclass(frozen=True, slots=True)
102
+ class SourceArtifactRef:
103
+ kind: SourceArtifactKind
104
+ source_sha256: str
105
+ character_length: int
106
+ line_ending_kind: str
107
+ lowering_semantic_version: str | None = None
108
+ wrapper_semantic_version: str | None = None
109
+ mode: str | None = None
110
+ worker_generation: int | None = None
111
+ worker_manifest_sha256: str | None = None
112
+ export_catalog_sha256: str | None = None
113
+
114
+ def __post_init__(self) -> None:
115
+ if type(self.kind) is not SourceArtifactKind:
116
+ raise ValueError("kind must be a SourceArtifactKind")
117
+ _require_int(self.character_length, "character_length")
118
+ _require_str(self.line_ending_kind, "line_ending_kind")
119
+ for name in (
120
+ "lowering_semantic_version",
121
+ "wrapper_semantic_version",
122
+ "mode",
123
+ ):
124
+ value = getattr(self, name)
125
+ if value is not None:
126
+ _require_str(value, name)
127
+ if self.worker_generation is not None:
128
+ _require_int(self.worker_generation, "worker_generation")
129
+ _validate_sha256(self.source_sha256)
130
+ if self.character_length < 0:
131
+ raise ValueError("character_length must be nonnegative")
132
+ if self.worker_generation is not None and self.worker_generation < 0:
133
+ raise ValueError("worker_generation must be nonnegative")
134
+ for name in ("worker_manifest_sha256", "export_catalog_sha256"):
135
+ value = getattr(self, name)
136
+ if value is not None:
137
+ _validate_sha256(value)
138
+
139
+
140
+ class MappingRelation(StrEnum):
141
+ EXACT = "exact"
142
+ DERIVED = "derived"
143
+ SYNTHETIC = "synthetic"
144
+
145
+
146
+ @dataclass(frozen=True, slots=True)
147
+ class SourceMapSegment:
148
+ generated: SourceSpan
149
+ origin_ref: SourceUnitRef | SourceArtifactRef | None
150
+ origin: SourceSpan | None
151
+ relation: MappingRelation
152
+ synthetic_region: str | None = None
153
+ anchor_ref: SourceUnitRef | SourceArtifactRef | None = None
154
+ anchor_span: SourceSpan | None = None
155
+
156
+ def __post_init__(self) -> None:
157
+ if not isinstance(self.generated, SourceSpan):
158
+ raise ValueError("generated must be a SourceSpan")
159
+ if type(self.relation) is not MappingRelation:
160
+ raise ValueError("relation must be a MappingRelation")
161
+ if self.origin_ref is not None and not isinstance(
162
+ self.origin_ref, (SourceUnitRef, SourceArtifactRef)
163
+ ):
164
+ raise ValueError("origin_ref must be a source reference")
165
+ if self.origin is not None and not isinstance(self.origin, SourceSpan):
166
+ raise ValueError("origin must be a SourceSpan")
167
+ if (self.anchor_ref is None) != (self.anchor_span is None):
168
+ raise ValueError("anchor reference and span must be provided together")
169
+ if self.anchor_ref is not None and not isinstance(
170
+ self.anchor_ref, (SourceUnitRef, SourceArtifactRef)
171
+ ):
172
+ raise ValueError("anchor_ref must be a source reference")
173
+ if self.anchor_span is not None and not isinstance(self.anchor_span, SourceSpan):
174
+ raise ValueError("anchor_span must be a SourceSpan")
175
+ if self.synthetic_region is not None:
176
+ _require_str(self.synthetic_region, "synthetic region", nonempty=True)
177
+
178
+ if self.relation is MappingRelation.SYNTHETIC:
179
+ if self.origin_ref is not None or self.origin is not None:
180
+ raise ValueError("synthetic text must not claim an origin coordinate")
181
+ if self.synthetic_region is None:
182
+ raise ValueError("synthetic text requires a named region")
183
+ else:
184
+ if self.origin_ref is None or self.origin is None:
185
+ raise ValueError("non-synthetic text requires an origin coordinate")
186
+ if self.relation is MappingRelation.EXACT and (
187
+ self.generated.end - self.generated.start != self.origin.end - self.origin.start
188
+ ):
189
+ raise ValueError("exact mapping must preserve one-to-one span lengths")
190
+
191
+
192
+ @dataclass(frozen=True, slots=True)
193
+ class MappedOffset:
194
+ relation: MappingRelation
195
+ unit: SourceUnitRef | None = None
196
+ origin_span: SourceSpan | None = None
197
+ synthetic_region: str | None = None
198
+ anchor_unit: SourceUnitRef | None = None
199
+ anchor_span: SourceSpan | None = None
200
+
201
+ def __post_init__(self) -> None:
202
+ if type(self.relation) is not MappingRelation:
203
+ raise ValueError("relation must be a MappingRelation")
204
+ if self.unit is not None and not isinstance(self.unit, SourceUnitRef):
205
+ raise ValueError("mapped unit must be a SourceUnitRef")
206
+ if self.origin_span is not None and not isinstance(self.origin_span, SourceSpan):
207
+ raise ValueError("mapped origin must be a SourceSpan")
208
+ if self.anchor_unit is not None and not isinstance(self.anchor_unit, SourceUnitRef):
209
+ raise ValueError("mapped anchor unit must be a SourceUnitRef")
210
+ if (self.anchor_unit is None) != (self.anchor_span is None):
211
+ raise ValueError("mapped anchor unit and span must be provided together")
212
+
213
+
214
+ def _artifact_manifest(
215
+ value: SourceArtifactRef,
216
+ *,
217
+ observe: bool = True,
218
+ ) -> dict[str, object]:
219
+ if observe:
220
+ _observe_text_work("map_manifest_allocation", 1)
221
+ return {
222
+ "kind": value.kind.value,
223
+ "source_sha256": value.source_sha256,
224
+ "character_length": value.character_length,
225
+ "line_ending_kind": value.line_ending_kind,
226
+ "lowering_semantic_version": value.lowering_semantic_version,
227
+ "wrapper_semantic_version": value.wrapper_semantic_version,
228
+ "mode": value.mode,
229
+ "worker_generation": value.worker_generation,
230
+ "worker_manifest_sha256": value.worker_manifest_sha256,
231
+ "export_catalog_sha256": value.export_catalog_sha256,
232
+ }
233
+
234
+
235
+ def _reference_manifest(
236
+ value: SourceUnitRef | SourceArtifactRef | None,
237
+ *,
238
+ observe: bool = True,
239
+ ) -> dict[str, object] | None:
240
+ if value is None:
241
+ return None
242
+ if isinstance(value, SourceArtifactRef):
243
+ if observe:
244
+ _observe_text_work("map_manifest_allocation", 1)
245
+ return {
246
+ "reference_kind": "artifact",
247
+ **_artifact_manifest(value, observe=observe),
248
+ }
249
+ if observe:
250
+ _observe_text_work("map_manifest_allocation", 1)
251
+ return {
252
+ "reference_kind": "unit",
253
+ "kind": value.kind.value,
254
+ "unit_id": value.unit_id,
255
+ "revision": value.revision,
256
+ "source_sha256": value.source_sha256,
257
+ }
258
+
259
+
260
+ def _span_manifest(
261
+ value: SourceSpan | None,
262
+ *,
263
+ observe: bool = True,
264
+ ) -> list[int] | None:
265
+ if value is not None and observe:
266
+ _observe_text_work("map_manifest_allocation", 1)
267
+ return None if value is None else [value.start, value.end]
268
+
269
+
270
+ def _proof_uint(mac: object, value: int) -> int:
271
+ if type(value) is not int or value < 0:
272
+ raise ValueError("proof integer must be nonnegative")
273
+ payload = value.to_bytes(max(1, (value.bit_length() + 7) // 8), "big")
274
+ length = len(payload).to_bytes(8, "big", signed=False)
275
+ mac.update(length) # type: ignore[attr-defined]
276
+ mac.update(payload) # type: ignore[attr-defined]
277
+ return len(length) + len(payload)
278
+
279
+
280
+ def _proof_optional_uint(mac: object, value: int | None) -> int:
281
+ marker = b"\x00" if value is None else b"\x01"
282
+ mac.update(marker) # type: ignore[attr-defined]
283
+ return 1 if value is None else 1 + _proof_uint(mac, value)
284
+
285
+
286
+ def _proof_text(mac: object, value: str) -> int:
287
+ payload = value.encode("utf-8")
288
+ width = len(payload).to_bytes(8, "big", signed=False)
289
+ mac.update(width) # type: ignore[attr-defined]
290
+ mac.update(payload) # type: ignore[attr-defined]
291
+ return len(width) + len(payload)
292
+
293
+
294
+ def _proof_optional_text(mac: object, value: str | None) -> int:
295
+ marker = b"\x00" if value is None else b"\x01"
296
+ mac.update(marker) # type: ignore[attr-defined]
297
+ return 1 if value is None else 1 + _proof_text(mac, value)
298
+
299
+
300
+ def _proof_span(mac: object, value: SourceSpan | None) -> int:
301
+ marker = b"\x00" if value is None else b"\x01"
302
+ mac.update(marker) # type: ignore[attr-defined]
303
+ if value is None:
304
+ return 1
305
+ return 1 + _proof_uint(mac, value.start) + _proof_uint(mac, value.end)
306
+
307
+
308
+ def _proof_artifact(mac: object, value: SourceArtifactRef) -> int:
309
+ width = _proof_text(mac, value.kind.value)
310
+ width += _proof_text(mac, value.source_sha256)
311
+ width += _proof_uint(mac, value.character_length)
312
+ width += _proof_text(mac, value.line_ending_kind)
313
+ width += _proof_optional_text(mac, value.lowering_semantic_version)
314
+ width += _proof_optional_text(mac, value.wrapper_semantic_version)
315
+ width += _proof_optional_text(mac, value.mode)
316
+ width += _proof_optional_uint(mac, value.worker_generation)
317
+ width += _proof_optional_text(mac, value.worker_manifest_sha256)
318
+ width += _proof_optional_text(mac, value.export_catalog_sha256)
319
+ return width
320
+
321
+
322
+ def _proof_reference(
323
+ mac: object,
324
+ value: SourceUnitRef | SourceArtifactRef | None,
325
+ ) -> int:
326
+ if value is None:
327
+ mac.update(b"\x00") # type: ignore[attr-defined]
328
+ return 1
329
+ if isinstance(value, SourceArtifactRef):
330
+ mac.update(b"\x01") # type: ignore[attr-defined]
331
+ return 1 + _proof_artifact(mac, value)
332
+ mac.update(b"\x02") # type: ignore[attr-defined]
333
+ width = 1 + _proof_text(mac, value.kind.value)
334
+ width += _proof_text(mac, value.unit_id)
335
+ width += _proof_uint(mac, value.revision)
336
+ width += _proof_text(mac, value.source_sha256)
337
+ return width
338
+
339
+
340
+ def _source_map_structural_proof(
341
+ source_map: SourceMap,
342
+ *,
343
+ observe: bool,
344
+ ) -> bytes:
345
+ if observe:
346
+ _observe_text_work(
347
+ "semantic_structural_segment_visit",
348
+ len(source_map.segments),
349
+ )
350
+ payload = _canonical_source_map_bytes(source_map, observe=False)
351
+ return _source_map_structural_proof_from_canonical(payload)
352
+
353
+
354
+ def _source_map_structural_proof_from_canonical(payload: bytes) -> bytes:
355
+ mac = hmac_new(_SOURCE_MAP_PROOF_KEY, digestmod="sha256")
356
+ _observe_text_work("semantic_structural_hmac_update", 1)
357
+ mac.update(payload)
358
+ return mac.digest()
359
+
360
+
361
+ def _source_map_manifest(
362
+ source_map: SourceMap,
363
+ *,
364
+ observe: bool,
365
+ ) -> dict[str, object]:
366
+ return {
367
+ "generated": _artifact_manifest(source_map.generated, observe=observe),
368
+ "segments": [
369
+ {
370
+ "generated": _span_manifest(segment.generated, observe=observe),
371
+ "origin_ref": _reference_manifest(
372
+ segment.origin_ref,
373
+ observe=observe,
374
+ ),
375
+ "origin": _span_manifest(segment.origin, observe=observe),
376
+ "relation": segment.relation.value,
377
+ "synthetic_region": segment.synthetic_region,
378
+ "anchor_ref": _reference_manifest(
379
+ segment.anchor_ref,
380
+ observe=observe,
381
+ ),
382
+ "anchor_span": _span_manifest(
383
+ segment.anchor_span,
384
+ observe=observe,
385
+ ),
386
+ }
387
+ for segment in source_map.segments
388
+ ],
389
+ }
390
+
391
+
392
+ def _canonical_source_map_bytes(
393
+ source_map: SourceMap,
394
+ *,
395
+ observe: bool,
396
+ ) -> bytes:
397
+ manifest = (
398
+ source_map.to_manifest()
399
+ if observe
400
+ else _source_map_manifest(source_map, observe=False)
401
+ )
402
+ return json.dumps(
403
+ manifest,
404
+ ensure_ascii=False,
405
+ sort_keys=True,
406
+ separators=(",", ":"),
407
+ ).encode("utf-8")
408
+
409
+
410
+ @dataclass(frozen=True, slots=True)
411
+ class SourceMap:
412
+ generated: SourceArtifactRef
413
+ segments: tuple[SourceMapSegment, ...]
414
+ _canonical_manifest_bytes: bytes = field(init=False, repr=False, compare=False)
415
+ _canonical_sha256: str = field(init=False, repr=False, compare=False)
416
+ _structural_proof: bytes = field(init=False, repr=False, compare=False)
417
+
418
+ def __post_init__(self) -> None:
419
+ if not isinstance(self.generated, SourceArtifactRef):
420
+ raise ValueError("generated must be a SourceArtifactRef")
421
+ if type(self.segments) is not tuple or not self.segments:
422
+ raise ValueError("source map requires segments for full generated coverage")
423
+
424
+ cursor = 0
425
+ previous_start = -1
426
+ for segment in self.segments:
427
+ if not isinstance(segment, SourceMapSegment):
428
+ raise ValueError("segments must contain SourceMapSegment values")
429
+ if segment.generated.end > self.generated.character_length:
430
+ raise ValueError("generated segment is out of bounds")
431
+ if segment.generated.start < previous_start or segment.generated.start < cursor:
432
+ raise ValueError("source map segments must be ordered and non-overlapping")
433
+ if segment.generated.start > cursor:
434
+ raise ValueError("source map must provide full generated coverage")
435
+ previous_start = segment.generated.start
436
+ cursor = max(cursor, segment.generated.end)
437
+ for reference, span, name in (
438
+ (segment.origin_ref, segment.origin, "origin"),
439
+ (segment.anchor_ref, segment.anchor_span, "anchor"),
440
+ ):
441
+ if (
442
+ isinstance(reference, SourceArtifactRef)
443
+ and span is not None
444
+ and span.end > reference.character_length
445
+ ):
446
+ raise ValueError(f"segment {name} is out of bounds")
447
+ if cursor != self.generated.character_length:
448
+ raise ValueError("source map must provide full generated coverage")
449
+ _observe_text_work("map_manifest_segment_visit", len(self.segments))
450
+ _observe_text_work("map_manifest_allocation", 2 + len(self.segments))
451
+ payload = _canonical_source_map_bytes(self, observe=True)
452
+ _observe_text_work("map_manifest_serialized_bytes", len(payload))
453
+ _observe_text_work("map_manifest_hash", len(payload))
454
+ object.__setattr__(self, "_canonical_manifest_bytes", payload)
455
+ object.__setattr__(self, "_canonical_sha256", sha256(payload).hexdigest())
456
+ object.__setattr__(
457
+ self,
458
+ "_structural_proof",
459
+ _source_map_structural_proof_from_canonical(payload),
460
+ )
461
+
462
+ def map_offset(self, offset: int) -> MappedOffset:
463
+ return map_offset(self, offset)
464
+
465
+ def to_manifest(self) -> dict[str, object]:
466
+ return _source_map_manifest(self, observe=True)
467
+
468
+ @property
469
+ def source_map_sha256(self) -> str:
470
+ return self._canonical_sha256
471
+
472
+
473
+ def _validate_flattened_map(source_map: SourceMap, *, name: str) -> None:
474
+ if getattr(source_map, "_compact_reload_map", False):
475
+ return
476
+ for segment in source_map.segments:
477
+ if segment.relation is not MappingRelation.SYNTHETIC and not isinstance(
478
+ segment.origin_ref, SourceUnitRef
479
+ ):
480
+ raise ValueError(f"{name} must reference visible source units")
481
+ if segment.anchor_ref is not None and not isinstance(
482
+ segment.anchor_ref, SourceUnitRef
483
+ ):
484
+ raise ValueError(f"{name} anchors must reference visible source units")
485
+
486
+
487
+ @dataclass(frozen=True, slots=True, repr=False)
488
+ class _TrustedTextProof:
489
+ text_object_id: int
490
+ source_sha256: str
491
+ character_length: int
492
+
493
+
494
+ def _mint_trusted_text_proof(
495
+ text: str,
496
+ source_hash: str,
497
+ *,
498
+ authority: object,
499
+ ) -> _TrustedTextProof:
500
+ if authority is not _TRUSTED_TEXT_PROOF_AUTHORITY:
501
+ raise ValueError("trusted text proof authority is invalid")
502
+ proof = _TrustedTextProof(id(text), source_hash, len(text))
503
+ with _TRUSTED_TEXT_PROOFS_LOCK:
504
+ _TRUSTED_TEXT_PROOFS[id(proof)] = proof
505
+ return proof
506
+
507
+
508
+ def _consume_trusted_text_proof(
509
+ proof: object,
510
+ text: str,
511
+ artifact: SourceArtifactRef,
512
+ ) -> bool:
513
+ if not isinstance(proof, _TrustedTextProof):
514
+ return False
515
+ with _TRUSTED_TEXT_PROOFS_LOCK:
516
+ registered = _TRUSTED_TEXT_PROOFS.pop(id(proof), None)
517
+ return bool(
518
+ registered is proof
519
+ and proof.text_object_id == id(text)
520
+ and proof.source_sha256 == artifact.source_sha256
521
+ and proof.character_length == artifact.character_length
522
+ )
523
+
524
+
525
+ @dataclass(frozen=True, slots=True, repr=False)
526
+ class _RetainedTextFragment:
527
+ generated: SourceSpan
528
+ text: str
529
+ retained_source: object | None = None
530
+ retained_span: SourceSpan | None = None
531
+ line_endings: tuple[int, int, int, bool, bool] | None = None
532
+ contains_nul: bool | None = None
533
+
534
+ def __post_init__(self) -> None:
535
+ if (
536
+ not isinstance(self.generated, SourceSpan)
537
+ or type(self.text) is not str
538
+ or len(self.text) != self.generated.end - self.generated.start
539
+ or (self.retained_source is None) != (self.retained_span is None)
540
+ ):
541
+ raise ValueError("retained text fragment is invalid")
542
+ if self.line_endings is None:
543
+ object.__setattr__(self, "line_endings", _line_ending_summary(self.text))
544
+ elif self.line_endings != _line_ending_summary_from_counts(
545
+ self.text,
546
+ self.line_endings,
547
+ ):
548
+ raise ValueError("retained text fragment line-ending summary is invalid")
549
+ if self.contains_nul is not None and type(self.contains_nul) is not bool:
550
+ raise ValueError("retained text fragment NUL summary is invalid")
551
+ _observe_text_work("fragment_allocate", 1)
552
+
553
+
554
+ def _line_ending_summary(text: str) -> tuple[int, int, int, bool, bool]:
555
+ return (
556
+ text.count("\r"),
557
+ text.count("\n"),
558
+ text.count("\r\n"),
559
+ text.startswith("\n"),
560
+ text.endswith("\r"),
561
+ )
562
+
563
+
564
+ def _local_nul_summary(text: str) -> bool:
565
+ _observe_text_work("fragment_nul_scan", len(text))
566
+ return "\x00" in text
567
+
568
+
569
+ def _line_ending_summary_from_counts(
570
+ text: str,
571
+ summary: tuple[int, int, int, bool, bool],
572
+ ) -> tuple[int, int, int, bool, bool]:
573
+ if (
574
+ type(summary) is not tuple
575
+ or len(summary) != 5
576
+ or any(type(value) is not int or value < 0 for value in summary[:3])
577
+ or any(type(value) is not bool for value in summary[3:])
578
+ ):
579
+ raise ValueError("retained text fragment line-ending summary is invalid")
580
+ # Immutable text identity is bound by the retained proof. Avoid rescanning
581
+ # it here; only constant-time edge properties can be checked independently.
582
+ if summary[3] != text.startswith("\n") or summary[4] != text.endswith("\r"):
583
+ raise ValueError("retained text fragment line-ending summary is invalid")
584
+ return summary
585
+
586
+
587
+ def _retained_state_proof(
588
+ artifact: SourceArtifactRef,
589
+ fragments: tuple[_RetainedTextFragment, ...],
590
+ ) -> bytes:
591
+ mac = hmac_new(_RETAINED_PROOF_KEY, digestmod="sha256")
592
+ width = _proof_text(mac, artifact.source_sha256)
593
+ width += _proof_uint(mac, artifact.character_length)
594
+ width += _proof_uint(mac, len(fragments))
595
+ for fragment in fragments:
596
+ _observe_text_work("retained_proof_fragment_visit", 1)
597
+ width += _proof_span(mac, fragment.generated)
598
+ width += _proof_uint(mac, id(fragment.text))
599
+ width += _proof_uint(mac, len(fragment.text))
600
+ width += _proof_optional_uint(
601
+ mac,
602
+ None if fragment.retained_source is None else id(fragment.retained_source),
603
+ )
604
+ width += _proof_span(mac, fragment.retained_span)
605
+ line_endings = fragment.line_endings
606
+ assert line_endings is not None
607
+ width += sum(_proof_uint(mac, value) for value in line_endings[:3])
608
+ for value in line_endings[3:]:
609
+ mac.update(b"\x01" if value else b"\x00")
610
+ width += 1
611
+ mac.update(
612
+ b"\x00"
613
+ if fragment.contains_nul is None
614
+ else b"\x02"
615
+ if fragment.contains_nul
616
+ else b"\x01"
617
+ )
618
+ width += 1
619
+ _observe_text_work("retained_proof_bytes", width)
620
+ return mac.digest()
621
+
622
+
623
+ def _mapped_text_authority_proof(
624
+ artifact: SourceArtifactRef,
625
+ text: str,
626
+ ) -> bytes:
627
+ mac = hmac_new(_RETAINED_PROOF_KEY, digestmod="sha256")
628
+ _proof_text(mac, artifact.source_sha256)
629
+ _proof_uint(mac, artifact.character_length)
630
+ _proof_uint(mac, id(text))
631
+ _proof_uint(mac, len(text))
632
+ return mac.digest()
633
+
634
+
635
+ def _validate_retained_fragments(
636
+ artifact: SourceArtifactRef,
637
+ fragments: object,
638
+ proof: object,
639
+ *,
640
+ construction_authority: object | None = None,
641
+ ) -> tuple[_RetainedTextFragment, ...]:
642
+ _observe_text_work(
643
+ "retained_metadata",
644
+ len(fragments) if isinstance(fragments, tuple) else 0,
645
+ )
646
+ if (
647
+ type(fragments) is not tuple
648
+ or not fragments
649
+ or any(not isinstance(item, _RetainedTextFragment) for item in fragments)
650
+ or fragments[0].generated.start != 0
651
+ or fragments[-1].generated.end != artifact.character_length
652
+ or any(
653
+ current.generated.end != following.generated.start
654
+ for current, following in zip(fragments, fragments[1:], strict=False)
655
+ )
656
+ or not isinstance(proof, bytes)
657
+ or (
658
+ construction_authority is not _RETAINED_CONSTRUCTION_AUTHORITY
659
+ and not compare_digest(proof, _retained_state_proof(artifact, fragments))
660
+ )
661
+ ):
662
+ raise ValueError("retained fragment authority is invalid")
663
+ return fragments
664
+
665
+
666
+ @dataclass(frozen=True, slots=True, weakref_slot=True, repr=False)
667
+ class _DeferredMappedSource:
668
+ artifact: SourceArtifactRef
669
+ source_map: SourceMap
670
+ lineage: tuple[SourceMap, ...]
671
+ local_source_map: SourceMap
672
+ retained_fragments: tuple[_RetainedTextFragment, ...]
673
+ retained_starts: tuple[int, ...]
674
+ _retained_proof: bytes
675
+ _construction_authority: object = field(repr=False, compare=False)
676
+
677
+ def __post_init__(self) -> None:
678
+ retained = _validate_retained_fragments(
679
+ self.artifact,
680
+ self.retained_fragments,
681
+ self._retained_proof,
682
+ construction_authority=self._construction_authority,
683
+ )
684
+ if self._construction_authority is not _RETAINED_CONSTRUCTION_AUTHORITY:
685
+ raise ValueError("retained fragment construction authority is invalid")
686
+ if self.retained_starts != tuple(
687
+ fragment.generated.start for fragment in retained
688
+ ):
689
+ raise ValueError("retained fragment index is invalid")
690
+
691
+ @property
692
+ def character_length(self) -> int:
693
+ return self.artifact.character_length
694
+
695
+
696
+ def _detached_retained_source(
697
+ source: _DeferredMappedSource,
698
+ ) -> _DeferredMappedSource:
699
+ fragments = tuple(
700
+ _RetainedTextFragment(
701
+ fragment.generated,
702
+ fragment.text,
703
+ line_endings=fragment.line_endings,
704
+ contains_nul=fragment.contains_nul,
705
+ )
706
+ for fragment in source.retained_fragments
707
+ )
708
+ return _DeferredMappedSource(
709
+ source.artifact,
710
+ source.source_map,
711
+ source.lineage,
712
+ source.local_source_map,
713
+ fragments,
714
+ tuple(fragment.generated.start for fragment in fragments),
715
+ _retained_state_proof(source.artifact, fragments),
716
+ _RETAINED_CONSTRUCTION_AUTHORITY,
717
+ )
718
+
719
+
720
+ def _validate_retained_source(
721
+ source: MappedSource | _DeferredMappedSource,
722
+ ) -> None:
723
+ if isinstance(source, MappedSource) and not compare_digest(
724
+ source._text_authority_proof,
725
+ _mapped_text_authority_proof(source.artifact, source.text),
726
+ ):
727
+ raise ValueError("mapped text authority is invalid")
728
+ retained = (
729
+ source._retained_fragments
730
+ if isinstance(source, MappedSource)
731
+ else source.retained_fragments
732
+ )
733
+ starts = (
734
+ source._retained_starts
735
+ if isinstance(source, MappedSource)
736
+ else source.retained_starts
737
+ )
738
+ _validate_retained_fragments(
739
+ source.artifact,
740
+ retained,
741
+ source._retained_proof,
742
+ )
743
+ if starts != tuple(fragment.generated.start for fragment in retained):
744
+ raise ValueError("retained fragment index is invalid")
745
+
746
+
747
+ def _validated_mapped_text_hash(source: MappedSource) -> str:
748
+ if (
749
+ not isinstance(source, MappedSource)
750
+ or source.artifact.kind is not SourceArtifactKind.WORKER_MODULE
751
+ or not isinstance(source._worker_text_proof, bytes)
752
+ or not compare_digest(
753
+ source._text_authority_proof,
754
+ _mapped_text_authority_proof(source.artifact, source.text),
755
+ )
756
+ or not compare_digest(
757
+ source._worker_text_proof,
758
+ _normalized_worker_text_proof(source.artifact, source.text),
759
+ )
760
+ ):
761
+ raise ValueError("mapped text authority is invalid")
762
+ return source.artifact.source_sha256
763
+
764
+
765
+ def _retained_fragments_for_span(
766
+ source: MappedSource | _DeferredMappedSource,
767
+ span: SourceSpan,
768
+ *,
769
+ scan_local_nul: bool = True,
770
+ ) -> tuple[_RetainedTextFragment, ...]:
771
+ length = (
772
+ len(source.text)
773
+ if isinstance(source, MappedSource)
774
+ else source.character_length
775
+ )
776
+ if not isinstance(span, SourceSpan) or span.end > length:
777
+ raise ValueError("retained fragment span must be within the source")
778
+ retained = (
779
+ source._retained_fragments
780
+ if isinstance(source, MappedSource)
781
+ else source.retained_fragments
782
+ )
783
+ starts = (
784
+ source._retained_starts
785
+ if isinstance(source, MappedSource)
786
+ else source.retained_starts
787
+ )
788
+ result: list[_RetainedTextFragment] = []
789
+ cursor = span.start
790
+ index = max(0, bisect_right(starts, span.start) - 1)
791
+ while index < len(retained):
792
+ fragment = retained[index]
793
+ index += 1
794
+ if fragment.generated.start >= span.end:
795
+ break
796
+ start = max(fragment.generated.start, span.start)
797
+ end = min(fragment.generated.end, span.end)
798
+ if start >= end:
799
+ continue
800
+ local_start = start - fragment.generated.start
801
+ local_end = end - fragment.generated.start
802
+ if local_start == 0 and local_end == len(fragment.text):
803
+ text = fragment.text
804
+ line_endings = fragment.line_endings
805
+ contains_nul = fragment.contains_nul
806
+ else:
807
+ _observe_text_work("slice", local_end - local_start)
808
+ text = fragment.text[local_start:local_end]
809
+ line_endings = None
810
+ contains_nul = (
811
+ _local_nul_summary(text)
812
+ if scan_local_nul
813
+ else fragment.contains_nul
814
+ )
815
+ retained_span = (
816
+ SourceSpan(start, end)
817
+ if fragment.retained_source is None
818
+ else SourceSpan(
819
+ fragment.retained_span.start + local_start, # type: ignore[union-attr]
820
+ fragment.retained_span.start + local_end, # type: ignore[union-attr]
821
+ )
822
+ )
823
+ result.append(
824
+ _RetainedTextFragment(
825
+ SourceSpan(cursor, cursor + len(text)),
826
+ text,
827
+ source if fragment.retained_source is None else fragment.retained_source,
828
+ retained_span,
829
+ line_endings,
830
+ contains_nul,
831
+ )
832
+ )
833
+ cursor += len(text)
834
+ if cursor != span.end:
835
+ raise ValueError("retained fragments do not cover the requested span")
836
+ return tuple(result)
837
+
838
+
839
+ @dataclass(frozen=True, slots=True, repr=False)
840
+ class _MappedSemanticSummary:
841
+ source_map_sha256: str
842
+ lineage_sha256: str
843
+ source_map_object_id: int
844
+ lineage_object_id: int
845
+ local_source_map_object_id: int | None
846
+ structural_proofs: tuple[tuple[int, bytes], ...]
847
+ authority_proof: bytes
848
+
849
+
850
+ def _canonical_lineage_sha256(lineage: tuple[SourceMap, ...]) -> str:
851
+ digest_value = sha256()
852
+ digest_value.update(b"[")
853
+ width = 2
854
+ for index, source_map in enumerate(lineage):
855
+ if index:
856
+ digest_value.update(b",")
857
+ width += 1
858
+ payload = source_map._canonical_manifest_bytes
859
+ digest_value.update(payload)
860
+ width += len(payload)
861
+ _observe_text_work("semantic_lineage_entry_visit", 1)
862
+ digest_value.update(b"]")
863
+ _observe_text_work("semantic_lineage_serialized_bytes", width)
864
+ _observe_text_work("semantic_lineage_hash", width)
865
+ return digest_value.hexdigest()
866
+
867
+
868
+ def _mapped_semantic_authority_proof(
869
+ artifact: SourceArtifactRef,
870
+ source_map: SourceMap,
871
+ lineage: tuple[SourceMap, ...],
872
+ local_source_map: SourceMap | None,
873
+ source_map_digest: str,
874
+ lineage_digest: str,
875
+ structural_proofs: tuple[tuple[int, bytes], ...],
876
+ ) -> bytes:
877
+ mac = hmac_new(_SOURCE_MAP_PROOF_KEY, digestmod="sha256")
878
+ _proof_artifact(mac, artifact)
879
+ _proof_uint(mac, id(source_map))
880
+ _proof_uint(mac, id(lineage))
881
+ _proof_optional_uint(
882
+ mac,
883
+ None if local_source_map is None else id(local_source_map),
884
+ )
885
+ _proof_text(mac, source_map_digest)
886
+ _proof_text(mac, lineage_digest)
887
+ for object_id, proof in structural_proofs:
888
+ _proof_uint(mac, object_id)
889
+ _proof_uint(mac, len(proof))
890
+ mac.update(proof)
891
+ return mac.digest()
892
+
893
+
894
+ def _build_mapped_semantic_summary(
895
+ artifact: SourceArtifactRef,
896
+ source_map: SourceMap,
897
+ lineage: tuple[SourceMap, ...],
898
+ local_source_map: SourceMap | None,
899
+ ) -> _MappedSemanticSummary:
900
+ maps: list[SourceMap] = []
901
+ for item in (source_map, *lineage, local_source_map):
902
+ if item is not None and all(item is not existing for existing in maps):
903
+ maps.append(item)
904
+ structural_proofs = tuple(
905
+ (id(item), item._structural_proof)
906
+ for item in maps
907
+ )
908
+ source_map_digest = source_map.source_map_sha256
909
+ lineage_digest = _canonical_lineage_sha256(lineage)
910
+ authority_proof = _mapped_semantic_authority_proof(
911
+ artifact,
912
+ source_map,
913
+ lineage,
914
+ local_source_map,
915
+ source_map_digest,
916
+ lineage_digest,
917
+ structural_proofs,
918
+ )
919
+ return _MappedSemanticSummary(
920
+ source_map_digest,
921
+ lineage_digest,
922
+ id(source_map),
923
+ id(lineage),
924
+ None if local_source_map is None else id(local_source_map),
925
+ structural_proofs,
926
+ authority_proof,
927
+ )
928
+
929
+
930
+ def _normalized_worker_text_proof(
931
+ artifact: SourceArtifactRef,
932
+ text: str,
933
+ ) -> bytes:
934
+ mac = hmac_new(_WORKER_TEXT_PROOF_KEY, digestmod="sha256")
935
+ _proof_artifact(mac, artifact)
936
+ _proof_uint(mac, id(text))
937
+ _proof_uint(mac, len(text))
938
+ return mac.digest()
939
+
940
+
941
+ class MappedSource:
942
+ """A private source artifact whose printable state never includes its text."""
943
+
944
+ __slots__ = (
945
+ "__weakref__",
946
+ "_artifact",
947
+ "_lineage",
948
+ "_local_source_map",
949
+ "_semantic_summary",
950
+ "_retained_fragments",
951
+ "_retained_proof",
952
+ "_retained_starts",
953
+ "_source_map",
954
+ "_text",
955
+ "_text_authority_proof",
956
+ "_transform_parent",
957
+ "_worker_text_proof",
958
+ )
959
+
960
+ def __init__(
961
+ self,
962
+ text: str,
963
+ artifact: SourceArtifactRef,
964
+ source_map: SourceMap,
965
+ lineage: tuple[SourceMap, ...] = (),
966
+ local_source_map: SourceMap | None = None,
967
+ *,
968
+ _retained_fragments: tuple[_RetainedTextFragment, ...] | None = None,
969
+ _transform_parent: MappedSource | _DeferredMappedSource | None = None,
970
+ _trusted_source_sha256: str | None = None,
971
+ _trusted_text_proof: _TrustedTextProof | None = None,
972
+ _retained_authority: object | None = None,
973
+ _normalized_worker_authority: object | None = None,
974
+ ) -> None:
975
+ _require_str(text, "mapped source text")
976
+ if not isinstance(artifact, SourceArtifactRef):
977
+ raise ValueError("mapped source artifact must be a SourceArtifactRef")
978
+ if _trusted_source_sha256 is not None:
979
+ raise ValueError("trusted source hash requires a builder-owned proof")
980
+ text_is_trusted = _consume_trusted_text_proof(
981
+ _trusted_text_proof,
982
+ text,
983
+ artifact,
984
+ )
985
+ if len(text) != artifact.character_length or (
986
+ not text_is_trusted and source_sha256(text) != artifact.source_sha256
987
+ ):
988
+ raise ValueError("mapped source artifact hash or length does not match its text")
989
+ if not isinstance(source_map, SourceMap) or source_map.generated != artifact:
990
+ raise ValueError("mapped source map must identify the exact artifact")
991
+ _validate_flattened_map(source_map, name="flattened source map")
992
+ if type(lineage) is not tuple or any(not isinstance(item, SourceMap) for item in lineage):
993
+ raise ValueError("mapped source lineage must contain source maps")
994
+ if local_source_map is not None and local_source_map.generated != artifact:
995
+ raise ValueError("local source map must identify the exact artifact")
996
+ if local_source_map is not None and (not lineage or lineage[-1] != local_source_map):
997
+ raise ValueError("local source map must be the latest lineage entry")
998
+ if _retained_fragments is not None and (
999
+ _retained_authority is not _RETAINED_CONSTRUCTION_AUTHORITY
1000
+ or not text_is_trusted
1001
+ ):
1002
+ raise ValueError("retained fragment construction authority is invalid")
1003
+ retained = (
1004
+ (
1005
+ _RetainedTextFragment(
1006
+ SourceSpan(0, len(text)),
1007
+ text,
1008
+ ),
1009
+ )
1010
+ if _retained_fragments is None
1011
+ else _retained_fragments
1012
+ )
1013
+ retained_proof = _retained_state_proof(artifact, retained)
1014
+ _validate_retained_fragments(
1015
+ artifact,
1016
+ retained,
1017
+ retained_proof,
1018
+ construction_authority=_RETAINED_CONSTRUCTION_AUTHORITY,
1019
+ )
1020
+ if _transform_parent is not None and not isinstance(
1021
+ _transform_parent,
1022
+ (MappedSource, _DeferredMappedSource),
1023
+ ):
1024
+ raise ValueError("mapped source transform parent is invalid")
1025
+ object.__setattr__(self, "_text", text)
1026
+ object.__setattr__(
1027
+ self,
1028
+ "_text_authority_proof",
1029
+ _mapped_text_authority_proof(artifact, text),
1030
+ )
1031
+ object.__setattr__(self, "_artifact", artifact)
1032
+ object.__setattr__(self, "_source_map", source_map)
1033
+ object.__setattr__(self, "_lineage", lineage)
1034
+ object.__setattr__(self, "_local_source_map", local_source_map)
1035
+ object.__setattr__(
1036
+ self,
1037
+ "_semantic_summary",
1038
+ _build_mapped_semantic_summary(
1039
+ artifact,
1040
+ source_map,
1041
+ lineage,
1042
+ local_source_map,
1043
+ ),
1044
+ )
1045
+ object.__setattr__(self, "_retained_fragments", retained)
1046
+ object.__setattr__(self, "_retained_starts", tuple(
1047
+ fragment.generated.start for fragment in retained
1048
+ ))
1049
+ object.__setattr__(self, "_retained_proof", retained_proof)
1050
+ object.__setattr__(self, "_transform_parent", _transform_parent)
1051
+ if _normalized_worker_authority is not None and (
1052
+ _normalized_worker_authority is not _NORMALIZED_WORKER_AUTHORITY
1053
+ or artifact.kind is not SourceArtifactKind.WORKER_MODULE
1054
+ ):
1055
+ raise ValueError("normalized Worker authority is invalid")
1056
+ object.__setattr__(
1057
+ self,
1058
+ "_worker_text_proof",
1059
+ None
1060
+ if _normalized_worker_authority is None
1061
+ else _normalized_worker_text_proof(artifact, text),
1062
+ )
1063
+
1064
+ def __setattr__(self, name: str, value: object) -> None:
1065
+ raise AttributeError("MappedSource is immutable")
1066
+
1067
+ def __delattr__(self, name: str) -> None:
1068
+ raise AttributeError("MappedSource is immutable")
1069
+
1070
+ @property
1071
+ def text(self) -> str:
1072
+ return self._text
1073
+
1074
+ @property
1075
+ def artifact(self) -> SourceArtifactRef:
1076
+ return self._artifact
1077
+
1078
+ @property
1079
+ def source_map(self) -> SourceMap:
1080
+ return self._source_map
1081
+
1082
+ @property
1083
+ def lineage(self) -> tuple[SourceMap, ...]:
1084
+ return self._lineage
1085
+
1086
+ @property
1087
+ def local_source_map(self) -> SourceMap:
1088
+ if self._local_source_map is None:
1089
+ raise ValueError("visible or externally assembled source has no local source map")
1090
+ return self._local_source_map
1091
+
1092
+ @property
1093
+ def transform_parent(self) -> MappedSource | _DeferredMappedSource | None:
1094
+ return self._transform_parent
1095
+
1096
+ @property
1097
+ def source_map_sha256(self) -> str:
1098
+ return self.source_map.source_map_sha256
1099
+
1100
+ def lineage_manifest(self) -> tuple[dict[str, object], ...]:
1101
+ return tuple(source_map.to_manifest() for source_map in self.lineage)
1102
+
1103
+ def __repr__(self) -> str:
1104
+ segment_count = (
1105
+ getattr(self.source_map, "compact_interval_count")
1106
+ if getattr(self.source_map, "_compact_reload_map", False)
1107
+ else len(self.source_map.segments)
1108
+ )
1109
+ return (
1110
+ "MappedSource(text=<redacted>, artifact="
1111
+ f"{self.artifact.kind.value}:{self.artifact.source_sha256}, "
1112
+ f"segments={segment_count}, lineage={len(self.lineage)})"
1113
+ )
1114
+
1115
+ def __deepcopy__(self, memo: dict[int, object]) -> MappedSource:
1116
+ return self
1117
+
1118
+
1119
+ def _mapped_semantic_summary(
1120
+ source: MappedSource,
1121
+ *,
1122
+ validate_structure: bool,
1123
+ ) -> _MappedSemanticSummary:
1124
+ if not isinstance(source, MappedSource):
1125
+ raise ValueError("mapped semantic authority is invalid")
1126
+ summary = source._semantic_summary
1127
+ maps: list[SourceMap] = []
1128
+ for item in (source.source_map, *source.lineage, source._local_source_map):
1129
+ if item is not None and all(item is not existing for existing in maps):
1130
+ maps.append(item)
1131
+ current_proofs = tuple(
1132
+ (id(item), item._structural_proof)
1133
+ for item in maps
1134
+ )
1135
+ expected_authority = _mapped_semantic_authority_proof(
1136
+ source.artifact,
1137
+ source.source_map,
1138
+ source.lineage,
1139
+ source._local_source_map,
1140
+ summary.source_map_sha256,
1141
+ summary.lineage_sha256,
1142
+ summary.structural_proofs,
1143
+ )
1144
+ if (
1145
+ summary.source_map_object_id != id(source.source_map)
1146
+ or summary.lineage_object_id != id(source.lineage)
1147
+ or summary.local_source_map_object_id
1148
+ != (None if source._local_source_map is None else id(source._local_source_map))
1149
+ or summary.structural_proofs != current_proofs
1150
+ or not compare_digest(summary.authority_proof, expected_authority)
1151
+ ):
1152
+ raise ValueError("mapped semantic authority is invalid")
1153
+ if validate_structure:
1154
+ for source_map, (_, expected_proof) in zip(
1155
+ maps,
1156
+ summary.structural_proofs,
1157
+ strict=True,
1158
+ ):
1159
+ compact_validator = getattr(
1160
+ source_map,
1161
+ "_validated_compact_structural_proof",
1162
+ None,
1163
+ )
1164
+ actual_proof = (
1165
+ compact_validator()
1166
+ if compact_validator is not None
1167
+ else _source_map_structural_proof(source_map, observe=True)
1168
+ )
1169
+ if not compare_digest(
1170
+ expected_proof,
1171
+ actual_proof,
1172
+ ):
1173
+ raise ValueError("mapped semantic authority is invalid")
1174
+ _observe_text_work("semantic_summary_reuse", 1)
1175
+ return summary
1176
+
1177
+
1178
+ def _trusted_mapped_semantic_summary(source: MappedSource) -> _MappedSemanticSummary:
1179
+ return _mapped_semantic_summary(source, validate_structure=False)
1180
+
1181
+
1182
+ def _validated_mapped_semantic_summary(source: MappedSource) -> _MappedSemanticSummary:
1183
+ return _mapped_semantic_summary(source, validate_structure=True)
1184
+
1185
+
1186
+ def _mapped_segment(segment: SourceMapSegment, offset: int, *, eof: bool = False) -> MappedOffset:
1187
+ if segment.relation is MappingRelation.SYNTHETIC:
1188
+ anchor_unit = segment.anchor_ref if isinstance(segment.anchor_ref, SourceUnitRef) else None
1189
+ return MappedOffset(
1190
+ MappingRelation.SYNTHETIC,
1191
+ synthetic_region=segment.synthetic_region,
1192
+ anchor_unit=anchor_unit,
1193
+ anchor_span=segment.anchor_span if anchor_unit is not None else None,
1194
+ )
1195
+
1196
+ unit = segment.origin_ref if isinstance(segment.origin_ref, SourceUnitRef) else None
1197
+ if unit is None or segment.origin is None:
1198
+ raise ValueError("flattened source map contains an intermediate artifact reference")
1199
+ anchor_unit = (
1200
+ segment.anchor_ref
1201
+ if isinstance(segment.anchor_ref, SourceUnitRef)
1202
+ else None
1203
+ )
1204
+ anchor_span = segment.anchor_span if anchor_unit is not None else None
1205
+ if segment.relation is MappingRelation.DERIVED:
1206
+ return MappedOffset(
1207
+ MappingRelation.DERIVED,
1208
+ unit,
1209
+ segment.origin,
1210
+ anchor_unit=anchor_unit,
1211
+ anchor_span=anchor_span,
1212
+ )
1213
+ delta = offset - segment.generated.start
1214
+ origin_offset = segment.origin.start + delta
1215
+ width = 0 if eof or segment.generated.start == segment.generated.end else 1
1216
+ return MappedOffset(
1217
+ MappingRelation.EXACT,
1218
+ unit,
1219
+ SourceSpan(origin_offset, origin_offset + width),
1220
+ anchor_unit=anchor_unit,
1221
+ anchor_span=anchor_span,
1222
+ )
1223
+
1224
+
1225
+ def map_offset(source_map: SourceMap, offset: int) -> MappedOffset:
1226
+ if not isinstance(source_map, SourceMap):
1227
+ raise ValueError("source_map must be a SourceMap")
1228
+ if type(offset) is not int or not 0 <= offset <= source_map.generated.character_length:
1229
+ raise ValueError("offset must be within the generated source")
1230
+
1231
+ positive = tuple(
1232
+ segment
1233
+ for segment in source_map.segments
1234
+ if segment.generated.start < segment.generated.end
1235
+ )
1236
+ if offset == source_map.generated.character_length:
1237
+ if positive:
1238
+ return _mapped_segment(positive[-1], offset, eof=True)
1239
+ exact_boundaries = tuple(
1240
+ segment
1241
+ for segment in source_map.segments
1242
+ if segment.relation is MappingRelation.EXACT
1243
+ and segment.origin is not None
1244
+ and segment.origin.start == segment.origin.end
1245
+ )
1246
+ if len(exact_boundaries) == 1:
1247
+ return _mapped_segment(exact_boundaries[0], offset, eof=True)
1248
+ raise ValueError("offset has no mappable position in the generated source")
1249
+
1250
+ starts = tuple(segment.generated.start for segment in positive)
1251
+ index = bisect_right(starts, offset) - 1
1252
+ if index < 0 or offset >= positive[index].generated.end:
1253
+ raise ValueError("offset has no generated source mapping")
1254
+ return _mapped_segment(positive[index], offset)
1255
+
1256
+
1257
+ _RELATION_COMPOSITION: dict[tuple[MappingRelation, MappingRelation], MappingRelation] = {
1258
+ (MappingRelation.EXACT, MappingRelation.EXACT): MappingRelation.EXACT,
1259
+ (MappingRelation.EXACT, MappingRelation.DERIVED): MappingRelation.DERIVED,
1260
+ (MappingRelation.EXACT, MappingRelation.SYNTHETIC): MappingRelation.SYNTHETIC,
1261
+ (MappingRelation.DERIVED, MappingRelation.EXACT): MappingRelation.DERIVED,
1262
+ (MappingRelation.DERIVED, MappingRelation.DERIVED): MappingRelation.DERIVED,
1263
+ (MappingRelation.DERIVED, MappingRelation.SYNTHETIC): MappingRelation.SYNTHETIC,
1264
+ (MappingRelation.SYNTHETIC, MappingRelation.EXACT): MappingRelation.SYNTHETIC,
1265
+ (MappingRelation.SYNTHETIC, MappingRelation.DERIVED): MappingRelation.SYNTHETIC,
1266
+ (MappingRelation.SYNTHETIC, MappingRelation.SYNTHETIC): MappingRelation.SYNTHETIC,
1267
+ }
1268
+
1269
+
1270
+ def _overlaps(segment: SourceMapSegment, span: SourceSpan) -> bool:
1271
+ if segment.generated.start == segment.generated.end:
1272
+ return span.start <= segment.generated.start <= span.end
1273
+ return segment.generated.start < span.end and span.start < segment.generated.end
1274
+
1275
+
1276
+ def _project_parent_piece(
1277
+ local: SourceMapSegment,
1278
+ parent: SourceMapSegment,
1279
+ generated: SourceSpan,
1280
+ parent_piece: SourceSpan,
1281
+ local_anchor: tuple[SourceUnitRef | None, SourceSpan | None],
1282
+ ) -> SourceMapSegment:
1283
+ relation = _RELATION_COMPOSITION[(local.relation, parent.relation)]
1284
+ if relation is MappingRelation.SYNTHETIC:
1285
+ region = (
1286
+ parent.synthetic_region
1287
+ if parent.relation is MappingRelation.SYNTHETIC
1288
+ else local.synthetic_region
1289
+ )
1290
+ anchor_ref = parent.anchor_ref
1291
+ anchor_span = parent.anchor_span
1292
+ return SourceMapSegment(
1293
+ generated,
1294
+ None,
1295
+ None,
1296
+ relation,
1297
+ region or "composed_synthetic",
1298
+ anchor_ref,
1299
+ anchor_span,
1300
+ )
1301
+
1302
+ assert parent.origin is not None
1303
+ if parent.relation is MappingRelation.EXACT:
1304
+ delta_start = parent_piece.start - parent.generated.start
1305
+ delta_end = parent_piece.end - parent.generated.start
1306
+ origin = SourceSpan(parent.origin.start + delta_start, parent.origin.start + delta_end)
1307
+ else:
1308
+ origin = parent.origin
1309
+ anchor_ref, anchor_span = local_anchor
1310
+ if anchor_ref is None and isinstance(parent.anchor_ref, SourceUnitRef):
1311
+ anchor_ref = parent.anchor_ref
1312
+ anchor_span = parent.anchor_span
1313
+ region = (
1314
+ local.synthetic_region
1315
+ if local.relation is MappingRelation.DERIVED
1316
+ else parent.synthetic_region
1317
+ if parent.relation is MappingRelation.DERIVED
1318
+ else None
1319
+ )
1320
+ return SourceMapSegment(
1321
+ generated,
1322
+ parent.origin_ref,
1323
+ origin,
1324
+ relation,
1325
+ region if relation is MappingRelation.DERIVED else None,
1326
+ anchor_ref,
1327
+ anchor_span,
1328
+ )
1329
+
1330
+
1331
+ def _anchor_for_parent_span(
1332
+ parent_map: SourceMap, span: SourceSpan
1333
+ ) -> tuple[SourceUnitRef | None, SourceSpan | None]:
1334
+ if span.start == span.end:
1335
+ mapped = map_offset(parent_map, span.start)
1336
+ if mapped.unit is not None and mapped.origin_span is not None:
1337
+ point = mapped.origin_span.start
1338
+ return mapped.unit, SourceSpan(point, point)
1339
+ return mapped.anchor_unit, mapped.anchor_span
1340
+
1341
+ candidates: list[tuple[SourceUnitRef, SourceSpan]] = []
1342
+ for segment in parent_map.segments:
1343
+ if not _overlaps(segment, span) or segment.generated.start == segment.generated.end:
1344
+ continue
1345
+ intersection = SourceSpan(
1346
+ max(segment.generated.start, span.start),
1347
+ min(segment.generated.end, span.end),
1348
+ )
1349
+ if segment.relation is MappingRelation.EXACT and isinstance(
1350
+ segment.origin_ref, SourceUnitRef
1351
+ ):
1352
+ assert segment.origin is not None
1353
+ start = segment.origin.start + intersection.start - segment.generated.start
1354
+ end = segment.origin.start + intersection.end - segment.generated.start
1355
+ candidates.append((segment.origin_ref, SourceSpan(start, end)))
1356
+ elif segment.relation is MappingRelation.DERIVED and isinstance(
1357
+ segment.origin_ref, SourceUnitRef
1358
+ ):
1359
+ assert segment.origin is not None
1360
+ candidates.append((segment.origin_ref, segment.origin))
1361
+ elif isinstance(segment.anchor_ref, SourceUnitRef) and segment.anchor_span is not None:
1362
+ candidates.append((segment.anchor_ref, segment.anchor_span))
1363
+ if not candidates or any(unit != candidates[0][0] for unit, _ in candidates[1:]):
1364
+ return None, None
1365
+ return candidates[0][0], SourceSpan(
1366
+ min(candidate.start for _, candidate in candidates),
1367
+ max(candidate.end for _, candidate in candidates),
1368
+ )
1369
+
1370
+
1371
+ def _compose_segment(
1372
+ local: SourceMapSegment, parent_map: SourceMap
1373
+ ) -> list[SourceMapSegment]:
1374
+ if local.relation is MappingRelation.SYNTHETIC:
1375
+ anchor_ref: SourceUnitRef | None = None
1376
+ anchor_span: SourceSpan | None = None
1377
+ if local.anchor_span is not None:
1378
+ anchor_ref, anchor_span = _anchor_for_parent_span(parent_map, local.anchor_span)
1379
+ return [
1380
+ SourceMapSegment(
1381
+ local.generated,
1382
+ None,
1383
+ None,
1384
+ MappingRelation.SYNTHETIC,
1385
+ local.synthetic_region,
1386
+ anchor_ref,
1387
+ anchor_span,
1388
+ )
1389
+ ]
1390
+
1391
+ assert local.origin is not None
1392
+ local_anchor: tuple[SourceUnitRef | None, SourceSpan | None] = (None, None)
1393
+ if local.anchor_span is not None:
1394
+ local_anchor = _anchor_for_parent_span(parent_map, local.anchor_span)
1395
+ local_generated_length = local.generated.end - local.generated.start
1396
+ local_origin_length = local.origin.end - local.origin.start
1397
+ if local_generated_length != local_origin_length:
1398
+ positive_parents = [
1399
+ segment
1400
+ for segment in parent_map.segments
1401
+ if segment.generated.start < segment.generated.end
1402
+ and _overlaps(segment, local.origin)
1403
+ ]
1404
+ if local.origin.start < local.origin.end and len(positive_parents) != 1:
1405
+ raise ValueError(
1406
+ "unequal-width derived fragment crosses multiple parent segments"
1407
+ )
1408
+ unit, origin = _anchor_for_parent_span(parent_map, local.origin)
1409
+ synthetic_parent = next(
1410
+ (
1411
+ segment
1412
+ for segment in positive_parents
1413
+ if segment.relation is MappingRelation.SYNTHETIC
1414
+ ),
1415
+ None,
1416
+ )
1417
+ if synthetic_parent is not None:
1418
+ anchor_ref = (
1419
+ synthetic_parent.anchor_ref
1420
+ if isinstance(synthetic_parent.anchor_ref, SourceUnitRef)
1421
+ else local_anchor[0] or unit
1422
+ )
1423
+ anchor_span = (
1424
+ synthetic_parent.anchor_span
1425
+ if anchor_ref == synthetic_parent.anchor_ref
1426
+ else local_anchor[1] or origin
1427
+ )
1428
+ return [
1429
+ SourceMapSegment(
1430
+ local.generated,
1431
+ None,
1432
+ None,
1433
+ MappingRelation.SYNTHETIC,
1434
+ synthetic_parent.synthetic_region
1435
+ or local.synthetic_region
1436
+ or "composed_synthetic",
1437
+ anchor_ref,
1438
+ anchor_span,
1439
+ )
1440
+ ]
1441
+ if unit is None or origin is None:
1442
+ raise ValueError("derived fragment crosses multiple parent origins")
1443
+ anchor_ref, anchor_span = local_anchor
1444
+ if anchor_ref is None and len(positive_parents) == 1 and isinstance(
1445
+ positive_parents[0].anchor_ref, SourceUnitRef
1446
+ ):
1447
+ anchor_ref = positive_parents[0].anchor_ref
1448
+ anchor_span = positive_parents[0].anchor_span
1449
+ return [
1450
+ SourceMapSegment(
1451
+ local.generated,
1452
+ unit,
1453
+ origin,
1454
+ MappingRelation.DERIVED,
1455
+ local.synthetic_region,
1456
+ anchor_ref,
1457
+ anchor_span,
1458
+ )
1459
+ ]
1460
+
1461
+ composed: list[SourceMapSegment] = []
1462
+ for parent in parent_map.segments:
1463
+ if not _overlaps(parent, local.origin):
1464
+ continue
1465
+ if parent.generated.start == parent.generated.end:
1466
+ parent_piece = parent.generated
1467
+ else:
1468
+ parent_piece = SourceSpan(
1469
+ max(parent.generated.start, local.origin.start),
1470
+ min(parent.generated.end, local.origin.end),
1471
+ )
1472
+ generated = SourceSpan(
1473
+ local.generated.start + parent_piece.start - local.origin.start,
1474
+ local.generated.start + parent_piece.end - local.origin.start,
1475
+ )
1476
+ composed.append(
1477
+ _project_parent_piece(
1478
+ local,
1479
+ parent,
1480
+ generated,
1481
+ parent_piece,
1482
+ local_anchor,
1483
+ )
1484
+ )
1485
+ if not composed:
1486
+ raise ValueError("local segment has no parent mapping")
1487
+ return composed
1488
+
1489
+
1490
+ def _coalesce_segments(segments: list[SourceMapSegment]) -> tuple[SourceMapSegment, ...]:
1491
+ result: list[SourceMapSegment] = []
1492
+ for segment in segments:
1493
+ if not result:
1494
+ result.append(segment)
1495
+ continue
1496
+ previous = result[-1]
1497
+ positive = (
1498
+ previous.generated.start < previous.generated.end
1499
+ and segment.generated.start < segment.generated.end
1500
+ )
1501
+ common = (
1502
+ positive
1503
+ and previous.generated.end == segment.generated.start
1504
+ and previous.relation is segment.relation
1505
+ and previous.origin_ref == segment.origin_ref
1506
+ and previous.synthetic_region == segment.synthetic_region
1507
+ and previous.anchor_ref == segment.anchor_ref
1508
+ and previous.anchor_span == segment.anchor_span
1509
+ )
1510
+ origins_join = (
1511
+ previous.origin is None
1512
+ and segment.origin is None
1513
+ or previous.origin is not None
1514
+ and segment.origin is not None
1515
+ and previous.origin.end == segment.origin.start
1516
+ )
1517
+ if common and origins_join:
1518
+ origin = (
1519
+ None
1520
+ if previous.origin is None
1521
+ else SourceSpan(
1522
+ previous.origin.start,
1523
+ segment.origin.end, # type: ignore[union-attr]
1524
+ )
1525
+ )
1526
+ result[-1] = SourceMapSegment(
1527
+ SourceSpan(previous.generated.start, segment.generated.end),
1528
+ previous.origin_ref,
1529
+ origin,
1530
+ previous.relation,
1531
+ previous.synthetic_region,
1532
+ previous.anchor_ref,
1533
+ previous.anchor_span,
1534
+ )
1535
+ else:
1536
+ result.append(segment)
1537
+ return tuple(result)
1538
+
1539
+
1540
+ def compose_source_maps(local: SourceMap, parent: SourceMap) -> SourceMap:
1541
+ if not isinstance(local, SourceMap) or not isinstance(parent, SourceMap):
1542
+ raise ValueError("composition requires SourceMap values")
1543
+ _validate_flattened_map(parent, name="flattened parent map")
1544
+ for segment in local.segments:
1545
+ for reference in (segment.origin_ref, segment.anchor_ref):
1546
+ if isinstance(reference, SourceArtifactRef) and reference != parent.generated:
1547
+ raise ValueError("local map does not reference the exact parent artifact")
1548
+ if segment.relation is not MappingRelation.SYNTHETIC and not isinstance(
1549
+ segment.origin_ref, SourceArtifactRef
1550
+ ):
1551
+ raise ValueError("local map origin must reference its parent artifact")
1552
+ if segment.anchor_ref is not None and not isinstance(segment.anchor_ref, SourceArtifactRef):
1553
+ raise ValueError("local map anchor must reference its parent artifact")
1554
+
1555
+ composed = [
1556
+ projected
1557
+ for segment in local.segments
1558
+ for projected in _compose_segment(segment, parent)
1559
+ ]
1560
+ result = SourceMap(local.generated, _coalesce_segments(composed))
1561
+ _validate_flattened_map(result, name="composed flattened source map")
1562
+ return result
1563
+
1564
+
1565
+ def _compose_reused_source_maps(local: SourceMap, parent: SourceMap) -> SourceMap:
1566
+ """Compose monotonic imported fragments in one pass, else use the general path."""
1567
+ if (
1568
+ any(
1569
+ segment.generated.start == segment.generated.end
1570
+ for segment in parent.segments
1571
+ )
1572
+ or any(
1573
+ segment.relation is MappingRelation.SYNTHETIC
1574
+ or segment.anchor_ref is not None
1575
+ or segment.origin is None
1576
+ or segment.origin.start == segment.origin.end
1577
+ for segment in local.segments
1578
+ )
1579
+ or any(
1580
+ current.origin is None
1581
+ or following.origin is None
1582
+ or current.origin.start > following.origin.start
1583
+ for current, following in zip(
1584
+ local.segments,
1585
+ local.segments[1:],
1586
+ strict=False,
1587
+ )
1588
+ )
1589
+ ):
1590
+ return compose_source_maps(local, parent)
1591
+ _validate_flattened_map(parent, name="flattened parent map")
1592
+ for segment in local.segments:
1593
+ if (
1594
+ segment.origin_ref != parent.generated
1595
+ or segment.anchor_ref is not None
1596
+ ):
1597
+ return compose_source_maps(local, parent)
1598
+
1599
+ positive = tuple(
1600
+ segment
1601
+ for segment in parent.segments
1602
+ if segment.generated.start < segment.generated.end
1603
+ )
1604
+ composed: list[SourceMapSegment] = []
1605
+ parent_index = 0
1606
+ for segment in local.segments:
1607
+ assert segment.origin is not None
1608
+ while (
1609
+ parent_index < len(positive)
1610
+ and positive[parent_index].generated.end <= segment.origin.start
1611
+ ):
1612
+ parent_index += 1
1613
+ overlapping: list[SourceMapSegment] = []
1614
+ scan = parent_index
1615
+ while (
1616
+ scan < len(positive)
1617
+ and positive[scan].generated.start < segment.origin.end
1618
+ ):
1619
+ if _overlaps(positive[scan], segment.origin):
1620
+ overlapping.append(positive[scan])
1621
+ scan += 1
1622
+ generated_width = segment.generated.end - segment.generated.start
1623
+ origin_width = segment.origin.end - segment.origin.start
1624
+ if generated_width != origin_width:
1625
+ if len(overlapping) != 1:
1626
+ return compose_source_maps(local, parent)
1627
+ parent_segment = overlapping[0]
1628
+ if parent_segment.relation is MappingRelation.SYNTHETIC:
1629
+ composed.append(
1630
+ SourceMapSegment(
1631
+ segment.generated,
1632
+ None,
1633
+ None,
1634
+ MappingRelation.SYNTHETIC,
1635
+ parent_segment.synthetic_region
1636
+ or segment.synthetic_region
1637
+ or "composed_synthetic",
1638
+ parent_segment.anchor_ref,
1639
+ parent_segment.anchor_span,
1640
+ )
1641
+ )
1642
+ continue
1643
+ assert parent_segment.origin is not None
1644
+ origin = (
1645
+ SourceSpan(
1646
+ parent_segment.origin.start
1647
+ + segment.origin.start
1648
+ - parent_segment.generated.start,
1649
+ parent_segment.origin.start
1650
+ + segment.origin.end
1651
+ - parent_segment.generated.start,
1652
+ )
1653
+ if parent_segment.relation is MappingRelation.EXACT
1654
+ else parent_segment.origin
1655
+ )
1656
+ composed.append(
1657
+ SourceMapSegment(
1658
+ segment.generated,
1659
+ parent_segment.origin_ref,
1660
+ origin,
1661
+ MappingRelation.DERIVED,
1662
+ segment.synthetic_region,
1663
+ parent_segment.anchor_ref,
1664
+ parent_segment.anchor_span,
1665
+ )
1666
+ )
1667
+ continue
1668
+ if not overlapping:
1669
+ return compose_source_maps(local, parent)
1670
+ for parent_segment in overlapping:
1671
+ parent_piece = SourceSpan(
1672
+ max(parent_segment.generated.start, segment.origin.start),
1673
+ min(parent_segment.generated.end, segment.origin.end),
1674
+ )
1675
+ generated = SourceSpan(
1676
+ segment.generated.start
1677
+ + parent_piece.start
1678
+ - segment.origin.start,
1679
+ segment.generated.start
1680
+ + parent_piece.end
1681
+ - segment.origin.start,
1682
+ )
1683
+ composed.append(
1684
+ _project_parent_piece(
1685
+ segment,
1686
+ parent_segment,
1687
+ generated,
1688
+ parent_piece,
1689
+ (None, None),
1690
+ )
1691
+ )
1692
+ result = SourceMap(local.generated, _coalesce_segments(composed))
1693
+ _validate_flattened_map(result, name="composed flattened source map")
1694
+ return result
1695
+
1696
+
1697
+ def _line_ending_kind(text: str) -> str:
1698
+ crlf_count = text.count("\r\n")
1699
+ bare_lf_count = text.count("\n") - crlf_count
1700
+ bare_cr_count = text.count("\r") - crlf_count
1701
+ kinds = sum(count > 0 for count in (crlf_count, bare_lf_count, bare_cr_count))
1702
+ if kinds > 1:
1703
+ return "mixed"
1704
+ if crlf_count:
1705
+ return "crlf"
1706
+ if bare_lf_count:
1707
+ return "lf"
1708
+ if bare_cr_count:
1709
+ return "cr"
1710
+ return "none"
1711
+
1712
+
1713
+ def _line_ending_kind_fragments(
1714
+ fragments: list[_RetainedTextFragment],
1715
+ ) -> str:
1716
+ """Classify line endings without materializing retained fragments."""
1717
+ cr_count = 0
1718
+ lf_count = 0
1719
+ crlf_count = 0
1720
+ previous_ended_cr = False
1721
+ for fragment in fragments:
1722
+ summary = fragment.line_endings
1723
+ assert summary is not None
1724
+ cr_count += summary[0]
1725
+ lf_count += summary[1]
1726
+ crlf_count += summary[2]
1727
+ if previous_ended_cr and summary[3]:
1728
+ crlf_count += 1
1729
+ if fragment.text:
1730
+ previous_ended_cr = summary[4]
1731
+ bare_cr_count = cr_count - crlf_count
1732
+ bare_lf_count = lf_count - crlf_count
1733
+ kinds = sum(count > 0 for count in (crlf_count, bare_lf_count, bare_cr_count))
1734
+ if kinds > 1:
1735
+ return "mixed"
1736
+ if crlf_count:
1737
+ return "crlf"
1738
+ if bare_lf_count:
1739
+ return "lf"
1740
+ if bare_cr_count:
1741
+ return "cr"
1742
+ return "none"
1743
+
1744
+
1745
+ def mapped_visible_source(text: str, unit: SourceUnitRef) -> MappedSource:
1746
+ _require_str(text, "visible source")
1747
+ if not isinstance(unit, SourceUnitRef):
1748
+ raise ValueError("visible source unit must be a SourceUnitRef")
1749
+ if source_sha256(text) != unit.source_sha256:
1750
+ raise ValueError("visible source hash does not match its source unit")
1751
+ artifact = SourceArtifactRef(
1752
+ SourceArtifactKind.VISIBLE,
1753
+ unit.source_sha256,
1754
+ len(text),
1755
+ _line_ending_kind(text),
1756
+ )
1757
+ segment = SourceMapSegment(
1758
+ SourceSpan(0, len(text)),
1759
+ unit,
1760
+ SourceSpan(0, len(text)),
1761
+ MappingRelation.EXACT,
1762
+ )
1763
+ source_map = SourceMap(artifact, (segment,))
1764
+ return MappedSource(text, artifact, source_map)
1765
+
1766
+
1767
+ def compose_mapped_sources(
1768
+ sources: tuple[MappedSource, ...],
1769
+ *,
1770
+ visible_sources: tuple[MappedSource, ...],
1771
+ kind: SourceArtifactKind,
1772
+ ) -> MappedSource:
1773
+ """Join complete mapped fragments with checked, multi-origin provenance.
1774
+
1775
+ Visible originals fence hashes, bounds, and the bytes of exact mappings.
1776
+ Newlines are synthetic and anchored to the following fragment. The result
1777
+ retains no prior assembled artifact or generation through transform parents.
1778
+ """
1779
+ if type(sources) is not tuple or type(visible_sources) is not tuple:
1780
+ raise ValueError("mapped composition requires immutable source tuples")
1781
+ visible: dict[SourceUnitRef, str] = {}
1782
+ identities: dict[tuple[SourceUnitKind, str, int], SourceUnitRef] = {}
1783
+ for source in visible_sources:
1784
+ _validated_mapped_semantic_summary(source)
1785
+ unit = source.source_map.map_offset(0).unit
1786
+ if (
1787
+ source.artifact.kind is not SourceArtifactKind.VISIBLE
1788
+ or unit is None
1789
+ or source_sha256(source.text) != unit.source_sha256
1790
+ or source.artifact.source_sha256 != unit.source_sha256
1791
+ or source.artifact.character_length != len(source.text)
1792
+ or source.source_map.segments != (
1793
+ SourceMapSegment(
1794
+ SourceSpan(0, len(source.text)),
1795
+ unit,
1796
+ SourceSpan(0, len(source.text)),
1797
+ MappingRelation.EXACT,
1798
+ ),
1799
+ )
1800
+ ):
1801
+ raise ValueError("mapped composition requires hash-matched visible sources")
1802
+ key = (unit.kind, unit.unit_id, unit.revision)
1803
+ if key in identities and identities[key] != unit:
1804
+ raise ValueError("mapped composition has conflicting source identities")
1805
+ identities[key] = unit
1806
+ visible[unit] = source.text
1807
+
1808
+ parts: list[str] = []
1809
+ segments: list[SourceMapSegment] = []
1810
+ local_segments: list[SourceMapSegment] = []
1811
+ lineage: list[SourceMap] = []
1812
+ cursor = 0
1813
+ for source in sources:
1814
+ _validated_mapped_semantic_summary(source)
1815
+ if (
1816
+ len(source.text) != source.artifact.character_length
1817
+ or source_sha256(source.text) != source.artifact.source_sha256
1818
+ ):
1819
+ raise ValueError("mapped composition fragment hash or length does not match")
1820
+ for segment in source.source_map.segments:
1821
+ for reference, span in (
1822
+ (segment.origin_ref, segment.origin),
1823
+ (segment.anchor_ref, segment.anchor_span),
1824
+ ):
1825
+ if reference is not None and (
1826
+ reference not in visible
1827
+ or span is None
1828
+ or span.end > len(visible[reference])
1829
+ ):
1830
+ raise ValueError("mapped composition origin is not covered by visible sources")
1831
+ if segment.relation is MappingRelation.EXACT:
1832
+ assert segment.origin_ref is not None and segment.origin is not None
1833
+ if (
1834
+ source.text[segment.generated.start:segment.generated.end]
1835
+ != visible[segment.origin_ref][segment.origin.start:segment.origin.end]
1836
+ ):
1837
+ raise ValueError("mapped composition exact origin text does not match")
1838
+ if parts:
1839
+ anchor = source.source_map.map_offset(0)
1840
+ join = SourceMapSegment(
1841
+ SourceSpan(cursor, cursor + 1),
1842
+ None,
1843
+ None,
1844
+ MappingRelation.SYNTHETIC,
1845
+ "notebook_method_join",
1846
+ anchor.unit or anchor.anchor_unit,
1847
+ anchor.origin_span or anchor.anchor_span,
1848
+ )
1849
+ parts.append("\n")
1850
+ segments.append(join)
1851
+ local_segments.append(join)
1852
+ cursor += 1
1853
+ parts.append(source.text)
1854
+ for segment in source.source_map.segments:
1855
+ segments.append(SourceMapSegment(
1856
+ SourceSpan(cursor + segment.generated.start, cursor + segment.generated.end),
1857
+ segment.origin_ref,
1858
+ segment.origin,
1859
+ segment.relation,
1860
+ segment.synthetic_region,
1861
+ segment.anchor_ref,
1862
+ segment.anchor_span,
1863
+ ))
1864
+ local_segments.append(SourceMapSegment(
1865
+ SourceSpan(cursor, cursor + len(source.text)),
1866
+ source.artifact,
1867
+ SourceSpan(0, len(source.text)),
1868
+ MappingRelation.EXACT,
1869
+ ))
1870
+ lineage.extend(source.lineage)
1871
+ cursor += len(source.text)
1872
+ text = "".join(parts)
1873
+ artifact = SourceArtifactRef(kind, source_sha256(text), len(text), _line_ending_kind(text))
1874
+ if not segments:
1875
+ empty = SourceMapSegment(
1876
+ SourceSpan(0, 0), None, None, MappingRelation.SYNTHETIC, "empty_notebook_methods"
1877
+ )
1878
+ segments.append(empty)
1879
+ local_segments.append(empty)
1880
+ flattened = SourceMap(artifact, _coalesce_segments(segments))
1881
+ local = SourceMap(artifact, _coalesce_segments(local_segments))
1882
+ return MappedSource(text, artifact, flattened, (*lineage, local), local)
1883
+
1884
+
1885
+ _ARTIFACT_IDENTITY_FIELDS = {
1886
+ "lowering_semantic_version",
1887
+ "wrapper_semantic_version",
1888
+ "mode",
1889
+ "worker_generation",
1890
+ "worker_manifest_sha256",
1891
+ "export_catalog_sha256",
1892
+ }
1893
+
1894
+
1895
+ class SourceTransformBuilder:
1896
+ def __init__(
1897
+ self,
1898
+ parent: MappedSource | _DeferredMappedSource,
1899
+ *,
1900
+ _normalized_parent_authority: object | None = None,
1901
+ ) -> None:
1902
+ if not isinstance(parent, (MappedSource, _DeferredMappedSource)):
1903
+ raise ValueError("transform parent must be a mapped source")
1904
+ if (
1905
+ _normalized_parent_authority is not None
1906
+ and _normalized_parent_authority is not _NORMALIZED_WORKER_AUTHORITY
1907
+ ):
1908
+ raise ValueError("normalized parent authority is invalid")
1909
+ self._parent = parent
1910
+ self._normalized_parent = _normalized_parent_authority is not None
1911
+ self._parts: list[_RetainedTextFragment] = []
1912
+ self._segments: list[SourceMapSegment] = []
1913
+ self._cursor = 0
1914
+ self._validated_retained_sources: set[int] = set()
1915
+
1916
+ def _validate_parent_span(self, span: SourceSpan) -> None:
1917
+ length = (
1918
+ len(self._parent.text)
1919
+ if isinstance(self._parent, MappedSource)
1920
+ else self._parent.character_length
1921
+ )
1922
+ if not isinstance(span, SourceSpan) or span.end > length:
1923
+ raise ValueError("fragment span must be within the parent source")
1924
+
1925
+ def _validate_normalized_worker_policy(
1926
+ self,
1927
+ kind: SourceArtifactKind,
1928
+ authority: object | None,
1929
+ ) -> None:
1930
+ if authority is None:
1931
+ return
1932
+ if (
1933
+ authority is not _NORMALIZED_WORKER_AUTHORITY
1934
+ or kind is not SourceArtifactKind.WORKER_MODULE
1935
+ ):
1936
+ raise ValueError("normalized Worker authority is invalid")
1937
+ for fragment in self._parts:
1938
+ _observe_text_work("worker_policy_fragment_visit", 1)
1939
+ if fragment.contains_nul is None:
1940
+ raise ValueError("normalized Worker fragment authority is incomplete")
1941
+ if fragment.contains_nul:
1942
+ raise ValueError("Worker source contains a NUL character")
1943
+ _observe_text_work("normalized_worker_authority", 1)
1944
+
1945
+ def _append(
1946
+ self,
1947
+ text: str,
1948
+ segment: SourceMapSegment,
1949
+ *,
1950
+ retained_source: object | None = None,
1951
+ retained_span: SourceSpan | None = None,
1952
+ ) -> None:
1953
+ _observe_text_work("segment_allocate", 1)
1954
+ self._parts.append(
1955
+ _RetainedTextFragment(
1956
+ SourceSpan(self._cursor, self._cursor + len(text)),
1957
+ text,
1958
+ retained_source,
1959
+ retained_span,
1960
+ contains_nul=_local_nul_summary(text),
1961
+ )
1962
+ )
1963
+ self._segments.append(segment)
1964
+ self._cursor += len(text)
1965
+
1966
+ def _append_retained(
1967
+ self,
1968
+ retained_source: MappedSource | _DeferredMappedSource,
1969
+ retained_span: SourceSpan,
1970
+ segment: SourceMapSegment,
1971
+ ) -> None:
1972
+ _observe_text_work("segment_allocate", 1)
1973
+ source_identity = id(retained_source)
1974
+ if source_identity not in self._validated_retained_sources:
1975
+ _validate_retained_source(retained_source)
1976
+ self._validated_retained_sources.add(source_identity)
1977
+ trusted_normalized_parent = (
1978
+ self._normalized_parent and retained_source is self._parent
1979
+ )
1980
+ fragments = _retained_fragments_for_span(
1981
+ retained_source,
1982
+ retained_span,
1983
+ scan_local_nul=not trusted_normalized_parent,
1984
+ )
1985
+ retained_cursor = retained_span.start
1986
+ for fragment in fragments:
1987
+ width = len(fragment.text)
1988
+ self._parts.append(
1989
+ _RetainedTextFragment(
1990
+ SourceSpan(self._cursor, self._cursor + width),
1991
+ fragment.text,
1992
+ retained_source,
1993
+ SourceSpan(retained_cursor, retained_cursor + width),
1994
+ fragment.line_endings,
1995
+ (
1996
+ False
1997
+ if trusted_normalized_parent
1998
+ and fragment.contains_nul is None
1999
+ else fragment.contains_nul
2000
+ ),
2001
+ )
2002
+ )
2003
+ self._cursor += width
2004
+ retained_cursor += width
2005
+ _observe_text_work("retained_fragment", retained_span.end - retained_span.start)
2006
+ self._segments.append(segment)
2007
+
2008
+ def _exact_segment(self, span: SourceSpan, width: int) -> SourceMapSegment:
2009
+ return SourceMapSegment(
2010
+ SourceSpan(self._cursor, self._cursor + width),
2011
+ self._parent.artifact,
2012
+ span,
2013
+ MappingRelation.EXACT,
2014
+ )
2015
+
2016
+ def copy(self, span: SourceSpan) -> None:
2017
+ self._validate_parent_span(span)
2018
+ width = span.end - span.start
2019
+ self._append_retained(
2020
+ self._parent,
2021
+ span,
2022
+ self._exact_segment(span, width),
2023
+ )
2024
+
2025
+ def exact(self, text: str, span: SourceSpan) -> None:
2026
+ """Append already materialized exact text for a deferred parent."""
2027
+ _require_str(text, "exact text")
2028
+ self._validate_parent_span(span)
2029
+ if len(text) != span.end - span.start:
2030
+ raise ValueError("exact text must preserve the parent span length")
2031
+ self._append(text, self._exact_segment(span, len(text)))
2032
+
2033
+ def derived(
2034
+ self,
2035
+ text: str,
2036
+ span: SourceSpan,
2037
+ region: str,
2038
+ *,
2039
+ anchor: SourceSpan | None = None,
2040
+ ) -> None:
2041
+ _require_str(text, "derived text")
2042
+ _require_str(region, "derived region", nonempty=True)
2043
+ self._validate_parent_span(span)
2044
+ if anchor is not None:
2045
+ self._validate_parent_span(anchor)
2046
+ self._append(
2047
+ text,
2048
+ SourceMapSegment(
2049
+ SourceSpan(self._cursor, self._cursor + len(text)),
2050
+ self._parent.artifact,
2051
+ span,
2052
+ MappingRelation.DERIVED,
2053
+ region,
2054
+ self._parent.artifact if anchor is not None else None,
2055
+ anchor,
2056
+ ),
2057
+ )
2058
+
2059
+ def reuse_exact(self, span: SourceSpan) -> None:
2060
+ """Import an unchanged exact parent segment without entering copy work."""
2061
+ self.copy(span)
2062
+
2063
+ def retained_exact(
2064
+ self,
2065
+ retained_source: MappedSource | _DeferredMappedSource,
2066
+ retained_span: SourceSpan,
2067
+ parent_span: SourceSpan,
2068
+ ) -> None:
2069
+ """Map an existing materialized span exactly against the current parent."""
2070
+ self._validate_parent_span(parent_span)
2071
+ width = retained_span.end - retained_span.start
2072
+ if width != parent_span.end - parent_span.start:
2073
+ raise ValueError("retained exact text must preserve span length")
2074
+ self._append_retained(
2075
+ retained_source,
2076
+ retained_span,
2077
+ self._exact_segment(parent_span, width),
2078
+ )
2079
+
2080
+ def synthetic(self, text: str, anchor: SourceSpan, region: str) -> None:
2081
+ _require_str(text, "synthetic text")
2082
+ _require_str(region, "synthetic region", nonempty=True)
2083
+ self._validate_parent_span(anchor)
2084
+ self._append(
2085
+ text,
2086
+ SourceMapSegment(
2087
+ SourceSpan(self._cursor, self._cursor + len(text)),
2088
+ None,
2089
+ None,
2090
+ MappingRelation.SYNTHETIC,
2091
+ region,
2092
+ self._parent.artifact,
2093
+ anchor,
2094
+ ),
2095
+ )
2096
+
2097
+ def reuse_derived(
2098
+ self,
2099
+ text: str,
2100
+ span: SourceSpan,
2101
+ region: str,
2102
+ *,
2103
+ anchor: SourceSpan | None = None,
2104
+ ) -> None:
2105
+ """Import an unchanged derived segment against the current parent."""
2106
+ _require_str(text, "derived text")
2107
+ _require_str(region, "derived region", nonempty=True)
2108
+ self._validate_parent_span(span)
2109
+ if anchor is not None:
2110
+ self._validate_parent_span(anchor)
2111
+ self._append(
2112
+ text,
2113
+ SourceMapSegment(
2114
+ SourceSpan(self._cursor, self._cursor + len(text)),
2115
+ self._parent.artifact,
2116
+ span,
2117
+ MappingRelation.DERIVED,
2118
+ region,
2119
+ self._parent.artifact if anchor is not None else None,
2120
+ anchor,
2121
+ ),
2122
+ )
2123
+
2124
+ def retained_derived(
2125
+ self,
2126
+ retained_source: MappedSource | _DeferredMappedSource,
2127
+ retained_span: SourceSpan,
2128
+ span: SourceSpan,
2129
+ region: str,
2130
+ *,
2131
+ anchor: SourceSpan | None = None,
2132
+ ) -> None:
2133
+ """Map an existing materialized span as derived current-parent text."""
2134
+ _require_str(region, "derived region", nonempty=True)
2135
+ self._validate_parent_span(span)
2136
+ if anchor is not None:
2137
+ self._validate_parent_span(anchor)
2138
+ width = retained_span.end - retained_span.start
2139
+ self._append_retained(
2140
+ retained_source,
2141
+ retained_span,
2142
+ SourceMapSegment(
2143
+ SourceSpan(self._cursor, self._cursor + width),
2144
+ self._parent.artifact,
2145
+ span,
2146
+ MappingRelation.DERIVED,
2147
+ region,
2148
+ self._parent.artifact if anchor is not None else None,
2149
+ anchor,
2150
+ ),
2151
+ )
2152
+
2153
+ def reuse_synthetic(self, text: str, anchor: SourceSpan, region: str) -> None:
2154
+ """Import an unchanged synthetic segment against the current parent."""
2155
+ _require_str(text, "synthetic text")
2156
+ _require_str(region, "synthetic region", nonempty=True)
2157
+ self._validate_parent_span(anchor)
2158
+ self._append(
2159
+ text,
2160
+ SourceMapSegment(
2161
+ SourceSpan(self._cursor, self._cursor + len(text)),
2162
+ None,
2163
+ None,
2164
+ MappingRelation.SYNTHETIC,
2165
+ region,
2166
+ self._parent.artifact,
2167
+ anchor,
2168
+ ),
2169
+ )
2170
+
2171
+ def retained_synthetic(
2172
+ self,
2173
+ retained_source: MappedSource | _DeferredMappedSource,
2174
+ retained_span: SourceSpan,
2175
+ anchor: SourceSpan,
2176
+ region: str,
2177
+ ) -> None:
2178
+ """Map an existing materialized span as synthetic current-parent text."""
2179
+ _require_str(region, "synthetic region", nonempty=True)
2180
+ self._validate_parent_span(anchor)
2181
+ width = retained_span.end - retained_span.start
2182
+ self._append_retained(
2183
+ retained_source,
2184
+ retained_span,
2185
+ SourceMapSegment(
2186
+ SourceSpan(self._cursor, self._cursor + width),
2187
+ None,
2188
+ None,
2189
+ MappingRelation.SYNTHETIC,
2190
+ region,
2191
+ self._parent.artifact,
2192
+ anchor,
2193
+ ),
2194
+ )
2195
+
2196
+ def _artifact(
2197
+ self,
2198
+ kind: SourceArtifactKind,
2199
+ identity: dict[str, object],
2200
+ *,
2201
+ deferred: bool,
2202
+ ) -> tuple[SourceArtifactRef, str | None]:
2203
+ if type(kind) is not SourceArtifactKind:
2204
+ raise ValueError("artifact kind must be a SourceArtifactKind")
2205
+ unknown = set(identity) - _ARTIFACT_IDENTITY_FIELDS
2206
+ if unknown:
2207
+ raise ValueError(
2208
+ f"unsupported artifact identity metadata: {sorted(unknown)!r}"
2209
+ )
2210
+ if not self._segments:
2211
+ raise ValueError("transform must contain at least one explicit fragment")
2212
+ if deferred:
2213
+ digest = sha256()
2214
+ for fragment in self._parts:
2215
+ digest.update(fragment.text.encode("utf-8"))
2216
+ text_hash = digest.hexdigest()
2217
+ _observe_text_work("projection_hash", self._cursor)
2218
+ text = None
2219
+ else:
2220
+ _observe_text_work("materialize", self._cursor)
2221
+ text = "".join(fragment.text for fragment in self._parts)
2222
+ _observe_text_work("final_hash", self._cursor)
2223
+ text_hash = source_sha256(text)
2224
+ ending = _line_ending_kind_fragments(self._parts)
2225
+ artifact = SourceArtifactRef(
2226
+ kind,
2227
+ text_hash,
2228
+ self._cursor,
2229
+ ending,
2230
+ **identity, # type: ignore[arg-type]
2231
+ )
2232
+ return artifact, text
2233
+
2234
+ def build_deferred(
2235
+ self,
2236
+ kind: SourceArtifactKind,
2237
+ **identity: object,
2238
+ ) -> _DeferredMappedSource:
2239
+ artifact, _ = self._artifact(kind, identity, deferred=True)
2240
+ local = SourceMap(artifact, _coalesce_segments(self._segments))
2241
+ flattened = _compose_reused_source_maps(local, self._parent.source_map)
2242
+ lineage = (*self._parent.lineage, local)
2243
+ retained = tuple(self._parts)
2244
+ return _DeferredMappedSource(
2245
+ artifact,
2246
+ flattened,
2247
+ lineage,
2248
+ local,
2249
+ retained,
2250
+ tuple(fragment.generated.start for fragment in retained),
2251
+ _retained_state_proof(artifact, retained),
2252
+ _RETAINED_CONSTRUCTION_AUTHORITY,
2253
+ )
2254
+
2255
+ def build(
2256
+ self,
2257
+ kind: SourceArtifactKind,
2258
+ *,
2259
+ _normalized_worker_authority: object | None = None,
2260
+ **identity: object,
2261
+ ) -> MappedSource:
2262
+ self._validate_normalized_worker_policy(
2263
+ kind,
2264
+ _normalized_worker_authority,
2265
+ )
2266
+ artifact, text = self._artifact(kind, identity, deferred=False)
2267
+ assert text is not None
2268
+ local = SourceMap(artifact, _coalesce_segments(self._segments))
2269
+ flattened = compose_source_maps(local, self._parent.source_map)
2270
+ lineage = (*self._parent.lineage, local)
2271
+ proof = _mint_trusted_text_proof(
2272
+ text,
2273
+ artifact.source_sha256,
2274
+ authority=_TRUSTED_TEXT_PROOF_AUTHORITY,
2275
+ )
2276
+ return MappedSource(
2277
+ text,
2278
+ artifact,
2279
+ flattened,
2280
+ lineage,
2281
+ local,
2282
+ _retained_fragments=tuple(self._parts),
2283
+ _transform_parent=self._parent,
2284
+ _trusted_text_proof=proof,
2285
+ _retained_authority=_RETAINED_CONSTRUCTION_AUTHORITY,
2286
+ _normalized_worker_authority=_normalized_worker_authority,
2287
+ )
2288
+
2289
+ def build_reused(
2290
+ self,
2291
+ kind: SourceArtifactKind,
2292
+ *,
2293
+ _normalized_worker_authority: object | None = None,
2294
+ **identity: object,
2295
+ ) -> MappedSource:
2296
+ """Build imported monotonic segments with a linear source-map splice."""
2297
+ self._validate_normalized_worker_policy(
2298
+ kind,
2299
+ _normalized_worker_authority,
2300
+ )
2301
+ artifact, text = self._artifact(kind, identity, deferred=False)
2302
+ assert text is not None
2303
+ local = SourceMap(artifact, _coalesce_segments(self._segments))
2304
+ flattened = _compose_reused_source_maps(local, self._parent.source_map)
2305
+ lineage = (*self._parent.lineage, local)
2306
+ proof = _mint_trusted_text_proof(
2307
+ text,
2308
+ artifact.source_sha256,
2309
+ authority=_TRUSTED_TEXT_PROOF_AUTHORITY,
2310
+ )
2311
+ return MappedSource(
2312
+ text,
2313
+ artifact,
2314
+ flattened,
2315
+ lineage,
2316
+ local,
2317
+ _retained_fragments=tuple(self._parts),
2318
+ _transform_parent=self._parent,
2319
+ _trusted_text_proof=proof,
2320
+ _retained_authority=_RETAINED_CONSTRUCTION_AUTHORITY,
2321
+ _normalized_worker_authority=_normalized_worker_authority,
2322
+ )
2323
+
2324
+ def build_canonical_reused(
2325
+ self,
2326
+ kind: SourceArtifactKind,
2327
+ *,
2328
+ _normalized_worker_authority: object | None = None,
2329
+ **identity: object,
2330
+ ) -> MappedSource:
2331
+ """Build a final source whose retained state owns no prior generation."""
2332
+ if not isinstance(self._parent, _DeferredMappedSource):
2333
+ raise ValueError("canonical retained build requires a deferred parent")
2334
+ self._validate_normalized_worker_policy(
2335
+ kind,
2336
+ _normalized_worker_authority,
2337
+ )
2338
+ artifact, text = self._artifact(kind, identity, deferred=False)
2339
+ assert text is not None
2340
+ local = SourceMap(artifact, _coalesce_segments(self._segments))
2341
+ flattened = _compose_reused_source_maps(local, self._parent.source_map)
2342
+ lineage = (*self._parent.lineage, local)
2343
+ retained = tuple(
2344
+ _RetainedTextFragment(
2345
+ fragment.generated,
2346
+ fragment.text,
2347
+ line_endings=fragment.line_endings,
2348
+ contains_nul=fragment.contains_nul,
2349
+ )
2350
+ for fragment in self._parts
2351
+ )
2352
+ parent = _detached_retained_source(self._parent)
2353
+ proof = _mint_trusted_text_proof(
2354
+ text,
2355
+ artifact.source_sha256,
2356
+ authority=_TRUSTED_TEXT_PROOF_AUTHORITY,
2357
+ )
2358
+ return MappedSource(
2359
+ text,
2360
+ artifact,
2361
+ flattened,
2362
+ lineage,
2363
+ local,
2364
+ _retained_fragments=retained,
2365
+ _transform_parent=parent,
2366
+ _trusted_text_proof=proof,
2367
+ _retained_authority=_RETAINED_CONSTRUCTION_AUTHORITY,
2368
+ _normalized_worker_authority=_normalized_worker_authority,
2369
+ )
2370
+
2371
+
2372
+ class LineIndex:
2373
+ """Map zero-based Unicode code-point offsets to one-based line/columns."""
2374
+
2375
+ def __init__(self, source: str) -> None:
2376
+ _require_str(source, "source")
2377
+ self._length = len(source)
2378
+ self._line_starts = (0, *(i + 1 for i, char in enumerate(source) if char == "\n"))
2379
+
2380
+ def offset_to_line_column(self, offset: int) -> tuple[int, int]:
2381
+ if type(offset) is not int or not 0 <= offset <= self._length:
2382
+ raise ValueError("offset must be within the source")
2383
+ line_index = bisect_right(self._line_starts, offset) - 1
2384
+ return line_index + 1, offset - self._line_starts[line_index] + 1
2385
+
2386
+ def line_column_to_offset(self, line: int, column: int) -> int:
2387
+ if type(line) is not int or not 1 <= line <= len(self._line_starts):
2388
+ raise ValueError("line must be within the source")
2389
+ if type(column) is not int or column < 1:
2390
+ raise ValueError("column must be positive")
2391
+ line_index = line - 1
2392
+ start = self._line_starts[line_index]
2393
+ next_start = (
2394
+ self._line_starts[line_index + 1]
2395
+ if line_index + 1 < len(self._line_starts)
2396
+ else self._length + 1
2397
+ )
2398
+ if start + column > next_start:
2399
+ raise ValueError("column must be within the source line")
2400
+ return start + column - 1
2401
+
2402
+ def line_range(self, line: int) -> SourceSpan:
2403
+ if type(line) is not int or not 1 <= line <= len(self._line_starts):
2404
+ raise ValueError("line must be within the source")
2405
+ start = self._line_starts[line - 1]
2406
+ end = (
2407
+ self._line_starts[line]
2408
+ if line < len(self._line_starts)
2409
+ else self._length
2410
+ )
2411
+ return SourceSpan(start, end)