# Delivery 5 lifecycle convergence — Batch C

## Caller audit

- `StateTransitionButton` is exported only through `admin/src/components/index.js`; no production direct consumer was found.
- `DeadlineIndicator` is constructed by `AssignmentCard`, whose existing `getElement()` use remains unchanged. Its stable root now exposes the lifecycle-owner seam consumed by list-region subtree cleanup, so assignment refresh and region destruction clear the owned interval.
- `WorkflowTimeline` is exported through the barrel and is constructed in `pages/my-assignments.js` for cached history and revalidation results. Both existing `new WorkflowTimeline({ events, expandable: true }).getElement()` calls remain byte-identical.

## Design notes

- Each component now owns idempotent `mount`, `update`, and `destroy` methods while retaining its legacy entry points.
- Updates preserve the public root node and replace its children after recursively destroying lifecycle-owning dropped nodes.
- State-transition confirmation/focus callbacks and pending promise completion are scoped to a mount generation. State-changing updates close confirmations and reset in-flight UI.
- Deadline intervals are singular, generation-scoped, cleared by destroy, and restarted by mount/update when a valid deadline exists.
- Timeline headers use explicitly tracked listeners; replacement and destruction unbind them before dropped subtree cleanup.

## Test inventory

- `statetransitionbutton-lifecycle.test.js`: 8 tests covering lifecycle, all-option combined/default updates, confirmation reset, double-submit, async/timer generation behavior, legacy guards, and listener cleanup.
- `deadlineindicator-lifecycle.test.js`: 6 tests covering root/mount behavior, the public owner seam, all-option defaults, interval singularity/cleanup, subtree cleanup, legacy guards, and resurrection.
- `workflowtimeline-lifecycle.test.js`: 3 tests covering the production contract, update/default parity, stale header unbinding, nested badge cleanup, legacy update guards, and resurrection.
- `region-presets.test.js`: 2 added tests covering nested lifecycle-owner teardown during list refresh and final region destruction.

## Verification evidence

All tests and release gates below ran through the registry-selected remote builder.

- Focused Vitest before review: 3 files and 16 tests passed. After the review repair, the DeadlineIndicator and RegionPresets focus run passed 2 files and 39 tests.
- Mutation sweep: all 43 original active lifecycle mutants and 3 additional review-repair mutants were killed; restored focused baselines exited 0. One attempted root-recursion mutation was behavior-equivalent because `destroyed` is set before recursive cleanup and was excluded from the active inventory.
- Full admin Vitest after repair: 72 files and 905 tests passed with `--maxWorkers=2`. After merging the landing-time `origin/master`, the integrated suite passed 73 files and 913 tests with the same worker cap.
- ESLint: all 4 changed source components and 4 focused test files passed.
- Deterministic production build: two clean Webpack 5.104.1 builds passed before review repair with `admin/dist/js/main.js` MD5 `8dcf5e0f075d367f5930b1a18eed328d`. After merging landing-time `origin/master`, two clean integrated builds passed with MD5 `80ddd2f04fc1445f10a7fc84392a1997`; every main/editor manifest asset existed.
- UI inventory after the landing-time master merge: 124 modules, 54 components, 17 pages, 0 unclassified modules, 0 direction violations, 1,378 legacy-class entries, 2 search controls, and 2 duplicate IDs; `--check` passed.
- UI gate: passed with 4 changed files in scope and no new violations.
- Independent `gpt-5.6-sol` review found one high-severity live-caller leak: list refresh/destruction dropped AssignmentCard deadline indicators without teardown. The stable DeadlineIndicator owner seam and ListRegionPreset recursive cleanup/remove hook repair it; focused tests and all gates were rerun afterward.
- Factory stages: PHP syntax, test, PHPCS, PHPStan, admin lint, build, and UI architecture all passed. The prepared remote snapshot did not expose `origin/master`; its PHPCS/UI baseline was therefore `HEAD`. This batch changes no PHP, and the separately run UI gate above retained its normal changed-file scope.

## Deliberately unchanged

- Existing public constructor, factory, legacy method, markup, and My Assignments call signatures are retained.
- Generated assets were rebuilt through the normal admin production build rather than edited or merged by hand.
