export const meta = { name: 'domain-reorg-adoption', description: 'Execute the gate-approved C1-C7 domain-reorg build plan: moves, webapp split, security review, PR — no merge', whenToUse: 'Run once, after Adam gives the go for the reorg build. Requires clean dev; plan + scoping artifacts live in docs/upstream-sync/domain-reorg/.', phases: [ { title: 'Preflight', detail: 'clean tree, artifacts present, branch created', model: 'haiku' }, { title: 'C1 docs/resources', detail: 'doc moves + prompt loader + wheel check', model: 'sonnet' }, { title: 'C2 review package', detail: '9 module moves + 38 importer rewrites', model: 'sonnet' }, { title: 'C3 shims+manifest', detail: '21 shims, ci_monitor, langgraph.json, bun pin', model: 'sonnet' }, { title: 'C4 webapp split', detail: 'the critical auth-surface split', model: 'fable' }, { title: 'C4 security review', detail: 'detector fan-out + proof-or-kill verify' }, { title: 'C5 test moves', detail: 'tests// mechanical moves', model: 'sonnet' }, { title: 'C6 UI moves', detail: 'ui/src/features/ moves + import rewrites', model: 'sonnet' }, { title: 'C7 docs/ledger/memory', detail: 'docs, triage ledger, memory, Confluence check', model: 'opus' }, { title: 'PR', detail: 'push branch, open PR, final report — NO merge' }, ], } // --------------------------------------------------------------------------- // Shared context strings // --------------------------------------------------------------------------- const REPO = '/Users/adammoussa/Documents/repositories/seahaven/open-swe' const SCRATCH = '/Users/adammoussa/Documents/repositories/seahaven/open-swe/docs/upstream-sync/domain-reorg' const BRANCH = 'refactor/domain-reorg-adoption' const COMMON = ` You are executing one commit of a gate-approved build plan in ${REPO} (branch ${BRANCH}). Plan: ${SCRATCH}/reorg-build-plan.md — READ IT FIRST, plus the section of ${SCRATCH}/reorg-scoping-report.md relevant to your commit. Move-map artifacts: ${SCRATCH}/movemap-m50.txt, ${SCRATCH}/cross.json, ${SCRATCH}/forkonly.json. HARD RULES (violations = abort and report, do not improvise): - Fork file contents, upstream layout. Upstream content ONLY for the 21 structural "A" shims listed in the scoping report. - NEVER adopt upstream content for agent/webhooks/{github,linear,slack}.py, tests/conftest.py, tests/e2e/harness.py. - Use "git mv" for moves so rename tracking survives. One commit for your cascade class only; commit message follows the repo's conventional style (see recent git log), body references the plan step. - No pushes from your stage. No force operations. No edits outside your commit's scope. Do not touch docs/upstream-sync/* unless your stage says so. - Gate ladder before committing: ruff check && ruff format --check, then uv run pytest --co -q, then the stage-specific gates. If a gate fails, fix within scope; if you cannot, ABORT: git reset --hard to the pre-stage SHA you recorded at start, and report the failure. Return JSON: {ok, commit_sha, gates: {name: pass|fail|skipped}, notes, aborted_reason}` const RESULT_SCHEMA = { type: 'object', properties: { ok: { type: 'boolean' }, commit_sha: { type: 'string' }, gates: { type: 'object' }, notes: { type: 'string' }, aborted_reason: { type: 'string' }, }, required: ['ok', 'notes'], } const results = { commits: [], securityReview: null, pr: null } function ensure(stage, r) { if (!r || !r.ok) { throw new Error(`${stage} failed: ${r ? r.aborted_reason || r.notes : 'agent returned null'}`) } results.commits.push({ stage, sha: r.commit_sha, gates: r.gates, notes: r.notes }) return r } // --------------------------------------------------------------------------- // Preflight — cheap checks, haiku // --------------------------------------------------------------------------- phase('Preflight') const pre = await agent( `${COMMON} STAGE: Preflight (no commit). 1. Verify ${REPO} is on dev and dev == origin/dev (fetch first is allowed here). Tree must be clean EXCEPT untracked files under docs/upstream-sync/domain-reorg/ and .claude/workflows/, which are expected (they are committed in C7). 2. Verify the plan file, scoping report, and all three move-map artifacts exist and are non-empty. 3. Verify branch ${BRANCH} does not already exist locally or on origin. 4. Create ${BRANCH} off dev. Record the base SHA. Return JSON with ok, notes, and base_sha in notes.`, { label: 'preflight', phase: 'Preflight', model: 'haiku', effort: 'low', schema: RESULT_SCHEMA }, ) if (!pre || !pre.ok) throw new Error(`Preflight failed: ${pre ? pre.notes : 'null'}`) log('Preflight OK — branch created') // --------------------------------------------------------------------------- // C1–C3: independent-of-C4 stages, sequential commits on the shared branch // --------------------------------------------------------------------------- phase('C1 docs/resources') ensure('C1', await agent( `${COMMON} STAGE: C1 — docs/resources/assets (plan section "C1"). Moves: INSTALLATION.md and CUSTOMIZATION.md -> docs/, static/ -> assets/ (fix README refs), default_prompt.md -> agent/resources/ (+ __init__.py). Apply the importlib.resources loader hunk to the fork's prompt.py exactly as described in scoping §2b (upstream's hunk pattern, fork's file). Extra gate: build the wheel (uv build or python -m build) and verify agent/resources/default_prompt.md is inside it; if missing, add the explicit hatchling include and note it.`, { label: 'C1', phase: 'C1 docs/resources', model: 'sonnet', schema: RESULT_SCHEMA }, )) phase('C2 review package') ensure('C2', await agent( `${COMMON} STAGE: C2 — agent/review/ package (plan section "C2", scoping §2a/2b reviewer rows). git mv the 9 reviewer/style modules per the move-map (reviewer_findings.py -> agent/review/findings.py etc.), replicate upstream's import-rewire pattern on FORK content for the R<100 ones, rewrite all 38 importer files (grep for reviewer_ and review_style_ imports to find them — do not trust the count blindly), create agent/review/__init__.py exporting the fork's existing public surface. Extra gate: full reviewer/findings unit suites pass (uv run pytest tests/ -k "review or finding" plus any suite the moved modules own).`, { label: 'C2', phase: 'C2 review package', model: 'sonnet', schema: RESULT_SCHEMA }, )) phase('C3 shims+manifest') ensure('C3', await agent( `${COMMON} STAGE: C3 — graphs/runtime/providers shims + langgraph.json + CI hardening (plan section "C3"). Adopt the 21 upstream "A" shim files verbatim-then-verify: for each, confirm every import it makes resolves against FORK modules (they delegate to agent.server etc.); fix delegation targets if fork names differ. Add fork-only agent/graphs/ci_monitor.py shim following the same pattern. Retarget langgraph.json graph entrypoints to agent.graphs.* (http.app stays agent.webapp:app). Pin bun-version in .github/workflows/ci.yml to the version in ui/ (check .bun-version / package.json engines; else current stable — note which). Extra gate: timeout-bounded "make dev" boot check — all six graphs (agent, reviewer, analyzer, chat, scheduler, ci_monitor) register and the FastAPI app mounts; kill it after verifying startup logs.`, { label: 'C3', phase: 'C3 shims+manifest', model: 'sonnet', schema: RESULT_SCHEMA }, )) // --------------------------------------------------------------------------- // C4 — the critical commit. Strongest model, high effort. // --------------------------------------------------------------------------- phase('C4 webapp split') ensure('C4', await agent( `${COMMON} STAGE: C4 — FastAPI split (plan section "C4" + approved decisions 1-2). THE critical auth-surface commit. Split the fork's 2,590-line agent/webapp.py into: agent/webhooks/common.py (shared verify/dispatch helpers), agent/api/app.py (composition), agent/api/health.py (/health + /webhooks/run-complete), and per-source github_routes.py / linear_routes.py / slack_routes.py / jira_routes.py / confluence_routes.py. Atlassian Connect lifecycle + descriptor routes (/connect/*) go INTO confluence_routes.py (approved decision 2). webapp.py becomes the compatibility shim re-exporting app (mirror upstream's shim shape). Preserve EXACTLY: all signature-verification logic (GitHub HMAC, Slack, Linear, verify_jira_secret + optional HMAC/timestamp, Connect JWT/qsh), token-attribution gating, TID-COLLIDE-01 binding, the renamed _is_repo_auto_review_enabled gates, ci-autofix trigger wiring. Handlers keep module-attribute access style (common.X / service.X). Retarget the ~240 monkeypatch.setattr(webapp, ...) sites across the 11 test files + tests/conftest.py + tests/e2e/harness.py per upstream's retarget pattern (webhook_common / handler modules) — find every site by grep, not by count. Extra gates before committing: full unit suite; FULL E2E (Playwright + real langgraph dev server); residual-importer sweep — git grep for "agent.webapp"/"from agent import webapp" must return only the shim and intentional compat references (list what remains in notes).`, { label: 'C4', phase: 'C4 webapp split', model: 'fable', effort: 'high', schema: RESULT_SCHEMA }, )) log('C4 committed — entering security review (hard gate before C5)') // --------------------------------------------------------------------------- // C4 security review — detector fan-out (sonnet lenses) + proof-or-kill verifier (opus), // with a bounded fix loop (fable) per the approved failure path (new commits, no rewrites). // --------------------------------------------------------------------------- phase('C4 security review') const LENSES = [ { key: 'authz', focus: 'broken object-level auth, missing access checks, webhook signature verification gaps (GitHub HMAC / Slack / Linear / Jira shared-secret+HMAC / Connect JWT+qsh), token-attribution gating, TID-COLLIDE-01 thread binding, the _is_repo_auto_review_enabled gates' }, { key: 'injection', focus: 'untrusted webhook payload handling: parsing, header trust, SSRF-prone fetches, path handling in the moved dispatch code' }, { key: 'logic', focus: 'multi-step invariants broken by the split: dispatch ordering, dedup/replay protection, race conditions across the new module boundaries, dropped code paths (diff every moved function against its pre-split source)' }, ] const FINDINGS_SCHEMA = { type: 'object', properties: { findings: { type: 'array', items: { type: 'object' } } }, required: ['findings'], } const VERDICT_SCHEMA = { type: 'object', properties: { confirmed: { type: 'array', items: { type: 'object' } }, unverified: { type: 'array', items: { type: 'object' } } }, required: ['confirmed', 'unverified'], } let reviewRound = 0 let confirmedHighs = [] while (true) { reviewRound += 1 const c4diff = `the C4 split commit(s) on ${BRANCH} in ${REPO} (git show for each C4/C4a commit; compare moved code against pre-split agent/webapp.py at the merge base)` const found = (await parallel(LENSES.map(l => () => agent( `You are a hostile ${l.key} security auditor. Audit ONLY ${l.key} issues in ${c4diff}. Focus: ${l.focus}. Read the actual files at both revisions; for each checklist area either cite the specific safe line or file a finding {id,title,claimed_severity,file,line,data_flow,proof:{input,outcome},recommendation}. Findings must be about the SPLIT (regressions vs pre-split behavior), not pre-existing issues. Return {findings:[...]}.`, { label: `detect:${l.key}:r${reviewRound}`, phase: 'C4 security review', model: 'sonnet', schema: FINDINGS_SCHEMA }, )))).filter(Boolean).flatMap(r => r.findings) if (!found.length) { results.securityReview = { rounds: reviewRound, confirmed: [], outcome: 'clean' }; break } const verdict = await agent( `You are a skeptical exploitation verifier — you did NOT find these and are rewarded for killing weak claims. For each candidate finding on ${c4diff}, demand a concrete proof-of-exploit (specific input -> specific bad outcome, consistent with the code at HEAD of ${BRANCH}). Default to unverified when uncertain. Candidates: ${JSON.stringify(found)}. Return {confirmed:[...], unverified:[...]} keeping severity only on confirmed items.`, { label: `verify:r${reviewRound}`, phase: 'C4 security review', model: 'opus', effort: 'high', schema: VERDICT_SCHEMA }, ) confirmedHighs = (verdict?.confirmed || []).filter(f => ['critical', 'high'].includes((f.claimed_severity || f.severity || '').toLowerCase())) if (!confirmedHighs.length) { results.securityReview = { rounds: reviewRound, confirmed: verdict?.confirmed || [], unverified: verdict?.unverified || [], outcome: 'pass' } break } if (reviewRound >= 3) { results.securityReview = { rounds: reviewRound, confirmed: confirmedHighs, outcome: 'BLOCKED' } throw new Error(`Security review still has ${confirmedHighs.length} confirmed critical/high after ${reviewRound} rounds — plan failure path: fundamental-flaw handling, return to Adam. Branch left intact for inspection.`) } log(`Security round ${reviewRound}: ${confirmedHighs.length} confirmed critical/high — dispatching fix commit C4a`) ensure(`C4a-r${reviewRound}`, await agent( `${COMMON} STAGE: C4a — address confirmed security-review findings as a NEW commit on ${BRANCH} (plan failure path: no history rewrite, no force-push). Findings with proofs: ${JSON.stringify(confirmedHighs)}. Fix each within the split's scope; re-run full unit + E2E before committing.`, { label: `C4a:r${reviewRound}`, phase: 'C4 security review', model: 'fable', effort: 'high', schema: RESULT_SCHEMA }, )) } log(`Security review outcome: ${results.securityReview.outcome} after ${results.securityReview.rounds} round(s)`) // --------------------------------------------------------------------------- // HARD GATE passed — C5 and C6 (sequential commits; C6 depends only on branch order, not C5 content) // --------------------------------------------------------------------------- phase('C5 test moves') ensure('C5', await agent( `${COMMON} STAGE: C5 — tests// moves (plan section "C5", scoping §2a + §2c placements). git mv every test per the move-map; apply remaining R<100 monkeypatch retargets not already done in C4; place the 13 fork-only tests per the approved table (webhooks/, auth/, tools/, sandbox/, github/). Path-only commit — zero logic edits. Extra gate: uv run pytest --co -q collects everything (no import errors, count matches pre-move) then full unit green.`, { label: 'C5', phase: 'C5 test moves', model: 'sonnet', effort: 'low', schema: RESULT_SCHEMA }, )) phase('C6 UI moves') ensure('C6', await agent( `${COMMON} STAGE: C6 — ui/src/features/ moves (plan section "C6"). git mv per the move-map including ported/ -> features/agents/experiments|chat; rewrite @/components/agents and @/lib/agents imports across the 54 importer files AND the moved files themselves (grep-driven); swap the tsconfig/eslint exclude lists for the single experiments glob; retarget the AgentPromptBar shim; delete ui/pnpm-workspace.yaml. Fork-diverged files (PlanReview.tsx, WorkflowApprovalCard.tsx, AgentsSidebar.tsx, SidebarFilterMenu.tsx, AgentGitPanel.tsx, AutomationEditor.tsx, DiffView.tsx, CloudPromptBar.tsx) keep fork content — imports only. Extra gate: cd ui && bun install && bunx tsc --noEmit && bun run build, then Playwright E2E.`, { label: 'C6', phase: 'C6 UI moves', model: 'sonnet', schema: RESULT_SCHEMA }, )) phase('C7 docs/ledger/memory') ensure('C7', await agent( `${COMMON} STAGE: C7 — docs + ledger + memory (plan section "C7" — read its obligations verbatim; you own them). 1. Update fork CLAUDE.md / README.md / AGENTS.md path references (architecture sections naming agent/webapp.py, old test paths, ui paths). 2. Ledger: flip 8356eb34 to landed in docs/upstream-sync/triage.jsonl with branch ${BRANCH}; add re-triage notes to the 8 unblocked rows per scoping §5; make triage-render; make triage-check must pass. 3. Memory: update /Users/adammoussa/.claude/projects/-Users-adammoussa-Documents-repositories-seahaven-open-swe/memory/open-swe-upstream-triage-status.md (+ MEMORY.md hook if needed) with the new module layout summary (agent/{graphs,runtime,api,review,resources,webhooks/*_routes}, tests//, ui/src/features/) and the reorg-landed status. Memory edits are NOT part of the git commit. 4. Confluence check: via ToolSearch load the Atlassian MCP search tools; search the IT space for any page documenting this repo's module map. If found, update it; if none, or if Confluence is unreachable, record the exact outcome string ("updated page " / "no Confluence change required" / "OUTSTANDING as of — Confluence inaccessible") in your notes AND in the memory file. 5. Stage docs/upstream-sync/domain-reorg/ and .claude/workflows/domain-reorg-adoption.mjs so the plan, scoping artifacts, and this workflow ship with the exercise. Commit all repo-file changes as the C7 commit; run ruff + triage-check as gates.`, { label: 'C7', phase: 'C7 docs/ledger/memory', model: 'opus', schema: RESULT_SCHEMA }, )) // --------------------------------------------------------------------------- // PR — push and open, NO merge. Merge is Adam's (after @openswe review). // --------------------------------------------------------------------------- phase('PR') results.pr = await agent( `${COMMON} STAGE: PR (no commit). Push ${BRANCH} to origin (plain push — the pre-push hook runs security scanners; if it blocks, report, never bypass). Open a PR against dev with gh pr create --base dev. Title: "refactor: adopt upstream domain reorg (8356eb34) — fork content, upstream layout". Body MUST include: the commit-by-commit summary from this build (paste from your reading of git log), explicit review-scope callouts for C2 (reviewer-module moves) and C4 (auth-surface split), the security-review outcome (${JSON.stringify(results.securityReview?.outcome)}), the C7 Confluence-check outcome, the post-deploy verification checklist from the plan (as unchecked boxes), and "MERGE-COMMIT ONLY — do not squash/rebase". Do NOT merge, do NOT approve, do NOT comment @openswe — Adam drives the review. Return JSON: {ok, notes} with the PR URL in notes.`, { label: 'open-pr', phase: 'PR', model: 'sonnet', schema: RESULT_SCHEMA }, ) return { branch: BRANCH, commits: results.commits, securityReview: results.securityReview, pr: results.pr?.notes || 'PR step failed — branch is pushed or local; open manually', next: 'Adam: review PR (C2+C4 scope), run @openswe review, merge with a MERGE COMMIT, then run the post-deploy checklist and post results to the PR.', }