Repository navigation
feat(multi-core): Phase 2a — claim primitive + launchd pool scripts (tracks #880) - #882
Closed
qingyun-wu wants to merge 1 commit into
Closed
qingyun-wu wants to merge 1 commit into
qingyun-wu wants to merge 1 commit into
Conversation
…tracks #880) Phase 2a of the multi-core agent pool (#880, design in #881). Ships the two foundation pieces that are safe to land before the pool-aware skill: 1. `src/claim_task.py` — atomic-rename claim primitive. Single-FS POSIX `rename()` is atomic — no two callers both succeed. Library API: `claim(task_id, core_id, workspace=None) -> Path | None`. CLI: same semantics, exit 0/1 to indicate win/lose. Input validation rejects path-traversal (`..`, `/`, dot-prefix) so a hostile task_id can't escape `tasks/`. 2. `tests/claim-task.test.py` — 7 unit tests: happy path, missing task, double claim, **2-process race** (forked subprocesses, verifies exactly one wins), different core IDs, path-traversal validation, realistic task_id format. All pass locally. 3. `scripts/install-core-pool.sh N` — generates N launchd plists at `~/Library/LaunchAgents/com.sutando.core-<n>.plist`, kicks each via `launchctl bootstrap`. Default N=3 per owner directive. Pre-flight refuses install when the `/proactive-loop-pool` skill (Phase 2b) doesn't exist — unless `--force` is passed — so installing today can't quietly create broken pool members that loop-restart and burn quota. 4. `scripts/uninstall-core-pool.sh` — bootout + plist removal. Logs under `$SUTANDO_WORKSPACE/logs/core-*.log` preserved for post-mortem. **Critical regression caught + fixed during self-test**: the original glob `com.sutando.core-*.plist` engulfed `com.sutando.core-agent.plist` (pre-existing Sutando.app launchd agent, NOT a pool member). The uninstaller removed it before I noticed; recovery was `cp .plist.bak .plist && launchctl bootstrap`. Both scripts now use the narrower `com.sutando.core-[0-9]*.plist` pattern with a prominent comment citing the regression so future maintainers don't loosen it. Lesson saved as durable memory (`feedback_specific_globs_system_paths.md`). **Out of scope (Phase 2b, separate PR)**: - `/proactive-loop-pool` skill that wedges the claim call. - Side-effect helper done-flag gate (~10 helpers across Python+TS bridges). - Boot-time orphan-scan watchdog. - Per-session `state/cores/core-<n>/` heartbeat generalization. **Regression posture**: opt-in only. Default Sutando behavior unchanged. The pool only activates when `install-core-pool.sh N` runs AND the Phase-2b skill exists. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This was referenced May 19, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Phase 2a of the multi-core agent pool. Ships the two foundation pieces that are safe to land before the pool-aware skill:
src/claim_task.py+ 7 unit tests including a 2-process race test (forked subprocesses, verifies exactly one wins via POSIX-atomic rename).scripts/install-core-pool.sh N(default N=3) andscripts/uninstall-core-pool.sh.Stacked on #881 (the multi-core-pool design doc). Once #881 merges, rebase the base to
mainand this lands cleanly.Regression-prevention posture
install-core-pool.shruns./proactive-loop-poolskill (Phase 2b) doesn't exist on disk — unless--forceis passed — so today's install can't quietly create broken pool members that loop-restart on missing skill and burn quota.com.sutando.core-[0-9]*.plist, NOT the widercom.sutando.core-*.plist. Critical — see "Regression caught during self-test" below.$SUTANDO_WORKSPACE/logs/core-*.logkept for post-mortem.claim_task.pyrejects..,/, dot-prefixed task_id / core_id (CodeQL py/path-injection class).Regression caught + fixed during self-test
Original uninstall glob
com.sutando.core-*.plistengulfedcom.sutando.core-agent.plist— the pre-existing Sutando.app production launchd agent, NOT a pool member. Self-test removed it; recovered viacp .plist.bak .plist && launchctl bootstrap. Both scripts now usecom.sutando.core-[0-9]*.plist(numeric-suffix-only) with a prominent comment citing this regression at each glob site. Saved as durable memory (feedback_specific_globs_system_paths.md) so the lesson outlives this PR.What's NOT in this PR (Phase 2b, separate)
/proactive-loop-poolskill that wedges the claim call before task pickup.state/cores/core-<n>/heartbeat generalization.Without Phase 2b, installing the pool at N>1 would result in 3× duplicate processing of every task. The install script's pre-flight refuse blocks this — owner can
--forceif they understand the risk and want to test the launchd shape.Eval (per the always-propose-eval rule)
tests/claim-task.test.py:claim()on the same task; exactly one wins, other loses, kernel decides..,/, dot-prefix1779170589673): acceptedTest plan
python3 tests/claim-task.test.py— 7/7 passbash -n scripts/install-core-pool.shsyntax check passbash -n scripts/uninstall-core-pool.shsyntax check pass--force, errors out cleanly with usage message)--forcepath verified on temp workspacecom.sutando.core-[0-9]*.plistdoes NOT matchcom.sutando.core-agent.plistTracks #880. Phase 2b lands as a separate PR once the wedge + done-flag gate are designed.
🤖 Generated with Claude Code