@usefidel/contracts 0.10.0 → 0.11.0

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.
@@ -112,7 +112,7 @@ export declare function errorPhaseFor(code: string | null | undefined): Validati
112
112
  /** True when `code` is a member of the current taxonomy. */
113
113
  export declare function isKnownErrorCode(code: string | null | undefined): code is RunErrorCode;
114
114
  /** Events the GA dashboard is built on. Typed properties, specified triggers. */
115
- export declare const GA_EVENT_NAMES: readonly ["signup_started", "signup_completed", "onboarding_started", "onboarding_completed", "figma_connected", "environment_connected", "web_validation_submitted", "web_validation_completed", "web_validation_failed", "web_validation_cancelled", "report_viewed", "report_share_created", "report_link_copied", "report_share_failed", "report_copy_failed", "diff_mark_resolved", "upgrade_clicked", "checkout_started", "feedback_submitted", "extension_opened", "validation_start", "validation_accepted", "validation_complete", "validation_error", "validation_cancel", "review_saved", "figma_auth_success", "figma_auth_error", "extension_share_copied", "upgrade_modal_viewed", "upgrade_cta_clicked"];
115
+ export declare const GA_EVENT_NAMES: readonly ["signup_started", "signup_completed", "onboarding_started", "onboarding_completed", "figma_connected", "environment_connected", "web_validation_submitted", "web_validation_completed", "web_validation_failed", "validation_cancel_requested", "validation_result_observed", "report_viewed", "report_share_created", "report_link_copied", "report_share_failed", "report_copy_failed", "diff_mark_resolved", "upgrade_clicked", "checkout_started", "feedback_submitted", "extension_opened", "validation_start", "validation_accepted", "validation_complete", "validation_error", "validation_cancel", "review_saved", "figma_auth_success", "figma_auth_error", "extension_share_copied", "upgrade_modal_viewed", "upgrade_cta_clicked"];
116
116
  /**
117
117
  * Events that exist but are NOT GA metrics.
118
118
  *
@@ -125,7 +125,7 @@ export declare const GA_EVENT_NAMES: readonly ["signup_started", "signup_complet
125
125
  */
126
126
  export declare const SECONDARY_EVENT_NAMES: readonly ["checkout_completed", "console_errors", "diff_expanded", "drawer_filter_changed", "review_save_error", "review_verdict", "review_verdict_all", "screenshot_exported", "ui_crash", "validation_resume", "validation_retry", "view_changed", "auth_refresh", "consensus_complete", "consensus_error", "extension_validation_failed", "idempotency_dedup_client", "pipeline_complete", "pipeline_phase", "pipeline_resume", "rate_limit_hit", "upgrade_wall_hit"];
127
127
  /** Every event name any Fidel client may emit. */
