@typeroll/mcp-server 0.45.67 → 0.45.69

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -45,11 +45,17 @@ export const migrationTools = [
45
45
  fields: z.array(z.object({ name: z.string().min(1), type: z.string().optional() })).optional(),
46
46
  blocks: z.array(z.any()),
47
47
  business_specific_block_types: z.array(z.string()).optional(),
48
+ reviewed_custom_block_types: z.array(z.object({
49
+ type: z.string().trim().min(1), reason: z.string().trim().min(1).max(2000),
50
+ })).max(100).optional(),
51
+ reviewed_html_blocks: z.array(z.object({
52
+ block_id: z.string().trim().min(1), reason: z.string().trim().min(1).max(2000),
53
+ })).max(100).optional(),
48
54
  }))
49
55
  .min(1)
50
56
  .max(50)
51
57
  .optional()
52
- .describe('Proposed block compositions to review before build. Include fields when you want missing schema bindings detected. Explicitly list only genuinely business-specific custom block types.'),
58
+ .describe('Proposed block compositions before build. Standard blocks first, reviewed reusable custom types next, raw HTML only as a documented last resort. reviewed_custom_block_types and reviewed_html_blocks record exact choices and reasons, not proof of visual quality. Missing types/fields still block readiness.'),
53
59
  },
