Skip to main content

Signal — Admin Tools (Users, Assignment History, Hiring Pipeline, JD Sync, Analytics)

Written by Schae Lilley

The Admin Tools module is Signal's back office: five screens for the people who operate Signal itself. Users (route /users, shown in the nav as "General Access") manages who holds each access tier; Assignment History (/audit-log) is the audit trail of team-assignment and revenue-split changes made in Signal; Hiring Pipeline (/hiring) reviews and approves open roles against a data-driven capacity check; JD Sheet Sync (/jd-sync) refreshes the job-description link map; and Analytics (/analytics) measures who actually uses Signal and whether the prediction tools drive action. All five routes require Gandalf access (Signal's elevated admin tier) except Analytics, which requires Sauron (the hardcoded super-admin list). Data comes from Signal's own records (entered by users in Signal — user roles, change log, usage events), the finance-owned hiring Google Sheet, the Ops-maintained JD Google Sheet, Nova org data (email→division), Vena revenue actuals (the Hiring Need check), and the ML churn/SE score history (Analytics risk correlation).

Field

Value

Route(s)

/users · /audit-log · /hiring · /jd-sync · /analytics

Access

Gandalf for /users, /audit-log, /hiring, /jd-sync; Sauron only for /analytics. Hiring Approve button shown to Admin-and-above.

Nav section

"Access" (General Access) and "Admin" (Assignment History, Hiring Pipeline, JD Sheet Sync, Analytics) — both pinned to the bottom of the sidebar

Primary data sources

Signal's own records (app_users, change_history, signal_usage_events, recommended_action_feedback); hiring Google Sheet; JD Google Sheet; Nova org data; Vena revenue (Hiring Need); ML churn/SE score history

Writes

User role toggles (app_users); hiring approval (writes back to the hiring Google Sheet); JD resync (server memory only)

Key code refs

src/views/UsersView.tsx, AuditLogView.tsx, HiringPipelineView.tsx, JdSyncView.tsx, AnalyticsView.tsx; src/App.tsx (guards/nav); src/context/AuthContext.tsx; server/index.ts (hiring, JD, usage endpoints), server/google-sheets.ts, server/usageEnrichment.ts

Last verified

staging @ 98df0c4, verified 2026-07-07

Purpose

