feat(ORCH-026): task dependencies (B waits for A) + single-repo merge serialization
Level A — merge/deploy serialization within one repo: reuse the existing ORCH-043/065 merge-lease (no new mechanism); the only new logic is an unconditional pre-merge rebase in check_branch_mergeable — under the held lease, auto_rebase_onto_main is ALWAYS called when premerge_rebase_always (default True), not just when the branch is behind. No-op on an up-to-date branch (rebase keeps HEAD, force-with-lease -> "Everything up-to-date", CI not triggered). Kill-switch off -> ORCH-043 behaviour 1:1. Level B — declarative task dependencies: additive job_deps table (CREATE ... IF NOT EXISTS, no live-DB migration); claim_next_job gate (NOT EXISTS) defers a job whose depends-on tasks are not yet 'done' without occupying a max_concurrency slot; inert on empty job_deps -> zero regression. New leaf src/task_deps.py (never-raise): is_task_ready (fail-open), DFS cycle detection + Blocked/alert, declare/ingest_plane_relations (db source never hits the network on the hot path), snapshot. Telegram waiting-line, /queue observability, reconciler skip + cycle backstop, reaper untouched. Invariants unchanged: STAGE_TRANSITIONS, QG_CHECKS registry (dep gate is a claim_next_job врезка, not a registered QG), DB schema of existing tables, HTTP endpoints; non-self repos remain a no-op on empty deps/scope. Flags: ORCH_PREMERGE_REBASE_ALWAYS, ORCH_TASK_DEPS_ENABLED, ORCH_TASK_DEPS_SOURCE. Docs: docs/architecture/README.md, CLAUDE.md, .env.example, CHANGELOG.md, adr-0015. Tests: tests/test_orch026_*.py (64 tests); full suite 991 green. Refs: ORCH-026 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -673,8 +673,19 @@ def check_branch_mergeable(repo: str, work_item_id: str, branch: str) -> tuple[b
|
||||
return False, reason
|
||||
|
||||
try:
|
||||
# ORCH-026 (Level A, A-2): proactive pre-merge rebase. When
|
||||
# premerge_rebase_always is on, ALWAYS rebase onto the CURRENT
|
||||
# origin/main under the held lease — even when branch_is_behind_main
|
||||
# says "not behind". The ancestor check can miss a divergence
|
||||
# (squash/force-push history, ORCH-073 phantom-merge class), so an
|
||||
# unconditional rebase is a deterministic anti-phantom: it guarantees
|
||||
# B carries A's code before merge. auto_rebase_onto_main is a cheap
|
||||
# no-op on an already up-to-date branch (rc 0, push up-to-date, CI not
|
||||
# retriggered). Kill-switch off -> 1:1 the ORCH-043 short-circuit
|
||||
# below (rebase only when behind).
|
||||
always = bool(getattr(settings, "premerge_rebase_always", False))
|
||||
# Double-check under the lease: another task may have just merged.
|
||||
if not merge_gate.branch_is_behind_main(repo, branch):
|
||||
if not always and not merge_gate.branch_is_behind_main(repo, branch):
|
||||
logger.info("check_branch_mergeable: %s up-to-date with main", branch)
|
||||
return True, "branch up-to-date with main"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user