# Delivery 5 lifecycle batch A

## Caller audit

Exact `rg -n -F 'TranslationProgress' admin/src` caller evidence:

```text
admin/src/pages/translate-posts.js:14:    getTranslationProgressBar,
admin/src/pages/translate-posts.js:15:    getTranslationProgressLabel,
admin/src/pages/translate-posts.js:17:    TranslationProgressCompletion,
admin/src/pages/translate-posts.js:18:    TranslationProgressView,
admin/src/pages/content-translate.js:22:    getTranslationProgressBar,
admin/src/pages/content-translate.js:23:    getTranslationProgressLabel,
admin/src/pages/content-translate.js:25:    IndeterminateTranslationProgress,
admin/src/pages/content-translate.js:26:    TranslationProgressCompletion,
admin/src/pages/content-translate.js:27:    TranslationProgressView,
admin/src/pages/string-translate.js:19:    getTranslationProgressBar,
admin/src/pages/string-translate.js:20:    getTranslationProgressLabel,
admin/src/pages/string-translate.js:22:    IndeterminateTranslationProgress,
admin/src/pages/string-translate.js:23:    TranslationProgressCompletion,
admin/src/pages/string-translate.js:24:    TranslationProgressView,
admin/src/components/index.js:107:    default as TranslationProgress,
```

Those callers use the existing progress helpers and view factories; their signatures and markup were left unchanged.

Exact barrel evidence: `admin/src/components/index.js:6:export { default as AnimatedItem, AnimatedList } from './AnimatedItem.js';`. No runtime caller was changed.

Exact barrel evidence: `admin/src/components/index.js:41:export { default as GridTable } from './GridTable.js';`. No runtime caller was changed.

Exact caller evidence: `admin/src/components/ColorField.js:11:import { openColorPicker } from './ColorPickerModal.js';` and `admin/src/components/index.js:15:export { openColorPicker } from './ColorPickerModal.js';`. `ColorField` continues to call `openColorPicker(currentColor, onSelect)`; its public no-return contract was left unchanged.

## TranslationProgress

The class now owns a stable progress root and has idempotent `mount()`, guarded `update()`, and idempotent `destroy()`. `render()` retains its established clear-and-append behavior. `translationprogress-lifecycle.test.js` discriminates mount idempotence, `translationId`, `progressData`, `container`, combined updates, construct parity, root identity, destruction, remounting, post-remount updates, and detachment.

The helper/view exports remain stateless render/query helpers because they have no listeners, timers, deferred work, or owned mutable DOM.

## AnimatedItem

The returned wrapper now has idempotent `mount()`, guarded in-place `update()`, and idempotent `destroy()`. Its construct-time `tag` remains construct-only because an element's tag cannot be changed in place without replacing the public wrapper node. `animateditem-lifecycle.test.js` discriminates mount idempotence without sibling reordering, children/control identity, `type`, falsy `staggerIndex`, `className`, combined parity, destruction/detachment, remounting, and post-remount updates.

## GridTable

The class now retains its rendered wrapper and has idempotent `mount()`, guarded `update()`, and idempotent `destroy()`. Rendering remains compatible with the existing `render`, `renderEmpty`, and `renderLoading` methods. `gridtable-lifecycle.test.js` discriminates columns, class name, empty message, data, row renderer, combined parity, root identity, destruction/detachment, remounting, and post-remount rendering.

## ColorPickerModal

`openColorPicker` creates an internal lifecycle owner with initial `mount()` and idempotent `destroy()`. It unbinds input and swatch handlers, destroys its buttons and modal, and invalidates callbacks on teardown. Its private `update()` method and post-destroy remount branch were removed because `openColorPicker` returns no instance and no internal caller reaches either path. The `select()` destroyed-state guard was likewise removed: teardown unbinds and destroys the button, leaving no public route to invoke `select()` after destruction. `colorpickermodal-lifecycle.test.js` now discriminates action-button teardown and delegation to `Modal.destroy()` in addition to the existing public opening, input/preset, listener, stale-callback, and select/teardown coverage.

Gates and mutation sweeps are run by the orchestrator, not by me.

## Review round 2

- `TranslationProgress.render()` now returns without mutating after `destroy()`.
- `GridTable.render()`, `renderEmpty()`, and `renderLoading()` now return the retained element without mutating after `destroy()`.
- `GridTable` now preserves only its root across renders, replaces child content wholesale, and destroys lifecycle-owning descendants before removal so row handlers are refreshed.
- `AnimatedItem.update()` applies constructor defaults when `type`, `staggerIndex`, or `className` are explicitly undefined.
- The `ColorPickerModal` architecture entry now records its implemented `mount/destroy` lifecycle.

## Orchestrator gate receipt (measured)

- Mutation sweep: 22 mutants applied individually (update-branch neutering, mount destroyed-reset removal, parentNode-guard removal, destroy-remove removal, GridTable syncChildren node replacement, ColorPickerModal unbind/button-destroy/modal-destroy/onClose removal, TranslationProgress render-clear removal) — every mutant KILLED, file restored and re-diffed clean after each; an earlier round left 12 survivors, which drove this repair round (3 unreachable paths were deleted instead of tested: ColorPickerModal `update()`, its `select()` destroyed-guard, and its mount-resurrection branch — the instance is module-internal and single-shot via `openColorPicker`).
- Focused suites: animateditem 8, colorpickermodal, gridtable, translationprogress, colorfield — 59 tests, all pass.
- Full admin suite with `--maxWorkers=2`: `Test Files 66 passed (66)`, `Tests 843 passed (843)`.
- `npx eslint` on the four components: clean.
- Production build twice: `dist/js/main.js` md5 identical across `rm -rf dist` rebuild; no dist churn in git status.
- `node tools/ui-inventory.mjs --check` ok (124 modules); `node tools/ui-gate.mjs` ok (an intermediate AnimatedItem class-template refactor tripped `legacy-class`; restored the original two-const class construction so the extracted token set is unchanged).
- `bash tools/factory-gate.sh all` green (composer toolchain installed in this worktree first).

## Review-round-2 orchestrator gate receipt (measured)

- Mutation sweep re-run after the five-defect repair: 29 distinct mutants (the original classes plus destroyed-guards on TranslationProgress.render and all three GridTable render entry points, the syncRoot destroy-scan, and each AnimatedItem `?? default` normalizer) — every mutant KILLED, file restored clean after each.
- Focused suites: 66 tests pass (was 59; +7 this round).
- Full admin suite with `--maxWorkers=2`: `Test Files 66 passed (66)`, `Tests 850 passed (850)`.
- eslint clean on the four components; production build twice byte-identical (`dist/js/main.js` md5), no dist churn.
- `ui-inventory --check` ok (124 modules); `ui-gate` ok (10 changed files scoped); `factory-gate.sh all` green.
