# Admin Snappy Implementation Plan

> **For agentic workers:** REQUIRED SUB-SKILL: Follow `.claude/agents/expert.md`; load mapped project skills before implementation. Execute through `/claudex-workflow` per owner request. Steps use checkbox syntax for tracking.

**Goal:** Make every plugin admin route paint shaped skeletons or scoped cached content immediately, revalidate safely, preserve interaction state, and improve measured latency through reusable browser/server primitives.

**Architecture:** Measure first. Build user/site-scoped SWR, per-region lifecycle, keyed DOM patching, centralized mutation tags, and generation-token REST caching over existing `ObjectCache`. Prove architecture on Languages and Content Translation before parallel page migration; consolidate motion after page SCSS settles.

**Tech Stack:** Vanilla ES modules, Vitest/jsdom, SCSS/Webpack, WordPress REST/PHP 8, PHPUnit, Playwright through `e2e-remote`.

**Base:** `origin/master`
**Source:** `docs/specs/2026-08-04-admin-snappy-design.md`

---

## Wave Plan

| Wave | Tasks | Files touched | Safe to parallelize? |
|---|---|---|---|
| 1 | Task 1 | `admin/performance/*`, `admin/scripts/measure-admin-performance.mjs` | single evidence task |
| 2 | Tasks 2, 3 | JS test config vs PHP cache files | ✅ no overlap |
| 3 | Tasks 4, 5 | browser data layer vs UI primitives | ✅ no overlap; both depend on Task 2 |
| 4 | Task 6 | shared API/store registry, localized identity, server invalidation bridges | single integration task |
| 5 | Tasks 7, 8 | Languages files vs Content Translation files | ✅ beachhead files disjoint |
| 6 | Task 9 | measurement report + beachhead E2E | single architecture gate |
| 7 | Tasks 10, 11, 12 | disjoint page/section groups and page SCSS | ✅ no overlap |
| 8 | Task 13 | shared motion partials/component SCSS | single serialized task |
| 9 | Task 14 | shared cleanup, full verification, final performance report | single integration task |

## File responsibility map

- `admin/src/utils/DataStore.js` — scoped bounded SWR store, subscription, revalidation, mutation, tag invalidation.
- `admin/src/data/adminStores.js` — browser fetcher/query adapter over localized canonical policy.
- `admin/src/components/PageShell.js` — per-route ownership and teardown.
- `admin/src/components/DataRegion.js` — store subscription, loading/error state, keyed interaction-safe updates.
- `admin/src/components/RegionPresets.js` — reusable table/select/form/stat/list/chart adapters composing existing components.
- `admin/src/components/Skeleton.js` — final-shape loading presets.
- `includes/Performance/AdminDataPolicy.php` — single route/scope/TTL/tag/mutation source for PHP and browser.
- `includes/API/RestResponseCache.php` — permission-safe REST hook caching.
- `includes/Performance/CacheInvalidation.php` — generation-token rotation and mutation-hook bridge.
- `admin/performance/*` — reproducible baseline/final measurements and route contract inventory.
- Existing page/section files — consume primitives; MUST NOT implement local cache/lifecycle variants.

## Task 1: Measure latency and freeze route/store inventory

**Wave:** 1  
**Blocks:** Tasks 3–14  
**Blocked by:** —

**Files:**
- Create: `admin/scripts/measure-admin-performance.mjs` — repeatable browser/network/main-thread measurement driver.
- Create: `admin/performance/admin-snappy-baseline.json` — machine-readable baseline.
- Create: `admin/performance/admin-snappy-route-contract.json` — exact page/store/GET/mutation/scope/TTL/tag inventory.
- Create: `admin/performance/README.md` — invocation, environment, interpretation, derived per-route budgets.

**Contract:**
- Baseline schema MUST record environment, route, sample size, request count, endpoint TTFB/payload bytes, route-to-skeleton, route-to-first-content, route-to-settled, scripting/render duration, long-task count/duration, and candidate localStorage parse/write duration.
- Cover Languages plus five heavy routes: Content Translation, String Translation, Translate Posts, Translate History, Licensing/Settings.
- Route contract rows MUST include `owner`, `key`, `endpoint`, normalized query fields, `browserTtlMs`, `persist`, `serverScope`, `serverTtl`, `tags`, `mutations`, `liveFields`.
- Derive acceptance per route: cold settled/main-thread no regression; warm first-content ≥50% faster, targeting ≤200ms when environment permits.
- Run browser through `~/.claude/bin/e2e-remote`; use already-deployed target mode or an authorized remote server command. NEVER launch local headless browser.

