Skip to content

TPE: reduce has/hasTag/==/in/is using schema type information - #2503

Open
john-h-kastner-aws wants to merge 4 commits into
mainfrom
tpe-reduce-has-hastag-false
Open

TPE: reduce has/hasTag/==/in/is using schema type information#2503
john-h-kastner-aws wants to merge 4 commits into
mainfrom
tpe-reduce-has-hastag-false

Conversation

@john-h-kastner-aws

Copy link
Copy Markdown
Contributor

Description of changes

Fixes #2500

Lean model and proofs in cedar-policy/cedar-spec#997

Issue #, if available

Checklist for requesting a review

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

  • A breaking change requiring a major version bump to cedar-policy (e.g., changes to the signature of an existing API).
  • A backwards-compatible change requiring a minor version bump to cedar-policy (e.g., addition of a new API).
  • A bug fix or other functionality change requiring a patch to cedar-policy.
  • A change "invisible" to users (e.g., documentation, changes to "internal" crates like cedar-policy-core, cedar-validator, etc.)
  • A change (breaking or otherwise) that only impacts unreleased or experimental code.

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).
  • Does not update the CHANGELOG because my change does not significantly impact released code.

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.
  • Requires updates, and I have made / will make these updates myself. (Please include in your description a timeline or link to the relevant PR in cedar-spec, and how you have tested that your updates are correct.)
  • Requires updates, but I do not plan to make them in the near future. (Make sure that your changes are hidden behind a feature flag to mark them as experimental.)
  • I'm not sure how my change impacts cedar-spec. (Post your PR anyways, and we'll discuss in the comments.)

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.
  • Requires updates, and I have made / will make these updates myself. (Please include in your description a timeline or link to the relevant PR in cedar-docs. PRs should be targeted at a staging-X.Y branch, not main.)
  • I'm not sure how my change impacts the documentation. (Post your PR anyways, and we'll discuss in the comments.)

Signed-off-by: jkastner <jkastner@amazon.com>
@john-h-kastner-aws
john-h-kastner-aws requested a review from luxas July 29, 2026 19:45
@github-actions

Copy link
Copy Markdown

Coverage Report

Head Commit: 1122502d04b7c6113ea4a4f609e7e064c8f70c0d

Base Commit: 64c925c4a9760a4f8bfdd4814e3b02371b57292a

Download the full coverage report.

Coverage of Added or Modified Lines of Rust Code

Required coverage: 80.00%

Actual coverage: 96.00%

Status: PASSED ✅

Details
File Status Covered Coverage Missed Lines
cedar-policy-core/src/batched_evaluator.rs 🟢 2/2 100.00%
cedar-policy-core/src/tpe.rs 🟢 1/1 100.00%
cedar-policy-core/src/tpe/evaluator.rs 🟢 23/25 92.00% 223, 262
cedar-policy-core/src/validator/schema.rs 🟢 16/16 100.00%
cedar-policy-core/src/validator/typecheck.rs 🟢 6/6 100.00%
cedar-policy-core/src/validator/types.rs 🟢 24/25 96.00% 506

Coverage of All Lines of Rust Code

Required coverage: 80.00%

Actual coverage: 88.38%

Status: PASSED ✅

Details
Package Status Covered Coverage Base Coverage
cedar-language-server 🟢 4722/5102 92.55% --
cedar-policy 🟢 4844/5950 81.41% --
cedar-policy-cli 🟡 1294/1669 77.53% --
cedar-policy-core 🟢 24703/27865 88.65% --
cedar-policy-formatter 🟢 914/1088 84.01% --
cedar-policy-symcc 🟢 6916/7396 93.51% --
cedar-wasm 🔴 0/28 0.00% --

Signed-off-by: jkastner <jkastner@amazon.com>
@github-actions

Copy link
Copy Markdown

Coverage Report

Head Commit: 2b7972d83a9b79ee38d978c9cb3a8a4c19488041

Base Commit: 64c925c4a9760a4f8bfdd4814e3b02371b57292a

Download the full coverage report.

Coverage of Added or Modified Lines of Rust Code

Required coverage: 80.00%

Actual coverage: 96.00%

