jonnifyagile agents
jonnify / Agile Agent Workflow / A3 · The roadmap layer / A3.3 / A3.3.3 · The open decisions

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

Seams & open decisions · named, not resolved Authentication → F6.8 Deployment & clustering → F6.8 Dashboard data → F6.9 Catalog browsing read → F6.4 The Postgres EventStore adapter → F6.3 master invariant · every resolution stays over the Portal facade
Authentication — open / named, not resolved · resolves at F6.8 · verbatim: "the choice of social/SSO and session model is decided then".

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.auth for password accounts, with the Accounts context 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 LiveDashboard is decided then.”
browse
Catalog browsing read — verbatim: “Browsing the available catalog uses Catalog.list_courses/0 (F6.4), distinct from the learner-scoped courses_of/1 on the F5 facade”.
eventstore
The Postgres EventStore adapter — 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

the open decision, resolved auth: phx.gen.auth calls the Portal facade · %Portal.Error{} the F5 engine · unchanged
Resolution: auth: phx.gen.auth. Master invariant: holds — the web layer calls only the Portal facade and renders only %Portal.Error{}. The open decision is named; the boundary is fixed.

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
the principle

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.

on the Portal

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

Related in this course