Skip to content

symcc: add SymSchema for amortized SymEntities across request envs#2467

Open
tomlikestorock wants to merge 2 commits into
cedar-policy:mainfrom
tomlikestorock:symcc-sym-schema
Open

symcc: add SymSchema for amortized SymEntities across request envs#2467
tomlikestorock wants to merge 2 commits into
cedar-policy:mainfrom
tomlikestorock:symcc-sym-schema

Conversation

@tomlikestorock

@tomlikestorock tomlikestorock commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Description of changes

Add SymSchema to cedar-policy-symcc for amortizing the expensive SymEntities::of_schema computation across multiple request environments.

Callers checking many request environments against the same schema (e.g. policy subsumption with large action lists) previously rebuilt symbolic entities per environment (~3.7s each in my perhaps pathological case). SymSchema precomputes them once (~1.86s for me) and produces SymEnv instances via sym_env() that share the entities via Arc (0.9ms each).

Example usage:

let sym_schema = SymSchema::new(&schema)?;
let mut compiler = CedarSymCompiler::new(solver)?;

for req_env in &request_envs {
    let sym_env = sym_schema.sym_env(req_env)?;
    let compiled_a = CompiledPolicySet::compile_with_custom_symenv(
        &pset_a, req_env, &schema, sym_env.clone(),
    )?;
    let compiled_b = CompiledPolicySet::compile_with_custom_symenv(
        &pset_b, req_env, &schema, sym_env.clone(),
    )?;
    let implies = compiler.check_implies_opt(&compiled_a, &compiled_b).await?;
    assert!(implies);
}

I benchmarked this against the non-deprecated symcc with good results. Since this wraps the symcc functionality I don't believe it requires a lean change.

Since this is a new public type I figured this is a new minor version at least.

Issue #, if available

None, perhaps a continuation cousin of #2439. I can make a new issue if desired.

Checklist for requesting a review

The change in this PR is (choose one, and delete the other options):

  • A backwards-compatible change requiring a minor version bump to cedar-policy (e.g., addition of a new API).

I confirm that this PR (choose one, and delete the other options):

  • Updates the "Unreleased" section of the CHANGELOG with a description of my change (required for major/minor version bumps).

I confirm that cedar-spec (choose one, and delete the other options):

  • Does not require updates because my change does not impact the Cedar formal model or DRT infrastructure.

I confirm that docs.cedarpolicy.com (choose one, and delete the other options):

  • Does not require updates because my change does not impact the Cedar language specification.

Copilot AI review requested due to automatic review settings July 10, 2026 00:36

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a new SymSchema API in cedar-policy-symcc to amortize the expensive SymEntities::of_schema computation across many request environments, enabling callers to efficiently build multiple SymEnvs that share precomputed symbolic entities.

Changes:

  • Add SymSchema (public) to precompute and reuse SymEntities per schema via sym_env(&RequestEnv).
  • Update SymEntities to wrap its internal map in Arc<...> to enable cheap sharing across SymEnv instances.
  • Add integration tests to assert SymSchema::sym_env matches SymEnv::new, reuses entity storage across calls, and rejects unknown actions; update exports and changelog.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
