Type a journey's terminal assertion as a boolean over observables; a derived strength gates it.

Journey task-closure (type the terminal post-condition, derive its strength)

Intent — Type a journey's terminal post-condition as a boolean expression over reusable, accessibility-observable leaf-predicates, derive a closure-strength verdict from the expression, and hold that every major journey derives TASK_CLOSED — so a journey test can no longer green while the user's task is broken (our instance: a typed closure block on the Journey entity whose leaves subclass a standard predicate library, from which a pure function derives TASK_CLOSED / FLOW_ONLY / DISABLED).

SummaryType a journey's terminal assertion as a boolean over observables; a derived strength gates it.
TargetBridge · System models
Formvalidation
Movepackage — a constraint shipped with its sensors
Modelgoverns-a-model — a gate/generator/API/policy whose subject is a model
EnforcementSoft·Hard — the typed closure aims the terminal assertion (soft: it declares what DONE means, a human still writes the spec); a strength-derivation gate holds the floor (hard: a major journey deriving FLOW_ONLY fails)
Governsuser-journey-model — a journey's terminal post-condition, typed

Its place in the environment — a variant / known-use of Model-Derived Assurance Coverage, under COMPLETE · Establish completion on re-derived evidence. Preserved here for its technical texture; the construction kit shows how it folds.

Motivation — the failure it kills

A journey test usually asserts that the flow ran — a page returned 200, a URL was reached, a card appeared — not that the task closed — the artifact the user came for is present, valid, and operable. The two are one hop apart, and that hop is where a real production break hid.

Picture the gap concretely. A user opens a sample document in the editor; the navigation to the editor route succeeds and the test asserts exactly that; then the client fetches the accessibility view and the fetch fails, so the view the user came to inspect never paints. The terminal assertion stopped at "the URL loaded." The spec passes against broken production. Call it the flow-vs-task gap: a green terminal assertion sitting one hop short of the user's goal.

The gap survives because "what works means at journey end" lives as prose in a review checklist. Prose cannot be checked against the spec's real assertion, so a spec that asserts only the flow satisfies the template while its code never reaches the task. The failure is a terminal assertion trusted to mean more than it checks.

Why it's not just a BDD Then clause (or the coverage floor, or "write a strong assertion")

The idea that a test should assert an outcome is old. What is new is typing that outcome as a machine-resolvable boolean, deriving a strength verdict from it, and gating the verdict. Each adjacent practice stops one step short:

The distinct move: type the post-condition, derive its strength, gate the verdict. It is the derive-a-verdict-from-a-model-trait reflex and the audit-becomes-a-lint reflex, applied to the meaning of the terminal assertion.

Mechanism

Four parts sit on the structured journey model.

A set of lints forward-police the discipline — that every major journey declares a closure, that each leaf subclasses the library rather than a one-off predicate, that the expression is well-formed and its derived strength surfaced, and that each leaf binds to an observable that actually exists in the served UI. They land audit-only first, since journeys not yet migrated derive FLOW_ONLY, then promote to blocking once the backlog drains.

Prerequisites

Consequences & costs

Capability beyond governance — one closure, two resolvers

Because the closure is typed, the same definition resolves two ways. Locally it drives a browser assertion in the fast tier. Before promotion it drives a headless probe against the deployed canary — the leaves that resolve over HTTP or a delivered file are checked against the pre-promotion revision directly, without rebuilding the browser suite on the deploy host.

That reuse closes a containment hole. A fast post-deploy battery checks page integrity — a route renders, no console error, no overflow — but never task closure, so a break that appears only under the deployed configuration is invisible to a local-only assertion. Resolving each major journey's typed closure against the canary restores "staging catches anything local catches" for the task dimension. Convention alone could not do this: the typed closure is the single artifact both resolvers read.

Known uses

Related mechanisms