**Behavior:**
- Use realistic existing dev data; do not synthesize tiny datasets that hide rendering cost.
- Separate network wait from synchronous DOM/chart work.
- Fail if any required route or API call lacks a contract row.
- Do not change production code.

**Acceptance:**
- Run: `node admin/scripts/measure-admin-performance.mjs --validate admin/performance/admin-snappy-baseline.json admin/performance/admin-snappy-route-contract.json`
- Expected: PASS; all required metrics/routes/contracts present and budgets derived.

- [ ] Write validator/measurement driver.
- [ ] Capture baseline through remote browser workflow.
- [ ] Freeze exact route/store/mutation inventory.
- [ ] Run acceptance; keep receipt for unchanged tree.
- [ ] Commit `admin/scripts/measure-admin-performance.mjs admin/performance/` with `perf: record admin loading baseline`.

## Task 2: Add deterministic admin unit-test harness

**Wave:** 2  
**Blocks:** Tasks 4, 5, 6  
**Blocked by:** Task 1

**Files:**
- Modify: `admin/package.json` — add `test`/`test:watch` scripts and Vitest/jsdom dependencies.
- Modify: `admin/package-lock.json` — resolved dependency graph.
- Create: `admin/vitest.config.js` — jsdom test environment and test paths.
- Create: `admin/tests/setup.js` — deterministic DOM/localStorage globals.

**Contract:**
- `npm test -- --run` MUST execute `admin/tests/**/*.test.js` in jsdom, return nonzero on failure, and leave no watch process.
- Tests MUST isolate localStorage, DOM, timers, and global `internationalPressZone` between cases.

**Behavior:**
- Preserve existing Webpack build.
- Address every install/test warning; do not suppress fixable warnings.

**Acceptance:**
- Run: `cd admin && npm test -- --run`
- Expected: PASS including existing `tests/flag-picker.test.js`.

- [ ] Add failing harness smoke test if needed.
- [ ] Install pinned compatible dependencies.
- [ ] Run acceptance and `npm run build`.
- [ ] Commit listed admin config/lock/test setup paths with `test: add admin unit harness`.

## Task 3: Build safe generation-token REST cache

**Wave:** 2  
**Blocks:** Task 6  
**Blocked by:** Task 1

**Files:**
- Create: `includes/Performance/AdminDataPolicy.php` — canonical PHP/browser route, scope, TTL, tag, and mutation policy.
- Create: `includes/API/RestResponseCache.php` — permission-safe REST hook adapter.
- Create: `includes/Performance/CacheInvalidation.php` — generation tokens and shared invalidation action.
- Create: `tests/unit/API/RestResponseCacheTest.php`.
- Create: `tests/unit/Performance/CacheInvalidationTest.php`.
- Modify: `includes/Core/Plugin.php` — instantiate/register cache and invalidation services once in existing controller bootstrap.

**Contract:**
```php
final class RestResponseCache {
    public function register(): void;
    public function invalidate(string $group): void;
}
```
- Register `rest_dispatch_request` and `rest_request_after_callbacks`; WordPress invokes the dispatch filter after route matching and permission callbacks, and a non-null dispatch response safely short-circuits only the callback.
- `AdminDataPolicy` MUST be sole source for route/group/scope/TTL/exclusion and browser-safe localized policy.
- Key inputs: blog ID, user ID by default, plugin version, normalized route args, group generation token.
- Site scope MUST require explicit route-contract opt-in.
- Use existing `InternationalPressZone\Performance\ObjectCache`; source lines 176–217 provide transient fallback.
- Invalidation replaces unique generation token. MUST NOT enumerate keys or call `flush()`.