128
- export declare const ANALYTICS_EVENT_NAMES: readonly ["signup_started", "signup_completed", "onboarding_started", "onboarding_completed", "figma_connected", "environment_connected", "web_validation_submitted", "web_validation_completed", "web_validation_failed", "web_validation_cancelled", "report_viewed", "report_share_created", "report_link_copied", "report_share_failed", "report_copy_failed", "diff_mark_resolved", "upgrade_clicked", "checkout_started", "feedback_submitted", "extension_opened", "validation_start", "validation_accepted", "validation_complete", "validation_error", "validation_cancel", "review_saved", "figma_auth_success", "figma_auth_error", "extension_share_copied", "upgrade_modal_viewed", "upgrade_cta_clicked", "checkout_completed", "console_errors", "diff_expanded", "drawer_filter_changed", "review_save_error", "review_verdict", "review_verdict_all", "screenshot_exported", "ui_crash", "validation_resume", "validation_retry", "view_changed", "auth_refresh", "consensus_complete", "consensus_error", "extension_validation_failed", "idempotency_dedup_client", "pipeline_complete", "pipeline_phase", "pipeline_resume", "rate_limit_hit", "upgrade_wall_hit"];
128
+ export declare const ANALYTICS_EVENT_NAMES: readonly ["signup_started", "signup_completed", "onboarding_started", "onboarding_completed", "figma_connected", "environment_connected", "web_validation_submitted", "web_validation_completed", "web_validation_failed", "validation_cancel_requested", "validation_result_observed", "report_viewed", "report_share_created", "report_link_copied", "report_share_failed", "report_copy_failed", "diff_mark_resolved", "upgrade_clicked", "checkout_started", "feedback_submitted", "extension_opened", "validation_start", "validation_accepted", "validation_complete", "validation_error", "validation_cancel", "review_saved", "figma_auth_success", "figma_auth_error", "extension_share_copied", "upgrade_modal_viewed", "upgrade_cta_clicked", "checkout_completed", "console_errors", "diff_expanded", "drawer_filter_changed", "review_save_error", "review_verdict", "review_verdict_all", "screenshot_exported", "ui_crash", "validation_resume", "validation_retry", "view_changed", "auth_refresh", "consensus_complete", "consensus_error", "extension_validation_failed", "idempotency_dedup_client", "pipeline_complete", "pipeline_phase", "pipeline_resume", "rate_limit_hit", "upgrade_wall_hit"];
129
129
  export type GaEventName = (typeof GA_EVENT_NAMES)[number];
130
130
  export type SecondaryEventName = (typeof SECONDARY_EVENT_NAMES)[number];
131
131
  export type AnalyticsEventName = GaEventName | SecondaryEventName;