Signal (Power Digital's internal BI web app) exposes sensitive company data — client revenue, salaries, churn predictions — so the Admin Tools module exists to govern that exposure:

  1. Access control (Users / "General Access", /users). Grants tiered access per person: Team Lead → Admin → Gandalf, via toggle switches. The most sensitive tier (Growth/People salary data) is managed on a separate screen (/growth/access, documented in the Growth Access module page), not inside Users.

  2. Accountability (Assignment History, /audit-log). Every team-assignment, revenue-split, allocation-config, and Service Expansion feedback change made through Signal is logged with who, when, and a before/after diff — so "who moved this client off my roster?" is answerable in seconds.

  3. Hiring discipline (Hiring Pipeline, /hiring). Each proposed hire sits next to a computed "Hiring Need" verdict (is that team actually at revenue capacity?), and an Admin can approve a role directly from Signal — the approval writes back to the finance team's Google Sheet.

  4. Adoption measurement (Analytics, /analytics). Shows who uses Signal, which pages and features, by division, and whether the churn/SE prediction tools produced action on flagged clients — the build-to-usage gap made measurable.

  5. JD link freshness (JD Sheet Sync, /jd-sync). A small utility that refreshes the employee/title → job-description Google Doc mapping that powers "JD" links on employee pages.

Access & visibility

Signal's role ladder (all five Admin Tools screens sit at the top of it):

  • Member — the base tier: any signed-in user with no elevated role. Members see only Summary and Employees; everything else redirects to /summary.

  • Team Lead (app_users.is_team_lead) — adds Manage Leads, Pulse submission, Revenue Overlap.

  • Admin (app_users.is_admin) — adds Corrections, Capacity, Client Profitability, Pulse Summary, and other admin-level views. Admin-gated things also pass for Gandalf.

  • Gandalf (app_users.is_gandalf) — adds the Admin Tools screens (/users, /audit-log, /hiring, /jd-sync), plus Divisional P&Ls and AI Solutions.

  • Sauron — a hardcoded super-admin email list in code (SUPER_ADMIN_EMAILS in src/context/AuthContext.tsx, mirrored in server/index.ts; 4 emails as of Jul 2026: john@, jaime.diaz@, laura.bejarano@, lily.loyer@ powerdigitalmarketinginc.com). Sauron auto-sets Team Lead + Admin + Gandalf and cannot be demoted from the UI. Only Sauron can open /analytics.

Exact gate mechanics per route (all in src/App.tsx):

  • /users, /audit-log, /hiring, /jd-sync — wrapped in GandalfRoute (redirects non-Gandalf users to /summary). Nav links carry the gandalfOnly flag.

  • /analytics — wrapped in SauronRoute (redirects non-Sauron users to /summary). Nav link is sauronOnly.

  • Nav placement: /users appears as "General Access" in an "Access" nav section; /audit-log ("Assignment History"), /hiring, /jd-sync, /analytics sit in the "Admin" nav section along with Corrections (Admin-tier). Both sections are pinned to the bottom of the sidebar, Access above Admin.

  • How the flags are granted: a Gandalf user flips the Team Lead / Admin / Gandalf toggles on the Users screen, which writes the booleans on the person's app_users row (Signal's own records). The change takes effect for the target user on their next session/refresh (role flags are cached in sessionStorage). One extra path exists: a hardcoded Gandalf allowlist in code (GANDALF_ALLOWLIST in AuthContext.tsx; one stakeholder email as of Jul 2026) grants Gandalf regardless of database state.

  • Server-side enforcement: the JD sync endpoint (POST /api/jd-sheet/sync) checks app_users.is_gandalf server-side (requireGandalf). The hiring endpoints (GET /api/hiring-roles*, POST /api/hiring-roles/approve) have no server-side role middleware as of Jul 2026 — the Approve button is gated in the UI to Admin-and-above only. Users and Assignment History read/write Supabase directly from the browser.

  • Account provisioning: an app_users row is created server-side on first sign-in (POST /api/auth/ensure-provisioned). Users who are an Executive Sponsor (Account Director) or Group Director on any active Nova client are auto-granted Team Lead at provisioning time; this upgrade is never auto-reverted.

  • Sign-in itself is Google OAuth restricted to three domains (ALLOWED_DOMAINS in AuthContext.tsx): powerdigitalmarketinginc.com, external.powerdigitalmarketinginc.com, cardinaldigitalmarketing.com.

Data sources & lineage

