tensorfs 0.3.45__tar.gz → 0.3.46__tar.gz

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 (137) hide show
  1. {tensorfs-0.3.45 → tensorfs-0.3.46}/Cargo.lock +2 -2
  2. {tensorfs-0.3.45 → tensorfs-0.3.46}/Cargo.toml +1 -1
  3. {tensorfs-0.3.45 → tensorfs-0.3.46}/PKG-INFO +1 -1
  4. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/asset_update.rs +111 -0
  5. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-py/src/store.rs +32 -3
  6. {tensorfs-0.3.45 → tensorfs-0.3.46}/pyproject.toml +1 -1
  7. {tensorfs-0.3.45 → tensorfs-0.3.46}/python/tensorfs/_ext.pyi +9 -0
  8. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/Cargo.toml +0 -0
  9. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/build.rs +0 -0
  10. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/examples/h3-swiglu-layout.md +0 -0
  11. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/examples/optional-cache-backfill.md +0 -0
  12. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/examples/resident-conversion.md +0 -0
  13. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/examples/resident_conversion_profile.rs +0 -0
  14. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/b64.rs +0 -0
  15. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/bin/tfs/ckpt.rs +0 -0
  16. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/bin/tfs/conform.rs +0 -0
  17. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/bin/tfs/fetch.rs +0 -0
  18. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/bin/tfs/ingest.rs +0 -0
  19. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/bin/tfs/main.rs +0 -0
  20. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/bin/tfs/rd.rs +0 -0
  21. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/bin/tfs/repo.rs +0 -0
  22. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/bin/tfs/snap.rs +0 -0
  23. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/bin/tfs/watch.rs +0 -0
  24. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/cache_roots.rs +0 -0
  25. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/canon.rs +0 -0
  26. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/capability.rs +0 -0
  27. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/catalog.rs +0 -0
  28. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/cbor.rs +0 -0
  29. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/checkpoint.rs +0 -0
  30. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/checkpoint_root.rs +0 -0
  31. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/corpus.rs +0 -0
  32. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/derived/adoption.rs +0 -0
  33. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/derived/estimate.rs +0 -0
  34. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/derived/graft_tests.rs +0 -0
  35. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/derived/progress.rs +0 -0
  36. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/derived/resume_tests.rs +0 -0
  37. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/derived/retention.rs +0 -0
  38. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/derived/roots.rs +0 -0
  39. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/derived.rs +0 -0
  40. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/dtype.rs +0 -0
  41. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/durability.rs +0 -0
  42. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/err.rs +0 -0
  43. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/fetch.rs +0 -0
  44. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/fill.rs +0 -0
  45. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/fit.rs +0 -0
  46. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/gc.rs +0 -0
  47. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/header.rs +0 -0
  48. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/home.rs +0 -0
  49. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/ids.rs +0 -0
  50. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/ingest/carrier.rs +0 -0
  51. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/ingest/convert.rs +0 -0
  52. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/ingest/fingerprint.rs +0 -0
  53. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/ingest/gguf.rs +0 -0
  54. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/ingest/h3_lora.rs +0 -0
  55. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/ingest/journal.rs +0 -0
  56. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/ingest/mod.rs +0 -0
  57. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/ingest/preflight.rs +0 -0
  58. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/ingest/source.rs +0 -0
  59. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/ingest/stamp.rs +0 -0
  60. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/ingest/transaction.rs +0 -0
  61. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/jcs.rs +0 -0
  62. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/lib.rs +0 -0
  63. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/limits.rs +0 -0
  64. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/machine.rs +0 -0
  65. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/manifest.rs +0 -0
  66. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/meta.rs +0 -0
  67. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/project.rs +0 -0
  68. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/providers.rs +0 -0
  69. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/read.rs +0 -0
  70. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/receipt.rs +0 -0
  71. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/reclaim.rs +0 -0
  72. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/registry.rs +0 -0
  73. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/relation.rs +0 -0
  74. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/repo_cache.rs +0 -0
  75. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/repository.rs +0 -0
  76. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/sha256.rs +0 -0
  77. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/source_artifact.rs +0 -0
  78. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/spec.rs +0 -0
  79. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/staging.rs +0 -0
  80. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/storage.rs +0 -0
  81. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/store.rs +0 -0
  82. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/transport/api.rs +0 -0
  83. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/transport/http.rs +0 -0
  84. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/transport/hub.rs +0 -0
  85. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/transport/ledger.rs +0 -0
  86. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/transport/mod.rs +0 -0
  87. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/transport/policy.rs +0 -0
  88. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/transport/prefix.rs +0 -0
  89. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/transport/pull.rs +0 -0
  90. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/transport/push.rs +0 -0
  91. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/transport/ranged.rs +0 -0
  92. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/transport/tests.rs +0 -0
  93. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/src/vectors.rs +0 -0
  94. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/tests/checkpoint_roots.rs +0 -0
  95. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/tests/fetch_url_progress.rs +0 -0
  96. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/tests/fit.rs +0 -0
  97. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/tests/fixtures/repo_apply/blobs.jsonl +0 -0
  98. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/tests/fixtures/repo_apply/expected_list.jsonl +0 -0
  99. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/tests/fixtures/repo_apply/expected_repository.json +0 -0
  100. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/tests/fixtures/repo_apply/expected_rows.jsonl +0 -0
  101. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/tests/fixtures/repo_apply/header.cbor +0 -0
  102. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/tests/fixtures/repo_apply/manifest.json +0 -0
  103. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/tests/fixtures/repo_apply/mutation.json +0 -0
  104. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/tests/h3_lora.rs +0 -0
  105. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/tests/h3_swiglu.rs +0 -0
  106. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/tests/home.rs +0 -0
  107. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/tests/import_tree.rs +0 -0
  108. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/tests/instrument_profiles.rs +0 -0
  109. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/tests/liveness.rs +0 -0
  110. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/tests/read_plan.rs +0 -0
  111. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/tests/reclaim.rs +0 -0
  112. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/tests/reclaim_run.rs +0 -0
  113. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/tests/repo_cache.rs +0 -0
  114. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/tests/repo_store.rs +0 -0
  115. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/tests/resident_admission.rs +0 -0
  116. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/tests/sha256_backends.rs +0 -0
  117. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/tests/sharded_cas.rs +0 -0
  118. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/tests/source_artifacts.rs +0 -0
  119. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/tests/source_plan.rs +0 -0
  120. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/tests/source_prefixes.rs +0 -0
  121. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/tests/source_preflight.rs +0 -0
  122. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/tests/staging.rs +0 -0
  123. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/tests/store_boundaries.rs +0 -0
  124. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/tests/tensor_schema.rs +0 -0
  125. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/tests/version.rs +0 -0
  126. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-core/tests/write_through.rs +0 -0
  127. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-py/Cargo.toml +0 -0
  128. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-py/src/docs.rs +0 -0
  129. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-py/src/errors.rs +0 -0
  130. {tensorfs-0.3.45 → tensorfs-0.3.46}/crates/tensorfs-py/src/lib.rs +0 -0
  131. {tensorfs-0.3.45 → tensorfs-0.3.46}/python/tensorfs/__init__.py +0 -0
  132. {tensorfs-0.3.45 → tensorfs-0.3.46}/python/tensorfs/_derived_channel.py +0 -0
  133. {tensorfs-0.3.45 → tensorfs-0.3.46}/python/tensorfs/_source_channel.py +0 -0
  134. {tensorfs-0.3.45 → tensorfs-0.3.46}/python/tensorfs/_tensors.py +0 -0
  135. {tensorfs-0.3.45 → tensorfs-0.3.46}/python/tensorfs/derived.py +0 -0
  136. {tensorfs-0.3.45 → tensorfs-0.3.46}/python/tensorfs/errors.py +0 -0
  137. {tensorfs-0.3.45 → tensorfs-0.3.46}/python/tensorfs/py.typed +0 -0
