verdog-runtime 0.1.0__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 (58) hide show
  1. verdog_runtime/__init__.py +13 -0
  2. verdog_runtime/_artifact_references.py +548 -0
  3. verdog_runtime/_checkpoint_compatibility.py +172 -0
  4. verdog_runtime/_child_checkpoint.py +262 -0
  5. verdog_runtime/_configuration.py +230 -0
  6. verdog_runtime/_definitions.py +45 -0
  7. verdog_runtime/_encoding.py +13 -0
  8. verdog_runtime/_file_lock.py +79 -0
  9. verdog_runtime/_lifecycle.py +171 -0
  10. verdog_runtime/_markdown.py +29 -0
  11. verdog_runtime/_process.py +211 -0
  12. verdog_runtime/_protocol.py +494 -0
  13. verdog_runtime/_relative_path.py +21 -0
  14. verdog_runtime/_run_metadata.py +989 -0
  15. verdog_runtime/_run_model.py +263 -0
  16. verdog_runtime/_run_store.py +682 -0
  17. verdog_runtime/_statistics.py +294 -0
  18. verdog_runtime/agents/__init__.py +31 -0
  19. verdog_runtime/agents/_artifacts.py +84 -0
  20. verdog_runtime/agents/_command.py +197 -0
  21. verdog_runtime/agents/claude.py +148 -0
  22. verdog_runtime/agents/codex.py +164 -0
  23. verdog_runtime/cancellation.py +69 -0
  24. verdog_runtime/child.py +979 -0
  25. verdog_runtime/cli.py +180 -0
  26. verdog_runtime/declarations/__init__.py +137 -0
  27. verdog_runtime/declarations/agents.py +61 -0
  28. verdog_runtime/declarations/calls.py +65 -0
  29. verdog_runtime/declarations/configuration.py +18 -0
  30. verdog_runtime/declarations/context.py +88 -0
  31. verdog_runtime/declarations/graph.py +262 -0
  32. verdog_runtime/declarations/ids.py +36 -0
  33. verdog_runtime/declarations/interfaces.py +12 -0
  34. verdog_runtime/declarations/keys.py +20 -0
  35. verdog_runtime/declarations/operations.py +103 -0
  36. verdog_runtime/declarations/results.py +63 -0
  37. verdog_runtime/declarations/state.py +179 -0
  38. verdog_runtime/entry.py +563 -0
  39. verdog_runtime/interpreter/__init__.py +47 -0
  40. verdog_runtime/interpreter/_agents.py +196 -0
  41. verdog_runtime/interpreter/_calls.py +149 -0
  42. verdog_runtime/interpreter/_continuation.py +611 -0
  43. verdog_runtime/interpreter/_errors.py +9 -0
  44. verdog_runtime/interpreter/_invocations.py +367 -0
  45. verdog_runtime/interpreter/execution.py +4221 -0
  46. verdog_runtime/interpreter/features.py +198 -0
  47. verdog_runtime/interpreter/nodes/__init__.py +9 -0
  48. verdog_runtime/interpreter/nodes/agent.py +149 -0
  49. verdog_runtime/interpreter/nodes/feature.py +24 -0
  50. verdog_runtime/interpreter/nodes/python.py +21 -0
  51. verdog_runtime/interpreter/policies.py +13 -0
  52. verdog_runtime/interpreter/validation.py +500 -0
  53. verdog_runtime/py.typed +0 -0
  54. verdog_runtime-0.1.0.dist-info/METADATA +73 -0
  55. verdog_runtime-0.1.0.dist-info/RECORD +58 -0
  56. verdog_runtime-0.1.0.dist-info/WHEEL +5 -0
  57. verdog_runtime-0.1.0.dist-info/licenses/LICENSE +235 -0
  58. verdog_runtime-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,13 @@
