Files
RuDS/specs/cli_sync.allium

71 lines
2.1 KiB
Plaintext

-- allium: 1
-- bDS CLI / App Notification Sync
-- Scope: extension (Bucket G — MCP + Automation)
-- Distilled from: src/main/engine/CliNotifier.ts, NotificationWatcher.ts
entity DbNotification {
project_id: String?
entity_type: String -- post, media, tag, script, template, project, setting
entity_id: String
action: created | updated | deleted
from_cli: Boolean
seen_at: Timestamp?
created_at: Timestamp
-- Derived
is_processed: seen_at != null
}
surface CliSyncRuntimeSurface {
facing _: CliSyncRuntime
provides:
CliMutationPerformed(project_id, entity_type, entity_id, action)
DbFileChangeDetected()
}
rule CliWriteNotification {
when: CliMutationPerformed(project_id, entity_type, entity_id, action)
-- CLI inserts notification row; app watches for it
ensures: DbNotification.created(
project_id: project_id,
entity_type: entity_type,
entity_id: entity_id,
action: action,
from_cli: true,
seen_at: null
)
}
rule AppWatchNotifications {
when: DbFileChangeDetected()
-- Watches the persisted notification store for external mutations
-- Debounced at 100ms
let unseen = DbNotifications where seen_at = null and from_cli = true
for n in unseen:
ensures: n.seen_at = now
ensures: EngineCacheInvalidated(n.entity_type)
ensures: EntityChangedEvent(n.project_id, n.entity_type, n.entity_id, n.action)
-- IPC event to renderer for UI refresh
}
rule PruneProcessedNotifications {
when: n: DbNotification.created_at + 1.hour <= now
requires: n.is_processed
-- Processed rows: prune after 1 hour
ensures: not exists n
}
rule PruneUnprocessedNotifications {
when: n: DbNotification.created_at + 24.hours <= now
requires: not n.is_processed
-- Unprocessed rows: prune after 24 hours
ensures: not exists n
}
invariant AppNoopNotifier {
-- The desktop application uses a no-op notifier for its own writes
-- It already knows about its own mutations
-- Only CLI writes produce notification rows
}