Build and deploy / build-and-deploy (push) Failing after 5s
Step 5 ships /practice/ and the six practice-area pages (construction,
technology, energy, insurance, shareholder, cross-border) from one route, and
adds the mechanical §4 gate Pouya ruled for.
check:claims — §4 Forbidden becomes a build error
scripts/check-claims.mjs greps dist/**/*.html for 10 patterns, each carrying
the incident that put it there. It strips <style> and non-JSON-LD <script>
first (a bare sweep for "leading" returned 26 hits, 25 of them
var(--leading-body)), self-tests every pattern against fixtures before
sweeping, and refuses a missing, empty or stale dist/. Wired into /build
Phase 5 and both deploy paths.
Q54 — six conduct undertakings publish, and §4 gains a third class
Conduct undertakings sit apart from credentials and offerings: the gate is
that Pouya said it in terms. The strings live in CONDUCT_UNDERTAKINGS so a
softening is one visible diff. (e) and (f) replace the third-person sentences
already on /arbitration/ rather than joining them.
Q49, Q50 recorded as rulings. §7 records the SES us-east-1 stray identity's
deletion. R11 holds typescript at its current major, with the peer-range
reason recorded.
Three facts corrected, two of them already shipped
- The LAT gloss said mediation "before filing and continuing after filing";
the Tribunal names mediation for "Before you apply" only and its second
sentence is about negotiation. An ellipsis in docs/01 had deleted it.
- "Connection allocation" is not an Ontario term.
- "The 2026 privacy statute" does not exist — Bill C-27 died without royal
assent. Struck from docs/03 rather than corrected in place.
ADR Chambers struck from /arbitration/ and from docs/01 item 3 (Pouya,
2026-08-30): the source establishes what the firm publishes, not that an
outside neutral can be appointed under its rules.
claims-auditor gains a second lens — for every quoted source, whether the
sentence beneath stays inside what the quotation establishes. Four shipped
defects had that shape and none of them is greppable.
CLAUDE.md gains a convention: never truncate the output of a check you intend
to believe. `npm run check | tail -3` returns warnings, hints and a blank line
and drops the errors line; it was reported as passing four times while
astro check was exiting 1 with 10 type errors.
Gates, exit status read directly, not through a pipe:
npm run check exit=0
npm run lint exit=0
npm run build exit=0
npm run check:claims exit=0
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Md3GndFqWPzK78xAoebsg5
89 lines
3.0 KiB
Plaintext
89 lines
3.0 KiB
Plaintext
---
|
|
/**
|
|
* The visible breadcrumb trail. `docs/04` requires `BreadcrumbList` markup on
|
|
* "all nested pages" AND that it **match the visible breadcrumbs** — so the
|
|
* markup and this component are built from one array at the call site, and a
|
|
* page cannot emit one without showing the other.
|
|
*
|
|
* WHICH PAGES GET ONE, AND WHY IT IS NOT EVERY PAGE. `/about/`, `/mediation/`,
|
|
* `/arbitration/`, `/med-arb/` and `/practice/` are all ONE HOP from the root
|
|
* and show no breadcrumb, so emitting the markup on them would assert a
|
|
* navigation structure the page does not have. The trail begins at the
|
|
* two-level pages: `/practice/<area>/`, and `/insights/<slug>/` at step 7.
|
|
*
|
|
* THE CURRENT PAGE IS NOT A LINK. A link to the page you are on is a target
|
|
* that does nothing, and `aria-current="page"` is the property that carries the
|
|
* meaning. `schema.org` still wants it as the last `ListItem`, which is why the
|
|
* caller passes the full trail and this component decides what to render.
|
|
*
|
|
* THE SEPARATOR IS `aria-hidden` AND LIVES IN CSS-adjacent markup rather than
|
|
* in the link text: a screen reader announcing "slash" between every crumb is
|
|
* noise, and `<nav aria-label="Breadcrumb">` already names the structure.
|
|
*/
|
|
interface Props {
|
|
/** Root-first, INCLUDING the current page as the last entry. */
|
|
trail: ReadonlyArray<{ name: string; href: string }>;
|
|
}
|
|
const { trail } = Astro.props;
|
|
---
|
|
|
|
<nav class="crumbs" aria-label="Breadcrumb">
|
|
<ol role="list">
|
|
{
|
|
trail.map((crumb, i) =>
|
|
i === trail.length - 1 ? (
|
|
<li aria-current="page">{crumb.name}</li>
|
|
) : (
|
|
<li>
|
|
<a href={crumb.href}>{crumb.name}</a>
|
|
<span aria-hidden="true">/</span>
|
|
</li>
|
|
),
|
|
)
|
|
}
|
|
</ol>
|
|
</nav>
|
|
|
|
<style>
|
|
/* `role="list"` on the <ol> and no local `list-style: none` — global.css does
|
|
both for `ol[role='list']`, and WebKit drops list semantics when the marker
|
|
goes, which is why the role is there. Same pairing as `.stage` on
|
|
`/arbitration/`. */
|
|
.crumbs ol {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
align-items: center;
|
|
gap: var(--space-2);
|
|
font-family: var(--font-mono);
|
|
font-size: var(--text-xs);
|
|
letter-spacing: var(--tracking-wide);
|
|
text-transform: uppercase;
|
|
color: var(--text-meta);
|
|
}
|
|
.crumbs li {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: var(--space-2);
|
|
}
|
|
/* 44px is the touch-target floor in docs/02. These are small uppercase mono
|
|
links in a row, which is exactly the shape that lands under it — the same
|
|
defect measured on `/med-arb/`'s onward links at 390px (21px tall against a
|
|
44px floor). `inline-flex` + `min-block-size` is the fix the rest of the
|
|
site uses. */
|
|
.crumbs a {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
min-block-size: 44px;
|
|
color: inherit;
|
|
text-decoration: none;
|
|
}
|
|
.crumbs a:hover {
|
|
color: var(--text);
|
|
text-decoration: underline;
|
|
text-underline-offset: 0.2em;
|
|
}
|
|
.crumbs [aria-current='page'] {
|
|
color: var(--text);
|
|
}
|
|
</style>
|