The Graph Query backend outputs the SPDG in a format that is understood by the paralegal-policy
framework. Policies are written as Rust programs running graph traversals and queries on the SPDG using this framework. This engine tends to be much faster than the Forge backend. It is also easier to get started with, as only a familiarity with Rust is required. It also requires no additional setup and running a policy can be a simple cargo run
command. This backend is however lower-level than Forge and we are actively working on a Paralegal specific DSL on top of it.
The low level query API paralegal-policy
is a Rust library. For most up-to-date information you should consult it’s rustdocs, available online at
The primary API is Context
, which offers partially index-memoized convenience queries. For some information you may have to access the raw graph (ProgramDescription
), accessible via Context::desc()
.
paralegal_policy::diagnostics - Rust
Policies communicate with the user in a similar mechanism as used by rustc: Diagnostics. Diagnostics are messages of varying severity that are emitted to the user. In Rust failure is typically handled with Result
or panicking, which are “fail fast” approaches. Diagnostics on the other hand are a “fail slow” approach that tries to execute as much of the policy as possible to try an provide comprehensive feedback to the user. Instead of aborting upon encountering a failure, your policy should emit a message and then resume execution from the last non-failure state. Diagnostics are emitted with Context::emit_diagnostics
, but most setups won’t need to call this as GraphLocation::with_context
does so automatically.
Two levels of severity are currently available to policy implementors:
error
represents a state that necessitates a policy failurewarning
represents an unusual state that may warrant investigation by the user, but odes not fail the policy outrightThe trait Diagnostics
defines analogous methods for emitting such messages. It is implemented for Context
.
You can also use the assert!
-style macros assert_error!
and assert_warning!
which take a context, a condition required to hold and an optional message.
In addition, our diagnostics mechanism allows the policy writer to programmatically accumulate additional context about where a message originates. The PolicyContext
, CombinatorContext
and ControllerContext
structs wrap Context
, overriding the error
and warning
methods to attach information about the current policy, combinator or controller respectively. They implement Deref
to Context
, so you can treat them the same as Context
. They are created with named_policy
, named_combinator
and named_controller
(or all_controllers
) respectively.
As an example, this policy:
ctx.named_policy("cannot escape", |ctx| {
let result_1 = ctx.named_combinator("collect something", |ctx| {
/* actual computation */
assert_error!(ctx, 1 + 2 == 4, "Oh oh, fail!");
true
});
would emit
[policy: cannot escape] [collect something] Oh oh, fail!