Ceremony Scheduling¶
Sprint ceremonies bridge the sprint lifecycle with the meeting protocol system. The ceremony scheduling subsystem provides a pluggable strategy architecture that determines when and why ceremonies fire, how sprints auto-transition, and how velocity is measured -- all configurable per project, per department, and per ceremony.
Motivation¶
Synthetic agents operate orders of magnitude faster than human teams. A 14-day sprint with bi-weekly retrospectives assumes human pace. Agents can finish an entire sprint backlog in minutes, which means:
- Velocity tracking breaks:
story_points / duration_daysbecomes meaningless when velocity is effectively infinite. - Ceremonies miss context: A weekly standup fires long after the work it should reflect on is done.
- Sprint boundaries create idle time: Agents waiting for a calendar tick, or sprint boundaries are ignored entirely.
- One size does not fit all: A solo founder agent needs minimal ceremony overhead, while an enterprise template needs predictable cadence.
The ceremony scheduling system solves this by making the scheduling paradigm itself pluggable. Users choose (or templates ship) the strategy that matches their workflow rhythm.
Design Decisions¶
All scheduling paradigms are pluggable strategies. The system ships eight
scheduling strategies (task-driven, calendar, hybrid, event-driven,
budget-driven, throughput-adaptive, external-trigger, milestone-driven)
behind a single CeremonySchedulingStrategy protocol. Users select the
strategy that fits their workflow at the project, department, or per-ceremony
level.
Why pluggable:
- Different templates naturally want different rhythms (startup vs. enterprise).
- The
CeremonySchedulingStrategyprotocol adds minimal implementation cost per strategy while maximizing flexibility. - Users can switch strategies between sprints without any code changes.
Key decisions:
- Templates can configure strategies at multiple levels. The 3-level config
resolution (project / department / per-ceremony) feeds into strategy
selection, but the effective
CeremonySchedulingStrategyis resolved and locked per sprint. - Each strategy defines its own velocity unit. There is no forced
normalization to points/sprint. Each strategy ships a default
VelocityCalculator(e.g. task-driven usespts/task, calendar usespts/day). Users can override via settings. - Ceremony triggering integrates with coordination via the protocol's
lifecycle hooks (
on_task_completed,on_external_event). TheCeremonyEvalContextis extensible for coordination metadata. Detailed interaction patterns are deferred to the coordination integration phase. - Strategy is locked per-sprint. Changes take effect at the next sprint start, with a migration notification to the responsible role.
Architecture Overview¶
TaskEngine --[TaskStateChanged]--> CeremonyScheduler
|
Sprint lifecycle <--[auto-transition]----+
|
SprintCeremonyConfig --[bridge]--> MeetingTypeConfig
|
MeetingScheduler.trigger_event()
The CeremonyScheduler is a coordination layer in engine/workflow/ that:
- Receives task completion events (and other lifecycle events) from the engine.
- Delegates scheduling decisions to the active CeremonySchedulingStrategy.
- Bridges ceremony configs into
MeetingTypeConfigfor the existing MeetingScheduler to execute. - Manages sprint auto-transitions when strategy-specific conditions are met.
The CeremonyScheduler does not replace MeetingScheduler -- it translates
sprint ceremony semantics into meeting system primitives.
Scheduling Strategies¶
Eight pluggable strategies are available behind the CeremonySchedulingStrategy
protocol. Each strategy defines its own ceremony trigger logic, sprint
auto-transition behavior, and default velocity unit.
Task-Driven¶
Ceremonies fire at task-count milestones. Sprints complete when tasks reach terminal status, not on a timer. Natural fit for agent speed.
sprint:
ceremony_policy:
strategy: task_driven
ceremonies:
- name: sprint_planning
# fires on sprint_start (one-shot)
policy_override:
strategy_config:
trigger: sprint_start
- name: standup
# fires every 5 task completions
policy_override:
strategy_config:
trigger: every_n_completions
every_n_completions: 5
- name: retrospective
# fires on sprint_end (all tasks done)
policy_override:
strategy_config:
trigger: sprint_end
Auto-transition: ACTIVE to IN_REVIEW when task completion count reaches
the configured transition_threshold fraction of total tasks.
Default velocity unit: points per task (pts/task).
Best for: fast-moving agents, minimal overhead, solo founders, startups, data pipelines.
Calendar¶
Traditional time-based scheduling using MeetingFrequency intervals.
Ceremonies fire on a wall-clock cadence regardless of task progress.
sprint:
ceremony_policy:
strategy: calendar
strategy_config:
duration_days: 14
ceremonies:
- name: standup
frequency: daily
- name: retrospective
frequency: bi_weekly
Auto-transition: ACTIVE to IN_REVIEW at the duration_days boundary.
Task completion does not trigger transition.
Default velocity unit: points per day (pts/day).
Best for: client-facing schedules, fixed reporting cadences, consultancies.
Hybrid (First Wins)¶
Both calendar and task-driven triggers exist on each ceremony. Whichever fires first wins and resets the cadence counter. Calendar provides a heartbeat floor; task counts provide a throughput ceiling.
sprint:
ceremony_policy:
strategy: hybrid
ceremonies:
- name: standup
frequency: per_sprint_day # calendar floor
policy_override:
strategy_config:
every_n_completions: 10 # task ceiling
- name: retrospective
frequency: bi_weekly
# also fires on sprint_end
Auto-transition: whichever comes first -- task completion threshold or calendar duration boundary.
Default velocity unit: points per sprint (pts/sprint).
Best for: teams that need predictability with throughput responsiveness, dev shops, product teams, enterprises.
Event-Driven¶
Ceremonies subscribe to engine events (sprint_started, task_completed,
board_state_changed, sprint_backlog_empty) with configurable debounce.
No fixed schedule -- ceremonies fire reactively.
sprint:
ceremony_policy:
strategy: event_driven
strategy_config:
debounce_default: 5
ceremonies:
- name: standup
policy_override:
strategy_config:
on_event: task_completed
debounce: 5 # batch: fire once per 5 events
- name: retrospective
policy_override:
strategy_config:
on_event: sprint_backlog_empty
Auto-transition: on a configured event (e.g. sprint_backlog_empty).
Default velocity unit: points per sprint (pts/sprint).
Best for: flexible project-based work, agencies, composable with the MessageBus.
Budget-Driven¶
Ceremonies fire at cost-consumption thresholds. Ties directly into the existing budget module (cost tracking, quota degradation, CFO optimization).
sprint:
ceremony_policy:
strategy: budget_driven
strategy_config:
standup_at_budget_pct: [25, 50, 75]
review_at_budget_pct: [50]
retro_at_budget_pct: [100]
Auto-transition: when sprint budget is exhausted (100% consumed) or when a configured budget threshold is crossed.
Default velocity unit: points per currency unit (pts/EUR).
Best for: cost-conscious organizations where every agent action has a real dollar cost. Ensures ceremonies happen proportionally to spend.
Throughput-Adaptive¶
Ceremonies fire when the team's throughput rate changes significantly. Not "every N tasks" but "when pace anomaly detected." Like an automated burndown chart monitor.
sprint:
ceremony_policy:
strategy: throughput_adaptive
strategy_config:
velocity_drop_threshold_pct: 30 # standup when velocity drops 30%
velocity_spike_threshold_pct: 50 # review when velocity spikes 50%
measurement_window_tasks: 10 # rolling window for rate calc
Auto-transition: when task completion rate stabilizes after final tasks complete (no anomaly-based transition -- uses a completion threshold like task-driven).
Default velocity unit: points per task (pts/task), with rate-of-change
as a secondary metric.
Best for: discovery/research work where pace varies wildly. Ceremonies fire when something changes, not on a fixed schedule.
External-Trigger¶
Ceremonies fire on external signals: webhooks, CI/CD events, git events, MCP tool invocations. Bridges the synthetic org with real-world development workflows.
sprint:
ceremony_policy:
strategy: external_trigger
strategy_config:
sources:
- type: webhook
endpoint: /hooks/ceremony
- type: git_event
events: [push, tag]
ceremonies:
- name: code_review
policy_override:
strategy_config:
on_external: pr_merged
- name: retrospective
policy_override:
strategy_config:
on_external: release_published
Auto-transition: on a configured external signal (e.g. deploy_complete).
Default velocity unit: points per sprint (pts/sprint).
Best for: integration with real-world dev workflows, CI/CD-driven organizations.
Milestone-Driven¶
Ceremonies fire at semantic project milestones rather than task counts or time. Milestones are defined as tags on tasks or task groups.
sprint:
ceremony_policy:
strategy: milestone_driven
strategy_config:
milestones:
- name: feature_complete
ceremony: sprint_review
- name: code_freeze
ceremony: retrospective
- name: release_candidate
ceremony: sprint_planning
Auto-transition: at a configured milestone (e.g. all tasks tagged
release_candidate are complete).
Default velocity unit: points per sprint (pts/sprint).
Best for: phased delivery, release-oriented workflows, open-source projects with async contributors.
Protocol Interfaces¶
CeremonySchedulingStrategy¶
The primary pluggable interface. Implementations provide stateless evaluation methods plus optional lifecycle hooks for stateful strategies.
@runtime_checkable
class CeremonySchedulingStrategy(Protocol):
"""Pluggable strategy for ceremony scheduling."""
# -- Core evaluation (stateless, called per event) --
def should_fire_ceremony(
self,
ceremony: SprintCeremonyConfig,
sprint: Sprint,
context: CeremonyEvalContext,
) -> bool:
"""Evaluate whether a ceremony should fire right now."""
...
def should_transition_sprint(
self,
sprint: Sprint,
config: SprintConfig,
context: CeremonyEvalContext,
) -> SprintStatus | None:
"""Return target status if sprint should auto-transition, else None."""
...
# -- Lifecycle hooks (optional, for stateful strategies) --
async def on_sprint_activated(
self, sprint: Sprint, config: SprintConfig,
) -> None: ...
async def on_sprint_deactivated(self) -> None: ...
async def on_task_completed(
self, sprint: Sprint, task_id: str, story_points: float,
context: CeremonyEvalContext,
) -> None: ...
async def on_task_added(
self, sprint: Sprint, task_id: str,
) -> None: ...
async def on_task_blocked(
self, sprint: Sprint, task_id: str,
) -> None: ...
async def on_budget_updated(
self, sprint: Sprint, budget_consumed_fraction: float,
) -> None: ...
async def on_external_event(
self, sprint: Sprint, event_name: str,
payload: Mapping[str, Any],
) -> None: ...
# -- Metadata --
@property
def strategy_type(self) -> CeremonyStrategyType: ...
def get_default_velocity_calculator(self) -> VelocityCalcType: ...
def validate_strategy_config(
self, config: Mapping[str, Any],
) -> None: ...
Design rationale: The protocol is intentionally feature-rich with many hooks. Simple strategies (task-driven, calendar) implement no-op hooks. Complex strategies (external-trigger, throughput-adaptive) use hooks to subscribe to events or track rate metrics. This ensures future strategies have maximum flexibility without protocol changes.
VelocityCalculator¶
Pluggable velocity computation. Each strategy ships a default calculator, but users can override.
@runtime_checkable
class VelocityCalculator(Protocol):
"""Pluggable velocity computation."""
def compute(self, record: VelocityRecord) -> VelocityMetrics:
"""Compute velocity metrics from a single sprint record."""
...
def rolling_average(
self, records: Sequence[VelocityRecord], window: int,
) -> VelocityMetrics:
"""Compute rolling average over recent sprints."""
...
@property
def calculator_type(self) -> VelocityCalcType: ...
@property
def primary_unit(self) -> str: ...
Shipped implementations:
| Calculator | Primary unit | Strategy default for |
|---|---|---|
TaskDrivenVelocityCalculator |
pts/task |
task_driven, throughput_adaptive |
CalendarVelocityCalculator |
pts/day |
calendar |
MultiDimensionalVelocityCalculator |
pts/sprint (+ secondary) |
hybrid |
BudgetVelocityCalculator |
pts/EUR |
budget_driven |
PointsPerSprintVelocityCalculator |
pts/sprint |
event_driven, external_trigger, milestone_driven |
Configuration¶
CeremonyPolicyConfig¶
A unified policy model that bundles strategy, velocity, and transition settings. Appears at three levels for hierarchical override resolution.
class CeremonyPolicyConfig(BaseModel):
"""Ceremony scheduling policy."""
strategy: CeremonyStrategyType | None = None
strategy_config: Mapping[str, Any] | None = None
velocity_calculator: VelocityCalcType | None = None
auto_transition: bool | None = None
transition_threshold: float | None = None # (0.0, 1.0]
3-Level Resolution¶
ceremony.policy_override ?? department.ceremony_policy ?? sprint_config.ceremony_policy
(most specific) (department scope) (project default)
Field-by-field resolution via resolve_ceremony_policy(): each field is
resolved independently from the most specific level that provides a non-None
value. If no level provides a value, the framework default applies.
Example:
# Project default: task-driven, auto-transition at 100%
workflow:
sprint:
ceremony_policy:
strategy: task_driven
auto_transition: true
transition_threshold: 1.0
departments:
marketing:
# Override: calendar for marketing
ceremony_policy:
strategy: calendar
engineering:
# Inherits task_driven from project default
ceremonies:
- name: standup
# Inherits department/project strategy
- name: retrospective
policy_override:
# Per-ceremony: always event-driven for retros
strategy: event_driven
Resolution for marketing's standup: calendar (from department).
Resolution for engineering's standup: task_driven (from project).
Resolution for any department's retrospective: event_driven (per-ceremony).
Runtime Mutability¶
Strategies are locked per sprint. Changes take effect at the next sprint start. This prevents confusing mid-sprint behavior changes.
When a strategy change is pending:
- A migration notification is sent to the responsible role (scrum master, department head, or whoever manages the task list).
- A warning is displayed: the change will take effect at the next sprint start and may cause initial optimization issues in the first few sprints until the new cadence stabilizes.
- The responsible role may need to reorder or reorganize the backlog for the new system.
CeremonyScheduler Service¶
The CeremonyScheduler is a runtime coordination service that:
- Owns ceremony trigger state: completion counters, fired-once tracking, activation timestamps. This state is ephemeral (resets per sprint, not persisted).
- Delegates decisions: calls
strategy.should_fire_ceremony()andstrategy.should_transition_sprint()on events. - Bridges to meetings: converts ceremony triggers into
MeetingScheduler.trigger_event()calls. - Returns transitioned sprints: follows the immutable pattern -- returns
a new
Sprintinstance if auto-transition occurred.
class CeremonyScheduler:
async def activate_sprint(
self, sprint: Sprint, config: SprintConfig,
strategy: CeremonySchedulingStrategy,
*, velocity_history: tuple[VelocityRecord, ...] = (),
) -> StrategyMigrationInfo | None: ...
async def deactivate_sprint(self) -> None: ...
async def on_task_completed(
self, sprint: Sprint, task_id: str, story_points: float,
) -> Sprint: ...
Ceremony-to-Meeting Bridge¶
Pure functions convert SprintCeremonyConfig into MeetingTypeConfig:
- Frequency-based ceremonies map to periodic
MeetingTypeConfig. - Trigger-based ceremonies map to event-triggered
MeetingTypeConfigwith deterministic event names:ceremony.<name>.<sprint_id>. - Protocol type, token budget, and participants carry through.
Velocity Tracking¶
VelocityRecord Extensions¶
VelocityRecord captures all available dimensions regardless of strategy:
| Field | Type | Description |
|---|---|---|
sprint_id |
NotBlankStr |
Reference to completed sprint |
sprint_number |
int |
Sequential sprint number |
story_points_committed |
float |
Points planned |
story_points_completed |
float |
Points delivered |
duration_days |
int |
Sprint duration in calendar days |
task_completion_count |
int \| None |
Tasks completed (new) |
wall_clock_seconds |
float \| None |
Real elapsed time (new) |
budget_consumed |
float \| None |
Cost consumed (new) |
Strategies populate what applies. None fields indicate the dimension is
not tracked by the active strategy.
Strategy Velocity Defaults¶
Each strategy declares a default VelocityCalcType. Users can override
via CeremonyPolicyConfig.velocity_calculator.
| Strategy | Default velocity | Unit |
|---|---|---|
| task_driven | TASK_DRIVEN |
pts/task |
| calendar | CALENDAR |
pts/day |
| hybrid | MULTI_DIMENSIONAL |
pts/sprint + secondary |
| event_driven | POINTS_PER_SPRINT |
pts/sprint |
| budget_driven | BUDGET |
pts/EUR |
| throughput_adaptive | TASK_DRIVEN |
pts/task + rate |
| external_trigger | POINTS_PER_SPRINT |
pts/sprint |
| milestone_driven | POINTS_PER_SPRINT |
pts/sprint |
Strategy Change and Velocity Window¶
When the ceremony strategy changes between sprints:
- The velocity rolling-average window resets (previous records used a different unit/calculation).
- A strategy change is logged at INFO level using the
SPRINT_CEREMONY_STRATEGY_CHANGEDevent. The velocity rolling-average window resets; prior records are preserved but their computed metrics no longer carry over. - Historical
VelocityRecorddata is preserved (raw dimensions are always stored). Only the computed velocity resets.
Template Defaults¶
Each built-in template ships with a default ceremony strategy that matches its persona. Users can override via settings.
| Template | Default strategy | Rationale |
|---|---|---|
solo_founder |
task_driven |
1 agent, minimal ceremony overhead |
startup |
task_driven |
Speed matters, iterate fast |
dev_shop |
hybrid |
Client deadlines + throughput responsiveness |
product_team |
hybrid |
Sprint cadence + task responsiveness |
agency |
event_driven |
Deliverable-oriented, project-based |
full_company |
hybrid |
Enterprise predictability + throughput |
research_lab |
throughput_adaptive |
Discovery pace varies wildly |
consultancy |
calendar |
Client expects fixed reporting schedules |
data_team |
task_driven |
Pipeline/batch completion oriented |
Observability¶
Event constants in synthorg.observability.events.workflow:
| Event | Description |
|---|---|
SPRINT_CEREMONY_SCHEDULED |
Ceremony scheduled (existing) |
SPRINT_CEREMONY_TRIGGERED |
Ceremony triggered by strategy evaluation |
SPRINT_CEREMONY_SKIPPED |
Ceremony evaluation returned false |
SPRINT_AUTO_TRANSITION |
Sprint auto-transitioned by strategy |
SPRINT_CEREMONY_SCHEDULER_STARTED |
CeremonyScheduler activated for sprint |
SPRINT_CEREMONY_SCHEDULER_STOPPED |
CeremonyScheduler deactivated |
SPRINT_CEREMONY_BRIDGE_CREATED |
Ceremony config bridged to meeting type |
SPRINT_CEREMONY_POLICY_RESOLVED |
3-level policy resolution completed |
SPRINT_CEREMONY_STRATEGY_CHANGED |
Strategy change detected between sprints |
VELOCITY_TASK_DRIVEN_NO_TASK_COUNT |
VelocityRecord has no task_completion_count for task-driven calculation |
VELOCITY_CALENDAR_NO_DURATION |
CalendarVelocityCalculator received a record with zero duration_days (defensive) |
VELOCITY_MULTI_NO_TASK_COUNT |
MultiDimensionalVelocityCalculator: no task_completion_count |
VELOCITY_MULTI_NO_DURATION |
MultiDimensionalVelocityCalculator received a record with zero duration_days (defensive) |
SPRINT_CEREMONY_EVENT_DEBOUNCE_NOT_MET |
Event-driven strategy debounce threshold not yet met |
SPRINT_CEREMONY_EVENT_COUNTER_INCREMENTED |
Event-driven strategy incremented an internal event counter |
SPRINT_CEREMONY_BUDGET_THRESHOLD_CROSSED |
Budget-driven strategy detected a budget threshold crossing |
SPRINT_CEREMONY_BUDGET_THRESHOLD_ALREADY_FIRED |
Budget-driven strategy skipped an already-fired threshold |
SPRINT_AUTO_TRANSITION_BUDGET |
Sprint auto-transitioned due to budget exhaustion |
VELOCITY_BUDGET_NO_BUDGET_CONSUMED |
BudgetVelocityCalculator: record has None or zero budget_consumed |
SPRINT_CEREMONY_THROUGHPUT_BASELINE_SET |
Throughput-adaptive strategy established baseline rate |
SPRINT_CEREMONY_THROUGHPUT_DROP_DETECTED |
Throughput-adaptive strategy detected a velocity drop |
SPRINT_CEREMONY_THROUGHPUT_SPIKE_DETECTED |
Throughput-adaptive strategy detected a velocity spike |
SPRINT_CEREMONY_THROUGHPUT_COLD_START |
Throughput-adaptive strategy in cold start (baseline not yet established) |
SPRINT_CEREMONY_EXTERNAL_EVENT_RECEIVED |
External-trigger strategy received an external event |
SPRINT_CEREMONY_EXTERNAL_EVENT_MATCHED |
External-trigger strategy matched an external event to a ceremony |
SPRINT_CEREMONY_EXTERNAL_SOURCE_REGISTERED |
External-trigger strategy registered event sources |
SPRINT_CEREMONY_EXTERNAL_SOURCE_CLEARED |
External-trigger strategy cleared event sources |
SPRINT_CEREMONY_MILESTONE_ASSIGNED |
Task assigned to a milestone |
SPRINT_CEREMONY_MILESTONE_UNASSIGNED |
Task removed from a milestone |
SPRINT_CEREMONY_MILESTONE_COMPLETED |
All tasks in a milestone are complete |
SPRINT_CEREMONY_MILESTONE_NOT_READY |
Milestone has no tasks assigned -- cannot fire |
SPRINT_AUTO_TRANSITION_MILESTONE |
Sprint auto-transitioned at a milestone completion |
Implementation Roadmap¶
Shipped in #961 (Foundation)¶
CeremonySchedulingStrategyprotocol (all hooks, maximally extensible)VelocityCalculatorprotocolCeremonyStrategyTypeenum (all 8 members)CeremonyPolicyConfig+ResolvedCeremonyPolicy+resolve_ceremony_policy()CeremonyEvalContext(rich evaluation context)CeremonySchedulerservice- Ceremony-to-meeting bridge functions
TaskDrivenStrategyreference implementationTaskDrivenVelocityCalculatorreference implementationVelocityCalcTypeenum,VelocityMetricsmodelVelocityRecordextensions (task_completion_count, wall_clock_seconds, budget_consumed)SprintConfig+SprintCeremonyConfigextensions (ceremony_policy, policy_override)- Observability event constants
- This design page
Shipped in #969 + #970 (Calendar + Hybrid Strategies)¶
CalendarStrategy-- time-based ceremony firing usingMeetingFrequencyintervalsCalendarVelocityCalculator--pts/daywith duration-weighted rolling averagesHybridStrategy-- first-wins between calendar (floor) and task-driven (ceiling) triggersMultiDimensionalVelocityCalculator--pts/sprintwithpts_per_task,pts_per_day,completion_ratiosecondaries- Observability event constants (
VELOCITY_CALENDAR_NO_DURATION-- defensive, for invalid/unvalidated records only,VELOCITY_MULTI_NO_TASK_COUNT,VELOCITY_MULTI_NO_DURATION-- defensive, for invalid/unvalidated records only)
Implemented in #971 + #972 (Event-Driven + Budget-Driven Strategies, integration pending)¶
EventDrivenStrategy-- reactive ceremony firing on engine events with configurable debouncePointsPerSprintVelocityCalculator--pts/sprintfor event-driven and external-trigger strategiesBudgetDrivenStrategy-- ceremony firing at cost-consumption thresholdsBudgetVelocityCalculator--pts/EURwith budget-weighted rolling averages- Observability event constants (
SPRINT_CEREMONY_EVENT_DEBOUNCE_NOT_MET,SPRINT_CEREMONY_EVENT_COUNTER_INCREMENTED,SPRINT_CEREMONY_BUDGET_THRESHOLD_CROSSED,SPRINT_CEREMONY_BUDGET_THRESHOLD_ALREADY_FIRED,SPRINT_AUTO_TRANSITION_BUDGET,VELOCITY_BUDGET_NO_BUDGET_CONSUMED)
Note: The
CeremonySchedulerdoes not yet wire all lifecycle hooks (on_task_added,on_task_blocked,on_budget_updated,on_external_event). Until scheduler integration is complete, these strategies' event counters will not increment for those event types. Scheduler integration is tracked in follow-up work.
Implemented in #973 + #974 (Throughput-Adaptive + External-Trigger Strategies, integration pending)¶
ThroughputAdaptiveStrategy-- ceremony firing when rolling throughput rate drops or spikes beyond configured thresholds (velocity_drop_threshold_pct, velocity_spike_threshold_pct, measurement_window_tasks). Baseline rate established from first full window, frozen per sprint. Default velocity calculator:TaskDrivenVelocityCalculator.ExternalTriggerStrategy-- ceremony firing on named external signals (webhooks, git events, MCP invocations). Event matching viacontext.external_eventsandon_external_eventlifecycle hook buffer. Source registration is declarative. Default velocity calculator:PointsPerSprintVelocityCalculator.- Observability event constants (
SPRINT_CEREMONY_THROUGHPUT_BASELINE_SET,SPRINT_CEREMONY_THROUGHPUT_DROP_DETECTED,SPRINT_CEREMONY_THROUGHPUT_SPIKE_DETECTED,SPRINT_CEREMONY_THROUGHPUT_COLD_START,SPRINT_CEREMONY_EXTERNAL_EVENT_RECEIVED,SPRINT_CEREMONY_EXTERNAL_EVENT_MATCHED,SPRINT_CEREMONY_EXTERNAL_SOURCE_REGISTERED,SPRINT_CEREMONY_EXTERNAL_SOURCE_CLEARED)
Note: Like #971 + #972, the
CeremonySchedulerdoes not yet wire all lifecycle hooks for these strategies. Scheduler integration is tracked in follow-up work.
Shipped in #975 + #976 + #980 (Milestone-Driven + Template Defaults + Department Overrides)¶
MilestoneDrivenStrategy-- ceremony firing when all tasks tagged with a milestone are complete. Milestone-to-task assignment viaon_external_event(milestone_assign/milestone_unassign). Edge-triggered (each milestone fires exactly once per sprint). Configurabletransition_milestonefor sprint auto-transition. Default velocity calculator:PointsPerSprintVelocityCalculator.- Template default ceremony strategy assignments for all 9 builtins (solo_founder/startup/data_team: task_driven, dev_shop/product_team/full_company: hybrid, agency: event_driven, research_lab: throughput_adaptive, consultancy: calendar).
- Per-department
ceremony_policyoverride inTemplateDepartmentConfigandDepartmentmodels. Department-level overrides merge field-by-field with project default viaresolve_ceremony_policy(). - Observability event constants (
SPRINT_CEREMONY_MILESTONE_ASSIGNED,SPRINT_CEREMONY_MILESTONE_UNASSIGNED,SPRINT_CEREMONY_MILESTONE_COMPLETED,SPRINT_CEREMONY_MILESTONE_NOT_READY,SPRINT_AUTO_TRANSITION_MILESTONE)
Note: Like #973 + #974, the
CeremonySchedulerdoes not yet wire all lifecycle hooks for the milestone-driven strategy. Scheduler integration is tracked in follow-up work.
Shipped in #978 (Strategy Migration UX)¶
StrategyMigrationInfofrozen model (sprint_id, previous/new strategy, velocity_history_size)detect_strategy_migration()pure function for change detectionformat_migration_warning()andformat_reorder_prompt()pure text formattersnotify_strategy_migration()async best-effort notification viaAgentMessengerCeremonyScheduler.activate_sprint()captures previous strategy type before deactivation, returnsStrategyMigrationInfo | NoneSPRINT_CEREMONY_STRATEGY_CHANGEDevent logged on detection- Strategy-aware velocity calculator default in
resolve_ceremony_policy()(STRATEGY_DEFAULT_VELOCITY_CALCmapping) - Explicit
velocity_calculatorin all 9 builtin template ceremony policies
Shipped in #979 (Dashboard UI)¶
- Ceremony policy API controller: project-level policy query, resolved policy with field-level origin tracking, active strategy query
- Department ceremony-policy endpoints: GET/PUT/DELETE per-department overrides in departments controller
- 7 ceremony policy settings in coordination namespace (ceremony_strategy, ceremony_strategy_config, ceremony_velocity_calculator, ceremony_auto_transition, ceremony_transition_threshold, dept_ceremony_policies, ceremony_policy_overrides)
- Ceremony policy settings page at
/settings/coordination/ceremony-policywith project policy editor, department overrides panel, per-ceremony overrides panel - Shared UI components: PolicySourceBadge (field origin indicator), InheritToggle (inherit/override switch)