mirror of
https://github.com/Sea-Haven-Industries/open-swe.git
synced 2026-10-03 13:53:27 +00:00
C7 of the domain-reorg adoption (build plan docs/upstream-sync/domain-reorg/ reorg-build-plan.md, step C7): - CLAUDE.md / AGENTS.md: retarget architecture path references to the new layout — graph entrypoints via agent.graphs.* shims, the agent/api/ + agent/webhooks/*_routes.py FastAPI split (webapp.py now a shim), agent/review/ package, tests/<domain>/ test paths, and the new-graph/ test conventions. README.md already pointed at docs/ (C1) — no change. - triage.jsonl: flip 8356eb34 (#1726) to landed on branch refactor/domain-reorg-adoption; add re-triage notes to the 8 unblocked rows (#1732/#1761/#1744/#1748/#1742 clean, #1736/#1758/#1760 near-clean). triage.md regenerated via make triage-render. - Ship the plan, scoping report, move-map artifacts, and the domain-reorg-adoption workflow so the exercise is reproducible. Memory + Confluence handled out-of-band (not in this commit): project memory updated with the new module layout; Confluence check found no IT page documents the repo module map — no Confluence change required.
229 lines
18 KiB
JavaScript
229 lines
18 KiB
JavaScript
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/<domain>/ 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/<domain>/ 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/<domain>/, 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 <id>" / "no Confluence change required" / "OUTSTANDING as of <today> — 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.',
|
||
}
|