KPI: label people with their email addresses, from the operator's machine #279

Merged
cruelacid merged 1 commit from worktree-kpi-labels into main 2026-10-08 14:16:55 +01:00
Owner

Task: NEC-242

Shows email addresses on the KPI leaderboard instead of 8-character ids, without changing either server.

  • deploy/clconsole/kpi/label-people.mjs runs by hand from a machine with ssh to clconsole and the identity host.
    • It looks up each id not yet labelled through GET /api/admin/users?id=, on the identity host itself. The admin token is read from identity.env there and never leaves that host.
    • It writes the addresses to person_labels in the KPI Postgres, in one transaction. Values travel through COPY, never spliced into SQL.
    • --all looks everyone up again, and --clear removes every label.
    • It prints counts only, never an address.
  • schema.sql: a new person_labels table. The leaderboard shows the address where there is one, and the id otherwise.
  • Unchanged: /api/kpi and the collector, which still carry no personal data.

Verified

  • Unit tests:
    • only identity UUIDs are looked up;
    • an id the lookup didn't find stays unlabelled rather than being given a wrong label;
    • answers for ids that weren't asked about are ignored;
    • values are escaped through COPY.
  • On a real Postgres: the upsert labels and then relabels a person without duplicating, an unlabelled person falls back to their id, and the "not yet labelled" query returns only that person.
  • pnpm test, typecheck, lint and build-dashboard --check all pass.

Changelog

NONE

🤖 Generated with Claude Code

https://claude.ai/code/session_01MY63BZ4UVtMHFcADNr1jFg

Task: NEC-242 Shows email addresses on the KPI leaderboard instead of 8-character ids, without changing either server. - **`deploy/clconsole/kpi/label-people.mjs`** runs by hand from a machine with ssh to clconsole and the identity host. - It looks up each id not yet labelled through `GET /api/admin/users?id=`, **on the identity host itself**. The admin token is read from `identity.env` there and never leaves that host. - It writes the addresses to `person_labels` in the KPI Postgres, in one transaction. Values travel through `COPY`, never spliced into SQL. - `--all` looks everyone up again, and `--clear` removes every label. - It prints counts only, never an address. - **`schema.sql`:** a new `person_labels` table. The leaderboard shows the address where there is one, and the id otherwise. - **Unchanged:** `/api/kpi` and the collector, which still carry no personal data. ## Verified - Unit tests: - only identity UUIDs are looked up; - an id the lookup didn't find stays unlabelled rather than being given a wrong label; - answers for ids that weren't asked about are ignored; - values are escaped through `COPY`. - On a real Postgres: the upsert labels and then relabels a person without duplicating, an unlabelled person falls back to their id, and the "not yet labelled" query returns only that person. - `pnpm test`, typecheck, lint and `build-dashboard --check` all pass. ## Changelog NONE 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01MY63BZ4UVtMHFcADNr1jFg
KPI: label people with their email addresses, from the operator's machine
Some checks failed
Release note / release-note (pull_request) Successful in 18s
CI / build (pull_request) Successful in 5m42s
CI / e2e (pull_request) Failing after 9m32s
CI / promote (pull_request) Has been skipped
0aacee3578
The dashboard shows people by identity id. label-people.mjs, run by hand from
a machine with ssh to both hosts, looks each unlabelled id up through the
identity service's admin route on the identity host itself (the admin token
is read there and never leaves it) and writes the addresses to a new
person_labels table in the KPI store on clconsole. The leaderboard shows the
address where there is one and the 8-character id otherwise. /api/kpi and
the collector are untouched and carry no personal data. --all relooks
everyone up, --clear removes every label, and the script prints counts only.

Task: NEC-242

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MY63BZ4UVtMHFcADNr1jFg
cruelacid force-pushed worktree-kpi-labels from 0aacee3578
Some checks failed
Release note / release-note (pull_request) Successful in 18s
CI / build (pull_request) Successful in 5m42s
CI / e2e (pull_request) Failing after 9m32s
CI / promote (pull_request) Has been skipped
to 5b84124f8c
All checks were successful
Release note / release-note (pull_request) Successful in 15s
CI / build (pull_request) Successful in 5m23s
CI / e2e (pull_request) Successful in 9m55s
CI / promote (pull_request) Has been skipped
CI / build (push) Successful in 6m46s
CI / e2e (push) Successful in 10m31s
CI / promote (push) Successful in 33s
2026-10-08 14:06:30 +01:00
Compare
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Nectenda/nectenda!279
No description provided.