Split TaskDetailPage into taskDetail folder

Task 7605 · Done · Coder · created · updated

## Requirement (verbatim, epic 7555) > Break large modules into smaller and more structured ones. E.g. "Very large modules: routes/[tasks.py](http://tasks.py) has 12,867 lines and [models.py](http://models.py) has 8,770." Settled upstream (PRD = task 7553, Architecture = task 7554): split the 26 files over 3,000 lines frozen on 2026-10-18 — one domain per module, one PR per module, every caller rewritten with no shim, external contracts and user-visible UI unchanged, no size gate. This child is ONE of 21 independent PRs; no child depends on another. ## This child: `apps/web/src/pages/TaskDetailPage.tsx` (3,026 lines) → folder `apps/web/src/pages/taskDetail/` (camelCase like `components/addNode/`), NO `index.ts` barrel (Architecture §5.11, AD3 deep split) Files (re-derive line ranges at rebase): - `TaskDetailPage.tsx`: the page shell, default export, route-mode switch. - `taskDetailConstants.ts`: tabs, sx, state sets (~189–346). - `ActivityLog.tsx` (~524–835); `coldRead.ts` (~913–959); `duplicateSeed.ts` (~836–893). - `TaskDetailHeaderParts.tsx`: `AutomationName`, `DetailStamp`. - `TaskCreateView.tsx`: the create-mode branch (~2029). - `TaskDetailHeader.tsx`. - `TaskDetailTabs.tsx` plus one file per tab panel when large. - `useTaskDetailLoad.ts`: `load`, cold reads, refetch. - `useTaskDetailDerived.ts`: the derived values (~1137–1600). - `useTaskDetailActions.ts`: handlers. Extracted hooks return typed objects; sections receive props. No context provider unless a section's prop count exceeds ~12, then one documented `TaskDetailContext`. Each file opens with a one-line header comment naming what it owns. Hard constraint: rendered DOM, routes and copy stay unchanged. Hooks are extracted with their effects in the same order; nothing is memoised that was not memoised before. If part of the split cannot stay behaviour-identical, extract only what can and name the remaining hook coupling in the PR body as a deferred follow-up — never a behaviour change. Regression net: the existing 12 `TaskDetailPage.*.test.tsx` files plus `App.test.tsx` and `LiveApp` — the 12 move into the folder with the page; their `vi.mock('./pages/TaskDetailPage')`-style paths are updated; `vi.mock` lines stay in each file. Importers: `App.tsx:76,523,531,536` and `live/LiveApp.tsx:45,350` (lazy imports), `App.test.tsx:158`, `test/taskDetailTestFixtures.tsx:132`, `tabLinks.test.ts:36` (`'pages/TaskDetailPage.tsx'` → `'pages/taskDetail/TaskDetailPage.tsx'`). Comments citing `pages/TaskDetailPage.tsx::name` are updated too. ## Shared rules (Architecture §3, binding) - No barrel, alias or re-export file keeps `pages/TaskDetailPage` importable (R3). - C5 Source-reading and path-keyed tests/registries are repointed, never deleted or skipped. Discovery: `git grep -nF 'TaskDetailPage' -- apps/ tools/ infra/ packages/ '*.toml' '*.json' '*.yml' '*.sh'`; re-key every path hit. - C7 Every living-doc pointer to the moved path points at the folder or owning file; a deleted path never appears in backticks. - Every new file owns one cohesive section/concern named for it; no `utils`/`misc`/`helpers` grab-bag. - AD9 Delivery: merge lane is ON — do NOT arm auto-merge. Rebase on fresh `develop` immediately before each `pull_request_enqueue`; enqueue after every push. Watch Jaah Deploy: on failure fix and enqueue again; cancelled/superseded → leave it. - Run `./dc check full` only on the committed, rebased tree, never in parallel with `./dc test` on the same slot. - Small internal cleanups allowed only where nothing outside the page can observe them. Credentials & reach: - AC5, AC6, AC7, O4, O-patch, O-catalog, O-mappers, O-cycle, O7 build | None beyond the worktree; the slot's local `./dc` stack (project p1-6) | verified on node h2: `./dc up` exit 0; `./dc run api alembic check` → "No new upgrade operations detected."; the in-process `app.openapi()` returned 726 paths and 1,037 schemas - AC9 / AD9: PR view, enqueue, Jaah Deploy watch | `jaah-forge`, pre-authenticated for the task, plus the `pull_request_enqueue` control tool; GitHub `jaah-ai/jaah` | verified: `jaah-forge api get repos/jaah-ai/jaah/actions/workflows` from node h2 listed the "Jaah Deploy" workflow - AC10 dev UI check, O7 node-healthy check | `jaah/debug/main/operator-login` (roster; covers app.jaah.ai and app.dev.jaah.ai); env `https://app.dev.jaah.ai` | verified: `credential_get` succeeded (value not recorded); HTTPS GET of app.dev.jaah.ai from node h2 returned 200. `dev.jaah.ai` (internal ALB) timed out from h2, so it is not used. `gmind/skynet/dev` is on the roster but its base_url is an old host, so it is not used. Out of scope: Do NOT split any other file — `apps/web/src/types.ts` (2,996) and other near-threshold files are follow-ups (N2), and the frozen web test files `TaskEditForm.test.tsx`, `Tasks.test.tsx`, `AccountEditPage.test.tsx` have their own children (N7). Do NOT add a line-count ceiling, lint rule or gate (N3). Do NOT keep `pages/TaskDetailPage` importable through a barrel or alias (N4). Do NOT change rendered DOM, copy, routes, API calls or any user-visible UI (N5). No new features, dependency bumps, new state libraries or behavioural fixes riding along; a bug found while moving code is named in the PR body as a deferred follow-up (N6). Do NOT rewrite git history (N8). Not applicable to this web-only PR: AC4/O4 openapi diff, AC5 alembic check, AC11. Done means: - AC1 No §4 file remains over 3,000 lines, and no module created by the split is over 3,000 lines. — Run `git ls-files | grep -E '\.(py|ts|tsx|js|sh)$' | grep -v -E 'node_modules|alembic/versions|migrations/|packages/agent-sdk/examples/' | xargs wc -l | awk '$1>3000 && $2!="total"' | sort -rn` on `develop` after the PR; observe `pages/TaskDetailPage.tsx` absent and no path under `pages/taskDetail/` listed. Quality tightening: the page shell `TaskDetailPage.tsx` is a readable composition of sections/hooks, not a relocated 2,500-line body. - AC2 Each new module owns one domain and declares it (R2). Fails if a module is a grab-bag (`utils2`, `misc`, `part2`, `helpers` mixing domains) or its docstring names two unrelated domains. — `for f in <new files>; do head -3 "$f"; done` → every file opens with a one-line ownership header comment; reviewer (code-review lane) confirms each file's contents match its stated concern and its name. Record the file→concern table in the PR body. - AC3 Old path removed, no shim (R3). — `test ! -f apps/web/src/pages/TaskDetailPage.tsx`; `git grep -n "pages/TaskDetailPage'"` → only the route import of the new page entry (i.e. no hit on the old path; App.tsx/LiveApp lazy imports point at `pages/taskDetail/TaskDetailPage`); no `index.ts` in the folder. - AC6 Full gate green. — `./dc check full --gate-result --timeout 1500` on the committed, rebased tree → `GATE_RESULT status=pass` (includes typecheck, web build and `tools/check_context.py`). - AC7 Coverage not reduced (R6). — Before/after: `npx vitest list | wc -l` (web) → after ≥ before; cite both numbers in the PR body; all 12 `TaskDetailPage.*.test.tsx` files, `App.test.tsx` and LiveApp tests pass unmodified except for import paths. - AC8 Docs pointers current (R7). — `git grep -nF 'pages/TaskDetailPage.tsx' -- '*.md' '*.toml' '*.json' '*.yml'` → 0 hits (except git-history-only prose); `python3 tools/check_context.py` → exit 0. - AC9 Delivered one PR per module (R4). — `jaah-forge pr view <n>` → diff touches only this page (+ its moved tests, importers, docs); merged into `develop` through the merge lane after `pull_request_enqueue` (not auto-merge), shown MERGED. - AC10 Availability on dev — the product still works for the operator after each PR deploys (no flag involved; refactor ships ON by deploy). — Watch **Jaah Deploy** for the merge commit succeed on GitHub; then open `https://app.dev.jaah.ai` in a browser: Tasks list loads; open an epic and a child Task detail (TaskDetailPage) — header, description, children, comments, sessions render with no console errors; every tab switches; create a Task `[split-check P11]` via the create view, edit and save it, Start it, duplicate it, then delete both. Observe each succeeds and looks as it did before the PR (compare screenshots before/after). - AC12 Quality: the result is more navigable, not just shorter. Fails if a split produces circular-import workarounds (function-local imports added only to dodge cycles), duplicated code across new modules, or modules so thin (one trivial function) that a reader must open many files to follow one flow. — Code-review lane on the PR: no circular imports between the new files, no duplicated logic, hooks/sections each meaningful; reviewer verdict recorded in the PR body.

Outcome

Split TaskDetailPage (3,026 lines) into 19 single-concern modules under pages/taskDetail/, with no barrel; DOM unchanged. Quick gate green; the 443 page tests pass; test count 10363 before and after. Both review lanes pass. Visual check: renders as before, no console errors. PR #6139 queued in the lane (rebased over the agent.py split). Draft #7671 filed.

Pull request

Artifacts

Activity

  • Draft
  • Ready
  • Runner started
  • Runner ended (done)