mirror of
https://gh-proxy.org/https://github.com/klinsmaya/multica.git
synced 2026-11-09 01:46:46 +08:00
* fix: gate worktree mode on a declared capability, not a version string (MUL-5707) Two tasks ran in the user's own directory despite the resource being set to worktree mode. The daemon was v0.4.23 — built before the worktree code — so it json-skipped execution_mode and took the in_place path. The claim gate existed to stop exactly that and did not fire: the runtime reports `v0.4.21-24-gcd3c0bb89`, a git-describe dev build, and the version floor deliberately exempts those so `make daemon` stays unblocked. The exemption is fine for a gate whose failure mode is a missing field; it is wrong for one whose failure mode is writing to somebody's working copy. Version strings cannot answer "does this binary implement worktree mode". The daemon now answers it directly: `local-worktree-v1` joins the existing X-Client-Capabilities negotiation, and all three gates read that instead. - Claim time (authoritative): decided from the capability on that very request. A daemon without it gets the task cancelled with the reason on the row — never a silent fallback to editing the directory, which is the outcome this mode exists to prevent. - Save time and the UI cannot see a live request, so registration now records the advertised capabilities on the runtime row and both read that. One signal everywhere instead of three different guesses. Absent capabilities means an older daemon, so every path fails closed. The error names the machine's directory and says to update the Multica app there, rather than quoting version numbers the user did not choose. MIN_LOCAL_WORKTREE_CLI_VERSION stays only as the number shown in the existing 422 payload; nothing gates on it any more. Co-authored-by: multica-agent <[email protected]> * fix(handler,views): judge daemon capability by the newest runtime row (MUL-5707) Review follow-up. Both gates asked "did ANY runtime row for this daemon advertise the capability", which never stops being true: deregistering a runtime only flips the row to offline, its metadata survives, and ListAgentRuntimes returns every row. A machine that once ran a capable daemon and then downgraded keeps an old capable row next to the fresh incapable one, so the save gate and the UI would go on offering worktree mode. The claim gate still refused the task — no directory was ever at risk — but the user only found out after the run instead of at the moment they could act on it. Both sides now read the daemon's most recently seen runtime row, and a row missing the capability is never skipped: being newest is what makes it authoritative, not whether its answer is convenient. A row that never reported sorts oldest so a live one always wins. The selection lives in one place per side (daemonAdvertisesWorktree / daemonSupportsLocalWorktree) with matching semantics, because a UI that disagrees with the API offers a mode the API refuses. Also pins the bridge the whole gate rests on, which nothing covered: DaemonRegister round-trips the advertised header onto the runtime row, and re-registering WITHOUT the header clears it — the exact downgrade the save gate has to notice. The daemon's own identity-header test now asserts local-worktree-v1, so dropping it from the advertised list can never be a silent change. Corrects three places that still described the version floor as the gate: version.go, the projects-and-resources source map, and the floor test, which now pins the two surfaces that merely DISPLAY the version to quote the same release. Co-authored-by: multica-agent <[email protected]> --------- Co-authored-by: Bohan-J <[email protected]> Co-authored-by: multica-agent <[email protected]>