feat(engine): Phase 4 — scheduler tick, gate chain, platform git, budget

The AI workforce engine's driver. One tick moves every ready task one step:
a turn, a gate, or a platform merge. The AI never runs git.

- scheduler.py: tick() over TURN_STAGES/MERGE_STAGES; selection caps
  (per-org 3, global 8); optimistic advance so two workers cannot both win;
  worktree created for code pipelines, released on completion/cancel/failure
  (kept during error_review); budget pause before any turn is spent; merge
  conflict back-off; transient-failure retries then the manager's error turn.
- gates.py: diff guard (empty/.git/CI/symlink/oversize), no-progress hash,
  tests in the sandbox, green gate that only trusts a green tests row or an
  explicit waiver. Every verdict is a gate_results row + a task.gate event.
  Fixed forbidden_paths: lstrip("./") stripped all leading dots, hiding
  .git and .github from the guard.
- container_engine.build_scheduler + worker drives the engine tick.
- ManagerOutcome.error_kind; TaskSpendRepository.spend_for_task.
- New settings engine_max_concurrent_turns, engine_max_turns_per_org,
  engine_tests_timeout_seconds, engine_max_merge_conflicts,
  engine_max_task_credits (+ .env.example).
- tests: test_engine_gates.py (13), test_engine_flow.py (11).

Checks: pytest 746 passed/1 skipped, ruff clean, mypy clean (160 files).
This commit is contained in:
mjalmoudy94
2026-10-14 19:02:58 +03:30
parent 581f703910
commit 36564e3f2b
13 changed files with 2563 additions and 67 deletions
+12
View File
@@ -104,7 +104,19 @@ PLATFORM_INVITE_TTL_HOURS=72
# >>> agent-2 (AI workforce engine)
ENGINE_MAX_TOOL_CALLS_PER_TURN=40
#: Consecutive malformed replies tolerated before a turn gives up.
ENGINE_MAX_PROTOCOL_RETRIES=3
ENGINE_TURN_TIMEOUT_SECONDS=900
#: Turns running at once, globally and per organization.
ENGINE_MAX_CONCURRENT_TURNS=8
ENGINE_MAX_TURNS_PER_ORG=3
#: The tests gate's own budget, and how many merge conflicts before the
#: manager takes over.
ENGINE_TESTS_TIMEOUT_SECONDS=600
ENGINE_MAX_MERGE_CONFLICTS=3
#: Per-task credit ceiling (0 = no ceiling). An organization that runs out is
#: paused, not left spinning.
ENGINE_MAX_TASK_CREDITS=0
ENGINE_MAX_CYCLES=6
ENGINE_MAX_EMPLOYEES=20
ENGINE_TICK_SECONDS=10