Agenda.Session (Agenda v0.1.0)

Copy Markdown View Source

A session — the thing being scheduled.

A session states how long it runs, the window it must fall inside, what it requires of resources, and what it would merely prefer. It says nothing about when it actually happens: that is what planning works out.

The word is deliberately not "meeting" (too narrow — a court hearing and a conference talk are neither), not "event" (Tempo.Event is taken, and it collides with event sourcing), and not "booking" (which names the request in some scheduling libraries, not the thing requested).

Summary

Types

t()

Something to be scheduled.

Functions

Set how long the session runs.

Invite resources who may attend but are not required.

Every resource named by a roster requirement.

Add an attribute requirement under role.

Build a session.

The requirements described by attribute rather than named.

Add soft preferences — they rank arrangements but never exclude one.

Add a requirement naming specific resources under role.

The requirements naming specific resources.

Set the interval the session must fall inside.

Types

t()

@type t() :: %Agenda.Session{
  duration: Agenda.Availability.pattern() | nil,
  invitees: keyword([Agenda.Resource.t()]),
  name: String.t(),
  preferences: keyword(),
  requirements: [Agenda.Requirement.t()],
  series: String.t() | nil,
  window: Agenda.Availability.pattern() | nil
}

Something to be scheduled.

Functions

duration(session, duration)

@spec duration(t(), Agenda.Availability.pattern()) :: t()

Set how long the session runs.

Arguments

Returns

  • the session, with its duration set.

Examples

iex> import Tempo.Sigils
iex> session = Agenda.Session.new("Review")
iex> Agenda.Session.duration(session, ~o"PT1H").duration
~o"PT1H"

invite(session, role, resources)

@spec invite(t(), atom(), [Agenda.Resource.t()]) :: t()

Invite resources who may attend but are not required.

The counterpart to roster/3. A rostered resource must be free or the session cannot be held; an invitee never affects whether a placement is possible, only how good it is — a time when more of them can come scores better, and Agenda.Arrangement records which of them the chosen time actually suits.

This is deliberately weaker than roster/3 in a second way: an invitee is not allocated. Their time is not taken and the ledger does not know about them, because a placement that consumed an optional person could make some other session impossible — and an optional attendee that can cost a placement is not optional. Book them with Agenda.Ledger.allocate/3 once the time is settled, if they are coming.

Arguments

Returns

  • The session, with the invitees added.

Examples

iex> bob = Agenda.resource("Bob")
iex> session = Agenda.session("Review", duration: "PT1H")
iex> Agenda.Session.invite(session, :optional, [bob]).invitees
[optional: [bob]]

named_resources(session)

@spec named_resources(t()) :: [Agenda.Resource.t()]

Every resource named by a roster requirement.

These are the resources whose own requires tighten the open roles — see Agenda.Requirement.induce/2.

Arguments

  • session is a t/0.

Returns

  • the named resources, in requirement order.

Examples

iex> alice = Agenda.Resource.new("Alice")
iex> session = Agenda.Session.new("Review") |> Agenda.Session.roster(:attendees, [alice])
iex> Enum.map(Agenda.Session.named_resources(session), & &1.name)
["Alice"]

needs(session, role, predicates)

@spec needs(t(), atom(), keyword()) :: t()

Add an attribute requirement under role.

Arguments

  • session is a t/0.

  • role is the role name, such as :room.

  • predicates is a keyword list of attribute predicates.

Returns

  • the session with the requirement added.

Examples

iex> import Agenda.Predicate
iex> session = Agenda.Session.new("Review")
iex> session = Agenda.Session.needs(session, :room, seats: at_least(8))
iex> Enum.map(session.requirements, & &1.name)
[:room]

new(name, options \\ [])

@spec new(
  String.t(),
  keyword()
) :: t()

Build a session.

Arguments

  • name is the session's name.

Options

Returns

Examples

iex> import Tempo.Sigils
iex> Agenda.Session.new("Quarterly review", duration: ~o"PT1H").name
"Quarterly review"

open_roles(session)

@spec open_roles(t()) :: [Agenda.Requirement.t()]

The requirements described by attribute rather than named.

Each of these is a role that planning must choose a resource for.

Arguments

  • session is a t/0.

Returns

  • the attribute requirements.

Examples

iex> session = Agenda.Session.new("Review") |> Agenda.Session.needs(:room, seats: 8)
iex> Enum.map(Agenda.Session.open_roles(session), & &1.name)
[:room]

prefers(session, preferences)

@spec prefers(
  t(),
  keyword()
) :: t()

Add soft preferences — they rank arrangements but never exclude one.

Arguments

  • session is a t/0.

  • preferences is a keyword list. within: place prefers resources inside that place; any other key is matched against resource attributes.

Returns

  • the session, with the preferences added.

Examples

iex> sydney = Agenda.Place.new("Sydney")
iex> session = Agenda.Session.new("Review")
iex> Agenda.Session.prefers(session, within: sydney).preferences |> Keyword.keys()
[:within]

roster(session, role, resources)

@spec roster(t(), atom(), [Agenda.Resource.t()]) :: t()

Add a requirement naming specific resources under role.

Arguments

  • session is a t/0.

  • role is the role name, such as :attendees.

  • resources is the list of required Agenda.Resource.t/0. Naming nobody adds no requirement — a role filled by no one constrains nothing, and a requirement that neither names nor describes would otherwise let planning bind any resource at all to the role.

Returns

  • the session with the requirement added, or unchanged if resources is empty.

Examples

iex> alice = Agenda.Resource.new("Alice")
iex> session = Agenda.Session.new("Review")
iex> session = Agenda.Session.roster(session, :attendees, [alice])
iex> Enum.map(session.requirements, & &1.name)
[:attendees]

iex> session = Agenda.Session.new("Review")
iex> Agenda.Session.roster(session, :attendees, []).requirements
[]

rosters(session)

@spec rosters(t()) :: [Agenda.Requirement.t()]

The requirements naming specific resources.

Arguments

  • session is a t/0.

Returns

  • the roster requirements.

Examples

iex> alice = Agenda.Resource.new("Alice")
iex> session = Agenda.Session.new("Review") |> Agenda.Session.roster(:attendees, [alice])
iex> Enum.map(Agenda.Session.rosters(session), & &1.name)
[:attendees]

window(session, window)

@spec window(t(), Agenda.Availability.pattern()) :: t()

Set the interval the session must fall inside.

Arguments

Returns

  • the session, bounded.

Examples

iex> import Tempo.Sigils
iex> session = Agenda.Session.new("Review")
iex> Agenda.Session.window(session, ~o"2026-06-15/2026-06-20").window
~o"2026-06-15/2026-06-20"