Routing
Oct 17, 2023198 min read
Navigation Covenants: Deep Dive #80
AV
Ariel Voss
Principal React Architect
Navigation covenants are continuous verifications that prevent UX drift.
This is the endcap of the #71–#80 arc: once you have choreography (#71/#76), evidence (#72/#77), rewind (#73/#78), and treaties (#74/#79), you still need one last thing — a guarantee that the system stays honest after the refactor, after the migration, and after the “tiny tweak”.
In practice, that means covenants that continuously verify:
- transcript rows stay paired (request/grant symmetry),
- focus posture is always present (rails never vanish),
- and switchback frames remain available after grants (rewind stays possible).
Treaties protect a single negotiation. Covenants protect the system across time.
Required docs links:
Extra docs links for this entry:
Covenant doctrine for navigation
- Checks run at render time.
- Results write to a covenant ledger.
- The covenant ledger is rendered into the DOM.
- Fail-forward posture: keep UI navigable and show evidence.
Worked Example: covenant verifier for nav transcript + focus rails
Step 1: Covenant rows
export type NavCovenantRow = {
at: number;
id: string;
ok: boolean;
reason?: string;
meta?: Record<string, unknown>;
};
Step 2: Shell verifier
import { useLiveState, useRenderEffect } from "react";
export function NavigationCovenantShell() {
const nav = useLiveState("nav.shell", {
surface: "file-router",
active: "file:/",
focusTarget: "main",
rows: [] as any[],
frames: [] as any[],
covenants: [] as NavCovenantRow[],
});
const covenants = [
{
id: "covenant.transcript.pairs",
check: () => {
const rows = nav.read("rows") ?? [];
const ok = Array.isArray(rows) && rows.length % 2 === 0;
if (!ok) {
return { ok: false, id: "covenant.transcript.pairs", reason: "odd-row-count" };
}
return { ok: true, id: "covenant.transcript.pairs", meta: { rows: rows.length } };
},
},
{
id: "covenant.focus.present",
check: () => {
const focus = nav.read("focusTarget");
const ok = typeof focus === "string" && focus.length > 0;
if (!ok) {
return { ok: false, id: "covenant.focus.present", reason: "missing-focus" };
}
return { ok: true, id: "covenant.focus.present", meta: { focus } };
},
},
{
id: "covenant.frames.array",
check: () => {
const frames = nav.read("frames") ?? [];
const ok = Array.isArray(frames);
if (!ok) {
return { ok: false, id: "covenant.frames.array", reason: "not-array" };
}
return { ok: true, id: "covenant.frames.array", meta: { count: frames.length } };
},
},
{
id: "covenant.surface.tagged",
check: () => {
const surface = nav.read("surface");
const ok = surface === "file-router" || surface === "component-router";
if (!ok) {
return { ok: false, id: "covenant.surface.tagged", reason: "unknown-surface" };
}
return { ok: true, id: "covenant.surface.tagged", meta: { surface } };
},
},
] as const;
useRenderEffect(() => {
const rows: NavCovenantRow[] = covenants.map((c) => {
const r = c.check();
return {
at: Date.now(),
id: r.id,
ok: r.ok,
reason: (r as any).reason,
meta: (r as any).meta,
};
});
nav.write("covenants", rows);
});
const covenantRows = nav.read("covenants") as NavCovenantRow[];
const failed = covenantRows.filter((r) => !r.ok);
return (
<section data-shell="nav-covenants" data-active={nav.read("active")}>
<h1>Navigation Covenants</h1>
<p className="text-sm text-[color:var(--docs-muted)]">
{failed.length === 0 ? "All covenants passing." : `${failed.length} covenant(s) failing.`}
</p>
<ol data-covenant-list className="mt-4 space-y-2">
{covenantRows.map((r) => (
<li key={r.id} data-covenant={r.id} data-ok={String(r.ok)}>
<strong>{r.id}</strong>{" "}
<span className="text-sm text-[color:var(--docs-muted)]">
{r.ok ? "ok" : `failed:${r.reason}`}
</span>
</li>
))}
</ol>
<pre data-covenants>{JSON.stringify(nav.read("covenants"), null, 2)}</pre>
</section>
);
}
Checklist
- Render-time checks.
- Evidence ledger rendered into the DOM.
- Fail-forward posture.
- Keep covenant ids stable across refactors.