# TechLog UI migration baseline ## Source provenance - Source path: `/home/donghyeon/workspace/techlog-studio-frontend` - Inspected: 2026-08-15 (Asia/Seoul) - Git revision/status: unavailable. The supplied source directory is an exported checkout with no `.git` metadata; both `git rev-parse HEAD` and `git status --short` report that it is not a Git repository. The source path and the byte checksums below are the reproducible provenance available for this baseline. ## Approved copied assets | Source and target-relative path | SHA-256 | | --- | --- | | `public/favicon.svg` | `e6d2e59b7b5bbb0342e0fb496dfc262decbfe4426bbb7b047aec8d467d1dc6f7` | | `public/media/fetch-strategy-boundary.svg` | `b07926823ed77fc200f962a1f64a440e130cefa6bed31144b611612af9b02606` | Only these two SVGs are approved for this baseline. They must remain exact byte-for-byte copies of the source assets. The evidence key `fetch-strategy-boundary` resolves to `/media/fetch-strategy-boundary.svg` with dimensions `1080 × 420`, trigger label `Fetch Join과 Batch Fetch 비교 다이어그램 크게 보기`, and dialog label `Fetch Join과 Batch Fetch의 페이징 경계 확대`. ## Required dependency pins | Package | Exact version | | --- | --- | | `pretendard` | `1.3.9` | | `@fontsource/ibm-plex-mono` | `5.3.0` | | `unified` | `11.0.5` | | `remark-parse` | `11.0.0` | | `remark-gfm` | `4.0.1` | | `remark-directive` | `4.0.0` | No Next.js, Vinext, or Cloudflare package is part of the migration baseline. ## Expected route inventory | Layout | Route ID | Path | | --- | --- | --- | | PUBLIC | `TECH_LOG_HOME` | `/` | | PUBLIC | `TECH_LOG_EXPLORE` | `/explore` | | PUBLIC | `TECH_LOG_EXPLORE_KIND` | `/explore/:kind` | | PUBLIC | `TECH_LOG_CASE` | `/cases/:slug` | | PUBLIC | `TECH_LOG_REFERENCE` | `/references/:slug` | | PUBLIC | `TECH_LOG_QUESTION` | `/questions/:slug` | | PUBLIC | `TECH_LOG_TOPIC` | `/topics/:slug` | | PUBLIC | `TECH_LOG_PROJECTS` | `/projects` | | PUBLIC | `TECH_LOG_PROJECT` | `/projects/:slug` | | PUBLIC | `TECH_LOG_PROJECT_RECORDS` | `/projects/:slug/records` | | PUBLIC | `TECH_LOG_PROJECT_DECISIONS` | `/projects/:slug/decisions` | | PUBLIC | `TECH_LOG_PROJECT_ACTIVITY` | `/projects/:slug/activity` | | PUBLIC | `TECH_LOG_RELEASES` | `/releases` | | PUBLIC | `TECH_LOG_RELEASE` | `/releases/:version` | | PUBLIC | `TECH_LOG_PROFILE` | `/profile` | | PUBLIC | `TECH_LOG_SEARCH` | `/search` | | STUDIO | `TECH_LOG_STUDIO_HOME` | `/studio` | | STUDIO | `TECH_LOG_STUDIO_DOCUMENTS` | `/studio/documents` | | STUDIO | `TECH_LOG_STUDIO_DOCUMENT_NEW` | `/studio/documents/new` | | STUDIO | `TECH_LOG_STUDIO_DOCUMENT_EDIT` | `/studio/documents/:id/edit` | | STUDIO | `TECH_LOG_STUDIO_DOCUMENT_VALIDATION` | `/studio/documents/:id/validation` | | STUDIO | `TECH_LOG_STUDIO_DOCUMENT_PREVIEW` | `/studio/documents/:id/preview` | | STUDIO | `TECH_LOG_STUDIO_DOCUMENT_PUBLISH` | `/studio/documents/:id/publish` | | STUDIO | `TECH_LOG_STUDIO_PUBLICATIONS` | `/studio/publications` | | STUDIO | `TECH_LOG_STUDIO_PUBLICATION_PREVIEW` | `/studio/publications/:publicationEventId/preview` | | STUDIO | `TECH_LOG_STUDIO_NOT_FOUND` | `/studio/*` | | PUBLIC | `NOT_FOUND` | `*` | ## Source stylesheet inventory - `app/globals.css` → `presentation/styles/globals.css` — `901205054ee96fe15062aaef7ff39c701985fdece15b58f7656776d0b744e607` - `app/studio.css` → `presentation/styles/studio.css` — `d0d958baeb55b74796988d8c0967a7c62d211e595224e07912aa1f884e466fdd` - `app/studio-editor.css` → `presentation/styles/studio-editor.css` — `ae9a473192d24465021d021cd42a5a84f9bdf4c3af0664537b4e10006ca1f889` - `components/studio/workflow.module.css` → `presentation/styles/workflow.module.css` — `8eaa478a88ef4d16429c7f6a32bb33631acb47deef0b40838edd0a72748f124e` - `components/studio/publication-flow.module.css` → `presentation/styles/publication-flow.module.css` — `5b1fdebeb27248b5cebc700b12d15cf11fe70471a394c9dc643a98c4569e8674` All five source/target pairs passed `cmp -s` and have identical SHA-256 digests. Production parity testing corrected the provisional bootstrap assumption in the design: the target loads the byte-identical TechLog `globals.css`, including its first-byte `@import "tailwindcss";`, exactly once and does not load the starter `theme.css`. This reproduces the source cascade; the resulting browser comparison is pixel-identical. ## Source-to-target browser parity The source was copied to `/tmp/techlog-source-parity.I0CBK7` before build and runtime caches were created. The supplied source directory was used only for read-only file comparison; it was not edited. The temp-copy Vinext production server on `4375` and the target `dist/server.mjs` production artifact on `4174` were captured by one Playwright Chromium instance with two fresh contexts under identical conditions: - `ko-KR`, `Asia/Seoul`, light color scheme, reduced motion, device scale 1, service workers blocked, and a fixed `2026-08-14T01:00:00.000Z` clock; - 1000-pixel viewport height, full-page screenshots, `document.fonts.ready`, Pretendard/IBM Plex font checks, zero-duration animation/transition/caret; - no screenshot masks; exact RGBA pixel comparison plus normalized recursive product-subtree tags, ordered children, complete classes, relevant attributes, text/ARIA relationships, response metadata, boot lifecycle, and console/request failure comparison. The only attributes omitted by name after concrete diagnostics are React Router `data-discover`, Next Image `data-nimg`/`decoding`/`srcset`, and Next SSR `selected`; generated React IDs and CSS-module hashes are normalized by value. No broad attribute class is omitted. | Evidence group | Cases | | --- | ---: | | 27 canonical routes at 360 and 1440 pixels | 54 | | Every additional known Public fixture slug/version | 18 | | Public home breakpoint transitions | 12 | | Studio screen/state fixtures | 19 | | Ten unknown Public dynamic shapes at 360 and 1440 pixels | 20 | | Search/menu/preview/dialog/publication interactions | 7 | | **Total** | **130** | Result: 130/130 passed, zero failed, zero different pixels, all recursive DOM/class/attribute/text/ARIA trees and HTTP response metadata equal, and zero unexplained source or target console/request errors. The target-only visual regression suite exercises the same 130 cases against 129 committed PNGs; the canonical and Studio-state 1440-pixel `/studio/publications` cases intentionally share one identical snapshot. Source screenshots were temporary comparison inputs and were not copied into the target snapshot directory. The checked clean-checkout command is `TZ=Asia/Seoul corepack pnpm verify:tech-log-source-parity`; it runs directly under the installed Node 24 runtime and has no `tsx` dependency. Durable evidence is committed at `docs/operations/evidence/tech-log-source-parity.json`. It records 178 source checksums with tree digest `6724c2f898eefc62d2fc0ee695bccc3ae61a69c5153ed43c69f2cf99ee45bca5`, target candidate `3a7c5deca06679fb9b8710da2cce87bbca07ce8a`, build-manifest digest `3579650faa482f566553c00d8b4a05a05b4f7a1ab93b83e48676289bbcf02984`, Vite-manifest digest `cfd583ed7b6c27dce7f47389447608636b6b9df3e28df00c6416674da2c7c46d`, case inventory digest `5689bcdb5d5637205cdeb92b7c57f72d99f0b039818b8f90afdde526bbafe0ac`, and evidence payload digest `f046047beded19ce468be607dcf99c6b74d4e07323457ec7145c56d2f67d2c79`. The production source responds to both a missing dynamic slug such as `/projects/missing-project` and an unmatched path such as `/definitely-not-a-product-route` with HTTP 404, `text/plain;charset=UTF-8`, and the exact nine-byte body `Not Found`. The target production server intentionally removes the Public shell for those paths and matches that response in direct HTTP and Chromium regressions. Known Public routes and all known Studio routes remain SPA-served; `/studio/*` unknown paths preserve the source's in-shell HTML with HTTP 404. This is the observed production source contract, not a generic runtime error. ## Accessibility review boundary Automated Chromium `@a11y` coverage passes 29/29. The source-controlled manual inventory contains exactly the 27 installed route IDs and removes the obsolete starter records. Every human record remains `pending-manual-review` until one reviewer evaluates keyboard, focus, modal/error behavior, color, reduced motion, and screen-reader output against immutable candidate `3a7c5deca06679fb9b8710da2cce87bbca07ce8a`. Therefore `corepack pnpm review:a11y-manual` intentionally exits nonzero with 27 incomplete records and `release IDs do not match`; neither the manual gate nor `FE-GATE-009` is represented as passing. The exact completion format is in `docs/accessibility/manual-checklist.md`, and signed evidence must be committed separately after it cites the candidate SHA. ## Governed route migration The migration records 23 TechLog-owned breaking-change evidence IDs with owner `tech-log-frontend`, an atomic same-release route/runtime/manifest migration, and rollback to `05e3d50ba01f01c27f257d2e9040c2bc413ea053`. The accepted registry snapshot digest is `428479ac5845374a82dd7d02a0c59a713106405f031cdc153789174f14c1405b`; its approval reason is `Install approved TechLog Public and Studio route contract`. Final compatibility impact is `none` with no unacknowledged change. ## Restricted-environment test baseline The exact repository aggregate command was run in the managed workspace: ```bash corepack pnpm test:all ``` Its fresh staged-candidate runtime-schema phase passed 3 files/40 tests. The unit phase passed 122 files/1,773 tests and reported 19 failures, all in the pre-existing `ci-artifact-contract` provider/cgroup, RLIMIT/EMFILE, restrictive-umask, `/tmp`, timing, and identity environment cases. No `tests/features/tech-log` test failed. A pre-staging diagnostic run also found 39 `APP_HOME` release-inventory failures because new serving files were not yet visible to `git ls-files`; staging the complete candidate fixed that test precondition, and all 39 disappeared. The same run's one guardian aggregate timeout passed 1/1 in isolation and 21/21 in the fresh staged aggregate. The failing files were then reproduced in isolation outside that child-process restriction: ```bash corepack pnpm exec vitest run tests/unit/ci-artifact-contract.test.ts tests/unit/ci-workflow-generation.test.ts tests/unit/http-scenario-evidence.test.ts ``` Result: 3 files/529 tests, 510 passed and the same 19 environment-only `ci-artifact-contract` cases failed. The 407 `ci-workflow-generation` and 14 `http-scenario-evidence` tests all passed. These 19 contain no TechLog code or test. The aggregate phases after unit were also run directly: component 18 files/124 tests, integration 11 files/82 tests under the required child-process scope, reference feature 4 files/13 tests, and recipes 2 files/17 tests all passed. The inventories in this document are human review baselines. Automated coverage is intentionally limited to the two SVG byte contracts, evidence asset lookup behavior, package manager frozen-lockfile verification, committed target visual regressions, and governed registry/release gates. The external source path is never required by committed CI tests.