Status: PASSED ✅

Details
File Status Covered Coverage Missed Lines
cedar-policy-core/src/batched_evaluator.rs 🟢 2/2 100.00%
cedar-policy-core/src/tpe.rs 🟢 1/1 100.00%
cedar-policy-core/src/tpe/evaluator.rs 🟢 23/25 92.00% 223, 262
cedar-policy-core/src/validator/schema.rs 🟢 16/16 100.00%
cedar-policy-core/src/validator/typecheck.rs 🟢 6/6 100.00%
cedar-policy-core/src/validator/types.rs 🟢 24/25 96.00% 506

Coverage of All Lines of Rust Code

Required coverage: 80.00%

Actual coverage: 88.39%

Status: PASSED ✅

Details
Package Status Covered Coverage Base Coverage
cedar-language-server 🟢 4722/5102 92.55% --
cedar-policy 🟢 4844/5950 81.41% --
cedar-policy-cli 🟡 1294/1669 77.53% --
cedar-policy-core 🟢 24706/27865 88.66% --
cedar-policy-formatter 🟢 914/1088 84.01% --
cedar-policy-symcc 🟢 6916/7396 93.51% --
cedar-wasm 🔴 0/28 0.00% --

@luxas luxas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks for the PR!

I should have time pretty soon to resume the possible_bool_outcomes feature and I could also rename can_error_assuming_well_formed as we discussed earlier.
I'll take a look at the cedar-spec change next.