@@ -179,7 +179,11 @@ export interface ValidationEventProperties {
179
179
  * upgrade wall still counted as started and no event could carry a `run_id`.
180
180
  * This one cannot be emitted without one.
181
181
  *
182
- * NOT a terminal event: exactly one of completed / failed / cancelled follows.
182
+ * NOT a terminal event. Emitted by the BROWSER, because acceptance is the
183
+ * browser's own observation: it made the request and read the response.
184
+ *
185
+ * Its terminal counterpart is emitted by the SERVER — see
186
+ * `WebValidationCompletedProperties` for why ownership splits here.
183
187
  */
184
188
  export interface ValidationSubmittedProperties extends ValidationEventProperties {
185
189
  /**
@@ -215,6 +219,30 @@ export interface ReportShareFailureProperties {
215
219
  */
216
220
  error_code: string;
217
221
  }
222
+ /**
223
+ * An accepted run reached a terminal status. EMITTED BY THE BACKEND FINALIZER,
224
+ * immediately after the `validation_runs` status update succeeds.
225
+ *
226
+ * A browser cannot own this event. Validation is asynchronous: the edge
227
+ * function answers 202 and finishes the run in a background task, so the
228
+ * transition happens in a process the tab has no part in. A browser-emitted
229
+ * completion is really "the user was still watching when it landed", and a
230
+ * completion rate built on it has that as its hidden denominator. Measured on
231
+ * staging: three accepted runs, three `web_validation_submitted`, zero
232
+ * completions — including one on the fixed client, because the tab moved on
233
+ * before the run finished.
234
+ *
235
+ * The emit is strictly ordered after the status write and is skipped when that
236
+ * write fails, so this event cannot claim a completion the database does not
237
+ * have. Analytics failure never changes the validation result: a failed capture
238
+ * is logged and dropped.
239
+ *
240
+ * The server uses the SAME Supabase user UUID as `distinct_id` that the browser
241
+ * uses. Anything else forks the person.
242
+ *
243
+ * DEDUPLICATE BY DISTINCT `run_id`. Never count raw event rows: a retry inside
244
+ * the finalizer, or a replayed background task, can emit twice for one run.
245
+ */
218
246
  export interface WebValidationCompletedProperties extends ValidationEventProperties {
219
247
  duration_ms: number;
220
248
  /**
@@ -237,7 +265,17 @@ export interface WebValidationCompletedProperties extends ValidationEventPropert
237
265
  result_completeness?: ResultCompleteness;
238
266
  }
239
267
  /**
240
- * A run that failed or was cancelled.
268
+ * A validation failed.
269
+ *
270
+ * OWNERSHIP SPLITS ON `run_id`, and the nullability is what carries it:
271
+ * - `run_id === null` — rejected BEFORE the backend accepted it (upgrade
272
+ * wall, rate limit, invalid URL). Only the browser saw this; there is no
273
+ * run and no server process to emit from. Browser-emitted.
274
+ * - `run_id !== null` — an accepted run reached `status = 'error'`.
275
+ * Backend-emitted, immediately after that status write succeeds, for the
276
+ * same reason `web_validation_completed` is.
277
+ *
278
+ * DEDUPLICATE BY DISTINCT `run_id` for the accepted half.
241
279
  *
242
280
  * `run_id` is NULLABLE here and required on the success events, and the
243
281
  * asymmetry is the point: a run rejected BEFORE the backend accepted it — the
@@ -254,12 +292,51 @@ export interface ValidationFailedProperties {
254
292
  error_phase: ValidationErrorPhase;
255
293
  retryable: boolean;
256
294
  }
257
- export interface ValidationCancelledProperties {
295
+ /**
296
+ * The user asked to stop, and the browser aborted its in-flight request.
297
+ *
298
+ * This is a REQUEST, not an outcome, and the name says so. `validation_runs`
299
+ * has no `cancelled` status — its check constraint allows only `complete`,
300
+ * `error`, `partial` and `processing` — so no accepted run can ever persist as
301
+ * cancelled. Aborting the client fetch does not stop the backend: the edge
302
+ * function answers 202 and finishes the run in a background task, so a run the
303
+ * user "cancelled" usually goes on to complete and emits
304
+ * `web_validation_completed` from the server a moment later.
305
+ *
306
+ * That is not a contradiction to reconcile away. The two events describe
307
+ * different things: this one is the user's intent, the server's is the run's
308
+ * fate. Counting this as a terminal outcome would under-count completions and
309
+ * invent a state the database cannot hold — which is exactly what the
310
+ * predecessor name `web_validation_cancelled` implied.
311
+ *
312
+ * `run_id` is null whenever the abort landed before the server replied.
313
+ */
314
+ export interface ValidationCancelRequestedProperties {
258
315
  run_id: string | null;
259
316
  validation_mode: ValidationMode;
260
317
  duration_ms: number;
261
318
  error_phase: ValidationErrorPhase;
262
319
  }
320
+ /**
321
+ * The user was still present when the result rendered.
322
+ *
323
+ * Behavioural, never operational. Completion is owned by the backend
324
+ * finalizer; this records only whether anyone was watching. Keeping the two
325
+ * apart is what makes both measurable:
326
+ *
327
+ * accepted-run completion rate = server terminal events / submitted
328
+ * result observation rate = this / completed runs
329
+ *
330
+ * Fusing them — which is what a browser-emitted `completed` did — yields a
331
+ * completion rate whose real denominator is "users who stayed on the page",
332
+ * silently floored by however long the pipeline takes.
333
+ */
334
+ export interface ValidationResultObservedProperties extends ValidationEventProperties {
335
+ /** Terminal status the client actually rendered. */
336
+ run_status: 'complete' | 'error' | 'partial';
337
+ /** ms from submit to the client rendering a terminal state. */
338
+ observed_after_ms: number;
339
+ }
263
340
  export interface ReportViewedProperties {
264
341
  run_id: string;
265
342
  validation_mode: ValidationMode;
@@ -322,7 +399,8 @@ export interface AnalyticsEventProperties {
322
399
  web_validation_submitted: ValidationSubmittedProperties;
323
400
  web_validation_completed: WebValidationCompletedProperties;
324
401
  web_validation_failed: ValidationFailedProperties;
325
- web_validation_cancelled: ValidationCancelledProperties;
402
+ validation_cancel_requested: ValidationCancelRequestedProperties;
403
+ validation_result_observed: ValidationResultObservedProperties;
326
404
  report_viewed: ReportViewedProperties;
327
405
  report_share_created: ReportShareProperties;
328
406
  report_link_copied: ReportShareProperties;
@@ -352,7 +430,7 @@ export interface AnalyticsEventProperties {
352
430
  validation_accepted: ValidationSubmittedProperties;
353
431
  validation_complete: WebValidationCompletedProperties;
354
432
  validation_error: ValidationFailedProperties;
355
- validation_cancel: ValidationCancelledProperties;
433
+ validation_cancel: ValidationCancelRequestedProperties;
356
434
  review_saved: {
357
435
  run_id?: string;
358
436
  review_action: string;
package/dist/analytics.js CHANGED
@@ -119,7 +119,8 @@ export const GA_EVENT_NAMES = [
119
119
  'web_validation_submitted',
120
120
  'web_validation_completed',
121
121
  'web_validation_failed',
122
- 'web_validation_cancelled',
122
+ 'validation_cancel_requested',
123
+ 'validation_result_observed',
123
124
  'report_viewed',
124
125
  'report_share_created',
125
126
  'report_link_copied',
package/dist/index.d.ts CHANGED
@@ -2,4 +2,4 @@ export { RUN_ERROR_CODES, ERROR_CODE_META, mapSnapshotErrorToCode, mapFigmaError
2
2
  export type { RunErrorCode, RunErrorMeta, ErrorMapping, RunDisplay, } from './run-errors.js';
3
3
  export type { IntakeFramework, UnsupportedStack, UnsupportedReason, UnresolvedReferenceSection, UnresolvedReferenceReason, UnresolvedReference, ParsedThemeColor, ParsedThemeTypography, ParsedThemeSize, ShadcnConfig, ParsedTheme, IntakeDetection, TokenSourceKind, TokenSource, PackageRole, PackageInfo, } from './theme-intake.js';
4
4
  export { ANALYTICS_SCHEMA_VERSION, ANALYTICS_EVENT_NAMES, GA_EVENT_NAMES, SECONDARY_EVENT_NAMES, ERROR_CODE_PHASE, FORBIDDEN_PROPERTY_KEYS, errorPhaseFor, isKnownErrorCode, sanitizeProperties, } from './analytics.js';
5
- export type { AnalyticsSurface, AnalyticsEnvironment, AnalyticsContext, AnalyticsPersonProperties, AnalyticsEventName, GaEventName, SecondaryEventName, AnalyticsEventProperties, AnalyticsPayload, ValidationMode, ValidationErrorPhase, ResultCompleteness, ValidationEventProperties, ValidationSubmittedProperties, ReportShareProperties, ReportShareFailureProperties, WebValidationCompletedProperties, ValidationFailedProperties, ValidationCancelledProperties, ReportViewedProperties, } from './analytics.js';
5
+ export type { AnalyticsSurface, AnalyticsEnvironment, AnalyticsContext, AnalyticsPersonProperties, AnalyticsEventName, GaEventName, SecondaryEventName, AnalyticsEventProperties, AnalyticsPayload, ValidationMode, ValidationErrorPhase, ResultCompleteness, ValidationEventProperties, ValidationSubmittedProperties, ReportShareProperties, ReportShareFailureProperties, WebValidationCompletedProperties, ValidationFailedProperties, ValidationCancelRequestedProperties, ValidationResultObservedProperties, ReportViewedProperties, } from './analytics.js';
package/package.json CHANGED
@@ -7,7 +7,7 @@
7
7
  "The source of truth still lives in the monorepo at packages/contracts/."
8
8
  ],
9
9
  "name": "@usefidel/contracts",
10
- "version": "0.10.0",
10
+ "version": "0.11.0",
11
11
  "description": "Shared, code-free contracts between Fidel surfaces. Run-error taxonomy, theme-intake wire types, and the canonical fidel.config.json builders.",
12
12
  "license": "UNLICENSED",
13
13
  "private": false,