Add schedule promote for atomic cadence promotion
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:
2026-06-19 01:57:56 +02:00
parent c04f4eedc9
commit 0c2df43a2f
6 changed files with 853 additions and 12 deletions

View File

@@ -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")