Skip to content

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!

Putting everything together