# RFC-001: Enterprise Policy Alias System **Date:** 2026-02-05 **Status:** Proposed **Author:** Aphoria Team **Target Audience:** Enterprise security teams, CTOs, and development organizations --- ## Executive Summary Enterprise security teams need to enforce organization-wide security policies across diverse development teams using different programming languages and project structures. The current tail-path matching system works well for bundled RFC/OWASP corpus but fails when security teams create custom policies using logical hierarchies (e.g., `code://standards/tls/*`) that don't align with extractor output (e.g., `code://rust/myapp/tls/*`). This RFC proposes **Policy Aliases**—an explicit mapping layer in Trust Packs that bridges the gap between enterprise policy hierarchies and code extractor conventions, enabling seamless cross-language policy enforcement with full audit trails and cryptographic verification. --- ## Problem Statement ### Current State: Tail-Path Matching Works for Bundled Corpus Aphoria uses a tail-path matching algorithm that extracts the last two segments of a subject path to create index keys. This enables cross-scheme concept matching: ``` RFC source: "rfc://5246/tls/cert_verification" Code extractor: "code://rust/myapp/tls/cert_verification" Both produce key: "tls/cert_verification::enabled" ``` This works because **extractors are intentionally designed** to align with RFC/OWASP hierarchies. The bundled authoritative corpus and code extractors share a common conceptual vocabulary. ### The Enterprise Gap: Policy Hierarchies Don't Match Extractor Output When enterprise security teams create their own policies, they naturally organize them using **logical domains**, not language-qualified paths: ```toml # Security team's mental model subject = "code://standards/tls/cert_verification" # Standards subject = "code://internal/exceptions/md5_allowed" # Exceptions subject = "code://vendor/aws/s3/public_access" # Cloud rules ``` But code extractors produce **language-qualified paths**: ```rust // Rust extractor output concept_path: "code://rust/myapp/tls/cert_verification" // Go extractor output concept_path: "code://go/myapp/tls/cert_verification" ``` **Tail-path matching fails:** | Source | Path | Extracted Key | |--------|------|---------------| | Policy | `code://standards/tls/cert_verification` | `tls/cert_verification::enabled` | | Code | `code://rust/myapp/tls/cert_verification` | `myapp/tls::enabled` | The keys don't match because they extract different segments: `standards/tls` vs `rust/myapp/tls`. ### Business Impact This mismatch has serious consequences for enterprises: 1. **Policy Enforcement Broken:** Security standards don't match code violations 2. **Compliance Risk:** Audits fail when policies exist but aren't enforced 3. **Adoption Blocker:** Enterprises can't use Trust Packs for cross-team governance 4. **False Security:** Teams think they're protected when policies aren't actually matching **Real-world scenario:** A security team exports a signed Trust Pack with TLS requirements. Development teams import it and run scans. Zero conflicts are reported—not because the code is compliant, but because the matching algorithm never connects policy to code. --- ## Design Goals 1. **Preserve Tail-Path Matching:** The fast O(1) lookup for bundled corpus must remain the default path 2. **Explicit Over Implicit:** Policy authors must explicitly define matches—no magic auto-aliasing 3. **Cryptographically Verified:** Aliases are part of the signed Trust Pack, tamper-resistant 4. **Zero Dev Team Configuration:** Import a Trust Pack URL, scanning works—no per-team setup 5. **Full Audit Trail:** Every conflict traces back to specific policy, alias pattern, and issuer 6. **Backward Compatible:** Existing Trust Packs without aliases continue working unchanged --- ## Technical Architecture ### Current: Tail-Path Matching ``` ┌─────────────────────────────────────────────────────────────┐ │ Scan Flow │ │ │ │ 1. Extractor produces: │ │ concept_path: "code://rust/myapp/tls/cert_verification" │ │ predicate: "enabled" │ │ value: false │ │ │ │ 2. ConceptIndex::lookup() computes key: │ │ key = "myapp/tls::enabled" (last 2 segments) │ │ │ │ 3. Hash table lookup: O(1) │ │ result = index.get("myapp/tls::enabled") │ │ │ │ 4. If match found → conflict detection │ │ If no match → skip (no authoritative source) │ └─────────────────────────────────────────────────────────────┘ ``` **Strengths:** - O(1) constant-time lookups - Zero configuration required - Cross-language matching for RFC-aligned extractors **Limitation:** - Only works when policy paths and extractor paths share the same final segments ### Extension: Policy Aliases Policy Aliases add a fallback matching layer that activates only when tail-path matching fails: ``` ┌─────────────────────────────────────────────────────────────┐ │ Extended Matching Flow │ │ │ │ 1. Try tail-path match (existing, fast path) │ │ key = make_key(subject, predicate) │ │ if index.contains(key) → return match │ │ │ │ 2. Try policy alias patterns (fallback path) │ │ for alias in trust_pack.policy_aliases: │ │ for pattern in alias.target_patterns: │ │ if glob_match(pattern, subject): │ │ key = make_key(alias.policy_path, predicate) │ │ if index.contains(key) → return match │ │ │ │ 3. No match → no authoritative source for this claim │ └─────────────────────────────────────────────────────────────┘ ``` ### Matching Algorithm **Pseudocode:** ```rust fn lookup_with_policy_aliases( index: &ConceptIndex, subject: &str, predicate: &str, policy_aliases: &[PolicyAlias], ) -> Option<&Vec> { // 1. Fast path: direct tail-path match (O(1)) if let Some(result) = index.lookup(subject, predicate) { return Some(result); } // 2. Fallback path: policy alias expansion (O(P × A)) // P = patterns per alias, A = number of aliases for alias in policy_aliases { if subject_matches_any_pattern(subject, &alias.target_patterns) { if let Some(result) = index.lookup(&alias.policy_path, predicate) { return Some(result); } } } None } fn subject_matches_any_pattern(subject: &str, patterns: &[String]) -> bool { patterns.iter().any(|pattern| glob_match(pattern, subject)) } fn glob_match(pattern: &str, subject: &str) -> bool { // Split both into segments let pattern_parts: Vec<&str> = pattern.split('/').collect(); let subject_parts: Vec<&str> = subject.split('/').collect(); // Must have same segment count if pattern_parts.len() != subject_parts.len() { return false; } // Match segment-by-segment; "*" matches any single segment pattern_parts.iter() .zip(subject_parts.iter()) .all(|(p, s)| *p == "*" || *p == *s) } ``` **Step-by-step example:** ``` Input: subject = "code://rust/backend-api/tls/cert_verification" predicate = "enabled" alias = PolicyAlias { policy_path: "code://standards/tls/cert_verification", target_patterns: ["code://rust/*/tls/cert_verification"], } Step 1: Tail-path match attempt key = "backend-api/tls::enabled" index.lookup("backend-api/tls::enabled") → None Step 2: Alias pattern matching Pattern: "code://rust/*/tls/cert_verification" Subject: "code://rust/backend-api/tls/cert_verification" Segment comparison: "code:" == "code:" ✓ "" == "" ✓ (after first slash) "rust" == "rust" ✓ "*" matches "backend-api" ✓ (wildcard) "tls" == "tls" ✓ "cert_verification" == "cert_verification" ✓ Pattern matches! Step 3: Lookup using policy_path key = "tls/cert_verification::enabled" index.lookup("tls/cert_verification::enabled") → Some([Assertion]) Result: Match found via policy alias ``` --- ## Trust Pack Schema Extension ### Current Schema ```rust #[derive(Archive, Deserialize, Serialize, Debug, Clone)] #[archive(check_bytes)] pub struct TrustPack { pub header: PackHeader, pub assertions: Vec, pub aliases: Vec, // Existing: concept-level aliases pub signature: [u8; 64], // Ed25519 signature } pub struct PackHeader { pub name: String, pub version: String, pub issuer_id: [u8; 32], // Ed25519 public key pub timestamp: u64, // Unix timestamp } ``` ### Extended Schema ```rust #[derive(Archive, Deserialize, Serialize, Debug, Clone)] #[archive(check_bytes)] pub struct TrustPack { pub header: PackHeader, pub assertions: Vec, pub aliases: Vec, pub policy_aliases: Vec, // NEW: Policy-level aliases pub signature: [u8; 64], } /// Maps policy assertion paths to extractor output patterns. /// /// Enables enterprise security teams to define standards using logical hierarchies /// (e.g., "code://standards/tls/*") that match extractor output /// (e.g., "code://rust/myapp/tls/*"). #[derive(Archive, Deserialize, Serialize, Debug, Clone)] #[archive(check_bytes)] pub struct PolicyAlias { /// The policy path used in assertions. /// Example: "code://standards/tls/cert_verification" pub policy_path: String, /// Glob patterns that should resolve to this policy path. /// Supports single-segment wildcards (*) only. /// /// Examples: /// - "code://rust/*/tls/cert_verification" (any Rust project) /// - "code://*/myapp/tls/cert_verification" (any language, specific project) /// - "code://*/*/tls/cert_verification" (any language, any project) pub target_patterns: Vec, } ``` **Backward Compatibility:** ```rust // Deserialization with default for missing field impl Default for TrustPack { fn default() -> Self { TrustPack { header: PackHeader::default(), assertions: vec![], aliases: vec![], policy_aliases: vec![], // Empty = no policy aliases = current behavior signature: [0u8; 64], } } } ``` Existing Trust Packs without `policy_aliases` field will deserialize with an empty vector, preserving current behavior. --- ## CLI Interface ### Adding Policy Aliases ```bash # Add a single alias with multiple target patterns aphoria policy add-alias \ --pack security-standards.pack \ --policy-path "code://standards/tls/cert_verification" \ --target "code://rust/*/tls/cert_verification" \ --target "code://go/*/tls/cert_verification" \ --target "code://python/*/tls/cert_verification" ``` **Options:** | Flag | Description | |------|-------------| | `--pack ` | Path to Trust Pack file | | `--policy-path ` | Policy assertion path to alias | | `--target ` | Glob pattern (can be specified multiple times) | | `--output ` | Output path (default: overwrite input) | ### Listing Policy Aliases ```bash aphoria policy list-aliases --pack security-standards.pack ``` **Output:** ``` Policy Aliases in "Acme Security Standards" v1.0.0: 1. code://standards/tls/cert_verification Targets: - code://rust/*/tls/cert_verification - code://go/*/tls/cert_verification - code://python/*/tls/cert_verification 2. code://standards/jwt/audience_validation Targets: - code://*/*/jwt/audience_validation Total: 2 policy aliases ``` ### Validating Aliases ```bash aphoria policy validate-aliases --pack security-standards.pack ``` **Output:** ``` Validating policy aliases... ✓ code://rust/*/tls/cert_verification - valid glob pattern ✓ code://go/*/tls/cert_verification - valid glob pattern ✓ code://python/*/tls/cert_verification - valid glob pattern ⚠ Warning: No assertions found for policy path "code://standards/jwt/audience_validation" (alias exists but no corresponding assertion) Validation complete: 3 valid, 0 invalid, 1 warning ``` --- ## Enterprise Workflow ### Step 1: Security Team Creates Standards (Golden Repo) ```bash cd security-standards/ # Create TLS certificate verification requirement aphoria bless \ --subject "code://standards/tls/cert_verification" \ --predicate "enabled" \ --value true \ --reason "RFC 5246 compliance - TLS certificate verification required" # Create JWT audience validation requirement aphoria bless \ --subject "code://standards/jwt/audience_validation" \ --predicate "enabled" \ --value true \ --reason "RFC 7519 compliance - JWT audience claim must be validated" ``` ### Step 2: Security Team Adds Policy Aliases ```bash # Export unsigned pack aphoria policy export --name "Acme-Security-Standards" --output acme-v1.0.pack # Add aliases for all supported languages aphoria policy add-alias \ --pack acme-v1.0.pack \ --policy-path "code://standards/tls/cert_verification" \ --target "code://rust/*/tls/cert_verification" \ --target "code://go/*/tls/cert_verification" \ --target "code://python/*/tls/cert_verification" \ --target "code://java/*/tls/cert_verification" aphoria policy add-alias \ --pack acme-v1.0.pack \ --policy-path "code://standards/jwt/audience_validation" \ --target "code://*/*/jwt/audience_validation" ``` ### Step 3: Security Team Publishes Pack ```bash # Upload to internal artifact server aws s3 cp acme-v1.0.pack s3://acme-policies/acme-v1.0.pack --acl private # Or publish to internal registry curl -X POST https://policy-registry.acme.com/packs \ -H "Authorization: Bearer $SECURITY_TEAM_TOKEN" \ --data-binary @acme-v1.0.pack ``` ### Step 4: Development Team Configures Project **File: `aphoria.toml`** ```toml [policies] sources = [ "https://policy-registry.acme.com/packs/acme-v1.0.pack" ] # Or using S3 presigned URL # sources = [ # "s3://acme-policies/acme-v1.0.pack" # ] ``` That's it. No other configuration needed. ### Step 5: Development Team Scans Code ```bash aphoria scan --mode persistent ``` **Console Output:** ``` ┌─────────────────────────────────────────────────────────────────┐ │ Aphoria Security Scan Report │ ├─────────────────────────────────────────────────────────────────┤ │ Project: backend-api │ │ Files: 42 │ │ Claims: 127 │ ├─────────────────────────────────────────────────────────────────┤ │ BLOCK (1) │ ├─────────────────────────────────────────────────────────────────┤ │ src/main.rs:42 │ │ │ │ code://rust/backend-api/tls/cert_verification │ │ │ │ Code asserts: enabled = false (confidence: 0.95) │ │ Authority: enabled = true (confidence: 1.00) │ │ │ │ Source: Acme-Security-Standards v1.0.0 │ │ Issuer: a1b2c3d4e5f6... │ │ Policy: code://standards/tls/cert_verification │ │ │ │ Matched via policy alias: │ │ Pattern: code://rust/*/tls/cert_verification │ │ │ │ Verdict: BLOCK │ │ Recommendation: Enable TLS certificate verification │ └─────────────────────────────────────────────────────────────────┘ Exit code: 1 ``` ### Step 6: CI/CD Integration **GitHub Actions:** ```yaml name: Security Scan on: [push, pull_request] jobs: aphoria-scan: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install Aphoria run: cargo install aphoria - name: Run Security Scan run: aphoria scan --mode persistent --exit-code # Exit code 1 = BLOCK verdict found → build fails ``` --- ## Security Considerations ### Signature Verification Policy aliases are included in the signed Trust Pack: ```rust fn sign_trust_pack(pack: &TrustPack, key: &SigningKey) -> [u8; 64] { // Signature covers ALL fields including policy_aliases let content = serialize(&TrustPackContent { header: pack.header.clone(), assertions: pack.assertions.clone(), aliases: pack.aliases.clone(), policy_aliases: pack.policy_aliases.clone(), // Included }); key.sign(&content).to_bytes() } ``` **Guarantee:** If anyone tampers with policy aliases, signature verification fails. ### Audit Trail Every conflict report includes: 1. **Pack Name & Version:** Which Trust Pack triggered the conflict 2. **Issuer ID:** Ed25519 public key of the signing authority 3. **Policy Path:** The canonical policy assertion that was matched 4. **Matched Pattern:** Which glob pattern caused the match 5. **Timestamp:** When the Trust Pack was created This enables forensic analysis: "Why did this build fail?" → "Because pattern X in pack Y matched code Z." ### Tamper Resistance ``` Trust Pack Integrity Chain: 1. Security team creates assertions in local Episteme store 2. `aphoria policy export` serializes + signs with team's Ed25519 key 3. Pack distributed via any channel (S3, registry, etc.) 4. Dev team's `aphoria scan` verifies signature before using 5. If signature invalid → pack rejected, scan fails with clear error ``` ### Privilege Separation | Actor | Can Do | Cannot Do | |-------|--------|-----------| | Security Team | Create assertions, add aliases, sign packs | Modify dev team code | | Dev Team | Import packs, run scans, acknowledge conflicts | Modify pack contents, bypass policies | | CI/CD | Run scans, fail builds | Override BLOCK verdicts | --- ## Performance Analysis ### Complexity Analysis | Operation | Time Complexity | Space Complexity | |-----------|-----------------|------------------| | Tail-path match (existing) | O(1) | O(N) where N = assertions | | Policy alias fallback | O(P × A) | O(A) where A = aliases | | Total lookup | O(1) + O(P × A) | O(N + A) | Where: - P = patterns per alias (typically 3-5) - A = total number of aliases (typically 10-50) **Expected Performance:** - 95% of lookups hit fast path (tail-path match) - 5% of lookups fall through to alias matching - Alias matching adds ~0.1ms per lookup (simple string comparison) ### Benchmark Targets | Metric | Target | Rationale | |--------|--------|-----------| | Scan time increase | < 5% | Alias matching should be negligible | | Memory overhead | < 10 KB per pack | Aliases are small strings | | Policy download time | < 1s | Packs cached after first download | ### Real-World Estimate For a typical enterprise deployment: - 50 policy assertions - 20 policy aliases - 5 patterns per alias (100 patterns total) - 10,000 code claims per scan **Calculations:** - Fast path hits: ~9,500 claims (95%) - Alias fallback: ~500 claims - Alias comparisons: 500 × 100 = 50,000 string comparisons - String comparison time: ~1 microsecond each - Total alias overhead: ~50ms per scan **Conclusion:** Negligible impact on scan time. --- ## Backward Compatibility ### Migration Path **No migration required.** The change is purely additive: 1. **Existing Trust Packs:** Deserialize with empty `policy_aliases` vector 2. **Existing Scans:** Empty aliases = skip alias fallback = current behavior 3. **Existing CI/CD:** No changes to configuration or commands 4. **Existing Extractors:** No changes to output format ### Zero-Friction Adoption | Scenario | Required Changes | |----------|------------------| | New enterprise deployment | Add `policy_aliases` to Trust Pack | | Existing small team | None (bundled corpus works) | | Existing enterprise with custom pack | Add aliases, re-sign, redistribute | ### Version Negotiation Trust Packs include a version field in the header: ```rust pub struct PackHeader { pub schema_version: u8, // 1 = original, 2 = with policy_aliases // ... } ``` Older Aphoria versions encountering schema v2 packs will: 1. Log a warning about unknown field 2. Ignore `policy_aliases` (graceful degradation) 3. Continue with tail-path matching only --- ## Alternative Approaches Considered ### Alternative 1: Normalize Extractor Output **Idea:** Make extractors output "canonical" paths that match standards. ```rust // Instead of: "code://rust/myapp/tls/cert_verification" // Output: "code://standards/tls/cert_verification" ``` **Why rejected:** - Loses language context (`rust/myapp`) needed for file location - Breaks existing aliases and observations - Forces extractors to know about ALL standards - Violates separation of concerns ### Alternative 2: Flexible Tail-Path Length **Idea:** Try matching with N=1, N=2, N=3 segments. ```rust // Try multiple keys "cert_verification::enabled" // N=1 "tls/cert_verification::enabled" // N=2 "myapp/tls/cert_verification::enabled" // N=3 ``` **Why rejected:** - Ambiguous matches (which key wins?) - Performance impact (3x lookups) - Doesn't solve semantic differences - No explicit control over matching behavior ### Alternative 3: Auto-Discover Aliases **Idea:** Automatically create aliases during scan when tail-path matches but full path differs. ```rust // Scan detects potential match, auto-creates alias if tail_match && !full_match { auto_alias(claim.concept_path, assertion.subject); } ``` **Why rejected:** - Implicit behavior (hard to debug) - No security team approval (bypasses policy control) - May create false positives - Violates "explicit over implicit" principle **Future consideration:** Could be implemented as suggestions (not automatic), shown in scan output. --- ## Implementation Roadmap ### Phase 1: Schema Extension (Day 1) 1. Add `PolicyAlias` type to `policy.rs` 2. Extend `TrustPack` struct with `policy_aliases` field 3. Update serialization/deserialization 4. Update signature computation to include aliases 5. Add unit tests for schema changes **Deliverable:** Trust Packs can store and serialize policy aliases. ### Phase 2: Pattern Matching (Day 1-2) 1. Implement `glob_match()` function 2. Add `lookup_with_policy_aliases()` to ConceptIndex 3. Write comprehensive test suite for pattern matching 4. Handle edge cases (empty patterns, invalid syntax) **Deliverable:** Pattern matching algorithm works correctly. ### Phase 3: Scan Integration (Day 2) 1. Load policy aliases from imported Trust Packs 2. Pass aliases to conflict detection 3. Include alias info in conflict reports 4. Update all output formats (JSON, table, markdown, SARIF) **Deliverable:** Scans detect conflicts via policy aliases. ### Phase 4: CLI Tooling (Day 3) 1. Implement `policy add-alias` command 2. Implement `policy list-aliases` command 3. Implement `policy validate-aliases` command 4. Update help text and documentation **Deliverable:** Security teams can manage aliases via CLI. ### Phase 5: Documentation & UAT (Day 3-4) 1. Update user documentation 2. Write enterprise deployment guide 3. Create UAT scenario with real enterprise workflow 4. Validate end-to-end functionality **Deliverable:** Complete documentation and validated implementation. --- ## Open Questions ### Q1: Should we support recursive wildcards? **Current proposal:** Single-segment wildcards only (`*`) ``` "code://rust/*/tls/*" ✓ Supported "code://rust/**/tls" ✗ Not supported (yet) ``` **Trade-off:** Recursive wildcards (`**`) are more flexible but harder to reason about. Start simple, add if needed. **Decision requested:** Defer recursive wildcards to future enhancement? ### Q2: What happens when multiple aliases match? **Current proposal:** First match wins (aliases processed in declaration order). **Alternative:** Most specific match wins (fewer wildcards = higher priority). **Trade-off:** First-match is simpler but requires security teams to order aliases carefully. **Decision requested:** First-match or most-specific? ### Q3: Should invalid patterns fail Trust Pack creation? **Current proposal:** Yes—validate patterns at creation time, reject invalid glob syntax. **Alternative:** Warn but allow (lenient), fail at scan time. **Trade-off:** Fail-fast is better for security teams but may be inconvenient during iteration. **Decision requested:** Strict validation at creation time? ### Q4: Should we cache pattern match results? **Current proposal:** Recompute on each lookup (simple, no cache invalidation issues). **Alternative:** Cache subject → policy_path map per scan. **Trade-off:** Caching improves performance but adds complexity. **Decision requested:** Defer optimization until benchmarks show need? --- ## Appendix: Example Scenarios ### Scenario A: Multi-Language TLS Enforcement **Security team creates:** ```bash aphoria bless \ --subject "code://standards/tls/cert_verification" \ --predicate "enabled" \ --value true aphoria policy add-alias \ --pack standards.pack \ --policy-path "code://standards/tls/cert_verification" \ --target "code://rust/*/tls/cert_verification" \ --target "code://go/*/tls/cert_verification" \ --target "code://python/*/tls/cert_verification" \ --target "code://java/*/tls/cert_verification" \ --target "code://kotlin/*/tls/cert_verification" ``` **Rust team's code:** ```rust // src/client.rs let client = reqwest::Client::builder() .danger_accept_invalid_certs(true) // Violation! .build()?; ``` **Extractor output:** ``` concept_path: "code://rust/api-service/tls/cert_verification" predicate: "enabled" value: false ``` **Scan result:** ``` BLOCK: TLS cert verification disabled Policy: code://standards/tls/cert_verification Matched via: code://rust/*/tls/cert_verification Source: Acme-Security-Standards v1.0.0 ``` --- ### Scenario B: Cloud-Specific Rules **Security team creates:** ```bash aphoria bless \ --subject "code://vendor/aws/s3/public_access" \ --predicate "blocked" \ --value true \ --reason "S3 buckets must not allow public access" aphoria policy add-alias \ --pack cloud-rules.pack \ --policy-path "code://vendor/aws/s3/public_access" \ --target "code://*/*/aws/s3/public_access" \ --target "code://*/*/cloud/storage/s3/public" ``` **Dev team's Terraform:** ```hcl resource "aws_s3_bucket_public_access_block" "example" { bucket = aws_s3_bucket.example.id block_public_acls = false # Violation! } ``` **Scan detects via alias matching.** --- ### Scenario C: Internal Policy Exceptions **Security team creates exception:** ```bash # Allow MD5 for specific legacy system aphoria bless \ --subject "code://internal/exceptions/legacy-auth/md5" \ --predicate "allowed" \ --value true \ --reason "Legacy auth system requires MD5 until migration complete" aphoria policy add-alias \ --pack exceptions.pack \ --policy-path "code://internal/exceptions/legacy-auth/md5" \ --target "code://rust/legacy-auth-service/crypto/md5" \ --target "code://go/legacy-auth-service/crypto/md5" ``` **Result:** Only the specific legacy service can use MD5; all other services still blocked. --- ## Glossary | Term | Definition | |------|------------| | **Assertion** | A claim about a subject-predicate-object relationship | | **Trust Pack** | Signed bundle of assertions and aliases for distribution | | **Policy Alias** | Mapping from policy path to extractor output patterns | | **Tail-Path Matching** | Algorithm using last 2 path segments for index lookup | | **Glob Pattern** | String pattern with `*` wildcards for matching paths | | **Issuer ID** | Ed25519 public key identifying Trust Pack signer | | **BLOCK Verdict** | Scan result indicating policy violation that should halt build | --- ## References - [Concept Matching Analysis](../applications/aphoria/docs/architecture/concept-matching-analysis.md) - [Policy Alias Implementation Guide](../applications/aphoria/docs/architecture/policy-alias-implementation.md) - [Matching Philosophy](../applications/aphoria/docs/architecture/matching-philosophy.md) - [Enterprise Validation Scenario](../applications/aphoria/docs/architecture/enterprise-validation.md) - [UAT: Real-World Policy Source Tracking](../applications/aphoria/uat/2026-02-04-uat-real-world-policy-source.md)