Comment thread cedar-policy-core/src/tpe/evaluator.rs
ResidualKind::BinaryApp { op, arg1, arg2 } => {
let arg1 = self.interpret(arg1);
let arg2 = self.interpret(arg2);
let must_be_false = match op {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This starts looking a lot like the abstract interpretation I was planning in #2122

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.

I think the difference is that here we determine that it must be a single value, allowing us to reduce to a concrete value instead of a residual. For #2122, we'll still be carrying around a residual so we can materialize the specific value of we need to

_ => false,
};
if must_be_false
&& !arg1.can_error_assuming_well_formed()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

One optimization that comes to mind here, would be to not interpret arg1 and arg2, but just check their can_error_assuming_well_formed in the original form, to potentially save some time.

It came to mind now, so I'll ponder about the soundness a bit more, but especially if I rename this to is_error_free_assuming_well_typed or similar, I believe it should be such that if the residual was error-free before interpretation (which is what we care about), then it necessarily also has to be error-free after interpretation (and thus interpretation is unnecessary if we can deduce this).

In other words, is_error_free_assuming_well_typed should be monotonic. This would be a pretty good theorem to add to the Lean code, unless we already have it.

@john-h-kastner-aws john-h-kastner-aws Aug 6, 2026

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.

There's a trade off here: partial evaluation should very often give us back an error free expression where we didn't have one before. So, by checking on the residual we get to apply the reduction in more cases.

I suppose we could check it before and after reduction if that's a meaningful optimization.

@john-h-kastner-aws john-h-kastner-aws Aug 6, 2026

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.

The monotonicity theorem, I think there would be something new to prove

We have (omitting welltypedness hypothesis)

  • ∀ r req es, r.ErrorFree → (r.evaluate req es).isOk
  • ∀ r req es, (r.evaluate req es).toOption = ((TPE.evaluate r preq pes).evaluate req es).toOption

Given r.ErrorFree, we know ∀ r req es, ((TPE.evaluate r preq pes).evaluate req es).isOk. But ErrorFree isn't complete, so we'd need to show that ErrorFree actually holds for it.

Really, what we care about is the isOk result. That's what makes the reduction sound, so I don't think adding this theorem is particularly useful, but it could be fun if you want to try it out.

Comment thread cedar-policy-core/src/tpe/evaluator.rs
Comment thread cedar-policy-core/src/tpe/evaluator.rs Outdated
Comment thread cedar-policy-core/src/validator/types.rs Outdated
Comment thread cedar-policy-core/src/validator/typecheck.rs
Comment thread cedar-policy-core/src/tpe/evaluator.rs
Comment thread cedar-policy-core/src/tpe/evaluator.rs
} else if let Ok(uid) = value.get_as_entity() {
match self.entities.get_attrs(uid) {
Some(attrs) => mk_concrete(attrs.contains_key(attr).into()),
None => mk_residual(ResidualKind::HasAttr {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Add a comment here to follow-up on resolving the presence or non-presence of required attributes from the schema?

@"false"
);
assert_snapshot!(
interpret_typed_str_to_str(r#"E::"none_tags".hasTag("s") && E::"none_tags".getTag("s") == "bar" "#),

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.

@luxas This demonstrates the && case for typechecking I commented on above.

E::"none_tags".hasTag("s") has type False, so we skip the RHS. The typechecker won't reduce it to false (due to error semantics, but also that's probably not the expected behavior for a typecheker), so we're left with the LHS, dropping the && RHS

Co-authored-by: Lucas Käldström <luxas@users.noreply.github.com>
@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown

Coverage Report

Head Commit: c5629406704acbec8958d4a1a34a48a117bdf678

Base Commit: 64c925c4a9760a4f8bfdd4814e3b02371b57292a

Download the full coverage report.

Coverage of Added or Modified Lines of Rust Code

Required coverage: 80.00%

Actual coverage: 96.00%

Status: PASSED ✅

Details
File Status Covered Coverage Missed Lines
cedar-policy-core/src/batched_evaluator.rs 🟢 2/2 100.00%
cedar-policy-core/src/tpe.rs 🟢 1/1 100.00%
cedar-policy-core/src/tpe/evaluator.rs 🟢 23/25 92.00% 223, 262
cedar-policy-core/src/validator/schema.rs 🟢 16/16 100.00%
cedar-policy-core/src/validator/typecheck.rs 🟢 6/6 100.00%
cedar-policy-core/src/validator/types.rs 🟢 24/25 96.00% 506

Coverage of All Lines of Rust Code

Required coverage: 80.00%

Actual coverage: 88.39%

Status: PASSED ✅

Details
Package Status Covered Coverage Base Coverage
cedar-language-server 🟢 4722/5102 92.55% --
cedar-policy 🟢 4844/5950 81.41% --
cedar-policy-cli 🟡 1294/1669 77.53% --
cedar-policy-core 🟢 24706/27865 88.66% --
cedar-policy-formatter 🟢 914/1088 84.01% --
cedar-policy-symcc 🟢 6916/7396 93.51% --
cedar-wasm 🔴 0/28 0.00% --

Signed-off-by: jkastner <jkastner@amazon.com>
@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown

Coverage Report

Head Commit: 2f139015cc2910bfa245038b3896c59da6328ca9

Base Commit: 64c925c4a9760a4f8bfdd4814e3b02371b57292a

Download the full coverage report.

Coverage of Added or Modified Lines of Rust Code

Required coverage: 80.00%

Actual coverage: 95.95%

Status: PASSED ✅

Details
File Status Covered Coverage Missed Lines
cedar-policy-core/src/batched_evaluator.rs 🟢 2/2 100.00%
cedar-policy-core/src/tpe.rs 🟢 1/1 100.00%
cedar-policy-core/src/tpe/evaluator.rs 🟢 23/25 92.00% 223, 262
cedar-policy-core/src/validator/schema.rs 🟢 16/16 100.00%
cedar-policy-core/src/validator/typecheck.rs 🟢 6/6 100.00%
cedar-policy-core/src/validator/types.rs 🟢 23/24 95.83% 505

Coverage of All Lines of Rust Code

Required coverage: 80.00%

Actual coverage: 88.39%

Status: PASSED ✅

Details
Package Status Covered Coverage Base Coverage
cedar-language-server 🟢 4722/5102 92.55% --
cedar-policy 🟢 4844/5950 81.41% --
cedar-policy-cli 🟡 1294/1669 77.53% --
cedar-policy-core 🟢 24705/27864 88.66% --
cedar-policy-formatter 🟢 914/1088 84.01% --
cedar-policy-symcc 🟢 6916/7396 93.51% --
cedar-wasm 🔴 0/28 0.00% --

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.

TPE Fails to Eliminate Irrelevant Policies

2 participants