jonnifyagile agents
jonnify / Agile Agent Workflow / A3 · The roadmap layer / A3.8 / A3.8.1 · Ladder to roadmap

A3.8 · Workshop: roadmapping Portal · dive 1

Ladder to roadmap

A value ladder is a backlog. A roadmap adds two things and no behaviour: a milestone per rung, and a row per rung in the iteration table.

A2 left nine vertical rungs, dependency-ordered. This dive takes them to the real F6 chapter roadmap by applying the anatomy (A3.3) and milestones (A3.5): assign each rung to one of three milestones, then fill its row — Ships, Demo, Harness, Feedback. Pick a rung on the right to see which milestone it falls in; the spec it points at is never touched.

Assign a rung to a milestone · pick a rung

the nine-rung ladder, grouped into three milestones Milestone 1 · Ship the catalog f6.1 · f6.2 · f6.3 · f6.4 · f6.5 · f6.5.5 Milestone 2 · Make it live f6.6 · f6.7 Milestone 3 · Ship to users f6.8 · f6.9 f6.1 a milestone is a usable-capability boundary · assigning is the roadmap, not a spec
f6.1 → milestone 1 · Ship the catalog (f6.1–f6.5.5). A milestone is a usable-capability boundary; the assignment is the roadmap, not a spec.

From ladder to milestones

A2 produced a value ladder: nine vertical rungs f6.1 through f6.9, dependency-ordered, each a real capability. That is a backlog — ordered, but flat. A roadmap groups the rungs into milestones, each a usable-capability boundary: the point at which a real role can do something end to end.

The F6 roadmap names three, verbatim: 1 · Ship the catalog (browse a persistent catalog and add courses), 2 · Make it live (search and create without reloads, every client live with a viewer count), and 3 · Ship to users (sign in, run behind auth on a deployed release, watch a dashboard). The grouping is a roadmap edit. It re-uses every rung's spec and changes none of them.

The order respects two forces at once: dependency — persistence (f6.3) before the rendered catalog (f6.5) — and product priority — the catalog ships before auth. Re-grouping the rungs is a roadmap move; the spec each rung points at is untouched.

Fill the iteration row

With the rungs grouped, each one gets a row in the per-iteration table. The columns are the roadmap's own: Rung, Ships (the slice), Demo, Harness, Feedback asked — each row a PR-sized increment. The figure below fills a rung's row from the roadmap's verbatim cells, and holds a spec edits counter at zero: filling the table edits the roadmap, never a spec. The two figures teach different moves — the hero assigns a rung to a milestone, this one fills its iteration row.

Fill a rung's row · the spec-edits counter stays at zero

f6.1 · one row of the per-iteration table Ships (the slice) the engine served as a web app Demo hit the root, see a page Harness ConnTest GET smoke Feedback asked shell and layout right? spec edits while filling the table: 0
f6.1 row — Ships: the engine served as a web app · Demo: hit the root, see a page · Harness: ConnTest GET smoke · Feedback: shell and layout right? · spec edits: 0.

A roadmap adds a milestone and a row per rung — order and demos and harnesses — and defines no behaviour; the spec-edits counter never moves.

The roadmap, reproduced on the Portal

On the Portal — the learning platform this course builds — the value ladder for the web surface is the nine rungs f6.1…f6.9, and the roadmap they produce is the real phoenix.roadmap.md. Grouped into three milestones, filled into the per-iteration table, every cell here is quoted from that file. The roadmap holds order and a demo per rung; each f6.N.md spec holds the behaviour.

That separation is what lets the next dive choose a tracer and defer breadth without editing a spec. The table below is the roadmap fragment as markdown — the document the workshop reproduces, not Elixir source.

# phoenix.roadmap.md — the per-iteration table (markdown; verbatim cells).
| Rung | Ships (the slice)                            | Demo                     | Harness            |
| ---- | -------------------------------------------- | ------------------------ | ------------------ |
| f6.1 | the engine served as a web app               | hit the root, see a page | ConnTest GET smoke |
| f6.3 | durable catalog and enrollments              | data survives a restart  | schema/changeset   |
| f6.5 | the rendered catalog (index, course_card, …) | browse the catalog       | HTML render tests  |

# Each row points at its f6.N.md spec. Re-grouping the rungs edits this table,
# never a spec — the spec-edits count stays 0. All of it under the master invariant:
# the web layer calls only the Portal facade.
the principle

A value ladder becomes a roadmap by grouping rungs into milestones and filling each rung's iteration row — order and a row per rung, and no behaviour.

on the Portal

On the Portal the table is phoenix.roadmap.md's per-iteration table; each row points at its f6.N.md spec; re-grouping the rungs edits the roadmap, never a spec.

The ladder is the backlog; the roadmap adds milestones and a row per rung — and defines no behaviour.

Recap — milestones, a row per rung, no behaviour

A value ladder is a backlog; a roadmap is the ladder grouped into three milestones with a row per rung in the per-iteration table — Ships, Demo, Harness, Feedback. Both moves edit the roadmap and never a spec, so the spec-edits counter stays at zero. With the ladder turned into a roadmap, the next dive chooses where to start: the tracer bullet, and the seams deferred behind it.

Next in A3.8: A3.8.2 · Choose the tracer — the first end-to-end thread, F6.1, and the breadth deferred behind it.

References

The delivery-planning sources behind grouping a backlog into shippable milestones, and where it connects in the course.

Sources

Related in this course