fix: session-scope the SDD workspace so concurrent sessions on one checkout stop colliding#1952
fix: session-scope the SDD workspace so concurrent sessions on one checkout stop colliding#1952mvanhorn wants to merge 11 commits into
Conversation
…s object
Codex auto-discovers a plugin's hooks/hooks.json whenever the Codex
manifest has no `hooks` field: load_plugin_hooks falls back to a
hardcoded DEFAULT_HOOKS_CONFIG_FILE = "hooks/hooks.json" and registers
it. hooks/hooks.json is the Claude Code SessionStart hook, it is tracked
in this repo, and the Codex marketplace installs the whole repo root
(source url "./"), so the fallback re-registered the SessionStart hook
and its install-time trust prompt on Codex.
Removing the Codex hook file and the manifest `hooks` pointer (commit
"Remove Codex hooks") did not disable the hook on Codex — it removed the
explicit declaration that was overriding the fallback, so the fallback
took over and found the Claude hooks/hooks.json.
Declare an empty inline hooks object ({}) in .codex-plugin/plugin.json.
It parses as an empty inline hook set and stops Codex reaching the
auto-discovery fallback. An absent field, an empty array ([]), and an
empty inline list all collapse back to the fallback, so the value must
be exactly {}.
Update the test to assert the manifest declares hooks: {} (and that
hooks/hooks.json exists, which is what makes the declaration necessary),
replacing the prior assertion that the field was absent — which passed
while the hook was still being auto-discovered.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… docs hooks/session-start-codex has had no caller since "Remove Codex hooks" (obra#1845) deleted hooks-codex.json and its manifest registration; the Codex manifest now declares an empty hooks object so Codex registers no session-start hook at all. The script is Codex-specific dead code — nothing executes it on Codex or any other harness. - Delete hooks/session-start-codex. - tests/hooks/test-session-start.sh: drop the two Codex cases that are redundant with the generic session-start tests (nested-format and the legacy-warning omission are already covered by the Claude Code cases). Re-point the "wrapper dispatches" case to the live `session-start` script so run-hook.cmd dispatch coverage — used by Claude Code and Cursor in production — is preserved rather than lost. - docs/porting-to-a-new-harness.md: Codex is no longer a Shape A (shell-hook) harness, so re-anchor that worked example to Cursor (a live shell-hook harness that demonstrates the same per-harness field, schema, and matcher variance) and mark Codex as native skill discovery with no session-start hook. Clears the references to the deleted hooks-codex.json. - docs/windows/polyglot-hooks.md: the "check hooks-codex.json" pointer referenced a file deleted in obra#1845; re-point to hooks-cursor.json. RELEASE-NOTES.md keeps its historical mention of hooks-codex.json (it accurately records what that release did). The tests/codex-plugin-sync fixtures build their own synthetic session-start-codex and test the sync mechanism generically, so they are intentionally left as-is. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…x portal packaging
|
Reporter of #1942 here — thanks for picking this up, @mvanhorn. Flagging that this is still blocking real work downstream. We run multiple concurrent Claude Code sessions against one checkout, and the shared We are currently mitigating locally with a PreToolUse hook that denies bare Worth noting the ecosystem has converged on this independently — #1888 (same collision, different angle), #1986 (cross-task subagent reuse), and #1905 (scope briefs by plan file, closed today). That suggests the underlying issue is being hit by more than one user. Anything we can do to help move this along — testing against our multi-session setup, splitting it into a smaller reviewable change, or narrowing scope to just the session-scoping fix? Happy to help; mostly wanting to make sure it does not stall silently. |
|
Thanks for the detailed report - really useful to know it's actively biting a concurrent-session setup, and good to see the convergence with #1888/#1986/#1905. Narrowing this to just the session-scoping fix sounds like the right way to get it moving, so I'll split that out as a focused change. And yes, testing against your multi-session setup once it's ready would be great - I'll ping you when the scoped version is up. |
|
Actually, scratch the 'split it out' - I went back through it and this PR is already scoped to just the session-scoping fix. The sdd-workspace script now keys the workspace dir on a sanitized session id (SUPERPOWERS_SDD_SESSION, falling back to CLAUDE_CODE_SESSION_ID, then to the shared dir), so concurrent sessions on one checkout get separate brief/report/diff/progress dirs instead of clobbering each other. The other three files are just the task-brief consumer, the SKILL doc, and tests - nothing broad bundled in. It's mergeable as-is, so no restructuring needed. Testing it against your multi-session setup would be the ideal confirmation; the knob is SUPERPOWERS_SDD_SESSION if you want to force distinct ids. |
Summary
Session-scope the SDD workspace so concurrent sessions on one checkout stop colliding.
Why this matters
The v6.1.0 change (#1780) that moved SDD scratch out of
.git/introduced a cross-session data race. Thesdd-workspacehelper resolves the artifact dir viagit rev-parse --show-toplevel-><working-tree-root>/.superpowers/sdd, andtask-brief,review-package, and theprogress.mdledger all write into it keyed only by task number (task-N-brief.md,progress.md). That directory is shared by every agent session running against the same checkout, so concurrent sessions silently overwrite each other's files: an implementer subagent can receive another plan's task text (the reporter sawtask-3-brief.mdholding a different plan's "Deploy the bridge" task) and a controller's `progrTesting
Changes are scoped to the files named in the fix; added or updated tests where the project has a suite, and matched existing conventions.
AI was used for assistance.
Fixes #1942