Skills
Skill 35 of 48
Maps discovered source entities and fields to Wix targets and documents lossiness.
21 minutes · 4,595 words · 20 sections
Install
npx skills add wix/skills --skill rp-mappernpx skills add wix/skills/plugin marketplace add wix/skillsThe first command installs just this skill, by the name in its SKILL.md; the second installs the whole repository.
Create a mapping plan from the discovered source schema into Wix entities and Wix data structures.
This skill translates source entities and fields into Wix targets. It should define what each source record becomes in Wix, how fields transform, and where custom schemas or extended fields are required.
migrations/<project>/source-schema.jsonmigrations/<project>/source-profile.md when availablemigrations/<project>/orchestration/checkpoints.jsonmigrations/<project>/orchestration/decisions.jsonRead only these canonical artifacts by default. Do not ingest the raw discovery dump
(migrations/<project>/data/...) wholesale — it is platform-specific and large. Instead, when an
entity’s mapping is ambiguous, follow that entity’s rawFile pointer in source-schema.json to open
just that one raw file for verification. Skip entities whose inUse is false (advertised by the
source but holding no records).
sourceMetaA source adapter may pre-fill part of the mapping when it recognizes the source format. Two
sourceMeta keys carry that, and both are optional — a schema without them maps exactly as
before:
sourceMeta.mappingHints[] ({ column, wixTarget, matchedAlias }) — an advisory
pre-fill, e.g. from a recognized vendor’s CSV profile. Seed the corresponding
fieldMappings[] entries from it so the user reviews and corrects instead of authoring from
scratch, and record decisionProvenance: source_platform_rule. It is never authoritative:
the source’s own field list still governs, and every hint still passes through the mapping
review checkpoint.sourceMeta.drift.unmappedColumns[] — real source columns the adapter’s profile did not
recognize. Each one must be explicitly mapped or explicitly recorded as skipped; leaving
them unaddressed is how a stale profile turns into silently dropped data.In addition to the project artifacts above, consult the relevant bundled adapter resource when the mapping depends on platform behavior that should not be guessed:
wix-replatform/resources/rp-source-<platform>/SKILL.mdwix-replatform/resources/rp-target-wix/SKILL.mdwix-replatform/resources/rp-target-wix/scripts/domain-knowledge.jsTreat those adapter resources as the authoritative home for platform knowledge. Do not copy source/Wix behavioral rules into the mapping plan as if they originated there; cite and apply them there.
Do not author field mappings by hand when a vendor overlay already knows them. Run the deterministic resolver first and let it do the mechanical join; your judgement is needed only for what it cannot decide.
node scripts/resolve-mapping.js --fileset <migrations-root>/<project>/data/csv-discovery/fileset.json \
--out <migrations-root>/<project>/mappingIt joins three inputs that are all already data — the header set discovery actually observed, the
vendor overlay’s columnMap, and rp-target-wix‘s lib/wix-target-spec.js — and writes
mapping/mapping-resolution.json plus mapping/mapping-residue.json. Exit code 2 means blocked:
a required Wix input is unfilled, or an overlay names a canonical field that does not exist.
What it decides, so you don’t:
residue.unmappedColumnsresidue.unsupportedTargetsresidue.unfilledRequired (a blocker)overlayDrift (the profile is stale)derivedEntities, including
requiresFaithfulnessLedgerEntry when the source taxonomy is hierarchicalYour job is residue, and only residue. Each entry needs an explicit decision — map it to a
canonical field, or record it as intentionally skipped with a reason. Leaving an entry undecided is
how a stale overlay turns into silently dropped data.
Two rules keep this honest:
rp-source-csv/vendors/<vendor>.json plus a header fixture in tests/fixtures/csv/headers/. That
is a data edit with no skill-logic change, and it means the next run resolves it deterministically
instead of asking a model again. A mapping decision made twice is a missing overlay entry.rp-target-wix/lib/wix-build.js turns a canonical record into a Wix Stores V3 create body
deterministically, and lib/wix-target-spec.js declares every field, constant and trap it relies
on. This layer is vendor-independent — Shopify, WooCommerce, Magento and BigCommerce all
converge on it — so codegen must vendor and call it, exactly as the reader vendors csv-parse.js.
Do not emit a per-project to-wix.js re-deriving money objects, slug sanitization, choice-by-name
variant references, or the empty physicalProperties trap. Those are settled, tested, and
regression-locked against 220 payloads from two live-verified imports
(tests/mapping/wix-build-oracle-test.js).
The spec also settles the one price decision that recurs on every vendor: see
STORES_V3_TARGET.priceResolution. A (regular, sale) pair is resolved into Wix’s
actualPrice/compareAtPrice, not mapped field-for-field — getting it backwards silently
overcharges every discounted product.
sourceMeta.candidateTargetRefs[] when discovery supplied it;
otherwise run domain-knowledge.js resolve-source; use semantic reasoning only when no
candidate exists and record unverified confidence.unsupportedTargets
already names them with reasons; carry those into the faithfulness ledger rather than restating.blockedSourceDependencies on the selected target entities, aggregate them
by sourceEntityRef, and write the blocked-data request state and review artifact below.migrations/<project>/mapping/run.jsonmigrations/<project>/mapping/mapping-plan.jsonmigrations/<project>/mapping/entity-decisions/<entity>.jsonmigrations/<project>/mapping/llm-handoff.jsonmigrations/<project>/mapping/review/mapping-gaps.jsonmigrations/<project>/mapping/review/mapping-plan.mdmigrations/<project>/mapping/review/mapping-summary.mdmigrations/<project>/mapping/review/blocked-data-requests.mdmigrations/<project>/state/blocked-data-requests/<sourceEntityRef-slug>.jsonmigrations/<project>/orchestration/checkpoints.jsonmigrations/<project>/orchestration/approvals.jsonRead only authored blockedSourceDependencies[] from selected target entity knowledge; never
infer a request from db-only, admin-page-only, or another channel by itself. Use the shared
lib/blocked-data-requests.js builder to aggregate one request per sourceEntityRef, appending
all dependent target entity/field rows. Resolve each source entity’s blocked[].fulfillment
through rp-source-wordpress/lib/blocked-data-handlers.js; offer it only when its fixture
self-test passes and, for bridge-plugin, the matching manifest case is production-ready.
Persist the request under state/ as the authority and render
mapping/review/blocked-data-requests.md as a passive review section. This adds no new blocking
prompt. At an interactive mapping pause, set askedInteractively: true only if the request is
actually shown and a human can decline it. In 1-click mode set it to false; an unanswered
request remains missing, never declined, because the run did not pause to ask.
Include for each source entity:
comment, item, entry, record, media, user, etc.). State what the entity
actually contains here, based on the discovered data, not just the route name.targetRef, targetDomain, targetEntity, targetClassification,
importReliability, preferredWrite, and knowledgeEvidence when the decision uses a
bundled domain entity recordtargetClassification is manual-mapping: the entity’s manualSteps
verbatim (prerequisite, actor-tagged steps, mechanism, evidence) instead of field
mappings/transformation/validation rules below — there is no transform to author, only a
runbook to carry over unchangedsafeModeReplacements[] when safe mode is enabled, listing every mapped email or phone
field that enters an outbound Wix payload. Write the same array in both
mapping/mapping-plan.json for the entity decision and
mapping/entity-decisions/<entity>.json.safeModeReplacements[], so email/phone replacement coverage is visible without opening
the JSON artifactsWhen a source entity is generic or overloaded, the mapping plan must name the concrete subtypes or usage contexts it observed. Examples:
comment: blog post comments, product reviews, page commentsitem: order line items, catalog items, CMS rowsmedia: blog hero images, product gallery assets, downloadable filesDo not leave a generic entity label unexplained if the discovered data shows multiple real-world meanings.
Safe mode is enabled by default through config/wix.env unless the user explicitly sets
SAFE_MODE=false before mapping. When enabled, mapping artifacts must emit semantic
contact-channel metadata so generated imports can replace outbound email and phone values
through deterministic shared writer code.
For every mapped entity, mark fields for safe-mode replacement when source evidence, target-Wix domain knowledge, target field semantics, user-directed mappings, CMS/custom fields, extended fields, form submissions, metadata, or plugin fields indicate an email or phone contact channel.
Each safeModeReplacements[] entry must include:
{
"kind": "email",
"sourcePath": "billing.email",
"targetPath": "billingInfo.email",
"required": true,
"reason": "source and target are email fields"
}targetPath is relative to the Wix-shaped object or request body defined by the mapping
decision. Use the shared safe-mode path grammar: object fields (billingInfo.email,
contact.email.email) and array wildcards (lineItems[].buyerInfo.email,
contact.additionalEmails[].email). When the same source value is copied to multiple
Wix fields, list each target path.
Load target-side hints from selected rp-target-wix entity records’
safeModeContactFields[] and merge them with source-side evidence and user mapping
decisions. If SAFE_MODE=false before mapping, do not require this metadata for execution.
This metadata must be surfaced in both machine and human mapping artifacts:
safeModeReplacements[] into mapping/mapping-plan.jsonsafeModeReplacements[] into mapping/entity-decisions/<entity>.jsonmapping/review/mapping-plan.mdSafe mode replacements section in
mapping/review/mapping-summary.md listing the affected entities and the mapped
email/phone pathsDo not leave safe-mode contact replacement coverage implicit in field tables or only in JSON. A reviewer should be able to confirm from the review markdown which outbound email/phone fields will be replaced in safe mode.
Be explicit about the difference between a source ID and a Wix target ID.
crosswalkAuthority: "local", a per-entity crosswalkStrategy, and a
reconciliationStrategy used for dedupe, resume, and relationship resolution.ImportCrosswalk is optional. Use cmsMirror: "none" | "download" | "upload" | "download-and-upload" to request it explicitly. It is a copy/seed adapter for
existing-site or handoff reference flows, not the required resume authority.WIX_SITE_STRATEGY=existing means the target is not an empty site provisioned to this
mapping’s shape — it is a site in use, with its own collections, fields and records. Map
against what is actually there:
cmsMirror: "download-and-upload". On an existing destination the on-site
ImportCrosswalk is not an optional convenience: it is the only record of prior imports
visible to a run that does not share this project’s local state.For every in-scope source entity that appears on the public website, include an explicit
urlPolicy in mapping/mapping-plan.json and the relevant
mapping/entity-decisions/<entity>.json artifact.
Minimum urlPolicy fields:
public: true for public routed entities; false for entities intentionally outside
URL preservation.sourceBasePath: the observed source base path, such as /shop/products; use null
only when the source URL cannot be derived and record that risk.sourceSlugField: source field holding the slug, when present.sourceUrlField: source field holding the full/permalink URL, when present.targetBasePath: known Wix destination base path, or null when website-builder route
selection is deferred.targetSlugField: planned target slug field, when applicable.preserveBasePath: whether the future website-builder phase should try to preserve the
source base path.preserveSlug: whether generated code should preserve the source slug unless target
validation or collision handling forces a change.redirectMode: record-if-different, manual-review, or none.If the same source entity type has multiple public route shapes, record each observed route class separately instead of guessing one base path. Slugs are identity and SEO data, but slug preservation alone is not URL preservation; route/base-path intent must be captured as data for the future website-builder phase.
Mapping review artifacts must include a short URL preservation section listing:
Confirm exact Wix entity/collection/field names before mapping a source field onto them — never invent a Wix API or field name.
When the mapping depends on Wix runtime behavior rather than just field names, verify and
follow the relevant rp-target-wix contract as well. Examples include create ordering,
native tag handling, category assignment requirements, member prerequisites, and whether a
product/media field should be sent as an external URL for Wix-side ingestion.
For entity suitability, do not grep or paste whole domain files into the plan. Use:
node skills/wix-replatform/resources/rp-target-wix/scripts/domain-knowledge.js summarize-entities --refs <domain/entity,...>Load full entity records only for selected candidates that materially affect the current project.
Field.type you assign must be a real
member of the Create Data Collection Type enum. (Common trap: there is no SLUG
type — a slug maps to a TEXT field. Never assign a guessed enum value and flag it
unverified; resolve it or omit it.)rp-target-wix‘s verified contracts plus
published Wix REST/SDK documentation and conservative, known-good names. Mark anything
you could not verify directly as unverified in the mapping plan so it is surfaced
before execution.Resolve ambiguous mappings using the documented default, record the decision and rationale
under the machine mapping artifacts and render them into mapping/review/mapping-plan.md,
and keep going. Known fidelity forks
(e.g. comments anonymize vs. skip) should already be answered by the submission intake;
apply those answers rather than re-asking. If a required input is truly missing, surface it
as a blocker rather than silently guessing.
If the source entity name is generic but the observed data disambiguates it, record that disambiguation explicitly in the machine mapping artifacts and review plan. Do not force later stages to infer what “comments”, “items”, or similarly broad labels meant in this specific migration.
The mapping stage is where lossiness and coverage gaps are discovered, so it is where
they must be recorded — not at execute time, which is too late to do anything but
report. Maintain a faithfulness ledger in mapping/review/mapping-gaps.json and render it
into mapping/review/mapping-plan.md, listing everything that
will not migrate cleanly, including:
unverified native REST path and notify the RePlatform team about
the missing writer. Use CMS only when no suitable native Wix entity exists, or when the
native entity is rejected for fidelity/side-effect reasons.Mandatory trigger — plugin coverage. Every row in discovery/plugin-coverage.json whose
status is not migration-planned must produce a mapping/review/mapping-gaps.json entry
carrying the capability, the status, and the row’s user-facing impact line — and so must a
migration-planned row that is lossy or carries blocked[] entries. This is what makes
plugin loss visible: a capability the pipeline discovered but could not deliver has to reach
the execution-plan report, and the ledger is the only path there.
Each such entry must also carry a severity, because a plugin-heavy site produces far more
rows than it has real problems — on a 55-plugin store, 26 rows were “we don’t recognise this
plugin”, which would bury the entries that matter if they all read alike. Use the same
vocabulary as profile pitfalls:
severity | Means | Typical rows |
|---|---|---|
blocker | data the user would care about is not coming across | requires-development; a blocked[] entry still unresolved or declined |
warning | it migrates lossily, or we are not sure yet | pending (including cannot-tell); migration-planned · via cms where the source is semantically richer |
info | accounted for, nothing lost that we know of | no-need-to-migrate with basis: proposed; migration-planned · proposed with no known loss |
The execution-plan report leads with blocker and warning and summarizes info as a count
with a pointer. Severity is a rendering aid, not permission to omit: every row still gets
an entry, so the audit trail stays complete and a mis-severitied row can be found later.
Additional plugin rules:
sourceMeta.candidateTargetRefs[] first, then
domain-knowledge.js resolve-source, then the target knowledge base’s capability index
keyed on sourceMeta.capability.sourceMeta.recognized: false) may only be mapped to a native Wix
entity when the domain knowledge confirms the capability. Otherwise map them to CMS. The
proposed capability from discovery is recorded with confidence: proposed, never a
target decision — treating a guess as native is how a silent, lossy write happens.mapping/review/mapping-plan.md, per capability: the source
entity and the fields it actually carries, the target entity and the fields it expects,
which source field lands in which target field, and which carry nowhere. In
mapping/review/mapping-summary.md, one line naming the source, the target, and the single
consequence that matters. For a derived capability, say in both that the mapping is
proposed rather than confirmed — a reviewer must be able to tell a guess from an
authored match. Without the pairing the user is approving a target name, not a mapping.no-need-to-migrate row with basis: proposed (the agent’s own reading, not a list
entry) is also listed in mapping-summary.md — automation deciding there is nothing to
move is a decision worth seeing.pitfalls[] into the plan, and surface blocker
severities in mapping/review/mapping-summary.md.credentials[] (a plugin’s own API key or secret, beyond the platform
admin credential — e.g. Subscriptions For WooCommerce’s plugin-generated
consumer_secret), the capability’s row in mapping/review/mapping-plan.md states the
credential prerequisite (what key, where the user finds or enables it in the source
admin), and mapping-summary.md carries one line listing every capability that will ask
for such a key. The user learns this at the mapping review, not first as a surprise
blocked: credential ask mid-run; the run-time collection still goes through the
standard batched blocked-and-recoverable ask.requires-development and pending rows belong in the summary’s gaps section in plain
language, even though there is no mapping to make for them.targetClassification: "manual-mapping" entity gets its own section in
mapping-summary.md, separate from both the gaps section above and the review-gate list
below — carry over its manualSteps.steps[] as a numbered list, not a one-line summary; the
point of this section is to hand over a runbook, not to compress it. Do not put these
rows in the pending/gaps section: unlike pending, a manual-mapping row is a complete,
decided mapping the moment it is authored with real evidence — there is nothing left for a
human to decide, only steps for the merchant to execute. It needs no verdict at the review
gate below.Mandatory step — pending rows are decided at the review gate. The mapping review is the
single human gate and the only exit from Pending: every pending row is put to the user
for a decision, none may survive the gate undecided. Four verdicts, each with a producer:
confidence stays proposed until a profile is authored).basis: decision and the
user’s stated reason as its rationale.mapping/review/mapping-gaps.json with severity blocker, emit an api_gap telemetry
event, and record the verdict in the human-signed register
(plugins/requires-development.json, decidedBy = the user) citing the recorded search.source_plugin_coverage
carries the decision); the profile or domain entity is authored between runs, never during
this one.Record each decision in orchestration/decisions.json; blocked-row asks batched at discovery
use the key pluginBlocker:<capability>:<kind> with value provided or declined.
Mandatory trigger — hierarchical source taxonomy → flat Wix target. When a source
entity carries "hierarchical": true (or any parent self-relation) in
source-schema.json and maps to a flat Wix target such as Blog categories, you must
write a faithfulness-ledger entry recording that the parent/child hierarchy is dropped on
import (the Wix Blog category target is flat — it has no parent/child relationship). This
is not optional discipline: the flag exists precisely so
the warning is data-driven. Do not map such a taxonomy without the ledger entry. (If
hierarchy must be preserved, the alternative is a CMS-collection taxonomy with a parent
reference field — note that trade-off in the ledger instead.)
This ledger is the source the execution-plan report draws from to surface “what we won’t
do” to the user before consent (rp-execute-import). If it isn’t recorded here, the
user can’t be warned there.
Every selected entity whose domain knowledge includes IMPORT_UNRELIABLE must create a
mapping/review/mapping-gaps.json entry with the same fixed flag string, the selected
targetRef, a project-specific summary, and the chosen fallback or review action.
Mandatory check — every in-scope entity’s dependencies are also in scope. Run it directly, do not re-derive it by reading prose:
node skills/wix-replatform/resources/rp-target-wix/scripts/domain-knowledge-validate.js \
--check-scope <comma-separated domain/entity refs in the mapping plan>Pass only the plan’s own selected refs — checkScope walks the dependsOn transitive closure
itself starting from that list, so do not pre-expand it by hand. It fails closed on three distinct,
named problems, any one of which is a gap the user must resolve at the gate before proceeding:
domain/entity
file (typo, stale ref). Fix the ref.dependsOn that isn’t in your original selection (e.g. importing orders without also
importing gift cards). Add the missing entity to scope, or accept and record the consequence
(e.g. orders referencing unresolvable gift cards) — not something codegen should discover later
by producing broken references.dependsOn authored at
all (distinct from “reviewed, no dependencies”). --list-missing-deps shows the same backlog
outside the context of any one plan.A clean --check-scope result means only this plan’s own reachable set is fully reviewed and
in scope — it says nothing about entities outside that reachable set. checkScope walks from
your selected refs, not from the whole domain tree, so an unrelated entity with no dependsOn
authored at all stays invisible to this gate until some plan actually reaches it. Run
--list-missing-deps (unscoped, whole-repo) separately to see the standing backlog.
As of this pass, only 19 of 62 entities in this repo have dependsOn authored — expect to hit
Unreviewed on most real plans today, not just as an edge case. That is not this gate failing;
it is the gate doing its job on a knowledge base that is still mid-backfill. When it happens:
author dependsOn on the reachable entity now, as part of the mapping work you are already
doing — deciding a mapping plan already means knowing what that entity depends on, so this is
recording that decision, not new research — then re-run --check-scope. Do not treat Unreviewed as
a reason to skip the gate or fall back to reading prose by hand for that entity.
This is the check that was missing when ecom/order.json first needed gift-cards/gift-card (see
spec 0042). Corrected 2026-08-18 (PR #142 review): an earlier version of this guidance told
callers to expand to the full transitively-reachable set by hand before calling --check-scope,
because the check only examined one hop per call. That burden is now the tool’s job, not yours —
checkScope performs the walk itself; pass it your plan’s actual selection and nothing more.
Default to importing only media referenced by in-scope entities such as posts, products, collections, categories, or CMS rows that are actually being migrated. Unattached source-library media is out of scope by default unless the user explicitly asks for a library/archive migration.
When an entity carries media, consult rp-target-wix for the target behavior:
After mapping/mapping-plan.json is written, create
migrations/<project>/mapping/review/mapping-summary.md as a
short review artifact for the user. Its purpose is to make the mapping decision easy to
review without forcing the user through the full plan.
The summary should:
mapping/review/mapping-plan.mdunverified
target paths from the faithfulness ledgerKeep it concise. The user should be able to decide “yes, this is the right migration
shape” from this file alone, then consult mapping/review/mapping-plan.md only when they want detail.
Recommended structure:
mapping/review/mapping-plan.mdSource -> Wix targetsPlugin coverage (when the source reported plugins): one line per capability that is not
migration-planned · confirmed, in the user’s terms, plus anything they must supply or
accept losingURL preservationMain gaps / lossinessImportant setup implicationsSafe mode replacements when applicableQuestions or risks to confirmDo not restate full field tables or detailed transformation rules here unless a specific field-level issue is central to the approval decision.
Once both mapping artifacts exist, reset orchestration/approvals.json so
mapping.status=pending, then stop and ask the user to review
migrations/<project>/mapping/review/mapping-summary.md. The checkpoint should make clear:
mapping/review/mapping-plan.mdDo not proceed to rp-setup-discovery or rp-import-codegen until the user accepts this
mapping review checkpoint, unless the user explicitly asks to continue provisionally. In
explicit user-requested 1-click mode (automationMode=one_click, source=user), still
write the same review artifacts, but record the checkpoint as accepted by the agent and
continue immediately. A missing mode or a non-user-authored one_click value is normal
interactive mode and must pause here; file upload does not imply one-click.
rp-import-codegen can implement them deterministically.unverified and surface the risk before execution.Maps discovered source entities and fields to Wix targets and documents lossiness. Use when creating machine-readable mapping artifacts and review markdown after discovery.
The verbatim description from this skill’s front matter — the string an agent matches on to decide whether to load it.
main, last pushed 24 September 2026.SKILL.md, not by matching a directory convention. 8 distinct layouts observed: .claude/skills/*/SKILL.md, skills/*/SKILL.md, skills/wix-headless-fast/*/skill.md, skills/wix-headless/*/skill.md, skills/wix-replatform/resources/*/SKILL.md, wix-headless-replatform/resources/*/SKILL.md, */SKILL.md, wix-replatform/resources/*/SKILL.md.h1 and no skipped levels:.claude-plugin/marketplace.json by Wix, declaring 1 plugin. It is read for editorial metadata only — never as the skill index, which is always the repository tree./wix/skills.md, and each skill at its own .md URL.3 files · 42 KB
Everything this skill ships beside its prose. All of it is set here, as subchapters of skill 35.
Executable code the skill can run.
Everything else published alongside the skill.