**Behavior:**
- Cache only successful pure-data GET results.
- Reject `WP_Error`, exceptions, redirects/non-2xx, and recursive `nonce`/`_wpnonce` keys.
- Cache valid empty arrays, zero, and false using dedicated miss sentinel.
- Cache failure executes builder live.
- Mutable TTL 30–60s; stable TTL ≤5m.
- `do_action('ipz_data_changed', $group)` rotates generation through one listener.

**Acceptance:**
- Run: `vendor/bin/phpunit tests/unit/API/RestResponseCacheTest.php tests/unit/Performance/CacheInvalidationTest.php`
- Expected: PASS for hit/miss, empty values, generation rotation, user/site isolation, nonce/error rejection, transient fallback, backend failure fallback.

- [ ] Write failing tests.
- [ ] Implement minimal cache/invalidation services.
- [ ] Verify actual second-call hit without Redis/Memcached in dev WordPress.
- [ ] Run acceptance.
- [ ] Commit implementation/bootstrap paths; stage exact test file paths; NEVER stage a test directory wholesale. Commit message: `feat: add scoped REST response cache`.

## Task 4: Build scoped bounded DataStore and registry types

**Wave:** 3  
**Blocks:** Task 6  
**Blocked by:** Tasks 1, 2

**Files:**
- Create: `admin/src/utils/DataStore.js`.
- Create: `admin/tests/data-store.test.js`.

**Contract:**
```js
getStore(key, { fetcher, tags = [], ttl = 300000, persist = true, version = 1, maxBytes = 262144 }): Store
Store.get(): { data, isStale, source } | null
Store.subscribe(listener): () => void
Store.revalidate({ signal } = {}): Promise<any>
Store.mutate(updater, { revalidate = true } = {}): void
Store.invalidate(): void
Store.destroy(): void
invalidateTags(tags): void
```
- Namespace: `ipz_swr_v<pluginVersion>_<siteId>_<userId>_<key>`.
- Payload: `{v,data,timestamp,lastAccess,tags}`.
- Per-entry cap 256 KiB; per namespace LRU budget 2 MiB.

**Behavior:**
- Default user isolation; purge foreign version/site/user keys at boot.
- Parse/quota/security failure degrades to memory-only.
- Deduplicate exact-key revalidation.
- Abort/late result MUST NOT publish.
- Cross-tab `storage` invalidation updates matching in-memory stores.
- Never synchronously compress oversized data.

**Acceptance:**
- Run: `cd admin && npm test -- --run tests/data-store.test.js`
- Expected: PASS for TTL/version, namespace isolation, LRU/quota, dedupe, abort, storage event, mutation rollback semantics.

- [ ] Write failing tests.
- [ ] Implement contract.
- [ ] Run acceptance.
- [ ] Commit `admin/src/utils/DataStore.js`; stage exact test file paths; NEVER stage a test directory wholesale. Commit: `feat: add scoped admin data store`.

## Task 5: Build PageShell, deep DataRegion, shared region adapters, and shaped skeletons

**Wave:** 3  
**Blocks:** Tasks 7, 8, 10–12  
**Blocked by:** Task 2

**Files:**
- Create: `admin/src/components/PageShell.js`.
- Create: `admin/src/components/DataRegion.js` — store subscription, state machine, keyed reconciliation, and interaction deferral.
- Create: `admin/src/components/RegionPresets.js` — table/select/form/stat/list/chart adapters over existing shared components.
- Modify: `admin/src/components/Skeleton.js`, `Table.js`, `Select.js`, `ErrorState.js`, `EmptyState.js` — expose adapter seams, remove confirmed raw-markup gaps, and keep backward-compatible exports.
- Modify: `admin/src/components/index.js`.
- Create: `admin/tests/page-shell.test.js`.
- Create: `admin/tests/data-region.test.js`.
- Create: `admin/tests/region-presets.test.js`.
- Create: `admin/tests/skeleton.test.js`.

**Contract:**
```js
new PageShell(container, { regions, onError }).mount(): Promise<void>
PageShell.destroy(): void
new DataRegion(parent, { store, view, skeleton, errorView }).mount(): Promise<void>
DataRegion.destroy(): void
```
- `RegionPresets` MUST provide table/select/form/stat/list/chart view adapters and compose existing `Table`, `Select`, `ErrorState`, `EmptyState`, and `Skeleton` components.
- Keyed reconciliation remains private inside DataRegion; pages MUST NOT configure DOM lifecycle mechanics.
- Skeleton presets: `table`, `form`, `statRow`, `list`, `chart`, `page`; retain existing `Skeleton(type,count)` compatibility.

