tensorfs 0.2.0__tar.gz → 0.2.1__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.
- {tensorfs-0.2.0 → tensorfs-0.2.1}/Cargo.lock +2 -2
- {tensorfs-0.2.0 → tensorfs-0.2.1}/Cargo.toml +1 -1
- {tensorfs-0.2.0 → tensorfs-0.2.1}/PKG-INFO +1 -1
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/src/bin/tfs/layout.rs +45 -35
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/src/bin/tfs/main.rs +36 -34
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/src/bin/tfs/rd.rs +1 -1
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/src/corpus.rs +3 -3
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/src/fit.rs +52 -52
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/src/grade.rs +9 -6
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/tests/grade.rs +24 -18
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/tests/tensor_schema.rs +3 -3
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-py/src/docs.rs +20 -19
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-py/src/lib.rs +1 -1
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-py/src/store.rs +2 -2
- {tensorfs-0.2.0 → tensorfs-0.2.1}/pyproject.toml +1 -1
- {tensorfs-0.2.0 → tensorfs-0.2.1}/python/tensorfs/__init__.py +8 -8
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/Cargo.toml +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/src/b64.rs +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/src/bin/tfs/ckpt.rs +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/src/bin/tfs/conform.rs +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/src/bin/tfs/fetch.rs +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/src/bin/tfs/ingest.rs +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/src/bin/tfs/repo.rs +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/src/bin/tfs/snap.rs +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/src/bin/tfs/watch.rs +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/src/canon.rs +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/src/capability.rs +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/src/catalog.rs +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/src/cbor.rs +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/src/checkpoint.rs +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/src/derived.rs +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/src/dtype.rs +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/src/err.rs +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/src/fetch.rs +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/src/fill.rs +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/src/gc.rs +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/src/header.rs +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/src/ids.rs +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/src/ingest/carrier.rs +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/src/ingest/convert.rs +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/src/ingest/fingerprint.rs +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/src/ingest/gguf.rs +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/src/ingest/mod.rs +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/src/ingest/source.rs +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/src/ingest/stamp.rs +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/src/ingest/transaction.rs +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/src/jcs.rs +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/src/lib.rs +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/src/limits.rs +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/src/machine.rs +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/src/manifest.rs +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/src/meta.rs +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/src/project.rs +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/src/read.rs +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/src/receipt.rs +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/src/registry.rs +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/src/relation.rs +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/src/repository.rs +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/src/sha256.rs +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/src/spec.rs +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/src/storage.rs +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/src/store.rs +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/src/vectors.rs +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/tests/fixtures/repo_apply/blobs.jsonl +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/tests/fixtures/repo_apply/expected_list.jsonl +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/tests/fixtures/repo_apply/expected_repository.json +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/tests/fixtures/repo_apply/expected_rows.jsonl +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/tests/fixtures/repo_apply/header.cbor +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/tests/fixtures/repo_apply/manifest.json +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/tests/fixtures/repo_apply/mutation.json +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/tests/liveness.rs +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/tests/repo_store.rs +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-core/tests/source_plan.rs +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-py/Cargo.toml +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/crates/tensorfs-py/src/errors.rs +0 -0
- {tensorfs-0.2.0 → tensorfs-0.2.1}/python/tensorfs/errors.py +0 -0
|
@@ -249,7 +249,7 @@ checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca"
|
|
|
249
249
|
|
|
250
250
|
[[package]]
|
|
251
251
|
name = "tensorfs-core"
|
|
252
|
-
version = "0.2.
|
|
252
|
+
version = "0.2.1"
|
|
253
253
|
dependencies = [
|
|
254
254
|
"fs2",
|
|
255
255
|
"minicbor",
|
|
@@ -258,7 +258,7 @@ dependencies = [
|
|
|
258
258
|
|
|
259
259
|
[[package]]
|
|
260
260
|
name = "tensorfs-py"
|
|
261
|
-
version = "0.2.
|
|
261
|
+
version = "0.2.1"
|
|
262
262
|
dependencies = [
|
|
263
263
|
"pyo3",
|
|
264
264
|
"tensorfs-core",
|
|
@@ -14,7 +14,7 @@ use tensorfs_core::capability::CapabilityRecords;
|
|
|
14
14
|
use tensorfs_core::checkpoint as ck;
|
|
15
15
|
use tensorfs_core::dtype::Dtype;
|
|
16
16
|
use tensorfs_core::fit::{
|
|
17
|
-
self, Accepts,
|
|
17
|
+
self, Accepts, CompatibilityReport, Custody, Fit, TensorRequirement, TensorRequirements,
|
|
18
18
|
};
|
|
19
19
|
use tensorfs_core::grade::{self, ConversionRegistration, Grade, GradeDecision, Mapping, Registry};
|
|
20
20
|
use tensorfs_core::header::Header;
|
|
@@ -51,10 +51,10 @@ macro_rules! rd {
|
|
|
51
51
|
};
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
/// A header
|
|
54
|
+
/// A header projected into tensor requirements. This is the identity contract:
|
|
55
55
|
/// what a `load()` that constructs exactly this checkpoint would require. It is the
|
|
56
56
|
/// starting point for every real pair — you edit one side and grade the difference.
|
|
57
|
-
pub fn
|
|
57
|
+
pub fn cmd_requirements(root: &Path, hex: &str, flags: &Flags) -> ExitCode {
|
|
58
58
|
let store = ok!(Store::open(root));
|
|
59
59
|
let length = match fs::metadata(store.object_path(hex)) {
|
|
60
60
|
Ok(m) => m.len(),
|
|
@@ -73,16 +73,16 @@ pub fn cmd_topology(root: &Path, hex: &str, flags: &Flags) -> ExitCode {
|
|
|
73
73
|
if let Some(p) = flag(flags, "emit-header") {
|
|
74
74
|
let _ = fs::write(p, ok!(header.canonical_bytes()));
|
|
75
75
|
}
|
|
76
|
-
let
|
|
77
|
-
emit(&
|
|
78
|
-
println!("contract {}",
|
|
79
|
-
println!("tensors {}",
|
|
80
|
-
println!("tensor schema {}",
|
|
76
|
+
let requirements = project(&header, flag(flags, "contract").unwrap_or("local"));
|
|
77
|
+
emit(&requirements, flags);
|
|
78
|
+
println!("contract {}", requirements.contract);
|
|
79
|
+
println!("tensors {}", requirements.count());
|
|
80
|
+
println!("tensor schema {}", requirements.tensor_schema_digest());
|
|
81
81
|
ExitCode::SUCCESS
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
-
pub fn project(h: &Header, contract_name: &str) ->
|
|
85
|
-
|
|
84
|
+
pub fn project(h: &Header, contract_name: &str) -> TensorRequirements {
|
|
85
|
+
TensorRequirements {
|
|
86
86
|
contract: tensorfs_core::ids::object_id(contract_name.as_bytes()),
|
|
87
87
|
components: h
|
|
88
88
|
.components
|
|
@@ -94,7 +94,7 @@ pub fn project(h: &Header, contract_name: &str) -> CodeTopology {
|
|
|
94
94
|
.map(|(k, t)| {
|
|
95
95
|
(
|
|
96
96
|
k.clone(),
|
|
97
|
-
|
|
97
|
+
TensorRequirement {
|
|
98
98
|
dtype: t.dtype,
|
|
99
99
|
shape: t.shape.clone(),
|
|
100
100
|
accepts: Accepts::OneOf(vec![t.encoding.clone()]),
|
|
@@ -110,14 +110,14 @@ pub fn project(h: &Header, contract_name: &str) -> CodeTopology {
|
|
|
110
110
|
}
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
/// `tfs fit <
|
|
113
|
+
/// `tfs fit <tensor-requirements.json> <root> <header> [--custody local] [--device <class>
|
|
114
114
|
/// --observations <obs.json>] [--json]` — design §3, the only compatibility verdict.
|
|
115
115
|
///
|
|
116
116
|
/// `<header>` is a header object id in `<root>` or a path to header bytes. Exit 0 on
|
|
117
117
|
/// `ok`; every refusal has its own exit code so a caller can branch without parsing, and
|
|
118
118
|
/// `--json` prints the total machine document (`machine::fit_json`).
|
|
119
|
-
pub fn cmd_fit(
|
|
120
|
-
let
|
|
119
|
+
pub fn cmd_fit(requirements_p: &Path, root: &Path, header_arg: &str, flags: &Flags) -> ExitCode {
|
|
120
|
+
let requirements = ok!(TensorRequirements::parse(&rd!(requirements_p)));
|
|
121
121
|
let header = match tensorfs_core::ids::hex64("header", header_arg) {
|
|
122
122
|
Ok(_) => {
|
|
123
123
|
let store = ok!(Store::open(root));
|
|
@@ -152,7 +152,7 @@ pub fn cmd_fit(code_p: &Path, root: &Path, header_arg: &str, flags: &Flags) -> E
|
|
|
152
152
|
}
|
|
153
153
|
let t = Instant::now();
|
|
154
154
|
let verdict = ok!(fit::fit(
|
|
155
|
-
&
|
|
155
|
+
&requirements,
|
|
156
156
|
&header,
|
|
157
157
|
custody,
|
|
158
158
|
device,
|
|
@@ -178,7 +178,7 @@ pub fn cmd_fit(code_p: &Path, root: &Path, header_arg: &str, flags: &Flags) -> E
|
|
|
178
178
|
ExitCode::from(verdict.exit_code())
|
|
179
179
|
}
|
|
180
180
|
|
|
181
|
-
/// Build a canonical header +
|
|
181
|
+
/// Build a canonical header + tensor requirements out of NEUTRAL measured rows.
|
|
182
182
|
///
|
|
183
183
|
/// The rows carry component, key, logical dtype/shape and the measured role geometry, and
|
|
184
184
|
/// nothing else — no format marks, no canonical bytes. That split is deliberate: the
|
|
@@ -219,7 +219,7 @@ pub fn cmd_import(rows_p: &Path, flags: &Flags) -> ExitCode {
|
|
|
219
219
|
|
|
220
220
|
let mut closure = tensorfs_core::header::Closure::default();
|
|
221
221
|
let mut out: Vec<(String, tensorfs_core::header::Tensor)> = Vec::new();
|
|
222
|
-
let mut reqs: Vec<(String,
|
|
222
|
+
let mut reqs: Vec<(String, TensorRequirement)> = Vec::new();
|
|
223
223
|
for tv in tensors {
|
|
224
224
|
let mut tf = match tensorfs_core::canon::Fields::new("row", tv) {
|
|
225
225
|
Ok(x) => x,
|
|
@@ -327,7 +327,7 @@ pub fn cmd_import(rows_p: &Path, flags: &Flags) -> ExitCode {
|
|
|
327
327
|
));
|
|
328
328
|
reqs.push((
|
|
329
329
|
key,
|
|
330
|
-
|
|
330
|
+
TensorRequirement {
|
|
331
331
|
dtype,
|
|
332
332
|
shape,
|
|
333
333
|
accepts: Accepts::OneOf(vec![sid]),
|
|
@@ -366,7 +366,7 @@ pub fn cmd_import(rows_p: &Path, flags: &Flags) -> ExitCode {
|
|
|
366
366
|
components: vec![(component.clone(), out)],
|
|
367
367
|
};
|
|
368
368
|
ok!(header.validate(&closure));
|
|
369
|
-
let
|
|
369
|
+
let requirements = TensorRequirements {
|
|
370
370
|
contract: tensorfs_core::ids::object_id(provenance.as_bytes()),
|
|
371
371
|
components: vec![(component.clone(), reqs)],
|
|
372
372
|
constructed_components: vec![component],
|
|
@@ -374,8 +374,8 @@ pub fn cmd_import(rows_p: &Path, flags: &Flags) -> ExitCode {
|
|
|
374
374
|
if let Some(p) = flag(flags, "out-header") {
|
|
375
375
|
let _ = fs::write(p, ok!(header.canonical_bytes()));
|
|
376
376
|
}
|
|
377
|
-
if let Some(p) = flag(flags, "out-
|
|
378
|
-
let _ = fs::write(p,
|
|
377
|
+
if let Some(p) = flag(flags, "out-requirements") {
|
|
378
|
+
let _ = fs::write(p, requirements.canonical_bytes());
|
|
379
379
|
}
|
|
380
380
|
if let Some(d) = flag(flags, "out-closure") {
|
|
381
381
|
let _ = fs::create_dir_all(d);
|
|
@@ -394,7 +394,7 @@ pub fn cmd_import(rows_p: &Path, flags: &Flags) -> ExitCode {
|
|
|
394
394
|
println!(" parts PLACEHOLDER object ids: no weight bytes transit this machine");
|
|
395
395
|
println!("header {}", ok!(header.object_id()));
|
|
396
396
|
println!("tensor schema {}", header.tensor_schema_digest());
|
|
397
|
-
println!("
|
|
397
|
+
println!("requirements {}", requirements.object_id());
|
|
398
398
|
for (id, s) in &closure.specs {
|
|
399
399
|
println!(
|
|
400
400
|
" spec {} roles {:?}",
|
|
@@ -497,7 +497,7 @@ fn emit_bytes(bytes: &[u8], flags: &Flags) {
|
|
|
497
497
|
}
|
|
498
498
|
|
|
499
499
|
/// `check_compatibility` over two documents on disk. Zero tensor bytes are read: the whole
|
|
500
|
-
/// decision is a function of
|
|
500
|
+
/// decision is a function of tensor requirements, a header and a closure, which is exactly why
|
|
501
501
|
/// it is decidable before a download.
|
|
502
502
|
///
|
|
503
503
|
/// `--depth` picks the question. The default is `first-mismatch` — PREFLIGHT, "can this
|
|
@@ -512,8 +512,8 @@ fn emit_bytes(bytes: &[u8], flags: &Flags) {
|
|
|
512
512
|
/// be read" and "some card has a qualified implementation for them" are two independent
|
|
513
513
|
/// questions; the second is `tfs capability`, and a caller cannot ask it without knowing
|
|
514
514
|
/// which pairs to ask about.
|
|
515
|
-
pub fn cmd_check(
|
|
516
|
-
let
|
|
515
|
+
pub fn cmd_check(requirements_p: &Path, header_p: &Path, flags: &Flags) -> ExitCode {
|
|
516
|
+
let requirements = ok!(TensorRequirements::parse(&rd!(requirements_p)));
|
|
517
517
|
let header = ok!(Header::parse(&rd!(header_p)));
|
|
518
518
|
let mut closure = tensorfs_core::header::Closure::default();
|
|
519
519
|
for p in flag(flags, "closure").unwrap_or("").split(',') {
|
|
@@ -540,10 +540,20 @@ pub fn cmd_check(code_p: &Path, header_p: &Path, flags: &Flags) -> ExitCode {
|
|
|
540
540
|
));
|
|
541
541
|
let t = Instant::now();
|
|
542
542
|
let out = ok!(fit::check_compatibility(
|
|
543
|
-
&
|
|
543
|
+
&requirements,
|
|
544
|
+
&header,
|
|
545
|
+
&closure,
|
|
546
|
+
&pin,
|
|
547
|
+
custody,
|
|
548
|
+
depth
|
|
544
549
|
));
|
|
545
550
|
let us = t.elapsed().as_secs_f64() * 1e6;
|
|
546
|
-
let report = ok!(CompatibilityReport::of(
|
|
551
|
+
let report = ok!(CompatibilityReport::of(
|
|
552
|
+
&requirements,
|
|
553
|
+
&header,
|
|
554
|
+
custody,
|
|
555
|
+
&out
|
|
556
|
+
));
|
|
547
557
|
emit(&report, flags);
|
|
548
558
|
|
|
549
559
|
// The machine surface (proto-020). A caller that shells out to this command must not
|
|
@@ -780,11 +790,11 @@ pub fn cmd_grade(report_p: &Path, flags: &Flags) -> ExitCode {
|
|
|
780
790
|
Err(c) => return c,
|
|
781
791
|
};
|
|
782
792
|
// Grading over a report ALONE cannot prove a registration closes the whole gap; holding
|
|
783
|
-
// both documents can. `--
|
|
793
|
+
// both documents can. `--requirements`/`--header` supply them here.
|
|
784
794
|
let t = Instant::now();
|
|
785
|
-
let g = match (flag(flags, "
|
|
795
|
+
let g = match (flag(flags, "requirements"), flag(flags, "header")) {
|
|
786
796
|
(Some(c), Some(h)) => {
|
|
787
|
-
let
|
|
797
|
+
let requirements = ok!(TensorRequirements::parse(&rd!(Path::new(c))));
|
|
788
798
|
let header = ok!(Header::parse(&rd!(Path::new(h))));
|
|
789
799
|
let mut closure = tensorfs_core::header::Closure::default();
|
|
790
800
|
for p in flag(flags, "closure").unwrap_or("").split(',') {
|
|
@@ -801,7 +811,7 @@ pub fn cmd_grade(report_p: &Path, flags: &Flags) -> ExitCode {
|
|
|
801
811
|
.collect(),
|
|
802
812
|
};
|
|
803
813
|
ok!(grade::resolve(
|
|
804
|
-
&
|
|
814
|
+
&requirements,
|
|
805
815
|
&header,
|
|
806
816
|
&closure,
|
|
807
817
|
&pin,
|
|
@@ -968,14 +978,14 @@ fn stream_in(path: Option<&Path>) -> Result<(Box<dyn BufRead>, bool), ExitCode>
|
|
|
968
978
|
/// same document — literally the same `grade_json` — so the single-pair form is not a
|
|
969
979
|
/// different surface with a shared name, and a preflight caller is never made to batch.
|
|
970
980
|
///
|
|
971
|
-
/// The registry is loaded ONCE for the whole stream. `--prove-with` (`--
|
|
981
|
+
/// The registry is loaded ONCE for the whole stream. `--prove-with` (`--requirements`/`--header`)
|
|
972
982
|
/// is single-pair only: proving a registration closes the whole gap needs both documents of
|
|
973
983
|
/// THAT pair, and a batch has one registry and many pairs.
|
|
974
984
|
pub fn cmd_grade_stream(path: Option<&Path>, flags: &Flags) -> ExitCode {
|
|
975
|
-
if flag(flags, "
|
|
985
|
+
if flag(flags, "requirements").is_some() || flag(flags, "header").is_some() {
|
|
976
986
|
eprintln!(
|
|
977
|
-
"REFUSED UNKNOWN_FIELD: --prove-with is single-pair only: it holds the
|
|
978
|
-
|
|
987
|
+
"REFUSED UNKNOWN_FIELD: --prove-with is single-pair only: it holds the tensor \
|
|
988
|
+
requirements and header of ONE pair, and a batch carries many"
|
|
979
989
|
);
|
|
980
990
|
return ExitCode::FAILURE;
|
|
981
991
|
}
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
//! distinct code per refusal (10..16, see `Fit::exit_code`); `--json` prints the machine
|
|
25
25
|
//! document.
|
|
26
26
|
//!
|
|
27
|
-
//! tfs fit <
|
|
27
|
+
//! tfs fit <tensor-requirements.json> <root> <header> [--custody canonical|local]
|
|
28
28
|
//! [--device <class> --observations <obs.json>] [--json]
|
|
29
29
|
//!
|
|
30
30
|
//! Qualification (tfs-008): what an (encoding, device) pair is QUALIFIED to execute.
|
|
@@ -95,7 +95,9 @@ use std::time::Instant;
|
|
|
95
95
|
use tensorfs_core::canon;
|
|
96
96
|
use tensorfs_core::dtype::Dtype;
|
|
97
97
|
use tensorfs_core::err::Refusal;
|
|
98
|
-
use tensorfs_core::fit::{
|
|
98
|
+
use tensorfs_core::fit::{
|
|
99
|
+
self, Accepts, CompatibilityReport, Custody, TensorRequirement, TensorRequirements,
|
|
100
|
+
};
|
|
99
101
|
use tensorfs_core::grade::{self, ConversionRegistration, Mapping};
|
|
100
102
|
use tensorfs_core::header::{Asset, Body, Closure, Header, Part, Tensor};
|
|
101
103
|
use tensorfs_core::ids::{Doc, ObjectRef, Plain};
|
|
@@ -248,7 +250,7 @@ fn main() -> ExitCode {
|
|
|
248
250
|
["fetch", "admit", r, p, i] => fetch::cmd_admit(Path::new(r), Path::new(p), i, &flags),
|
|
249
251
|
["fetch", "complete", r, p] => fetch::cmd_complete(Path::new(r), Path::new(p)),
|
|
250
252
|
["compat", "import", r] => layout::cmd_import(Path::new(r), &flags),
|
|
251
|
-
["compat", "
|
|
253
|
+
["compat", "requirements", r, h] => layout::cmd_requirements(Path::new(r), h, &flags),
|
|
252
254
|
["compat", "check", c, h] => layout::cmd_check(Path::new(c), Path::new(h), &flags),
|
|
253
255
|
["compat", "release-cut", r] => layout::cmd_release_cut(Path::new(r)),
|
|
254
256
|
["grade", "decision", d] => layout::cmd_decision(Path::new(d)),
|
|
@@ -902,24 +904,24 @@ fn stamp_doc(
|
|
|
902
904
|
}
|
|
903
905
|
|
|
904
906
|
/// The layout plane's three frozen documents, all derived from the corpus header so the
|
|
905
|
-
/// vector and the live path cannot describe different things. The
|
|
906
|
-
/// header's
|
|
907
|
+
/// vector and the live path cannot describe different things. The requirements are the
|
|
908
|
+
/// header's own tensor schema (a contract that asks for exactly what is there is the Satisfied
|
|
907
909
|
/// case), and the registration is run, not asserted.
|
|
908
910
|
#[allow(clippy::type_complexity)]
|
|
909
911
|
/// The layout plane's frozen documents, produced together because every one of them is a
|
|
910
912
|
/// projection of the SAME header and the same base contract — which is what makes the
|
|
911
913
|
/// verdicts they earn comparable.
|
|
912
914
|
struct LayoutPlane {
|
|
913
|
-
|
|
915
|
+
requirements: TensorRequirements,
|
|
914
916
|
report: CompatibilityReport,
|
|
915
917
|
registration: ConversionRegistration,
|
|
916
918
|
worst_full: CompatibilityReport,
|
|
917
919
|
worst_first: CompatibilityReport,
|
|
918
|
-
recast:
|
|
920
|
+
recast: TensorRequirements,
|
|
919
921
|
recast_report: CompatibilityReport,
|
|
920
922
|
/// The planted contract behind `worst_*`: a dtype cast on the first key and a shape
|
|
921
923
|
/// edit on the last, the `tfs fit` shape-mismatch arm.
|
|
922
|
-
worst:
|
|
924
|
+
worst: TensorRequirements,
|
|
923
925
|
/// The CONVERTIBLE arm: every required dtype widened to f32, which the registered
|
|
924
926
|
/// lossless bf16 -> f32 mapping closes. CONVERTIBLE is the only grade that populates
|
|
925
927
|
/// `remedy_registration` and `remedy_mapping`, and tensorhub reads both, so the machine
|
|
@@ -928,8 +930,8 @@ struct LayoutPlane {
|
|
|
928
930
|
}
|
|
929
931
|
|
|
930
932
|
fn layout_plane_docs(h: &Header, closure: &Closure) -> TfsResult<LayoutPlane> {
|
|
931
|
-
let
|
|
932
|
-
contract: tensorfs_core::ids::object_id(b"
|
|
933
|
+
let requirements = TensorRequirements {
|
|
934
|
+
contract: tensorfs_core::ids::object_id(b"TensorRequirements:corpus"),
|
|
933
935
|
components: h
|
|
934
936
|
.components
|
|
935
937
|
.iter()
|
|
@@ -940,7 +942,7 @@ fn layout_plane_docs(h: &Header, closure: &Closure) -> TfsResult<LayoutPlane> {
|
|
|
940
942
|
.map(|(k, t)| {
|
|
941
943
|
(
|
|
942
944
|
k.clone(),
|
|
943
|
-
|
|
945
|
+
TensorRequirement {
|
|
944
946
|
dtype: t.dtype,
|
|
945
947
|
shape: t.shape.clone(),
|
|
946
948
|
accepts: Accepts::Any,
|
|
@@ -956,14 +958,14 @@ fn layout_plane_docs(h: &Header, closure: &Closure) -> TfsResult<LayoutPlane> {
|
|
|
956
958
|
};
|
|
957
959
|
let pin: Vec<String> = h.encodings.iter().map(EncodingSpec::object_id).collect();
|
|
958
960
|
let out = fit::check_compatibility(
|
|
959
|
-
&
|
|
961
|
+
&requirements,
|
|
960
962
|
h,
|
|
961
963
|
closure,
|
|
962
964
|
&pin,
|
|
963
965
|
Custody::Canonical,
|
|
964
966
|
fit::Depth::Full,
|
|
965
967
|
)?;
|
|
966
|
-
let report = CompatibilityReport::of(&
|
|
968
|
+
let report = CompatibilityReport::of(&requirements, h, Custody::Canonical, &out)?;
|
|
967
969
|
let reg = ConversionRegistration::register(
|
|
968
970
|
"bf16-to-f32",
|
|
969
971
|
Mapping::Widen {
|
|
@@ -981,7 +983,7 @@ fn layout_plane_docs(h: &Header, closure: &Closure) -> TfsResult<LayoutPlane> {
|
|
|
981
983
|
// Graded on the FIRST fact the pair reads PRODUCIBLE and a catalog would offer the
|
|
982
984
|
// conversion; graded on the WHOLE set it is INCOMPATIBLE. Both reports are frozen with
|
|
983
985
|
// their verdicts so the two answers cannot silently become one.
|
|
984
|
-
let mut worst =
|
|
986
|
+
let mut worst = requirements.clone();
|
|
985
987
|
let keys: usize = worst.components.iter().map(|(_, k)| k.len()).sum();
|
|
986
988
|
if keys < 2 {
|
|
987
989
|
return Err(tensorfs_core::err::Refusal {
|
|
@@ -1010,7 +1012,7 @@ fn layout_plane_docs(h: &Header, closure: &Closure) -> TfsResult<LayoutPlane> {
|
|
|
1010
1012
|
// The same contract with every required dtype recast and NOTHING else touched. This
|
|
1011
1013
|
// remains a compact regression for the dtype-remedy path after deleting the old
|
|
1012
1014
|
// shape-only catalog index.
|
|
1013
|
-
let mut recast =
|
|
1015
|
+
let mut recast = requirements.clone();
|
|
1014
1016
|
for (_, keys) in recast.components.iter_mut() {
|
|
1015
1017
|
for (_, r) in keys.iter_mut() {
|
|
1016
1018
|
r.dtype = Dtype::F8E4M3FN;
|
|
@@ -1028,7 +1030,7 @@ fn layout_plane_docs(h: &Header, closure: &Closure) -> TfsResult<LayoutPlane> {
|
|
|
1028
1030
|
|
|
1029
1031
|
// THE CONVERTIBLE ARM. Same shape as the recast above, widened the other way: every
|
|
1030
1032
|
// required dtype becomes f32, so the gap is exactly the lossless cast `reg` registers.
|
|
1031
|
-
let mut widen =
|
|
1033
|
+
let mut widen = requirements.clone();
|
|
1032
1034
|
for (_, keys) in widen.components.iter_mut() {
|
|
1033
1035
|
for (_, r) in keys.iter_mut() {
|
|
1034
1036
|
r.dtype = Dtype::F32;
|
|
@@ -1044,7 +1046,7 @@ fn layout_plane_docs(h: &Header, closure: &Closure) -> TfsResult<LayoutPlane> {
|
|
|
1044
1046
|
)?;
|
|
1045
1047
|
let widen_report = CompatibilityReport::of(&widen, h, Custody::Canonical, &out)?;
|
|
1046
1048
|
Ok(LayoutPlane {
|
|
1047
|
-
|
|
1049
|
+
requirements,
|
|
1048
1050
|
report,
|
|
1049
1051
|
registration: reg,
|
|
1050
1052
|
worst_full: whole_set,
|
|
@@ -1268,7 +1270,7 @@ fn build_corpus() -> TfsResult<(Vec<Case>, Vec<EncodingSpec>)> {
|
|
|
1268
1270
|
"stamp",
|
|
1269
1271
|
"stamp",
|
|
1270
1272
|
stmp.canonical_bytes(),
|
|
1271
|
-
"the verified ledger:
|
|
1273
|
+
"the verified ledger: tensor schema, candidate set, converter, golden, accounting",
|
|
1272
1274
|
));
|
|
1273
1275
|
cases.push(ok_case(
|
|
1274
1276
|
"ingest",
|
|
@@ -1278,9 +1280,9 @@ fn build_corpus() -> TfsResult<(Vec<Case>, Vec<EncodingSpec>)> {
|
|
|
1278
1280
|
"one evidence arm; signer in the envelope; binds its stamp",
|
|
1279
1281
|
));
|
|
1280
1282
|
|
|
1281
|
-
// --- the layout plane (tfs-009):
|
|
1283
|
+
// --- the layout plane (tfs-009): tensor requirements, report, registration
|
|
1282
1284
|
let LayoutPlane {
|
|
1283
|
-
|
|
1285
|
+
requirements,
|
|
1284
1286
|
report,
|
|
1285
1287
|
registration: reg,
|
|
1286
1288
|
worst_full,
|
|
@@ -1292,9 +1294,9 @@ fn build_corpus() -> TfsResult<(Vec<Case>, Vec<EncodingSpec>)> {
|
|
|
1292
1294
|
} = layout_plane_docs(&ha, &closure)?;
|
|
1293
1295
|
cases.push(ok_case(
|
|
1294
1296
|
"layout",
|
|
1295
|
-
"
|
|
1296
|
-
"
|
|
1297
|
-
|
|
1297
|
+
"tensor-requirements",
|
|
1298
|
+
"tensor_requirements",
|
|
1299
|
+
requirements.canonical_bytes(),
|
|
1298
1300
|
"the meta-device census of factory(config), projected: accepts, pinned dtypes, \
|
|
1299
1301
|
constructed components",
|
|
1300
1302
|
));
|
|
@@ -1326,8 +1328,8 @@ fn build_corpus() -> TfsResult<(Vec<Case>, Vec<EncodingSpec>)> {
|
|
|
1326
1328
|
));
|
|
1327
1329
|
cases.push(ok_case(
|
|
1328
1330
|
"layout",
|
|
1329
|
-
"
|
|
1330
|
-
"
|
|
1331
|
+
"tensor-requirements-recast",
|
|
1332
|
+
"tensor_requirements",
|
|
1331
1333
|
recast.canonical_bytes(),
|
|
1332
1334
|
"the same contract with only the dtypes recast: a different tensor schema digest",
|
|
1333
1335
|
));
|
|
@@ -1375,21 +1377,21 @@ fn build_corpus() -> TfsResult<(Vec<Case>, Vec<EncodingSpec>)> {
|
|
|
1375
1377
|
cases.push(red_case(
|
|
1376
1378
|
"layout-red",
|
|
1377
1379
|
"unconstructed-component",
|
|
1378
|
-
"
|
|
1380
|
+
"tensor_requirements",
|
|
1379
1381
|
sub(
|
|
1380
|
-
&
|
|
1382
|
+
&requirements.canonical_bytes(),
|
|
1381
1383
|
"\"constructed_components\":[",
|
|
1382
1384
|
"\"constructed_components\":[\"ghost\",",
|
|
1383
1385
|
),
|
|
1384
1386
|
"MISSING_COMPONENT",
|
|
1385
|
-
"constructed_components names exactly the components the
|
|
1387
|
+
"constructed_components names exactly the components the requirements carry",
|
|
1386
1388
|
));
|
|
1387
1389
|
cases.push(red_case(
|
|
1388
1390
|
"layout-red",
|
|
1389
1391
|
"empty-accepts",
|
|
1390
|
-
"
|
|
1392
|
+
"tensor_requirements",
|
|
1391
1393
|
sub(
|
|
1392
|
-
&
|
|
1394
|
+
&requirements.canonical_bytes(),
|
|
1393
1395
|
"\"accepts\":\"any\"",
|
|
1394
1396
|
"\"accepts\":[]",
|
|
1395
1397
|
),
|
|
@@ -1553,13 +1555,13 @@ fn build_corpus() -> TfsResult<(Vec<Case>, Vec<EncodingSpec>)> {
|
|
|
1553
1555
|
// `tfs fit --json` (tfs-042): the one code <-> checkpoint answer, frozen on the ok arm
|
|
1554
1556
|
// and on a planted shape edit so the eight-code vocabulary and its §3 text are held.
|
|
1555
1557
|
{
|
|
1556
|
-
let ok = fit::fit(&
|
|
1558
|
+
let ok = fit::fit(&requirements, &ha, Custody::Canonical, Some("cpu"), None)?;
|
|
1557
1559
|
cases.push(ok_case(
|
|
1558
1560
|
"machine",
|
|
1559
1561
|
"fit-ok",
|
|
1560
1562
|
"machine_fit",
|
|
1561
1563
|
tensorfs_core::machine::fit_json(&ok, Custody::Canonical),
|
|
1562
|
-
"the
|
|
1564
|
+
"the requirements describe exactly what the checkpoint carries: `ok`, routes counted, \
|
|
1563
1565
|
encoded leaves qualified on the device asked about",
|
|
1564
1566
|
));
|
|
1565
1567
|
let planted = fit::fit(&worst, &ha, Custody::Canonical, None, None)?;
|
|
@@ -2283,8 +2285,8 @@ fn cmd_gen(dir: &Path) -> ExitCode {
|
|
|
2283
2285
|
let h = Header::parse(&c.bytes).unwrap();
|
|
2284
2286
|
v += &format!("tensor_schema: {}\n", h.tensor_schema_digest());
|
|
2285
2287
|
}
|
|
2286
|
-
if c.doc == "
|
|
2287
|
-
let code = tensorfs_core::fit::
|
|
2288
|
+
if c.doc == "tensor_requirements" {
|
|
2289
|
+
let code = tensorfs_core::fit::TensorRequirements::parse(&c.bytes).unwrap();
|
|
2288
2290
|
v += &format!("tensor_schema: {}\n", code.tensor_schema_digest());
|
|
2289
2291
|
}
|
|
2290
2292
|
if c.doc == "manifest" {
|
|
@@ -45,7 +45,7 @@ fn load(root: &Path, hex: &str) -> Result<(Store, Manifest, Header), Refusal> {
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
/// Every component this header carries. The `tfs` CLI's own plans are whole-artifact by
|
|
48
|
-
/// construction — it has no
|
|
48
|
+
/// construction — it has no tensor requirements to narrow by — so it declares the full set
|
|
49
49
|
/// (#570b). A caller that binds a subset declares the subset.
|
|
50
50
|
fn all_components(h: &Header) -> Vec<String> {
|
|
51
51
|
h.components.iter().map(|(c, _)| c.clone()).collect()
|
|
@@ -42,7 +42,7 @@ pub const DOC_KINDS: &[&str] = &[
|
|
|
42
42
|
"session",
|
|
43
43
|
"receipt",
|
|
44
44
|
"stamp",
|
|
45
|
-
"
|
|
45
|
+
"tensor_requirements",
|
|
46
46
|
"compat_report",
|
|
47
47
|
// proto-020: the CLI's `--json` machine surfaces, frozen like every other
|
|
48
48
|
// cross-boundary document because they ARE one — tensorhub decodes them.
|
|
@@ -96,9 +96,9 @@ pub fn run_doc(
|
|
|
96
96
|
"session" => IngestSession::parse(bytes).map(|_| (None, None))?,
|
|
97
97
|
"receipt" => IngestVerificationReceipt::parse(bytes).map(|_| (None, None))?,
|
|
98
98
|
"stamp" => crate::ingest::stamp::Stamp::parse(bytes).map(|_| (None, None))?,
|
|
99
|
-
// The layout plane's documents (tfs-009). A
|
|
99
|
+
// The layout plane's documents (tfs-009). A tensor requirements projects to the SAME
|
|
100
100
|
// frozen projection a header does, so its digest is reported here too.
|
|
101
|
-
"
|
|
101
|
+
"tensor_requirements" => crate::fit::TensorRequirements::parse(bytes)
|
|
102
102
|
.map(|c| (Some(c.tensor_schema_digest()), None))?,
|
|
103
103
|
// The machine surfaces (proto-020). The document is a projection, not a stored
|
|
104
104
|
// object, so there is no reader to round-trip it through: what a consumer needs
|