rename the TIC system agent to event triage
Nightly Build / build (push) Successful in 7m16s

TIC said nothing about what the agent does, and named the wrong thing: the
tick belongs to the scheduler, which is generic and lives outside it. The
agent's only decision is whether an incoming event deserves an interruption
— it sorts, it never acts — so it is now event-triage, matching the
functional naming of the two memory lints.

- agents/tic/ -> agents/event-triage/, module tic/ -> event_triage/,
  TicManager -> EventTriageManager, TicConfig -> EventTriageConfig
- agent id and chat source: "tic" -> "event-triage"
- config keys: tic.* -> event_triage.*, and the config.yml section tic: ->
  event_triage: (greenfield: previously set values fall back to defaults)
- i18n en/it/fr: Event triage / Triage eventi / Tri des evenements; dropped
  the stale "TIC sessions" mention from the debug-pages description
- docs/system-agents.md, docs/index.md, docs/settings.md, CLAUDE.md, SKALD.md
This commit is contained in:
2026-07-28 21:59:37 +01:00
parent 0b793d56ae
commit 046f060fcd
50 changed files with 251 additions and 240 deletions
+10 -10
View File
@@ -898,14 +898,14 @@ pub async fn create_owner_tables(pool: &SqlitePool) -> Result<()> {
.await?;
// Execution log of the **system agents** — the background agents the instance
// runs on a user's behalf without being asked (TIC is the first and, today,
// the only one). The sibling of `job_runs`: same shape, but keyed on the agent
// instead of a scheduled job, because a system agent has no user-authored row
// to point at.
// runs on a user's behalf without being asked (event triage is the first and,
// today, the only one). The sibling of `job_runs`: same shape, but keyed on the
// agent instead of a scheduled job, because a system agent has no user-authored
// row to point at.
//
// Owner table, and that is the whole privacy story: a run of TIC summarises
// what landed in this user's inbox, so it belongs in *their* encrypted file
// and nowhere else. There is deliberately no `user_id` column — the file is
// Owner table, and that is the whole privacy story: an event-triage run
// summarises what landed in this user's inbox, so it belongs in *their*
// encrypted file and nowhere else. There is deliberately no `user_id` column — the file is
// the owner (§5.1). An admin reading `system.db` learns nothing about it.
//
// A user whose database is still locked is skipped by the scheduler and
@@ -948,8 +948,8 @@ pub async fn create_owner_tables(pool: &SqlitePool) -> Result<()> {
// productive run aged out.
//
// Persisting it is what makes a long interval survive a restart. An in-memory
// deadline is fine at TIC's scale — a few minutes, re-armed on boot — but a
// weekly agent on a machine rebooted every few days would have its deadline
// deadline is fine at event triage's scale — a few minutes, re-armed on boot —
// but a weekly agent on a machine rebooted every few days would have its deadline
// reset before it ever fired, and would simply never run.
//
// Owner table for the same reason as the run log: when an agent last ran for
@@ -1166,7 +1166,7 @@ mod tests {
one("INSERT INTO scheduled_jobs (id, title, cron, prompt, session_id) VALUES (1, 't', '* * * * *', 'p', 1)")
.await.unwrap();
one("INSERT INTO job_runs (job_id, started_at, status) VALUES (1, 'now', 'completed')").await.unwrap();
one("INSERT INTO system_agent_runs (agent_id, started_at, status) VALUES ('tic', 'now', 'running')").await.unwrap();
one("INSERT INTO system_agent_runs (agent_id, started_at, status) VALUES ('event-triage', 'now', 'running')").await.unwrap();
// Owner table with a BARE `catalog_name` ref — proves it stands alone with
// FKs on (an owner→registry FK here would die on this INSERT).
one("INSERT INTO mcp_user_servers (name, catalog_name, source) VALUES ('u', 'whatsapp', 'local_script')").await.unwrap();