# Guide: Multi-Team Policy Governance — Scaling Standards Across the Org **Target Audience:** Platform Engineers, Security Leads, Engineering Directors **Prerequisite:** [Policy Audit Trails](./policy-audit-trails.md) --- ## The Problem: Too Many Cooks Your organization has grown. Now you have: - **Security Team** — owns cryptography and authentication policies - **Platform Team** — owns infrastructure and observability policies - **Compliance Team** — owns data handling and PII policies - **Game Team** — owns performance and asset loading policies Each team publishes policies. A developer violates something and sees: ``` BLOCK code://go/auth/jwt/expiry ``` They ask: *"Who do I talk to about this? Is this Security or Platform?"* Without policy source tracking, they're stuck playing email roulette. --- ## The Solution: Federated Policy with Clear Ownership With policy source tracking, every violation shows exactly which team's policy caused it: ``` BLOCK code://go/auth/jwt/expiry Source: Security Team Standards v3.2 (sec-team: a1b2c3d4) ↑ Pack name ↑ Team ↑ Key ``` Now the developer knows: *"This is a Security Team policy. I'll ask them for an exception."* --- ## Architecture: One Project, Many Policies ``` Developer's Project ├── aphoria.toml │ policies = [ │ "https://policies.acme.com/security-v3.2.pack", │ "https://policies.acme.com/platform-v2.1.pack", │ "https://policies.acme.com/compliance-v1.0.pack" │ ] └── src/ └── ... ``` Each pack is owned by a different team. When conflicts arise, the source attribution tells you who to escalate to. --- ## Step 1: Each Team Creates Their Domain Policy ### Security Team ```bash cd security-team-policies/ aphoria init # Security-specific rules aphoria bless "code://*/tls/min_version" value "TLS1.3" \ --reason "Only TLS 1.3+ allowed per security policy" aphoria bless "code://*/jwt/expiry" max_seconds 900 \ --reason "Access tokens expire in 15 minutes" aphoria bless "code://*/crypto/hash" algorithm "sha256" \ --reason "MD5 and SHA1 banned for cryptographic use" aphoria export --name "Security Team Standards" --output security-v3.2.pack ``` ### Platform Team ```bash cd platform-team-policies/ aphoria init # Platform-specific rules aphoria bless "code://*/grpc/timeout" max_seconds 30 \ --reason "gRPC calls must timeout within 30s" aphoria bless "code://*/logging/level" default "info" \ --reason "Default log level is INFO, not DEBUG" aphoria bless "code://*/metrics/enabled" value true \ --reason "All services must export Prometheus metrics" aphoria export --name "Platform Team Standards" --output platform-v2.1.pack ``` ### Compliance Team ```bash cd compliance-team-policies/ aphoria init # Compliance-specific rules aphoria bless "code://*/pii/logging" masked true \ --reason "GDPR: PII must never appear in logs" aphoria bless "code://*/data/retention" max_days 90 \ --reason "Data retention policy: 90 days max" aphoria export --name "Compliance Standards" --output compliance-v1.0.pack ``` --- ## Step 2: Centralized Policy Registry Host all packs in a central location with a manifest: ```yaml # https://policies.acme.com/manifest.yaml policies: security: url: https://policies.acme.com/security-v3.2.pack owner: security-team@acme.com slack: "#security-policy" platform: url: https://policies.acme.com/platform-v2.1.pack owner: platform-team@acme.com slack: "#platform-support" compliance: url: https://policies.acme.com/compliance-v1.0.pack owner: compliance@acme.com slack: "#compliance-questions" ``` --- ## Step 3: Developer Experience A developer working on `payment-service` configures their project: ```toml # aphoria.toml policies = [ "https://policies.acme.com/security-v3.2.pack", "https://policies.acme.com/platform-v2.1.pack", "https://policies.acme.com/compliance-v1.0.pack" ] ``` They run a scan and see multiple violations: ``` ┌──────────────────────────────────────────────────────────────────────┐ │ SCAN RESULTS: payment-service │ ├──────────────────────────────────────────────────────────────────────┤ │ │ │ BLOCK code://go/payment/tls/min_version │ │ Your Code: TLS1.2 │ │ Policy: TLS1.3 │ │ Source: Security Team Standards v3.2 (a1b2c3d4) │ │ Contact: #security-policy │ │ │ │ FLAG code://go/payment/grpc/timeout │ │ Your Code: 60s │ │ Policy: 30s max │ │ Source: Platform Team Standards v2.1 (e5f6g7h8) │ │ Contact: #platform-support │ │ │ │ BLOCK code://go/payment/pii/logging │ │ Your Code: logging full request body │ │ Policy: PII must be masked │ │ Source: Compliance Standards v1.0 (c9d0e1f2) │ │ Contact: #compliance-questions │ │ │ └──────────────────────────────────────────────────────────────────────┘ ``` The developer now knows: - TLS issue → Ask **Security Team** in `#security-policy` - Timeout issue → Ask **Platform Team** in `#platform-support` - PII issue → Ask **Compliance** in `#compliance-questions` --- ## Handling Policy Conflicts Between Teams What if Security says "log everything for forensics" but Compliance says "mask all PII"? ### Option 1: Policy Hierarchy Configure policy precedence in your project: ```toml # aphoria.toml policies = [ "https://policies.acme.com/compliance-v1.0.pack", # Highest priority "https://policies.acme.com/security-v3.2.pack", "https://policies.acme.com/platform-v2.1.pack" # Lowest priority ] ``` Later policies can override earlier ones. Compliance wins. ### Option 2: Domain Scoping Teams scope their policies to avoid overlap: ```bash # Security Team: only auth/* and crypto/* paths aphoria bless "code://*/auth/..." ... aphoria bless "code://*/crypto/..." ... # Compliance Team: only pii/* and data/* paths aphoria bless "code://*/pii/..." ... aphoria bless "code://*/data/..." ... ``` ### Option 3: Joint Resolution Pack Create a "Resolved Conflicts" pack signed by both teams: ```bash # After Security + Compliance agree aphoria bless "code://*/logging/pii" \ masked true \ --reason "Joint resolution: Mask PII, log metadata for forensics" aphoria export --name "Security-Compliance Resolution" --output resolved-v1.pack ``` --- ## Reporting Across Teams Generate a policy coverage report showing which teams govern which areas: ```bash aphoria scan . --mode persistent --format json | jq ' .findings | group_by(.conflicting_sources[0].policy_source.pack_name) | map({ team: .[0].conflicting_sources[0].policy_source.pack_name, violations: length }) ' ``` **Output:** ```json [ { "team": "Security Team Standards v3.2", "violations": 3 }, { "team": "Platform Team Standards v2.1", "violations": 1 }, { "team": "Compliance Standards v1.0", "violations": 2 } ] ``` --- ## Summary | Without Policy Source Tracking | With Policy Source Tracking | |--------------------------------|-----------------------------| | "Who owns this rule?" | "Security Team Standards v3.2" | | "Where do I escalate?" | "#security-policy Slack channel" | | "Can I get an exception?" | "Ask the signing team (a1b2c3d4)" | | "Which team approved this?" | Cryptographic proof in pack signature | **The Result:** Decentralized policy authorship with centralized enforcement and clear accountability. --- **Next:** Learn how to integrate Aphoria into your CI/CD pipeline in [Pre-flight Checks](./pre-flight-checks.md).