Skip to content

Boundary

Bringing multiple fields together into one coherent decision.

A boundary is where individual pipelines stop being isolated checks and start becoming a meaningful whole. It’s the layer that lets you validate an entire object — not just one field at a time — and decide whether the combined result is acceptable.

Boundaries don’t validate values themselves; they aggregate, shape, and interpret the results of multiple pipelines. If the pipeline is the unit of work, the boundary is the unit of meaning.

Why Boundaries Exist

Most real data structures aren’t single values. They’re objects:

{
  name: "Alice",
  age: "42",
  email: "alice@example.com"
}

Each field has its own pipeline:

  • name → string → nonEmpty.
  • age → numericString → number → positive.
  • email → string → isEmail.

But the object also has meaning:

  • Should we accept it if one field fails?
  • Should we include rejected fields in the final output?
  • Should we include undefined fields?
  • Should we hide certain issues?
  • Should we escalate certain issues?
  • Should we apply a final transformation?

A boundary answers these questions. It’s the whole object decision-maker.

What a Boundary Does

A boundary performs four jobs:

  1. Aggregate field results

    It collects:

    • Each field’s final value
    • Each field’s events
    • Each field’s issues
    • Each field’s metadata

    This gives the boundary a complete picture of what happened.

  2. Shape values

    Boundaries can control how the final object looks:

    • Include only accepted fields.
    • Include rejected fields too.
    • Include undefined keys.
    • Apply a final transform.

    This lets you tailor the output to your use case.

  3. Shape metadata

    Boundaries can include or exclude:

    • Timestamps.
    • runId.
    • Per-field metadata.

    This is especially useful for privacy-sensitive contexts.

  4. Make a final decision

Boundaries decide whether the entire object is:

  • Accepted
  • Rejected
  • Requires review

This decision is based on:

  • Shaped events.
  • Shaped issues.
  • Reject/review patterns.
  • Acceptance mode.

Acceptance Modes

Boundaries support four acceptance strategies:

  • all (default): All fields must be accepted, and there must be no issues.
  • partial: Reject only if a reject-pattern or fatal event appears.
  • any: Accept if at least one field is accepted.
  • strict: Reject if any issue or review condition appears.

These modes let you tune strictness without rewriting pipelines.

Boundary-Level Policy

Boundaries can override or extend pipeline-level policy:

  • Ignore certain event codes.
  • Hide events from the final output.
  • Hide issues from the final output.
  • Override severity.
  • Escalate severity.
  • Reject patterns.
  • Review patterns.

This gives you fine-grained control over how the object as a whole is evaluated.

Pipeline-level policy handles individual fields. Boundary-level policy handles the entire structure.

What Boundaries Never Do

Boundaries are intentionally limited. They do not:

  • Run scan.
  • Run normalization.
  • Run parsing.
  • Run validation.
  • Mutate field pipelines.
  • Change event codes.
  • Coerce values.

Boundaries only shape and interpret the results of pipelines. They never alter what happened — only what it means.

Why Boundaries Matter

Boundaries are the layer that makes Jane feel like a real data boundary framework rather than a collection of validators:

  • They aggregate
  • They shape
  • They interpret
  • They decide

They let you treat an entire object as a single unit of meaning, with predictable behavior and clean separation of concerns.