Friday user_activity tool (Dustin-only)

Added: 2026-08-07 (entirely-api 0e5b9f7 + 1b65b17)

Friday tool answering “when did X last log in / what has X been doing / did X change the tracker”. Requested after Friday had no way to answer “when did Stephanie last log in and make tracker changes”.

Data sources

  • portal_users (portal_users.db): last_login_at, last_seen_at, last_seen_domain
  • audit_log.db via audit_service.get_events: login history + non-auth activity summary (category.action counts + recent events)
  • tracker_changes.db via tracker_history.list_changes(changed_by=...) (new filter param) — attribution began 2026-07-28; bulk/system edits are recorded as internal

Access control — Dustin ONLY (explicit instruction 2026-08-07)

Two layers, because Jacob is also up_owner so voice-tier gating is not enough:

  1. _DUSTIN_ONLY_TOOLS filter in portal_friday._get_tools_for_role(role, username) removes it from everyone else’s tool definitions (both chat loops pass username).
  2. Executor _exec_user_activity hard-gates on username == "dustin" — fail-closed for the friday_engine path too (field voice context has no username key). Registered in _INTERNAL_OWNER_TOOLS AFTER the _INTERNAL_ADMIN_TOOLS.copy() line so up_admin never inherits it.

Behavior notes

  • All timestamps rendered in ET (_fmt_et, handles ISO and sqlite datetime('now') formats).
  • Name matching stems tokens down to 4 chars so spelling variants hit (“Stephanie” → stem “stephan” → matches “Stephaney Bilyard”).
  • Tests: tests/test_friday_user_activity.py (8 tests, gate + matching + ET).