Policy Guidance
This guide is the package-facing decision layer for two operational choices:
Policy Guidance
- when to prefer
strict: trueversusstrict: false - how to choose
lateArrivalPolicyfor streaming workloads
It is not trying to restate every semantic detail from the deeper guides. It is trying to answer the practical question:
- what is the safer default for this workload?
The Short Version
Use strict: false when you need the library to keep moving and surface problems as structured anomalies.
Use strict: true when invalid or unresolved ordering should stop the workflow immediately rather than become provisional output.
One mental model helps:
strictis the main fail-fast switch for ordering and validationallowUnknownOrderis the uncertainty-visibility control layered on top of non-strict outputdetectAnomaliesis a diagnostic-output control, not a correctness mode
Translation fail-fast behavior is still configured separately through translateBatch() policy.
For streaming late arrivals:
- use
flagwhen you want to keep delayed events visible without triggering correction output - use
dropwhen late events should not enter the emitted stream but still need anomaly visibility - use
emit_correctionwhen previously emitted non-final output may need reconciliation - use
failwhen a late arrival should be treated as an operational contract violation
Choosing strict
Prefer strict: false when
- you are exploring or debugging mixed real-world data
- you want anomalies recorded instead of the whole batch or stream aborting
- upstream quality is uneven and you still need a bounded operational answer
- you are evaluating the library on realistic messy inputs
Typical shape:
import { orderEvents, translateBatch } from "causal-order"
const translated = translateBatch(records, config)
const result = orderEvents(translated.translated, {
strict: false,
detectAnomalies: true,
})
What this buys you:
- invalid records can still be surfaced as anomalies instead of crashing the whole run
- unresolved ordering can still be written deterministically with warnings
- the anomaly stream stays part of the operational answer
- translation ingress policy can still be tightened independently if you need fail-fast onboarding before ordering
Prefer strict: true when
- audit and compliance pipelines should stop rather than publish uncertain output
- financial or regulated processing requires fail-fast behavior
- CI and fixture verification should reject invalid or unresolved ordering immediately
- upstream data-quality enforcement matters more than partial output
- producer debugging and contract testing should catch bad input as early as possible
Typical shape:
import { orderEvents } from "causal-order"
const result = orderEvents(events, {
strict: true,
detectAnomalies: true,
})
What this buys you:
- invalid input does not quietly become a provisional answer
- dependency cycles and other unresolved cases stop the run
- mistakes are found earlier in pipelines that are supposed to be contract-clean
Choosing lateArrivalPolicy
lateArrivalPolicy only matters for orderEventStream().
It is about what to do when an event arrives after the active watermark boundary.
flag
Use flag when:
- you want late events to stay visible in emitted output
- you do not want correction metadata or reconciliation flow
- delayed events are normal and downstream consumers can tolerate them as late-but-visible output
Typical shape:
import { orderEventStream } from "causal-order"
for await (const batch of orderEventStream(source(), {
batchSize: 100,
maxLateArrivalMs: 30_000n,
lateArrivalPolicy: "flag",
strict: false,
})) {
await applyBatch(batch)
}
Choose flag for:
- general observability pipelines
- operational monitoring where visibility matters more than correction flow
- reconnect cases where consumers can interpret late events directly
drop
Use drop when:
- late events should not enter the emitted ordered stream
- you still need anomaly visibility for those drops
- the downstream projection should stay narrow even when input is noisy
Choose drop for:
- real-time dashboards that should stay focused on current windows
- ephemeral alerting views
- projections where old late data is less useful than a clean current slice
Be careful:
- dropped late events are still important operationally
- if the delayed data matters for truth,
dropis probably the wrong choice
emit_correction
Use emit_correction when:
- late arrivals should remain visible
- previously emitted non-final output may need reconciliation
- reconnect-heavy or offline-sync flows are part of the real workload
Typical shape:
import {
ingestedAtWatermark,
orderEventStream,
} from "causal-order"
for await (const batch of orderEventStream(source(), {
batchSize: 500,
maxLateArrivalMs: 30_000n,
lateArrivalPolicy: "emit_correction",
watermark: ingestedAtWatermark,
strict: false,
})) {
await applyBatch(batch)
}
Choose emit_correction for:
- delayed reconnect flows
- offline sync recovery
- systems that keep publishing while one producer or region reconnects later
Be careful:
- non-final output must be treated as replaceable derived state
- this is an operational reconciliation signal, not proof of causal completeness
fail
Use fail when:
- a late arrival is a contract violation, not a recoverable condition
- downstream consumers should stop rather than reconcile
- the stream boundary is intentionally strict
Choose fail for:
- compliance or regulated streaming paths
- stream-based contract tests
- workloads where lateness itself means the data is operationally unacceptable
Practical Defaults
If you are unsure, start here:
- bounded batch replay, audit, or debugging:
strict: falsefirst, then tighten tostrict: trueonce the input contract is clean - producer contract tests or CI verification:
strict: true - ordinary continuous streaming:
lateArrivalPolicy: "flag"withstrict: false - reconnect-heavy or offline-sync streaming:
lateArrivalPolicy: "emit_correction"withstrict: false - regulated streaming where lateness is unacceptable:
lateArrivalPolicy: "fail"
One Rule To Keep
Do not choose a stricter setting just because it sounds safer in the abstract. Choose it when the surrounding workflow is actually prepared to stop, reject, or reconcile based on that signal.
The honest answer is:
strict: falseis often the safer operational default during exploration and recoverystrict: trueis often the safer governance default once the contract must be enforced