Skills
Skill 42 of 67
Always-active telemetry companion for RePlatform migration runs.
21 minutes · 4,574 words · 9 sections
Install
npx skills add wix/skills --skill rp-telemetrynpx 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.
Capture per-run telemetry that tells us what to improve in the skills and the underlying Wix tooling. This skill stays active alongside the migration skills for the entire run; the migration skills themselves are unchanged and know nothing about telemetry.
Observation, not diagnosis. Every field records what was observed — what happened, what was expected, what actually occurred, where, and how often. Never record a root cause, a fix, a recommendation, or a workaround-as-solution. There is deliberately no field for them; the schema rejects unknown fields. Root cause is derived later, at review time, by a reviewing agent with full context — not asserted by you in the moment.
Three discipline rules apply to every free-text field (what_happened, expected,
actual):
entity_type: "product" — never a product’s name, SKU, price, or body text.For investigated mapping coverage, use lib/knowledge-observation.js event(...) and the
normal recorder. It requires findingClass (missing-knowledge, missing-writer,
target-limitation, source-ambiguity or conflicting-knowledge), public targetRef/operation,
toolkitVersion, outcome (resolved-mapping, deferred-field, deferred-record or verified-repair),
verificationLevel and affectedCount (measured integer or null). Record successful novel
mappings as well as unresolved work. Only verified read-back supports verified-repair.
The validator admits registered public identifiers; unknown operations use unregistered.
It rejects arbitrary extra keys. Never pass a raw custom key, source value or customer ID.
The recorder owns JSON in actual/BI actualSkill; do not combine this payload with an
independent actual. Occurrences, affected observations and distinct runs are different counts;
overlapping decisions do not establish a distinct-record total. Existing offline/disabled BI
delivery and replay apply; local persistence is not a claim of warehouse ingestion.
All telemetry is persisted through the bundled recorder — never hand-write or edit
run-telemetry.json or telemetry/ files. Run it from this resource directory
(see CONVENTIONS.md), pointing at the active migration project:
node scripts/rp-telemetry.js <command> [...] --project <abs path to migrations/<project>>The recorder owns everything mechanical: schema validation (it rejects invalid enums and
unknown fields — fix and retry, never guess around it), timestamps, per-class event
folding, the run/attempt/session resume model, the privacy scrub, and the well-formedness
gate at finalize. It prints one JSON result per call; {"ok":false,...} lists exactly
what to fix.
| Call | When |
|---|---|
start '<dims-json>' | At run begin — before any other pipeline step. Resumes an unfinalized run automatically. |
dims '<dims-json>' | Whenever a dimension becomes known mid-run (platform version and extensions after discovery, site_id after provisioning). |
stage start <stage> / stage end <stage> --outcome <outcome> | At every stage boundary. Outcomes: passed, halted, failed, skipped. passed is refused for codegen and setup_discovery while that stage’s llm-handoff.json has needsLlm: true or open blockers/unresolved/openItems; record halted instead. Never pre-fill the outcome in a subagent brief. |
meter [--api-ms N --model-ms N --script-ms N --input-tokens N …] | Measured latency/token counts for a stage. Call it whenever you have real numbers; see “Metering” below. |
wait start [--halt <subtype> --skill <s> [--what '<text>']] / wait end | The moment the run halts for the user, and the moment it resumes. This is how user latency stays out of active_ms — never estimate elapsed time yourself. Pass --halt for a needs-user halt and the recorder emits the paired halt_needs_user event for you. |
record '<event-json>' | The moment something observable happens (taxonomy below). |
digest --transcript <path> [--offline] | Just before finalize — a deterministic parse of this run’s Claude Code session transcript (cost, turn counts, tool failures, retry loops, hook errors). Never authored by you; --offline re-runs it later against a checkpointed or local transcript for a run that died before calling it. |
finalize '<rollup-json>' | When the run reaches a terminal state. |
rebuild [--attempt <n>] [--push] | Only on request, to re-assemble a past run’s signal document from its archived journal after a recorder fix — never during a run. --push re-emits the rebuilt run to the BI sink (backfill after an outage; idempotent — the reviewer dedupes at query time). |
status | To orient after a resume. |
Preflight reads that same status and reports whether a journal exists — active,
absent, finalized_only or unreadable — as a non-blocking line in its result. When
nothing is recording, the preflight script then calls start itself (moving an
unreplayable journal aside first) and adds a recovery field to that line. This is a
safety net, not the main path: start at run begin below stays required. A
recovery: failed reading falls under the “never mention” rule below — it is recorded for
the RePlatform team in the preflight result and progress log, never told to the person
running the migration, and never blocks the run.
start as the first telemetry act of the run, with whatever dimensions are already
known:
node scripts/rp-telemetry.js start '{"source_platform":"wordpress",
"source_site_url":"https://client-site.example","source_acquisition":"public_storefront",
"delivery_mode":"management","destination_strategy":"new_site",
"runtime_env":{"agent_runtime":"claude-code","model":"<model id>"}}' --project <dir>start on a project with an unfinalized run resumes it (same run, same attempt,
one more session) and closes any open wait interval. start after a finalized run
opens the next attempt. Never try to manage run identity yourself.
Always start on resume, even mid-stage. Besides the session accounting, the
resume is a BI heal point: the recorder re-pushes everything the previous session’s
transport may have lost (push failures are journaled, then healed at the next
opportunity — a halted run may never reach finalize, so skipping the resume start
can strand the run’s tail in the local journal). status shows bi_backlog: true
when unpushed rows are pending.
A safety net backs this up, and it does not replace your start: the start of a
replatform run/resume supervisor process, and the orchestration route script after
at least 15 minutes of journal silence, record the resumed session themselves on an
open recording (tagged with a trigger). A start within a minute of such an automatic
session, or at any point during the live supervisor run that opened it, joins that
session instead of opening another — it still records the dimensions you pass. The
15-minute gap is a heuristic about sittings, not a detected session. A failed or
skipped automatic resume falls under the “never mention” rule below: it goes only to
the progress log or the supervisor’s run record.
source_acquisition is an open set of class tokens, but reuse an established one
(admin_api, public_storefront, public_content, file_export) rather than
minting a synonym — cross-run folding depends on stable tokens.
Skills provenance is auto-stamped — you don’t pass it. At start the recorder
stamps two identifiers onto the run so every record can be traced back to the skills
that produced it:
skills_version — the bundle’s semver release label (from VERSION). Coarse and
hand-bumped by design; it is the group-by/order-by key that binds issues to a
release line (“all issues on 1.2.x”, “regressed since 1.1.0”).skills_commit — the exact source commit the bundle was built from: the precise
vendored snapshot within a release. Many commits ship under one hand-bumped
skills_version, so a run reporting 1.0.0 is otherwise unattributable to the
change that produced its issue. The recorder resolves it, in order of authority,
from the sourceCommit stamped into .publish-manifest.json at publish time (the
only source that works in a partner runtime, and the only correct one once the
bundle is vendored into wix/skills), else a dev-mode git rev-parse --short HEAD
of the source checkout, else null.Both may be overridden by passing skills_version / skills_commit in the start
dims (a runtime with better provenance than the recorder can infer), but normally you
leave them to auto-resolve.
Operator identity is auto-stamped too — you don’t pass it, and you must not
invent it. At start the recorder resolves wix_user_id (the operator’s Wix
user GUID) from the Wix CLI’s login artifact, ~/.wix/auth/account.json. A run
normally starts before the destination stage, where the CLI login is created, so
“no login yet” is the usual case, not an edge.
A run that starts without the id is not silent. The recorder makes it a placeholder subject, a random GUID for that run alone, saves it in the run’s journal, and sends the run’s records to BI under it from the first minute. Those run rows carry no operator id, no source site address, no project name and no destination site id. It is random and nothing else: never derived from anything, never shared by two runs, never the all-zeros GUID (BI did not ingest that one).
Every later recorder command (record, stage, meter, source-read, dims, wait,
digest, finalize, start on resume, meter-from-audit.js) and every orchestration route
call (each stage boundary) re-check the login, and wix-destination.js ensure hands over the
Wix account it has confirmed with the operator (never an unconfirmed or switched login). Once
an id resolves, the identity is journaled as a dims record and the whole run is sent again
under the operator’s id with the operator, site address, project name and destination site
id on its run rows; nothing is sent under the placeholder after that. Nobody has to call
anything. Right after you see the operator’s Wix CLI login confirmed you may run
rp-telemetry.js identity to adopt it at once; it also re-sends anything BI has not confirmed and reports adopted and
bi_backlog; with identity already known and nothing pending it does nothing.
A run that never sees a login completes under its placeholder with no operator id; its
health keeps operator_identity_unresolved, and nothing is recorded as a failed send. The
local record is authoritative either way.
You may pass wix_user_id explicitly in the start dims and it wins over resolution, but
only when the runtime genuinely knows better (a hosted runner that authenticated the operator
itself). Never pass a GUID you guessed, copied from another run, or read off a site — a wrong
identity misattributes the run to a real person and is worse than a placeholder.
Never mention any of this to the person running the migration. Telemetry
health is our signal, not theirs: it says nothing about whether their migration
worked, and an unattributed run is complete and correct. It is read from BI and
the local rollup, not narrated in a completion report. The same goes for push
failures and bi_push counts — they are yours to repair and never the operator’s
to hear about.
When a result carries telemetry_attention, repair it yourself and keep going.
Every rp-telemetry.js result adds that field while something is wrong and omits it
otherwise. issues says what: bi_backlog (rows BI has not confirmed) or
identity_not_adopted (a Wix login exists but the run has no operator id yet);
last_failure is a short code for the last failed send; repair is the command.
finalize and rebuild --push report bi_push_failed the same way, with
rebuild --push as the repair. A run with no login yet and sending switched off on
purpose are not trouble and never raise it.
repair command once and read the result
that follows. It re-checks the login and re-sends what BI has not confirmed. The field
is gone when it worked. Do not repeat the repair at later stage boundaries.finalize, if the last result you saw still carried the field, record one
event with event_type: pipeline_defect, subtype: record_defect, naming the issues
in what_happened, then finalize. The event is sent with the backlog as soon as BI is
reachable again. If finalize reports bi_push_failed, run rebuild --push once.
That is all: at most three telemetry commands in a run, and none when nothing went wrong.rp-telemetry.js result, and every stage boundary
runs one.Stage boundaries as the pipeline moves. Map orchestrator steps to stages like this:
| Stage | Covers |
|---|---|
config | Everything before discovery: project resolution, config files, up-front input collection |
discovery | Source discovery (rp-discovery + source adapter) |
mcp_gate | The Wix MCP prerequisite gate between discovery and mapping |
mapping | rp-mapper producing the mapping plan |
mapping_review | The mapping review checkpoint (user-facing) |
setup_discovery | rp-setup-discovery |
codegen | rp-import-codegen |
approval_gate | The execution-plan approval gate (user-facing) |
setup_provisioning | Site creation, app installs, collections — rp-execute-setup |
storefront_build | The website-mode wix-headless build + release; skipped in management mode |
extract | Source extraction to disk, before any write (rp-execute-import) |
import | The import writes (rp-execute-import) |
finish | Verification spot-checks, completion reporting, handoff |
Stages bind to when the work actually runs, not to their canonical order. If the
orchestration runs extraction early (e.g. extract + dry-run before the approval gate,
inside the codegen phase), close the open stage, bracket the extraction in its own
extract stage, then reopen — a stage may be entered more than once, and its
active_ms sums the entries. Booking a real extraction into codegen (and leaving
extract as a milliseconds-long token stage) is exactly the mis-attribution the
extract stage exists to prevent.
When the discovery stage ends, always stamp what it learned:
dims '{"source_platform_version":"...","source_extensions":["..."], "discovered_entity_types":["post","product","event"]}' — pass [] explicitly when
discovery found no extensions (or, improbably, no entity types); a null left behind is
flagged in telemetry_health as source_extensions_null_after_discovery /
discovered_entity_types_null_after_discovery. discovered_entity_types lists every
source entity class discovery found in use — including classes with no Wix target; it
is what finalize cross-checks the volumes rows against, so the “what we couldn’t
import” demand signal cannot be silently under-reported.
wait start / wait end around every needs-user halt: credential requests, the
mapping-review checkpoint, the approval gate, any halt-to-needs-user. Pass the halt
class on the same call —
wait start --halt missing_input --skill rp-mapper --what "run halted at the mapping-review checkpoint awaiting approval"
— and the recorder emits the paired halt_needs_user event mechanically; a stalled
wait with no halt event in its stage is flagged in telemetry_health
(wait_without_halt_event:<stage>). If the session is about to end on a halt, leave
the wait open — the resume’s start closes it, so overnight user latency lands in
waiting_ms where it belongs. If you resume real work while a wait is open (e.g.
investigating something before the user has answered), wait end first and
wait start again when you go back to waiting — active work must never be booked as
waiting.
record events as they happen (next section). Record in the moment, not
retrospectively — improvisation and halts are only reliably knowable when they occur.
digest --transcript <path to this session's CC transcript> just before finalize.
It parses the Claude Code session transcript, deterministically — no model, no
judgment, nothing for you to say. If it fails, carry on to finalize anyway;
telemetry never blocks a migration.
finalize once, at a terminal state, with the rollup:
node scripts/rp-telemetry.js finalize '{"terminal_state":"completed",
"volumes":[{"entity_type":"product","target":"native","target_surface":"stores/v3",
"discovered":142,"planned":142,"attempted":142,"succeeded":139,"failed":3,
"skipped":0,"already_imported":0}],
"verification":[{"subject":"product","method":"query_back","checked":10,"passed":10,"failed":0}],
"operator_acceptance":"accepted"}' --project <dir>volumes come from the execution artifacts (manifest, audit log, crosswalk):
planned and target/target_surface from the approved plan;
already_imported is crosswalk-skipped scope from a prior attempt — never fold it
into skipped.discovered: N, skipped: N, target: none where no target exists, planned 0 or null). “What we
cannot or chose not to import” must be signal-layer arithmetic, never an evidence
dig — rows only for imported types silently erase the excluded half of the approved
plan. This is enforced mechanically: on a completed run, any class stamped in
discovered_entity_types with no volume row is flagged
volume_row_missing:<type> in telemetry_health.verification makes the finish step’s spot-checks countable. checked: 0 is an
honest “written but unverified” — report it rather than papering over it.halted_needs_user only when the run is genuinely
being closed out in a stalled state. A user who declines the plan is
abandoned_by_user (plus a user_decision event with subtype: declined), never
halted_needs_user or failed.blocked terminal state; terminal_state is a registered BI enum. A run
stopped on a blocker (run.json status: blocked) records the stop as a
halt_needs_user event — wait start --halt <subtype> — not as a user_decision.
It stays unfinalized while a resume is expected. If it is closed out on the blocker,
finalize halted_needs_user with stopped_at_stage set. Use abandoned_by_user only
when the user declines to continue.
Route checks, refused run calls and answer --continue keep an explicit hold’s
wait open. They do not count as execution sessions. After replatform resume or a
transition with --status running, the next execution entry resumes telemetry normally.bi_push. If it reports failed > 0 or skipped > 0, the
run (or part of it) did not reach the central BI record: retry once with
rebuild --push, and if it still fails, tell the operator in the completion report
that the run exists only locally — never let a run silently vanish from the shared
record. skipped > 0 means RP_TELEMETRY_BI_DISABLED was set during the session;
on a real migration run that env var must never be set. A clean bi_push result
(failed: 0, skipped: 0) means the rows were handed to frog, not that they have
arrived in BI — per bi-sink.js‘s own transport code, a 2xx is not an ingestion
receipt; only a Trino read-back proves arrival, and no such read-back is available
from inside a run. Report bi_push success as “handed off,” never as “confirmed in
BI.”network_error:<CODE>
(for example ENOTFOUND: the machine cannot resolve the host and probably needs a proxy;
ECONNREFUSED: nothing is listening at the proxy address) or proxy_connect_<status> (the
proxy refused the tunnel, for example 407 for missing credentials). The push follows
HTTPS_PROXY / NO_PROXY from the environment by itself, on every supported Node, so the
operator sets nothing at launch. The proxy must be an http:// or https:// proxy; a socks
proxy is not supported and the push then goes direct. The detail never contains the proxy address.active_ms into where the time actually wentactive_ms alone cannot locate a bottleneck: it is wall-clock between two stage boundaries, fusing
model reasoning + subprocess execution + remote API latency + defect-repair time into one
number. meter splits it, and cost is derived from the token counts.
# a generated script reporting its own measured work
node scripts/rp-telemetry.js meter --api-ms 250000 --api-calls 73 --api-retries 2 --script-ms 1200 --project <dir>
# the agent runtime reporting its own usage for the stage it just finished
node scripts/rp-telemetry.js meter --model-ms 42000 --input-tokens 8000 --output-tokens 1500 --cache-read-tokens 120000 --project <dir>Derive the API half mechanically — do not hand-count it. After a generated import runs:
node scripts/meter-from-audit.js --project <migration dir> --stage import # --dry-run to previewIt reads logs/import-audit.ndjson and emits measured api_ms / api_calls / api_retries.
It exists because a bulk write logs one audit row per item, each carrying the batch’s total
latency — summing rows multiplies one call’s latency by its item count, which can
report several times more API time than the stage existed for. The helper
collapses rows per distinct (runId, endpoint, batch, latencyMs), so a batch counts once while
genuinely separate calls each count.
Fields: durations model_ms / api_ms / script_ms; counts input_tokens, output_tokens,
cache_read_tokens, cache_write_tokens, api_calls, api_retries. Defaults to the open stage;
--stage <stage> targets another. Repeated calls accumulate, so each script invocation and each
stage re-entry reports independently.
Rules that keep the numbers trustworthy:
latencyMs, the runtime’s reported usage. If you do not have
a measurement, omit the field; the gap is reported as unattributed_ms and flagged, which is far
more useful than a guess.stage_over_attributed:<stage> when attributed time
exceeds elapsed time, because unattributed_ms clamps at zero and would otherwise hide it.model_pricing_snapshot in the start dims
({ "<model>": { "input_per_mtok": 15, "output_per_mtok": 75, "cache_read_per_mtok": 1.5 } }) and
the rollup computes cost.estimated_cost_usd. A stored dollar figure silently goes wrong when list
prices change; tokens plus a dated snapshot stay recomputable. Without a snapshot, cost is null
with cost_basis: "no_pricing_snapshot" — never a fabricated number.contained_recovery is derived, not self-reported. Any error or pipeline_defect in a stage
marks it, because a stage that spent its time debugging is the one an agent is least likely to
remember to flag. timing.stages_with_recovery lists them, so a clean run and a thrash are
distinguishable instead of both reading as “this is what the stage costs”.The rollup’s timing.agentic_ms vs timing.deterministic_ms (and agentic_share) is the number
that shows whether moving work into deterministic code is paying off. agentic_share is null when
nothing was metered rather than 0, which would falsely read as a fully deterministic run.
The WordPress bridge can read key/value (“EAV”) tables like postmeta, key-scoped.
That is the largest widening of source-read reach this pipeline has taken, so it is counted.
node scripts/rp-telemetry.js source-read --discovery-queries 1 --discovery-table postmeta --redacted-values 0 --project <dir>
node scripts/rp-telemetry.js source-read --scoped-queries 6 --scoped-table postmeta --redacted-values 2 --project <dir>
node scripts/rp-telemetry.js source-read --tier-refusals 1 --project <dir>Counts accumulate across calls, so report per batch rather than holding a running total.
wix-wp-plugin-v2-client.js derives the per-read counts for you and hands them to its
onSourceRead hook — use that rather than counting at a call site, because the call site that
forgets is what makes a run’s total quietly wrong.
redacted_values is the field worth watching across runs. The other three describe how one
migration read one site. A non-zero redaction total means a source site keeps a credential in a
column nobody expected, which is a fleet-level signal no single run can see. tier_refusals has
to be reported by the caller rather than inferred, because the plugin answers a tier violation
with the same 400 as a nonexistent column — deliberately, so a refusal never discloses which
column holds the values.
Key names are never telemetry. The run’s own artifacts hold those. discovery_tables and
scoped_tables carry bare WordPress table names (postmeta), which are structural, not customer
data; the validator rejects anything that is not ^[A-Za-z0-9_]+$, and rejects a pinned_keys
field outright as unknown. Nothing here should ever be able to carry a value.
operator_acceptanceAt the finish handoff, ask the operator one plain question: does the migrated result look
right to them — accepted, rework_needed, or rejected? Record their answer in
finalize. If the run never reaches finish or they do not answer, it stays unknown.
This is the only field separating “completed and good” from “completed and unusable” —
ask it, but never pressure or interpret; their verdict as given, coarse by design.
Events are folded per problem class by the recorder (same type + stage + entity type +
API surfaces + app + error code + subtype fold into one event with a count), so record
every occurrence class once and pass count when you observed many at once — e.g. a
generated script reporting 4,000 identical write failures is one record call with
"count": 4000. Distinct problems are distinct subtypes or error codes, not bigger
counts.
Every event needs: event_type, stage (defaults to the open stage), skill (the
active rp-* resource, e.g. "rp-mapper"), severity (blocking | degraded |
cosmetic | info), and what_happened. Add entity_type, wix_api_surface (e.g.
stores/v3), source_api_surface (endpoint class like wp/v2/posts — never a URL),
wix_app_id, and error_code whenever they apply — they are the cross-run group-by keys.
halt_needs_user — the run stopped at a defined needs-user state. Prefer the
mechanical form — wait start --halt <subtype> … emits it for you (lifecycle step 3);
record it yourself only for a halt with no wait interval. subtype: missing_input
(missing/invalid required input or credential) | manual_only (genuinely manual step,
no API) | systemic_failure (systemic failure or data-loss risk).
manual_action_required — the execution plan flagged something as “can’t be done,
needs manual action” (e.g. a storage-plan upgrade), whether or not the run halted on
it. subtype: plan_or_billing | dashboard_only | external_dependency | other.
error — an API or script error, including recovered ones. Carry error_code
(required — it is the discriminator; no subtype), retry_count, and recovered.
Record one event per resolved retry chain, after the outcome is known — the final
recovered, the total retry_count — never one call per attempt (per-attempt calls
fold into one class, and the failing first attempt’s fields would bury the recovery).
When recovery required a change (not just a retry), actual must record what
change made it succeed, as an observation: “retried with the description as plain
text instead of HTML; the write succeeded” — never “the fix is X”. If that change
deviated from the documented path — including a change to a planned command or
value, like simplifying an input the plan specified — also emit a paired
skill_coverage_gap (undocumented_workaround).
fidelity_loss — the migration technically proceeded but lost something.
subtype: dropped_field | unverified_enum | no_target (source entity with no
clean Wix target) | coerced_value. For a loss triggered by specific records, inline
the offending record’s sanitized shape in observed_shapes — field names and
types and which field was dropped/coerced, never values.
api_gap — a missing or insufficient Wix API capability. subtype:
missing_api | missing_capability (API exists but cannot express the operation) |
internal_only (capability exists but is not publicly exposed) | other. Carry
wix_api_surface (required) and error_code — that signature is matched centrally
across runs. Never write to any backlog file; the event is the whole per-run
obligation.
skill_coverage_gap — the standing self-report, and the highest-value signal
for improving the skills. Whenever you act beyond what the active skill explicitly
told you to do — you guess a value, work around a missing instruction, resolve an
ambiguity by judgment, or handle a case the skill does not cover — record it at that
moment. subtype: guessed_value | undocumented_workaround |
ambiguous_instruction | path_not_covered. Describe the situation and the action
taken as an observation: “skill did not specify which enum value maps to X, so a value
was chosen to proceed” — never “the skill should add Y”. If you are unsure whether
something counts as improvisation, it does — record it.
user_decision — the user’s answer at every defined checkpoint or fork: the
mapping-review checkpoint, the approval gate, and intake forks (comments
anonymization, delivery mode, media reachability, …). subtype: accepted |
declined | deferred | amended; decision_point (required) names the fork, e.g.
mapping_review, approval_gate, comments_anonymization. Record the decision, not
the user’s reasoning verbatim. An amended acceptance whose change exposed a mapping
problem additionally surfaces that problem as fidelity_loss or
skill_coverage_gap. A declined at a terminal checkpoint pairs with
terminal_state: abandoned_by_user.
pipeline_defect — our own migration machinery misbehaved: not a Wix API error,
not a source failure, not your improvisation. subtype: state_inconsistency (two
pipeline state artifacts disagree) | ordering_violation (a step ran before its
prerequisite’s output existed) | record_defect (a pipeline record/log is malformed
or misleading as evidence) | other. Name the artifacts and their states in
what_happened — names and states, never contents.
source_plugin_coverage — which of the source site’s plugins we could not resolve,
plus one run-level summary. Record after discovery writes
discovery/plugin-coverage.json.
Record one event per unresolved item only. The unresolved set is: every pending row
(including reason: cannot-tell and unread candidate namespaces), every
requires-development row, and every row carrying blocked[] entries (a
user-file / credential / surface-changed blocker, declined or not). These are the
whole point of this event type — they are the only signal that says which plugin profile
to write next, and without them that ordering is guesswork.
Do not emit a per-row event for anything already resolved: migration-planned rows
with confidence: confirmed, or no-need-to-migrate rows with basis: list or
basis: decision (a human already signed that verdict). On a
55-plugin store that would be ~29 events restating a checked-in list — telemetry with no
information content, which makes the real backlog harder to see, not easier. (A
migration-planned or no-need-to-migrate row that automation derived —
confidence: proposed / basis: proposed — is reported through skill_coverage_gap
(guessed_value), not here.)
Emit exactly one aggregate event per run carrying the distribution: plugins installed,
counts by the four statuses (and by via / confidence for planned rows), blocked counts
by kind, and whether the plugin list was available. That preserves the cross-run view of
how coverage is trending without one event per plugin.
Per-event fields: subtype is the row’s status (pending | requires_development) or
blocked for a blocker entry (then also carry the blocker kind); carry the plugin slug
and version, the capability, the read channel, whether the row was recognized, and
source_api_surface as the endpoint class. Slug and version are required — without them
a cross-run view cannot tell which plugin caused what. Plugin slugs and versions are
software identifiers, not client data; still never record site URLs or record contents.
A requires-development row additionally pairs with api_gap, and a lossy via: cms row
with fidelity_loss — this event reports distribution and backlog, never the gap itself.
evidence_refs — rare, not routineAuthor every event to be self-sufficient: coded fields + bounded free text +
observed_shapes should let a reviewer triage it without opening any artifact. Add
evidence_refs ({"artifact":"execution-log.md","locator":"## Import"}) only for the
exceptional event whose signal genuinely cannot carry the full observation. Use
project-root-relative paths and prefer section headings as locators (line ranges break
when files regenerate). Never reference secret-bearing config files.
run-telemetry.json or telemetry/ files — the
recorder appends; you only call it.present / blank / absent) and nothing else: never the value, never a prefix
of it, never its length, never a hash. A length narrows a brute force and a hash confirms a
guess, so neither is a safe substitute for the value.stage/wait boundary calls.Always-active telemetry companion for RePlatform migration runs. Records what happened during a run — halts, errors, fidelity losses, API gaps, skill coverage gaps, user decisions, pipeline defects — through a validated recorder script, plus the run rollup (stages, timings, volumes, verification). Loaded by the orchestrator at run start and kept active for the whole run.
The verbatim description from this skill’s front matter — the string an agent matches on to decide whether to load it.
main, last pushed 8 November 2026.SKILL.md, not by matching a directory convention. 5 distinct layouts observed: skills/*/SKILL.md, skills/wix-headless-replatform/resources/*/SKILL.md, skills/wix-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.6 files · 184 KB
Everything this skill ships beside its prose. All of it is set here, as subchapters of skill 42.
Executable code the skill can run.
Everything else published alongside the skill.