@@ -421,7 +421,7 @@ checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca"
421
421
 
422
422
  [[package]]
423
423
  name = "tensorfs-core"
424
- version = "0.3.45"
424
+ version = "0.3.46"
425
425
  dependencies = [
426
426
  "fs2",
427
427
  "libc",
@@ -435,7 +435,7 @@ dependencies = [
435
435
 
436
436
  [[package]]
437
437
  name = "tensorfs-py"
438
- version = "0.3.45"
438
+ version = "0.3.46"
439
439
  dependencies = [
440
440
  "pyo3",
441
441
  "tensorfs-core",
@@ -3,5 +3,5 @@ resolver = "2"
3
3
  members = ["crates/tensorfs-core", "crates/tensorfs-py"]
4
4
 
5
5
  [workspace.package]
6
- version = "0.3.45"
6
+ version = "0.3.46"
7
7
  edition = "2021"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tensorfs
3
- Version: 0.3.45
3
+ Version: 0.3.46
4
4
  Classifier: Programming Language :: Python :: 3
5
5
  Classifier: Programming Language :: Python :: Implementation :: CPython
6
6
  Classifier: Programming Language :: Rust
@@ -23,6 +23,9 @@ pub enum Edit {
23
23
  source_path: String,
24
24
  media_type: String,
25
25
  },
26
+ /// Inherit one already-committed asset from the source checkpoint header.
27
+ /// The asset declaration and segment ObjectRefs are copied verbatim; no payload is read.
28
+ Inherit { name: String, source_name: String },
26
29
  /// Remove an asset by its exact header name. Missing names are harmless, making
27
30
  /// retries deterministic.
28
31
  Drop { name: String },
@@ -72,6 +75,7 @@ pub fn update(
72
75
  detail: "asset update source has no CozyTensors header".into(),
73
76
  })?;
74
77
  let mut header = checkpoint::load_header(store, header_ref)?;
78
+ let source_assets: BTreeMap<String, Asset> = header.assets.iter().cloned().collect();
75
79
  let closure = checkpoint::load_closure(store, &header)?;
76
80
 
77
81
  let mut assets: BTreeMap<String, Asset> = header.assets.drain(..).collect();
@@ -80,6 +84,13 @@ pub fn update(
80
84
  Edit::Drop { name } => {
81
85
  assets.remove(name);
82
86
  }
87
+ Edit::Inherit { name, source_name } => {
88
+ let asset = source_assets.get(source_name).ok_or_else(|| Refusal {
89
+ code: Code::OBJECT_ABSENT,
90
+ detail: format!("source asset {source_name:?} is absent"),
91
+ })?;
92
+ assets.insert(name.clone(), asset.clone());
93
+ }
83
94
  Edit::Copy {
84
95
  name,
85
96
  source_path,
@@ -129,6 +140,47 @@ pub fn update(
129
140
  })
130
141
  }
131
142
 
143
+ /// Inherit selected runtime assets from one exact source checkpoint into another
144
+ /// metadata-only derived checkpoint. Tensor and asset payloads are never opened.
145
+ pub fn inherit(
146
+ store: &Store,
147
+ target_manifest: &ObjectRef,
148
+ source_manifest: &ObjectRef,
149
+ names: &[String],
150
+ ) -> Result<ResultSnapshot> {
151
+ let target = checkpoint::load_manifest(store, target_manifest)?;
152
+ let target_header_ref = target.header().ok_or_else(|| Refusal {
153
+ code: Code::ATTACHMENT_CARDINALITY,
154
+ detail: "asset inheritance target has no CozyTensors header".into(),
155
+ })?;
156
+ let source = checkpoint::load_manifest(store, source_manifest)?;
157
+ let source_header_ref = source.header().ok_or_else(|| Refusal {
158
+ code: Code::ATTACHMENT_CARDINALITY,
159
+ detail: "asset inheritance source has no CozyTensors header".into(),
160
+ })?;
161
+ let mut header = checkpoint::load_header(store, target_header_ref)?;
162
+ let source_header = checkpoint::load_header(store, source_header_ref)?;
163
+ let target_closure = checkpoint::load_closure(store, &header)?;
164
+ let source_assets: BTreeMap<String, Asset> = source_header.assets.into_iter().collect();
165
+ let mut assets: BTreeMap<String, Asset> = header.assets.drain(..).collect();
166
+ for name in names {
167
+ let asset = source_assets.get(name).ok_or_else(|| Refusal {
168
+ code: Code::OBJECT_ABSENT,
169
+ detail: format!("source asset {name:?} is absent"),
170
+ })?;
171
+ assets.insert(name.clone(), asset.clone());
172
+ }
173
+ header.assets = assets.into_iter().collect();
174
+ header.validate(&target_closure)?;
175
+ let header_object = checkpoint::put_doc(store, &header)?;
176
+ let manifest = checkpoint::build_manifest(&header, &header_object, &target_closure)?;
177
+ let manifest_object = store.put_manifest(&manifest)?.obj;
178
+ Ok(ResultSnapshot {
179
+ header: header_object,
180
+ manifest: manifest_object,
181
+ })
182
+ }
183
+
132
184
  #[cfg(test)]
133
185
  mod tests {
134
186
  use super::*;
@@ -290,4 +342,63 @@ mod tests {
290
342
  assert_eq!(one.manifest, two.manifest);
291
343
  std::fs::remove_dir_all(root).unwrap();
292
344
  }
345
+
346
+ #[test]
347
+ fn inherits_existing_asset_refs_without_payload_reads() {
348
+ let root = temp();
349
+ let store = Store::init(&root).unwrap();
350
+ let spec = registry::seeds().into_iter().next().unwrap().spec;
351
+ let payload = put(&store, b"tokenizer");
352
+ let header = Header {
353
+ configs: vec![],
354
+ assets: vec![(
355
+ "tokenizer/vocab.json".into(),
356
+ Asset {
357
+ logical_sha256: payload.sha256.clone(),
358
+ logical_length: payload.length,
359
+ media_type: "application/json".into(),
360
+ segments: vec![payload.clone()],
361
+ },
362
+ )],
363
+ encodings: vec![spec.clone()],
364
+ components: vec![(
365
+ "model".into(),
366
+ vec![(
367
+ "w".into(),
368
+ Tensor {
369
+ dtype: Dtype::U8,
370
+ shape: vec![1],
371
+ encoding: spec.object_id(),
372
+ parts: vec![(
373
+ "value".into(),
374
+ Part {
375
+ dtype: Dtype::U8,
376
+ shape: vec![1],
377
+ body: Body::Inline(vec![0]),
378
+ },
379
+ )],
380
+ },
381
+ )],
382
+ )],
383
+ };
384
+ let href = put(&store, &header.canonical_bytes().unwrap());
385
+ let source = Draft {
386
+ entries: vec![("model.cozytensors".into(), Entry::CozyTensors(href))],
387
+ }
388
+ .seal()
389
+ .unwrap();
390
+ let source_ref = store.put_manifest(&source).unwrap().obj;
391
+ let result = update(
392
+ &store,
393
+ &source_ref,
394
+ &[Edit::Inherit {
395
+ name: "tokenizer/vocab.json".into(),
396
+ source_name: "tokenizer/vocab.json".into(),
397
+ }],
398
+ )
399
+ .unwrap();
400
+ let output = checkpoint::load_header(&store, &result.header).unwrap();
401
+ assert_eq!(output.assets[0].1.segments, vec![payload]);
402
+ std::fs::remove_dir_all(root).unwrap();
403
+ }
293
404
  }
@@ -593,18 +593,19 @@ impl PyStore {
593
593
 
594
594
  /// Rewrite only a CozyTensors header/manifest to add, replace, or drop model assets.
595
595
  /// `copies` are `(name, source_path, media_type)` rows selected from the exact source
596
- /// manifest; TensorFS reuses their ObjectRefs without reading payload bytes.
597
- #[pyo3(signature = (manifest_id, manifest_length, copies=Vec::new(), drops=Vec::new()))]
596
+ /// manifest; `inherits` are `(name, source_name)` rows copied from the source header.
597
+ #[pyo3(signature = (manifest_id, manifest_length, copies=Vec::new(), inherits=Vec::new(), drops=Vec::new()))]
598
598
  fn update_model_assets<'p>(
599
599
  &self,
600
600
  py: Python<'p>,
601
601
  manifest_id: &str,
602
602
  manifest_length: u64,
603
603
  copies: Vec<(String, String, String)>,
604
+ inherits: Vec<(String, String)>,
604
605
  drops: Vec<String>,
605
606
  ) -> PyResult<Bound<'p, PyDict>> {
606
607
  let source = obj_ref(py, manifest_id, manifest_length)?;
607
- let mut edits = Vec::with_capacity(copies.len() + drops.len());
608
+ let mut edits = Vec::with_capacity(copies.len() + inherits.len() + drops.len());
608
609
  edits.extend(copies.into_iter().map(|(name, source_path, media_type)| {
609
610
  tensorfs_core::asset_update::Edit::Copy {
610
611
  name,
@@ -612,6 +613,9 @@ impl PyStore {
612
613
  media_type,
613
614
  }
614
615
  }));
616
+ edits.extend(inherits.into_iter().map(|(name, source_name)| {
617
+ tensorfs_core::asset_update::Edit::Inherit { name, source_name }
618
+ }));
615
619
  edits.extend(
616
620
  drops
617
621
  .into_iter()
@@ -628,6 +632,31 @@ impl PyStore {
628
632
  Ok(out)
629
633
  }
630
634
 
635
+ /// Inherit selected verified model assets from one checkpoint into another,
636
+ /// rewriting only the target header and manifest.
637
+ #[pyo3(signature = (target_manifest_id, target_manifest_length, source_manifest_id, source_manifest_length, names=Vec::new()))]
638
+ fn inherit_model_assets<'p>(
639
+ &self,
640
+ py: Python<'p>,
641
+ target_manifest_id: &str,
642
+ target_manifest_length: u64,
643
+ source_manifest_id: &str,
644
+ source_manifest_length: u64,
645
+ names: Vec<String>,
646
+ ) -> PyResult<Bound<'p, PyDict>> {
647
+ let target = obj_ref(py, target_manifest_id, target_manifest_length)?;
648
+ let source = obj_ref(py, source_manifest_id, source_manifest_length)?;
649
+ let result = py
650
+ .detach(|| tensorfs_core::asset_update::inherit(&self.store, &target, &source, &names))
651
+ .or_refuse(py)?;
652
+ let out = PyDict::new(py);
653
+ out.set_item("header_id", result.header.id())?;
654
+ out.set_item("header_length", result.header.length)?;
655
+ out.set_item("manifest_id", result.manifest.id())?;
656
+ out.set_item("manifest_length", result.manifest.length)?;
657
+ Ok(out)
658
+ }
659
+
631
660
  fn verify_checkpoint_source(
632
661
  &self,
633
662
  py: Python<'_>,
@@ -4,7 +4,7 @@ build-backend = "maturin"
4
4
 
5
5
  [project]
6
6
  name = "tensorfs"
7
- version = "0.3.45"
7
+ version = "0.3.46"
8
8
  description = "TensorFS — canonical tensor artifact substrate"
9
9
  requires-python = ">=3.12"
10
10
  classifiers = [
@@ -489,8 +489,17 @@ class Store:
489
489
  manifest_id: str,
490
490
  manifest_length: int,
491
491
  copies: Sequence[tuple[str, str, str]] = ...,
492
+ inherits: Sequence[tuple[str, str]] = ...,
492
493
  drops: Sequence[str] = ...,
493
494
  ) -> dict[str, str | int]: ...
495
+ def inherit_model_assets(
496
+ self,
497
+ target_manifest_id: str,
498
+ target_manifest_length: int,
499
+ source_manifest_id: str,
500
+ source_manifest_length: int,
501
+ names: Sequence[str] = ...,
502
+ ) -> dict[str, str | int]: ...
494
503
  def objects(self) -> list[str]: ...
495
504
  def reap_holds(self) -> list[str]: ...
496
505