A3.3 · Anatomy of a roadmap.md · dive 3
The open decisions
A good roadmap names what it has not decided — the choice, where it will be made, and the seam — so the plan is honest about its own uncertainty.
The “Seams & open decisions” section of
phoenix.roadmap.md lists each unresolved choice and defers it to a rung. Pick a
decision on the right to read it from the real file and see the rung it resolves at.
The open decisions · pick one
Named, not resolved
The closing section of phoenix.roadmap.md is “Seams & open decisions”.
It does not pretend the chapter has no uncertainty; it lists each unresolved choice, says where it is the
right time to decide, and names the seam the decision will plug into. An honest roadmap states its open
questions rather than hiding them.
- auth
- Authentication (F6.8) — verbatim: “The likely path is
mix phx.gen.authfor password accounts, with theAccountscontext from F6.4 as the seam; the choice of social/SSO and session model is decided then.” - deploy
- Deployment & clustering (F6.8) — verbatim: “An Elixir release plus a clustering strategy (for example
libcluster)…the deploy target (a managed platform or containers) is decided then.” - dashboard
- Dashboard data (F6.9) — verbatim: “the dashboard folds live events…which metrics it shows and whether it embeds
LiveDashboardis decided then.” - browse
- Catalog browsing read — verbatim: “Browsing the available catalog uses
Catalog.list_courses/0(F6.4), distinct from the learner-scopedcourses_of/1on the F5 facade”. - eventstore
- The Postgres
EventStoreadapter — verbatim: “Its body, schema, and migration land in F6.3 behind the F5.8 port, so enrollment is durable in production while tests stay on the in-memory adapter.”
Naming a decision and deferring it is not avoidance — it is sequencing. Each is “decided then”, at the rung where the information to decide it exists.
Bounded by the master invariant
The open decisions are real, but they are not unbounded. The master invariant constrains every one of them,
verbatim: “The web layer calls only the Portal facade and renders only the
closed %Portal.Error{} set.” Whatever authentication, deployment target, or
dashboard the project chooses, the resolution sits over the facade — so the F5 engine below it does not
move.
The control below picks a resolution for one open decision. The invariant readout stays “holds” across every allowed choice, because the boundary is fixed regardless of which option wins. This is the move the hero figure could not show: the hero read each decision and its rung; this proves the consequence — that the invariant holds no matter how a decision resolves.
Pick a resolution · the invariant still holds
Name the open decisions and where each resolves — and let one fixed invariant bound every resolution, so the engine below the facade never moves.
The open decisions, on the Portal
On the Portal, phoenix.roadmap.md names five seams it does not resolve up front:
authentication and the deploy target (both “decided then” at F6.8), the dashboard's metrics
(decided at F6.9), the catalog browsing read (Catalog.list_courses/0, distinct from
the facade's courses_of/1), and the Postgres EventStore
adapter behind the F5.8 port. Each is deferred to the rung where the information to decide it exists.
None of them threatens the engine, because all of them sit over the facade. In the file's words, the only
structural change to the F5 supervision tree across all of F6 is adding
PortalWeb.Endpoint; later rungs add PubSub and Presence “only as the real-time
features require them”. The open decision is named; the master invariant fixes the boundary it resolves
within.
# phoenix.roadmap.md — "Seams & open decisions" (named, not resolved). # Authentication (F6.8) — "the choice of social/SSO … is decided then" # Deployment & clustering (F6.8) — "the deploy target … is decided then" # Dashboard data (F6.9) — "which metrics it shows … is decided then" # Every resolution stays over the master invariant — the boundary is fixed. defmodule PortalWeb.SomeController do # calls only the Portal facade; renders only %Portal.Error{} Portal.enroll(user_id, course_id) # whatever auth resolves to, this does not change end
Name the open decisions, where each resolves, and the seam — an honest roadmap states its uncertainty instead of hiding it; a fixed invariant bounds every resolution.
phoenix.roadmap.md's “Seams & open decisions” defers auth and
deploy to F6.8 and the dashboard to F6.9; the master invariant — calls only the
Portal facade — holds across all of them.
A roadmap names its open decisions and where they resolve — and one master invariant holds across every one, so nothing below the facade moves.
Recap — honest about its uncertainty
The “Seams & open decisions” section names what a roadmap has not decided — auth,
deployment, the dashboard, the catalog read, the event-store adapter — says where each is decided, and
names the seam. Deferring a decision to its rung is sequencing, not avoidance; and the master invariant bounds
every resolution, so the engine below the facade never moves. That closes A3.3: a roadmap carries six parts,
the per-iteration table at its heart, and the open decisions named but not resolved — all read on the
real phoenix.roadmap.md.
Return to A3.3 · Anatomy of a roadmap.md for the module navigation, or to the A3 chapter to continue.
References
The sources behind naming open decisions and bounding them with an invariant, and where this connects in the course.
Sources
- Hunt & Thomas — The Pragmatic Programmer — reversible decisions and decoupling: defer the choice, keep the seam.
- Humble & Farley — Continuous Delivery — deciding deployment and release strategy at the responsible last moment.
- Beck, K. — Extreme Programming Explained — the planning game: decide what you must now, defer the rest.
Related in this course
- A3.3 · Anatomy of a roadmap.md — the module hub.
- A3.3.2 · The iteration table — the previous dive.
- A3 · The roadmap layer — the orientation dive this expands.
- A1.04 · Two layers — the roadmap over the spec.
- F6 · The Portal on the web (Phoenix) — the real chapter and its seams section.
- Companion · Functional Programming in Elixir