1
+ """The Verdog workflow runtime.
2
+
3
+ Byte-identical for every project, which is why it is one installed package rather
4
+ than a copy inside each: one shared runtime keeps execution types identical across
5
+ projects and lets subroutines interoperate directly.
6
+ """
7
+
8
+ from .cancellation import (
9
+ CancellationToken as CancellationToken,
10
+ ExecutionCancelled as ExecutionCancelled,
11
+ )
12
+
13
+ __all__ = ["CancellationToken", "ExecutionCancelled"]
@@ -0,0 +1,548 @@
1
+ """Reference immutable run artifacts without copying them at checkpoint boundaries."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import hashlib
6
+ import os
7
+ import stat
8
+ from collections.abc import Mapping, Sequence
9
+ from dataclasses import dataclass
10
+ from pathlib import Path
11
+ from typing import Any, TypeAlias, cast
12
+
13
+ from ._run_metadata import FileSignature, file_signature, fsync_directory
14
+ from ._run_model import CONTROL_DIRECTORY, RunStoreError
15
+ from ._relative_path import strict_posix_relative_parts
16
+
17
+ _ARTIFACT_REFERENCES_VERSION = 1
18
+ _COPY_CHUNK_SIZE = 1024 * 1024
19
+ _FICLONE = 0x40049409
20
+ _INVOCATION_METADATA = ".verdog-invocation.json"
21
+
22
+
23
+ @dataclass(frozen=True, slots=True)
24
+ class ArtifactDirectory:
25
+ relative: Path
26
+ mode: int
27
+
28
+
29
+ @dataclass(frozen=True, slots=True)
30
+ class ArtifactFile:
31
+ relative: Path
32
+ mode: int
33
+ size: int
34
+ sha256: str
35
+
36
+
37
+ ArtifactReferences: TypeAlias = tuple[
38
+ tuple[ArtifactDirectory, ...], tuple[ArtifactFile, ...]
39
+ ]
40
+ ArtifactCache: TypeAlias = dict[Path, tuple[FileSignature, ArtifactFile]]
41
+
42
+
43
+ def _artifact_relative(name: str) -> Path:
44
+ parts = strict_posix_relative_parts(name)
45
+ if parts is None or CONTROL_DIRECTORY in parts:
46
+ raise RunStoreError(
47
+ f"unsafe checkpoint artifact path: {name or '<empty>'}",
48
+ code="checkpoint.artifact_unsafe",
49
+ details={"path": name},
50
+ )
51
+ return Path(*parts)
52
+
53
+
54
+ def _artifact_mode(value: os.stat_result) -> int:
55
+ return stat.S_IMODE(value.st_mode) & 0o777
56
+
57
+
58
+ def _integrity_error(relative: Path) -> None:
59
+ raise RunStoreError(
60
+ f"checkpoint artifact failed its integrity check: {relative.as_posix()}",
61
+ code="checkpoint.artifact_corrupt",
62
+ details={"path": relative.as_posix()},
63
+ )
64
+
65
+
66
+ def _artifact_path(root: Path, relative: Path, *, directory: bool) -> Path:
67
+ target = root.joinpath(*relative.parts)
68
+ try:
69
+ canonical_root = root.resolve(strict=True)
70
+ resolved = target.resolve(strict=True)
71
+ mode = target.lstat().st_mode
72
+ except OSError as error:
73
+ raise RunStoreError(
74
+ f"checkpoint artifact is unavailable: {relative.as_posix()}",
75
+ code="checkpoint.artifact_unavailable",
76
+ details={"path": relative.as_posix()},
77
+ ) from error
78
+ if (
79
+ root.is_symlink()
80
+ or target.is_symlink()
81
+ or not (stat.S_ISDIR(mode) if directory else stat.S_ISREG(mode))
82
+ or resolved != canonical_root.joinpath(*relative.parts)
83
+ ):
84
+ raise RunStoreError(
85
+ f"checkpoint artifact is unsafe: {relative.as_posix()}",
86
+ code="checkpoint.artifact_unsafe",
87
+ details={"path": relative.as_posix()},
88
+ )
89
+ return resolved
90
+
91
+
92
+ def _artifact_file_path(root: Path, relative: Path) -> Path:
93
+ return _artifact_path(root, relative, directory=False)
94
+
95
+
96
+ def _scan_artifacts(
97
+ root: Path,
98
+ ) -> tuple[dict[Path, FileSignature], dict[Path, FileSignature]]:
99
+ _artifact_path(root, Path(), directory=True)
100
+ directories: dict[Path, FileSignature] = {}
101
+ files: dict[Path, FileSignature] = {}
102
+ pending = [Path()]
103
+ while pending:
104
+ base = pending.pop()
105
+ directory = root / base
106
+ try:
107
+ with os.scandir(directory) as scan:
108
+ entries = sorted(scan, key=lambda item: item.name)
109
+ report_directory = base == Path() or any(
110
+ entry.name == _INVOCATION_METADATA for entry in entries
111
+ )
112
+ for entry in entries:
113
+ if entry.name == CONTROL_DIRECTORY:
114
+ continue
115
+ if report_directory and entry.name in ("config.md", "stats.md"):
116
+ continue
117
+ if base == Path() and entry.name == "trace.log":
118
+ continue
119
+ relative = _artifact_relative((base / entry.name).as_posix())
120
+ metadata = entry.stat(follow_symlinks=False)
121
+ signature = file_signature(metadata)
122
+ if stat.S_ISDIR(metadata.st_mode):
123
+ directories[relative] = signature
124
+ pending.append(relative)
125
+ elif stat.S_ISREG(metadata.st_mode):
126
+ files[relative] = signature
127
+ else:
128
+ raise RunStoreError(
129
+ f"artifact is not a regular file or directory: {root / relative}",
130
+ code="checkpoint.artifact_unsafe",
131
+ details={"path": str(root / relative)},
132
+ )
133
+ except OSError as error:
134
+ raise RunStoreError(
135
+ f"artifact directory changed while checkpointing: {directory}",
136
+ code="checkpoint.artifact_unstable",
137
+ details={"path": str(directory)},
138
+ ) from error
139
+ return directories, files
140
+
141
+
142
+ def _read_artifact(
143
+ root: Path, relative: Path, signature: FileSignature, *, flush: bool
144
+ ) -> ArtifactFile:
145
+ path = _artifact_file_path(root, relative)
146
+ try:
147
+ descriptor = os.open(path, os.O_RDONLY | getattr(os, "O_NOFOLLOW", 0))
148
+ with os.fdopen(descriptor, "rb") as stream:
149
+ if file_signature(os.fstat(stream.fileno())) != signature:
150
+ _integrity_error(relative)
151
+ digest = hashlib.file_digest(stream, "sha256").hexdigest()
152
+ if flush:
153
+ os.fsync(stream.fileno())
154
+ if (
155
+ file_signature(os.fstat(stream.fileno())) != signature
156
+ or file_signature(path.lstat()) != signature
157
+ ):
158
+ _integrity_error(relative)
159
+ except OSError as error:
160
+ raise RunStoreError(
161
+ f"checkpoint artifact is unreadable: {relative.as_posix()}",
162
+ code="checkpoint.artifact_unavailable",
163
+ details={"path": relative.as_posix()},
164
+ ) from error
165
+ return ArtifactFile(
166
+ relative, stat.S_IMODE(signature[2]) & 0o777, signature[3], digest
167
+ )
168
+
169
+
170
+ def _write_all(descriptor: int, value: bytes) -> None:
171
+ offset = 0
172
+ while offset < len(value):
173
+ written = os.write(descriptor, value[offset:])
174
+ if written <= 0:
175
+ raise OSError("artifact write made no progress")
176
+ offset += written
177
+
178
+
179
+ def _transfer_and_hash(source: int, target: int | None) -> tuple[int, str]:
180
+ digest = hashlib.sha256()
181
+ size = 0
182
+ os.lseek(source, 0, os.SEEK_SET)
183
+ while chunk := os.read(source, _COPY_CHUNK_SIZE):
184
+ digest.update(chunk)
185
+ size += len(chunk)
186
+ if target is not None:
187
+ _write_all(target, chunk)
188
+ return size, digest.hexdigest()
189
+
190
+
191
+ def _reference_mode(value: Mapping[str, Any], path: Path) -> int:
192
+ mode = value.get("mode")
193
+ if not isinstance(mode, int) or isinstance(mode, bool) or mode < 0 or mode > 0o777:
194
+ raise RunStoreError(
195
+ f"checkpoint artifact has an invalid mode: {path}",
196
+ code="checkpoint.artifact_manifest_invalid",
197
+ details={"path": str(path), "field": "mode"},
198
+ )
199
+ return mode
200
+
201
+
202
+ def _reference_string(value: Mapping[str, Any], key: str, path: Path) -> str:
203
+ found = value.get(key)
204
+ if not isinstance(found, str) or not found:
205
+ raise RunStoreError(
206
+ f"checkpoint artifact has an invalid {key}: {path}",
207
+ code="checkpoint.artifact_manifest_invalid",
208
+ details={"path": str(path), "field": key},
209
+ )
210
+ return found
211
+
212
+
213
+ def _reference_size(value: Mapping[str, Any], path: Path) -> int:
214
+ found = value.get("size")
215
+ if not isinstance(found, int) or isinstance(found, bool) or found < 0:
216
+ raise RunStoreError(
217
+ f"checkpoint artifact has an invalid size: {path}",
218
+ code="checkpoint.artifact_manifest_invalid",
219
+ details={"path": str(path), "field": "size"},
220
+ )
221
+ return found
222
+
223
+
224
+ def _reference_records(value: Mapping[str, Any], key: str, path: Path) -> list[object]:
225
+ records = value.get(key)
226
+ if not isinstance(records, list):
227
+ raise RunStoreError(
228
+ f"checkpoint artifact manifest has no valid {key}: {path}",
229
+ code="checkpoint.artifact_manifest_invalid",
230
+ details={"path": str(path), "field": key},
231
+ )
232
+ return cast(list[object], records)
233
+
234
+
235
+ def _reference_directories(
236
+ value: Mapping[str, Any], path: Path
237
+ ) -> tuple[ArtifactDirectory, ...]:
238
+ found: list[ArtifactDirectory] = []
239
+ for item in _reference_records(value, "directories", path):
240
+ if not isinstance(item, dict):
241
+ raise RunStoreError(
242
+ f"checkpoint artifact directory is invalid: {path}",
243
+ code="checkpoint.artifact_manifest_invalid",
244
+ details={"path": str(path)},
245
+ )
246
+ record = cast(dict[str, Any], item)
247
+ found.append(
248
+ ArtifactDirectory(
249
+ _artifact_relative(_reference_string(record, "path", path)),
250
+ _reference_mode(record, path),
251
+ )
252
+ )
253
+ return tuple(sorted(found, key=lambda item: item.relative.as_posix()))
254
+
255
+
256
+ def _reference_files(value: Mapping[str, Any], path: Path) -> tuple[ArtifactFile, ...]:
257
+ found: list[ArtifactFile] = []
258
+ for item in _reference_records(value, "files", path):
259
+ if not isinstance(item, dict):
260
+ raise RunStoreError(
261
+ f"checkpoint artifact file is invalid: {path}",
262
+ code="checkpoint.artifact_manifest_invalid",
263
+ details={"path": str(path)},
264
+ )
265
+ record = cast(dict[str, Any], item)
266
+ digest = _reference_string(record, "sha256", path)
267
+ if len(digest) != 64 or any(
268
+ character not in "0123456789abcdef" for character in digest
269
+ ):
270
+ raise RunStoreError(
271
+ f"checkpoint artifact digest is invalid: {path}",
272
+ code="checkpoint.artifact_manifest_invalid",
273
+ details={"path": str(path), "field": "sha256"},
274
+ )
275
+ found.append(
276
+ ArtifactFile(
277
+ _artifact_relative(_reference_string(record, "path", path)),
278
+ _reference_mode(record, path),
279
+ _reference_size(record, path),
280
+ digest,
281
+ )
282
+ )
283
+ return tuple(sorted(found, key=lambda item: item.relative.as_posix()))
284
+
285
+
286
+ def _validate_reference_layout(
287
+ directories: Sequence[ArtifactDirectory],
288
+ files: Sequence[ArtifactFile],
289
+ manifest_path: Path,
290
+ ) -> None:
291
+ directory_paths = {item.relative for item in directories}
292
+ file_paths = {item.relative for item in files}
293
+ if (
294
+ len(directory_paths) != len(directories)
295
+ or len(file_paths) != len(files)
296
+ or directory_paths & file_paths
297
+ ):
298
+ raise RunStoreError(
299
+ f"checkpoint artifact paths are ambiguous: {manifest_path}",
300
+ code="checkpoint.artifact_manifest_invalid",
301
+ details={"path": str(manifest_path)},
302
+ )
303
+ missing_parent = next(
304
+ (
305
+ relative
306
+ for relative in (*directory_paths, *file_paths)
307
+ if relative.parent != Path() and relative.parent not in directory_paths
308
+ ),
309
+ None,
310
+ )
311
+ if missing_parent is not None:
312
+ raise RunStoreError(
313
+ f"checkpoint artifact parent is missing: {missing_parent.as_posix()}",
314
+ code="checkpoint.artifact_manifest_invalid",
315
+ details={"path": missing_parent.as_posix()},
316
+ )
317
+
318
+
319
+ def decode_artifact_references(
320
+ raw: object, manifest_path: Path, /
321
+ ) -> ArtifactReferences | None:
322
+ """Decode artifact metadata already read from one checkpoint manifest."""
323
+
324
+ if raw is None:
325
+ return None
326
+ if not isinstance(raw, dict):
327
+ raise RunStoreError(
328
+ f"checkpoint has no valid artifact references: {manifest_path}",
329
+ code="checkpoint.artifact_manifest_invalid",
330
+ details={"path": str(manifest_path)},
331
+ )
332
+ artifact = cast(dict[str, Any], raw)
333
+ if (
334
+ type(artifact.get("schema_version")) is not int
335
+ or artifact.get("schema_version") != _ARTIFACT_REFERENCES_VERSION
336
+ or artifact.get("kind") != "references"
337
+ ):
338
+ raise RunStoreError(
339
+ f"checkpoint has no valid artifact references: {manifest_path}",
340
+ code="checkpoint.artifact_manifest_invalid",
341
+ details={"path": str(manifest_path)},
342
+ )
343
+ directories = _reference_directories(artifact, manifest_path)
344
+ files = _reference_files(artifact, manifest_path)
345
+ _validate_reference_layout(directories, files, manifest_path)
346
+ return directories, files
347
+
348
+
349
+ def validate_artifact_extension(
350
+ previous: ArtifactReferences | None, current: ArtifactReferences
351
+ ) -> None:
352
+ """Previously published artifacts are immutable; directories may gain children."""
353
+
354
+ if previous is None:
355
+ return
356
+ for old, new in zip(previous, current):
357
+ indexed = {item.relative: item for item in new}
358
+ for item in old:
359
+ if indexed.get(item.relative) != item:
360
+ _integrity_error(item.relative)
361
+
362
+
363
+ def capture_artifacts(
364
+ source_root: Path,
365
+ *,
366
+ cache: ArtifactCache,
367
+ previous: ArtifactReferences | None = None,
368
+ ) -> dict[str, object]:
369
+ """Flush and inventory existing outputs, retaining verified hashes in ``cache``."""
370
+
371
+ before_directories, before_files = _scan_artifacts(source_root)
372
+ directories = tuple(
373
+ ArtifactDirectory(relative, stat.S_IMODE(signature[2]) & 0o777)
374
+ for relative, signature in sorted(before_directories.items())
375
+ )
376
+ files: list[ArtifactFile] = []
377
+ changed_directories: set[Path] = {Path()}
378
+ for relative, signature in sorted(before_files.items()):
379
+ cached = cache.get(relative)
380
+ if cached is not None and cached[0] == signature:
381
+ record = cached[1]
382
+ else:
383
+ record = _read_artifact(source_root, relative, signature, flush=True)
384
+ cache[relative] = (signature, record)
385
+ changed_directories.add(relative.parent)
386
+ files.append(record)
387
+ current = directories, tuple(files)
388
+ validate_artifact_extension(previous, current)
389
+ if (before_directories, before_files) != _scan_artifacts(source_root):
390
+ raise RunStoreError(
391
+ "run artifacts changed while checkpoint references were being captured",
392
+ code="checkpoint.artifact_unstable",
393
+ details={"output_dir": str(source_root)},
394
+ )
395
+ previous_directories: set[Path] = (
396
+ set() if previous is None else {item.relative for item in previous[0]}
397
+ )
398
+ for record in directories:
399
+ if record.relative not in previous_directories:
400
+ changed_directories.update((record.relative, record.relative.parent))
401
+ for relative in sorted(
402
+ changed_directories, key=lambda item: len(item.parts), reverse=True
403
+ ):
404
+ fsync_directory(source_root / relative)
405
+ return {
406
+ "schema_version": _ARTIFACT_REFERENCES_VERSION,
407
+ "kind": "references",
408
+ "directories": [
409
+ {"path": item.relative.as_posix(), "mode": item.mode}
410
+ for item in directories
411
+ ],
412
+ "files": [
413
+ {
414
+ "path": item.relative.as_posix(),
415
+ "mode": item.mode,
416
+ "size": item.size,
417
+ "sha256": item.sha256,
418
+ }
419
+ for item in files
420
+ ],
421
+ }
422
+
423
+
424
+ def _validate_directories(root: Path, directories: Sequence[ArtifactDirectory]) -> None:
425
+ _artifact_path(root, Path(), directory=True)
426
+ for record in directories:
427
+ path = _artifact_path(root, record.relative, directory=True)
428
+ if _artifact_mode(path.lstat()) != record.mode:
429
+ _integrity_error(record.relative)
430
+
431
+
432
+ def validate_artifacts(
433
+ source_root: Path, references: ArtifactReferences, *, cache: ArtifactCache
434
+ ) -> None:
435
+ """Verify exactly the referenced artifacts; later outputs do not invalidate them."""
436
+
437
+ directories, files = references
438
+ _validate_directories(source_root, directories)
439
+ for record in files:
440
+ path = _artifact_file_path(source_root, record.relative)
441
+ signature = file_signature(path.lstat())
442
+ current = _read_artifact(source_root, record.relative, signature, flush=False)
443
+ if current != record:
444
+ _integrity_error(record.relative)
445
+ cache[record.relative] = (signature, current)
446
+
447
+
448
+ def _try_reflink(source: int, target: int) -> bool:
449
+ if os.name != "posix":
450
+ return False
451
+ try:
452
+ import fcntl
453
+
454
+ fcntl.ioctl(target, _FICLONE, source)
455
+ except OSError:
456
+ os.ftruncate(target, 0)
457
+ return False
458
+ return True
459
+
460
+
461
+ def _materialize_artifact_bytes(
462
+ source: Path,
463
+ target: Path,
464
+ record: ArtifactFile,
465
+ expected_signature: FileSignature,
466
+ ) -> None:
467
+ source_descriptor = os.open(source, os.O_RDONLY | getattr(os, "O_NOFOLLOW", 0))
468
+ try:
469
+ if file_signature(os.fstat(source_descriptor)) != expected_signature:
470
+ raise RunStoreError(
471
+ "checkpoint artifact changed during materialization: "
472
+ f"{record.relative.as_posix()}",
473
+ code="checkpoint.artifact_corrupt",
474
+ details={"path": record.relative.as_posix()},
475
+ )
476
+ target_descriptor = os.open(target, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600)
477
+ try:
478
+ cloned = _try_reflink(source_descriptor, target_descriptor)
479
+ size, digest = _transfer_and_hash(
480
+ source_descriptor, None if cloned else target_descriptor
481
+ )
482
+ os.fsync(target_descriptor)
483
+ finally:
484
+ os.close(target_descriptor)
485
+ current_signature = file_signature(source.lstat())
486
+ if (
487
+ file_signature(os.fstat(source_descriptor)) != expected_signature
488
+ or current_signature != expected_signature
489
+ or size != record.size
490
+ or digest != record.sha256
491
+ ):
492
+ raise RunStoreError(
493
+ "checkpoint artifact failed its integrity check: "
494
+ f"{record.relative.as_posix()}",
495
+ code="checkpoint.artifact_corrupt",
496
+ details={"path": record.relative.as_posix()},
497
+ )
498
+ finally:
499
+ os.close(source_descriptor)
500
+
501
+
502
+ def _copy_referenced_artifact(
503
+ source_root: Path, record: ArtifactFile, target: Path
504
+ ) -> None:
505
+ source = _artifact_file_path(source_root, record.relative)
506
+ metadata = source.lstat()
507
+ if _artifact_mode(metadata) != record.mode:
508
+ _integrity_error(record.relative)
509
+ expected_signature = file_signature(metadata)
510
+ target.parent.mkdir(parents=True, exist_ok=True, mode=0o700)
511
+ try:
512
+ _materialize_artifact_bytes(source, target, record, expected_signature)
513
+ except RunStoreError:
514
+ target.unlink(missing_ok=True)
515
+ raise
516
+ except OSError as error:
517
+ target.unlink(missing_ok=True)
518
+ raise RunStoreError(
519
+ "checkpoint artifact could not be materialized: "
520
+ f"{record.relative.as_posix()}",
521
+ code="checkpoint.artifact_unavailable",
522
+ details={"path": record.relative.as_posix()},
523
+ ) from error
524
+ target.chmod(record.mode)
525
+
526
+
527
+ def materialize_artifact_references(
528
+ source_root: Path,
529
+ destination: Path,
530
+ directories: Sequence[ArtifactDirectory],
531
+ files: Sequence[ArtifactFile],
532
+ ) -> None:
533
+ _validate_directories(source_root, directories)
534
+ for record in sorted(directories, key=lambda item: len(item.relative.parts)):
535
+ destination.joinpath(*record.relative.parts).mkdir(mode=0o700)
536
+ for record in files:
537
+ _copy_referenced_artifact(
538
+ source_root,
539
+ record,
540
+ destination.joinpath(*record.relative.parts),
541
+ )
542
+ for record in sorted(
543
+ directories, key=lambda item: len(item.relative.parts), reverse=True
544
+ ):
545
+ directory = destination.joinpath(*record.relative.parts)
546
+ fsync_directory(directory)
547
+ directory.chmod(record.mode)
548
+ fsync_directory(destination)