The first visible change to /learning/ arrived after the tests, the breadcrumb, and the JSON-LD

P2 of the learning-hub navigation merged on 2 July 2026, the first visible navigation change since the hub launched. Track sections appeared on /learning/ for the first time.

By the time that branch landed, feat/learning-nav-p0-substrate had already been merged. It contained 37 fixture tests in vitest, a data model, semantic breadcrumbs, and the repo’s first wired npm test pipeline. None of that was visible to a visitor. All of it existed before P2.

The order wasn’t obvious and wasn’t the default. It came from the spec.

The spec came first

docs/specs/learning-hub/navigation.md was written before any code existed. I ran an ultracode workflow to produce it: 16 agents in parallel, three readers pulling context from the existing site structure and five design dimensions each adversarially verified. The output was an implementation-grade spec with phased delivery, explicit acceptance criteria, and a11y requirements called out by phase, not deferred to the end.

That last part is the thing. The spec assigned semantic breadcrumbs to P0 and JSON-LD to P2. Not “add later”, not “nice to have”. Assigned, with a phase.

When the spec says a11y ships in P0, and the commitment is made to the phasing, the breadcrumb becomes a build gate the same way the data model is a build gate. You can’t ship P1 with a broken data model. You also can’t ship P1 with the breadcrumb missing, because P0 didn’t complete without it.

Scope discipline in a spec doesn’t add ceremony. It removes the negotiation you’d otherwise have at 11pm, when P2 is nearly done and someone (in this case, also me) starts wondering whether the JSON-LD is strictly necessary before the branch goes out.

P0+P1 as substrate

P0+P1 shipped as a bundle. Decision #10 in the spec consolidated them, because the data model and the build gate were coupled. Neither was useful without the other.

What that branch contained:

  • The data model behind the track sections (nothing rendered from it yet)
  • vitest wired into npm test, with 37 fixture tests covering the data layer
  • Semantic breadcrumbs live in the DOM
  • No new visible elements

The repo had no test infrastructure before this. npm test had no wiring. The navigation spec introduced both the tests and the runner as part of the substrate phase. That’s not a side effect of building navigation. It’s what happens when the spec treats “verifiable by a machine” as a first-class property of P0, not a sprint-6 follow-up.

37 tests for a data model and a breadcrumb feels like a lot. It isn’t. Fixture tests are cheap to write and expensive not to have when you’re refactoring the data model three months later with no safety net. The cost is front-loaded; the cost of absence is distributed across every change that touches the model afterwards.

P2 and the UI gate

P2 was the first run through the UI gate since the hub launched. Track sections are the first visible representation of the data model that P0+P1 built. Getting the interactive approval mockup through the gate before any code touched the component is the same discipline as writing the spec before any code touched the feature. You don’t find out the layout is wrong after the implementation exists. You find out in the mockup, where the fix is a CSS change, not a component rewrite.

JSON-LD also shipped in P2: the S1 structured data block for the hub. Not because P2 was already large enough to justify scope expansion. Because the spec assigned it there.

What the spec changed

The standard path for accessibility on a personal site build is roughly: ship the visible elements, add alt attributes, add aria-label to the obvious interactive components, add a breadcrumb when the nav gets complex enough to need one, add JSON-LD when Lighthouse flags its absence.

That path is rational given typical constraints. The cost of deferring the breadcrumb is zero today. Some unknown positive number later. So it defers.

The spec inverted the calculus. Once the breadcrumb was assigned to P0 with an acceptance criterion, deferring it meant P0 was incomplete. Incomplete P0 blocked P1. “Add breadcrumb later” lives in a comment somewhere. An incomplete P0 blocks the critical path, which is the same work in a different position on the dependency graph, with a different probability of shipping.

This is the mechanism. The spec doesn’t make accessibility easier to implement. It makes it harder to skip.

What the ultracode workflow added

The spec came from a 16-agent ultracode run I put together. The honest answer to why: a single-pass draft produces a reasonable-looking document and misses the structural decisions that only surface when I run design dimensions in parallel and compare them adversarially.

The phasing decision is what a single pass wouldn’t have caught. P0 as “data model + build gate + breadcrumb” before any visible UI is not an obvious design choice. Most navigation builds don’t phase that way because there’s no forcing function. Running five design dimensions in parallel and comparing them adversarially let me trace the dependency: the data model had to exist before the visible components could be correct, and once the data model was the first deliverable, the breadcrumb (which depends on the same data) became cheap to add to the same phase rather than deferred.

That dependency would have surfaced without the parallel verification pass. Probably in code, during P2, as a refactor.

Out of scope: this isn’t an argument for ultracode on every navigation change. The workflow is appropriate when the phasing decisions are non-obvious and getting them wrong means a rewrite rather than an adjustment. A three-link nav doesn’t need 16 agents. The learning hub has multi-level hierarchy, structured data requirements, and a test infrastructure that didn’t exist yet. That’s the right size problem for the tool.

The sequence

Spec first. Then the data model. Then the test runner and 37 tests, followed by the semantic breadcrumb. None of it visible. The first visible thing arrived after that: track sections, run through the interactive mockup gate before any code was written, with JSON-LD shipped alongside.

That sequence sits in the build log at docs/devlog.md, across two entries dated 2026-07-01 plus one dated 2026-07-02. The spec is at docs/specs/learning-hub/navigation.md. The 37 tests still sit in the repo, still passing. npm test still runs them first.

All writing