{{ error }}

Rule deployed to shadow successfully!

{{ shadowDeployError }}

Rule rollout updated successfully!

{{ rolloutDeployError }}

{{ saveSuccessMessage }}

You are viewing Revision {{ revisionNumber }} of this rule (read-only).

Go to latest version

Read-only mode. Editing, pause/resume, draft deployment, and rollout controls are hidden for your current permissions.

This rule is paused. It stays saved, but it is excluded from active production evaluation until resumed.

Rule Details

{{ rule.status | uppercase }} Shadow version active {{ rolloutEntry.traffic_percent }}% rollout active Allowlist

{{ saveError }}

{{ rule.rid }}
{{ rule.description }}
{{ rule.evaluation_lane === 'allowlist' ? 'Allowlist rules' : 'Main rules' }}

{{ selectedLaneDescription() }}

Validation errors

  • {{ error.message }} (line {{ error.line }}, column {{ error.column }})

Field warnings

  • {{ warning }}

Detected references

Fields

${{ param }}

User lists

@{{ listName }}

Outcomes

!{{ outcomeName }}
{{ formatDate(rule.created_at) }}

A validated AI draft is still only in preview. Use “Use Draft In Main Editor” before saving changes.

Performance

Stored outcome hits for this rule over time in the selected window.

{{ performanceError }}

No stored outcome hits for this rule in the selected time range.

Hits In Window

{{ getPerformanceHitCount() }}

Outcomes Seen

{{ performanceOutcomeDatasets.length }}

Hit counts reflect stored non-null outcomes persisted for this rule.

Test Rule

Reason: {{ testResult.reason }}

Rule Result: {{ testResult.rule_outcome | json }}

{{ testError }}

Backtest Changes

Compare the current rule logic against your proposed changes using recent event data.

{{ backtestError }}

Backtest Results

{{ getBacktestStatusLabel(bt.task_id, bt) }}

{{ getBacktestQueueStatus(bt.task_id, bt) === 'pending' ? 'Backtest is queued...' : 'Backtest is running...' }}

{{ getTaskResult(bt.task_id)?.error || 'Backtest failed' }}

{{ getTaskResult(bt.task_id)?.error || 'Backtest cancelled' }}

Logic Changes

{{ change.value }}
Logic diff is larger than {{ backtestDiffCharLimitLabel }} characters, so it is not rendered inline.

Outcome Comparison

Outcome Current Proposed Delta
{{ row.outcome }} {{ row.storedCount }} ({{ row.storedRate | number:'1.1-1' }}%) {{ row.proposedCount }} ({{ row.proposedRate | number:'1.1-1' }}%) {{ row.delta > 0 ? '+' : '' }}{{ row.delta }}
Total records evaluated {{ taskResult.total_records }}

Evaluated {{ taskResult.eligible_records || taskResult.total_records || 0 }} records and skipped {{ taskResult.skipped_records }} older records that were not eligible for the common comparison set.

  • {{ warning }}

Historical Labels

Total records: {{ taskResult.total_records || 0 }}

Labeled records: {{ taskResult.labeled_records || 0 }}

Coverage: {{ backtestView.labeledShare | number:'1.1-1' }}%

Current Quality

Pairs scored: {{ backtestView.storedQualitySummary?.pair_count || 0 }}

Avg precision: {{ formatQualityMetric(backtestView.storedQualitySummary?.average_precision) }}

Avg recall: {{ formatQualityMetric(backtestView.storedQualitySummary?.average_recall) }}

Avg F1: {{ formatQualityMetric(backtestView.storedQualitySummary?.average_f1) }}

Best pair: {{ backtestView.storedQualitySummary?.best_pair || '—' }}

Proposed Quality

Pairs scored: {{ backtestView.proposedQualitySummary?.pair_count || 0 }}

Avg precision: {{ formatQualityMetric(backtestView.proposedQualitySummary?.average_precision) }}

Avg recall: {{ formatQualityMetric(backtestView.proposedQualitySummary?.average_recall) }}

Avg F1: {{ formatQualityMetric(backtestView.proposedQualitySummary?.average_f1) }}

Best pair: {{ backtestView.proposedQualitySummary?.best_pair || '—' }}

Ground Truth Labels

Label Count Share of labeled
{{ row.label }} {{ row.count }} {{ row.share | number:'1.1-1' }}%

Showing first {{ getBacktestRenderRowLimit() }} labels; {{ backtestView.hiddenLabelRowCount }} additional label{{ backtestView.hiddenLabelRowCount === 1 ? '' : 's' }} omitted from inline rendering.

Outcome vs Label Quality

Support columns show TP / FP / FN for each outcome→label pair.

Outcome Label Current P Current R Current F1 Current TP / FP / FN Proposed P Proposed R Proposed F1 Proposed TP / FP / FN
{{ row.outcome }} {{ row.label }} {{ formatQualityMetric(row.stored?.precision) }} {{ formatQualityMetric(row.stored?.recall) }} {{ formatQualityMetric(row.stored?.f1) }} {{ row.stored?.true_positive || 0 }} / {{ row.stored?.false_positive || 0 }} / {{ row.stored?.false_negative || 0 }} {{ formatQualityMetric(row.proposed?.precision) }} {{ formatQualityMetric(row.proposed?.recall) }} {{ formatQualityMetric(row.proposed?.f1) }} {{ row.proposed?.true_positive || 0 }} / {{ row.proposed?.false_positive || 0 }} / {{ row.proposed?.false_negative || 0 }}

Showing first {{ getBacktestRenderRowLimit() }} outcome-label pairs; {{ backtestView.hiddenQualityRowCount }} additional pair{{ backtestView.hiddenQualityRowCount === 1 ? '' : 's' }} omitted from inline rendering.

No labeled events were found in the backtest window, so precision and recall are unavailable for this run.

Deploy to Shadow

No shadow version exists for this rule. The following logic will be deployed to shadow:

A shadow version is already running. The diff below shows what will change in shadow:

{{ editedLogic }}
Current shadow Incoming
{{ change.value }}

{{ rolloutEntry ? 'Update Rollout' : 'Start Rollout' }}

Serve this candidate version to a stable percentage of live traffic while the current production version remains the control.

Logic changes (production → candidate):

Logic is identical to the current production version.

production candidate
{{ chunk.added ? '+' : chunk.removed ? '-' : ' ' }}{{ chunk.value }}