Restore

O Operator
Restore

Restore file to captured state

Every captured change carries its SHA-256-addressed content in BLOB_STORE. Restoring writes that content back to the original path — current file gets backed up to <path>.drift_restore_backup_<epoch> before overwrite.

What will change
Preview -- nothing has been written yet.
Target file/var/www/vhosts/3dshawn.com/site1/TEMPLATES/alerts.html
SiteDriftSense self-monitor on local
Kindlocal
Captured at2026-07-11 18:27:46
Captured SHAe8e28508e1fcbf1a6a69043819219161f5c3001060adf80a7b83f53cdd9101ea
Current state on disk
Live check just now. If SHAs match, the restore is a no-op.
File presentyes
Size12426 bytes
Current SHA4433ba3e7905
Same as captured?no -- restore will change it
What restore will change — live diff
Left column shows current on-disk content; right shows what restore will write. +0 additions, -24 deletions, 184 unchanged context lines.
11<div class="page-head">
22 <span class="page-eyebrow"><span class="dot"></span> Notify</span>
33 <h1 class="page-title">Alert rules</h1>
44 <p class="page-subtitle">Route file + schema changes to Slack, Discord, or any HTTP webhook. Rules fire in near-real-time (as the cron dispatcher runs every minute). Every attempt is logged.</p>
5</div>
6
7<div class="ds-guide">
8 <div class="dsg-icon">i</div>
9 <div>
10 <span class="dsg-title">How a rule fires:</span>
11 Two flavors. <strong>Per-row</strong> rules (default) fire on every change that matches the path glob + kind + status filter &mdash; good for "wake me on any deletion". <strong>Frequency</strong> rules (set threshold &gt; 0) fire once when a matching file crosses N changes in M minutes &mdash; good for "wake me when someone edits the payment gateway config 5+ times in an hour". Rate limit protects you from firehoses; every delivery attempt is logged whether it succeeded or failed.
12 </div>
135</div>
146
157<div class="dash-grid" style="grid-template-columns:1fr 1fr;margin-bottom:20px">
168
179 <!-- Rule form -->
1810 <div class="module glow-teal">
1911 <div class="module-head"><div class="left">
2012 <div class="module-icon"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg></div>
2113 <div class="module-title">[if:$is_edit]Edit rule #$edit_id[/if][if:!$is_edit]New rule[/if]</div>
2214 <span class="module-subtitle">Combine a matcher (kind + path glob) with a delivery target. Save, then wait for the next capture tick.</span>
2315 </div></div>
2416 <div class="module-body">
2517 <form method="post" action="/alerts.cgi" style="display:flex;flex-direction:column;gap:12px">
2618 <input type="hidden" name="op" value="$form_op">
2719 [if:$is_edit]<input type="hidden" name="alert_rule_id" value="$edit_id">[/if]
2820
2921 <label style="display:flex;flex-direction:column;gap:4px">
3022 <span class="rb-label">Name</span>
3123 <input type="text" name="rule_name" value="$rule_name" placeholder="e.g. Prod nginx config changes" required
3224 style="background:var(--bg-1);color:var(--text);border:1px solid var(--border);border-radius:8px;padding:8px 12px;font-family:inherit">
3325 </label>
3426
3527 <div style="display:flex;gap:12px">
3628 <label style="flex:1;display:flex;flex-direction:column;gap:4px">
3729 <span class="rb-label">Match kind</span>
3830 <select name="match_kind" style="background:var(--bg-1);color:var(--text);border:1px solid var(--border);border-radius:8px;padding:8px 12px">
3931 <option value="either" $mk_either_sel>Either (file + schema)</option>
4032 <option value="file" $mk_file_sel>File changes only</option>
4133 <option value="schema" $mk_schema_sel>Schema DDL only</option>
4234 </select>
4335 </label>
4436 <label style="flex:1;display:flex;flex-direction:column;gap:4px">
4537 <span class="rb-label">Path glob</span>
4638 <input type="text" name="match_path_glob" value="$match_path_glob" placeholder="e.g. /etc/nginx/** or drift_sense.**"
4739 style="background:var(--bg-1);color:var(--text);border:1px solid var(--border);border-radius:8px;padding:8px 12px;font-family:var(--mono);font-size:12px">
4840 </label>
4941 </div>
5042
5143 <div style="display:flex;gap:12px">
5244 <label style="flex:1;display:flex;flex-direction:column;gap:4px">
5345 <span class="rb-label">Status filter <span class="dim" style="text-transform:none;letter-spacing:0;font-size:10.5px">(files only)</span></span>
5446 <input type="text" name="match_status_list" value="$match_status_list" placeholder="added,modified,deleted"
5547 style="background:var(--bg-1);color:var(--text);border:1px solid var(--border);border-radius:8px;padding:8px 12px;font-family:var(--mono);font-size:12px">
5648 </label>
5749 <label style="flex:1;display:flex;align-items:center;gap:8px;margin-top:16px">
5850 <input type="checkbox" name="exclude_ts_only" value="1" $exclude_ts_only_checked>
5951 <span style="font-size:12.5px;color:var(--text-dim)">Exclude timestamp-only changes</span>
6052 </label>
6153 </div>
6254
6355 <hr style="border:none;border-top:1px solid var(--border);margin:4px 0">
6456
6557 <div style="display:flex;gap:12px">
6658 <label style="flex:1;display:flex;flex-direction:column;gap:4px">
6759 <span class="rb-label">Delivery</span>
6860 <select name="delivery_kind" style="background:var(--bg-1);color:var(--text);border:1px solid var(--border);border-radius:8px;padding:8px 12px">
6961 <option value="generic_webhook" $dk_generic_webhook_sel>Generic HTTP webhook</option>
7062 <option value="slack" $dk_slack_sel>Slack incoming webhook</option>
7163 <option value="discord" $dk_discord_sel>Discord webhook</option>
7264 <option value="email" $dk_email_sel>Email (not yet implemented)</option>
7365 </select>
7466 </label>
7567 <label style="flex:2;display:flex;flex-direction:column;gap:4px">
7668 <span class="rb-label">Webhook URL</span>
7769 <input type="text" name="delivery_url" value="$delivery_url" placeholder="https://hooks.slack.com/..."
7870 style="background:var(--bg-1);color:var(--text);border:1px solid var(--border);border-radius:8px;padding:8px 12px;font-family:var(--mono);font-size:11.5px">
7971 </label>
8072 </div>
8173
8274 <div style="display:flex;gap:12px">
8375 <label style="flex:1;display:flex;flex-direction:column;gap:4px">
8476 <span class="rb-label">Rate limit / min</span>
8577 <input type="number" name="rate_limit_per_min" value="$rate_limit_per_min" min="0"
8678 style="background:var(--bg-1);color:var(--text);border:1px solid var(--border);border-radius:8px;padding:8px 12px">
8779 </label>
8880 <label style="flex:1;display:flex;flex-direction:column;gap:4px">
8981 <span class="rb-label">Coalesce window (s)</span>
9082 <input type="number" name="coalesce_window_s" value="$coalesce_window_s" min="0"
9183 style="background:var(--bg-1);color:var(--text);border:1px solid var(--border);border-radius:8px;padding:8px 12px">
9284 </label>
9385 <label style="flex:1;display:flex;align-items:center;gap:8px;margin-top:16px">
9486 <input type="checkbox" name="is_active" value="1" $is_active_checked>
9587 <span style="font-size:12.5px;color:var(--text-dim)">Rule is active</span>
96 </label>
97 </div>
98
99 <hr style="border:none;border-top:1px solid var(--border);margin:4px 0">
100
101 <div class="rb-label" style="margin-bottom:-4px">Frequency mode <span class="dim" style="text-transform:none;letter-spacing:0;font-size:10.5px">&mdash; when threshold &gt; 0, this rule fires whenever a matching file crosses N changes in M minutes (instead of firing per row)</span></div>
102 <div style="display:flex;gap:12px">
103 <label style="flex:1;display:flex;flex-direction:column;gap:4px">
104 <span class="rb-label">Threshold (changes)</span>
105 <input type="number" name="frequency_threshold" value="$frequency_threshold" min="0"
106 style="background:var(--bg-1);color:var(--text);border:1px solid var(--border);border-radius:8px;padding:8px 12px">
107 </label>
108 <label style="flex:1;display:flex;flex-direction:column;gap:4px">
109 <span class="rb-label">Window (minutes)</span>
110 <input type="number" name="frequency_window_min" value="$frequency_window_min" min="1"
111 style="background:var(--bg-1);color:var(--text);border:1px solid var(--border);border-radius:8px;padding:8px 12px">
11288 </label>
11389 </div>
11490
11591 <div style="display:flex;gap:8px;justify-content:flex-end;margin-top:8px">
11692 [if:$is_edit]<a href="/alerts.cgi" class="tr-chip">Cancel</a>[/if]
11793 <button type="submit" class="tr-chip is-active" style="border:none">[if:$is_edit]Save changes[/if][if:!$is_edit]Create rule[/if]</button>
11894 </div>
11995 </form>
12096 </div>
12197 </div>
12298
12399 <!-- Delivery history -->
124100 <div class="module glow-emerald">
125101 <div class="module-head"><div class="left">
126102 <div class="module-icon"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg></div>
127103 <div class="module-title">Recent deliveries</div>
128104 <span class="module-subtitle">Last 30 fire attempts across every rule. Audit trail for compliance / debugging.</span>
129105 </div></div>
130106 <div class="module-body tight" style="max-height:520px;overflow:auto">
131107 [if:$has_deliveries]
132108 <table class="tbl">
133109 <thead><tr>
134110 <th style="width:80px">Status</th>
135111 <th>Rule / target</th>
136112 <th style="width:120px">Result</th>
137113 <th style="width:150px">When</th>
138114 </tr></thead>
139115 <tbody>
140116 [loop:@deliveries]
141117 <tr>
142118 <td><span class="pill $delivery_pill">$delivery_status</span></td>
143119 <td class="mono" style="font-size:11.5px"><a href="$source_url" style="color:var(--accent-hi);text-decoration:none">$summary_h</a></td>
144120 <td class="dim mono" style="font-size:11px">$err_h</td>
145121 <td class="mono dim"><span class="ts" data-ts="$fired_epoch" data-fmt="relative">$fired_at</span></td>
146122 </tr>
147123 [/loop]
148124 </tbody>
149125 </table>
150126 [/if]
151127 [if:!$has_deliveries]
152128 <div style="padding:36px 14px;text-align:center;color:var(--text-dim);font-size:13.5px">
153129 No deliveries yet. Create a rule and wait for a change to fire it.
154130 </div>
155131 [/if]
156132 </div>
157133 </div>
158134</div>
159135
160136<!-- Rule list -->
161137<div class="module glow-sky">
162138 <div class="module-head"><div class="left">
163139 <div class="module-icon"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2"><line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/></svg></div>
164140 <div class="module-title">Rules</div>
165141 <span class="module-subtitle">Click a row to edit. Deactivating a rule stops it firing but keeps its history.</span>
166142 </div></div>
167143 <div class="module-body tight">
168144 [if:$has_rules]
169145 <table class="tbl">
170146 <thead><tr>
171147 <th style="width:80px">Status</th>
172148 <th>Name</th>
173149 <th>Matches</th>
174150 <th style="width:110px">Delivery</th>
175151 <th>Target</th>
176152 <th style="width:70px">Fires</th>
177153 <th style="width:150px">Last fired</th>
178154 <th style="width:60px">Actions</th>
179155 </tr></thead>
180156 <tbody>
181157 [loop:@rules]
182158 <tr>
183159 <td><span class="pill $status_pill">$status_label</span></td>
184160 <td><a href="$edit_url" style="color:var(--accent-hi);text-decoration:none">$rule_name</a></td>
185161 <td class="mono dim" style="font-size:11.5px">$match_kind &middot; $match_glob_h</td>
186162 <td><span class="pill $kind_pill">$delivery_kind</span></td>
187163 <td class="mono dim" style="font-size:11px">$url_h</td>
188164 <td class="mono">$fire_count</td>
189165 <td class="mono dim"><span class="ts" data-ts="$last_fired_epoch" data-fmt="relative">$last_fired_h</span></td>
190166 <td>
191167 <form method="post" action="/alerts.cgi" style="display:inline">
192168 <input type="hidden" name="op" value="toggle">
193169 <input type="hidden" name="alert_rule_id" value="$alert_rule_id">
194170 <button type="submit" class="tr-chip" title="Toggle active" style="padding:3px 8px;font-size:11px">⏻</button>
195171 </form>
196172 </td>
197173 </tr>
198174 [/loop]
199175 </tbody>
200176 </table>
201177 [/if]
202178 [if:!$has_rules]
203179 <div style="padding:36px 14px;text-align:center;color:var(--text-dim);font-size:13.5px">
204180 No rules yet. Use the form above to create your first.
205181 </div>
206182 [/if]
207183 </div>
208184</div>
Confirm restore
Backs current content to <target>.drift_restore_backup_<epoch>, writes the captured content, verifies SHA post-write.
Cancel Logged to RESTORE_LOG regardless of outcome.