Provider Notifications
Provider notifications are delivery facts around Fairway handoffs and review completion signals. They are not reviews, task status changes, merge decisions, push decisions, deploy decisions, or release approvals.
Capability Boundary
Provider capabilities are session and surface scoped. One Codex app session may
have send_message_to_thread and read_thread; another project/session may
not. Agents must verify the tool surface they actually have before claiming a
reviewer or coordinator thread was steered.
If direct thread tooling is unavailable, record the Fairway handoff or notification state and route through the coordinator/control track. Do not claim direct delivery from chat memory alone.
External Notifier Interface
[[external_notifiers]] defines optional notifier endpoints for
operator-controlled notification workflows. Dry-run rendering remains available
for all enabled notifiers, and reviewed mode = "send" notifiers can deliver
through bounded adapters:
fairway notify notifiers [--include-disabled]
fairway notify dry-run --notifier <name> --task <task-id> --domain <domain> [--template <name>] [--record-intent]
fairway notify send --notifier <name> --task <task-id> --domain <domain> [--template <name>] [--target <label>]
notify dry-run renders the notification request from a configured fixed
template label. With --record-intent, it records a notification row with state
intent and template metadata only. It does not store arbitrary wake prompt
text for later replay, send Slack, email, Teams, webhook, or provider-thread
messages, record notification_delivered, or give the read-only dashboard send
authority.
notify send is the real-delivery adapter path. It is available only for
explicitly configured mode = "send" notifiers with delivery-capable types
(log or webhook). Destinations and webhook bearer tokens are environment
variable values resolved at send time; Fairway records the notifier name,
domain, fixed template label, state, and a safe target label/env var name, not
URLs, tokens, arbitrary prompts, transcripts, generated content, or raw tool
bodies. The optional CLI --target override is a display label only and is
restricted to letters, digits, dots, dashes, and underscores. Send records
sent before the adapter call, then records notification_delivered or
notification_failed. Configured rate limits count send attempts and also
degrade to notification_failed evidence so a missed delivery remains visible
as a durable wait. The dashboard remains read-only and never invokes this path.
Notification States
intent: notification is planned but not yet attempted.handoff_recorded: Fairway recorded a durable handoff, but no provider delivery proof exists.sent: a provider send was attempted and is waiting for acknowledgement.notification_delivered: adapter/provider delivery proof exists.thread_steered: direct thread tooling was available and a message was posted to the target thread.acknowledged: the target acknowledged receipt.review_acknowledged: the reviewer/control lane acknowledged receipt.review_recorded: the notification is superseded by a matching Fairway review.failed: delivery failed; a reason is required.notification_failed: delivery failed; a reason is required.
For required review domains, Fairway treats handoff_recorded, missing
notification rows, sent without acknowledgement, failed, and
notification_failed as notification-blocked until the notification is
delivered, thread-steered, acknowledged, or the review is recorded. A Fairway
handoff is durable queue state; it is not proof that a reviewer or control
thread was contacted.
Completion Handback Signal
When a delegated provider closes a slice and the next required action belongs to another actor, use a completion handback instead of relying on chat state:
fairway record completion-handback FW-123 \
--to coordinator \
--next-action "decide whether to schedule the next live window" \
--completion-state blocked-with-follow-up \
--evidence .fairway/artifacts/FW-123/closeout.md \
--approval-boundary "implementation handback only" \
--provider codex \
--target 019e... \
--state thread_steered
The helper writes a normal handoff plus a linked task_notifications row. Task
detail and coordinator plan show whether the handback is still pending,
delivered, or failed. Pending cross-role completion handbacks block terminal
closeout until a delivered state or an explicit failure state is recorded; a
clean Fairway task status alone is not proof that the next actor was informed.
The handback record does not grant approval, merge, deploy, provider wake, or
dashboard send authority.
Implemented reference: FW-187 added the durable completion handback
notification model over existing handoff and notification rows, including
delivery/failure proof before cross-role terminal closeout.
If a completion handback becomes obsolete, record an explicit supersede marker instead of deleting or ignoring it:
fairway record completion-handback-supersede FW-123 \
--handoff-id 42 \
--replacement-handoff-id 43 \
--reason "new closeout handback carries the current next action" \
--evidence .fairway/artifacts/FW-123/supersede.md
The command writes immutable completion-handback-superseded evidence. Task
detail and audit history still show the old handback, the reason, replacement
handoff id, evidence path, and timestamp. Coordinator plan and notification
audit no longer treat the superseded handback as an active wait. For
non-terminal tasks, Fairway refuses supersede cleanup unless a replacement
handoff is named or the task already has an explicit blocked status decision.
This prevents hiding an unresolved handoff on still-active work.
Dashboard task detail projects the same completion-handback rows and coordinator closeout waits as read-only state. It shows next owner/action, completion state, task/live-window context, delivery state, stale age, provider target, and suggested CLI action, but it never sends the handback or wake prompt.
--completion-state records the outcome being handed back, separate from
notification delivery. Supported outcomes include done, reviewed,
merge-ready, blocked-with-follow-up, monitor-completed,
live-window-closeout, and live-window-next-decision. Coordinator plan uses
the same [coordinator].notification_ack_timeout clock as review/provider
notification waits to mark pending completion handbacks stale. It also projects a
live-window closeout or next-decision checkpoint with no completion handback
as a closeout-to-next-owner wait, so operator closeout cannot disappear into
silent idle when the control thread was not woken.
Implemented reference: FW-188 added closeout wait surfacing for pending
completion handbacks and live-window closeout checkpoints, including stale
visibility based on [coordinator].notification_ack_timeout.
fairway coordinator tick --completion-handback-wake is the bounded wake
surface for these stale waits. It renders fixed prompts from the current
completion-handback/coordinator-plan rows. With --send, it records a
coordinator-domain notification with a stable completion_handback_wake
signature; a prior successful signature suppresses duplicates. If the next owner
has no provider target, the tick records notification_failed with the same
signature. The dashboard does not call this path and remains display-only.
Review Completion Resume Signal
When all required review domains for a task are approved, Fairway can surface a
review-complete next action. The coordinator plan includes the task id, commit,
approved domains, missing domains, and suggested fairway merge-ready <task-id>
command.
The signal is bounded. It is suppressed after matching coordinator delivery or
acknowledgement is recorded, and it appears again if the task commit or review
set changes. Use the review_signature value printed by fairway coordinator plan or fairway task-detail <task-id> in the notification reason:
fairway record notification FW-123 \
--domain coordinator \
--provider codex \
--target 019e... \
--state thread_steered \
--reason "review_complete review_signature=<current-review-signature>"
The commit alone is not sufficient acknowledgement because a task can gain or change required review domains without changing the implementation commit.
The signal does not authorize merge, push, CI, deploy, release, or task completion. Those remain explicit coordinator/operator actions guarded by Fairway evidence, review, workflow, and merge-ready checks.
Review Wait Wake Signals
fairway review-waits wake is a bounded provider-notification surface for
parked review waits. It renders a fixed prompt from current review-wait rows:
Review wait update for <task-id>:
- Task status: <status>
- <domain>: <state>
Next action:
1. Re-run fairway review-waits list --task <task-id>.
2. Follow the status-aware review-wait guidance in the prompt.
3. Do not treat review-wait resolution as task closeout unless task-level gates
support it.
Without --send, the command is dry-run output for a coordinator or provider
adapter. With --send, it records a task_notifications row on the
coordinator domain using the current review-wait signature. A matching
previous successful notification suppresses duplicates. If no wake target is
configured, dry-run output names mapping_required; --send records
notification_failed with the signature and action=mapping_required instead
of claiming delivery. Resolved review waits on a blocked, in-progress, todo, or
otherwise non-review task produce review-wait-only guidance naming the task
status; they do not tell operators to run merge-ready or continue closeout.
Blocking stale or notification_failed waits instruct operators to address
the review-wait blocker before closeout.
The dashboard does not call this path. Dashboard review-wait state and SSE events remain read-only visibility surfaces.
Lifecycle Audit
fairway audit notifications [--task <task-id>] [--all] is the read-only
operator report for provider notification lifecycle state. It projects rows from
existing Fairway facts: review waits, completion handbacks, generic wait rows,
coordinator plan rows, handoffs, reviews, task status, provider targets, and
task_notifications. It does not add a notification table, wait table, wake
queue, or scheduler store.
The report distinguishes handoff_recorded, sent,
notification_delivered, thread_steered, review_recorded, failed,
notification_failed, stale, acknowledged, terminal, and superseded cases.
Rows include task id, target domain or role, provider and target, latest handoff
id, latest notification id, stale age, expected next action, and whether a wake
target is missing and needs mapping_required remediation. A
fixed-template recovery command such as recording delivery proof, recording a
failure reason, or repairing provider routing.
By default the audit shows actionable unresolved rows and suppresses terminal,
resolved, delivered, superseded, and other non-actionable acknowledgement
history. Unresolved completion handbacks remain visible even when their latest
linked notification state is acknowledged, review_acknowledged, or
review_recorded; those states are not completion-handback delivery proof.
--all includes the suppressed rows for forensic review. The command is
visibility only: it does not send provider messages, approve reviews, close
tasks, mutate dashboard state, or authorize merge, push, deploy, release, live
execution, or provider wake delivery.