commit 6afd777a93293baaa9ab715cfd3686d1ae15a10f
parent 22aafe19bd86c4eefca2cda2ecc0490668114034
Author: triesap <tyson@radroots.org>
Date: Sat, 19 Sep 2026 19:14:05 +0000
media: enforce visibility before remote retrieval
- Bind media access to the full current query and authoritative visibility
- Recheck visibility after network and file waits before publishing bytes
- Verify wrong scope, retraction, arbitrary URLs and invalid response bytes
- Regenerate exact native artifacts and retain full verification evidence
Diffstat:
11 files changed, 733 insertions(+), 283 deletions(-)
diff --git a/TeraFFI/provenance.json b/TeraFFI/provenance.json
@@ -22,9 +22,9 @@
"sha256": "3ed9b7ece2f86e5b5d1ddc6ecbb97deb49c46ca2ea91a930eaec1b580232345c"
},
{
- "bytes": 76260296,
+ "bytes": 76270880,
"path": "TeraFFI.xcframework/ios-arm64-simulator/libtera_ffi.a",
- "sha256": "559e3ba169e0f7d242428b08043cdfa091acb84c00d7a72c642294e97cfe5ebe"
+ "sha256": "8b1ec252937d363c716d0ebe21c14632cc0c244e3c51d04513e07587540428f4"
},
{
"bytes": 80633,
@@ -37,9 +37,9 @@
"sha256": "3ed9b7ece2f86e5b5d1ddc6ecbb97deb49c46ca2ea91a930eaec1b580232345c"
},
{
- "bytes": 76343192,
+ "bytes": 76351800,
"path": "TeraFFI.xcframework/ios-arm64/libtera_ffi.a",
- "sha256": "c3cd8151391cd2fbf9f9180e9a6c141b11a5b68ad689ddadb072166767c45fc8"
+ "sha256": "c4d544e8eb415a9393dcdbca7078ec7a261577c3ffa38e3df500945d683465bb"
},
{
"bytes": 49312,
@@ -77,34 +77,34 @@
"sha256": "3ed9b7ece2f86e5b5d1ddc6ecbb97deb49c46ca2ea91a930eaec1b580232345c"
},
{
- "bytes": 21861696,
+ "bytes": 21877840,
"path": "native/aarch64-apple-darwin/libtera_ffi.dylib",
- "sha256": "1235e1aa48b5244bd156baccffa54da81fea517fbac766fc9da01d93e114049d"
+ "sha256": "b1264839af1d58a242f305b0d721367ae0768cc90196f4b59d814237de28b3b9"
},
{
- "bytes": 76260296,
+ "bytes": 76270880,
"path": "native/aarch64-apple-ios-sim/libtera_ffi.a",
- "sha256": "559e3ba169e0f7d242428b08043cdfa091acb84c00d7a72c642294e97cfe5ebe"
+ "sha256": "8b1ec252937d363c716d0ebe21c14632cc0c244e3c51d04513e07587540428f4"
},
{
- "bytes": 76343192,
+ "bytes": 76351800,
"path": "native/aarch64-apple-ios/libtera_ffi.a",
- "sha256": "c3cd8151391cd2fbf9f9180e9a6c141b11a5b68ad689ddadb072166767c45fc8"
+ "sha256": "c4d544e8eb415a9393dcdbca7078ec7a261577c3ffa38e3df500945d683465bb"
},
{
- "bytes": 100688,
+ "bytes": 101576,
"path": "source/aarch64-apple-darwin.json",
- "sha256": "f97e05d5b587358e94a938b7c74591970a11392cd5a8c87c4d7d12b934629058"
+ "sha256": "7724f92bcd6c6c339e9b603b1e2104317f677ffe8bc756548dc5d03c1282b371"
},
{
- "bytes": 100532,
+ "bytes": 101420,
"path": "source/aarch64-apple-ios-sim.json",
- "sha256": "6811dca32ae3685b2f7e0121cc2f8e0dfa2401a6826d6ad40b510dd754353677"
+ "sha256": "d5f50af53363e1d4d6a5b015516b08ba65d0da95c893dfae30dc48b41a5e7ed1"
},
{
- "bytes": 100528,
+ "bytes": 101416,
"path": "source/aarch64-apple-ios.json",
- "sha256": "698ed0982a5d5347d757d7f3dce2ac1f12ea16ad03b92d43f6867e7696b8c73a"
+ "sha256": "794044e08f464ef25fb388c1f5611513e9fa0fd64d793f83f60adb6af12462f8"
}
],
"language": "swift",
@@ -112,7 +112,7 @@
"schema": "radroots.artifact-manifest.v2",
"source": {
"repository": "https://github.com/radrootslabs/tera",
- "tree": "f1bd4bd0656de8a67a9602889c0655fb3bdadc56"
+ "tree": "e8bc8e378ae5db8ad84891b9262670a1aaf4e395"
},
"source_records": {
"aarch64-apple-darwin": "source/aarch64-apple-darwin.json",
@@ -139,9 +139,9 @@
"sha256": "3ed9b7ece2f86e5b5d1ddc6ecbb97deb49c46ca2ea91a930eaec1b580232345c"
},
{
- "bytes": 76260296,
+ "bytes": 76270880,
"path": "Tera/Frameworks/TeraFFI.xcframework/ios-arm64-simulator/libtera_ffi.a",
- "sha256": "559e3ba169e0f7d242428b08043cdfa091acb84c00d7a72c642294e97cfe5ebe"
+ "sha256": "8b1ec252937d363c716d0ebe21c14632cc0c244e3c51d04513e07587540428f4"
},
{
"bytes": 80633,
@@ -154,9 +154,9 @@
"sha256": "3ed9b7ece2f86e5b5d1ddc6ecbb97deb49c46ca2ea91a930eaec1b580232345c"
},
{
- "bytes": 76343192,
+ "bytes": 76351800,
"path": "Tera/Frameworks/TeraFFI.xcframework/ios-arm64/libtera_ffi.a",
- "sha256": "c3cd8151391cd2fbf9f9180e9a6c141b11a5b68ad689ddadb072166767c45fc8"
+ "sha256": "c4d544e8eb415a9393dcdbca7078ec7a261577c3ffa38e3df500945d683465bb"
},
{
"bytes": 643709,
@@ -174,19 +174,19 @@
"sha256": "7b3f92a57ebcc7873349403243098d5dcf993b2dbdab9ed84fea4a50c20baab0"
},
{
- "bytes": 100688,
+ "bytes": 101576,
"path": "TeraFFI/source/aarch64-apple-darwin.json",
- "sha256": "f97e05d5b587358e94a938b7c74591970a11392cd5a8c87c4d7d12b934629058"
+ "sha256": "7724f92bcd6c6c339e9b603b1e2104317f677ffe8bc756548dc5d03c1282b371"
},
{
- "bytes": 100532,
+ "bytes": 101420,
"path": "TeraFFI/source/aarch64-apple-ios-sim.json",
- "sha256": "6811dca32ae3685b2f7e0121cc2f8e0dfa2401a6826d6ad40b510dd754353677"
+ "sha256": "d5f50af53363e1d4d6a5b015516b08ba65d0da95c893dfae30dc48b41a5e7ed1"
},
{
- "bytes": 100528,
+ "bytes": 101416,
"path": "TeraFFI/source/aarch64-apple-ios.json",
- "sha256": "698ed0982a5d5347d757d7f3dce2ac1f12ea16ad03b92d43f6867e7696b8c73a"
+ "sha256": "794044e08f464ef25fb388c1f5611513e9fa0fd64d793f83f60adb6af12462f8"
}
],
"schema": "tera.installed-native-artifacts.v1"
diff --git a/TeraFFI/source.lock b/TeraFFI/source.lock
@@ -1,7 +1,7 @@
schema = "tera.installed-source.v1"
repository = "https://github.com/radrootslabs/tera"
-source_tree = "f1bd4bd0656de8a67a9602889c0655fb3bdadc56"
-manifest_sha256 = "6e9f9645c78446371d5fdfc90007ca89d09ab102cc17f417d03d7eaff08a9810"
+source_tree = "e8bc8e378ae5db8ad84891b9262670a1aaf4e395"
+manifest_sha256 = "386966b5d6d0f9a1639d26520636d725fe1f035d74f776132c9fb4190e8d6eb7"
source_date_epoch = 1787871027
[foundation]
diff --git a/TeraFFI/source/aarch64-apple-darwin.json b/TeraFFI/source/aarch64-apple-darwin.json
@@ -1173,10 +1173,10 @@
"sha256": "ec18505ac5efb7bfa1b6c351178aa7f6b15d8272d87dc567711acdd65ca372b7"
},
"core/crates/tera_core/src/runtime/product_surface/today.rs": {
- "bytes": 141339,
- "git_blob": "5dfa0eb946df781b7f75fc12fc95b69ee999f255",
+ "bytes": 133627,
+ "git_blob": "ad2bc57a5823079b49036f80a17a480fd070f318",
"mode": "100644",
- "sha256": "a9bd67c9787018560a2a99200e0bcb87714fb4fd62f7423bf146e37659eb7e44"
+ "sha256": "2eddec5f72e483f09498f8252abf3f558b064e2f80b8ed0aa4594a516a18fe56"
},
"core/crates/tera_core/src/runtime/product_surface/today_admission_tests.rs": {
"bytes": 13548,
@@ -1220,6 +1220,24 @@
"mode": "100644",
"sha256": "d5da0dc2e13a5a72731c3efc1b4fd02459acc542a94c5a38380dfa1b9e9520da"
},
+ "core/crates/tera_core/src/runtime/product_surface/today_media_retrieval.rs": {
+ "bytes": 8538,
+ "git_blob": "df5a02041a03f2ccfc9b34ec4e46b77d6f1366a3",
+ "mode": "100644",
+ "sha256": "fe2f479a3130c23bfebfa9db38febe79a67383fb7a1dda899c195b43cc83472e"
+ },
+ "core/crates/tera_core/src/runtime/product_surface/today_media_visibility.rs": {
+ "bytes": 1125,
+ "git_blob": "70eb543db2055dd67df53c47dee5b6841b787876",
+ "mode": "100644",
+ "sha256": "8007c774ae9b9505a0aa632bf51d16606a3846ebf94d74cc3e0b22bb9702f04b"
+ },
+ "core/crates/tera_core/src/runtime/product_surface/today_media_visibility_tests.rs": {
+ "bytes": 10250,
+ "git_blob": "ff72b95943c453da26fbfac65ac772bb97045d2e",
+ "mode": "100644",
+ "sha256": "7aa4ed5c05dddde1921c2ad601807daecbfb6ba38b4a50ef14ab4994244e1f74"
+ },
"core/crates/tera_core/src/runtime/product_surface/today_paging.rs": {
"bytes": 6207,
"git_blob": "0b06f6369cc475cd96625307cdb85a040b7ae923",
@@ -2145,13 +2163,13 @@
"sha256": "b052a73a824e8f8b26af2646a4758f13655e04de9551a8271890d3cf2b63209d"
},
"test-fixtures/legacy-identifiers.v1.json": {
- "bytes": 141516,
- "git_blob": "46db8eded2880dd4ba156dd1fbcd655ed0666e0d",
+ "bytes": 141951,
+ "git_blob": "9f8976ef731b206d2b7699640d400cfa08f8e9e9",
"mode": "100644",
- "sha256": "a665ec09cd62714e9227b3849d813b08b07efdc047cd4ea7b714c2b53fbb70ee"
+ "sha256": "80bdf7c1efc05d83260c08201b8d05ecf2d8780ae477239ec05fddc1bb5024a4"
}
},
"policy": "staged_inputs",
- "tree": "f1bd4bd0656de8a67a9602889c0655fb3bdadc56"
+ "tree": "e8bc8e378ae5db8ad84891b9262670a1aaf4e395"
}
}
diff --git a/TeraFFI/source/aarch64-apple-ios-sim.json b/TeraFFI/source/aarch64-apple-ios-sim.json
@@ -1169,10 +1169,10 @@
"sha256": "ec18505ac5efb7bfa1b6c351178aa7f6b15d8272d87dc567711acdd65ca372b7"
},
"core/crates/tera_core/src/runtime/product_surface/today.rs": {
- "bytes": 141339,
- "git_blob": "5dfa0eb946df781b7f75fc12fc95b69ee999f255",
+ "bytes": 133627,
+ "git_blob": "ad2bc57a5823079b49036f80a17a480fd070f318",
"mode": "100644",
- "sha256": "a9bd67c9787018560a2a99200e0bcb87714fb4fd62f7423bf146e37659eb7e44"
+ "sha256": "2eddec5f72e483f09498f8252abf3f558b064e2f80b8ed0aa4594a516a18fe56"
},
"core/crates/tera_core/src/runtime/product_surface/today_admission_tests.rs": {
"bytes": 13548,
@@ -1216,6 +1216,24 @@
"mode": "100644",
"sha256": "d5da0dc2e13a5a72731c3efc1b4fd02459acc542a94c5a38380dfa1b9e9520da"
},
+ "core/crates/tera_core/src/runtime/product_surface/today_media_retrieval.rs": {
+ "bytes": 8538,
+ "git_blob": "df5a02041a03f2ccfc9b34ec4e46b77d6f1366a3",
+ "mode": "100644",
+ "sha256": "fe2f479a3130c23bfebfa9db38febe79a67383fb7a1dda899c195b43cc83472e"
+ },
+ "core/crates/tera_core/src/runtime/product_surface/today_media_visibility.rs": {
+ "bytes": 1125,
+ "git_blob": "70eb543db2055dd67df53c47dee5b6841b787876",
+ "mode": "100644",
+ "sha256": "8007c774ae9b9505a0aa632bf51d16606a3846ebf94d74cc3e0b22bb9702f04b"
+ },
+ "core/crates/tera_core/src/runtime/product_surface/today_media_visibility_tests.rs": {
+ "bytes": 10250,
+ "git_blob": "ff72b95943c453da26fbfac65ac772bb97045d2e",
+ "mode": "100644",
+ "sha256": "7aa4ed5c05dddde1921c2ad601807daecbfb6ba38b4a50ef14ab4994244e1f74"
+ },
"core/crates/tera_core/src/runtime/product_surface/today_paging.rs": {
"bytes": 6207,
"git_blob": "0b06f6369cc475cd96625307cdb85a040b7ae923",
@@ -2141,13 +2159,13 @@
"sha256": "b052a73a824e8f8b26af2646a4758f13655e04de9551a8271890d3cf2b63209d"
},
"test-fixtures/legacy-identifiers.v1.json": {
- "bytes": 141516,
- "git_blob": "46db8eded2880dd4ba156dd1fbcd655ed0666e0d",
+ "bytes": 141951,
+ "git_blob": "9f8976ef731b206d2b7699640d400cfa08f8e9e9",
"mode": "100644",
- "sha256": "a665ec09cd62714e9227b3849d813b08b07efdc047cd4ea7b714c2b53fbb70ee"
+ "sha256": "80bdf7c1efc05d83260c08201b8d05ecf2d8780ae477239ec05fddc1bb5024a4"
}
},
"policy": "staged_inputs",
- "tree": "f1bd4bd0656de8a67a9602889c0655fb3bdadc56"
+ "tree": "e8bc8e378ae5db8ad84891b9262670a1aaf4e395"
}
}
diff --git a/TeraFFI/source/aarch64-apple-ios.json b/TeraFFI/source/aarch64-apple-ios.json
@@ -1169,10 +1169,10 @@
"sha256": "ec18505ac5efb7bfa1b6c351178aa7f6b15d8272d87dc567711acdd65ca372b7"
},
"core/crates/tera_core/src/runtime/product_surface/today.rs": {
- "bytes": 141339,
- "git_blob": "5dfa0eb946df781b7f75fc12fc95b69ee999f255",
+ "bytes": 133627,
+ "git_blob": "ad2bc57a5823079b49036f80a17a480fd070f318",
"mode": "100644",
- "sha256": "a9bd67c9787018560a2a99200e0bcb87714fb4fd62f7423bf146e37659eb7e44"
+ "sha256": "2eddec5f72e483f09498f8252abf3f558b064e2f80b8ed0aa4594a516a18fe56"
},
"core/crates/tera_core/src/runtime/product_surface/today_admission_tests.rs": {
"bytes": 13548,
@@ -1216,6 +1216,24 @@
"mode": "100644",
"sha256": "d5da0dc2e13a5a72731c3efc1b4fd02459acc542a94c5a38380dfa1b9e9520da"
},
+ "core/crates/tera_core/src/runtime/product_surface/today_media_retrieval.rs": {
+ "bytes": 8538,
+ "git_blob": "df5a02041a03f2ccfc9b34ec4e46b77d6f1366a3",
+ "mode": "100644",
+ "sha256": "fe2f479a3130c23bfebfa9db38febe79a67383fb7a1dda899c195b43cc83472e"
+ },
+ "core/crates/tera_core/src/runtime/product_surface/today_media_visibility.rs": {
+ "bytes": 1125,
+ "git_blob": "70eb543db2055dd67df53c47dee5b6841b787876",
+ "mode": "100644",
+ "sha256": "8007c774ae9b9505a0aa632bf51d16606a3846ebf94d74cc3e0b22bb9702f04b"
+ },
+ "core/crates/tera_core/src/runtime/product_surface/today_media_visibility_tests.rs": {
+ "bytes": 10250,
+ "git_blob": "ff72b95943c453da26fbfac65ac772bb97045d2e",
+ "mode": "100644",
+ "sha256": "7aa4ed5c05dddde1921c2ad601807daecbfb6ba38b4a50ef14ab4994244e1f74"
+ },
"core/crates/tera_core/src/runtime/product_surface/today_paging.rs": {
"bytes": 6207,
"git_blob": "0b06f6369cc475cd96625307cdb85a040b7ae923",
@@ -2141,13 +2159,13 @@
"sha256": "b052a73a824e8f8b26af2646a4758f13655e04de9551a8271890d3cf2b63209d"
},
"test-fixtures/legacy-identifiers.v1.json": {
- "bytes": 141516,
- "git_blob": "46db8eded2880dd4ba156dd1fbcd655ed0666e0d",
+ "bytes": 141951,
+ "git_blob": "9f8976ef731b206d2b7699640d400cfa08f8e9e9",
"mode": "100644",
- "sha256": "a665ec09cd62714e9227b3849d813b08b07efdc047cd4ea7b714c2b53fbb70ee"
+ "sha256": "80bdf7c1efc05d83260c08201b8d05ecf2d8780ae477239ec05fddc1bb5024a4"
}
},
"policy": "staged_inputs",
- "tree": "f1bd4bd0656de8a67a9602889c0655fb3bdadc56"
+ "tree": "e8bc8e378ae5db8ad84891b9262670a1aaf4e395"
}
}
diff --git a/core/crates/tera_core/src/runtime/product_surface/today.rs b/core/crates/tera_core/src/runtime/product_surface/today.rs
@@ -90,6 +90,13 @@ pub use reconciliation::TodayReconciliation;
#[path = "today_submission_overlay.rs"]
mod submission_overlay;
+#[cfg(feature = "mobile-social")]
+#[path = "today_media_retrieval.rs"]
+mod media_retrieval;
+
+#[path = "today_media_visibility.rs"]
+mod media_visibility;
+
#[cfg(test)]
#[path = "today_reconciliation_tests.rs"]
mod reconciliation_tests;
@@ -555,14 +562,13 @@ impl TeraRuntime {
pending: Phase1InboundMediaPending,
) -> Result<bool, TodayError> {
let _command = self.lifecycle.enter()?;
+ let _projection = self.today_projection_lock.lock().await;
let storage = self
.client
.storage()
.map_err(|_| TodayError::RuntimeUnavailable)?;
let generation = projection_generation()?;
- let mut state = load_state(storage, context, generation)
- .await?
- .ok_or(TodayError::ProjectionMissing)?;
+ let mut state = media_visibility::current_state(self, context).await?;
let mut trial = state.clone();
let prior_configuration = trial.media_cache.status()?.configuration;
if prior_configuration.is_some_and(|value| value != pending.configuration()) {
@@ -589,14 +595,13 @@ impl TeraRuntime {
failure: Phase1InboundMediaFailure,
) -> Result<bool, TodayError> {
let _command = self.lifecycle.enter()?;
+ let _projection = self.today_projection_lock.lock().await;
let storage = self
.client
.storage()
.map_err(|_| TodayError::RuntimeUnavailable)?;
let generation = projection_generation()?;
- let mut state = load_state(storage, context, generation)
- .await?
- .ok_or(TodayError::ProjectionMissing)?;
+ let mut state = media_visibility::current_state(self, context).await?;
let changed = mutate_matching_media(&mut state, reference_fingerprint, |media| {
media.fail(failure.clone())
})?;
@@ -618,14 +623,13 @@ impl TeraRuntime {
policy: Phase1MediaCachePolicy,
cached_at_unix_ms: u64,
) -> Result<Vec<Phase1MediaArtifactId>, TodayError> {
+ let _projection = self.today_projection_lock.lock().await;
let storage = self
.client
.storage()
.map_err(|_| TodayError::RuntimeUnavailable)?;
let generation = projection_generation()?;
- let mut state = load_state(storage, context, generation)
- .await?
- .ok_or(TodayError::ProjectionMissing)?;
+ let mut state = media_visibility::current_state(self, context).await?;
let mut trial = state.clone();
let changed = mutate_matching_media(&mut trial, reference_fingerprint, |media| {
media.verify(operation_id, receipt.clone())
@@ -652,6 +656,7 @@ impl TeraRuntime {
observed_at_unix_ms: u64,
) -> Result<bool, TodayError> {
let _command = self.lifecycle.enter()?;
+ let _projection = self.today_projection_lock.lock().await;
let storage = self
.client
.storage()
@@ -676,6 +681,7 @@ impl TeraRuntime {
let _command = self.lifecycle.enter()?;
#[cfg(feature = "mobile-social")]
let _guard = self.inbound_media_lock.lock().await;
+ let _projection = self.today_projection_lock.lock().await;
let storage = self
.client
.storage()
@@ -706,6 +712,7 @@ impl TeraRuntime {
let _command = self.lifecycle.enter()?;
#[cfg(feature = "mobile-social")]
let _guard = self.inbound_media_lock.lock().await;
+ let _projection = self.today_projection_lock.lock().await;
let storage = self
.client
.storage()
@@ -746,200 +753,6 @@ impl TeraRuntime {
state.media_cache.status().map_err(TodayError::from)
}
- /// Resolves one renderable artifact only after rechecking the exact local
- /// file. Missing or corrupt bytes atomically revoke all matching receipts.
- #[cfg(feature = "mobile-social")]
- pub async fn phase1_verified_media_artifact(
- &self,
- context: &LocalNetwork,
- artifact_id: Phase1MediaArtifactId,
- observed_at_unix_ms: u64,
- ) -> Result<Option<Phase1LocalMediaArtifact>, TodayError> {
- let _command = self.lifecycle.enter()?;
- let _guard = self.inbound_media_lock.lock().await;
- let directory = self
- .inbound_media_directory
- .as_deref()
- .ok_or(Phase1InboundMediaError::CacheUnavailable)?;
- let storage = self
- .client
- .storage()
- .map_err(|_| TodayError::RuntimeUnavailable)?;
- let generation = projection_generation()?;
- let mut state = load_state(storage, context, generation)
- .await?
- .ok_or(TodayError::ProjectionMissing)?;
- let Some(receipt) = verified_receipt(&state, artifact_id) else {
- return Ok(None);
- };
- match super::media::verified_artifact(directory, &receipt).await {
- Ok(artifact) => {
- if state.media_cache.touch(artifact_id, observed_at_unix_ms)? {
- persist_media_state(storage, context, generation, &mut state).await?;
- }
- Ok(Some(artifact))
- }
- Err(error) => {
- state.media_cache.invalidate_artifact(artifact_id);
- invalidate_artifact_references(&mut state, artifact_id);
- persist_media_state(storage, context, generation, &mut state).await?;
- let _ = super::media::remove_artifact_files(directory, artifact_id).await;
- Err(error.into())
- }
- }
- }
-
- /// Completes one bounded BUD-01 retrieval, exact-byte verification, and
- /// atomic content-addressed cache commit under the configured Blossom slot.
- #[cfg(feature = "mobile-social")]
- pub async fn phase1_retrieve_media(
- &self,
- context: &LocalNetwork,
- reference_fingerprint: [u8; 32],
- operation_id: [u8; 16],
- policy: Phase1MediaCachePolicy,
- cancellation: BlossomCancellation,
- ) -> Result<Phase1LocalMediaArtifact, TodayError> {
- let _command = self.lifecycle.enter()?;
- let _guard = self.inbound_media_lock.lock().await;
- let directory = self
- .inbound_media_directory
- .as_deref()
- .ok_or(Phase1InboundMediaError::CacheUnavailable)?;
- let blossom = self
- .client
- .blossom()
- .map_err(|_| TodayError::RuntimeUnavailable)?
- .cloned()
- .ok_or(TodayError::RuntimeUnavailable)?;
- let sdk_configuration = blossom
- .config_fingerprint()
- .ok_or(TodayError::RuntimeUnavailable)?;
- let configuration =
- Phase1MediaConfigurationFingerprint::new(*sdk_configuration.as_bytes())?;
- let structural = load_structural_reference(self, context, reference_fingerprint).await?;
- let started_at_unix_ms = inbound_now_unix_ms()?;
- self.phase1_begin_media_retrieval(
- context,
- reference_fingerprint,
- Phase1InboundMediaPending::new(operation_id, configuration, started_at_unix_ms)?,
- )
- .await?;
- let request = match inbound_request(&structural) {
- Ok(request) => request,
- Err(error) => {
- record_inbound_failure(
- self,
- context,
- reference_fingerprint,
- operation_id,
- "invalid_reference",
- false,
- )
- .await;
- return Err(error);
- }
- };
- let sdk_receipt = match blossom.retrieve(request, cancellation).await {
- Ok(receipt) => receipt,
- Err(error) => {
- record_inbound_failure(
- self,
- context,
- reference_fingerprint,
- operation_id,
- error.code().trim_start_matches("blossom_"),
- error.retryable(),
- )
- .await;
- return Err(error.into());
- }
- };
- if sdk_receipt.config_fingerprint() != sdk_configuration {
- record_inbound_failure(
- self,
- context,
- reference_fingerprint,
- operation_id,
- "configuration_changed",
- false,
- )
- .await;
- return Err(Phase1InboundMediaError::ConfigurationMismatch.into());
- }
- let dimensions = sdk_receipt.dimensions();
- let receipt = match Phase1VerifiedMediaReceipt::from_commitment(
- &structural,
- sdk_receipt.final_url().clone(),
- sdk_receipt.commitment(),
- dimensions.width(),
- dimensions.height(),
- configuration,
- sdk_receipt.verified_at_unix_ms(),
- ) {
- Ok(receipt) => receipt,
- Err(error) => {
- record_inbound_failure(
- self,
- context,
- reference_fingerprint,
- operation_id,
- "verification_failed",
- false,
- )
- .await;
- return Err(error.into());
- }
- };
- let artifact =
- match super::media::write_verified_artifact(directory, &receipt, sdk_receipt.bytes())
- .await
- {
- Ok(artifact) => artifact,
- Err(error) => {
- record_inbound_failure(
- self,
- context,
- reference_fingerprint,
- operation_id,
- "cache_write_failed",
- true,
- )
- .await;
- return Err(error.into());
- }
- };
- let evicted = match self
- .phase1_commit_media_receipt(
- context,
- reference_fingerprint,
- operation_id,
- receipt,
- policy,
- sdk_receipt.verified_at_unix_ms(),
- )
- .await
- {
- Ok(evicted) => evicted,
- Err(error) => {
- record_inbound_failure(
- self,
- context,
- reference_fingerprint,
- operation_id,
- "cache_commit_failed",
- true,
- )
- .await;
- return Err(error);
- }
- };
- for artifact_id in evicted {
- super::media::remove_artifact_files(directory, artifact_id).await?;
- }
- Ok(artifact)
- }
-
/// Persists active-author delivery state as a local-only Today overlay.
pub async fn phase1_set_local_author_overlay(
&self,
@@ -989,34 +802,6 @@ impl TeraRuntime {
}
#[cfg(feature = "mobile-social")]
-async fn load_structural_reference(
- runtime: &TeraRuntime,
- context: &LocalNetwork,
- reference_fingerprint: [u8; 32],
-) -> Result<Phase1StructuralMediaReference, TodayError> {
- let storage = runtime
- .client
- .storage()
- .map_err(|_| TodayError::RuntimeUnavailable)?;
- let state = load_state(storage, context, projection_generation()?)
- .await?
- .ok_or(TodayError::ProjectionMissing)?;
- state
- .cards
- .iter()
- .flat_map(|projected| projected.card.media.iter())
- .chain(
- state
- .profiles
- .values()
- .flat_map(|profile| [&profile.picture, &profile.banner].into_iter().flatten()),
- )
- .find(|media| media.structural().fingerprint() == &reference_fingerprint)
- .map(|media| media.structural().clone())
- .ok_or(TodayError::InvalidRequest)
-}
-
-#[cfg(feature = "mobile-social")]
fn inbound_request(
structural: &Phase1StructuralMediaReference,
) -> Result<BlossomInboundRequest, TodayError> {
diff --git a/core/crates/tera_core/src/runtime/product_surface/today_media_retrieval.rs b/core/crates/tera_core/src/runtime/product_surface/today_media_retrieval.rs
@@ -0,0 +1,232 @@
+use super::*;
+
+impl TeraRuntime {
+ /// Resolves one renderable artifact only after rechecking the exact local
+ /// file. Missing or corrupt bytes atomically revoke all matching receipts.
+ #[cfg(feature = "mobile-social")]
+ pub async fn phase1_verified_media_artifact(
+ &self,
+ context: &LocalNetwork,
+ artifact_id: Phase1MediaArtifactId,
+ observed_at_unix_ms: u64,
+ ) -> Result<Option<Phase1LocalMediaArtifact>, TodayError> {
+ let _command = self.lifecycle.enter()?;
+ let _guard = self.inbound_media_lock.lock().await;
+ let directory = self
+ .inbound_media_directory
+ .as_deref()
+ .ok_or(Phase1InboundMediaError::CacheUnavailable)?;
+ let storage = self
+ .client
+ .storage()
+ .map_err(|_| TodayError::RuntimeUnavailable)?;
+ let _projection = self.today_projection_lock.lock().await;
+ let generation = projection_generation()?;
+ let mut state = media_visibility::current_state(self, context).await?;
+ let Some(receipt) = verified_receipt(&state, artifact_id) else {
+ return Ok(None);
+ };
+ match super::super::media::verified_artifact(directory, &receipt).await {
+ Ok(artifact) => {
+ state = media_visibility::current_state(self, context).await?;
+ if state.media_cache.touch(artifact_id, observed_at_unix_ms)? {
+ persist_media_state(storage, context, generation, &mut state).await?;
+ }
+ Ok(Some(artifact))
+ }
+ Err(error) => {
+ state = media_visibility::current_state(self, context).await?;
+ state.media_cache.invalidate_artifact(artifact_id);
+ invalidate_artifact_references(&mut state, artifact_id);
+ persist_media_state(storage, context, generation, &mut state).await?;
+ let _ = super::super::media::remove_artifact_files(directory, artifact_id).await;
+ Err(error.into())
+ }
+ }
+ }
+
+ /// Completes one bounded BUD-01 retrieval, exact-byte verification, and
+ /// atomic content-addressed cache commit under the configured Blossom slot.
+ #[cfg(feature = "mobile-social")]
+ pub async fn phase1_retrieve_media(
+ &self,
+ context: &LocalNetwork,
+ reference_fingerprint: [u8; 32],
+ operation_id: [u8; 16],
+ policy: Phase1MediaCachePolicy,
+ cancellation: BlossomCancellation,
+ ) -> Result<Phase1LocalMediaArtifact, TodayError> {
+ let _command = self.lifecycle.enter()?;
+ let directory = self
+ .inbound_media_directory
+ .as_deref()
+ .ok_or(Phase1InboundMediaError::CacheUnavailable)?;
+ let blossom = self
+ .client
+ .blossom()
+ .map_err(|_| TodayError::RuntimeUnavailable)?
+ .cloned()
+ .ok_or(TodayError::RuntimeUnavailable)?;
+ let sdk_configuration = blossom
+ .config_fingerprint()
+ .ok_or(TodayError::RuntimeUnavailable)?;
+ let configuration =
+ Phase1MediaConfigurationFingerprint::new(*sdk_configuration.as_bytes())?;
+ let structural = load_structural_reference(self, context, reference_fingerprint).await?;
+ let started_at_unix_ms = inbound_now_unix_ms()?;
+ if !self
+ .phase1_begin_media_retrieval(
+ context,
+ reference_fingerprint,
+ Phase1InboundMediaPending::new(operation_id, configuration, started_at_unix_ms)?,
+ )
+ .await?
+ {
+ return Err(TodayError::InvalidRequest);
+ }
+ let request = match inbound_request(&structural) {
+ Ok(request) => request,
+ Err(error) => {
+ record_inbound_failure(
+ self,
+ context,
+ reference_fingerprint,
+ operation_id,
+ "invalid_reference",
+ false,
+ )
+ .await;
+ return Err(error);
+ }
+ };
+ let sdk_receipt = match blossom.retrieve(request, cancellation).await {
+ Ok(receipt) => receipt,
+ Err(error) => {
+ record_inbound_failure(
+ self,
+ context,
+ reference_fingerprint,
+ operation_id,
+ error.code().trim_start_matches("blossom_"),
+ error.retryable(),
+ )
+ .await;
+ return Err(error.into());
+ }
+ };
+ if sdk_receipt.config_fingerprint() != sdk_configuration {
+ record_inbound_failure(
+ self,
+ context,
+ reference_fingerprint,
+ operation_id,
+ "configuration_changed",
+ false,
+ )
+ .await;
+ return Err(Phase1InboundMediaError::ConfigurationMismatch.into());
+ }
+ let dimensions = sdk_receipt.dimensions();
+ let receipt = match Phase1VerifiedMediaReceipt::from_commitment(
+ &structural,
+ sdk_receipt.final_url().clone(),
+ sdk_receipt.commitment(),
+ dimensions.width(),
+ dimensions.height(),
+ configuration,
+ sdk_receipt.verified_at_unix_ms(),
+ ) {
+ Ok(receipt) => receipt,
+ Err(error) => {
+ record_inbound_failure(
+ self,
+ context,
+ reference_fingerprint,
+ operation_id,
+ "verification_failed",
+ false,
+ )
+ .await;
+ return Err(error.into());
+ }
+ };
+ // Serialize only the local file/receipt phase, never the network wait.
+ let _guard = self.inbound_media_lock.lock().await;
+ // A completed network request does not retain obsolete visibility.
+ if load_structural_reference(self, context, reference_fingerprint).await? != structural {
+ return Err(TodayError::InvalidRequest);
+ }
+ let artifact = match super::super::media::write_verified_artifact(
+ directory,
+ &receipt,
+ sdk_receipt.bytes(),
+ )
+ .await
+ {
+ Ok(artifact) => artifact,
+ Err(error) => {
+ record_inbound_failure(
+ self,
+ context,
+ reference_fingerprint,
+ operation_id,
+ "cache_write_failed",
+ true,
+ )
+ .await;
+ return Err(error.into());
+ }
+ };
+ let evicted = match self
+ .phase1_commit_media_receipt(
+ context,
+ reference_fingerprint,
+ operation_id,
+ receipt,
+ policy,
+ sdk_receipt.verified_at_unix_ms(),
+ )
+ .await
+ {
+ Ok(evicted) => evicted,
+ Err(error) => {
+ record_inbound_failure(
+ self,
+ context,
+ reference_fingerprint,
+ operation_id,
+ "cache_commit_failed",
+ true,
+ )
+ .await;
+ return Err(error);
+ }
+ };
+ for artifact_id in evicted {
+ super::super::media::remove_artifact_files(directory, artifact_id).await?;
+ }
+ Ok(artifact)
+ }
+}
+
+#[cfg(feature = "mobile-social")]
+async fn load_structural_reference(
+ runtime: &TeraRuntime,
+ context: &LocalNetwork,
+ reference_fingerprint: [u8; 32],
+) -> Result<Phase1StructuralMediaReference, TodayError> {
+ let state = media_visibility::current_state(runtime, context).await?;
+ state
+ .cards
+ .iter()
+ .flat_map(|projected| projected.card.media.iter())
+ .chain(
+ state
+ .profiles
+ .values()
+ .flat_map(|profile| [&profile.picture, &profile.banner].into_iter().flatten()),
+ )
+ .find(|media| media.structural().fingerprint() == &reference_fingerprint)
+ .map(|media| media.structural().clone())
+ .ok_or(TodayError::InvalidRequest)
+}
diff --git a/core/crates/tera_core/src/runtime/product_surface/today_media_visibility.rs b/core/crates/tera_core/src/runtime/product_surface/today_media_visibility.rs
@@ -0,0 +1,30 @@
+use super::*;
+
+#[cfg(all(test, feature = "mobile-social"))]
+#[path = "today_media_visibility_tests.rs"]
+mod tests;
+
+/// A cached reference is not authority after the selected query or visible
+/// event set changes. The owner re-evaluates replacement/deletion semantics;
+/// raw row counts and the store's identity generation cannot establish this.
+pub(super) async fn current_state(
+ runtime: &TeraRuntime,
+ context: &LocalNetwork,
+) -> Result<TodayProjectionState, TodayError> {
+ let scope = paging_scope::query_scope(context, runtime.store_public_key)?;
+ let storage = runtime
+ .client
+ .storage()
+ .map_err(|_| TodayError::RuntimeUnavailable)?;
+ let state = load_state(storage, context, projection_generation()?)
+ .await?
+ .ok_or(TodayError::ProjectionMissing)?;
+ if state.query_scope != Some(scope) {
+ return Err(TodayError::InvalidRequest);
+ }
+ let visibility = EventStore::rebuild_visibility(storage).await?;
+ if state.visibility_digest != Some(*visibility.digest().as_bytes()) {
+ return Err(TodayError::InvalidRequest);
+ }
+ Ok(state)
+}
diff --git a/core/crates/tera_core/src/runtime/product_surface/today_media_visibility_tests.rs b/core/crates/tera_core/src/runtime/product_surface/today_media_visibility_tests.rs
@@ -0,0 +1,337 @@
+use super::super::tests::{context, ingest, keys, signed, visible_admission};
+use super::*;
+use crate::runtime::{
+ builder::RuntimeBuilder,
+ store::{MobileUserStoreConfig, ProtectedDataAvailability},
+};
+use radroots_blossom::Sha256 as BlobHash;
+use radroots_sdk::transport::{
+ BlossomConfig, BlossomEndpointAuthority, BlossomHostKind, BlossomProfile,
+};
+use radroots_transport::source::ObservedEvent;
+use std::{sync::Arc, time::Duration};
+use tokio::{
+ io::{AsyncReadExt, AsyncWriteExt},
+ net::TcpListener,
+ sync::oneshot,
+};
+
+const NOW: u64 = 2_000_000_000;
+
+struct Fixture {
+ _root: tempfile::TempDir,
+ runtime: Arc<TeraRuntime>,
+ selected: LocalNetwork,
+ fingerprint: [u8; 32],
+ source: String,
+ bytes: Vec<u8>,
+ listener: TcpListener,
+}
+
+async fn fixture() -> Fixture {
+ let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
+ let origin = format!("http://{}", listener.local_addr().unwrap());
+ let mut bytes = b"\x89PNG\r\n\x1a\n\0\0\0\rIHDR".to_vec();
+ bytes.extend_from_slice(&2_u32.to_be_bytes());
+ bytes.extend_from_slice(&3_u32.to_be_bytes());
+ let url = format!("{origin}/{}.png", BlobHash::digest(&bytes).to_hex());
+ let root = tempfile::tempdir().unwrap();
+ let public_key = keys().public_key().to_string();
+ let store = MobileUserStoreConfig::from_encoded(
+ root.path(),
+ &public_key,
+ &"86".repeat(32),
+ NOW * 1_000,
+ ProtectedDataAvailability::Available,
+ )
+ .unwrap();
+ std::fs::create_dir_all(store.owner_directory()).unwrap();
+ let blossom = BlossomConfig::from_profile(
+ BlossomProfile::new(
+ BlossomHostKind::Simulator,
+ BlossomEndpointAuthority::LoopbackDevelopment,
+ &origin,
+ std::iter::empty::<&str>(),
+ )
+ .unwrap(),
+ )
+ .with_network_policy(
+ Duration::from_millis(250),
+ Duration::from_secs(3),
+ 1,
+ Duration::from_millis(1),
+ )
+ .unwrap();
+ let runtime = Arc::new(
+ RuntimeBuilder::new(store)
+ .blossom_config(blossom)
+ .build()
+ .await
+ .unwrap(),
+ );
+ let selected = context(None, 1);
+ let profile = signed(
+ 0,
+ vec![],
+ &format!(r#"{{"name":"Media fixture","picture":"{url}"}}"#),
+ NOW,
+ );
+ let source = profile.id().to_hex();
+ ingest(&runtime, &selected, profile, NOW + 1).await;
+ let picture = runtime
+ .phase1_me(&selected, &public_key, NOW + 2, "UTC")
+ .await
+ .unwrap()
+ .profile
+ .unwrap()
+ .picture
+ .unwrap();
+ Fixture {
+ _root: root,
+ runtime,
+ selected,
+ fingerprint: *picture.structural().fingerprint(),
+ source,
+ bytes,
+ listener,
+ }
+}
+
+async fn retrieve(
+ runtime: &TeraRuntime,
+ selected: &LocalNetwork,
+ fingerprint: [u8; 32],
+) -> Result<Phase1LocalMediaArtifact, TodayError> {
+ runtime
+ .phase1_retrieve_media(
+ selected,
+ fingerprint,
+ [86; 16],
+ Phase1MediaCachePolicy::new(1_024, 8).unwrap(),
+ BlossomCancellation::default(),
+ )
+ .await
+}
+
+async fn serve(
+ listener: TcpListener,
+ bytes: Vec<u8>,
+ started: oneshot::Sender<()>,
+ resume: oneshot::Receiver<()>,
+) {
+ let (mut stream, _) = listener.accept().await.unwrap();
+ let mut request = Vec::new();
+ while !request.windows(4).any(|part| part == b"\r\n\r\n") {
+ let mut chunk = [0; 1_024];
+ let count = stream.read(&mut chunk).await.unwrap();
+ assert_ne!(count, 0);
+ request.extend_from_slice(&chunk[..count]);
+ assert!(request.len() <= 16_384);
+ }
+ let request = String::from_utf8(request).unwrap();
+ assert!(request.starts_with("GET /"));
+ assert!(!request.to_lowercase().contains("authorization:"));
+ started.send(()).unwrap();
+ resume.await.unwrap();
+ let header = format!(
+ "HTTP/1.1 200 OK\r\nContent-Type: image/png\r\nContent-Length: {}\r\nConnection: close\r\n\r\n",
+ bytes.len()
+ );
+ stream.write_all(header.as_bytes()).await.unwrap();
+ stream.write_all(&bytes).await.unwrap();
+ stream.shutdown().await.unwrap();
+}
+
+#[tokio::test]
+async fn wrong_query_scope_and_unadmitted_reference_cannot_start_transport() {
+ let f = fixture().await;
+ let wrong = context(Some("another locality"), 1);
+ for (selected, fingerprint) in [(&wrong, f.fingerprint), (&f.selected, [1; 32])] {
+ assert!(matches!(
+ retrieve(&f.runtime, selected, fingerprint).await,
+ Err(TodayError::InvalidRequest)
+ ));
+ }
+ assert!(
+ tokio::time::timeout(Duration::from_millis(30), f.listener.accept())
+ .await
+ .is_err()
+ );
+ let (started, entered) = oneshot::channel();
+ let (resume, wait) = oneshot::channel();
+ let server = tokio::spawn(serve(f.listener, f.bytes.clone(), started, wait));
+ resume.send(()).unwrap();
+ let artifact = retrieve(&f.runtime, &f.selected, f.fingerprint)
+ .await
+ .unwrap();
+ entered.await.unwrap();
+ server.await.unwrap();
+ assert_eq!(artifact.bytes(), f.bytes);
+ assert!(matches!(
+ f.runtime
+ .phase1_verified_media_artifact(&wrong, artifact.artifact_id(), (NOW + 3) * 1_000)
+ .await,
+ Err(TodayError::InvalidRequest)
+ ));
+ let deletion = signed(5, vec![vec!["e", &f.source]], "", NOW + 4);
+ EventStore::admit(
+ f.runtime.client.storage().unwrap(),
+ visible_admission(deletion, (NOW + 4) * 1_000),
+ )
+ .await
+ .unwrap();
+ assert!(matches!(
+ f.runtime
+ .phase1_verified_media_artifact(&f.selected, artifact.artifact_id(), (NOW + 5) * 1_000)
+ .await,
+ Err(TodayError::InvalidRequest)
+ ));
+ assert!(
+ artifact.local_path().exists(),
+ "visibility revocation does not authorize shared blob deletion"
+ );
+ f.runtime.shutdown().await.unwrap();
+}
+
+#[tokio::test]
+async fn same_raw_count_visibility_change_revokes_cached_retrieval_authority() {
+ let f = fixture().await;
+ let deletion = signed(5, vec![vec!["e", &f.source]], "", NOW + 4);
+ let admission = visible_admission(deletion, (NOW + 4) * 1_000);
+ let storage = f.runtime.client.storage().unwrap();
+ EventStore::admit(
+ storage,
+ EventAdmission::raw(ObservedEvent::new(
+ admission.event().clone(),
+ admission.provenance().clone(),
+ )),
+ )
+ .await
+ .unwrap();
+ f.runtime
+ .phase1_refresh_today(&f.selected, NOW + 5, TodayProjectionUpdate::Incremental)
+ .await
+ .unwrap();
+ let before = EventStore::status(storage).await.unwrap().raw_events();
+ EventStore::admit(storage, admission).await.unwrap();
+ assert_eq!(
+ EventStore::status(storage).await.unwrap().raw_events(),
+ before
+ );
+ assert!(matches!(
+ retrieve(&f.runtime, &f.selected, f.fingerprint).await,
+ Err(TodayError::InvalidRequest)
+ ));
+ assert!(
+ tokio::time::timeout(Duration::from_millis(30), f.listener.accept())
+ .await
+ .is_err()
+ );
+ f.runtime.shutdown().await.unwrap();
+}
+
+#[tokio::test]
+async fn retraction_during_network_wait_cannot_publish_verified_bytes() {
+ let f = fixture().await;
+ let (started, entered) = oneshot::channel();
+ let (resume, wait) = oneshot::channel();
+ let server = tokio::spawn(serve(f.listener, f.bytes, started, wait));
+ let runtime = f.runtime.clone();
+ let selected = f.selected.clone();
+ let fingerprint = f.fingerprint;
+ let pending = tokio::spawn(async move { retrieve(&runtime, &selected, fingerprint).await });
+ tokio::time::timeout(Duration::from_secs(2), entered)
+ .await
+ .unwrap()
+ .unwrap();
+ let deletion = signed(5, vec![vec!["e", &f.source]], "", NOW + 4);
+ ingest(&f.runtime, &f.selected, deletion, NOW + 5).await;
+ resume.send(()).unwrap();
+ assert!(matches!(
+ pending.await.unwrap(),
+ Err(TodayError::InvalidRequest)
+ ));
+ server.await.unwrap();
+ assert_eq!(
+ f.runtime
+ .phase1_media_cache_status(&f.selected)
+ .await
+ .unwrap()
+ .artifacts,
+ 0
+ );
+ f.runtime.shutdown().await.unwrap();
+}
+
+#[tokio::test]
+async fn arbitrary_embedded_url_cannot_bypass_the_verified_transport() {
+ let f = fixture().await;
+ let url = format!("http://{}/arbitrary", f.listener.local_addr().unwrap());
+ ingest(
+ &f.runtime,
+ &f.selected,
+ signed(0, vec![], &format!(r#"{{"picture":"{url}"}}"#), NOW + 10),
+ NOW + 11,
+ )
+ .await;
+ let picture = f
+ .runtime
+ .phase1_me(
+ &f.selected,
+ &keys().public_key().to_string(),
+ NOW + 12,
+ "UTC",
+ )
+ .await
+ .unwrap()
+ .profile
+ .unwrap()
+ .picture
+ .unwrap();
+ assert!(
+ retrieve(&f.runtime, &f.selected, *picture.structural().fingerprint())
+ .await
+ .is_err()
+ );
+ assert!(
+ tokio::time::timeout(Duration::from_millis(30), f.listener.accept())
+ .await
+ .is_err()
+ );
+ assert_eq!(
+ f.runtime
+ .phase1_media_cache_status(&f.selected)
+ .await
+ .unwrap()
+ .artifacts,
+ 0
+ );
+ f.runtime.shutdown().await.unwrap();
+}
+
+#[tokio::test]
+async fn visible_reference_does_not_turn_wrong_response_bytes_into_an_artifact() {
+ let f = fixture().await;
+ let mut wrong = f.bytes;
+ wrong[23] ^= 1;
+ let (started, entered) = oneshot::channel();
+ let (resume, wait) = oneshot::channel();
+ let server = tokio::spawn(serve(f.listener, wrong, started, wait));
+ resume.send(()).unwrap();
+ assert!(
+ retrieve(&f.runtime, &f.selected, f.fingerprint)
+ .await
+ .is_err()
+ );
+ entered.await.unwrap();
+ server.await.unwrap();
+ assert_eq!(
+ f.runtime
+ .phase1_media_cache_status(&f.selected)
+ .await
+ .unwrap()
+ .artifacts,
+ 0
+ );
+ f.runtime.shutdown().await.unwrap();
+}
diff --git a/release/provenance.json b/release/provenance.json
@@ -2,7 +2,7 @@
"artifacts": {
"app_api_sha256": "020924097c0d7efc33128cb8fd3d3b2026d95f57c44da71880e585aff80f070b",
"ffi_api_sha256": "7b3f92a57ebcc7873349403243098d5dcf993b2dbdab9ed84fea4a50c20baab0",
- "ffi_provenance_sha256": "6e9f9645c78446371d5fdfc90007ca89d09ab102cc17f417d03d7eaff08a9810",
+ "ffi_provenance_sha256": "386966b5d6d0f9a1639d26520636d725fe1f035d74f776132c9fb4190e8d6eb7",
"info_plist_sha256": "15ef08b1cdd1096cfb9eeaf5be5bf8f814807a7ca9350bbbb47860fa72ec13ef",
"privacy_manifest_sha256": "a331d51864743ebe4e00dd22360b4a538b6b3ac26a6b3eb54094e60a36959a12",
"sbom_sha256": "b202075f3c34a3a70e8745ca6d6acab6c2cf5e2d6de9a2b2647475d73a8d3f28",
@@ -22,7 +22,7 @@
"lib_revision": "963dd8dc99fc5f16ef7d7eea11f8d964770a696e",
"source_date_epoch": 1787871027,
"swift_package_lock_sha256": "d5c9240384b50f006ee6e9eff886a3775546280e90a05cbe781eaa296632da26",
- "tera_ffi_source_tree": "f1bd4bd0656de8a67a9602889c0655fb3bdadc56",
+ "tera_ffi_source_tree": "e8bc8e378ae5db8ad84891b9262670a1aaf4e395",
"xcode_package_lock_sha256": "b6806f710734f8e628d7a7d7b97826d89eea78fba32fa9b464f513bcadd411e2"
},
"version": "0.1.0-alpha"
diff --git a/test-fixtures/legacy-identifiers.v1.json b/test-fixtures/legacy-identifiers.v1.json
@@ -4261,6 +4261,10 @@
"count": 2
},
{
+ "path": "core/crates/tera_core/src/runtime/product_surface/today_media_visibility_tests.rs",
+ "count": 1
+ },
+ {
"path": "core/crates/tera_ffi/Cargo.toml",
"count": 1
},
@@ -4895,6 +4899,10 @@
"count": 1
},
{
+ "path": "core/crates/tera_core/src/runtime/product_surface/today_media_visibility_tests.rs",
+ "count": 1
+ },
+ {
"path": "core/crates/tera_core/src/runtime/product_surface/today_performance_tests.rs",
"count": 1
},
@@ -5323,6 +5331,10 @@
"count": 2
},
{
+ "path": "core/crates/tera_core/src/runtime/product_surface/today_media_visibility_tests.rs",
+ "count": 1
+ },
+ {
"path": "core/crates/tera_core/src/runtime/product_surface/today_sync.rs",
"count": 1
},