**Behavior:**
- Readiness MUST be per-region; cached blocks paint while missing blocks remain skeletons.
- Destroy unsubscribes, aborts, removes listeners, marks inactive; late callbacks no-op.
- DataRegion patches stable keyed nodes; leaf views change text only.
- Defer updates during focus-within, dirty form, selected rows, open menu/dropdown, or bound modal. Apply newest deferred payload after interaction.
- Preserve focus, selection, scroll, open details, dirty values.
- Skeletons are aria-hidden; containing region exposes non-repeating accessible loading state.
- Componentizer gate: confirmed raw table/select/loading/error/empty markup MUST migrate to existing shared components through RegionPresets; no parallel raw markup implementation.

**Acceptance:**
- Run: `cd admin && npm test -- --run tests/page-shell.test.js tests/data-region.test.js tests/region-presets.test.js tests/skeleton.test.js`
- Expected: PASS for lifecycle teardown, mixed readiness, keyed identity, interaction deferral, shared-component composition, and backward compatibility.

- [ ] Write failing tests.
- [ ] Implement three contracts.
- [ ] Run acceptance.
- [ ] Commit component/index paths; stage exact test file paths; NEVER stage a test directory wholesale. Commit: `feat: add reusable admin loading primitives`.

## Task 6: Wire central descriptors, mutation tags, identity, and server invalidation

**Wave:** 4  
**Blocks:** Tasks 7–12  
**Blocked by:** Tasks 3, 4

**Files:**
- Create: `admin/src/data/adminStores.js` — browser adapter over localized `AdminDataPolicy`; owns fetchers, not duplicated policy.
- Modify: `admin/src/utils/api.js` — normalized successful-mutation event.
- Modify: `includes/Admin/AssetLoader.php` — localize plugin version, blog/site ID, user ID, and browser-safe AdminDataPolicy.
- Modify: `includes/Admin/MenuController.php` only if its separate localizer remains reachable — same identity/policy fields.
- Modify: `includes/Core/LanguageManager.php`, `ContentManager.php`, `StringScanner.php`; `includes/Translation/JobRecorder.php`, `JobSender.php`, `JobReceiver.php`, `TranslationFinalizer.php`; `includes/Workflow/AssignmentEngine.php`, `StateMachine.php`; `includes/Team/ActivityTracker.php`, `TimeTracker.php` — emit domain cache tags at custom-table mutation seams.
- Modify: `includes/API/StringTranslateController.php`, `TranslationsController.php`, `TranslateController.php`, `WorkflowController.php` only where writes bypass listed domain modules.
- Create: `admin/tests/admin-stores.test.js`.
- Create: `tests/unit/Performance/CacheInvalidationIntegrationTest.php`.

**Contract:**
- `AdminDataPolicy.php` MUST remain sole route/group/scope/TTL/tag/mutation source. `adminStores.js` consumes localized browser-safe policy and adds fetchers/query serialization only.
- API mutation event shape: `{method: 'POST'|'PUT'|'PATCH'|'DELETE', path: normalizedPath}` after successful response only.
- Browser/server tags MUST derive from same policy entry.
- Cache eligibility MUST follow spec table: license/payment/progress/migration live state remain uncached.

**Behavior:**
- Dynamic ID routes use deterministic matchers.
- Language/settings/content/string/post/workflow mutations invalidate all dependent descriptors.
- Direct custom-table, CLI, webhook, and WP hook paths reach same group action.
- Pages never hand-invalidate.

**Acceptance:**
- Run: `cd admin && npm test -- --run tests/admin-stores.test.js && cd .. && vendor/bin/phpunit tests/unit/Performance/CacheInvalidationIntegrationTest.php`
- Expected: PASS; every contract mutation has tags, forbidden route classes have no persistent/server cache, two users cannot share entries.

