Add durable goal scheduling and executable loop coordination - #9
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 647aa853e0
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| PRAGMA journal_mode=WAL; | ||
| PRAGMA busy_timeout=5000; | ||
| CREATE TABLE IF NOT EXISTS goals (id TEXT PRIMARY KEY, json TEXT NOT NULL); | ||
| CREATE TABLE IF NOT EXISTS work_items (id TEXT PRIMARY KEY, goal_id TEXT NOT NULL, json TEXT NOT NULL, FOREIGN KEY(goal_id) REFERENCES goals(id) ON DELETE CASCADE); |
There was a problem hiding this comment.
When two persisted goals use the same local work item id (for example both have work-1, which the fixtures and pilot seeds do), this schema makes work_items.id globally unique, so saving the second goal replaces the first goal's work item and LoadAsync for the first goal returns an incomplete aggregate. The same keying pattern affects the other goal-scoped projection tables, so multi-goal scheduling can corrupt previously saved goals unless the primary key includes goal_id or the stored ids are made globally unique everywhere.
Useful? React with 👍 / 👎.
| ?? throw new InvalidOperationException($"Work item '{workItem.Id}' could not be leased."); | ||
|
|
||
| aggregate = (await store.LoadAsync(goalId, cancellationToken))!; | ||
| var first = await ExecuteAttemptAsync(aggregate, workItem, 1, false, cancellationToken); |
There was a problem hiding this comment.
Continue from the next persisted attempt number
For a recovered goal whose expired lease is reset to Ready after an attempt was already saved, RunAsync dispatches attempt 1 again instead of deriving the next number from aggregate.Attempts. That creates duplicate attempt numbers and reuses evidence ids like worker-1-0, so restart recovery can overwrite prior evidence and ignore the per-work-item attempt budget.
Useful? React with 👍 / 👎.
| var output = await process.StandardOutput.ReadToEndAsync(cancellationToken); | ||
| var error = await process.StandardError.ReadToEndAsync(cancellationToken); |
There was a problem hiding this comment.
Drain worker stdout and stderr concurrently
If the Python MAF worker writes enough data to stderr while stdout is still open, the child can block on the stderr pipe while this code is still waiting for stdout to finish, so the coordinator hangs even though cancellation is the only escape. This affects noisy worker failures or logging-heavy runs; start both reads before awaiting either stream (as the native verifier does) to avoid pipe-buffer deadlocks.
Useful? React with 👍 / 👎.
Summary\nAdds durable SQLite goal scheduling, recovery, evidence-gated verification, operator projections, and the executable cross-component loop coordinator.\n\n## Changes\n- Recover failed workflow states and add finite multi-repository watch state\n- Persist goals, dependencies, leases, attempts, budgets, evidence, transitions, and idempotency\n- Add deterministic verification and bounded repair policy\n- Add operator projection and MAF process worker integration\n- Add the executable LoopPilotRunner\n\n## Why\nThe orchestrator must remain the authoritative bounded control plane and must not complete goals based on model confidence alone.\n\n## Validation\n- Release build succeeded with zero warnings\n- 126 tests passed on the clean origin/main-based branch\n- Pilot runner built and generated all four evidence scenarios\n\n## Risks\n- SQLite is intentionally single-node for v1\n- Worker execution expects the companion MAF adapter\n- External actions remain approval-gated\n\n## Related\nCAS Loop Engineering milestone v1.\n\n## Reviewer notes\nStart with src/GsdOrchestrator/Loop/LoopCoordinator.cs, then Scheduling and Verification.