{
  "$schema": "./user-flow-examples.schema.json",
  "schemaVersion": "1.0.0",
  "reviewedAt": "2026-08-01",
  "fictional": true,
  "legend": {
    "nodeKinds": {
      "entry": "The first observable surface in this bounded task.",
      "screen": "A stable interface surface where the person can act.",
      "decision": "A branch whose possible results are explicit in the map.",
      "status": "A waiting or progress state visible to the person.",
      "error": "A visible failure state with a specific recovery path.",
      "terminal": "A success or safe-exit outcome for this bounded task."
    },
    "edgeKinds": {
      "action": "An intentional user action.",
      "result": "A visible result produced after an action or check.",
      "recovery": "A path from an error or blocked state back to useful progress.",
      "exit": "A deliberate safe exit from the bounded task."
    }
  },
  "flows": [
    {
      "id": "support_request",
      "title": "Submit a support request",
      "actor": "Signed-in workspace member",
      "goal": "Create one support request and receive a visible reference without confusing provider delivery with the durable save.",
      "entryNodeId": "support_home",
      "terminalNodeIds": ["request_confirmed", "request_safe_exit"],
      "nodes": [
        {
          "id": "support_home",
          "kind": "entry",
          "surface": "Support home",
          "visibleState": "The person can review help options or start a new request.",
          "userCan": "Choose the new-request action.",
          "outcome": null
        },
        {
          "id": "request_form",
          "kind": "screen",
          "surface": "Request form",
          "visibleState": "Required fields, privacy guidance, and a submit action are visible.",
          "userCan": "Enter a subject and description, then submit.",
          "outcome": null
        },
        {
          "id": "form_check",
          "kind": "decision",
          "surface": "Validation gate",
          "visibleState": "The form remains visible while the submission is checked.",
          "userCan": "Wait for either field guidance or save progress.",
          "outcome": null
        },
        {
          "id": "form_error",
          "kind": "error",
          "surface": "Request form",
          "visibleState": "Specific invalid fields are identified without erasing valid input.",
          "userCan": "Correct the named fields and resubmit.",
          "outcome": null
        },
        {
          "id": "request_saving",
          "kind": "status",
          "surface": "Request form",
          "visibleState": "A non-destructive saving state prevents ambiguous repeat submissions.",
          "userCan": "Wait or leave through the safe-exit path if progress cannot continue.",
          "outcome": null
        },
        {
          "id": "save_result",
          "kind": "decision",
          "surface": "Save result gate",
          "visibleState": "The interface resolves the attempt as saved or retryable failure.",
          "userCan": "Continue to confirmation or retry the same attempt.",
          "outcome": null
        },
        {
          "id": "save_error",
          "kind": "error",
          "surface": "Request form",
          "visibleState": "The request was not confirmed and a retry action is visible.",
          "userCan": "Retry without re-entering valid fields or choose the safe exit.",
          "outcome": null
        },
        {
          "id": "request_confirmed",
          "kind": "terminal",
          "surface": "Request confirmation",
          "visibleState": "A fictional request reference and next-step boundary are visible.",
          "userCan": "Copy the reference or return to support home.",
          "outcome": "success"
        },
        {
          "id": "request_safe_exit",
          "kind": "terminal",
          "surface": "Support options",
          "visibleState": "The person sees a safe fallback without a false saved message.",
          "userCan": "Leave the task or use another published support route.",
          "outcome": "safe-exit"
        }
      ],
      "edges": [
        {
          "id": "support_start",
          "from": "support_home",
          "to": "request_form",
          "kind": "action",
          "trigger": "Choose new request",
          "condition": "The person is signed in and can access support.",
          "observableResult": "The request form opens with its required fields and guidance.",
          "retryRule": "Opening the blank form again does not create a request."
        },
        {
          "id": "request_submit",
          "from": "request_form",
          "to": "form_check",
          "kind": "action",
          "trigger": "Submit the request",
          "condition": "The person intentionally submits the current form values.",
          "observableResult": "The form enters a checked submission path without showing success.",
          "retryRule": "A second click while checking is ignored or mapped to the same attempt."
        },
        {
          "id": "request_invalid",
          "from": "form_check",
          "to": "form_error",
          "kind": "result",
          "trigger": "Validation rejects one or more fields",
          "condition": "At least one required or bounded field is invalid.",
          "observableResult": "The invalid fields and reasons are described while valid input remains.",
          "retryRule": "No request is created for repeated invalid submissions."
        },
        {
          "id": "request_correct",
          "from": "form_error",
          "to": "request_form",
          "kind": "recovery",
          "trigger": "Correct the named fields",
          "condition": "The person changes at least one invalid value.",
          "observableResult": "The form is ready for a new intentional submit action.",
          "retryRule": "Corrections do not duplicate a prior save attempt."
        },
        {
          "id": "request_valid",
          "from": "form_check",
          "to": "request_saving",
          "kind": "result",
          "trigger": "Validation accepts the fields",
          "condition": "Required values satisfy the bounded input rules.",
          "observableResult": "A saving status is visible and repeated submission is unavailable.",
          "retryRule": "The save uses one stable attempt identity."
        },
        {
          "id": "request_resolve",
          "from": "request_saving",
          "to": "save_result",
          "kind": "result",
          "trigger": "The save attempt resolves",
          "condition": "The system returns a definitive stored or not-confirmed result.",
          "observableResult": "The interface leaves the waiting state and exposes one result branch.",
          "retryRule": "A timeout remains not confirmed until reconciliation resolves it."
        },
        {
          "id": "request_saved",
          "from": "save_result",
          "to": "request_confirmed",
          "kind": "result",
          "trigger": "The durable request is confirmed",
          "condition": "One request reference exists for the stable attempt.",
          "observableResult": "The confirmation surface displays the fictional reference exactly once.",
          "retryRule": "Replaying the same attempt returns the same reference."
        },
        {
          "id": "request_failed",
          "from": "save_result",
          "to": "save_error",
          "kind": "result",
          "trigger": "The save cannot be confirmed",
          "condition": "No durable reference can be presented safely.",
          "observableResult": "The page states that the request is not confirmed and offers retry.",
          "retryRule": "Retry reuses the stable attempt identity and current form values."
        },
        {
          "id": "request_retry",
          "from": "save_error",
          "to": "request_saving",
          "kind": "recovery",
          "trigger": "Retry the request",
          "condition": "The person chooses retry without changing the request body.",
          "observableResult": "The same attempt returns to a visible saving state.",
          "retryRule": "The retry must not create a second request."
        },
        {
          "id": "request_exit",
          "from": "save_error",
          "to": "request_safe_exit",
          "kind": "exit",
          "trigger": "Choose another support option",
          "condition": "The person does not want to retry now.",
          "observableResult": "The task exits without a false confirmation.",
          "retryRule": "Returning later starts from an explicitly restored or blank form."
        }
      ],
      "acceptanceChecks": [
        "Happy: valid input produces one confirmation with one stable fictional request reference.",
        "Invalid: missing required input identifies the field and keeps all valid values.",
        "Retry: repeating the same save attempt cannot produce a second reference.",
        "Recovery: a failed save can return to saving or leave through a truthful safe exit.",
        "Accessibility: validation, saving, failure, and confirmation states are programmatically exposed and keyboard reachable."
      ],
      "scopeBoundary": "This map owns only the person's observable submission path. Agent triage, assignment, provider notification, resolution workflow, and policy remain outside it."
    },
    {
      "id": "account_recovery",
      "title": "Recover account access",
      "actor": "Person who cannot sign in",
      "goal": "Reach a new-secret confirmation or a safe support exit without revealing whether an account exists.",
      "entryNodeId": "sign_in",
      "terminalNodeIds": ["access_restored", "recovery_safe_exit"],
      "nodes": [
        {
          "id": "sign_in",
          "kind": "entry",
          "surface": "Sign-in page",
          "visibleState": "The recovery action is available without exposing account details.",
          "userCan": "Choose account recovery.",
          "outcome": null
        },
        {
          "id": "recovery_form",
          "kind": "screen",
          "surface": "Recovery request",
          "visibleState": "One account identifier field and privacy-safe guidance are visible.",
          "userCan": "Submit the identifier.",
          "outcome": null
        },
        {
          "id": "recovery_check",
          "kind": "decision",
          "surface": "Recovery request",
          "visibleState": "The request is checked without revealing account existence.",
          "userCan": "Wait for a neutral result.",
          "outcome": null
        },
        {
          "id": "recovery_input_error",
          "kind": "error",
          "surface": "Recovery request",
          "visibleState": "A formatting error is described without account lookup detail.",
          "userCan": "Correct the identifier format.",
          "outcome": null
        },
        {
          "id": "recovery_instructions",
          "kind": "status",
          "surface": "Recovery instructions",
          "visibleState": "Neutral next-step guidance is shown whether or not an account matches.",
          "userCan": "Open a received recovery link or choose support.",
          "outcome": null
        },
        {
          "id": "token_check",
          "kind": "decision",
          "surface": "Recovery link",
          "visibleState": "The recovery link is checked before a new secret can be entered.",
          "userCan": "Wait for valid or expired guidance.",
          "outcome": null
        },
        {
          "id": "expired_link",
          "kind": "error",
          "surface": "Recovery link",
          "visibleState": "The link is invalid or expired and a new-request action is visible.",
          "userCan": "Request a new recovery attempt.",
          "outcome": null
        },
        {
          "id": "new_secret",
          "kind": "screen",
          "surface": "Choose new secret",
          "visibleState": "Current requirements and a confirmation field are visible.",
          "userCan": "Enter and submit a new secret.",
          "outcome": null
        },
        {
          "id": "secret_check",
          "kind": "decision",
          "surface": "Choose new secret",
          "visibleState": "The new value is checked without exposing it.",
          "userCan": "Wait for validation or confirmation.",
          "outcome": null
        },
        {
          "id": "secret_error",
          "kind": "error",
          "surface": "Choose new secret",
          "visibleState": "The unmet requirement is described without echoing the secret.",
          "userCan": "Correct and resubmit.",
          "outcome": null
        },
        {
          "id": "access_restored",
          "kind": "terminal",
          "surface": "Recovery confirmation",
          "visibleState": "The change is confirmed and the next sign-in action is visible.",
          "userCan": "Return to sign in.",
          "outcome": "success"
        },
        {
          "id": "recovery_safe_exit",
          "kind": "terminal",
          "surface": "Recovery support",
          "visibleState": "A safe support route is available without disclosing account existence.",
          "userCan": "Leave recovery or continue through support.",
          "outcome": "safe-exit"
        }
      ],
      "edges": [
        {
          "id": "recovery_start",
          "from": "sign_in",
          "to": "recovery_form",
          "kind": "action",
          "trigger": "Choose account recovery",
          "condition": "The person cannot sign in.",
          "observableResult": "The recovery request surface opens.",
          "retryRule": "Opening the surface creates no recovery attempt."
        },
        {
          "id": "recovery_submit",
          "from": "recovery_form",
          "to": "recovery_check",
          "kind": "action",
          "trigger": "Submit the account identifier",
          "condition": "The person intentionally submits the current value.",
          "observableResult": "The request enters a neutral checking state.",
          "retryRule": "Rapid repeat submission maps to the same bounded attempt."
        },
        {
          "id": "recovery_bad_format",
          "from": "recovery_check",
          "to": "recovery_input_error",
          "kind": "result",
          "trigger": "The identifier format is invalid",
          "condition": "The value cannot be processed in its current form.",
          "observableResult": "A format correction is requested without account detail.",
          "retryRule": "No account lookup result is disclosed."
        },
        {
          "id": "recovery_correct",
          "from": "recovery_input_error",
          "to": "recovery_form",
          "kind": "recovery",
          "trigger": "Correct the identifier",
          "condition": "The person changes the invalid value.",
          "observableResult": "The form is ready for intentional resubmission.",
          "retryRule": "Correction alone sends no recovery request."
        },
        {
          "id": "recovery_neutral_result",
          "from": "recovery_check",
          "to": "recovery_instructions",
          "kind": "result",
          "trigger": "The request is accepted for neutral handling",
          "condition": "The identifier has a processable format.",
          "observableResult": "Neutral instructions avoid confirming whether an account exists.",
          "retryRule": "Repeated requests follow an explicit cooldown without changing the public message."
        },
        {
          "id": "recovery_open_link",
          "from": "recovery_instructions",
          "to": "token_check",
          "kind": "action",
          "trigger": "Open a recovery link",
          "condition": "The person has a candidate link from an authorized channel.",
          "observableResult": "The link enters validation before the new-secret form.",
          "retryRule": "Opening the same link cannot apply a change twice."
        },
        {
          "id": "recovery_support",
          "from": "recovery_instructions",
          "to": "recovery_safe_exit",
          "kind": "exit",
          "trigger": "Choose support",
          "condition": "The person cannot access or use the recovery link.",
          "observableResult": "The flow exits through a safe support path.",
          "retryRule": "Returning later begins a new bounded recovery attempt."
        },
        {
          "id": "recovery_expired",
          "from": "token_check",
          "to": "expired_link",
          "kind": "result",
          "trigger": "The link is invalid, expired, or already used",
          "condition": "The link cannot authorize a change.",
          "observableResult": "The page explains that a new request is needed.",
          "retryRule": "Refreshing cannot revive or reuse the invalid link."
        },
        {
          "id": "recovery_restart",
          "from": "expired_link",
          "to": "recovery_form",
          "kind": "recovery",
          "trigger": "Request a new link",
          "condition": "The person chooses to restart recovery.",
          "observableResult": "A fresh recovery form opens without old secret fields.",
          "retryRule": "The new attempt has a distinct identity and explicit cooldown."
        },
        {
          "id": "recovery_valid",
          "from": "token_check",
          "to": "new_secret",
          "kind": "result",
          "trigger": "The link is valid",
          "condition": "The link authorizes one bounded secret change.",
          "observableResult": "The new-secret surface opens without displaying account-sensitive detail.",
          "retryRule": "The link remains single-use after a successful change."
        },
        {
          "id": "secret_submit",
          "from": "new_secret",
          "to": "secret_check",
          "kind": "action",
          "trigger": "Submit the new secret",
          "condition": "The person enters both required values.",
          "observableResult": "The value is checked without being echoed in a result message.",
          "retryRule": "Repeat submission during checking is ignored or mapped to one attempt."
        },
        {
          "id": "secret_invalid",
          "from": "secret_check",
          "to": "secret_error",
          "kind": "result",
          "trigger": "The new secret fails a current requirement",
          "condition": "At least one stated requirement is not met.",
          "observableResult": "The unmet rule is described without exposing the submitted value.",
          "retryRule": "No change is applied for repeated invalid submissions."
        },
        {
          "id": "secret_correct",
          "from": "secret_error",
          "to": "new_secret",
          "kind": "recovery",
          "trigger": "Correct the new secret",
          "condition": "The person changes the invalid value.",
          "observableResult": "The surface is ready for a new explicit submit action.",
          "retryRule": "Editing alone does not consume the link."
        },
        {
          "id": "secret_saved",
          "from": "secret_check",
          "to": "access_restored",
          "kind": "result",
          "trigger": "The secret change is confirmed",
          "condition": "The authorized change succeeds once.",
          "observableResult": "A confirmation and return-to-sign-in action are visible.",
          "retryRule": "Replaying the same link cannot apply another change."
        }
      ],
      "acceptanceChecks": [
        "Happy: a valid single-use link reaches confirmation and the next sign-in action.",
        "Invalid: malformed identifiers and invalid secrets receive specific correction guidance without account disclosure.",
        "Retry: repeated request, link, or save actions cannot apply the change twice.",
        "Recovery: an expired link returns to a new request and inaccessible delivery can exit to support.",
        "Accessibility: focus, error text, waiting status, and confirmation remain understandable without relying on color."
      ],
      "scopeBoundary": "This map owns only visible recovery surfaces and results. Identity proofing policy, delivery-provider behavior, session revocation, fraud review, and support operations remain separate."
    },
    {
      "id": "catalog_search",
      "title": "Search and refine a catalog",
      "actor": "Visitor looking for one suitable item",
      "goal": "Reach a relevant detail page or a truthful empty result while keeping loading, failure, and refinement paths visible.",
      "entryNodeId": "catalog_home",
      "terminalNodeIds": ["item_detail", "catalog_safe_exit"],
      "nodes": [
        {
          "id": "catalog_home",
          "kind": "entry",
          "surface": "Catalog",
          "visibleState": "Search and filter controls are available with an initial item set.",
          "userCan": "Enter a query or select a filter.",
          "outcome": null
        },
        {
          "id": "results_loading",
          "kind": "status",
          "surface": "Catalog results",
          "visibleState": "A loading state preserves the current query and selected filters.",
          "userCan": "Wait or cancel the latest refinement.",
          "outcome": null
        },
        {
          "id": "results_gate",
          "kind": "decision",
          "surface": "Catalog results",
          "visibleState": "The latest request resolves as results, empty, or unavailable.",
          "userCan": "Review the resulting state.",
          "outcome": null
        },
        {
          "id": "results_list",
          "kind": "screen",
          "surface": "Catalog results",
          "visibleState": "Matching items and active refinements are visible.",
          "userCan": "Open an item or refine again.",
          "outcome": null
        },
        {
          "id": "empty_results",
          "kind": "error",
          "surface": "Catalog results",
          "visibleState": "No matches are stated with current query and removable filters.",
          "userCan": "Clear a filter, change the query, or leave safely.",
          "outcome": null
        },
        {
          "id": "results_error",
          "kind": "error",
          "surface": "Catalog results",
          "visibleState": "The latest result could not be loaded and retry is available.",
          "userCan": "Retry the same search or change the query.",
          "outcome": null
        },
        {
          "id": "item_detail",
          "kind": "terminal",
          "surface": "Item detail",
          "visibleState": "The selected item and a return-to-results path are visible.",
          "userCan": "Review the chosen item.",
          "outcome": "success"
        },
        {
          "id": "catalog_safe_exit",
          "kind": "terminal",
          "surface": "Catalog guidance",
          "visibleState": "The visitor can leave without a false match or hidden filter state.",
          "userCan": "Browse another category or end the task.",
          "outcome": "safe-exit"
        }
      ],
      "edges": [
        {
          "id": "catalog_search_start",
          "from": "catalog_home",
          "to": "results_loading",
          "kind": "action",
          "trigger": "Submit query or filter",
          "condition": "The visitor intentionally changes the result criteria.",
          "observableResult": "The current query and filters remain visible during loading.",
          "retryRule": "Only the latest request may replace the visible result set."
        },
        {
          "id": "catalog_resolve",
          "from": "results_loading",
          "to": "results_gate",
          "kind": "result",
          "trigger": "The latest result request resolves",
          "condition": "A result, empty, or failed outcome is available.",
          "observableResult": "The loading state ends and one current outcome is selected.",
          "retryRule": "A late older response cannot overwrite the latest criteria."
        },
        {
          "id": "catalog_found",
          "from": "results_gate",
          "to": "results_list",
          "kind": "result",
          "trigger": "One or more matches are available",
          "condition": "The result set matches the latest query and filters.",
          "observableResult": "Matching items and the active criteria are visible together.",
          "retryRule": "Refreshing preserves the current criteria when policy allows."
        },
        {
          "id": "catalog_empty",
          "from": "results_gate",
          "to": "empty_results",
          "kind": "result",
          "trigger": "No matches are available",
          "condition": "The latest query returns an empty set.",
          "observableResult": "A truthful empty state shows which criteria can be changed.",
          "retryRule": "Repeating unchanged criteria remains empty rather than inventing results."
        },
        {
          "id": "catalog_failed",
          "from": "results_gate",
          "to": "results_error",
          "kind": "result",
          "trigger": "The result request fails",
          "condition": "No current result set can be confirmed.",
          "observableResult": "The unavailable state is distinct from zero matches.",
          "retryRule": "Retry uses the same latest criteria until the visitor changes them."
        },
        {
          "id": "catalog_open_item",
          "from": "results_list",
          "to": "item_detail",
          "kind": "action",
          "trigger": "Open an item",
          "condition": "The chosen item is present in the current result set.",
          "observableResult": "The selected detail surface opens with a return path.",
          "retryRule": "Opening the same item is read-only and creates no duplicate action."
        },
        {
          "id": "catalog_refine",
          "from": "results_list",
          "to": "results_loading",
          "kind": "action",
          "trigger": "Change query or filters",
          "condition": "The visitor intentionally changes at least one criterion.",
          "observableResult": "The revised criteria remain visible while new results load.",
          "retryRule": "The latest refinement supersedes older in-flight requests."
        },
        {
          "id": "catalog_relax",
          "from": "empty_results",
          "to": "results_loading",
          "kind": "recovery",
          "trigger": "Clear or change criteria",
          "condition": "The visitor changes at least one empty-result constraint.",
          "observableResult": "A new result attempt starts with revised visible criteria.",
          "retryRule": "The revised criteria define a new request identity."
        },
        {
          "id": "catalog_empty_exit",
          "from": "empty_results",
          "to": "catalog_safe_exit",
          "kind": "exit",
          "trigger": "Leave the empty result",
          "condition": "The visitor chooses not to refine further.",
          "observableResult": "The task ends without presenting an unrelated item as a match.",
          "retryRule": "Returning later restores only deliberately persisted criteria."
        },
        {
          "id": "catalog_retry",
          "from": "results_error",
          "to": "results_loading",
          "kind": "recovery",
          "trigger": "Retry current search",
          "condition": "The visitor keeps the same query and filters.",
          "observableResult": "The same criteria return to a visible loading state.",
          "retryRule": "Repeated retry cannot allow an older response to win."
        }
      ],
      "acceptanceChecks": [
        "Happy: a query with matches reaches the intended detail while preserving a return path.",
        "Invalid: an empty result names the active criteria and never masquerades as a technical failure.",
        "Retry: a late old response cannot overwrite a newer query or filter selection.",
        "Recovery: empty and unavailable states each offer an appropriate next action.",
        "Accessibility: loading, result count, empty, and failure status are programmatically exposed."
      ],
      "scopeBoundary": "This map owns only the visitor's search, result, refinement, and item-selection surfaces. Catalog ingestion, ranking policy, moderation, and inventory workflow remain separate."
    },
    {
      "id": "appointment_request",
      "title": "Request an appointment",
      "actor": "Visitor requesting a fictional service slot",
      "goal": "Select an available slot, review details, and receive a truthful request confirmation or recover from changed availability.",
      "entryNodeId": "schedule_start",
      "terminalNodeIds": ["appointment_confirmed", "appointment_safe_exit"],
      "nodes": [
        {
          "id": "schedule_start",
          "kind": "entry",
          "surface": "Appointment request",
          "visibleState": "Service, date, and accessibility-support choices are available.",
          "userCan": "Choose request criteria.",
          "outcome": null
        },
        {
          "id": "availability_loading",
          "kind": "status",
          "surface": "Available times",
          "visibleState": "The selected criteria stay visible while availability is checked.",
          "userCan": "Wait or revise criteria.",
          "outcome": null
        },
        {
          "id": "availability_gate",
          "kind": "decision",
          "surface": "Available times",
          "visibleState": "Availability resolves as available, none, or unavailable to check.",
          "userCan": "Choose the next branch.",
          "outcome": null
        },
        {
          "id": "no_slots",
          "kind": "error",
          "surface": "Available times",
          "visibleState": "No matching slot is stated without implying a technical failure.",
          "userCan": "Change date or service criteria.",
          "outcome": null
        },
        {
          "id": "availability_error",
          "kind": "error",
          "surface": "Available times",
          "visibleState": "Availability could not be checked and retry is visible.",
          "userCan": "Retry the same criteria or leave safely.",
          "outcome": null
        },
        {
          "id": "slot_list",
          "kind": "screen",
          "surface": "Available times",
          "visibleState": "Current candidate slots and their time zone are visible.",
          "userCan": "Choose one slot.",
          "outcome": null
        },
        {
          "id": "contact_details",
          "kind": "screen",
          "surface": "Contact details",
          "visibleState": "Minimum required contact fields and purpose guidance are visible.",
          "userCan": "Enter details and continue.",
          "outcome": null
        },
        {
          "id": "request_review",
          "kind": "screen",
          "surface": "Review request",
          "visibleState": "Service, time zone, slot, details summary, and edit actions are visible.",
          "userCan": "Edit or submit the request.",
          "outcome": null
        },
        {
          "id": "appointment_submit",
          "kind": "status",
          "surface": "Review request",
          "visibleState": "A submission-in-progress state blocks ambiguous repeat actions.",
          "userCan": "Wait for the current result.",
          "outcome": null
        },
        {
          "id": "appointment_gate",
          "kind": "decision",
          "surface": "Appointment result",
          "visibleState": "The request resolves as accepted, slot changed, or not confirmed.",
          "userCan": "Continue to confirmation or recover.",
          "outcome": null
        },
        {
          "id": "slot_changed",
          "kind": "error",
          "surface": "Appointment result",
          "visibleState": "The selected slot is no longer available and no appointment is claimed.",
          "userCan": "Return to current availability.",
          "outcome": null
        },
        {
          "id": "appointment_error",
          "kind": "error",
          "surface": "Appointment result",
          "visibleState": "The request is not confirmed and a retry action is visible.",
          "userCan": "Retry the same request or leave safely.",
          "outcome": null
        },
        {
          "id": "appointment_confirmed",
          "kind": "terminal",
          "surface": "Appointment confirmation",
          "visibleState": "A fictional request reference, time zone, and next-step boundary are visible.",
          "userCan": "Save the reference or return home.",
          "outcome": "success"
        },
        {
          "id": "appointment_safe_exit",
          "kind": "terminal",
          "surface": "Appointment options",
          "visibleState": "The task ends without a false booking or lost criteria claim.",
          "userCan": "Leave or use another published contact route.",
          "outcome": "safe-exit"
        }
      ],
      "edges": [
        {
          "id": "availability_start",
          "from": "schedule_start",
          "to": "availability_loading",
          "kind": "action",
          "trigger": "Check availability",
          "condition": "The visitor chooses a service and date range.",
          "observableResult": "The selected criteria remain visible during checking.",
          "retryRule": "Only the latest criteria may update the slot list."
        },
        {
          "id": "availability_resolve",
          "from": "availability_loading",
          "to": "availability_gate",
          "kind": "result",
          "trigger": "Availability checking resolves",
          "condition": "Available, empty, or unavailable outcome is known.",
          "observableResult": "The waiting state ends with one distinct result branch.",
          "retryRule": "Late responses cannot replace a newer criteria set."
        },
        {
          "id": "availability_found",
          "from": "availability_gate",
          "to": "slot_list",
          "kind": "result",
          "trigger": "Candidate slots are available",
          "condition": "At least one current slot matches the selected criteria.",
          "observableResult": "Current slots and time zone are visible.",
          "retryRule": "Displaying a slot does not reserve it."
        },
        {
          "id": "availability_none",
          "from": "availability_gate",
          "to": "no_slots",
          "kind": "result",
          "trigger": "No candidate slot matches",
          "condition": "The availability check succeeds with an empty set.",
          "observableResult": "A truthful no-slots message suggests changing criteria.",
          "retryRule": "Repeated unchanged criteria remain empty."
        },
        {
          "id": "availability_failed",
          "from": "availability_gate",
          "to": "availability_error",
          "kind": "result",
          "trigger": "Availability cannot be checked",
          "condition": "No current availability result can be confirmed.",
          "observableResult": "Technical unavailability is distinct from no matching slots.",
          "retryRule": "Retry preserves the current criteria."
        },
        {
          "id": "availability_change",
          "from": "no_slots",
          "to": "schedule_start",
          "kind": "recovery",
          "trigger": "Change date or service",
          "condition": "The visitor chooses different criteria.",
          "observableResult": "The starting surface restores the prior choices for editing.",
          "retryRule": "Changing criteria creates a new availability request."
        },
        {
          "id": "availability_retry",
          "from": "availability_error",
          "to": "availability_loading",
          "kind": "recovery",
          "trigger": "Retry availability",
          "condition": "The visitor keeps the same criteria.",
          "observableResult": "The same criteria return to a visible checking state.",
          "retryRule": "Only one latest retry result can update the screen."
        },
        {
          "id": "availability_exit",
          "from": "availability_error",
          "to": "appointment_safe_exit",
          "kind": "exit",
          "trigger": "Choose another contact route",
          "condition": "The visitor does not want to retry.",
          "observableResult": "The flow ends without claiming a slot or request.",
          "retryRule": "Returning later begins a new availability check."
        },
        {
          "id": "slot_select",
          "from": "slot_list",
          "to": "contact_details",
          "kind": "action",
          "trigger": "Choose a candidate slot",
          "condition": "The slot is visible in the latest result set.",
          "observableResult": "The contact surface shows the selected slot and time zone.",
          "retryRule": "Selection alone does not reserve the slot."
        },
        {
          "id": "details_continue",
          "from": "contact_details",
          "to": "request_review",
          "kind": "action",
          "trigger": "Continue to review",
          "condition": "Required contact fields satisfy current validation.",
          "observableResult": "A review summary appears before submission.",
          "retryRule": "Returning to edit preserves only purpose-limited values."
        },
        {
          "id": "review_edit",
          "from": "request_review",
          "to": "contact_details",
          "kind": "action",
          "trigger": "Edit contact details",
          "condition": "The visitor chooses an edit action.",
          "observableResult": "The contact surface restores the review values for correction.",
          "retryRule": "Editing creates no appointment request."
        },
        {
          "id": "review_submit",
          "from": "request_review",
          "to": "appointment_submit",
          "kind": "action",
          "trigger": "Submit appointment request",
          "condition": "The visitor confirms the reviewed details.",
          "observableResult": "A submission-in-progress state replaces the active submit action.",
          "retryRule": "Repeated clicks map to the same request attempt."
        },
        {
          "id": "appointment_resolve",
          "from": "appointment_submit",
          "to": "appointment_gate",
          "kind": "result",
          "trigger": "The request attempt resolves",
          "condition": "Accepted, changed-slot, or not-confirmed result is available.",
          "observableResult": "The waiting state ends with one explicit result branch.",
          "retryRule": "A timeout remains not confirmed until reconciled."
        },
        {
          "id": "appointment_accept",
          "from": "appointment_gate",
          "to": "appointment_confirmed",
          "kind": "result",
          "trigger": "The request is accepted",
          "condition": "One fictional request reference exists for the selected slot.",
          "observableResult": "Confirmation shows the slot, time zone, and reference.",
          "retryRule": "Replaying the same attempt returns the same reference."
        },
        {
          "id": "appointment_slot_changed",
          "from": "appointment_gate",
          "to": "slot_changed",
          "kind": "result",
          "trigger": "The candidate slot changed before acceptance",
          "condition": "The selected slot cannot be confirmed.",
          "observableResult": "The page states that no appointment was confirmed.",
          "retryRule": "The old slot cannot be silently resubmitted."
        },
        {
          "id": "appointment_not_confirmed",
          "from": "appointment_gate",
          "to": "appointment_error",
          "kind": "result",
          "trigger": "The request is not confirmed",
          "condition": "No request reference can be shown safely.",
          "observableResult": "The page offers retry without a false success message.",
          "retryRule": "Retry reuses the reviewed request identity."
        },
        {
          "id": "slot_refresh",
          "from": "slot_changed",
          "to": "availability_loading",
          "kind": "recovery",
          "trigger": "Review current availability",
          "condition": "The visitor wants another current slot.",
          "observableResult": "Availability is checked again with the same service criteria.",
          "retryRule": "The changed slot is not preselected."
        },
        {
          "id": "appointment_retry",
          "from": "appointment_error",
          "to": "appointment_submit",
          "kind": "recovery",
          "trigger": "Retry the request",
          "condition": "The reviewed details and slot are unchanged.",
          "observableResult": "The same attempt returns to submission-in-progress.",
          "retryRule": "Retry cannot create a duplicate request reference."
        },
        {
          "id": "appointment_exit",
          "from": "appointment_error",
          "to": "appointment_safe_exit",
          "kind": "exit",
          "trigger": "Leave without retry",
          "condition": "The visitor chooses another route.",
          "observableResult": "The task exits without claiming an appointment.",
          "retryRule": "Returning later rechecks availability."
        }
      ],
      "acceptanceChecks": [
        "Happy: one available slot and valid review produce one fictional request reference with time zone.",
        "Invalid: no-slots, unavailable-to-check, changed-slot, and not-confirmed states remain distinct.",
        "Retry: repeated submission cannot create a duplicate request reference.",
        "Recovery: changed availability returns to a current slot check without silently selecting a replacement.",
        "Accessibility: date choices, errors, waiting states, review, and confirmation work by keyboard and expose status."
      ],
      "scopeBoundary": "This map owns only the visitor's appointment-request surfaces. Staff scheduling policy, calendar-provider delivery, payment, reminders, and fulfillment workflow remain outside it."
    },
    {
      "id": "file_upload",
      "title": "Upload and confirm one file",
      "actor": "Signed-in member adding one fictional document",
      "goal": "Select, validate, upload, review, and confirm one file or exit safely without presenting an incomplete upload as saved.",
      "entryNodeId": "file_page",
      "terminalNodeIds": ["file_confirmed", "file_safe_exit"],
      "nodes": [
        {
          "id": "file_page",
          "kind": "entry",
          "surface": "Document page",
          "visibleState": "Allowed purpose, file constraints, and upload action are visible.",
          "userCan": "Open the file selector.",
          "outcome": null
        },
        {
          "id": "file_selected",
          "kind": "screen",
          "surface": "File selection",
          "visibleState": "The local filename, declared type, size, and remove action are visible.",
          "userCan": "Submit the selected file or choose another.",
          "outcome": null
        },
        {
          "id": "file_gate",
          "kind": "decision",
          "surface": "File selection",
          "visibleState": "The selection is checked before bytes are sent.",
          "userCan": "Wait for valid or correction guidance.",
          "outcome": null
        },
        {
          "id": "file_invalid",
          "kind": "error",
          "surface": "File selection",
          "visibleState": "The rejected constraint is described and the file is not presented as uploaded.",
          "userCan": "Remove the file and choose another.",
          "outcome": null
        },
        {
          "id": "file_uploading",
          "kind": "status",
          "surface": "Upload progress",
          "visibleState": "Progress and cancel guidance are visible without claiming persistence.",
          "userCan": "Wait for the upload result.",
          "outcome": null
        },
        {
          "id": "upload_gate",
          "kind": "decision",
          "surface": "Upload result",
          "visibleState": "The attempt resolves as available for review or not confirmed.",
          "userCan": "Continue to review or retry.",
          "outcome": null
        },
        {
          "id": "upload_error",
          "kind": "error",
          "surface": "Upload result",
          "visibleState": "The upload is not confirmed and retry or remove actions are visible.",
          "userCan": "Retry the same file or leave safely.",
          "outcome": null
        },
        {
          "id": "file_review",
          "kind": "screen",
          "surface": "File review",
          "visibleState": "The sanitized display name, type, size, and remove action are visible.",
          "userCan": "Confirm or remove the uploaded file.",
          "outcome": null
        },
        {
          "id": "file_confirmed",
          "kind": "terminal",
          "surface": "Document confirmation",
          "visibleState": "The fictional document reference and next action are visible.",
          "userCan": "Return to the document list.",
          "outcome": "success"
        },
        {
          "id": "file_safe_exit",
          "kind": "terminal",
          "surface": "Document page",
          "visibleState": "The task ends without claiming an incomplete file was saved.",
          "userCan": "Leave or choose a different file later.",
          "outcome": "safe-exit"
        }
      ],
      "edges": [
        {
          "id": "file_choose",
          "from": "file_page",
          "to": "file_selected",
          "kind": "action",
          "trigger": "Choose one file",
          "condition": "The member intentionally opens the selector and chooses a file.",
          "observableResult": "The selected filename, declared type, size, and remove action appear.",
          "retryRule": "Choosing a file sends no bytes until explicit submit."
        },
        {
          "id": "file_submit",
          "from": "file_selected",
          "to": "file_gate",
          "kind": "action",
          "trigger": "Submit selected file",
          "condition": "One current file selection exists.",
          "observableResult": "The selection enters validation without showing upload progress yet.",
          "retryRule": "Rapid repeat submission maps to one selected-file attempt."
        },
        {
          "id": "file_reject",
          "from": "file_gate",
          "to": "file_invalid",
          "kind": "result",
          "trigger": "The selection violates a stated constraint",
          "condition": "Type, size, or another pre-upload rule fails.",
          "observableResult": "The exact constraint is described without claiming security inspection.",
          "retryRule": "Rejected selections are never presented as uploaded."
        },
        {
          "id": "file_reselect",
          "from": "file_invalid",
          "to": "file_page",
          "kind": "recovery",
          "trigger": "Remove rejected file",
          "condition": "The member chooses to select another file.",
          "observableResult": "The document page returns with constraints still visible.",
          "retryRule": "The rejected bytes are not reused automatically."
        },
        {
          "id": "file_accept",
          "from": "file_gate",
          "to": "file_uploading",
          "kind": "result",
          "trigger": "The selection passes pre-upload checks",
          "condition": "The file satisfies the visible client-side constraints.",
          "observableResult": "Upload progress begins without claiming server acceptance.",
          "retryRule": "The upload uses one stable attempt identity."
        },
        {
          "id": "upload_resolve",
          "from": "file_uploading",
          "to": "upload_gate",
          "kind": "result",
          "trigger": "The upload attempt resolves",
          "condition": "A reviewable or not-confirmed result is available.",
          "observableResult": "The progress state ends with one explicit result branch.",
          "retryRule": "A timeout remains not confirmed until reconciled."
        },
        {
          "id": "upload_ready",
          "from": "upload_gate",
          "to": "file_review",
          "kind": "result",
          "trigger": "The upload is available for review",
          "condition": "One sanitized file reference is available for this attempt.",
          "observableResult": "The review surface shows safe metadata and a remove action.",
          "retryRule": "Replaying the same attempt returns the same review reference."
        },
        {
          "id": "upload_failed",
          "from": "upload_gate",
          "to": "upload_error",
          "kind": "result",
          "trigger": "The upload is not confirmed",
          "condition": "No reviewable file reference can be shown safely.",
          "observableResult": "The page states that upload is not confirmed and offers retry.",
          "retryRule": "Retry reuses the same selected-file attempt when still available."
        },
        {
          "id": "upload_retry",
          "from": "upload_error",
          "to": "file_uploading",
          "kind": "recovery",
          "trigger": "Retry upload",
          "condition": "The member retries the unchanged selected file.",
          "observableResult": "The same attempt returns to visible progress.",
          "retryRule": "Retry cannot create duplicate file references."
        },
        {
          "id": "upload_exit",
          "from": "upload_error",
          "to": "file_safe_exit",
          "kind": "exit",
          "trigger": "Remove file and leave",
          "condition": "The member does not want to retry.",
          "observableResult": "The task exits without a false saved state.",
          "retryRule": "Returning later requires a new explicit selection."
        },
        {
          "id": "file_confirm",
          "from": "file_review",
          "to": "file_confirmed",
          "kind": "action",
          "trigger": "Confirm the reviewed file",
          "condition": "The member accepts the displayed safe metadata.",
          "observableResult": "The confirmation surface shows one fictional document reference.",
          "retryRule": "Repeated confirmation returns the same document reference."
        },
        {
          "id": "file_remove",
          "from": "file_review",
          "to": "file_safe_exit",
          "kind": "exit",
          "trigger": "Remove the uploaded file",
          "condition": "The member decides not to keep the reviewed file.",
          "observableResult": "The flow exits without presenting the file as retained.",
          "retryRule": "Returning later requires a new explicit upload."
        }
      ],
      "acceptanceChecks": [
        "Happy: a valid fictional file reaches review and one confirmation reference.",
        "Invalid: a rejected file names the visible constraint and never appears uploaded.",
        "Retry: retrying the same upload cannot create duplicate file references.",
        "Recovery: invalid and failed attempts can choose another file, retry, or exit truthfully.",
        "Accessibility: selection, progress, errors, review, and confirmation are keyboard reachable and programmatically exposed."
      ],
      "scopeBoundary": "This map owns only visible file-selection and upload states. Authorization, malware scanning, storage, retention, deletion, audit, and document-review workflow remain separate implementation responsibilities."
    },
    {
      "id": "notification_preferences",
      "title": "Update notification preferences",
      "actor": "Signed-in member changing optional notifications",
      "goal": "Review, change, and confirm preferences or recover from a conflict without implying provider delivery.",
      "entryNodeId": "preferences_page",
      "terminalNodeIds": ["preferences_confirmed", "preferences_safe_exit"],
      "nodes": [
        {
          "id": "preferences_page",
          "kind": "entry",
          "surface": "Notification preferences",
          "visibleState": "Current optional channels, purposes, and required notices are distinguished.",
          "userCan": "Change permitted preferences.",
          "outcome": null
        },
        {
          "id": "preferences_review",
          "kind": "screen",
          "surface": "Preference review",
          "visibleState": "Changed and unchanged preferences are summarized before save.",
          "userCan": "Edit again or confirm the changes.",
          "outcome": null
        },
        {
          "id": "preferences_saving",
          "kind": "status",
          "surface": "Preference review",
          "visibleState": "Saving is visible and the active save action is unavailable.",
          "userCan": "Wait for the result.",
          "outcome": null
        },
        {
          "id": "preferences_gate",
          "kind": "decision",
          "surface": "Preference result",
          "visibleState": "The save resolves as confirmed, stale, or not confirmed.",
          "userCan": "Continue or recover from the result.",
          "outcome": null
        },
        {
          "id": "preferences_conflict",
          "kind": "error",
          "surface": "Preference result",
          "visibleState": "A newer preference version exists and silent overwrite did not occur.",
          "userCan": "Reload the current settings before choosing again.",
          "outcome": null
        },
        {
          "id": "preferences_error",
          "kind": "error",
          "surface": "Preference result",
          "visibleState": "The update is not confirmed and retry is available.",
          "userCan": "Retry the same change or exit safely.",
          "outcome": null
        },
        {
          "id": "preferences_confirmed",
          "kind": "terminal",
          "surface": "Notification preferences",
          "visibleState": "The saved version and effective choices are visible.",
          "userCan": "Leave settings or make another deliberate change.",
          "outcome": "success"
        },
        {
          "id": "preferences_safe_exit",
          "kind": "terminal",
          "surface": "Account settings",
          "visibleState": "The task ends without claiming that an unconfirmed change was saved.",
          "userCan": "Leave or return to settings later.",
          "outcome": "safe-exit"
        }
      ],
      "edges": [
        {
          "id": "preferences_change",
          "from": "preferences_page",
          "to": "preferences_review",
          "kind": "action",
          "trigger": "Review changes",
          "condition": "At least one permitted preference differs from the loaded version.",
          "observableResult": "A before-and-after summary is visible before save.",
          "retryRule": "Reviewing creates no saved change."
        },
        {
          "id": "preferences_edit",
          "from": "preferences_review",
          "to": "preferences_page",
          "kind": "action",
          "trigger": "Edit preferences",
          "condition": "The member wants to revise the pending choices.",
          "observableResult": "The editable surface restores the pending values.",
          "retryRule": "Editing creates no saved change."
        },
        {
          "id": "preferences_submit",
          "from": "preferences_review",
          "to": "preferences_saving",
          "kind": "action",
          "trigger": "Confirm preference changes",
          "condition": "The member accepts the reviewed choices and loaded version.",
          "observableResult": "A saving state replaces the active confirm action.",
          "retryRule": "Repeated clicks map to one version-bound attempt."
        },
        {
          "id": "preferences_resolve",
          "from": "preferences_saving",
          "to": "preferences_gate",
          "kind": "result",
          "trigger": "The save attempt resolves",
          "condition": "Confirmed, stale, or not-confirmed result is available.",
          "observableResult": "The waiting state ends with one explicit result branch.",
          "retryRule": "A timeout remains not confirmed until reconciled."
        },
        {
          "id": "preferences_saved",
          "from": "preferences_gate",
          "to": "preferences_confirmed",
          "kind": "result",
          "trigger": "The current version is saved",
          "condition": "The update succeeds against the loaded version.",
          "observableResult": "The effective choices and new version are visible.",
          "retryRule": "Replaying the same attempt returns the same saved version."
        },
        {
          "id": "preferences_stale",
          "from": "preferences_gate",
          "to": "preferences_conflict",
          "kind": "result",
          "trigger": "A newer version already exists",
          "condition": "The loaded version is stale.",
          "observableResult": "The conflict is stated and no silent overwrite is claimed.",
          "retryRule": "The stale version cannot be retried without reload."
        },
        {
          "id": "preferences_failed",
          "from": "preferences_gate",
          "to": "preferences_error",
          "kind": "result",
          "trigger": "The update is not confirmed",
          "condition": "No current saved version can be presented safely.",
          "observableResult": "The page offers retry without changing the visible effective settings.",
          "retryRule": "Retry reuses the same reviewed values and loaded version."
        },
        {
          "id": "preferences_reload",
          "from": "preferences_conflict",
          "to": "preferences_page",
          "kind": "recovery",
          "trigger": "Reload current preferences",
          "condition": "The member chooses to resolve the version conflict.",
          "observableResult": "The editable surface displays the latest confirmed settings.",
          "retryRule": "Pending stale values are not silently re-applied."
        },
        {
          "id": "preferences_retry",
          "from": "preferences_error",
          "to": "preferences_saving",
          "kind": "recovery",
          "trigger": "Retry the preference update",
          "condition": "The reviewed values and loaded version are unchanged.",
          "observableResult": "The same attempt returns to a visible saving state.",
          "retryRule": "Retry cannot create duplicate versions."
        },
        {
          "id": "preferences_exit",
          "from": "preferences_error",
          "to": "preferences_safe_exit",
          "kind": "exit",
          "trigger": "Leave without retry",
          "condition": "The member does not want to retry now.",
          "observableResult": "The task exits without claiming the pending change was saved.",
          "retryRule": "Returning later reloads the confirmed version."
        }
      ],
      "acceptanceChecks": [
        "Happy: reviewed choices save against one version and the effective settings are visible.",
        "Invalid: required notices cannot be presented as optional controls.",
        "Retry: repeating one version-bound attempt cannot create duplicate updates.",
        "Recovery: a stale version reloads current settings before another deliberate change.",
        "Accessibility: channel purposes, review summary, saving, conflict, failure, and confirmation are programmatically exposed."
      ],
      "scopeBoundary": "This map owns only visible preference editing and confirmation. Consent law, required-notice policy, provider delivery, suppression, unsubscribe processing, and audit retention remain separate."
    }
  ]
}
