use serde_json::{json, Value};
use tandem_core::{any_policy_matches, tool_schema_risk_tier};
use tandem_enterprise_contract::authority::{AuthorityAccessRequest, IntraTenantAuthorityGraph};
use tandem_memory::types::OWNER_ORG_UNIT_METADATA_KEY;
use tandem_types::{
AccessEffect, AccessPermission, DataClass, OrganizationUnit, OrganizationUnitAccessGrant,
OrganizationUnitKind, OrganizationUnitMembership, OrganizationUnitMembershipSource,
PrincipalRef, ResourceKind, ResourceRef, TenantContext, ToolRiskTier, ToolSchema,
ToolSecurityDescriptor,
};
#[cfg(test)]
mod tests;
pub mod harness;
pub use harness::{acme_slack_demo_receipt_for_profile, run_acme_slack_demo_harness};
pub const DEMO_ORG_ID: &str = "acme";
pub const DEMO_WORKSPACE_ID: &str = "hq";
pub const DEMO_TAXONOMY_ID: &str = "department";
pub const DEMO_BASE_NOW_MS: u64 = 1_700_000_000_000;
pub const DEMO_PROMPT: &str = "@tandem what changed with customer ACME this week?";
#[derive(Debug, Clone)]
pub struct DemoProfile {
pub slack_user_id: &'static str,
pub actor_id: String,
pub unit_id: &'static str,
pub display_name: &'static str,
pub kind: OrganizationUnitKind,
pub principal: PrincipalRef,
pub unit_principal: PrincipalRef,
}
impl DemoProfile {
pub fn owner_org_unit_id(&self) -> String {
format!("{DEMO_TAXONOMY_ID}/{}", self.unit_id)
}
pub fn org_units(&self) -> Vec<String> {
vec![self.owner_org_unit_id()]
}
}
pub const DEMO_UNSTAFFED_UNIT: &str = "security";
#[derive(Debug, Clone)]
pub struct DemoMemoryRow {
pub id: &'static str,
pub owner_org_unit_id: String,
pub data_class: DataClass,
pub resource: ResourceRef,
pub subject: String,
pub summary: &'static str,
}
impl DemoMemoryRow {
pub fn domain(&self) -> &str {
&self.resource.resource_id
}
pub fn put_metadata(&self) -> Value {
json!({
OWNER_ORG_UNIT_METADATA_KEY: self.owner_org_unit_id,
"classification": self.data_class,
"demo_row_id": self.id,
})
}
}
#[derive(Debug, Clone)]
pub struct DemoTool {
pub schema: ToolSchema,
pub expected_risk_tier: ToolRiskTier,
}
impl DemoTool {
pub fn approval_required(&self) -> bool {
self.expected_risk_tier.approval_required_by_default()
}
}
#[derive(Debug, Clone)]
pub struct AcmeDemoDataset {
pub tenant_context: TenantContext,
pub graph: IntraTenantAuthorityGraph,
pub profiles: Vec<DemoProfile>,
pub memory_rows: Vec<DemoMemoryRow>,
pub tools: Vec<DemoTool>,
}
impl AcmeDemoDataset {
pub fn profile_for_slack_user(&self, slack_user_id: &str) -> Option<&DemoProfile> {
self.profiles
.iter()
.find(|profile| profile.slack_user_id == slack_user_id)
}
}
pub fn slack_user_to_unit_id(slack_user_id: &str) -> Option<&'static str> {
match slack_user_id {
"U_SALES" => Some("sales"),
"U_ENG" => Some("engineering"),
"U_FINANCE" => Some("finance"),
"U_LEADER" => Some("leadership"),
"U_CONTRACTOR" => Some("contractor_acme_x"),
_ => None,
}
}
fn demo_tenant() -> TenantContext {
TenantContext::explicit(DEMO_ORG_ID, DEMO_WORKSPACE_ID, None)
}
fn profile(
slack_user_id: &'static str,
unit_id: &'static str,
display_name: &'static str,
kind: OrganizationUnitKind,
) -> DemoProfile {
let actor_id = format!("channel:slack:{slack_user_id}");
DemoProfile {
slack_user_id,
actor_id: actor_id.clone(),
unit_id,
display_name,
kind,
principal: PrincipalRef::human_user(actor_id),
unit_principal: PrincipalRef::organization_unit(format!("{DEMO_TAXONOMY_ID}/{unit_id}")),
}
}
fn unit(profile: &DemoProfile) -> OrganizationUnit {
OrganizationUnit::active(
profile.unit_id,
demo_tenant(),
profile.display_name,
profile.kind,
PrincipalRef::human_user("user-admin"),
DEMO_BASE_NOW_MS,
)
.with_taxonomy_id(DEMO_TAXONOMY_ID)
}
fn membership(profile: &DemoProfile) -> OrganizationUnitMembership {
OrganizationUnitMembership::active(
format!("m-{}", profile.unit_id),
demo_tenant(),
profile.unit_principal.clone(),
profile.principal.clone(),
OrganizationUnitMembershipSource::Direct,
DEMO_BASE_NOW_MS,
)
}
fn resource(kind: ResourceKind, domain: &str) -> ResourceRef {
ResourceRef::new(DEMO_ORG_ID, DEMO_WORKSPACE_ID, kind, domain)
}
fn org_wide_resource() -> ResourceRef {
ResourceRef::new(DEMO_ORG_ID, "*", ResourceKind::Organization, DEMO_ORG_ID)
}
fn allow_grant(
grant_id: &str,
unit: &PrincipalRef,
resource: ResourceRef,
data_classes: Vec<DataClass>,
) -> OrganizationUnitAccessGrant {
OrganizationUnitAccessGrant::active(
grant_id,
demo_tenant(),
unit.clone(),
resource,
DEMO_BASE_NOW_MS,
)
.with_permissions(vec![AccessPermission::View, AccessPermission::Read])
.with_data_classes(data_classes)
}
fn deny_grant(
grant_id: &str,
unit: &PrincipalRef,
resource: ResourceRef,
data_classes: Vec<DataClass>,
) -> OrganizationUnitAccessGrant {
OrganizationUnitAccessGrant::active(
grant_id,
demo_tenant(),
unit.clone(),
resource,
DEMO_BASE_NOW_MS,
)
.with_effect(AccessEffect::Deny)
.with_permissions(vec![AccessPermission::View, AccessPermission::Read])
.with_data_classes(data_classes)
}
fn tool_grant(
grant_id: &str,
unit: &PrincipalRef,
tool_patterns: Vec<String>,
) -> OrganizationUnitAccessGrant {
OrganizationUnitAccessGrant::active(
grant_id,
demo_tenant(),
unit.clone(),
org_wide_resource(),
DEMO_BASE_NOW_MS,
)
.with_permissions(vec![AccessPermission::Execute])
.with_tool_patterns(tool_patterns)
}
fn memory_row(
id: &'static str,
owner: &DemoProfile,
domain_kind: ResourceKind,
domain: &'static str,
data_class: DataClass,
summary: &'static str,
) -> DemoMemoryRow {
DemoMemoryRow {
id,
owner_org_unit_id: owner.owner_org_unit_id(),
data_class,
resource: resource(domain_kind, domain),
subject: owner.actor_id.clone(),
summary,
}
}
fn patterns(items: &[&str]) -> Vec<String> {
items.iter().map(|item| item.to_string()).collect()
}
fn read_tool(name: &str, data_classes: Vec<DataClass>, expected: ToolRiskTier) -> DemoTool {
let schema = ToolSchema {
name: name.to_string(),
description: format!("ACME demo tool {name} (read)"),
input_schema: json!({"type": "object"}),
capabilities: Default::default(),
security: ToolSecurityDescriptor {
required_permissions: vec![AccessPermission::Read],
data_classes,
..Default::default()
},
};
DemoTool {
schema,
expected_risk_tier: expected,
}
}
fn tagged_tool(name: &str, data_classes: Vec<DataClass>, risk_tier: ToolRiskTier) -> DemoTool {
let schema = ToolSchema {
name: name.to_string(),
description: format!("ACME demo tool {name}"),
input_schema: json!({"type": "object"}),
capabilities: Default::default(),
security: ToolSecurityDescriptor {
required_permissions: vec![AccessPermission::Read],
data_classes,
risk_tier: Some(risk_tier),
..Default::default()
},
};
DemoTool {
schema,
expected_risk_tier: risk_tier,
}
}
fn send_tool(name: &str) -> DemoTool {
let schema = ToolSchema {
name: name.to_string(),
description: format!("ACME demo tool {name} (external send)"),
input_schema: json!({"type": "object"}),
capabilities: Default::default(),
security: ToolSecurityDescriptor {
external_side_effect: true,
..Default::default()
},
};
DemoTool {
schema,
expected_risk_tier: ToolRiskTier::ExternalSend,
}
}
pub fn acme_demo_dataset() -> AcmeDemoDataset {
let tenant = demo_tenant();
let sales = profile(
"U_SALES",
"sales",
"Sales",
OrganizationUnitKind::Department,
);
let engineering = profile(
"U_ENG",
"engineering",
"Engineering",
OrganizationUnitKind::Department,
);
let finance = profile(
"U_FINANCE",
"finance",
"Finance",
OrganizationUnitKind::Department,
);
let leadership = profile(
"U_LEADER",
"leadership",
"Leadership",
OrganizationUnitKind::ExecutiveGroup,
);
let contractor = profile(
"U_CONTRACTOR",
"contractor_acme_x",
"ACME-X Contractor",
OrganizationUnitKind::ContractorGroup,
);
let profiles = vec![
sales.clone(),
engineering.clone(),
finance.clone(),
leadership.clone(),
contractor.clone(),
];
let memory_rows = vec![
memory_row(
"sales_crm_acme",
&sales,
ResourceKind::DataStore,
"crm",
DataClass::CustomerData,
"ACME renewal in flight: primary contact Gavin Belson, expansion interest in seats.",
),
memory_row(
"sales_support_theme",
&sales,
ResourceKind::DataStore,
"support",
DataClass::Confidential,
"Top support theme this quarter for ACME: onboarding friction on SSO.",
),
memory_row(
"sales_risk_flag",
&sales,
ResourceKind::DataStore,
"risk",
DataClass::Confidential,
"Account risk note: ACME champion changed roles; relationship risk medium.",
),
memory_row(
"eng_github_auth",
&engineering,
ResourceKind::Repository,
"github",
DataClass::SourceCode,
"auth-service main: JWT rotation landed in PR #4821; ACME SSO integration branch open.",
),
memory_row(
"eng_linear_milestone",
&engineering,
ResourceKind::DataStore,
"linear",
DataClass::Internal,
"Linear: ACME SSO epic in progress, targeted for the M2 milestone.",
),
memory_row(
"eng_incident_sev2",
&engineering,
ResourceKind::DataStore,
"incidents",
DataClass::Internal,
"Incident log: SEV-2 cache stampede affecting ACME tenant, mitigated 2026-06-14.",
),
memory_row(
"finance_invoice_acme",
&finance,
ResourceKind::DataStore,
"invoices",
DataClass::FinancialRecord,
"Invoice INV-2043: ACME, $120k, net-30, currently unpaid (7 days overdue).",
),
memory_row(
"finance_payment_run",
&finance,
ResourceKind::DataStore,
"payments",
DataClass::FinancialRecord,
"Payment run 2026-07-01: $412k disbursed; ACME refund of $8k pending approval.",
),
memory_row(
"finance_contract_acme",
&finance,
ResourceKind::DataStore,
"contracts",
DataClass::FinancialRecord,
"ACME MSA: auto-renew on 2026-09-01 with a 14% price uplift clause.",
),
memory_row(
"leadership_board_summary",
&leadership,
ResourceKind::Document,
"board",
DataClass::Confidential,
"Exec summary: ACME is a top-5 account; renewal on track, one open SEV and a payment slip.",
),
DemoMemoryRow {
id: "shared_signing_key",
owner_org_unit_id: format!("{DEMO_TAXONOMY_ID}/{DEMO_UNSTAFFED_UNIT}"),
data_class: DataClass::Credential,
resource: resource(ResourceKind::SecretProviderCredential, "secrets"),
subject: "platform-secops".to_string(),
summary: "Production signing key for the ACME tenant; rotation scheduled 2026-08.",
},
memory_row(
"contractor_project_x",
&contractor,
ResourceKind::Project,
"project-x",
DataClass::Internal,
"Project X spec: build the ACME widget export; scope limited to the export pipeline.",
),
];
let mut graph = IntraTenantAuthorityGraph::new(tenant.clone());
graph.extend_units(profiles.iter().map(unit));
graph.extend_memberships(profiles.iter().map(membership));
let read_tools_all = [
"mcp.crm.*",
"mcp.support.*",
"mcp.github.*",
"mcp.linear.*",
"mcp.incidents.*",
];
graph.extend_unit_access_grants(vec![
allow_grant(
"g-sales-crm",
&sales.unit_principal,
resource(ResourceKind::DataStore, "crm"),
vec![DataClass::CustomerData, DataClass::Confidential],
),
allow_grant(
"g-sales-support",
&sales.unit_principal,
resource(ResourceKind::DataStore, "support"),
vec![DataClass::Confidential],
),
allow_grant(
"g-sales-risk",
&sales.unit_principal,
resource(ResourceKind::DataStore, "risk"),
vec![DataClass::Confidential],
),
tool_grant(
"g-sales-tools",
&sales.unit_principal,
patterns(&["mcp.crm.*", "mcp.support.*", "mcp.email.*"]),
),
allow_grant(
"g-eng-github",
&engineering.unit_principal,
resource(ResourceKind::Repository, "github"),
vec![DataClass::SourceCode, DataClass::Internal],
),
allow_grant(
"g-eng-linear",
&engineering.unit_principal,
resource(ResourceKind::DataStore, "linear"),
vec![DataClass::Internal],
),
allow_grant(
"g-eng-incidents",
&engineering.unit_principal,
resource(ResourceKind::DataStore, "incidents"),
vec![DataClass::Internal],
),
deny_grant(
"g-eng-deny-invoices",
&engineering.unit_principal,
resource(ResourceKind::DataStore, "invoices"),
vec![DataClass::FinancialRecord],
),
deny_grant(
"g-eng-deny-contracts",
&engineering.unit_principal,
resource(ResourceKind::DataStore, "contracts"),
vec![DataClass::FinancialRecord],
),
tool_grant(
"g-eng-tools",
&engineering.unit_principal,
patterns(&[
"mcp.github.*",
"mcp.linear.*",
"mcp.incidents.*",
"mcp.email.*",
]),
),
allow_grant(
"g-finance-invoices",
&finance.unit_principal,
resource(ResourceKind::DataStore, "invoices"),
vec![DataClass::FinancialRecord, DataClass::Confidential],
),
allow_grant(
"g-finance-payments",
&finance.unit_principal,
resource(ResourceKind::DataStore, "payments"),
vec![DataClass::FinancialRecord, DataClass::Confidential],
),
allow_grant(
"g-finance-contracts",
&finance.unit_principal,
resource(ResourceKind::DataStore, "contracts"),
vec![DataClass::FinancialRecord, DataClass::Confidential],
),
tool_grant(
"g-finance-tools",
&finance.unit_principal,
patterns(&["mcp.invoices.*", "mcp.contracts.*", "mcp.email.*"]),
),
allow_grant(
"g-leadership-org-wide",
&leadership.unit_principal,
org_wide_resource(),
vec![
DataClass::Internal,
DataClass::Confidential,
DataClass::CustomerData,
DataClass::SourceCode,
],
),
tool_grant(
"g-leadership-tools",
&leadership.unit_principal,
patterns(
&read_tools_all
.iter()
.copied()
.chain(["mcp.email.*"])
.collect::<Vec<_>>(),
),
),
allow_grant(
"g-contractor-project",
&contractor.unit_principal,
resource(ResourceKind::Project, "project-x"),
vec![DataClass::Internal],
),
tool_grant(
"g-contractor-tools",
&contractor.unit_principal,
patterns(&["mcp.projects.x.*"]),
),
]);
let tools = vec![
read_tool(
"mcp.crm.search_accounts",
vec![DataClass::CustomerData],
ToolRiskTier::CustomerDataAccess,
),
read_tool(
"mcp.support.list_summaries",
vec![DataClass::Confidential],
ToolRiskTier::ReadDiscover,
),
read_tool(
"mcp.github.read_repo",
vec![DataClass::SourceCode],
ToolRiskTier::ReadDiscover,
),
read_tool(
"mcp.linear.list_issues",
vec![DataClass::Internal],
ToolRiskTier::ReadDiscover,
),
read_tool(
"mcp.incidents.list_incidents",
vec![DataClass::Internal],
ToolRiskTier::ReadDiscover,
),
tagged_tool(
"mcp.invoices.read_invoices",
vec![DataClass::FinancialRecord],
ToolRiskTier::FinancialRecordAccess,
),
tagged_tool(
"mcp.contracts.read_contracts",
vec![DataClass::FinancialRecord],
ToolRiskTier::FinancialRecordAccess,
),
read_tool(
"mcp.projects.x.read_spec",
vec![DataClass::Internal],
ToolRiskTier::ReadDiscover,
),
send_tool("mcp.email.send_email"),
];
AcmeDemoDataset {
tenant_context: tenant,
graph,
profiles,
memory_rows,
tools,
}
}
pub fn profile_can_read_memory(profile: &DemoProfile, row: &DemoMemoryRow, _now_ms: u64) -> bool {
profile
.org_units()
.iter()
.any(|unit| unit == &row.owner_org_unit_id)
}
pub fn profile_holds_resource_grant(
dataset: &AcmeDemoDataset,
profile: &DemoProfile,
resource: &ResourceRef,
data_class: DataClass,
now_ms: u64,
) -> bool {
let request = AuthorityAccessRequest::new(
profile.principal.clone(),
resource.clone(),
AccessPermission::Read,
data_class,
);
dataset.graph.evaluate(&request, now_ms).is_allow()
}
pub fn profile_can_use_tool(
dataset: &AcmeDemoDataset,
profile: &DemoProfile,
tool: &DemoTool,
now_ms: u64,
) -> bool {
let allowed_patterns: Vec<String> = dataset
.graph
.effective_grants(&profile.principal, now_ms)
.into_iter()
.filter(|grant| grant.effect == AccessEffect::Allow)
.flat_map(|grant| grant.tool_patterns)
.map(|pattern| pattern.trim().to_ascii_lowercase())
.filter(|pattern| !pattern.is_empty())
.collect();
any_policy_matches(&allowed_patterns, &tool.schema.name.to_ascii_lowercase())
}
pub fn profile_reachable_set(
dataset: &AcmeDemoDataset,
profile: &DemoProfile,
now_ms: u64,
) -> Value {
let mut resources: Vec<String> = dataset
.memory_rows
.iter()
.filter(|row| profile_can_read_memory(profile, row, now_ms))
.map(|row| row.id.to_string())
.collect();
resources.sort();
let mut tools: Vec<Value> = dataset
.tools
.iter()
.filter(|tool| profile_can_use_tool(dataset, profile, tool, now_ms))
.map(|tool| {
json!({
"tool": tool.schema.name,
"risk_tier": tool_schema_risk_tier(&tool.schema).as_str(),
"approval_required": tool.approval_required(),
})
})
.collect();
tools.sort_by(|a, b| a["tool"].as_str().cmp(&b["tool"].as_str()));
json!({
"slack_user": profile.slack_user_id,
"org_unit": profile.owner_org_unit_id(),
"reachable_memory": resources,
"reachable_tools": tools,
})
}
pub fn reachable_set_snapshot(dataset: &AcmeDemoDataset, now_ms: u64) -> Value {
json!({
"prompt": DEMO_PROMPT,
"tenant": {
"org_id": DEMO_ORG_ID,
"workspace_id": DEMO_WORKSPACE_ID,
"taxonomy_id": DEMO_TAXONOMY_ID,
},
"profiles": dataset
.profiles
.iter()
.map(|profile| profile_reachable_set(dataset, profile, now_ms))
.collect::<Vec<_>>(),
})
}