- [ ] Write failing registry/integration tests.
- [ ] Add identity localization and centralized event wiring.
- [ ] Wrap only cache-eligible routes from measured inventory.
- [ ] Run acceptance and minimal build.
- [ ] Commit implementation/controller/localizer paths; stage exact test file paths; NEVER stage a test directory wholesale. Commit: `feat: centralize admin cache invalidation`.

## Task 7: Migrate Languages beachhead

**Wave:** 5  
**Blocks:** Task 9  
**Blocked by:** Tasks 5, 6

**Files:**
- Modify: `admin/src/pages/languages.js`.
- Modify: `admin/src/styles/pages/_languages.scss` only if shaped skeleton layout requires it.
- Create: `admin/tests/languages-loading.test.js`.

**Contract:**
- Consume `languages:list` descriptor through PageShell/DataRegion.
- Skeleton matches header/actions/table column geometry.
- Add/edit/delete/toggle/default mutations use optimistic `Store.mutate()` then centralized revalidation.

**Behavior:**
- Remove full `await loadLanguages()` + whole-table rebuild after each mutation.
- Preserve selected/focused control and modal state during background refresh.
- No localStorage/cache logic in page.

**Acceptance:**
- Run: `cd admin && npm test -- --run tests/languages-loading.test.js`
- Expected: PASS for cold/warm paint, mutation invalidation, keyed row preservation, error fallback.

- [ ] Write failing page test.
- [ ] Migrate page with no shared-file edits.
- [ ] Run acceptance and build.
- [ ] Commit page/SCSS paths; stage exact test file paths; NEVER stage a test directory wholesale. Commit: `feat: make languages load instantly`.

## Task 8: Migrate Content Translation beachhead

**Wave:** 5  
**Blocks:** Task 9  
**Blocked by:** Tasks 5, 6

**Files:**
- Modify: `admin/src/pages/content-translate.js`.
- Modify: dedicated content/translation SCSS already imported by this page; MUST NOT touch shared motion files.
- Create: `admin/tests/content-translate-loading.test.js`.

**Contract:**
- Use query-keyed bounded descriptors for list/all/detail GETs.
- Persist only paginated payloads ≤256 KiB; active translation/job state memory-only.
- Table/list updates keyed by stable content ID.

**Behavior:**
- Render cached blocks independently; do not await unrelated blocks.
- Preserve filters, pagination, selections, open detail/modal, and in-flight progress.
- If Task 1 proves synchronous render dominant, batch keyed row insertion within frame budget; do not add virtualization without evidence.

**Acceptance:**
- Run: `cd admin && npm test -- --run tests/content-translate-loading.test.js`
- Expected: PASS for bounded persistence, mixed readiness, state preservation, active-state exclusion.

- [ ] Write failing page test.
- [ ] Migrate page without shared-file edits.
- [ ] Run acceptance and build.
- [ ] Commit page/dedicated SCSS paths; stage exact test file paths; NEVER stage a test directory wholesale. Commit: `feat: accelerate content translation loading`.

## Task 9: Enforce beachhead architecture gate

**Wave:** 6  
**Blocks:** Tasks 10–14  
**Blocked by:** Tasks 7, 8

**Files:**
- Modify: `admin/performance/admin-snappy-baseline.json` — append beachhead comparison receipt without overwriting baseline.
- Create: `tests/e2e/admin-snappy-beachhead.spec.js`.

**Contract:**
- Compare Languages and Content Translation against Task 1 budgets.
- Test cold skeleton→data, warm cache-before-network, two-user isolation, mutation invalidation, interaction preservation, route teardown, and bounded storage.

**Behavior:**
- Run through `~/.claude/bin/e2e-remote` only.
- If either route misses warm improvement or regresses cold/main-thread budget, classify measured bottleneck and revise primitive/page contract before fan-out. Do not waive gate.

**Acceptance:**
- Run: `node admin/scripts/measure-admin-performance.mjs --validate-beachhead admin/performance/admin-snappy-baseline.json`
- Expected: PASS; both routes meet derived budgets and E2E outcomes.

