Add schedule promote for atomic cadence promotion
Some checks failed
ci / test (push) Failing after 13m58s
Some checks failed
ci / test (push) Failing after 13m58s
Orchestrates cadence.yml, activity-definitions, fleet schedule.yml, and activity-core sync in one command. Supports --dry-run and --fleet-only for repairing partial promotions.
This commit is contained in:
@@ -23,6 +23,7 @@ from .integrations.event_bus import (
|
||||
from .integrations.helix import HelixCorrelationAdapter, enrich_helix_correlation
|
||||
from .metrics import MetricsStore, OptimizerStore, performance_summary_markdown
|
||||
from .optimization import OptimizationLoop, MIN_SAMPLES_FOR_RECOMMENDATIONS
|
||||
from .engagement_promote import promote_engagement
|
||||
from .schedule import (
|
||||
ScheduleError,
|
||||
default_schedule_yaml,
|
||||
@@ -1534,6 +1535,105 @@ def schedule_init(
|
||||
click.echo(" Validate with: kaizen-agentic schedule validate")
|
||||
|
||||
|
||||
@schedule.command("promote")
|
||||
@click.option(
|
||||
"--engagement-repo",
|
||||
"-e",
|
||||
required=True,
|
||||
type=click.Path(exists=True, file_okay=False, path_type=Path),
|
||||
help="Customer engagement repo (e.g. coulomb-loop)",
|
||||
)
|
||||
@click.option(
|
||||
"--engagement",
|
||||
default="coulomb-loop",
|
||||
show_default=True,
|
||||
help="Engagement slug written into fleet schedule.yml headers",
|
||||
)
|
||||
@click.option(
|
||||
"--to-phase",
|
||||
type=click.Choice(["stabilize", "operate"]),
|
||||
default=None,
|
||||
help="Target phase (default: next phase after current)",
|
||||
)
|
||||
@click.option("--loop", default=None, help="Promote a single loop id only")
|
||||
@click.option("--dry-run", is_flag=True, help="Print planned actions without writing")
|
||||
@click.option("--skip-cadence", is_flag=True, help="Skip loops/*/cadence.yml updates")
|
||||
@click.option(
|
||||
"--skip-definitions", is_flag=True, help="Skip activity-definitions transforms"
|
||||
)
|
||||
@click.option("--skip-fleet", is_flag=True, help="Skip .kaizen/schedule.yml on roster")
|
||||
@click.option("--skip-sync", is_flag=True, help="Skip activity-core definition sync")
|
||||
@click.option(
|
||||
"--fleet-only",
|
||||
is_flag=True,
|
||||
help="Only update fleet schedule.yml (+ sync unless --skip-sync)",
|
||||
)
|
||||
@click.option(
|
||||
"--activity-core",
|
||||
type=click.Path(exists=True, file_okay=False, path_type=Path),
|
||||
default=None,
|
||||
help="activity-core repo root (or ACTIVITY_CORE_ROOT env)",
|
||||
)
|
||||
def schedule_promote(
|
||||
engagement_repo: Path,
|
||||
engagement: str,
|
||||
to_phase: Optional[str],
|
||||
loop: Optional[str],
|
||||
dry_run: bool,
|
||||
skip_cadence: bool,
|
||||
skip_definitions: bool,
|
||||
skip_fleet: bool,
|
||||
skip_sync: bool,
|
||||
fleet_only: bool,
|
||||
activity_core: Optional[Path],
|
||||
):
|
||||
"""Atomically promote cadence across cadence.yml, definitions, fleet, and sync."""
|
||||
if fleet_only:
|
||||
skip_cadence = True
|
||||
skip_definitions = True
|
||||
if to_phase is None:
|
||||
to_phase = "operate"
|
||||
|
||||
result = promote_engagement(
|
||||
engagement_repo,
|
||||
engagement_slug=engagement,
|
||||
to_phase=to_phase,
|
||||
loop=loop,
|
||||
dry_run=dry_run,
|
||||
skip_cadence=skip_cadence,
|
||||
skip_definitions=skip_definitions,
|
||||
skip_fleet=skip_fleet,
|
||||
skip_sync=skip_sync,
|
||||
activity_core_root=activity_core,
|
||||
)
|
||||
|
||||
if dry_run:
|
||||
click.echo("Dry run — planned actions:")
|
||||
else:
|
||||
click.echo("Promotion complete — actions:")
|
||||
|
||||
by_layer: dict[str, list[str]] = {}
|
||||
for action in result.actions:
|
||||
by_layer.setdefault(action.layer, []).append(action.description)
|
||||
|
||||
for layer in ("cadence", "definitions", "fleet", "sync"):
|
||||
items = by_layer.get(layer)
|
||||
if items:
|
||||
click.echo(f"\n[{layer}]")
|
||||
for item in items:
|
||||
click.echo(f" • {item}")
|
||||
|
||||
if result.errors:
|
||||
click.echo("\nWarnings / errors:", err=True)
|
||||
for err in result.errors:
|
||||
click.echo(f" ! {err}", err=True)
|
||||
if not result.actions:
|
||||
sys.exit(1)
|
||||
|
||||
if not result.actions and not result.errors:
|
||||
click.echo("Nothing to do — layers already aligned.")
|
||||
|
||||
|
||||
@schedule.command("list")
|
||||
@click.option("--target", "-t", default=".", help="Project root (default: current)")
|
||||
@click.option("--all", "show_all", is_flag=True, help="Include disabled entries")
|
||||
|
||||
Reference in New Issue
Block a user