Witness-Alert Primitive β every domain inherits Apple-alert + RSS for free¶
GFTCL-WITNESS-ALERT-001 Β· v117 substrate Β· finance is the first declared domain Β· ships in this commit.
The pattern, named once¶
Every domain in the cell already emits witnessed events on NATS. What's been missing everywhere is the uniform path from witnessed-event to operator-notification-plus-durable-subscribable-record. This primitive ships that path as a shared substrate layer that any domain plugs into by writing one Swift declaration β not a thousand lines of finance-specific or health-specific plumbing.
The shape, in plain terms:
- A domain witnesses something on NATS β
gaiaftcl.finance.capture.sealed,gaiaftcl.health.protocol.cure_proxy_transition,gaiaftcl.mesh.cell.unreachable, etc. - An alert rule binds (subject, field, comparison, threshold, signal) to that event class. "When Nakamoto < 5, fire a BAD alert." Operator-editable.
- When a rule fires, the alert lands in
alert_queueβ a durable, append-only, content-addressed witness log in the cell's SQLite substrate. - Two adapters read the queue independently and deliver to the operator:
- Apple-alert adapter β
UNUserNotificationCenterlocal push (signal β interruption level:bad=time-sensitive,good=passive,neutral=active) - RSS adapter β
/feed/alerts.xml(every domain) +/feed/alerts/{domain}.xml(per-domain), served on the existing local HTTP server - Every delivery attempt is logged in
alert_delivery_logβ append-only audit of what reached the operator and when.
The queue's witness columns are immutable by constitutional trigger (trig_alert_queue_witness_immutable); the delivery-log is append-only (trig_alert_delivery_log_append_only). The same discipline the Lion Math sweep receipts run under, now for every alert.
Why two surfaces, and the division of labor¶
- Apple alert = push. Interrupts the operator now; ephemeral by nature; urgent; single-operator; on-device.
- RSS feed = durable witness. Every alert that ever fired, timestamped, immutable, subscribable, re-readable. Each entry carries the receipt reference (rule, comparison, observed value, snapshot hash) so a feed item is not a notification β it's a re-runnable witnessed event.
- Queue between them. Decouples "the cell witnessed something" from "the operator was told." Nothing is lost when the operator is away, the device is asleep, or push delivery fails.
RSS is the sovereign choice: open standard, pull-based, no third-party push vendor, inherently a feed of timestamped immutable entries (which is an append-only witness log in another costume). Anything can subscribe β a reader app, a script, another cell, a regulator. v1 is local-private (127.0.0.1:8423 only); authorized-public via the one-membrane-token architecture is a named next summit.
Architecture¶
NATS witnessed events
β
βΌ
ββββββββββββββββββββββ
β AlertGovernor β β domain-agnostic actor
β (GaiaFTCLCore) β in GaiaFTCLCore
βββββββββββ¬βββββββββββ
β writes
βΌ
ββββββββββββββββββββββββββββββββ
β alert_queue (SQLite) β β APPEND-ONLY
β witness cols IMMUTABLE β witness log
ββββββ¬βββββββββββββββββββ¬βββββββ
β β
reads β β reads
βΌ βΌ
ββββββββββββββββββββββββ ββββββββββββββββββββββββ
β AppleAlertAdapter β β AlertFeedRenderer β
β UNUserNotification β β /feed/alerts*.xml β
ββββββββββββββββββββββββ ββββββββββββββββββββββββ
Each domain plugs in via the AlertableDomain protocol with five things:
public protocol AlertableDomain: Sendable {
var domainID: String { get } // "finance"
var watchedSubjects: [String] { get } // ["gaiaftcl.finance.capture.sealed", ...]
var seedRules: [AlertRule] { get } // seeded once; operator-editable
func projectFields(payload: [String: Any]) -> [String: AlertableValue]
func renderSnapshot(rule: AlertRule, observedValue: AlertableValue,
payload: [String: Any]) -> AlertSnapshot
}
That's it. No domain ever writes queue rows, calls UNUserNotificationCenter, or renders RSS β those are the shared primitive's job.
The first domain β finance (reference impl)¶
Sources/FinanceAlertableEvents/FinanceAlertableEvents.swift declares:
Watched subjects:
- gaiaftcl.finance.capture.sealed β capture-concentration sealed
- gaiaftcl.finance.alert.tripped β direct trip event
- gaiaftcl.finance.resolution.concentrated β poly-market resolution concentration
Watchable fields (projected from raw payload to AlertableValue β exact Rat where finance currency lives):
- nakamoto β Int Nakamoto coefficient
- top1_share_pct, top5_share_pct, resolution_share β exact rationals
- market_id, signal_hint β text
Five seed rules:
| ruleID | comparison | signal | meaning |
| --- | --- | --- | --- |
| rule.finance.capture.nakamoto_lt_5 | nakamoto < 5 | bad | < 5 holders control > 50% β capture risk |
| rule.finance.capture.top1_share_gt_50pct | top1_share_pct > 1/2 | bad | single holder > half the market |
| rule.finance.capture.deconcentration_ok | nakamoto β₯ 10 | good | healthy de-concentration |
| rule.finance.resolution.concentrated_gt_2_3 | resolution_share > 2/3 | bad | single resolver > 2/3 of outcomes |
| rule.finance.alert.tripped_named_bad | signal_hint == "bad" | bad | direct finance trip with named bad signal |
Operator edits to these rules persist across launches (seeds use INSERT OR IGNORE).
Survey β where this primitive lands across the cell¶
The whole point of generalizing: one primitive, every domain inherits. Open frontier of declared-domain summits:
- Finance / poly markets β primary, shipped. Capture-positive, de-concentration, resolution-concentration.
- Health (OWL protocols) β alertable transitions: a protocol moving from CURE-PROXY toward CURE-CLOSED (good), a seal's falsifier theorem breaking under new input (bad), a GAMP-5 receipt expiring (bad). The RSS feed of health-seal state changes IS a regulatory artifact.
- Engineering β composite-seal-invalidated when a constituent primitive changes (bad), summit-closed (good). Design-review backstop subscribes; engineer is alerted before shipping against a broken seal.
- Substrate / mesh health β the cell watching itself. Cell unreachable, NATS subject backing up, dead-letter, witness-store write latency climbing. Sovereign ops monitoring with no third-party observability vendor β possibly the highest-daily-value use for a sole operator.
- Governance (Franklin guardian) β REFUSED terminal states, constitutional rule trips, entropy spent without value. The RSS feed becomes the constitutional audit log.
- Ingestion (VIE / Earth Substrate) β feed-source stale, schema-validation failures, witnessed-data freshness lapsing.
Each is one AlertableDomain declaration away β same shape as FinanceAlertableEvents.swift. No more plumbing.
What ships in this commit¶
| File | Purpose |
|---|---|
cells/xcode/Sources/GaiaFTCLCore/AlertableEvent.swift |
Protocol + types (AlertableDomain, AlertableValue, AlertRule, AlertSnapshot, AlertSignal, AlertComparison, WitnessHasher) |
cells/xcode/Sources/GaiaFTCLCore/NarratorSchemaV117.swift |
Migration: alert_rules, alert_queue, alert_delivery_log, alert_domain_registry + immutability triggers + PQ CALORIE receipt |
cells/xcode/Sources/GaiaFTCLCore/AlertGovernor.swift |
Domain-agnostic actor: register, ingest, evaluate, queue-write. Idempotent (alert IDs content-addressed on rule_id + payload_sha256) |
cells/xcode/Sources/GaiaFTCLCore/AlertQueueReader.swift |
GRDB-backed reader over the shared SubstrateDatabase pool |
cells/xcode/Sources/GaiaFTCLCore/AppleAlertAdapter.swift |
UNUserNotificationCenter push adapter with signalβinterruption-level mapping. Suppresses gracefully when no app bundle. |
cells/xcode/Sources/GaiaNodeServerCore/AlertLedgerReader.swift |
Thin shim delegating to AlertQueueReader (kept here so existing RSS code path stays clean) |
cells/xcode/Sources/GaiaNodeServerCore/AlertFeedRenderer.swift |
RSS 2.0 renderer with signal-prefixed titles ([BAD] / [GOOD] / [INFO]) + audit body |
cells/xcode/Sources/GaiaNodeServerCore/HTTPListener.swift |
Routes /feed/alerts.xml + /feed/alerts/{domain}.xml (slug-validated, no path traversal) |
cells/xcode/Sources/FinanceAlertableEvents/FinanceAlertableEvents.swift |
First declared domain β finance |
cells/xcode/Sources/M8WitnessAlertSmokeTest/main.swift |
End-to-end verification |
Verification¶
swift run M8WitnessAlertSmokeTest runs end-to-end against the real substrate.sqlite and asserts:
- β All four V117 tables present
- β
AlertGovernor.register(FinanceAlertableEvents())writes domain row + 5 seed rules - β BAD payload (Nakamoto=3) fires 2 expected rules
- β GOOD payload (Nakamoto=12) fires the de-concentration rule
- β Replaying the same payload is idempotent (0 new queue rows β content-addressed alert IDs)
- β
RSS all-feed contains
[BAD]entries; finance feed carries witness markers - β
Content-Type: application/rss+xml; charset=utf-8 - β
Trigger ABORTS any UPDATE to a witness column with
witness columns are immutable - β Apple-alert drain runs without crash (suppressed when no app bundle / no auth)
swift build β full workspace builds clean.
swift run M8InventoryAuditor β OVERALL TERMINAL: COMPLETE.
v1 scope vs named-next-summit¶
Shipped in v1: - Schema + governor + queue - Apple-alert adapter (graceful no-op when not in an app bundle) - RSS adapter on existing local HTTP server (local-private only, 127.0.0.1) - Finance reference declaration with 5 seed rules - End-to-end smoke test
Named next, deferred:
- Authorized-public RSS via membrane-token gate (so a regulator / consortium / authorized public can subscribe to a safety feed without sovereignty leak)
- Franklin chat rule-authoring ("alert me when any finance capture goes Nakamoto < 5")
- HOME alert-queue surface in the workbench (co-resident, signal-colored, expandable to receipt)
- Additional domain declarations (health, engineering, mesh, governance, ingestion) β each is one Swift file like FinanceAlertableEvents.swift
Constitutional posture¶
- No new external dependency. Native Apple
UNUserNotificationCenter+Network.frameworkHTTP + GRDB (already in use). - Substrate never crosses the wire β only the RSS rendering of verdicts + receipt references.
- Witness columns of
alert_queueare immutable by SQL trigger; tampering with sealed alerts is REFUSED by the database itself. - Alert IDs are content-addressed: same rule against same payload digest β same alert ID β INSERT OR IGNORE β no double-fire. Replays are safe and provably so.
- No NATS traffic leaves the cell. No telemetry. No analytics service.
Patent / license notice¶
Β© 2026 Richard Gillespie. All rights reserved. USPTO patent applications 19/460,960 and 19/096,071.
Federation-cosigned
This page's source is sealed in the GaiaFTCL federation manifest β page SHA-256 307370b8fed881b5β¦, manifest witness a090592e0609adc8β¦, signed 2026-06-02T18:58:22Z by cell gaiaftcl-mac-cell. Verify with gaiaftcl wiki sign --all and compare wiki-all-signatures.json.