Resolves the 142 findings from tidal/docs/reviews/CODE_REVIEW_m0-m10.md across the engine, server, net, and CLI surfaces: - WAL/session-journal durability, checkpoint format, and crash-recovery hardening - Replication shipper/receiver, tenant isolation, and migration paths - Cluster scatter-gather, router, standalone server + health/offload endpoints - tidalctl refactored into command modules with JSON output and WAL-state tooling - Cohort, governance, signal-ledger, and vector-registry correctness fixes - Expanded UAT/integration/durability test coverage across all milestones
206 lines
6.2 KiB
Rust
206 lines
6.2 KiB
Rust
//! M10p1 integration test — Community Governance Policy Engine.
|
|
//!
|
|
//! Validates versioned community policies governing signal eligibility and
|
|
//! per-contribution weighting: excluded intents are rejected, admitted weights
|
|
//! are clamped, versions are monotonic with effective timestamps, the governing
|
|
//! version is queryable, and policies survive close/reopen.
|
|
//!
|
|
//! ROADMAP §Milestone 10 Phase 1.
|
|
|
|
#![allow(clippy::too_many_lines, clippy::unwrap_used)]
|
|
|
|
use std::{collections::BTreeSet, time::Duration};
|
|
|
|
use tidaldb::{
|
|
CommunityId, GovernancePolicy, ShareIntent, SharePolicy, TidalDb, UserId, WeightingBounds,
|
|
schema::{DecaySpec, EntityId, EntityKind, SchemaBuilder, Timestamp, Window},
|
|
};
|
|
|
|
fn schema() -> tidaldb::schema::Schema {
|
|
let mut b = SchemaBuilder::new();
|
|
for name in ["like", "low_quality", "skip_for_now"] {
|
|
let _ = b
|
|
.signal(
|
|
name,
|
|
EntityKind::Item,
|
|
DecaySpec::Exponential {
|
|
half_life: Duration::from_secs(7 * 24 * 3600),
|
|
},
|
|
)
|
|
.windows(&[Window::AllTime])
|
|
.velocity(false)
|
|
.add();
|
|
}
|
|
b.build().unwrap()
|
|
}
|
|
|
|
fn full_share() -> SharePolicy {
|
|
SharePolicy::community_share(
|
|
1,
|
|
[
|
|
ShareIntent::Like,
|
|
ShareIntent::LowQuality,
|
|
ShareIntent::SkipForNow,
|
|
],
|
|
)
|
|
}
|
|
|
|
fn policy(community: CommunityId, version: u32, effective_at_ns: u64) -> GovernancePolicy {
|
|
GovernancePolicy {
|
|
community_id: community,
|
|
version,
|
|
effective_at_ns,
|
|
allowed_intents: BTreeSet::new(),
|
|
excluded_intents: BTreeSet::from(["skip_for_now".to_string()]),
|
|
weighting: WeightingBounds { min: 0.0, max: 2.0 },
|
|
trust_threshold: 0.0,
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn excluded_intent_is_rejected_by_policy() {
|
|
let db = TidalDb::builder()
|
|
.ephemeral()
|
|
.with_schema(schema())
|
|
.open()
|
|
.unwrap();
|
|
let (c, item, user) = (CommunityId(1), EntityId::new(5), UserId(1));
|
|
db.join_community(user, c, full_share()).unwrap();
|
|
db.define_community_policy(policy(c, 1, 0)).unwrap();
|
|
let now = Timestamp::now();
|
|
|
|
// `skip_for_now` is excluded by governance -> rejected (not recorded).
|
|
assert!(
|
|
!db.signal_for_community("skip_for_now", item, 1.0, now, user, c)
|
|
.unwrap()
|
|
);
|
|
// `like` is admitted.
|
|
assert!(
|
|
db.signal_for_community("like", item, 1.0, now, user, c)
|
|
.unwrap()
|
|
);
|
|
assert_eq!(
|
|
db.read_community_windowed_count(c, item, "like", Window::AllTime)
|
|
.unwrap(),
|
|
1
|
|
);
|
|
assert_eq!(
|
|
db.read_community_windowed_count(c, item, "skip_for_now", Window::AllTime)
|
|
.unwrap(),
|
|
0
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn weight_is_clamped_by_policy() {
|
|
let db = TidalDb::builder()
|
|
.ephemeral()
|
|
.with_schema(schema())
|
|
.open()
|
|
.unwrap();
|
|
let item = EntityId::new(5);
|
|
let now = Timestamp::now();
|
|
|
|
// Governed community: max weight 2.0.
|
|
let governed = CommunityId(1);
|
|
db.join_community(UserId(1), governed, full_share())
|
|
.unwrap();
|
|
db.define_community_policy(policy(governed, 1, 0)).unwrap();
|
|
assert!(
|
|
db.signal_for_community("like", item, 100.0, now, UserId(1), governed)
|
|
.unwrap()
|
|
);
|
|
|
|
// Ungoverned community: weight passes through.
|
|
let free = CommunityId(2);
|
|
db.join_community(UserId(1), free, full_share()).unwrap();
|
|
assert!(
|
|
db.signal_for_community("like", item, 100.0, now, UserId(1), free)
|
|
.unwrap()
|
|
);
|
|
|
|
let governed_score = db
|
|
.read_community_decay_score(governed, item, "like", 0)
|
|
.unwrap()
|
|
.unwrap();
|
|
let free_score = db
|
|
.read_community_decay_score(free, item, "like", 0)
|
|
.unwrap()
|
|
.unwrap();
|
|
assert!(
|
|
governed_score <= 2.0 + 1e-6,
|
|
"governed weight must be clamped to 2.0, got {governed_score}"
|
|
);
|
|
assert!(
|
|
free_score > 2.0,
|
|
"ungoverned weight must pass through, got {free_score}"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn policy_versions_are_monotonic_and_queryable() {
|
|
let db = TidalDb::builder()
|
|
.ephemeral()
|
|
.with_schema(schema())
|
|
.open()
|
|
.unwrap();
|
|
let c = CommunityId(1);
|
|
db.define_community_policy(policy(c, 1, 0)).unwrap();
|
|
assert_eq!(db.governing_policy_version(c), Some(1));
|
|
|
|
// v2 supersedes once registered (effective at 0 here).
|
|
db.define_community_policy(policy(c, 2, 0)).unwrap();
|
|
assert_eq!(db.governing_policy_version(c), Some(2));
|
|
|
|
// Re-registering a non-increasing version fails.
|
|
assert!(db.define_community_policy(policy(c, 2, 0)).is_err());
|
|
assert!(db.define_community_policy(policy(c, 1, 0)).is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn no_policy_means_no_governance() {
|
|
let db = TidalDb::builder()
|
|
.ephemeral()
|
|
.with_schema(schema())
|
|
.open()
|
|
.unwrap();
|
|
let (c, item, user) = (CommunityId(9), EntityId::new(1), UserId(1));
|
|
db.join_community(user, c, full_share()).unwrap();
|
|
let now = Timestamp::now();
|
|
// Without a governance policy, even `skip_for_now` flows (share policy allows it).
|
|
assert!(
|
|
db.signal_for_community("skip_for_now", item, 1.0, now, user, c)
|
|
.unwrap()
|
|
);
|
|
assert_eq!(db.governing_policy_version(c), None);
|
|
}
|
|
|
|
#[test]
|
|
fn policy_survives_reopen() {
|
|
let home = tidaldb::TempTidalHome::new().unwrap();
|
|
let c = CommunityId(1);
|
|
{
|
|
let db = TidalDb::builder()
|
|
.with_data_dir(home.path())
|
|
.with_schema(schema())
|
|
.open()
|
|
.unwrap();
|
|
db.define_community_policy(policy(c, 1, 0)).unwrap();
|
|
db.define_community_policy(policy(c, 2, 0)).unwrap();
|
|
db.shutdown().unwrap();
|
|
}
|
|
let db = TidalDb::builder()
|
|
.with_data_dir(home.path())
|
|
.with_schema(schema())
|
|
.open()
|
|
.unwrap();
|
|
assert_eq!(
|
|
db.governing_policy_version(c),
|
|
Some(2),
|
|
"governance policy must survive reopen"
|
|
);
|
|
// Monotonic check still holds against restored history.
|
|
assert!(db.define_community_policy(policy(c, 2, 0)).is_err());
|
|
assert!(db.define_community_policy(policy(c, 3, 0)).is_ok());
|
|
}
|