commit 314bfb7ba718c3c309058304110c55cbb39965da
parent 93cd88dc6f6daa63e70705ea9da890996aea7b62
Author: triesap <tyson@radroots.org>
Date: Sat, 13 Jun 2026 16:30:32 -0700
build: add chorus pocket startup scaffold
- switch Pocket dependencies to the triesap fork source
- add a Pocket store handle with Tangle group tables
- expose a Chorus/Pocket runtime startup probe
- record fork source pins and targeted validation
Diffstat:
6 files changed, 213 insertions(+), 9 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
@@ -2923,7 +2923,7 @@ checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e"
[[package]]
name = "pocket-db"
version = "0.1.0"
-source = "git+https://github.com/mikedilger/pocket?rev=329334f20948c796c6016b673b92551ac4855ad7#329334f20948c796c6016b673b92551ac4855ad7"
+source = "git+https://github.com/triesap/pocket?rev=329334f20948c796c6016b673b92551ac4855ad7#329334f20948c796c6016b673b92551ac4855ad7"
dependencies = [
"heed",
"libc",
@@ -2934,7 +2934,7 @@ dependencies = [
[[package]]
name = "pocket-types"
version = "0.1.0"
-source = "git+https://github.com/mikedilger/pocket?rev=329334f20948c796c6016b673b92551ac4855ad7#329334f20948c796c6016b673b92551ac4855ad7"
+source = "git+https://github.com/triesap/pocket?rev=329334f20948c796c6016b673b92551ac4855ad7#329334f20948c796c6016b673b92551ac4855ad7"
dependencies = [
"derive_more",
"rand 0.9.4",
@@ -4387,9 +4387,11 @@ dependencies = [
"serde_json",
"sha2",
"tangle_core",
+ "tangle_groups",
"tangle_nips",
"tangle_protocol",
"tangle_store",
+ "tangle_store_pocket",
"tangle_store_surreal",
"tangle_test_support",
"tokio",
diff --git a/crates/tangle_runtime/Cargo.toml b/crates/tangle_runtime/Cargo.toml
@@ -14,9 +14,11 @@ serde = { version = "1", features = ["derive"] }
serde_json = "1"
sha2 = "0.10"
tangle_core = { path = "../tangle_core" }
+tangle_groups = { path = "../tangle_groups" }
tangle_nips = { path = "../tangle_nips" }
tangle_protocol = { path = "../tangle_protocol" }
tangle_store = { path = "../tangle_store" }
+tangle_store_pocket = { path = "../tangle_store_pocket" }
tangle_store_surreal = { path = "../tangle_store_surreal" }
tokio = { version = "1", features = ["net", "sync"] }
tracing = "0.1"
diff --git a/crates/tangle_runtime/src/chorus_pocket.rs b/crates/tangle_runtime/src/chorus_pocket.rs
@@ -0,0 +1,109 @@
+use core::fmt;
+use std::path::{Path, PathBuf};
+use tangle_groups::GroupRuntimeConfig;
+use tangle_store_pocket::{PocketStoreConfig, PocketStoreError, PocketStoreHandle};
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct ChorusPocketRuntimeConfig {
+ pocket: PocketStoreConfig,
+ groups: GroupRuntimeConfig,
+}
+
+impl ChorusPocketRuntimeConfig {
+ pub fn new(pocket: PocketStoreConfig, groups: GroupRuntimeConfig) -> Self {
+ Self { pocket, groups }
+ }
+
+ pub fn pocket(&self) -> &PocketStoreConfig {
+ &self.pocket
+ }
+
+ pub fn groups(&self) -> &GroupRuntimeConfig {
+ &self.groups
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct ChorusPocketStartupReport {
+ store_directory: PathBuf,
+ groups_enabled: bool,
+}
+
+impl ChorusPocketStartupReport {
+ pub fn store_directory(&self) -> &Path {
+ &self.store_directory
+ }
+
+ pub fn groups_enabled(&self) -> bool {
+ self.groups_enabled
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct ChorusPocketRuntimeError {
+ message: String,
+}
+
+impl ChorusPocketRuntimeError {
+ pub fn message(&self) -> &str {
+ &self.message
+ }
+}
+
+impl fmt::Display for ChorusPocketRuntimeError {
+ fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ formatter.write_str(&self.message)
+ }
+}
+
+impl std::error::Error for ChorusPocketRuntimeError {}
+
+impl From<PocketStoreError> for ChorusPocketRuntimeError {
+ fn from(error: PocketStoreError) -> Self {
+ Self {
+ message: error.to_string(),
+ }
+ }
+}
+
+pub fn probe_chorus_pocket_startup(
+ config: &ChorusPocketRuntimeConfig,
+) -> Result<ChorusPocketStartupReport, ChorusPocketRuntimeError> {
+ let store = PocketStoreHandle::open(config.pocket())?;
+ store.sync()?;
+ Ok(ChorusPocketStartupReport {
+ store_directory: store.dir().to_path_buf(),
+ groups_enabled: config.groups().enabled(),
+ })
+}
+
+#[cfg(test)]
+mod tests {
+ use super::{ChorusPocketRuntimeConfig, probe_chorus_pocket_startup};
+ use tangle_groups::parse_group_runtime_config_json;
+ use tangle_store_pocket::{PocketStoreConfig, PocketSyncPolicy};
+
+ #[test]
+ fn chorus_pocket_startup_probe_opens_store_and_reports_group_state() {
+ let root = std::env::temp_dir().join(format!(
+ "tangle-chorus-pocket-runtime-{}",
+ std::process::id()
+ ));
+ let pocket = PocketStoreConfig::new(
+ root.join("pocket"),
+ 1024 * 1024 * 1024,
+ 128,
+ PocketSyncPolicy::FlushOnShutdown,
+ )
+ .expect("pocket");
+ let groups = parse_group_runtime_config_json(r#"{"enabled": false}"#).expect("groups");
+ let config = ChorusPocketRuntimeConfig::new(pocket.clone(), groups);
+
+ let report = probe_chorus_pocket_startup(&config).expect("startup");
+
+ assert_eq!(report.store_directory(), pocket.data_directory());
+ assert!(!report.groups_enabled());
+
+ let _ = std::fs::remove_dir_all(root);
+ }
+}
diff --git a/crates/tangle_runtime/src/lib.rs b/crates/tangle_runtime/src/lib.rs
@@ -1,5 +1,7 @@
#![forbid(unsafe_code)]
+pub mod chorus_pocket;
+
use axum::{
Json, Router,
extract::ws::{Message, WebSocket, WebSocketUpgrade},
diff --git a/crates/tangle_store_pocket/Cargo.toml b/crates/tangle_store_pocket/Cargo.toml
@@ -8,8 +8,8 @@ license.workspace = true
description = "Pocket storage boundary for tangle"
[dependencies]
-pocket-db = { git = "https://github.com/mikedilger/pocket", rev = "329334f20948c796c6016b673b92551ac4855ad7" }
-pocket-types = { git = "https://github.com/mikedilger/pocket", rev = "329334f20948c796c6016b673b92551ac4855ad7" }
+pocket-db = { git = "https://github.com/triesap/pocket", rev = "329334f20948c796c6016b673b92551ac4855ad7" }
+pocket-types = { git = "https://github.com/triesap/pocket", rev = "329334f20948c796c6016b673b92551ac4855ad7" }
[lints]
workspace = true
diff --git a/crates/tangle_store_pocket/src/lib.rs b/crates/tangle_store_pocket/src/lib.rs
@@ -3,9 +3,12 @@
use core::fmt;
use pocket_db::Store;
use pocket_types::{Event, Filter, Id, Pubkey};
-use std::path::{Path, PathBuf};
+use std::{
+ io,
+ path::{Path, PathBuf},
+};
-pub const POCKET_SOURCE_REPOSITORY: &str = "https://github.com/mikedilger/pocket";
+pub const POCKET_SOURCE_REPOSITORY: &str = "https://github.com/triesap/pocket";
pub const POCKET_SOURCE_REVISION: &str = "329334f20948c796c6016b673b92551ac4855ad7";
pub type PocketEvent = Event;
@@ -14,6 +17,9 @@ pub type PocketFilter = Filter;
pub type PocketPubkey = Pubkey;
pub type PocketStore = Store;
+pub const TANGLE_POCKET_EXTRA_TABLES: [&str; 3] =
+ ["group_projection", "group_outbox", "group_checkpoint"];
+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct PocketDependencyBoundary {
source_repository: &'static str,
@@ -37,6 +43,32 @@ impl PocketDependencyBoundary {
}
}
+pub struct PocketStoreHandle {
+ store: PocketStore,
+}
+
+impl PocketStoreHandle {
+ pub fn open(config: &PocketStoreConfig) -> Result<Self, PocketStoreError> {
+ std::fs::create_dir_all(config.data_directory())
+ .map_err(|error| PocketStoreError::from_create_dir(config.data_directory(), error))?;
+ let store = PocketStore::new(config.data_directory(), TANGLE_POCKET_EXTRA_TABLES.to_vec())
+ .map_err(PocketStoreError::from_pocket)?;
+ Ok(Self { store })
+ }
+
+ pub fn dir(&self) -> &Path {
+ self.store.dir()
+ }
+
+ pub fn sync(&self) -> Result<(), PocketStoreError> {
+ self.store.sync().map_err(PocketStoreError::from_pocket)
+ }
+
+ pub fn into_inner(self) -> PocketStore {
+ self.store
+ }
+}
+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PocketSyncPolicy {
FlushOnWrite,
@@ -129,20 +161,54 @@ impl fmt::Display for PocketConfigError {
impl std::error::Error for PocketConfigError {}
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct PocketStoreError {
+ message: String,
+}
+
+impl PocketStoreError {
+ pub fn from_create_dir(path: &Path, error: io::Error) -> Self {
+ Self {
+ message: format!(
+ "failed to create Pocket store directory {}: {error}",
+ path.display()
+ ),
+ }
+ }
+
+ pub fn from_pocket(error: pocket_db::Error) -> Self {
+ Self {
+ message: error.to_string(),
+ }
+ }
+
+ pub fn message(&self) -> &str {
+ &self.message
+ }
+}
+
+impl fmt::Display for PocketStoreError {
+ fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ formatter.write_str(&self.message)
+ }
+}
+
+impl std::error::Error for PocketStoreError {}
+
#[cfg(test)]
mod tests {
use super::{
POCKET_SOURCE_REPOSITORY, POCKET_SOURCE_REVISION, PocketDependencyBoundary,
- PocketStoreConfig, PocketSyncPolicy,
+ PocketStoreConfig, PocketStoreHandle, PocketSyncPolicy, TANGLE_POCKET_EXTRA_TABLES,
};
#[test]
- fn pocket_dependency_boundary_pins_chorus_latest_manifest_revision() {
+ fn pocket_dependency_boundary_pins_triesap_revision() {
let boundary = PocketDependencyBoundary::current();
assert_eq!(
boundary.source_repository(),
- "https://github.com/mikedilger/pocket"
+ "https://github.com/triesap/pocket"
);
assert_eq!(boundary.source_repository(), POCKET_SOURCE_REPOSITORY);
assert_eq!(
@@ -153,6 +219,29 @@ mod tests {
}
#[test]
+ fn pocket_store_handle_opens_syncs_and_exposes_tangle_tables() {
+ let root = std::env::temp_dir().join(format!("tangle-pocket-store-{}", std::process::id()));
+ let config = PocketStoreConfig::new(
+ root.join("pocket"),
+ 1024 * 1024 * 1024,
+ 128,
+ PocketSyncPolicy::FlushOnShutdown,
+ )
+ .expect("config");
+
+ let handle = PocketStoreHandle::open(&config).expect("open");
+
+ assert_eq!(handle.dir(), config.data_directory());
+ assert_eq!(
+ TANGLE_POCKET_EXTRA_TABLES,
+ ["group_projection", "group_outbox", "group_checkpoint"]
+ );
+ handle.sync().expect("sync");
+
+ let _ = std::fs::remove_dir_all(root);
+ }
+
+ #[test]
fn pocket_store_config_preserves_explicit_storage_boundary() {
let config = PocketStoreConfig::new(
"runtime/radroots/tangle/pocket",