• 04-P's blocked_pending_human branch, 01-M's task-table indexing rationale,
    and REQ-09's boundary case all presume an autonomous dispatcher scans queued
    tasks and keeps serving the queue past a blocked one -- but no such component
    existed. org_node_lifecycle._check_concurrency (U-010) only gates a single
    trigger call; e2e_pipeline.run_end_to_end (U-014) drives exactly one task,
    synchronously, only ever called from tests.
    
    Adds src/scheduler.py: run_scheduler_once() dispatches multiple Goals via
    ThreadPoolExecutor bounded by org_concurrency_config.max_concurrent_goals,
    each worker opening its own sqlite connection (with a busy_timeout) rather
    than sharing one across threads -- U-027's SIGSEGV already proved that needs
    a hand-held lock, which would just serialize everything back to front.
    
    Also closes a gap run_end_to_end's own docstring already flagged: it never
    called close_task_done (PASS) or org_level_loop.run_fix_loop (FAIL), leaving
    every task stuck at 'validating'. finish_task_lifecycle() applies that step
    without changing run_end_to_end's own tested behavior or scope.
    
    Real-write concurrency (multiple threads, separate connections, same db
    file) is stress-tested for real in test_scheduler.py without spending API
    budget -- the actually-new risk surface here is the threading/connection
    design, not the already-validated (U-031/U-017) work itself.
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    bboonnee authored
     
    Browse File »