Skip to main content

max / makenotwork

Exorcise sweep: strip AI tells from pom and tagtree Last of the uncommitted sweep. Not my edits; verified rather than authored. pom: connective dashes in README, deploy config, alert and dashboard output strings, and the health tool. Includes the status-line format in display.rs, which moves from an escaped U+2014 to a colon. cargo test --lib 365 passed 0 failed. shared/tagtree: architecture doc plus the lib.rs module header. 25 tests and the doctests pass.
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-07-27 21:11 UTC
Signed with PGP, not checked
Commit: d58e7d83c4ed857facd86f5950d9237eb79d76d2
Parent: 38ba533
10 files changed, +54 insertions, -108 deletions
M pom/README.md +6 -6
@@ -1,6 +1,6 @@
1 1 # Peace of Mind
2 2
3 - A production operations monitor -- health checks, TLS certificate tracking, remote test orchestration, peer mesh, and email alerts. Built with Rust, Tokio, Axum, and SQLite.
3 + A production operations monitor: health checks, TLS certificate tracking, remote test orchestration, peer mesh, and email alerts. Built with Rust, Tokio, Axum, and SQLite.
4 4
5 5 ## Prerequisites
6 6
@@ -35,11 +35,11 @@
35 35
36 36 PoM reads `~/.config/pom/pom.toml`. The config defines:
37 37
38 - - **Targets** -- HTTP endpoints to monitor, with expected status codes, JSON field checks, body substring matches, and check intervals
39 - - **Peers** -- other PoM instances in the mesh (URL, bearer token, heartbeat interval, grace period)
40 - - **Alerts** -- Postmark API credentials, recipient addresses, per-target cooldowns (falls back to stdout in dev mode)
41 - - **TLS** -- hosts to probe for certificate expiry warnings
42 - - **Tests** -- SSH targets and commands for remote test suite execution
38 + - **Targets**: HTTP endpoints to monitor, with expected status codes, JSON field checks, body substring matches, and check intervals
39 + - **Peers**: other PoM instances in the mesh (URL, bearer token, heartbeat interval, grace period)
40 + - **Alerts**: Postmark API credentials, recipient addresses, per-target cooldowns (falls back to stdout in dev mode)
41 + - **TLS**: hosts to probe for certificate expiry warnings
42 + - **Tests**: SSH targets and commands for remote test suite execution
43 43
44 44 ## Module Overview
45 45
@@ -63,7 +63,7 @@
63 63 # Polls /admin/uploads/health.json for queue depth, stuck-scan count,
64 64 # held backlog, and per-layer error rates. Thresholds per
65 65 # scan-pipeline-audit.md § 6. Localhost on the makenotwork port to
66 - # skip the Caddy + Cloudflare path — internal-only signal.
66 + # skip the Caddy + Cloudflare path (internal-only signal).
67 67 base_url = "http://127.0.0.1:3000"
68 68 interval_secs = 300
69 69 timeout_secs = 10
@@ -38,7 +38,7 @@
38 38 <head>
39 39 <meta charset="utf-8">
40 40 <meta name="viewport" content="width=device-width, initial-scale=1">
41 - <title>PoM — {instance_name}</title>
41 + <title>PoM: {instance_name}</title>
42 42 <link rel="preconnect" href="https://fonts.googleapis.com">
43 43 <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
44 44 <link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500&family=Lato:wght@400;700&display=swap" rel="stylesheet">
@@ -371,7 +371,6 @@
371 371 }
372 372 document.getElementById('global-dot').className = 'summary-dot ' + dotClass(worst).replace('dot-', 'dot-');
373 373
374 - // Sort target names
375 374 const names = Object.keys(targets).sort();
376 375 let gridHtml = '';
377 376 for (let i = 0; i < names.length; i++) {
@@ -379,13 +378,10 @@
379 378 }
380 379 document.getElementById('target-grid').innerHTML = gridHtml;
381 380
382 - // Details
383 381 document.getElementById('details-section').innerHTML = renderDetails(targets);
384 382
385 - // Update timestamp
386 383 document.getElementById('last-updated').textContent = 'Updated ' + new Date().toLocaleTimeString();
387 384
388 - // Mesh
389 385 if (HAS_MESH) {
390 386 try {
391 387 const mr = await fetch('/api/mesh', FETCH_OPTS);
M pom/src/display.rs +18 -52
@@ -26,14 +26,7 @@
26 26 /// Format a single health snapshot as a human-readable line.
27 27 pub fn format_health_snapshot(s: &HealthSnapshot) -> String {
28 28 let mut out = String::new();
29 - write!(
30 - out,
31 - "[{}] {} \u{2014} {}",
32 - s.status.icon(),
33 - s.target,
34 - s.status
35 - )
36 - .unwrap();
29 + write!(out, "[{}] {}: {}", s.status.icon(), s.target, s.status).unwrap();
37 30 write!(out, " ({}ms)", s.response_time_ms).unwrap();
38 31 if let Some(details) = &s.details {
39 32 if let Some(v) = &details.version {
@@ -122,25 +115,25 @@
122 115
123 116 if let Some(t) = tls {
124 117 if let Some(ref err) = t.error {
125 - writeln!(out, " TLS: [ERR] {} \u{2014} {}", t.host, scrub(err)).unwrap();
118 + writeln!(out, " TLS: [ERR] {}: {}", t.host, scrub(err)).unwrap();
126 119 } else if t.days_remaining <= 0 {
127 120 writeln!(
128 121 out,
129 - " TLS: [ERR] {} \u{2014} EXPIRED (expired {})",
122 + " TLS: [ERR] {}: EXPIRED (expired {})",
130 123 t.host, t.not_after
131 124 )
132 125 .unwrap();
133 126 } else if t.days_remaining <= 14 {
134 127 writeln!(
135 128 out,
136 - " TLS: [WARN] {} \u{2014} {}d remaining (expires {})",
129 + " TLS: [WARN] {}: {}d remaining (expires {})",
137 130 t.host, t.days_remaining, t.not_after
138 131 )
139 132 .unwrap();
140 133 } else {
141 134 writeln!(
142 135 out,
143 - " TLS: [OK] {} \u{2014} {}d remaining (expires {})",
136 + " TLS: [OK] {}: {}d remaining (expires {})",
144 137 t.host, t.days_remaining, t.not_after
145 138 )
146 139 .unwrap();
@@ -193,24 +186,14 @@
193 186
194 187 if let Some(w) = whois {
195 188 if let Some(ref err) = w.error {
196 - writeln!(out, " WHOIS: [ERR] {} \u{2014} {}", w.domain, scrub(err)).unwrap();
189 + writeln!(out, " WHOIS: [ERR] {}: {}", w.domain, scrub(err)).unwrap();
197 190 } else if let Some(days) = w.days_remaining {
198 191 if days <= 0 {
199 - writeln!(out, " WHOIS: [ERR] {} \u{2014} EXPIRED", w.domain).unwrap();
192 + writeln!(out, " WHOIS: [ERR] {}: EXPIRED", w.domain).unwrap();
200 193 } else if days <= 30 {
201 - writeln!(
202 - out,
203 - " WHOIS: [WARN] {} \u{2014} {}d remaining",
204 - w.domain, days
205 - )
206 - .unwrap();
194 + writeln!(out, " WHOIS: [WARN] {}: {}d remaining", w.domain, days).unwrap();
207 195 } else {
208 - writeln!(
209 - out,
210 - " WHOIS: [OK] {} \u{2014} {}d remaining",
211 - w.domain, days
212 - )
213 - .unwrap();
196 + writeln!(out, " WHOIS: [OK] {}: {}d remaining", w.domain, days).unwrap();
214 197 }
215 198 }
216 199 }
@@ -233,7 +216,7 @@
233 216 && s.stale
234 217 && let Some(reason) = &s.reason
235 218 {
236 - writeln!(out, " Tests: STALE \u{2014} {}", scrub(reason)).unwrap();
219 + writeln!(out, " Tests: STALE ({})", scrub(reason)).unwrap();
237 220 }
238 221
239 222 if let Some(inc) = incident {
@@ -258,7 +241,7 @@
258 241 for h in history {
259 242 writeln!(
260 243 out,
261 - "[{}] {} \u{2014} {} ({}ms) {}",
244 + "[{}] {}: {} ({}ms) {}",
262 245 h.status.icon(),
263 246 h.target,
264 247 h.status,
@@ -284,7 +267,7 @@
284 267 }
285 268 write!(out, " {}", r.started_at).unwrap();
286 269 if let (Some(p), Some(f)) = (r.summary.total_passed, r.summary.total_failed) {
287 - write!(out, " \u{2014} {p} passed, {f} failed").unwrap();
270 + write!(out, " ({p} passed, {f} failed)").unwrap();
288 271 }
289 272 writeln!(out).unwrap();
290 273 }
@@ -323,25 +306,13 @@
323 306 writeln!(out, "DNS Records:").unwrap();
324 307 for r in dns_results {
325 308 if let Some(ref err) = r.error {
326 - writeln!(
327 - out,
328 - " [ERR] {} {} \u{2014} {}",
329 - r.name,
330 - r.record_type,
331 - scrub(err)
332 - )
333 - .unwrap();
309 + writeln!(out, " [ERR] {} {}: {}", r.name, r.record_type, scrub(err)).unwrap();
334 310 } else if r.matches {
335 - writeln!(
336 - out,
337 - " [OK] {} {} \u{2014} {:?}",
338 - r.name, r.record_type, r.actual
339 - )
340 - .unwrap();
311 + writeln!(out, " [OK] {} {}: {:?}", r.name, r.record_type, r.actual).unwrap();
341 312 } else {
342 313 writeln!(
343 314 out,
344 - " [FAIL] {} {} \u{2014} expected {:?}, got {:?}",
315 + " [FAIL] {} {}: expected {:?}, got {:?}",
345 316 r.name, r.record_type, r.expected, r.actual
346 317 )
347 318 .unwrap();
@@ -356,19 +327,14 @@
356 327 writeln!(out, "WHOIS:").unwrap();
357 328 for w in whois_results {
358 329 if let Some(ref err) = w.error {
359 - writeln!(out, " [ERR] {} \u{2014} {}", w.domain, scrub(err)).unwrap();
330 + writeln!(out, " [ERR] {}: {}", w.domain, scrub(err)).unwrap();
360 331 } else {
361 332 let days_str = w.days_remaining.map_or_else(
362 333 || "expiry unknown".to_string(),
363 334 |d| format!("{d}d remaining"),
364 335 );
365 336 let registrar_str = w.registrar.as_deref().unwrap_or("unknown registrar");
366 - writeln!(
367 - out,
368 - " [OK] {} \u{2014} {days_str} ({registrar_str})",
369 - w.domain
370 - )
371 - .unwrap();
337 + writeln!(out, " [OK] {}: {days_str} ({registrar_str})", w.domain).unwrap();
372 338 }
373 339 }
374 340 }
@@ -484,7 +450,7 @@
484 450 assert!(!cleaned.contains('\u{1b}'), "ESC must be stripped");
485 451 assert!(!cleaned.contains('\r') && !cleaned.contains('\n'));
486 452 assert_eq!(cleaned, "1.0[2J[1;1H FAKE ALL-CLEAR");
487 - // Printable Unicode (e.g. the em-dash the display uses) is preserved.
453 + // Printable non-ASCII Unicode is preserved.
488 454 assert_eq!(scrub("v1.2 \u{2014} ok"), "v1.2 \u{2014} ok");
489 455 }
490 456
@@ -752,7 +752,6 @@
752 752 // First alert, not in cooldown
753 753 assert!(!alerter.is_within_cooldown("health:mnw").await);
754 754
755 - // Record an alert
756 755 db::insert_alert(
757 756 &pool,
758 757 "health:mnw",
@@ -764,7 +763,6 @@
764 763 .await
765 764 .unwrap();
766 765
767 - // Now should be in cooldown
768 766 assert!(alerter.is_within_cooldown("health:mnw").await);
769 767 }
770 768
@@ -979,12 +977,10 @@
979 977 // Not in cooldown initially
980 978 assert!(!alerter.is_within_cooldown("health:example.com").await);
981 979
982 - // Send an alert for "example.com"
983 980 alerter
984 981 .send_health_alert("example.com", "Example", "operational", "error", None)
985 982 .await;
986 983
987 - // Same target should now be in cooldown
988 984 assert!(alerter.is_within_cooldown("health:example.com").await);
989 985
990 986 // Different target should NOT be in cooldown
@@ -20,7 +20,6 @@
20 20 // Cancellation token for graceful shutdown
21 21 let token = tokio_util::sync::CancellationToken::new();
22 22
23 - // Instance identity
24 23 let instance_id = peer::load_or_create_instance_id(config.instance.id.as_deref())?;
25 24 let instance_name = config.instance_name();
26 25 let instance_info = peer::InstanceInfo {
@@ -31,7 +30,6 @@
31 30 started_at: chrono::Utc::now().to_rfc3339(),
32 31 };
33 32
34 - // Alerter
35 33 let alerter = match config.alerts.as_ref() {
36 34 Some(alert_config) => {
37 35 info!("Alerts enabled (to: {})", alert_config.to);
@@ -49,7 +47,6 @@
49 47 info!("Instance: {instance_name} (id={instance_id})");
50 48 info!("Starting serve mode (default interval: {default_interval}s, prune: {prune_days}d)");
51 49
52 - // Mesh state
53 50 let mesh = peer::new_mesh_state(instance_info, &config.peers);
54 51
55 52 // Load known peer identities from DB
@@ -64,7 +61,6 @@
64 61
65 62 let mut handles: Vec<JoinHandle<()>> = Vec::new();
66 63
67 - // Spawn all monitoring tasks
68 64 handles.extend(tasks::spawn_health_tasks(
69 65 config,
70 66 pool,
@@ -139,7 +135,6 @@
139 135 handles.extend(hb_handles);
140 136 }
141 137
142 - // Spawn monitoring-offline meta-alert task
143 138 if let Some(handle) =
144 139 tasks::spawn_meta_alert_task(config, pool, default_interval, &token, alerter.as_ref())
145 140 {
@@ -152,7 +152,7 @@
152 152 if staleness.stale
153 153 && let Some(reason) = &staleness.reason
154 154 {
155 - let _ = writeln!(target_status, "Tests: STALE \u{2014} {reason}");
155 + let _ = writeln!(target_status, "Tests: STALE ({reason})");
156 156 }
157 157 }
158 158
@@ -57,7 +57,6 @@
57 57 }
58 58 }
59 59
60 - /// Get health check history.
61 60 #[tool(
62 61 description = "Get recent health check history. Optionally filter by target and limit results (default 10)."
63 62 )]
@@ -71,7 +70,6 @@
71 70 }
72 71 }
73 72
74 - /// List configured targets.
75 73 #[tool(
76 74 description = "List all configured targets with their labels and capabilities (health check, test suite)."
77 75 )]
@@ -93,7 +91,6 @@
93 91 }
94 92 }
95 93
96 - /// Get test run history.
97 94 #[tool(
98 95 description = "Get recent test run history (without raw output). Optionally filter by target and limit results (default 10)."
99 96 )]
@@ -121,7 +118,6 @@
121 118 }
122 119 }
123 120
124 - /// Get peer mesh status.
125 121 #[tool(
126 122 description = "Get the peer mesh status showing all PoM instances, their connectivity, versions, and target health. Requires serve mode to be running."
127 123 )]
@@ -1,8 +1,8 @@
1 - # TagTree -- Architecture
1 + # TagTree Architecture
2 2
3 3 ## Purpose
4 4
5 - TagTree is a shared Rust library crate that provides a hierarchical dot-notation tag standard. Tags are lowercase strings with dot-separated segments representing a hierarchy (e.g., `genre.electronic.house`, `work.meeting.standup`). The crate handles validation, parsing, tree operations, SQL helpers, prefix renaming, and keystroke-speed autocomplete -- with zero runtime dependencies.
5 + TagTree is a shared Rust library crate that provides a hierarchical dot-notation tag standard. Tags are lowercase strings with dot-separated segments representing a hierarchy (e.g., `genre.electronic.house`, `work.meeting.standup`). The crate handles validation, parsing, tree operations, SQL helpers, prefix renaming, and keystroke-speed autocomplete, with zero runtime dependencies.
6 6
7 7 ## Tag Format
8 8
@@ -22,9 +22,9 @@
22 22 | MT | 3 | 64 | 0 | Community-scoped thread tags |
23 23 | MNW | 5 | 100 | 0 | Content/project tags |
24 24
25 - - `max_depth` -- maximum number of segments allowed
26 - - `max_length` -- maximum character length of the entire tag string
27 - - `semantic_depth` -- number of leading segments that carry dispatch meaning (0 = all free-form; 1 = first segment is a namespace like `genre`, `mood`)
25 + - `max_depth`: maximum number of segments allowed
26 + - `max_length`: maximum character length of the entire tag string
27 + - `semantic_depth`: number of leading segments that carry dispatch meaning (0 = all free-form; 1 = first segment is a namespace like `genre`, `mood`)
28 28
29 29 ## Core Types
30 30
@@ -39,45 +39,45 @@
39 39
40 40 ### Validation
41 41
42 - - `validate_with(tag, config)` -- validate against a `TagConfig`
43 - - `validate(tag)` -- validate with defaults (depth 5, length 100, no semantic prefix)
42 + - `validate_with(tag, config)`: validate against a `TagConfig`
43 + - `validate(tag)`: validate with defaults (depth 5, length 100, no semantic prefix)
44 44
45 45 ### Hierarchy Parsing
46 46
47 - - `parent(tag)` -- parent path (`"a.b.c"` -> `Some("a.b")`)
48 - - `leaf(tag)` -- last segment (`"a.b.c"` -> `"c"`)
49 - - `depth(tag)` -- segment count (`"a.b.c"` -> `3`)
50 - - `segment(tag, i)` -- extract segment by 0-based index
51 - - `prefix_at_depth(tag, n)` -- first `n` segments as a path
52 - - `ancestors(tag)` -- all ancestor paths, root to parent
47 + - `parent(tag)`: parent path (`"a.b.c"` -> `Some("a.b")`)
48 + - `leaf(tag)`: last segment (`"a.b.c"` -> `"c"`)
49 + - `depth(tag)`: segment count (`"a.b.c"` -> `3`)
50 + - `segment(tag, i)`: extract segment by 0-based index
51 + - `prefix_at_depth(tag, n)`: first `n` segments as a path
52 + - `ancestors(tag)`: all ancestor paths, root to parent
53 53
54 54 ### Tree Relationships
55 55
56 - - `is_ancestor_of(a, b)` -- true if `a` is an ancestor of `b` at a segment boundary
57 - - `common_ancestor(a, b)` -- longest shared prefix
56 + - `is_ancestor_of(a, b)`: true if `a` is an ancestor of `b` at a segment boundary
57 + - `common_ancestor(a, b)`: longest shared prefix
58 58
59 59 ### Set Operations (in-memory)
60 60
61 - - `children_at_prefix(prefix, tags)` -- immediate children one level below prefix
62 - - `subtree(prefix, tags)` -- all descendants of prefix (including prefix if present)
63 - - `rename_prefix(old, new, tag)` -- swap a tag's prefix, returning new tag
61 + - `children_at_prefix(prefix, tags)`: immediate children one level below prefix
62 + - `subtree(prefix, tags)`: all descendants of prefix (including prefix if present)
63 + - `rename_prefix(old, new, tag)`: swap a tag's prefix, returning new tag
64 64
65 65 ### Semantic Splitting
66 66
67 - - `semantic_prefix(tag, depth)` -- namespace portion
68 - - `free_suffix(tag, depth)` -- value portion after semantic prefix
67 + - `semantic_prefix(tag, depth)`: namespace portion
68 + - `free_suffix(tag, depth)`: value portion after semantic prefix
69 69
70 70 ### SQL Helpers
71 71
72 - - `escape_like(s)` -- escape `%`, `_`, `\` for safe LIKE embedding
73 - - `like_descendant_pattern(prefix)` -- build `prefix.%` for hierarchy queries (works on both SQLite and PostgreSQL)
72 + - `escape_like(s)`: escape `%`, `_`, `\` for safe LIKE embedding
73 + - `like_descendant_pattern(prefix)`: build `prefix.%` for hierarchy queries (works on both SQLite and PostgreSQL)
74 74
75 75 ### TagIndex (Autocomplete)
76 76
77 77 Sorted `Vec<String>` with binary-search lookup. Two-tier suggestion strategy:
78 78
79 - 1. **Path prefix** (tier 1) -- binary search for tags whose full path starts with input. O(log n + k).
80 - 2. **Segment prefix** (tier 2) -- linear scan for tags where any non-first segment starts with input. Only runs if tier 1 didn't fill the limit and input has no dots. A segment index gates entry: if no known segment starts with input, scan is skipped in O(log m).
79 + 1. **Path prefix** (tier 1): binary search for tags whose full path starts with input. O(log n + k).
80 + 2. **Segment prefix** (tier 2): linear scan for tags where any non-first segment starts with input. Only runs if tier 1 didn't fill the limit and input has no dots. A segment index gates entry: if no known segment starts with input, scan is skipped in O(log m).
81 81
82 82 Key methods: `new()`, `empty()`, `insert()`, `remove()`, `rebuild()`, `contains()`, `suggest(input, limit)`, `suggest_with_status(input, limit)`.
83 83
@@ -98,9 +98,9 @@
98 98 // WHERE tag LIKE ?1 ESCAPE '\' -> finds all genre.* tags
99 99 ```
100 100
101 - - **AF, GO, BB** -- SQLite repositories use `like_descendant_pattern` for hierarchy queries; `TagIndex` powers autocomplete in the UI
102 - - **MT** -- community-scoped tags validated per-thread; migration 014 added `path` column using TagTree conventions
103 - - **MNW** -- server-side validation on content/project tags; migration 038 added `path` column
101 + - **AF, GO, BB**: SQLite repositories use `like_descendant_pattern` for hierarchy queries; `TagIndex` powers autocomplete in the UI
102 + - **MT**: community-scoped tags validated per-thread; migration 014 added `path` column using TagTree conventions
103 + - **MNW**: server-side validation on content/project tags; migration 038 added `path` column
104 104
105 105 ## Performance Characteristics
106 106
@@ -793,7 +793,6 @@
793 793 /// Insert a tag into the index. Maintains sorted order. Idempotent.
794 794 pub fn insert(&mut self, tag: String) {
795 795 if let Err(pos) = self.tags.binary_search(&tag) {
796 - // Add new segments
797 796 for seg in tag.split(SEPARATOR) {
798 797 let s = seg.to_string();
799 798 if let Err(sp) = self.segments.binary_search(&s) {
@@ -980,8 +979,6 @@
980 979 }
981 980 }
982 981
983 - // Tests
984 -
985 982 #[cfg(test)]
986 983 mod tests {
987 984 use super::*;