Overview › The hierarchy › GoalSegment schema

The GoalSegment Schema

The typed group contract — new this session. It is the data structure every later phase of the goal hierarchy consumes: build-time gates, group metrics, and the deterministic selector.

What & why

Today a “group” is only a measurement aggregate — an inferred segment label on a state. To make a group a goal-directed unit (one that owns a typed objective and can be deterministically driven), it needs a first-class, authored contract. GoalSegment (riff/types.py, commit 23432c5) is that contract. It is phase 3 of the goal-hierarchy design.

Strictly additive. A flow without a segments: block has none, and nothing changes — the common case today. The schema is the foundation later phases build on; it does not alter the runtime of existing flows.

The schema

GoalSegment is a frozen dataclass. The complex fields are stored as tuples-of-pairs or JSON strings so the dataclass stays frozen-hashable, with helper properties to decode them.

FieldMeaning
namethe segment's stable id
kindthe typed objective: collect | confirm | act | terminal | handoff
purposeone-line statement of the group's goal
membersthe member state ids that form this group
target_slotsthe contract: ((slot, json_spec), …) — each spec carries required, validator, confirmation
entry_guard / exit_guardguard expressions that prove entry/exit conditions
ordering_json{preferred_order, allow_bundle, max_new_slots_per_turn}
repair_policy_json{invalid, low_confidence, max_attempts_per_slot, fallback_state, …}

Three helper properties decode the packed fields: .target (the slot contract dict), .repair_policy, and .ordering.

How it's authored (YAML)

The loader (riff/loader.py) parses an optional top-level segments: mapping into the frozen tuple on the Flow. Absent → empty tuple.

# flows/<flow>.yaml
segments:
  collect_customer:
    kind: collect
    purpose: collect caller identity and service location
    members: [ask_contact_bundle, repair_phone]
    entry_guard: 'intent in ["book", "request_service"]'
    exit_guard: all_required_slots_valid
    target_slots:
      name:    { required: true, validator: person_name,         confirmation: implicit }
      phone:   { required: true, validator: us_phone,            confirmation: explicit_if_asr_low }
      address: { required: true, validator: serviceable_address, confirmation: explicit }
    ordering:      { preferred_order: [name, phone, address], allow_bundle: true, max_new_slots_per_turn: 2 }
    repair_policy: { invalid: ask_repair, max_attempts_per_slot: 2, fallback_state: collect_customer_failed }

What consumes it

PhaseReadsStatus
Build-time gates (4)target_slots typed, exit_guard proves the contract, fallback_state reachable, completion_slots coveredplanned, runs in lint/load + pre-push
Group metrics (5)kind's typed goal — slot_yield for collect, confirmation_success for confirm, …cohesion proxy shipped
GOAP-lite selector (7)target_slots + ordering to pick the next member deterministicallyplanned, behind a flag
The repair path is already real. repair_policy.fallback_state is reached via the shipped stalled-guard + sets: recovery primitive (commit e22399d) — the deterministic way to handle a withholding caller. See Stall recovery.

Use case

An author writing a new booking flow declares its collect phase as a GoalSegment with three target slots and an exit guard. From that one declaration: the build-time gate verifies every target slot has a collecting state and the fallback is reachable; the group metric scores slot_yield against the declared contract; and (once enabled) the selector drives the members deterministically. The goal and its metric exist from the first commit, because the group is the goal.

Example

# load a flow and inspect its segments programmatically
python -c "from riff.loader import load_flow; \
f = load_flow('flows/austin_plumbing.yaml'); \
print([(s.name, s.kind, list(s.target)) for s in f.segments])"

(For flows without a segments: block this prints [] — the inferred segment labels used by the metrics still come from segment inference.)

Where it fits

GoalSegment is the bridge between the goal-hierarchy design and the running engine. It turns the middle tier from a label into a contract — the prerequisite for build-time gates, contract-backed group metrics, and the deterministic member selector that keeps the LLM language-only.