- [ ] Run unit/PHP receipts if source tree differs.
- [ ] Execute remote beachhead E2E and measurements.
- [ ] Repair measured architecture defects until green.
- [ ] Commit production repairs and performance receipt paths; do not stage E2E tests. Commit: `perf: validate admin loading architecture`.

## Task 10: Migrate dashboards, analytics, and assignments

**Wave:** 7  
**Blocks:** Task 13  
**Blocked by:** Task 9

**Files:**
- Modify: `admin/src/pages/dashboard.js`, `TeamDashboard.js`, `WorkflowDashboard.js`, `my-assignments.js`, `analytics.js`.
- Modify: `admin/src/sections/analytics-dashboard.js`.
- Modify: `admin/src/styles/pages/_dashboard.scss`, `_analytics.scss` only.
- Create: group-specific admin unit tests under `admin/tests/`.

**Contract:**
- Consume only predeclared dashboard/team/workflow/analytics descriptors.
- Recent/active jobs stay memory-only; Chart.js region uses chart skeleton and updates without recreating unchanged charts.

**Behavior:**
- Wrapper pages delegate ownership to sections/components; do not duplicate stores.
- Preserve chart canvas lifecycle, assignment actions, selected rows, and active job state.
- Every page/section destroy delegates PageShell/DataRegion cleanup.

**Acceptance:**
- Run: `cd admin && npm test -- --run tests/dashboard-loading.test.js tests/analytics-loading.test.js tests/assignments-loading.test.js`
- Expected: PASS for cache policy, independent regions, Chart.js lifecycle, and teardown.

- [ ] Write failing group tests.
- [ ] Migrate listed owners only.
- [ ] Run acceptance/build.
- [ ] Commit production page/section/SCSS paths; stage exact test file paths; NEVER stage a test directory wholesale. Commit: `feat: accelerate admin dashboards`.

## Task 11: Migrate settings, onboarding, licensing, and migration

**Wave:** 7  
**Blocks:** Task 13  
**Blocked by:** Task 9

**Files:**
- Modify: `admin/src/pages/settings.js`, `onboarding.js`, `licensing.js`, `migration.js`.
- Modify: `admin/src/styles/pages/_settings.scss`, `_onboarding.scss`, `_licensing.scss`, `_migration.scss` only.
- Create: group-specific tests under `admin/tests/`.

**Contract:**
- Settings and onboarding plans may persist per registry.
- License status/usage, PayPal session, migration preflight/verify/progress MUST remain memory-only and server-uncached while still receiving shaped skeletons and reusable lifecycle.

**Behavior:**
- Revalidation MUST NOT overwrite dirty settings.
- Payment/license/migration actions always use live response and invalidate dependent safe stores after success.
- Preserve step state, active checkout, focus, and form validation.

**Acceptance:**
- Run: `cd admin && npm test -- --run tests/settings-loading.test.js tests/onboarding-loading.test.js tests/licensing-loading.test.js tests/migration-loading.test.js`
- Expected: PASS for dirty-form preservation and forbidden-cache policies.

- [ ] Write failing group tests.
- [ ] Migrate listed pages only.
- [ ] Run acceptance/build.
- [ ] Commit production page/SCSS paths; stage exact test file paths; NEVER stage a test directory wholesale. Commit: `feat: accelerate admin settings flows`.

## Task 12: Migrate strings, posts, history, and translation wrappers

**Wave:** 7  
**Blocks:** Task 13  
**Blocked by:** Task 9

**Files:**
- Modify: `admin/src/pages/string-translate.js`, `translate-posts.js`, `translate-history.js`, `translations.js`.
- Modify: `admin/src/styles/pages/_translations.scss` only.
- Create: group-specific tests under `admin/tests/`.

**Contract:**
- Query-keyed paginated string/post/history stores; bounded persistence.
- Completed history rows may persist 30s; active progress and polling MUST remain memory-only.
- `translations.js` remains wrapper/delegator; no duplicate store.

**Behavior:**
- Preserve filters, pagination, bulk selections, open modals, and active jobs.
- Replace direct legacy `Cache.js` usage in Posts/History with DataStore.
- `Cache.js` was deleted by `9f5d447c` only after zero-reference checks across source, tests, Webpack entries, dynamic imports, and built runtime.

