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-12 00:02:07
Captured SHA817bbf6495958fa1964d6ef0d3e273b51161cf2a38d854dc62ee350239fd61d5
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, -8 deletions, 200 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>
9688 </label>
9789 </div>
9890
9991 <hr style="border:none;border-top:1px solid var(--border);margin:4px 0">
10092
10193 <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>
10294 <div style="display:flex;gap:12px">
10395 <label style="flex:1;display:flex;flex-direction:column;gap:4px">
10496 <span class="rb-label">Threshold (changes)</span>
10597 <input type="number" name="frequency_threshold" value="$frequency_threshold" min="0"
10698 style="background:var(--bg-1);color:var(--text);border:1px solid var(--border);border-radius:8px;padding:8px 12px">
10799 </label>
108100 <label style="flex:1;display:flex;flex-direction:column;gap:4px">
109101 <span class="rb-label">Window (minutes)</span>
110102 <input type="number" name="frequency_window_min" value="$frequency_window_min" min="1"
111103 style="background:var(--bg-1);color:var(--text);border:1px solid var(--border);border-radius:8px;padding:8px 12px">
112104 </label>
113105 </div>
114106
115107 <div style="display:flex;gap:8px;justify-content:flex-end;margin-top:8px">
116108 [if:$is_edit]<a href="/alerts.cgi" class="tr-chip">Cancel</a>[/if]
117109 <button type="submit" class="tr-chip is-active" style="border:none">[if:$is_edit]Save changes[/if][if:!$is_edit]Create rule[/if]</button>
118110 </div>
119111 </form>
120112 </div>
121113 </div>
122114
123115 <!-- Delivery history -->
124116 <div class="module glow-emerald">
125117 <div class="module-head"><div class="left">
126118 <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>
127119 <div class="module-title">Recent deliveries</div>
128120 <span class="module-subtitle">Last 30 fire attempts across every rule. Audit trail for compliance / debugging.</span>
129121 </div></div>
130122 <div class="module-body tight" style="max-height:520px;overflow:auto">
131123 [if:$has_deliveries]
132124 <table class="tbl">
133125 <thead><tr>
134126 <th style="width:80px">Status</th>
135127 <th>Rule / target</th>
136128 <th style="width:120px">Result</th>
137129 <th style="width:150px">When</th>
138130 </tr></thead>
139131 <tbody>
140132 [loop:@deliveries]
141133 <tr>
142134 <td><span class="pill $delivery_pill">$delivery_status</span></td>
143135 <td class="mono" style="font-size:11.5px"><a href="$source_url" style="color:var(--accent-hi);text-decoration:none">$summary_h</a></td>
144136 <td class="dim mono" style="font-size:11px">$err_h</td>
145137 <td class="mono dim"><span class="ts" data-ts="$fired_epoch" data-fmt="relative">$fired_at</span></td>
146138 </tr>
147139 [/loop]
148140 </tbody>
149141 </table>
150142 [/if]
151143 [if:!$has_deliveries]
152144 <div style="padding:36px 14px;text-align:center;color:var(--text-dim);font-size:13.5px">
153145 No deliveries yet. Create a rule and wait for a change to fire it.
154146 </div>
155147 [/if]
156148 </div>
157149 </div>
158150</div>
159151
160152<!-- Rule list -->
161153<div class="module glow-sky">
162154 <div class="module-head"><div class="left">
163155 <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>
164156 <div class="module-title">Rules</div>
165157 <span class="module-subtitle">Click a row to edit. Deactivating a rule stops it firing but keeps its history.</span>
166158 </div></div>
167159 <div class="module-body tight">
168160 [if:$has_rules]
169161 <table class="tbl">
170162 <thead><tr>
171163 <th style="width:80px">Status</th>
172164 <th>Name</th>
173165 <th>Matches</th>
174166 <th style="width:110px">Delivery</th>
175167 <th>Target</th>
176168 <th style="width:70px">Fires</th>
177169 <th style="width:150px">Last fired</th>
178170 <th style="width:60px">Actions</th>
179171 </tr></thead>
180172 <tbody>
181173 [loop:@rules]
182174 <tr>
183175 <td><span class="pill $status_pill">$status_label</span></td>
184176 <td><a href="$edit_url" style="color:var(--accent-hi);text-decoration:none">$rule_name</a></td>
185177 <td class="mono dim" style="font-size:11.5px">$match_kind &middot; $match_glob_h</td>
186178 <td><span class="pill $kind_pill">$delivery_kind</span></td>
187179 <td class="mono dim" style="font-size:11px">$url_h</td>
188180 <td class="mono">$fire_count</td>
189181 <td class="mono dim"><span class="ts" data-ts="$last_fired_epoch" data-fmt="relative">$last_fired_h</span></td>
190182 <td>
191183 <form method="post" action="/alerts.cgi" style="display:inline">
192184 <input type="hidden" name="op" value="toggle">
193185 <input type="hidden" name="alert_rule_id" value="$alert_rule_id">
194186 <button type="submit" class="tr-chip" title="Toggle active" style="padding:3px 8px;font-size:11px">⏻</button>
195187 </form>
196188 </td>
197189 </tr>
198190 [/loop]
199191 </tbody>
200192 </table>
201193 [/if]
202194 [if:!$has_rules]
203195 <div style="padding:36px 14px;text-align:center;color:var(--text-dim);font-size:13.5px">
204196 No rules yet. Use the form above to create your first.
205197 </div>
206198 [/if]
207199 </div>
208200</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.