"Signal's own records" below means data entered by users in Signal (stored in Signal's application database).

On-screen element

Origin system

Code path

Refresh

Caveat

Users: user table (name, email, first sign-in, last active, role, 3 toggles)

Signal's own records — app_users rows, auto-created on first sign-in

Browser reads app_users directly (UsersView.tsx); rows provisioned by POST /api/auth/ensure-provisioned

Live on page load

"Last Active" is displayed but no code path in the app repo stamps it — treat it as unreliable. "First Sign In" falls back to the row's created date.

Users: role toggles

Signal's own records — app_users.is_team_lead / is_admin / is_gandalf

Browser writes app_users directly (UsersView.tsx)

Immediate write; target user picks it up next session/refresh

Sauron rows are locked (cannot be demoted). The lock list in UsersView.tsx contains only john@ as of Jul 2026, narrower than the 4-email Sauron list.

Users: "Allowed domains" badge

Code constant

ALLOWED_DOMAINS in src/context/AuthContext.tsx

Code deploy only

3 domains as of Jul 2026

Assignment History: change table

Signal's own records — change_history, written by Manage Leads / revenue-split / allocation-config / SE-feedback save paths (logChange)

getChangeHistory in src/services/supabase.ts, last 500 rows

Live on page load

Only captures changes made through Signal. Entity types: team_assignment, revenue_split, allocation_config, se_client_feedback (the filter dropdown exposes the first three).

Assignment History: client & employee names

Nova org/client data (loaded app-wide on start)

DataContext accounts/employees; IDs resolved client-side (AuditLogView.tsx)

App start

Unknown IDs render as #id / "Client #id"

Hiring Pipeline: Power Digital tab

Hiring Google Sheet (finance-owned), tab "Divison Sal Cap" (sheet's own spelling), sheet ID env HIRING_SHEET_ID with a hardcoded default

GET /api/hiring-roles → server/google-sheets.ts fetchHiringRoles()

15-minute server cache (code constant); "Sync Sheet" button forces refresh

Sheet layout/tab names are parsed heuristically — a sheet restructure changes behavior

Hiring Pipeline: Cardinal (Healthcare) tab

Same hiring Google Sheet, tab matching /cardinal/i (default "Cardinal Health Sal Cap", env CARDINAL_SHEET_TAB)

GET /api/hiring-roles/cardinal

Same 15-min cache

Tab auto-discovered; falls back to the configured name

Hiring Pipeline: Approve action

Writes to the hiring Google Sheet (stage → "2 - Approved" + today's date)

POST /api/hiring-roles/approve → approveHiringRole() in google-sheets.ts

Immediate; server hiring cache invalidated

The Google Sheet is the system of record — this changes finance's document, not just Signal

Hiring Pipeline: "Hiring Need" verdict

Computed in the browser: Vena revenue actuals (RPE/MRR per employee, via the server KPI engine) vs. official role KPI targets (Signal's KPI Targets configuration, synced from a KPI Google Sheet)

getHiringNeed in HiringPipelineView.tsx + computeRoleCapacity in src/utils/roleCapacity.ts, fed by DataContext employee metrics

Follows the app-wide selected period and data load

Thresholds are code constants (see Metrics & definitions). Falls back from division-scoped to all-division department data; "No Data" when no KPI-tracked employees match.

JD Sync: status card

JD Google Sheet (Ops-curated Name/Title/JD sheet; env JD_MAP_SHEET_ID, hardcoded default), read via a Google service account

GET /api/jd-sheet/status, POST /api/jd-sheet/sync (Gandalf server-checked)

Manual sync only; result held in server memory

Sync state is lost on every server restart/deploy; until synced, Signal serves a static snapshot compiled into the code (server/jd-data.ts)

Analytics: events, chart, top users/actions

Signal's own records — signal_usage_events; page views are auto-logged on every route change app-wide plus richer per-feature actions

Browser reads directly (getUsageEvents, up to 5,000 rows per range — code constant); events written by usePageViewTracking + logUsageEvent

Live

Only instrumented interactions are counted; page-view coverage is app-wide as of Jul 2026, but feature-level actions exist mainly for churn/SE/portfolio

Analytics: "Actions on flagged clients"

Signal's own records — recommended_action_feedback (Take/Hide events from Churn/SE client detail), reduced to currently-"taken" (latest event per user+client+action wins)

getTakenActionsForAnalytics (up to 10,000 rows — code constant)

Live

Correlation with risk uses the ML score history below; if that lookup fails the card shows "Risk lookup unavailable"

Analytics: "Adoption by division"

Nova org data (email → division/department)

GET /api/usage/email-divisions → fetchEmailDivisions() in server/usageEnrichment.ts

1-hour server cache (code constant)

Failure leaves the panel empty ("email→division lookup unavailable"); unmatched emails roll up as "Unknown"

Analytics: "Usage by client risk"

ML model score history — weekly churn-band snapshots (point-in-time, as of the event week)

POST /api/usage/client-status → fetchClientStatusByWeek() in usageEnrichment.ts

Per page load / range change

Risk band is what the model said that week, not today; resolves after first paint ("resolving…" state), failure shows an explicit unavailable state

Metrics & definitions

  • Role (Users screen) — badge derived from the app_users flags: Sauron (hardcoded super-admin list), Admin (is_admin), Team Lead (is_team_lead), Member (none). Gandalf is a separate toggle, not a badge. Origin: Signal's own records + code constants.

  • Total Users / Admins / Allowed domains (Users screen) — count of app_users rows (everyone who has ever signed in); count of rows with is_admin or on the super-admin list; count of allowed sign-in domains (code constant, 3 as of Jul 2026).

  • Total Changes (Assignment History) — number of change_history rows loaded; capped at the most recent 500 (code constant as of Jul 2026).

  • Stage (Hiring Pipeline) — the sheet's raw stage string bucketed by prefix: 0→Theoretical, 1→Proposed, 2→Approved, 7/"rth"→RTH, 9 or "fbf…hired"→FBF-Hired, 8/"fbf"→FBF, 3/5/"hired"→Hired, 4/6/"term"→Termed; blank→Unassigned; else Other. Origin: hiring Google Sheet + code mapping.

  • Hiring Need (Hiring Pipeline) — for the role's department within its division, average of each KPI-tracked employee's actual (RPE or MRR, per the role's primary KPI, from Vena revenue) versus the role's official KPI target, as a percentage. Verdicts (code constants as of Jul 2026): ≥100% = "Valid Hire" (team at capacity), 85–99% = "Review" (nearing capacity), <85% = "Questionable" (open capacity), no matching KPI-tracked employees = "No Data". If the division has no data, it falls back to the department across all divisions. High percentage = the team is over its revenue-per-head target, so hiring is justified.

  • Open Roles / Approved / Proposed / Total Salary / 2026 Impact / US Hires / International (Hiring Pipeline summary cards) — counts and sums over the currently filtered rows; Salary and 2026 Impact (projected revenue) come straight from sheet columns; Geo normalizes the sheet's geo string to US vs International.

  • Rows processed / Names mapped / Titles mapped (unanimous) / Excluded rows / Conflicted titles (JD Sync) — results of parsing the JD Google Sheet: per-person name→JD links, per-title links only when every person with that title has the same JD ("unanimous"), rows excluded by parsing rules, and titles whose JD differs across people (must be resolved per-name in the sheet).

  • Total events / Unique users / Top module / Top action (Analytics) — over the selected range and filters: count of signal_usage_events rows (capped at 5,000 fetched — code constant), distinct user emails, most frequent module, most frequent action.

  • Activity over time (Analytics) — events per day (per hour for the 24h range), one line for the total plus a dashed line per module with data; portfolio = purple, churn = red, service expansion = green (code constants), other modules get a fallback color.

  • Adoption by division (Analytics) — events and distinct users grouped by the event user's Nova division, with "% of events resolved" indicating how many emails matched the Nova lookup.

  • Usage by client risk (Analytics) — client-scoped events bucketed by the client's churn band (Critical/High/Medium/Low/Unknown) as of the event's ISO week, from the ML churn score history.

  • Actions on flagged clients (Analytics) — of recommended actions currently marked "taken" (latest take/untake event wins per user+client+action), how many were on clients whose churn band was High or Critical that week ("flagged" = High + Critical, code constant), plus distinct flagged clients acted on and a per-module split. This is the closest thing to an outcome metric for the prediction tools.

How it's used

  1. Grant a new leader access. A new VP needs Signal. They sign in once with their company Google account (this auto-creates their user row; Executive Sponsors (Account Directors) and Group Directors on active Nova clients are auto-granted Team Lead). A Gandalf user opens Users ("General Access" in the Access nav section), searches the name, and flips on the needed tier: Team Lead for Manage Leads and Pulse, Admin for Capacity/Profitability/Corrections, Gandalf for the Admin Tools themselves. Least-privilege by default.

  2. Grant salary visibility. Growth/People data (salaries, performance) is NOT granted on the Users screen — it is managed on the separate Growth Access screen (/growth/access) by delegated Growth managers with an unlock password. See the Growth Access module page.

  3. Investigate a disputed assignment. An account lead says a client vanished from their book. Open Assignment History (/audit-log), search the client name, expand the row: it shows who changed the team, when (hover for the exact timestamp), and the before/after lead lists resolved to names — then revert in Manage Leads if needed.

  4. Pressure-test and approve a hire. In headcount review, open Hiring Pipeline; the stage filter defaults to Proposed + Approved. For each proposed role, read the Hiring Need verdict — "Questionable — has open capacity" means that team is below its revenue-per-employee target and the ask deserves scrutiny; "Valid Hire — at capacity" supports approval. An Admin clicks Approve, which updates the finance team's Google Sheet (stage "2 - Approved" + today's date). Filter by Division/Department, export CSV for the meeting.

  5. Run the adoption review. Weekly, a Sauron user opens Analytics, sets range to 7d: check Unique users and Adoption by division against the team's weekly-active-usage goal, then check Actions on flagged clients — are the churn/SE predictions producing action on high-risk clients, or just page views? Use Top users and Top pages & actions to see who to enable next.

  6. Fix stale JD links. Ops updated job descriptions and employee pages still link old docs. Open JD Sheet Sync, click "Resync JD Sheet", confirm the counts. If it errors, the screen shows the fix (usually: share the sheet with the displayed service-account email — a Copy button is provided). Check the conflicted-titles list; those titles need per-person rows in the sheet.

What users can change here

  • Users (/users): toggling Team Lead / Admin / Gandalf writes the corresponding boolean on the person's app_users row in Signal's own records. Side effects: the target user's nav and route access change on their next session/refresh; toggling your own row refreshes immediately. Sauron rows cannot be demoted from the UI (hardcoded lock). Growth/People access is NOT changed here (separate Growth Access screen).

  • Hiring Pipeline (/hiring): the Approve button (visible to Admin-and-above, on Proposed/Theoretical rows) writes to the hiring Google Sheet — sets that row's stage to "2 - Approved" and stamps today's date. This changes the finance team's source-of-truth document, not just Signal's display. The server's 15-minute hiring cache is invalidated so the change shows immediately. "Sync Sheet" is a read-only refresh.

  • JD Sheet Sync (/jd-sync): the "Resync JD Sheet" button re-reads the JD Google Sheet into an in-memory server map (no database write). The refreshed map immediately powers /api/jd-links (JD links on employee pages) but is lost on every server restart or deploy, after which Signal reverts to a static snapshot compiled into the code.

  • Assignment History (/audit-log) and Analytics (/analytics) are read-only. They display writes made elsewhere: Manage Leads / revenue splits / SE feedback for the audit log; app-wide usage instrumentation for Analytics.

Caveats & data quality

  • "Last Active" on the Users screen is not stamped by any code path in the app repo as of Jul 2026 — the column exists and is rendered, but nothing in the frontend or backend updates it, so it may show "Never" or stale values. Do not use it for offboarding decisions without verifying how (or whether) it is populated. "First Sign In" falls back to the row-creation date.

  • Sauron and the Gandalf allowlist are hardcoded in the frontend/backend code, not managed in the UI: the 4-email Sauron list (SUPER_ADMIN_EMAILS), the un-demotable lock on the Users screen (only 1 of those 4 emails as of Jul 2026), and a 1-email hardcoded Gandalf allowlist. All are code-deploy changes.

  • Hiring endpoints lack server-side role checks as of Jul 2026: GET /api/hiring-roles* and POST /api/hiring-roles/approve have no auth middleware; the Approve action is gated only in the UI (Admin-and-above). JD sync, by contrast, is enforced server-side (Gandalf).

  • Assignment History only sees Signal-made changes. Assignments changed outside Signal (directly in Nova or in the database) do not appear. It loads the most recent 500 rows (code constant); older history is in the database but not shown.

  • JD Sync state is ephemeral — a resync lives in server memory and silently reverts to the static code snapshot on every deploy/restart. The status card tells you which mode is active ("Not yet synced this session — currently serving the static snapshot").

  • Google Sheet dependencies are fragile by nature. The Hiring Pipeline parses tab names, header layouts, and the stage taxonomy ("0 Theoretical" … "9 FBF-Hired") from the finance sheet; a sheet restructure changes behavior. Sheet IDs are env-overridable defaults hardcoded in server/google-sheets.ts. The hiring data cache is 15 minutes; the "Sync Sheet" button bypasses it.

  • Hiring Need thresholds (≥100 / 85–99 / <85) are code constants in HiringPipelineView.tsx, not configurable settings; the underlying KPI targets come from Signal's KPI Targets configuration and their business currency (blessed by leadership vs. stale benchmark) is a business question the code cannot answer.

  • Analytics counts only what is instrumented. Page views are logged app-wide on route changes as of Jul 2026, but richer feature actions exist mainly for the churn/SE/portfolio modules; the events fetch is capped at 5,000 rows per range and taken-actions at 10,000 (code constants), so very long "all time" ranges can undercount.

  • Analytics enrichment panels degrade gracefully: Adoption by division, Usage by client risk, and Actions on flagged clients light up only when the Nova email→division lookup and the ML score-history tables are reachable; otherwise they show explanatory empty/unavailable states rather than zeros. Risk bands are point-in-time (as of the event's week), so they will not match today's churn view.

  • Action labels are a curated map (ACTION_LABELS in AnalyticsView.tsx): new instrumented features display as raw "module · action" until a friendly label is added.

  • Who maintains the hiring Google Sheet and the JD sheet (owning team, update cadence) is operational knowledge — not defined in the app repo.

Related views

  • Manage Leads (/leads) — the primary writer of the change_history entries that Assignment History displays (team assignments, revenue splits).

  • Growth Access (/growth/access) — the separate management screen for Growth/People (salary) visibility: per-user tab capabilities (People, Performance Radar, Manage access) and division/department scoping, protected by an unlock password. Managed by delegated Growth managers or Sauron — Gandalf alone does not grant entry.

  • Corrections (/corrections) — sits in the same Admin nav section (Admin tier); user-submitted data-issue flags.

  • Role Capacity (/capacity) and KPI Targets (/kpi-targets) — the same capacity math and official targets behind the Hiring Pipeline's Hiring Need verdict; division pills in the hiring table deep-link to Capacity.

  • Employees (/employees) — consumes the JD link map that JD Sheet Sync refreshes; department pills in the hiring table deep-link here.

  • Churn Risk (/predictions/churn), Service Expansion (/predictions/se), Portfolio Review (/predictions/portfolio) — the modules whose usage and "action taken" events Analytics measures.

FAQ

Q: Why can't I open the Users / Hiring Pipeline / Assignment History pages? I just get redirected to Summary. A: Those pages require Gandalf access — Signal's elevated admin tier, above Team Lead and Admin. If you land on Summary, your account doesn't have the Gandalf flag. Ask an existing Gandalf user (typically Signal's owners/leadership) to enable it for you on the Users screen ("General Access" in the Access section of the sidebar).

Q: Who can see the Analytics page, and why can't I? A: Analytics (/analytics) is restricted to "Sauron" — a hardcoded super-admin email list in Signal's code (4 people as of Jul 2026: the app owner and the Signal build team). It shows raw usage logs for every user, so even Gandalf users are excluded. Adding someone requires a code change, not a UI toggle.

Q: What's the difference between Team Lead, Admin, Gandalf, and Sauron? A: They are Signal's access tiers, granted as toggles on the Users screen. Team Lead unlocks Manage Leads, Pulse submission, and Revenue Overlap. Admin adds Corrections, Capacity, Client Profitability, and Pulse Summary (and everything Team Lead has). Gandalf adds the Admin Tools screens, Divisional P&Ls, and AI Solutions. Sauron is the hardcoded super-admin list — it auto-includes all other tiers, can't be demoted from the UI, and is the only tier that can open Analytics. A user with no tier ("Member") sees only Summary and Employees.

Q: How do I give someone access to salary / People data? A: Not on the Users screen. Growth/People data (salaries, performance) is managed on the separate Growth Access screen (/growth/access), which requires the "Manage Growth access" capability (or Sauron) plus an unlock password. There you pick the user, the tabs they may see (People, Performance Radar), and the divisions/departments their data is limited to. Gandalf access alone does not include People data.

Q: A client disappeared from someone's book — how do I find out who changed it? A: Open Assignment History (/audit-log, Gandalf access required), search the client name, and expand the matching row. You'll see who made the change (their email), when, and a before/after diff with lead names resolved. Note it only records changes made through Signal (Manage Leads, revenue splits, allocation config, SE feedback) — changes made directly in Nova or the database won't appear.

Q: Does approving a role in the Hiring Pipeline actually change anything outside Signal? A: Yes. The Approve button writes directly to the finance team's hiring Google Sheet: it sets that row's stage to "2 - Approved" and stamps today's date. Signal is not keeping a separate copy — the Google Sheet is the system of record, so the approval is visible to anyone using that sheet.

Q: What do the "Valid Hire" / "Review" / "Questionable" labels in the Hiring Pipeline mean? A: That's the computed "Hiring Need" verdict. Signal compares the role's team (same department and division) against their official revenue-per-employee or MRR targets using Vena revenue actuals: at ≥100% of target the team is at capacity so the hire is justified ("Valid Hire"); 85–99% is "Review" (nearing capacity); below 85% is "Questionable" (the team has open capacity). "No Data" means no KPI-tracked employees matched that department. The thresholds are code constants as of Jul 2026, and the verdict is an input to the decision, not the decision itself.

Q: The Hiring Pipeline doesn't show the role I just added to the sheet — why? A: The server caches the hiring sheet for 15 minutes. Click the "Sync Sheet" button in the tab bar to force a fresh pull from Google Sheets. Also check the Stage filter — it defaults to Proposed + Approved only, so roles in other stages (Theoretical, RTH, FBF, Hired, Termed) are hidden until you widen the filter.

Q: JD links on employee pages are stale or missing — what do I do? A: Open JD Sheet Sync (/jd-sync, Gandalf access) and click "Resync JD Sheet". If it fails with a permission error, the screen shows the fix: share the JD Google Sheet with the displayed service-account email (Viewer access; there's a Copy button). Two caveats: a title listed under "conflicting JDs" needs per-person rows in the sheet, and the sync only lives in server memory — after a deploy or restart, Signal reverts to a built-in snapshot until someone resyncs.

Q: Do the Analytics numbers capture all Signal usage? A: Mostly, with limits. Page views are logged automatically on every route change across the app, but detailed feature actions (generate, copy, take-action) are instrumented mainly in the Churn, Service Expansion, and Portfolio modules. The view also fetches at most 5,000 events per range, so very long ranges can undercount. Treat trends and comparisons as reliable, absolute totals as a floor.

Q: In Analytics, why does a client's risk band differ from what the Churn Risk page shows today? A: The "Usage by client risk" and "Actions on flagged clients" cards use the churn band as of the week each event happened, from the ML model's weekly score history — deliberately point-in-time, so usage is credited against what the user saw then. The Churn Risk page shows the current score, which may have moved since.

Q: Why does "Adoption by division" show users under "Unknown"? A: The division rollup resolves each event's email against Nova org data (employee → division). Emails that don't match an active Nova user — departed employees, service accounts, or mismatched addresses — fall into "Unknown". The "% of events resolved" indicator on the card tells you how complete the mapping was; if the whole panel is empty, the Nova lookup itself was unavailable.

Did this answer your question?