**Acceptance:**
- Run: `cd admin && npm test -- --run tests/string-translate-loading.test.js tests/translate-posts-loading.test.js tests/translate-history-loading.test.js`
- Expected: PASS for bounded query stores, active/completed split, state preservation, and wrapper ownership.

- [ ] Write failing group tests.
- [ ] Migrate listed pages only.
- [ ] Run acceptance/build.
- [ ] Commit production page/SCSS paths; stage exact test file paths; NEVER stage a test directory wholesale. Commit: `feat: accelerate translation data pages`.

## Task 13: Consolidate motion and skeleton styling

**Wave:** 8  
**Blocks:** Task 14  
**Blocked by:** Tasks 10, 11, 12

**Files:**
- Modify: `admin/src/styles/_animations.scss`, `_variables.scss`, `_forms.scss`, `_dashboard-shared.scss`.
- Modify: `admin/src/styles/components/_tabs.scss`, `_progress-bar.scss`, `_spinner.scss`, and exact remaining files containing `@keyframes`/raw touched durations.
- Modify: `admin/src/styles/_utilities.scss`, `admin/src/styles/components/_flag-picker.scss` — canonical skeleton styles and keyframe migration.
- Create: `admin/tests/motion-contract.test.js` or deterministic SCSS contract script.

**Contract:**
- All admin `@keyframes` declarations MUST live in `_animations.scss`.
- Motion tokens: fast/base/slow durations plus out/in-out easing.
- Reusable classes: fade-in, slide-up, crossfade, skeleton shimmer.
- Global reduced-motion rule disables nonessential transitions/animation/shimmer.

**Behavior:**
- Animate transform/opacity only, except existing semantic progress stripes.
- Remove duplicate definitions; never alias-copy them.
- Replace raw timing literals in touched admin styles with tokens.
- Keep layout and dark mode unchanged.

**Acceptance:**
- Run: `cd admin && npm test -- --run tests/motion-contract.test.js && npm run build`
- Expected: PASS; deterministic scan reports every keyframe in `_animations.scss`, reduced-motion present, no duplicate names, clean build.

- [ ] Write failing deterministic contract test.
- [ ] Consolidate keyframes/tokens/utilities.
- [ ] Run acceptance.
- [ ] Commit production SCSS paths; stage exact test file paths; NEVER stage a test directory wholesale. Commit: `style: unify admin motion`.

## Task 14: Integrate, clean up, and verify every route

**Wave:** 9  
**Blocks:** —  
**Blocked by:** Task 13

**Files:**
- Modify: `admin/src/data/adminStores.js` only for measured discrepancies returned by page tasks.
- Delete: `admin/src/utils/Cache.js` only if zero references remain.
- Modify/Delete: obsolete bespoke loading code/styles proven unreachable by repository search.
- Create: `tests/e2e/admin-snappy-all-pages.spec.js`.
- Modify: `admin/performance/admin-snappy-baseline.json` — append final measurements.

**Contract:**
- Every admin page/section with data appears in registry and renders per-region skeleton/cached/live/error states.
- No page-local localStorage/cache/invalidation implementation remains.
- Full result meets every Task 1 per-route budget and all spec safety constraints.

**Behavior:**
- Use current-tree receipts; rerun only gates invalidated by changed inputs.
- Verify cache HIT on WordPress transient fallback.
- E2E through `~/.claude/bin/e2e-remote` only.
- Run existing journey suite unchanged. Any warning/error/prevent-band signal MUST be fixed or explicitly proven benign before landing.
- Do not delete legacy files with remaining consumers.

**Acceptance:**
- Run: `cd admin && npm test -- --run && npm run build`; `vendor/bin/phpunit`; remote Playwright for `admin-snappy-all-pages.spec.js` plus existing journeys; `node admin/scripts/measure-admin-performance.mjs --validate-final admin/performance/admin-snappy-baseline.json`.
- Expected: all clean PASS; every route meets derived budget; no cross-user cache leak; no interaction-state regression; no duplicate keyframes; no legacy Cache references if file deleted.