54
60
  handler: withErrorBoundary(async (args, { client, siteId }) => {
55
61
  const res = args.compositions
@@ -207,7 +213,7 @@ export const migrationTools = [
207
213
  },
208
214
  {
209
215
  name: 'record_migration_seo_acceptance',
210
- description: 'Record the reviewed SEO/content parity evidence used by the launch report. This does not run the audit. Supply the exact source/target origins, checked timestamp, dataset description, page count and difference counts. Also supply fidelity: desktop/mobile visual comparisons, shared-data checks, integration checks and evidence notes. HTTP 200 is not visual acceptance. status=accepted requires unresolved=0. Re-run and record new evidence after every deploy.',
216
+ description: 'Record the reviewed SEO/content parity evidence used by the launch report. This does not run the audit. Supply the exact source/target origins, checked timestamp, dataset description, page count and difference counts. Also supply fidelity: desktop/mobile review against the source (preserve) or approved design (renew), shared-data checks, integration checks and evidence notes identifying the intent and approved differences. HTTP 200 is not visual acceptance. status=accepted requires unresolved=0. Re-run and record new evidence after every deploy.',
211
217
  inputSchema: {
212
218
  status: z.enum(['accepted', 'rejected']),
213
219
  checked_at: z.string().datetime(),
@@ -64,7 +64,7 @@ export const siteTools = [
64
64
  },
65
65
  {
66
66
  name: 'check_site_indexing',
67
- description: 'Probe the site\'s recorded fallback and live production origins and report indexing safety. Keeps X-Robots-Tag, HTML robots meta, and robots.txt crawl policy separate; fallback URLs must expose the documented edge noindex header, while production follows sitewide_noindex. Use before launch and after changing domains or indexing settings.',
67
+ description: 'Probe the site\'s recorded fallback and live production origins and report indexing safety. Keeps X-Robots-Tag, HTML robots meta, and robots.txt crawl policy separate. expectation_reason identifies fallback_protection, platform_robots_blocked, sitewide_noindex or public_site. Customer publishing without a future website host intentionally blocks indexing even when sitewide_noindex is false; this is expected, not an error. Fallback URLs must expose the documented edge noindex header. Use before launch and after changing domains or indexing settings.',
68
68
  handler: withErrorBoundary(async (_args, { client, siteId }) => {
69
69
  const res = await client.get(siteId, 'indexing-diagnostics');
70
70
  return ok(res);
package/dist/version.js CHANGED
@@ -8,4 +8,4 @@
8
8
  //
9
9
  // Keep it in lockstep with package.json: tests/version.test.ts asserts
10
10
  // VERSION === package.json.version, so a bump that forgets this line fails CI.
11
- export const VERSION = '0.45.67';
11
+ export const VERSION = '0.45.69';
package/dist/workspace.js CHANGED
@@ -57,6 +57,16 @@ Public documentation: https://typeroll.com/docs/llms.txt
57
57
  - Never edit generated publishing source to change CMS content. Do not overwrite
58
58
  current CMS or owner answers from an old local snapshot.
59
59
 
60
+ ## Migrations
61
+
62
+ Read tr-migration-evidence, then the source-specific recipe (tr-migrate-wp,
63
+ tr-import-url, tr-migrate-astro or tr-migrate-multisite). Record preserve or renew
64
+ intent in brief/migration.md; ask if unclear. Standard blocks first, reviewed
65
+ custom types next, documented HTML exceptions last. Preserve or meaningfully
66
+ redirect every old public URL. Import completion is not block reconstruction
67
+ or launch acceptance. Compare preserve work to the source, renew work to the
68
+ approved design/content brief. Discover tools and recipes on demand.
69
+
60
70
  ## Everyday requests
61
71
 
62
72
  - Links, images, menus, settings, analytics and site-wide changes: read the
@@ -77,6 +87,7 @@ export const workspaceTemplates = {
77
87
  'brief/site.md': '# Site brief\n\n## Purpose and audience\n\n## Languages and scope\n\n## Primary user journeys\n\n## Content authority and sources\n\n## Editorial constraints and forbidden internal markers\n',
78
88
  'brief/brand.md': '# Brand\n\n## Voice and tone\n\n## Visual direction and references\n\n## Typography, colors and image policy\n\n## Desktop and mobile navigation\n\nRecord intent here; current design tokens belong in CMS settings.\n',
79
89
  'brief/content-model.md': '# Content model\n\n## Page types and routes\n\n## Fields and references\n\n## Shared templates and partials\n\n## Taxonomy and navigation\n\nUse the current CMS schema. This document describes decisions, not a second schema store.\n',
90
+ 'brief/migration.md': '# Migration brief (when applicable)\n\n## Intent: preserve or renew\n\n## Source URLs, date and agreed scope\n\n## Design and content acceptance reference\n\n## Retained facts and approved content changes\n\n## Standard blocks, custom types and HTML exceptions\n\n## Old URL to preserved path or relevant redirect\n\n## Prototype and verification evidence\n\nKeep private extracts in sources/private/ and screenshots in qa/reports/.\n',
80
91
  'decisions.md': '# Decisions\n\nRecord date, decision, reason, approved scope and alternatives when useful.\n',
81
92
  'sources/README.md': '# Sources\n\nStore research references and copy proposals. Record source URLs and dates.\nPrivate extracts belong in ignored private/ or an approved external store.\nDo not treat local drafts as current CMS content or commit media libraries.\n',
82
93
  'scripts/README.md': '# Project automation\n\nKeep repeatable imports and QA scripts here. Use the authenticated REST API\nfor scripted work; keep credentials outside files and inject them at runtime.\nMCP remains the interactive interface. Typeroll currently has no general site CRUD CLI.\n',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@typeroll/mcp-server",
3
- "version": "0.45.67",
3
+ "version": "0.45.69",
4
4
  "description": "Typeroll CMS MCP server – connect AI agents to the REST API to manage content and publish static websites.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -49,8 +49,9 @@ drafts and unpublished pages. Mint one link and reuse it while iterating.
49
49
  a local file with `create_upload_url` (see `tr-images`); `list_media` finds
50
50
  existing ones. Use the returned CDN URL exactly. With a named target, place it
51
51
  there (`add_block` with `core/image` on a block page; an `<img>` with `alt` in
52
- `html_content` on an HTML page). Without one, ask what the image is for. Ask
53
- for alt text when none was given. Afterwards say in one sentence where it
52
+ `html_content` on an HTML page). Without one, ask what the image is for. Preserve meaningful alt text or describe the image’s function; decorative images
53
+ may have empty alt, while linked images need an accessible name. Ask when the
54
+ intended purpose is unclear. Afterwards say in one sentence where it
54
55
  landed; to answer "has it been added?", read the page again rather than
55
56
  trusting the conversation.
56
57
 
@@ -9,10 +9,12 @@ description: Use when the user wants to import or migrate content from a non-Wor
9
9
  another MCP client) working through MCP and the public API. The portal's built-in
10
10
  AI assistant has no migration tools: it does not import, convert or verify sites.
11
11
 
12
- **Before bulk conversion:** read `tr-migration-evidence` with `read_skill`.
13
- Complete its source baseline and one verified prototype per active template.
14
- Read target content to protect edits, not to justify accidental target defaults.
15
- Its shared evidence record is required for visual acceptance.
12
+ **Before import or reconstruction:** read `tr-migration-evidence` with
13
+ `read_skill`. Choose preserve (platform change) or renew (new design/content),
14
+ record the brief and verify one prototype per active template before bulk writes.
15
+ Use standard blocks first, reviewed custom types next, rare documented HTML last.
16
+ Both paths must preserve or meaningfully redirect every old public URL. That
17
+ shared contract defines acceptance; this recipe only adds source-specific steps.
16
18
 
17
19
 
18
20
  > **The buffer model (draft writes).** Every content write in this recipe
@@ -35,7 +37,9 @@ Its shared evidence record is required for visual acceptance.
35
37
 
36
38
  ## Preconditions
37
39
 
38
- - Target Typeroll site exists with working header/footer.
40
+ - Target Site and Version are selected through OAuth or a scoped API key.
41
+ - Run `get_import_readiness` before importing content or media; verify the
42
+ Organization storage first. Build shared header/footer against the chosen brief.
39
43
  - Source URL(s) accessible (check with a quick `fetch`; if blocked, mention
40
44
  it and ask the user for an HTML export or screenshot).
41
45
 
@@ -56,7 +60,7 @@ Parse `<a href>` links to discover internal pages. Build a list:
56
60
  - Any sub-pages that look important
57
61
 
58
62
  Exclude private/session/admin URLs deliberately. Inventory public pagination and
59
- query routes; decide preservation or retirement from their actual purpose.
63
+ query routes and keep them working or map relevant redirects. Do not silently retire public routes.
60
64
 
61
65
  **Map source styling to named styles.** A class the source uses for a
62
66
  recurring treatment (`.eyebrow`, `.lead`, `.btn-outline`, `.section-dark`)
@@ -76,8 +80,9 @@ read_partial partial_id="header"
76
80
  list_pages limit=5
77
81
  ```
78
82
 
79
- Read existing target data to avoid overwriting work. Establish source geometry
80
- and validate native prototypes using `tr-migration-evidence` before mass writes.
83
+ Read existing target data to avoid overwriting work. Compare prototypes to the
84
+ source in preserve mode, or to the agreed new design in renew mode. Validate
85
+ standard/custom blocks using `tr-migration-evidence` before mass writes.
81
86
 
82
87
  ### 3. Fetch and clean each source page
83
88
 
@@ -117,15 +122,16 @@ icons. A required file that fails transfer blocks acceptance; do not silently
117
122
  omit it. Inventory PDFs, download hrefs, srcsets and backgrounds as well.
118
123
 
119
124
  **d. Adapt to the target's design.**
120
- Use verified native fields from the source capability map. Preserve appearance
121
- by default; do not substitute target defaults or corrective tenant CSS.
125
+ Use standard blocks first, then reusable custom types with editable fields.
126
+ Preserve source appearance/text in preserve mode; use the approved new design
127
+ and content plan in renew mode. Raw HTML is the documented last resort.
122
128
 
123
129
  ### 4. Create pages as drafts
124
130
 
125
131
  ```
126
132
  create_page title="Om oss" slug="om-oss"
127
- html_content="<cleaned, adapted HTML>"
128
- content_mode="html" status="draft"
133
+ path="/om-oss/" blocks=[<reviewed block tree>]
134
+ content_mode="blocks" status="draft"
129
135
  seo_title="Om oss — Acme"
130
136
  seo_description="..."
131
137
  ```
@@ -155,7 +161,7 @@ Walk through every imported page with the user. Common issues:
155
161
 
156
162
  ### 7. Publish + deploy
157
163
 
158
- After approval:
164
+ After approval, save working copies and confirm publishing readiness:
159
165
  ```
160
166
  batch_update_pages updates=[
161
167
  {page_id: "om-oss", patch: {status: "published"}},
@@ -163,15 +169,20 @@ batch_update_pages updates=[
163
169
  ]
164
170
  trigger_deploy
165
171
  get_deploy_status job_id=<id>
172
+ verify_migration_urls
173
+ get_migration_launch_report
166
174
  ```
167
175
 
176
+ This is candidate verification, not permission to change traffic DNS. Every old
177
+ public URL must serve its content or a relevant redirect before cutover.
178
+
168
179
  ## Platform-specific notes
169
180
 
170
181
  ### Squarespace
171
182
  - Main content is inside `.content-wrapper` or `[data-section-theme]` blocks
172
183
  - Portfolio images are usually high-resolution originals in `/universal/images/`
173
184
  - JSON-LD is Squarespace's own schema — strip it
174
- - Gallery blocks → convert to CSS grid with inline `<img>` tags
185
+ - Gallery blocks → standard image/gallery layouts, or a reusable custom type
175
186
 
176
187
  ### Wix
177
188
  - Wix sites are React SPAs — `fetch` returns an empty shell
@@ -186,7 +197,7 @@ get_deploy_status job_id=<id>
186
197
 
187
198
  ### Static HTML / old sites
188
199
  - Often the cleanest import. Fetch, strip nav/footer, keep body.
189
- - Watch for table-based layouts (pre-2010 sites) — convert to CSS grid
200
+ - Rebuild table-based layouts with layout blocks; keep actual tabular data as tables
190
201
 
191
202
  ## Pitfalls
192
203
 
@@ -9,10 +9,12 @@ description: Migrate an existing Astro site, including Astro Content Collections
9
9
  another MCP client) working through MCP and the public API. The portal's built-in
10
10
  AI assistant has no migration tools: it does not import, convert or verify sites.
11
11
 
12
- **Before bulk conversion:** read `tr-migration-evidence` with `read_skill`.
13
- Complete its source baseline and one verified prototype per active template.
14
- Read target content to protect edits, not to justify accidental target defaults.
15
- Its shared evidence record is required for visual acceptance.
12
+ **Before import or reconstruction:** read `tr-migration-evidence` with
13
+ `read_skill`. Choose preserve (platform change) or renew (new design/content),
14
+ record the brief and verify one prototype per active template before bulk writes.
15
+ Use standard blocks first, reviewed custom types next, rare documented HTML last.
16
+ Both paths must preserve or meaningfully redirect every old public URL. That
17
+ shared contract defines acceptance; this recipe only adds source-specific steps.
16
18
 
17
19
 
18
20
  Astro Content Collections are source data. In Typeroll, each source record
@@ -9,10 +9,12 @@ description: Use when migrating SEVERAL sites at once — a WordPress multisite
9
9
  another MCP client) working through MCP and the public API. The portal's built-in
10
10
  AI assistant has no migration tools: it does not import, convert or verify sites.
11
11
 
12
- **Before bulk conversion:** read `tr-migration-evidence` with `read_skill`.
13
- Complete its source baseline and one verified prototype per active template.
14
- Read target content to protect edits, not to justify accidental target defaults.
15
- Its shared evidence record is required for visual acceptance.
12
+ **Before import or reconstruction:** read `tr-migration-evidence` with
13
+ `read_skill`. Choose preserve (platform change) or renew (new design/content),
14
+ record the brief and verify one prototype per active template before bulk writes.
15
+ Use standard blocks first, reviewed custom types next, rare documented HTML last.
16
+ Both paths must preserve or meaningfully redirect every old public URL. That
17
+ shared contract defines acceptance; this recipe only adds source-specific steps.
16
18
 
17
19
 
18
20
  > **The buffer model (draft writes).** Every content write in this recipe
@@ -38,9 +40,9 @@ that is expensive to reverse (domains, deploys, and analytics all hang off
38
40
  it). The rest of this recipe assumes the common case: **N sites, one per
39
41
  domain**, sharing a design.
40
42
 
41
- Requires an **org-scoped API key** (`create_site` needs it, and one key
42
- reaching every site is the whole point here). With MCP you pass `site_id`
43
- per call; over stdio you'll be re-pointing `TYPEROLL_SITE_ID` per site.
43
+ Use personal OAuth with the required Organization permissions or an org-scoped
44
+ API key. Select each Site explicitly and use its returned context; never reuse
45
+ another Site's OAuth context. Keep Site and Version explicit on batch calls.
44
46
 
45
47
  ## Phase 0 — Plan the batch (do this once, in writing)
46
48
 
@@ -61,15 +63,14 @@ Then once per market, with that market's own source:
61
63
  get_migration_readiness site_id=<de-site> source_url="https://example.de"
62
64
  ```
63
65
 
64
- The blockers (media storage, hosting credentials) are **platform-level, not
65
- per-site** — if they fail for one site they fail for all ten, and finding out
66
- after building three sites means redoing three sites' worth of image work.
67
- Get them fixed before Phase 1, and re-run the check per site once the sites
68
- exist (the warnings — verification URL, form email, design reference — are
69
- per-site).
66
+ Check each target Site: storage is shared per Organization, but Hosting Groups,
67
+ permissions and verification origins can differ. Verified customer storage is
68
+ required before import; GitHub/build/domain readiness is checked separately for
69
+ publication. Do not infer that every Site shares the same blockers.
70
70
 
71
71
  Ask explicitly:
72
- - Which site is the **design reference**? Build that one properly first.
72
+ - Which intent applies per Site: preserve or renew? Which source or approved
73
+ prototype is the **design reference**? Build that one properly first.
73
74
  - Are the sites **translations of each other** (same page structure) or
74
75
  independent? This decides whether hreflang clusters are mechanical or
75
76
  hand-mapped.
@@ -117,10 +118,11 @@ Add every source you have, each with its own label — they merge per URL:
117
118
  the traffic sort to the top.
118
119
  - `source="crawl"` — anything you found by following internal links
119
120
 
120
- Mark the obvious throwaways immediately, so the work list is real:
121
+ Exclude only private/admin/session noise, with reasons. Public tags and archives
122
+ need working routes or relevant redirects, even when omitted from new navigation:
121
123
 
122
124
  ```
123
- add_migration_urls urls=[{ url: "/wp-admin", excluded: true }, { url: "/tag/nyheter", excluded: true }]
125
+ add_migration_urls urls=[{ url: "/wp-admin", excluded: true, notes: "Private source administration" }, { url: "/wp-login.php", excluded: true, notes: "Private source login; not public content" }]
124
126
  ```
125
127
 
126
128
  Read it back and note the starting number:
@@ -183,7 +185,7 @@ list_migration_urls site_id=<de-site> status="unhandled"
183
185
  For each entry, one of three outcomes — no fourth option:
184
186
 
185
187
  - It moved → `create_redirect from_path="/alte-seite" to_path="/neue-seite"`
186
- - It's gone on purpose → `update_migration_url url_id=… excluded=true notes="Old campaign LP, signed off by <name>"`
188
+ - It was merged → redirect to the relevant replacement, not the homepage
187
189
  - It should exist and doesn't → go back and migrate it
188
190
 
189
191
  Re-read the list. `unhandled` reaching zero is the exit condition for this
@@ -9,10 +9,12 @@ description: Use when the user asks to migrate a WordPress site to Typeroll, men
9
9
  another MCP client) working through MCP and the public API. The portal's built-in
10
10
  AI assistant has no migration tools: it does not import, convert or verify sites.
11
11
 
12
- **Before bulk conversion:** read `tr-migration-evidence` with `read_skill`.
13
- Complete its source baseline and one verified prototype per active template.
14
- Read target content to protect edits, not to justify accidental target defaults.
15
- Its shared evidence record is required for visual acceptance.
12
+ **Before import or reconstruction:** read `tr-migration-evidence` with
13
+ `read_skill`. Choose preserve (platform change) or renew (new design/content),
14
+ record the brief and verify one prototype per active template before bulk writes.
15
+ Use standard blocks first, reviewed custom types next, rare documented HTML last.
16
+ Both paths must preserve or meaningfully redirect every old public URL. That
17
+ shared contract defines acceptance; this recipe only adds source-specific steps.
16
18
 
17
19
 
18
20
  > **The buffer model (draft writes).** Every content write in this recipe
@@ -41,9 +43,9 @@ get_migration_readiness source_url="https://oldsite.com"
41
43
 
42
44
  When the migration includes reusable page/item layouts, include each proposed
43
45
  block composition and its content type fields in this same call. A
44
- `waiting_for_native_support` result means leave that template intact and do
45
- not replace the gap with generic custom blocks, raw HTML, or corrective site
46
- CSS. Independent content and SEO work may continue. Rerun the review after the
46
+ `waiting_for_native_support` result means inspect the actual blocker. Review
47
+ intentional custom types and rare HTML exceptions using `tr-migration-evidence`;
48
+ fix missing types/fields and report renderer defects rather than masking them. Independent content and SEO work may continue. Rerun the review after the
47
49
  required Core version is deployed, then verify preview and a fresh hosted
48
50
  build.
49
51
 
@@ -60,8 +62,11 @@ once the work is done, so discovering it late means redoing the expensive part.
60
62
  - **Media storage** — without it, every `<img>` keeps its WordPress URL. The
61
63
  new site looks perfect and is still served images by the old host. It breaks
62
64
  the day the customer cancels that hosting, months later, all at once.
63
- - **Hosting adapter** — without credentials, deploys return a job id and
64
- publish nothing, while reporting success.
65
+ - **Publishing** — with verified Organization storage, customer publishing can
66
+ import and preview before GitHub, builds or website domains are connected.
67
+ Publishing readiness is a separate gate before a hosted build/cutover. Legacy
68
+ self-hosted configurations may report a missing hosting adapter; follow the
69
+ returned blocker rather than assuming all installations have the same setup.
65
70
 
66
71
  Warnings are worth relaying but don't stop you: no verification origin (the
67
72
  pre-cutover parity check can't run), forms without a
@@ -69,12 +74,13 @@ notification address, or a target site with no design to rebuild INTO.
69
74
 
70
75
  Then the ordinary preconditions:
71
76
 
72
- - `@typeroll/mcp-server` configured with a valid `TYPEROLL_API_KEY`.
77
+ - MCP connected through personal OAuth or an appropriately scoped API key.
78
+ Select and confirm the Site/Version before writes; do not request pasted secrets.
73
79
  - The source WP site has `/wp-json` reachable (Google for "wordpress
74
80
  REST API disabled" if not — common for hardened hosts).
75
81
  - The target exists. Establish the source design baseline first, then prove
76
82
  representative target templates using `tr-migration-evidence`. Preserve
77
- appearance unless a redesign is explicitly requested.
83
+ appearance in preserve mode; use the approved design/content brief in renew mode.
78
84
  - If the target already has content, you must NOT clobber it — always
79
85
  `list_pages` first and only write to slugs that don't already exist.
80
86
  Pass the slug explicitly: `create_page` then refuses an address that is
@@ -161,10 +167,11 @@ c. Migrate referenced images with `upload_media_from_url`. The customer's
161
167
 
162
168
  The managed importer stores cleaned HTML. Typeroll does not convert HTML into blocks, and `set_page_mode` never rewrites HTML. Pages move to blocks only when someone rebuilds them with blocks.
163
169
 
164
- d. Preserve exact text, headings, anchors, links, media and semantic structure with native blocks first. Read the
165
- available block types and map headings, prose, images, buttons and layout
166
- into their typed fields. Use HTML mode only for source-specific markup that
167
- has no native representation and has passed the composition preflight.
170
+ d. Rebuild into editable blocks according to the selected intent. Preserve exact
171
+ wording in preserve mode; track approved changes in renew mode. Map headings,
172
+ prose, images, buttons and layout to standard fields first, then create
173
+ reviewed custom types where needed. Use raw HTML only for a documented,
174
+ exceptional fragment. Preserve anchors and map every old URL in either mode.
168
175
 
169
176
  e. Write the page as a draft:
170
177
 
@@ -192,8 +199,10 @@ create_redirect from_path="/old-services" to_path="/services"
192
199
 
193
200
  Walk the inventory; for each URL: did it become a page with the same
194
201
  path? If yes, no redirect. If renamed, `create_redirect`. If
195
- intentionally dropped, mark it `excluded` via `update_migration_url` (the
196
- customer should sign off on every dropped URL).
202
+ combined with another page, redirect to the relevant combined content. Do not
203
+ mark a public page excluded just because the new design omits it. Public URL
204
+ retirement requires a separately agreed exception; admin/session noise can be
205
+ excluded with a recorded reason.
197
206
 
198
207
  Use a pattern only after verifying every affected source-to-destination mapping.
199
208
  For an explicitly approved prefix change, `/old-blog/:slug` → `/articles/:slug`
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: tr-migration-evidence
3
- description: Source-first design baseline, native capability mapping and evidence gates required before bulk website migration or visual acceptance.
3
+ description: Choose preserve or renew intent, map standard and custom blocks, preserve old URLs, and verify content, design and behavior before migration acceptance.
4
4
  ---
5
5
 
6
6
  # Migration evidence contract
@@ -10,15 +10,88 @@ another MCP client) working through MCP and the public API. The portal's built-i
10
10
  AI assistant has no migration tools: it does not import, convert or verify sites.
11
11
 
12
12
  Use this shared contract with WordPress, Astro, URL and multisite recipes.
13
- Default to preserving the source appearance and behavior. A redesign requires
14
- explicit scope. A partly migrated target is not the design reference.
13
+ ## Choose the migration intent before writes
14
+
15
+ Record `preserve` or `renew` in the workspace's `brief/migration.md` (or the
16
+ project's equivalent brief), with scope, source URLs and the user's decision.
17
+ These are planning labels, not fields accepted by the migration API. Ask when
18
+ the intent is unclear; do not infer redesign permission from “migrate”.
19
+
20
+ | Intent | Source material | Acceptance reference |
21
+ | --- | --- | --- |
22
+ | Preserve: change publishing platform | Keep text, images, structure, visual identity and behavior as closely as practical. | The original site. Record deliberate deviations and their agreed benefit. |
23
+ | Renew: improve design and content | Use source text, images, structure and graphic design as raw material. Agree what to retain, rewrite, combine or replace. | The agreed brief, content plan and approved prototypes, not visual similarity to the old site. |
24
+
25
+ Both paths preserve facts, ownership, required business behavior and historical
26
+ URL continuity. Renewal does not authorize invented claims, removal of useful
27
+ content or an unapproved domain switch. Do not use a partly migrated target as
28
+ an accidental design reference. Protect existing target edits in either path.
29
+
30
+ ## Use editable blocks in both paths
31
+
32
+ 1. Inspect standard block schemas, composition starters, named styles and Page
33
+ templates. Prefer these when they fit.
34
+ 2. When they do not fit, read `tr-custom-blocks` and create a reusable Site block
35
+ type with meaningful editable fields. Prefer a composition of standard blocks;
36
+ a field-driven template type is appropriate when composition cannot express it.
37
+ Validate the type, preview it, save/read it back and test a representative use
38
+ in static output. Do not store a whole page as an opaque HTML field.
39
+ 3. Raw HTML is a last resort for a small, exceptional fragment. Record the exact
40
+ block/Page, why neither standard nor custom types fit, editing limitations and
41
+ verification. Keep the surrounding page block-based whenever possible.
42
+
43
+ A justified HTML exception is a unique art-directed hero: layered imagery,
44
+ animation and text placed precisely over a background at different breakpoints.
45
+ Prefer a field-driven custom type when editors need to change its text, images
46
+ or links repeatedly; a one-off hero may remain an isolated HTML block. Verify
47
+ actual breakpoints, cropping, keyboard access, contrast and reduced motion. Keep
48
+ essential copy and links usable without animation. Do not copy source-platform
49
+ scripts; any custom script needs explicit scope and the supported runtime.
50
+
51
+ On Core 0.2.89 / MCP 0.45.69+, composition preflight accepts reviewed custom types in
52
+ `reviewed_custom_block_types: [{type, reason}]` and rare HTML blocks in
53
+ `reviewed_html_blocks: [{block_id, reason}]`. Inspect the deployed schema first on older installations. These are reviewer
54
+ attestations, not proof of quality. They only acknowledge those specific choices; missing
55
+ block types/fields and unreviewed workarounds still block readiness. Do not call
56
+ something business-specific just to bypass a check. A confirmed renderer bug
57
+ still needs a platform fix, not a disguised HTML/CSS workaround.
58
+
59
+ ## Import is not block reconstruction
60
+
61
+ The managed WordPress importer deterministically stores cleaned HTML and shared
62
+ references, without AI rewriting. That is a source-preserving intermediate step.
63
+ The external agent rebuilds it into reviewed blocks/templates for either intent;
64
+ `set_page_mode` does not perform conversion. Keep the complete source, map every
65
+ in-scope content element, and do not silently truncate long pages. In preserve
66
+ mode retain wording; in renew mode track approved rewrites and source facts.
67
+ An import finishing does not mean design, block reconstruction or launch is done.
68
+
69
+ ## Old URLs must continue to work
70
+
71
+ Inventory public URLs from sitemaps, CMS records, internal links, pagination and
72
+ available traffic/backlink exports, including important assets and anchors.
73
+ Record each old URL as preserved or redirected to a relevant working destination.
74
+ Renewal may merge pages, but every old address still needs a meaningful mapping.
75
+ Never blanket-redirect to the homepage or mark public content `excluded` merely
76
+ to make coverage green. Private/admin/session noise can be excluded with a reason;
77
+ retiring a public URL requires a separately agreed exception to this contract.
78
+
79
+ Use `add_migration_urls` with `source_origin`, keep a per-URL mapping, and run
80
+ `verify_migration_urls` against the authorized deployed candidate, then
81
+ `get_migration_launch_report`. Check both slash forms, redirect chains/loops,
82
+ query routes and fragments with their actual routing mechanism. DNS is not an
83
+ HTTP redirect: changed hostnames need a host that continues serving redirects.
84
+ A missing route or a 200 at unrelated content fails continuity in either path.
85
+ Do not switch traffic until these checks pass and cutover is authorized.
15
86
 
16
87
  ## Gate 1: source baseline, before conversion
17
88
 
18
- Record the authoritative source URL/date, scope, relevant Core version, active
89
+ Record the chosen intent, authoritative source URL/date, scope, relevant Core version, active
19
90
  Page templates and overrides. Inventory home, category/archive, long/short
20
91
  articles, downloads, empty related lists and each distinct business surface.
21
- Capture screenshots and computed geometry at matching actual `innerWidth`
92
+ For preserve, capture source and target geometry; for renew, compare the target
93
+ with the approved design while retaining source coverage evidence. Capture
94
+ screenshots and computed geometry at matching actual `innerWidth`
22
95
  values (320/390/768/1024/1280/1536 where relevant, plus both sides of actual
23
96
  breakpoints). Record loaded font families/weights, color panels, logo/header,
24
97
  hero, gutters, article/sidebar widths, card anatomy/grid and footer. Inspect
@@ -42,9 +115,10 @@ back each prototype, then inspect its preview and an authorized static build.
42
115
  Example: a 48px heading uses `core/heading.font_size_px: 48` on Core 0.2.25+;
43
116
  read the saved block back and measure computed `fontSize` at 1280px. Writing
44
117
  `font_size_px` to `core/prose`, which does not declare it, is an unsupported
45
- mapping even if an API preserves that unknown key. Stop with
46
- `waiting_for_native_support` when required capability is absent or ignored;
47
- do not hide the gap with tenant CSS or generic custom blocks.
118
+ mapping even if an API preserves that unknown key. A new presentation may use
119
+ a reviewed custom type as described above. Missing or ignored declared behavior
120
+ is a platform defect: stop that recipe with `waiting_for_native_support` and do
121
+ not disguise the failure with tenant CSS.
48
122
 
49
123
  Validate shared Page references, item order, missing images and empty/unpublished
50
124
  references. Keep semantics separate from presentation: category emoji belongs
@@ -66,13 +140,12 @@ behavior or other semantics unsupported by the chosen block: record the gap
66
140
  and use a supported composition or stop for native support.
67
141
  Do not apply a template to hundreds of Pages until its prototype passes.
68
142
 
69
- ## Report platform gaps, do not patch them
143
+ ## Distinguish custom presentation from platform defects
70
144
 
71
- Matching the source sometimes needs something the platform does not offer.
72
- Never close that with site or page `custom_css`, raw HTML or a generic custom
73
- block: the next site hits the same gap and the workaround breaks on the next
74
- Core change. Record it and report it instead. Check these five causes first,
75
- because each has looked like a site problem:
145
+ A new layout or reusable visual component is a legitimate custom block, not
146
+ necessarily a Core defect. Use the block hierarchy above. When a declared Core
147
+ feature fails, do not cover it with site/page CSS, raw HTML or a replacement
148
+ block. Record and report it. Check these five causes first:
76
149
 
77
150
  1. **A platform default no setting reaches.** Compare computed text rendering
78
151
  and base styles on `body`, links and headings (`-webkit-font-smoothing`,
@@ -99,7 +172,7 @@ block ID and type or the setting; source and target computed values; what is
99
172
  missing, ignored or wrong; the proposed setting or fix; and acceptance
100
173
  criteria a reviewer can measure. State that no workaround CSS is in place.
101
174
  Mark the affected recipe `waiting_for_native_support`, continue independent
102
- work, and verify against the source again after the release.
175
+ work, and verify against the chosen acceptance reference after the release.
103
176
 
104
177
  ## Separate files, addresses and business behavior
105
178
 
@@ -176,13 +249,14 @@ pre-cutover scope honestly when DNS or integrations remain out of scope.
176
249
 
177
250
  The initial route census must combine source sitemaps, internal links, archive
178
251
  pagination, CMS inventory and known utility routes. Include homepage, archives,
179
- 404/search behavior and routes outside the sitemap where present. Do not invent
180
- features absent from the source. Assign every route a recipe, template override,
252
+ 404/search behavior and routes outside the sitemap where present. In preserve mode, do not invent
253
+ features absent from the source. In renew mode, include additions in the agreed brief. Assign every route a recipe, template override,
181
254
  composition or documented exception. Inventory the whole shell: content outside
182
255
  `main`, header, footer, service navigation and archive heroes are not optional.
183
256
 
184
- Derive required evidence from that census. Pair every in-scope source/target route
185
- at mobile and desktop; add each unique component, breakpoint and interaction
257
+ Derive required evidence from that census. For preserve, pair every in-scope source/target route
258
+ at mobile and desktop; for renew, compare every target route to its approved
259
+ prototype and account for the source content/URL mapping; add each unique component, breakpoint and interaction
186
260
  state. Inspect page-specific media, lists, tables, embeds, CTAs, anchors and related
187
261
  content. One representative article cannot attest every article's content.
188
262
 
@@ -207,12 +281,13 @@ partial or template changes invalidate every dependent row; content changes
207
281
  invalidate that route and dependent listings. An old revision cannot approve a new
208
282
  one. Source availability failures remain `UNVERIFIED`, not silently excluded.
209
283
 
210
- Visual signoff requires zero uncovered required surfaces and zero unexplained
211
- regressions. `FAIL` or `UNVERIFIED` blocks that signoff, even when a separately scoped
284
+ Visual signoff is against the chosen intent: source fidelity for preserve,
285
+ approved design/content for renew. It requires zero uncovered required surfaces
286
+ and zero unexplained regressions against that reference. `FAIL` or `UNVERIFIED` blocks that signoff, even when a separately scoped
212
287
  technical publication has approval. An intentional deviation needs exact before/
213
288
  after evidence, specific user benefit and accepted scope; “cleaner” is not a reason.
214
289
 
215
- Examples from a moving-services migration:
290
+ Preserve-mode examples from a moving-services migration:
216
291
 
217
292
  | Surface | Passing evidence | Separate visual result |
218
293
  | --- | --- | --- |
package/skills/tr-seo.md CHANGED
@@ -36,9 +36,10 @@ read_site_settings
36
36
  ```
37
37
 
38
38
  For each page, check:
39
- - Is `seo_title` set? (if not, Google uses `title` + suffix — often fine;
40
- aim for 50–60 characters, longer gets truncated)
41
- - Is `seo_description` set? (150–160 chars, unique per page, includes keywords)
39
+ - Does the rendered title accurately identify the page, including any suffix?
40
+ - Is the description useful, specific and supported by the page's content?
41
+ Search snippets may be rewritten or truncated; fixed character counts are
42
+ not acceptance rules and must not cause padding or lost meaning.
42
43
  - Is `og_image` set for the homepage and key landing pages?
43
44
  - Does the page have exactly one `<h1>`?
44
45
 
@@ -53,7 +54,7 @@ batch_update_pages updates=[
53
54
  ```
54
55
 
55
56
  Guidelines:
56
- - 150–160 characters
57
+ - Use the length needed for a clear, accurate summary; avoid padding
57
58
  - Include the most important keyword naturally
58
59
  - Make it a compelling reason to click, not a summary of the page's nav
59
60