cedar-policy-symcc/tests/integration_tests.rs Adds tests covering SymSchema correctness, reuse semantics, and error behavior.
cedar-policy-symcc/src/symcc/symbolizer.rs Updates SymEntities construction to wrap maps in Arc.
cedar-policy-symcc/src/symcc/interpretation.rs Updates SymEntities::interpret to return an Arc-backed SymEntities.
cedar-policy-symcc/src/symcc/env.rs Changes SymEntities storage to Arc and adds the new SymSchema type/API.
cedar-policy-symcc/src/symcc/encoder.rs Updates unit tests to construct SymEntities with Arc::new(...).
cedar-policy-symcc/src/symcc.rs Re-exports SymSchema from the symcc module.
cedar-policy-symcc/src/lib.rs Re-exports SymSchema at the crate root.
cedar-policy-symcc/CHANGELOG.md Documents the new SymSchema API in the Unreleased section.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +458 to +465
pub fn sym_env(&self, req_env: &RequestEnv) -> crate::err::Result<SymEnv> {
let env = Environment::from_request_env(req_env, self.schema.as_ref())
.ok_or_else(|| crate::err::Error::ActionNotInSchema(req_env.action().to_string()))?;
Ok(SymEnv {
request: SymRequest::of_request_type(&env.req_ty)?,
entities: self.entities.clone(),
})
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a pre-existing issue in SymEnv::new (same ok_or_else(ActionNotInSchema) on line 56). SymSchema::sym_env matches the existing behavior. Should I change both?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think changing both makes sense, no need to block this PR though.

Comment thread cedar-policy-symcc/tests/integration_tests.rs Outdated
Wrap SymEntities inner BTreeMap in Arc for cheap cloning. Add SymSchema
struct that precomputes SymEntities once per schema and produces SymEnv
instances via sym_env(), reusing the shared entities.

Callers checking many request environments against the same schema
(e.g. policy subsumption with large action lists) avoid rebuilding
symbolic entities per environment:
  - without SymSchema: ~3.7s/env
  - with SymSchema: ~0.9ms/env + 1.86s one-time build

Signed-off-by: Thomas Hill <thill@cloudflare.com>
@github-actions

Copy link
Copy Markdown

Coverage Report

Head Commit: eec92997f1fbc3caa51bfacae98fdeaddc273dc1

Base Commit: feb3e1dcb8c7064b1bfc5293e53d362228d2bc54

Download the full coverage report.

Coverage of Added or Modified Lines of Rust Code

Required coverage: 80.00%

Actual coverage: 82.35%

Status: PASSED ✅

Details
File Status Covered Coverage Missed Lines
cedar-policy-symcc/src/symcc/env.rs 🟢 12/15 80.00% 446-448
cedar-policy-symcc/src/symcc/interpretation.rs 🟢 1/1 100.00%
cedar-policy-symcc/src/symcc/symbolizer.rs 🟢 1/1 100.00%

Coverage of All Lines of Rust Code

Required coverage: 80.00%

Actual coverage: 88.23%

Status: PASSED ✅

Details
Package Status Covered Coverage Base Coverage
cedar-language-server 🟢 4722/5102 92.55% 92.55%
cedar-policy 🟢 4643/5758 80.64% 80.64%
cedar-policy-cli 🟡 1271/1648 77.12% 77.12%
cedar-policy-core 🟢 24746/27945 88.55% 88.55%
cedar-policy-formatter 🟢 914/1088 84.01% 84.01%
cedar-policy-symcc 🟢 6845/7329 93.40% 93.42%
cedar-wasm 🔴 0/28 0.00% 0.00%

@github-actions

Copy link
Copy Markdown

Coverage Report

Head Commit: 8b682e1bb375a296fc4cf4e483d87416e2a66bb7

Base Commit: feb3e1dcb8c7064b1bfc5293e53d362228d2bc54

Download the full coverage report.

Coverage of Added or Modified Lines of Rust Code

Required coverage: 80.00%

Actual coverage: 82.35%

Status: PASSED ✅

Details
File Status Covered Coverage Missed Lines
cedar-policy-symcc/src/symcc/env.rs 🟢 12/15 80.00% 446-448
cedar-policy-symcc/src/symcc/interpretation.rs 🟢 1/1 100.00%
cedar-policy-symcc/src/symcc/symbolizer.rs 🟢 1/1 100.00%

Coverage of All Lines of Rust Code

Required coverage: 80.00%

Actual coverage: 88.23%

Status: PASSED ✅

Details
Package Status Covered Coverage Base Coverage
cedar-language-server 🟢 4722/5102 92.55% 92.55%
cedar-policy 🟢 4643/5758 80.64% 80.64%
cedar-policy-cli 🟡 1271/1648 77.12% 77.12%
cedar-policy-core 🟢 24746/27945 88.55% 88.55%
cedar-policy-formatter 🟢 914/1088 84.01% 84.01%
cedar-policy-symcc 🟢 6845/7329 93.40% 93.42%
cedar-wasm 🔴 0/28 0.00% 0.00%

SymEntities reverted to a plain BTreeMap wrapper — the Arc now lives
on SymEnv.entities and SymSchema.entities, keeping SymEntities a value
type while preserving cheap Arc-clone sharing in SymSchema::sym_env().

Signed-off-by: Thomas Hill <thill@cloudflare.com>
@github-actions

Copy link
Copy Markdown

Coverage Report

Head Commit: c9076e0d13a1105875497b2e03c4dbcbfbb76d67

Base Commit: feb3e1dcb8c7064b1bfc5293e53d362228d2bc54

Download the full coverage report.

Coverage of Added or Modified Lines of Rust Code

Required coverage: 80.00%

Actual coverage: 81.25%

Status: PASSED ✅

Details
File Status Covered Coverage Missed Lines
cedar-policy-symcc/src/symcc/env.rs 🟡 11/14 78.57% 446-448
cedar-policy-symcc/src/symcc/interpretation.rs 🟢 1/1 100.00%
cedar-policy-symcc/src/symcc/symbolizer.rs 🟢 1/1 100.00%

Coverage of All Lines of Rust Code

Required coverage: 80.00%

Actual coverage: 88.23%

Status: PASSED ✅

Details
Package Status Covered Coverage Base Coverage
cedar-language-server 🟢 4722/5102 92.55% 92.55%
cedar-policy 🟢 4643/5758 80.64% 80.64%
cedar-policy-cli 🟡 1271/1648 77.12% 77.12%
cedar-policy-core 🟢 24746/27945 88.55% 88.55%
cedar-policy-formatter 🟢 914/1088 84.01% 84.01%
cedar-policy-symcc 🟢 6842/7326 93.39% 93.42%
cedar-wasm 🔴 0/28 0.00% 0.00%

@lianah

lianah commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Looks good to me! I wonder if we want to eventually update the CompiledPolicy/CompiledPolicySet::compile API or add a new top level API to take a SymSchema to avoid the duplicate work and memory.

@john-h-kastner-aws john-h-kastner-aws self-requested a review July 15, 2026 21:30

@john-h-kastner-aws john-h-kastner-aws left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

approving with a comment on naming. No specific better name in mind, but probably worth a bit of thought.

I wonder if we want to eventually update the CompiledPolicy/CompiledPolicySet::compile API or add a new top level API to take a SymSchema to avoid the duplicate work and memory.

I think we should. Probably change CompiledPolicySet::compile to accept the new SymSchema, and leaving CompiledPolicySet::compile_with_custom_symenv as the escape hatch in case that doesn't work for some use case.

For that we'd want to update the Lean model to match, but it should be trivial.

/// [`SymSchema::sym_env`], which is significantly cheaper than rebuilding the
/// symbolic entities per environment (as [`SymEnv::new`] does).
#[derive(Debug, Clone)]
pub struct SymSchema {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure that SymSchema is the best name here since the schema isn't symbolic, the entities are. Would CompiledSchema be better? I don't know that it actually makes more sense, but we have "compiled" the schema into SymEntities. Any thoughts @lianah ?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think CompiledSchema sounds good. Also, it's similar to CompiledPolicy which follows a similar pattern and contains the type checked policy + the symbolic representation of the policy.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since Liana's agrees, @tomlikestorock , can you do the rename?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh sure, no problem

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants