jonnifyagile agents
jonnify / Agile Agent Workflow / A4 · Spec / The spec ladder

A4 · The spec layer · spec ladder

The spec ladder

A spec is a living document. View its content across the iterations git recorded — the Portal's shipped web rungs, F6.1 through F6.6.

Every .specref chip in chapter A4 links here. Slide across the rungs on the right and read what each one settled: the goal, the ship date, the routing surface at that iteration, and the one thing that changed. Watch the route shape move — F6.1's first-draft /courses/:user_id is reconciled away at F6.5, and the catalog goes live at /courses at F6.6.

The F6 web ladder · slide across the iterations

F6.1
F6.1 F6.2 F6.3 F6.4 F6.5 F6.6 F6.1 · Bootstrap the Phoenix Portal shipped 2026-06-03 ROUTING SURFACE — — GET /courses/:user_id (first-draft course page) what changed: first draft — the /courses/:user_id route is introduced here
F6.1 · Bootstrap the Phoenix Portal — shipped 2026-06-03. Routes: GET /courses/:user_id (first-draft course page for a given user) · GET /health. What changed: first draft — the /courses/:user_id route is introduced here.

A spec is a living document

A spec is not written once and frozen. It is edited by feedback, rung after rung, and version control records every edit. The slider above reads that record: each stop is a shipped iteration of the Portal's web layer, and the figure reports what the spec said at that point — the goal it pursued, the date it shipped, the routing surface it declared, and the one thing the rung changed. F6.1 through F6.6 are all shipped; the iteration axis is the git history.

The most instructive thread is the routing surface, because a route name is a decision the spec can get wrong and later correct. F6.1 introduced /courses/:user_id as a first-draft course page for a given user. By F6.5 that name was a problem: a learner cannot see another learner's enrolled courses, so a path that takes any user's id as a parameter promises something the access rules forbid. The fix was a reconcile, not a patch.

The principle

A spec is a living document. Version control records its content across iterations, so a wrong early decision is visible — and the right repair is to edit the spec, not to paper over it in code.

On the Portal

The F6 web ladder is six shipped rungs. The first-draft /courses/:user_id was reconciled away at F6.5 into /my/courses — one honest name for a learner's own enrollments — and the catalog went live at /courses at F6.6.

The slider is the spec's edit history made legible — a route the spec got wrong is a route the next rung can rename.

Routes: then versus now

One reconcile is the spine of the whole ladder, so it is worth holding both ends of it side by side. Toggle between the first-draft surface (F6.1, the route as introduced) and the as-built surface (F6.6, the route as it ships today). The learner route is the one that moved.

The learner route · first draft, or as built

THE CATALOG — public, anyone can browse GET /courses (static index over Portal.Catalog) A LEARNER'S OWN COURSES — first draft GET /courses/:user_id (a course page for a given user) F6.1: the learner route takes any user's id as a path parameter
First draft (F6.1): the catalog is GET /courses; a learner's own courses are GET /courses/:user_id — a course page for a given user, with the id passed as a path parameter. The reconcile at F6.5 renamed this route.

The same need — "show a learner their courses" — got one honest name only after the first draft proved it could promise access the rules forbid.

The six rungs

Each rung below is a shipped iteration of the Portal's web layer. They are the citations every .specref chip in this chapter points at — the chip's link lands on the matching anchor here.

F6.1shipped

Bootstrap the Phoenix Portal

Stand the headless F5 engine up as a Phoenix web app: the endpoint joins the supervision tree, one browser route reaches a thin controller over the facade, a liveness route proves it is up. Introduces the first-draft /courses/:user_id and /health.

F6.2shipped

Routing & the access surface

A real routing surface on F6.1's endpoint — read, write, RESTful, and live routes with the browser / api / require_auth pipelines. The route shape and pipelines arrive.

F6.3shipped

Persistence with Ecto

Make the Portal durable without the core depending on a database — Ecto as one more adapter behind the F5 facade. Persistence arrives behind the facade; routes unchanged.

F6.4shipped

Contexts & domain on the web

The real domain behind one web-facing surface — a Catalog context over the Ecto Course schema. The Portal.Catalog context arrives; the catalog becomes the spine.

F6.5shipped

Views with HEEx

Server-render the catalog: an index over the courses, a verified link per course. The reconcile — /courses/:user_id retires into /my/courses (one honest name for a learner's own enrollments, protected); the catalog is /courses.

F6.6shipped

LiveView

Make F6.5's catalog interactive without full reloads — CatalogLive streams the catalog and renders live search and create over the facade. As built today: live "/courses" · /course/:course_tag · /my/courses (protected).

These six rungs ground chapter A4's worked examples. The honest as-built example is the public catalog A4.1 · Specification by Example reads: /courses (anyone) versus /my/courses (a learner's own, protected).

References

The sources behind a living, version-controlled spec, and where this viewer connects in the course.

Sources

Related in this course