Skip to content

Boundary rule catalog

Boundary rules are opt‑in, declarative constraints that operate at the shape level, after individual fields have been scanned, normalized, parsed, and validated.

They answer a different question than validators: Given all accepted fields, does the overall shape make sense? Boundary rules enforce structural, relational, and cross‑field constraints that cannot be expressed at the field level.

Boundary rules:

  • Never run automatically.
  • Never mutate values.
  • Never validate individual fields.
  • Never parse or normalize.
  • Emit boundary‑level events.
  • Run after all field decisions are known.
  • Operate on the final values of fields.
  • Can produce multiple issues in a single pass.

Boundary rules are the final gate before a boundary is accepted.

How Boundary Rules Work

  • Field‑level work completes first: Scanning, normalization, parsing, and validation all run before boundary rules. Each field now has a final value and a decision (accept, reject, and so on).
  • Boundary rules receive the full field map: Each rule is passed { fields }, where each entry contains:
  • The final value.
  • The decision.
  • The events emitted so far.
  • Rules inspect relationships between fields:
  • Presence or absence.
  • Mutual exclusivity.
  • Conditional requirements.
  • Chronological ordering.
  • Structural constraints.
  • Unknown keys.
  • Rules emit boundary‑level events: These events describe shape‑level issues, not field‑level ones.
  • Policy interprets boundary events. Policy decides whether boundary issues:
  • Reject the boundary
  • Downgrade to warnings
  • Trigger review

Boundary rules never decide acceptance on their own.

Boundary Rule Categories

Boundary rules are grouped by the type of structural constraint they enforce.

Each section includes:

  • A description of the rule category.
  • The rules in that category.
  • Cross‑links to related validators and parsers.

This helps developers understand how boundary rules fit into the full pipeline.

Presence Rules

Presence rules ensure that required fields appear — or that optional fields appear only under certain conditions.

requireAll

  • All listed fields must be present and accepted.
  • Missing or rejected fields each produce an error.

requireOne

  • At least one of the listed fields must be accepted.
  • Emits a single error if none are present.

conditionallyRequired

  • When a controlling field matches a specific value, additional fields become required.
  • Emits one error per missing field.

Exclusivity Rules

Exclusivity rules ensure that certain fields cannot appear together.

mutuallyExclusive

  • Fields a and b cannot both be accepted.
  • Emits a single conflict error.

atMostOne

  • No more than one of the listed fields may be accepted.
  • Emits one error if multiple appear.

Structural Rules

Structural rules enforce shape‑level constraints that go beyond simple presence or exclusivity.

noUnknownFields

  • Any field not listed is treated as unknown.
  • Emits one error per unknown key.

dateRange

  • Ensures startDate occurs before endDate.
  • Emits a single chronological‑ordering error.

Example: Mutually Exclusive Rule

export function mutuallyExclusive(a: string, b: string): BoundaryRule {
    return ({ fields }) => {
        const ra = fields[a];
        const rb = fields[b];

        if (ra?.decision?.code === "accept" &&
            rb?.decision?.code === "accept") {
            const ev: JaneEvent = {
                phase: "decide",
                kind: "error",
                code: "boundary.does.mutual-exclusion",
                message: `Fields "${a}" and "${b}" cannot both be present`,
                path: rootPath(),
            };

            return { events: [ev], issues: [ev] };
        }

        return { events: [], issues: [] };
    };
}

This illustrates the boundary‑rule contract:

  • Inspect final field decisions.
  • Evaluate cross‑field relationships.
  • Emit structured boundary events.
  • Never mutate values.
  • Never override field‑level decisions.

Summary

Boundary rules are the final structural enforcement stage of the Jane pipeline. They ensure that the shape of the data — not just individual fields — is valid.

Boundary rules are:

  • Opt‑in: Nothing runs unless you call .boundary().
  • Declarative: You describe relationships, not mechanics.
  • Pure: No mutation, no coercion.
  • Event‑emitting: Every issue is recorded.
  • Policy‑interpreted: Boundary rules never reject on their own.

Boundary rules are where the full shape becomes meaningful — explicitly, predictably, and transparently.