- [ ] Write/complete all-page outcome test.
- [ ] Integrate registry discrepancies serially.
- [ ] Prove zero references before cleanup.
- [ ] Run invalidated deterministic, build, PHP, remote E2E, accessibility, and performance gates.
- [ ] Commit production cleanup/registry/performance paths; stage exact test file paths; NEVER stage a test directory wholesale. Commit: `perf: complete snappy admin loading`.

## Decision enumeration

No owner decision remains. Robust defaults resolve cache backend (existing ObjectCache with transient fallback), scope (user by default), test runner (Vitest/jsdom), and rollout gate (measured beachhead). Source-control, CI, worktree, and publication mechanics belong to delivery controller and MUST NOT be surfaced as user decisions.

## Main-thread self-review

- **Spec coverage:** all evidence, browser isolation/LRU, teardown, interaction safety, generation invalidation, mutation hooks, route policies, beachhead, motion, testing, and cleanup requirements map to Tasks 1–14.
- **Advisor corrections applied:** generation tokens; current-user keys; scoped browser namespaces; LRU cap; explicit test harness; destroy/abort; interaction deferral; correct controller inventory delegated to measured contract; custom-table/CLI/webhook invalidation; route/store table; measure-first/beachhead rollout; remote E2E; cross-tab events.
- **Advisor claims rejected with source evidence:** `ObjectCache` DOES have transient fallback (`includes/Performance/ObjectCache.php:176-217`); valid empty payloads MUST remain cacheable with a miss sentinel.
- **Additional improvements:** per-region rather than whole-page readiness; bounded persistence instead of blindly storing large payloads; default user scope; deterministic abort semantics; no virtualization without measurement; same-wave file ownership; motion serialized after SCSS migrations.
- **Componentizer review:** existing barrel confirms `Table`, `Select`, `ErrorState`, `EmptyState`, `Skeleton`, and related primitives. Scan found raw tables in 3 owners, raw selects in 7, loading branches in 14, and whole-container clearing in 12. Task 5 now adds RegionPresets over existing components; migration tasks MUST remove confirmed bypasses instead of adding parallel markup.
- **Code-quality review:** public standalone Region was shallow and made callers understand reconciliation plus store lifecycle. It is now private behavior inside deep DataRegion; PageShell retains route ownership only. AdminDataPolicy eliminates duplicated PHP/JS TTL/scope/tag rules.
- **Architecture deepening review:** DataStore (cache), DataRegion (data-view state), PageShell (route ownership), and AdminDataPolicy (shared policy) pass deletion test: removing each redistributes nontrivial complexity across 15 pages or both runtimes. RegionPresets has multiple real adapters/consumers; no hypothetical one-adapter seam remains.
- **Wave audit:** same-wave tasks have disjoint production files; Tasks 10–12 consume predeclared descriptors and cannot edit shared registry; Task 14 serializes discrepancies.
- **Body-bloat/vagueness audit:** tasks pin seams and named edge cases; no implementation bodies; every task has one executable acceptance contract.

## Final implementation reconciliation

The frozen measurement contract remains the seven rows in
`admin/performance/admin-snappy-route-contract.json`; the runtime policy in
`includes/Performance/AdminDataPolicy.php` has fifteen reachable descriptors.
The posts tab is `#/translations/posts` and uses
`/translations/content?postType=post`. Team, workflow, and assignments are
reachable SPA routes and consume policy-owned stores.

REST replay is permanently installed at `rest_dispatch_request`, after route
matching and permission checks; writes invalidate at
`rest_request_after_callbacks`. Replayed responses retain status, headers, and
empty payloads, and cache hits consume the same resolved rate-limit identity as
origin requests.

`Cache.js` is deleted with no production references. TTL-zero stores always
revalidate during `DataRegion.mount()` while retaining already painted rows and
an accessible retry state on failure. Quick Actions is directly below the
Dashboard overview header; System Status/Health is removed. Plugin-owned dark
mode is removed from admin, editor, and language-switcher output.

Validation uses `npm run lint:js`, `npm test -- --run`, `npm run build`, the
mixed `bash tests/run-unit-tests.sh tests/unit` and Composer PHP tools. Remote
browser validation resolves Playwright 1.62.0 from `tests/e2e` and runs Chromium
and Firefox against `http://100.126.128.50:8081` only.
