Understanding Policy¶
So far, you’ve been building pipelines and boundaries — defining what data should look like and how it should be transformed. That’s the structural layer of Jane. Policy is the behavioral layer.
Policy controls how Jane interprets validation outcomes, how strict it should be, what gets reported, and what gets rejected. It determines whether something is an error or a warning, whether validation should stop early or continue, and what analysis features should run. If pipelines define rules, policy defines intent.
This chapter explains how policy works, how to apply it at both the pipeline and boundary levels, and how all policy features fit together into a predictable mental model.
What Is Policy?¶
A policy is a declarative configuration that answers questions like:
- Should this validation be strict or forgiving?
- Which issues should fail the pipeline?
- Which issues should only be reviewed or warned?
- Should analysis features like diff, explain, or telemetry run?
- How should results be shaped and reported?
Policy never validates data directly. Instead, it governs the behavior of validation.
Every Jane execution runs with an effective policy, resolved from:
- Default policy
- Jane-level policy
- Boundary-level policy
- Pipeline-level overrides
- Policy always flows downward and becomes more specific as you go.
- Policy Scopes
Jane supports policy at two distinct scopes:
-
Pipeline Policy:
Applied to a single pipeline:
ts jane .value(input.age) .lax() .parse('numeric') .positive()Pipeline policy affects only that pipeline.
-
Boundary Policy
Applied to an entire object:
ts await jane.strictBoundary({ name: jane.value(input.name).string(), age: jane.value(input.age).parse('numeric'), });
Boundary policy applies to all pipelines inside the boundary, unless a pipeline explicitly overrides it.
Policy Modes: Strict, Moderate, Lax¶
The most important policy concept is mode. Mode controls how Jane interprets validation events.
Strict Mode¶
jane.strict()
jane.strictBoundary({...})
- Warnings become errors.
- Any issue fails the pipeline or boundary.
Best for:
- Security
- Configuration
- Internal invariants
Moderate Mode (Default)¶
jane.value(...)
jane.boundary({...})
- Errors fail
- Warnings are reported but allowed
Best for:
- APIs
- User input
- Most applications
Lax Mode¶
jane.lax()
jane.laxBoundary({...})
- Only fatal issues fail.
- Everything else is reported.
Best for:
- Observability
- Gradual enforcement
- Legacy systems
Mode is the foundation of policy. Everything else builds on top of it.
Applying Policy to Pipelines¶
Pipeline policy is applied fluently:
const result = await jane
.value(input.email)
.lax()
.nonEmpty()
.isEmail()
.run();
This pipeline:
- Runs in lax mode.
- Reports issues.
- Does not fail unless a fatal error occurs.
Pipeline-level policy is ideal when:
- One field needs special handling.
- You want to relax or tighten validation locally.
- You want analysis features for a specific value.
Naming Pipelines¶
Naming improves observability:
jane
.value(input.age)
.named("user.age")
.parse('numeric')
.positive()
Names appear in events, telemetry, and analysis output.
Applying Policy to Boundaries¶
Boundary policy defines shared behavior across fields.
const result = await jane.strictBoundary({
name: jane.value(input.name).string().nonEmpty(),
age: jane.value(input.age).parse('numeric').positive(),
});
This guarantees:
- Consistent mode across fields.
- Unified analysis behavior.
- Predictable results.
Boundary policy is the right place to enforce consistency.
Analysis Features (Policy-Driven)¶
Analysis features are opt-in and policy-controlled.
Diff¶
jane.withDiff()
Records how values changed through the pipeline.
Explain¶
jane.withExplain()
Explains why a value passed or failed.
Replay¶
jane.withReplay()
Records each pipeline stage for debugging.
Telemetry¶
jane.withTelemetry((records) => {
sendToObservability(records);
});
Telemetry emits structured events suitable for logging, metrics, and tracing.
These features can be enabled at:
- Pipeline level
- Boundary level
Policy determines whether they actually run.
Severity Mapping¶
Not all issues are equal. Policy lets you redefine severity:
jane.severity({
'validate.nonEmpty.failed': 'warn',
'parse.numericString.invalid': 'error',
});
This allows:
- Gradual enforcement.
- Backward compatibility.
- Business-specific interpretation.
Severity mapping works at both pipeline and boundary levels.
Reject, Review, and Warn¶
Policy supports pattern-based classification:
jane.reject('parse.*')
jane.review('validate.*')
jane.warn('scan.*')
These controls allow you to say:
- These issues must fail.
- These issues require review.
- These are informational.
This is especially powerful for:
- API versioning
- Deprecation paths
- Soft launches
- Boundary-Specific Policy Features
Boundaries introduce additional policy controls:
-
Accept Modes:
jane.boundaryAccept('all')Controls how field results are aggregated:
-
all: All fields must pass. any: At least one field must pass.strict: No issues allowed.-
partial: Allow partial success. -
Value Handling:
ts jane.boundaryIncludeRejected() jane.boundaryIncludeUndefined()Controls what appears in the final output object.
-
Boundary Transforms:
ts jane.boundaryTransform((values) => ({ ...values, fullName: `${values.first} ${values.last}` }));Allows final shaping of boundary output.
How Policy Is Resolved¶
When you run a pipeline or boundary:
- Default policy is applied
- Jane-level policy is merged
- Boundary-level policy is merged
- Pipeline-level policy overrides last
This resolution is:
- Predictable
- Explicit
- Immutable
You never need to guess which policy is active.
Using Policy in Real Applications¶
- API Validation: Use moderate boundaries with selective strict pipelines.
- Configuration Validation: Use strict boundaries with reject rules.
- Observability & Telemetry: Use lax mode with telemetry enabled.
- Migration & Legacy Data: Use severity mapping and review rules. Policy lets Jane adapt to real systems, not idealized ones.
What You’ve Learned¶
You now understand:
- What policy is and why it exists.
- How policy scopes work.
- How mode affects behavior.
- How to apply policy to pipelines and boundaries.
- How analysis and severity are policy-driven.
- How Jane resolves effective policy.
- Policy is what turns Jane from a validator into a decision engine.
Next, we’ll put everything together in a real-world example. Let's build something!