From 0194f2317ac8ee9d7561a9891918d4bfaed40fbd Mon Sep 17 00:00:00 2001 From: Xuanwo Date: Wed, 12 Aug 2026 16:44:38 +0800 Subject: [PATCH] build: pin Lance no-op update attachment fix --- Cargo.lock | 44 +++---- Cargo.toml | 28 ++-- ...ma_metadata_updates_dependency_contract.rs | 120 +++++++++++++++++- 3 files changed, 151 insertions(+), 41 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1b0ddc89d..6d55e02d4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3456,7 +3456,7 @@ checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" [[package]] name = "fsst" version = "11.0.0-beta.4" -source = "git+https://github.com/lance-format/lance.git?rev=357d678be223f6e785d0ccaf39ac8a5ba1793dcc#357d678be223f6e785d0ccaf39ac8a5ba1793dcc" +source = "git+https://github.com/lance-format/lance.git?rev=dacbf6ecccc7a1a804a8cb150204a41f2ae248ce#dacbf6ecccc7a1a804a8cb150204a41f2ae248ce" dependencies = [ "arrow-array", "rand 0.9.5", @@ -4816,7 +4816,7 @@ checksum = "e037a2e1d8d5fdbd49b16a4ea09d5d6401c1f29eca5ff29d03d3824dba16256a" [[package]] name = "lance" version = "11.0.0-beta.4" -source = "git+https://github.com/lance-format/lance.git?rev=357d678be223f6e785d0ccaf39ac8a5ba1793dcc#357d678be223f6e785d0ccaf39ac8a5ba1793dcc" +source = "git+https://github.com/lance-format/lance.git?rev=dacbf6ecccc7a1a804a8cb150204a41f2ae248ce#dacbf6ecccc7a1a804a8cb150204a41f2ae248ce" dependencies = [ "arc-swap", "arrow", @@ -4891,7 +4891,7 @@ dependencies = [ [[package]] name = "lance-arrow" version = "11.0.0-beta.4" -source = "git+https://github.com/lance-format/lance.git?rev=357d678be223f6e785d0ccaf39ac8a5ba1793dcc#357d678be223f6e785d0ccaf39ac8a5ba1793dcc" +source = "git+https://github.com/lance-format/lance.git?rev=dacbf6ecccc7a1a804a8cb150204a41f2ae248ce#dacbf6ecccc7a1a804a8cb150204a41f2ae248ce" dependencies = [ "arrow-array", "arrow-buffer", @@ -4913,7 +4913,7 @@ dependencies = [ [[package]] name = "lance-arrow-scalar" version = "58.0.0" -source = "git+https://github.com/lance-format/lance.git?rev=357d678be223f6e785d0ccaf39ac8a5ba1793dcc#357d678be223f6e785d0ccaf39ac8a5ba1793dcc" +source = "git+https://github.com/lance-format/lance.git?rev=dacbf6ecccc7a1a804a8cb150204a41f2ae248ce#dacbf6ecccc7a1a804a8cb150204a41f2ae248ce" dependencies = [ "arrow-array", "arrow-buffer", @@ -4927,7 +4927,7 @@ dependencies = [ [[package]] name = "lance-arrow-stats" version = "58.0.0" -source = "git+https://github.com/lance-format/lance.git?rev=357d678be223f6e785d0ccaf39ac8a5ba1793dcc#357d678be223f6e785d0ccaf39ac8a5ba1793dcc" +source = "git+https://github.com/lance-format/lance.git?rev=dacbf6ecccc7a1a804a8cb150204a41f2ae248ce#dacbf6ecccc7a1a804a8cb150204a41f2ae248ce" dependencies = [ "arrow-array", "arrow-schema", @@ -4937,7 +4937,7 @@ dependencies = [ [[package]] name = "lance-bitpacking" version = "11.0.0-beta.4" -source = "git+https://github.com/lance-format/lance.git?rev=357d678be223f6e785d0ccaf39ac8a5ba1793dcc#357d678be223f6e785d0ccaf39ac8a5ba1793dcc" +source = "git+https://github.com/lance-format/lance.git?rev=dacbf6ecccc7a1a804a8cb150204a41f2ae248ce#dacbf6ecccc7a1a804a8cb150204a41f2ae248ce" dependencies = [ "arrayref", "crunchy", @@ -4948,7 +4948,7 @@ dependencies = [ [[package]] name = "lance-core" version = "11.0.0-beta.4" -source = "git+https://github.com/lance-format/lance.git?rev=357d678be223f6e785d0ccaf39ac8a5ba1793dcc#357d678be223f6e785d0ccaf39ac8a5ba1793dcc" +source = "git+https://github.com/lance-format/lance.git?rev=dacbf6ecccc7a1a804a8cb150204a41f2ae248ce#dacbf6ecccc7a1a804a8cb150204a41f2ae248ce" dependencies = [ "arrow-array", "arrow-buffer", @@ -4989,7 +4989,7 @@ dependencies = [ [[package]] name = "lance-datafusion" version = "11.0.0-beta.4" -source = "git+https://github.com/lance-format/lance.git?rev=357d678be223f6e785d0ccaf39ac8a5ba1793dcc#357d678be223f6e785d0ccaf39ac8a5ba1793dcc" +source = "git+https://github.com/lance-format/lance.git?rev=dacbf6ecccc7a1a804a8cb150204a41f2ae248ce#dacbf6ecccc7a1a804a8cb150204a41f2ae248ce" dependencies = [ "arrow", "arrow-array", @@ -5020,7 +5020,7 @@ dependencies = [ [[package]] name = "lance-datagen" version = "11.0.0-beta.4" -source = "git+https://github.com/lance-format/lance.git?rev=357d678be223f6e785d0ccaf39ac8a5ba1793dcc#357d678be223f6e785d0ccaf39ac8a5ba1793dcc" +source = "git+https://github.com/lance-format/lance.git?rev=dacbf6ecccc7a1a804a8cb150204a41f2ae248ce#dacbf6ecccc7a1a804a8cb150204a41f2ae248ce" dependencies = [ "arrow", "arrow-array", @@ -5038,7 +5038,7 @@ dependencies = [ [[package]] name = "lance-derive" version = "11.0.0-beta.4" -source = "git+https://github.com/lance-format/lance.git?rev=357d678be223f6e785d0ccaf39ac8a5ba1793dcc#357d678be223f6e785d0ccaf39ac8a5ba1793dcc" +source = "git+https://github.com/lance-format/lance.git?rev=dacbf6ecccc7a1a804a8cb150204a41f2ae248ce#dacbf6ecccc7a1a804a8cb150204a41f2ae248ce" dependencies = [ "proc-macro2", "quote", @@ -5048,7 +5048,7 @@ dependencies = [ [[package]] name = "lance-encoding" version = "11.0.0-beta.4" -source = "git+https://github.com/lance-format/lance.git?rev=357d678be223f6e785d0ccaf39ac8a5ba1793dcc#357d678be223f6e785d0ccaf39ac8a5ba1793dcc" +source = "git+https://github.com/lance-format/lance.git?rev=dacbf6ecccc7a1a804a8cb150204a41f2ae248ce#dacbf6ecccc7a1a804a8cb150204a41f2ae248ce" dependencies = [ "arrow-arith", "arrow-array", @@ -5083,7 +5083,7 @@ dependencies = [ [[package]] name = "lance-file" version = "11.0.0-beta.4" -source = "git+https://github.com/lance-format/lance.git?rev=357d678be223f6e785d0ccaf39ac8a5ba1793dcc#357d678be223f6e785d0ccaf39ac8a5ba1793dcc" +source = "git+https://github.com/lance-format/lance.git?rev=dacbf6ecccc7a1a804a8cb150204a41f2ae248ce#dacbf6ecccc7a1a804a8cb150204a41f2ae248ce" dependencies = [ "arrow-arith", "arrow-array", @@ -5115,7 +5115,7 @@ dependencies = [ [[package]] name = "lance-index" version = "11.0.0-beta.4" -source = "git+https://github.com/lance-format/lance.git?rev=357d678be223f6e785d0ccaf39ac8a5ba1793dcc#357d678be223f6e785d0ccaf39ac8a5ba1793dcc" +source = "git+https://github.com/lance-format/lance.git?rev=dacbf6ecccc7a1a804a8cb150204a41f2ae248ce#dacbf6ecccc7a1a804a8cb150204a41f2ae248ce" dependencies = [ "arc-swap", "arrow", @@ -5183,7 +5183,7 @@ dependencies = [ [[package]] name = "lance-index-core" version = "11.0.0-beta.4" -source = "git+https://github.com/lance-format/lance.git?rev=357d678be223f6e785d0ccaf39ac8a5ba1793dcc#357d678be223f6e785d0ccaf39ac8a5ba1793dcc" +source = "git+https://github.com/lance-format/lance.git?rev=dacbf6ecccc7a1a804a8cb150204a41f2ae248ce#dacbf6ecccc7a1a804a8cb150204a41f2ae248ce" dependencies = [ "arrow-array", "arrow-schema", @@ -5206,7 +5206,7 @@ dependencies = [ [[package]] name = "lance-io" version = "11.0.0-beta.4" -source = "git+https://github.com/lance-format/lance.git?rev=357d678be223f6e785d0ccaf39ac8a5ba1793dcc#357d678be223f6e785d0ccaf39ac8a5ba1793dcc" +source = "git+https://github.com/lance-format/lance.git?rev=dacbf6ecccc7a1a804a8cb150204a41f2ae248ce#dacbf6ecccc7a1a804a8cb150204a41f2ae248ce" dependencies = [ "arrow", "arrow-array", @@ -5243,7 +5243,7 @@ dependencies = [ [[package]] name = "lance-linalg" version = "11.0.0-beta.4" -source = "git+https://github.com/lance-format/lance.git?rev=357d678be223f6e785d0ccaf39ac8a5ba1793dcc#357d678be223f6e785d0ccaf39ac8a5ba1793dcc" +source = "git+https://github.com/lance-format/lance.git?rev=dacbf6ecccc7a1a804a8cb150204a41f2ae248ce#dacbf6ecccc7a1a804a8cb150204a41f2ae248ce" dependencies = [ "arrow-array", "arrow-buffer", @@ -5260,7 +5260,7 @@ dependencies = [ [[package]] name = "lance-namespace" version = "11.0.0-beta.4" -source = "git+https://github.com/lance-format/lance.git?rev=357d678be223f6e785d0ccaf39ac8a5ba1793dcc#357d678be223f6e785d0ccaf39ac8a5ba1793dcc" +source = "git+https://github.com/lance-format/lance.git?rev=dacbf6ecccc7a1a804a8cb150204a41f2ae248ce#dacbf6ecccc7a1a804a8cb150204a41f2ae248ce" dependencies = [ "arrow", "async-trait", @@ -5273,7 +5273,7 @@ dependencies = [ [[package]] name = "lance-namespace-impls" version = "11.0.0-beta.4" -source = "git+https://github.com/lance-format/lance.git?rev=357d678be223f6e785d0ccaf39ac8a5ba1793dcc#357d678be223f6e785d0ccaf39ac8a5ba1793dcc" +source = "git+https://github.com/lance-format/lance.git?rev=dacbf6ecccc7a1a804a8cb150204a41f2ae248ce#dacbf6ecccc7a1a804a8cb150204a41f2ae248ce" dependencies = [ "arrow", "arrow-ipc", @@ -5327,7 +5327,7 @@ dependencies = [ [[package]] name = "lance-select" version = "11.0.0-beta.4" -source = "git+https://github.com/lance-format/lance.git?rev=357d678be223f6e785d0ccaf39ac8a5ba1793dcc#357d678be223f6e785d0ccaf39ac8a5ba1793dcc" +source = "git+https://github.com/lance-format/lance.git?rev=dacbf6ecccc7a1a804a8cb150204a41f2ae248ce#dacbf6ecccc7a1a804a8cb150204a41f2ae248ce" dependencies = [ "arrow-array", "arrow-buffer", @@ -5343,7 +5343,7 @@ dependencies = [ [[package]] name = "lance-table" version = "11.0.0-beta.4" -source = "git+https://github.com/lance-format/lance.git?rev=357d678be223f6e785d0ccaf39ac8a5ba1793dcc#357d678be223f6e785d0ccaf39ac8a5ba1793dcc" +source = "git+https://github.com/lance-format/lance.git?rev=dacbf6ecccc7a1a804a8cb150204a41f2ae248ce#dacbf6ecccc7a1a804a8cb150204a41f2ae248ce" dependencies = [ "arrow", "arrow-array", @@ -5384,7 +5384,7 @@ dependencies = [ [[package]] name = "lance-testing" version = "11.0.0-beta.4" -source = "git+https://github.com/lance-format/lance.git?rev=357d678be223f6e785d0ccaf39ac8a5ba1793dcc#357d678be223f6e785d0ccaf39ac8a5ba1793dcc" +source = "git+https://github.com/lance-format/lance.git?rev=dacbf6ecccc7a1a804a8cb150204a41f2ae248ce#dacbf6ecccc7a1a804a8cb150204a41f2ae248ce" dependencies = [ "arrow-array", "arrow-schema", @@ -5398,7 +5398,7 @@ dependencies = [ [[package]] name = "lance-tokenizer" version = "11.0.0-beta.4" -source = "git+https://github.com/lance-format/lance.git?rev=357d678be223f6e785d0ccaf39ac8a5ba1793dcc#357d678be223f6e785d0ccaf39ac8a5ba1793dcc" +source = "git+https://github.com/lance-format/lance.git?rev=dacbf6ecccc7a1a804a8cb150204a41f2ae248ce#dacbf6ecccc7a1a804a8cb150204a41f2ae248ce" dependencies = [ "frostem", "icu_segmenter", diff --git a/Cargo.toml b/Cargo.toml index 5fb97ace2..8ad65d318 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,20 +13,20 @@ categories = ["database-implementations"] rust-version = "1.91.0" [workspace.dependencies] -lance = { version = "=11.0.0-beta.4", default-features = false, rev = "357d678be223f6e785d0ccaf39ac8a5ba1793dcc", git = "https://github.com/lance-format/lance.git" } -lance-core = { version = "=11.0.0-beta.4", rev = "357d678be223f6e785d0ccaf39ac8a5ba1793dcc", git = "https://github.com/lance-format/lance.git" } -lance-datagen = { version = "=11.0.0-beta.4", rev = "357d678be223f6e785d0ccaf39ac8a5ba1793dcc", git = "https://github.com/lance-format/lance.git" } -lance-file = { version = "=11.0.0-beta.4", rev = "357d678be223f6e785d0ccaf39ac8a5ba1793dcc", git = "https://github.com/lance-format/lance.git" } -lance-io = { version = "=11.0.0-beta.4", default-features = false, rev = "357d678be223f6e785d0ccaf39ac8a5ba1793dcc", git = "https://github.com/lance-format/lance.git" } -lance-index = { version = "=11.0.0-beta.4", rev = "357d678be223f6e785d0ccaf39ac8a5ba1793dcc", git = "https://github.com/lance-format/lance.git" } -lance-linalg = { version = "=11.0.0-beta.4", rev = "357d678be223f6e785d0ccaf39ac8a5ba1793dcc", git = "https://github.com/lance-format/lance.git" } -lance-namespace = { version = "=11.0.0-beta.4", rev = "357d678be223f6e785d0ccaf39ac8a5ba1793dcc", git = "https://github.com/lance-format/lance.git" } -lance-namespace-impls = { version = "=11.0.0-beta.4", default-features = false, rev = "357d678be223f6e785d0ccaf39ac8a5ba1793dcc", git = "https://github.com/lance-format/lance.git" } -lance-table = { version = "=11.0.0-beta.4", rev = "357d678be223f6e785d0ccaf39ac8a5ba1793dcc", git = "https://github.com/lance-format/lance.git" } -lance-testing = { version = "=11.0.0-beta.4", rev = "357d678be223f6e785d0ccaf39ac8a5ba1793dcc", git = "https://github.com/lance-format/lance.git" } -lance-datafusion = { version = "=11.0.0-beta.4", rev = "357d678be223f6e785d0ccaf39ac8a5ba1793dcc", git = "https://github.com/lance-format/lance.git" } -lance-encoding = { version = "=11.0.0-beta.4", rev = "357d678be223f6e785d0ccaf39ac8a5ba1793dcc", git = "https://github.com/lance-format/lance.git" } -lance-arrow = { version = "=11.0.0-beta.4", rev = "357d678be223f6e785d0ccaf39ac8a5ba1793dcc", git = "https://github.com/lance-format/lance.git" } +lance = { version = "=11.0.0-beta.4", default-features = false, rev = "dacbf6ecccc7a1a804a8cb150204a41f2ae248ce", git = "https://github.com/lance-format/lance.git" } +lance-core = { version = "=11.0.0-beta.4", rev = "dacbf6ecccc7a1a804a8cb150204a41f2ae248ce", git = "https://github.com/lance-format/lance.git" } +lance-datagen = { version = "=11.0.0-beta.4", rev = "dacbf6ecccc7a1a804a8cb150204a41f2ae248ce", git = "https://github.com/lance-format/lance.git" } +lance-file = { version = "=11.0.0-beta.4", rev = "dacbf6ecccc7a1a804a8cb150204a41f2ae248ce", git = "https://github.com/lance-format/lance.git" } +lance-io = { version = "=11.0.0-beta.4", default-features = false, rev = "dacbf6ecccc7a1a804a8cb150204a41f2ae248ce", git = "https://github.com/lance-format/lance.git" } +lance-index = { version = "=11.0.0-beta.4", rev = "dacbf6ecccc7a1a804a8cb150204a41f2ae248ce", git = "https://github.com/lance-format/lance.git" } +lance-linalg = { version = "=11.0.0-beta.4", rev = "dacbf6ecccc7a1a804a8cb150204a41f2ae248ce", git = "https://github.com/lance-format/lance.git" } +lance-namespace = { version = "=11.0.0-beta.4", rev = "dacbf6ecccc7a1a804a8cb150204a41f2ae248ce", git = "https://github.com/lance-format/lance.git" } +lance-namespace-impls = { version = "=11.0.0-beta.4", default-features = false, rev = "dacbf6ecccc7a1a804a8cb150204a41f2ae248ce", git = "https://github.com/lance-format/lance.git" } +lance-table = { version = "=11.0.0-beta.4", rev = "dacbf6ecccc7a1a804a8cb150204a41f2ae248ce", git = "https://github.com/lance-format/lance.git" } +lance-testing = { version = "=11.0.0-beta.4", rev = "dacbf6ecccc7a1a804a8cb150204a41f2ae248ce", git = "https://github.com/lance-format/lance.git" } +lance-datafusion = { version = "=11.0.0-beta.4", rev = "dacbf6ecccc7a1a804a8cb150204a41f2ae248ce", git = "https://github.com/lance-format/lance.git" } +lance-encoding = { version = "=11.0.0-beta.4", rev = "dacbf6ecccc7a1a804a8cb150204a41f2ae248ce", git = "https://github.com/lance-format/lance.git" } +lance-arrow = { version = "=11.0.0-beta.4", rev = "dacbf6ecccc7a1a804a8cb150204a41f2ae248ce", git = "https://github.com/lance-format/lance.git" } ahash = "0.8" # Note that this one does not include pyarrow arrow = { version = "58.0.0", optional = false } diff --git a/rust/lancedb/src/table/schema_metadata_updates_dependency_contract.rs b/rust/lancedb/src/table/schema_metadata_updates_dependency_contract.rs index 8d25864ef..a763d9ad1 100644 --- a/rust/lancedb/src/table/schema_metadata_updates_dependency_contract.rs +++ b/rust/lancedb/src/table/schema_metadata_updates_dependency_contract.rs @@ -1,33 +1,40 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: Copyright The LanceDB Authors -//! Dependency-contract test for Lance A4 schema metadata attachment (B4p). +//! Dependency-contract test for Lance A4 / A4u schema metadata attachment (B4p). //! //! Pins the exact generic Lance API shape LanceDB B4 will consume: //! [`SchemaMetadataUpdates`], [`UpdateMap`], [`UpdateMapEntry`], //! [`Transaction::with_schema_metadata_updates`], and the public //! `with_schema_metadata_updates` methods on insert/update/delete builders. //! +//! Also pins the A4u Update no-op invariant: an attached field metadata patch +//! must accompany a real data change; when a predicate matches zero rows, +//! `rows_updated == 0` and the patch must not be published. +//! //! Neutral metadata keys only. No Function / UDF / Job semantics. use std::collections::HashMap; +use std::sync::Arc; +use arrow_array::{Int32Array, RecordBatch, RecordBatchIterator, StringArray}; +use arrow_schema::{DataType, Field, Schema as ArrowSchema}; use lance::Result; use lance::dataset::transaction::{ Operation, SchemaMetadataUpdates, Transaction, UpdateMap, UpdateMapEntry, }; -use lance::dataset::{DeleteBuilder, InsertBuilder, UpdateBuilder}; +use lance::dataset::{Dataset, DeleteBuilder, InsertBuilder, UpdateBuilder}; use lance_table::format::Fragment; const FIELD_ID: i32 = 7; const META_KEY: &str = "b4p.dependency.meta"; const META_VALUE: &str = "neutral-value"; -fn field_metadata_patch() -> SchemaMetadataUpdates { +fn field_metadata_patch(field_id: i32) -> SchemaMetadataUpdates { SchemaMetadataUpdates { schema_metadata_updates: None, field_metadata_updates: HashMap::from([( - FIELD_ID, + field_id, UpdateMap { update_entries: vec![UpdateMapEntry { key: META_KEY.to_string(), @@ -68,7 +75,7 @@ fn typecheck_delete_builder_attachment( #[test] fn append_transaction_retains_schema_metadata_updates_patch() { - let updates = field_metadata_patch(); + let updates = field_metadata_patch(FIELD_ID); assert!( !updates.is_empty(), "fixture must be a substantive non-empty field metadata patch" @@ -101,3 +108,106 @@ fn append_transaction_retains_schema_metadata_updates_patch() { Some(META_VALUE) ); } + +/// A4u dependency: a no-op Update (predicate matches zero rows) must not +/// publish an attached field metadata patch. Manifest version advancement is +/// unconstrained. +#[tokio::test] +async fn noop_update_does_not_publish_attached_field_metadata() { + let tmp = tempfile::tempdir().unwrap(); + let uri = tmp.path().join("noop_update.lance"); + let uri = uri.to_str().unwrap(); + + let schema = Arc::new(ArrowSchema::new(vec![ + Field::new("id", DataType::Int32, false), + Field::new("value", DataType::Utf8, false), + ])); + let batch = RecordBatch::try_new( + schema.clone(), + vec![ + Arc::new(Int32Array::from(vec![1, 2, 3])), + Arc::new(StringArray::from(vec!["a", "b", "c"])), + ], + ) + .unwrap(); + let dataset = Dataset::write(RecordBatchIterator::new(vec![Ok(batch)], schema), uri, None) + .await + .expect("fixture dataset must write"); + + let field = dataset + .schema() + .field("value") + .expect("value column must exist"); + let field_id = field.id; + assert!( + !field.metadata.contains_key(META_KEY), + "{META_KEY} must be initially absent, got {:?}", + field.metadata + ); + + let updates = field_metadata_patch(field_id); + assert!( + !updates.is_empty(), + "fixture must be a substantive non-empty field metadata patch" + ); + + let before_count = dataset.count_rows(None).await.unwrap(); + assert_eq!(before_count, 3); + + let result = UpdateBuilder::new(Arc::new(dataset)) + .update_where("id < 0") + .unwrap() + .set("value", "'changed'") + .unwrap() + .with_schema_metadata_updates(updates) + .expect("Update attachment must construct") + .build() + .unwrap() + .execute() + .await + .expect("no-op attached Update must complete"); + + assert_eq!(result.rows_updated, 0, "predicate must match zero rows"); + assert_eq!( + result.new_dataset.count_rows(None).await.unwrap(), + before_count, + "row count must remain unchanged" + ); + assert_eq!( + result + .new_dataset + .count_rows(Some("value = 'changed'".into())) + .await + .unwrap(), + 0, + "SET expression must not rewrite any rows" + ); + assert_eq!( + result + .new_dataset + .count_rows(Some("value IN ('a', 'b', 'c')".into())) + .await + .unwrap(), + before_count, + "original values must remain unchanged" + ); + + let reopened = Dataset::open(uri).await.unwrap(); + assert_eq!(reopened.count_rows(None).await.unwrap(), before_count); + assert_eq!( + reopened + .count_rows(Some("value = 'changed'".into())) + .await + .unwrap(), + 0 + ); + let reopened_field = reopened + .schema() + .field_by_id(field_id) + .expect("stable field id must still exist"); + assert!( + !reopened_field.metadata.contains_key(META_KEY), + "no-op Update must not publish attached field metadata; got {:?}", + reopened_field.metadata.get(META_KEY) + ); +}