diff --git a/internal/cli/oncall.go b/internal/cli/oncall.go index 7b3342f..66bab64 100644 --- a/internal/cli/oncall.go +++ b/internal/cli/oncall.go @@ -39,7 +39,7 @@ func newOncallWhoCmd() *cobra.Command { cmd := &cobra.Command{ Use: "who", Short: "Show who is currently on call", - Long: curatedLong("Show who is currently on call across schedules within a time window, optionally filtered by team or schedule name. Returns person_ids (numeric) only; resolve names/phones by dumping 'fduty member list' and joining client-side (member list has no by-id lookup).", "Schedules", "List"), + Long: curatedLong("Show who is currently on call across schedules within a time window, optionally filtered by team or schedule name. The table output already resolves person_ids to display names; when you have raw person_ids elsewhere, batch-resolve them with 'fduty person infos ...' (NOT by paginating 'fduty member list' — person_id and member_id are different id namespaces).", "Schedules", "List"), RunE: func(cmd *cobra.Command, args []string) error { return runCommand(cmd, args, func(ctx *RunContext) error { startTime, err := timeutil.Parse(since) diff --git a/skills/flashduty/reference/member.md b/skills/flashduty/reference/member.md index bf1b3c5..a13347a 100644 --- a/skills/flashduty/reference/member.md +++ b/skills/flashduty/reference/member.md @@ -4,7 +4,7 @@ Prereq: `SKILL.md` read. `invite` sends invitation emails immediately (up to 20 ## Route here when -"成员 / 邀请 / 用户 / 角色 / member / invite / user profile / role assignment / org roster" → **member**. Sibling domains: `team` (team membership lists, not org-level members); `role` (role definitions — get role IDs here first). Key IDs: **`member_id` (int)** from `member list`; **`role_id` (int)** from `fduty role list`. +"成员 / 邀请 / 用户 / 角色 / member / invite / user profile / role assignment / org roster" → **member**. Sibling domains: `team` (team membership lists, not org-level members); `role` (role definitions — get role IDs here first); `person` (resolve a `person_id` → name with `fduty person infos …`, e.g. ids returned by `schedule`/`oncall`/`incident`/`alert` output). Key IDs: **`member_id` (int)** from `member list`; **`role_id` (int)** from `fduty role list`. ## Intent → verb @@ -119,6 +119,7 @@ Update member roles ## Gotchas +- **Resolving a `person_id` → name: use `fduty person infos …`, NOT `member list`.** `schedule`/`oncall`/`incident`/`alert` output returns `person_id`s, a **different namespace from `member_id`**. `fduty person infos` (the sibling `person` group) batch-resolves any number of `person_id`s to `person_name` in one call (rows under `.items[]`). Matching `member list` rows on `member_id == ` is wrong, and paginating the full roster to find them silently misses people on later pages. - **`invite` members array is body-only — use `--data`.** Individual members cannot be passed as flat flags; the `members` array (with nested `role_ids`, `email`, `phone`, etc.) lives only in the JSON body. Up to 20 members per call. - **`info-reset ` is POSITIONAL.** Pass the member ID as the first bare argument, not `--member-id`: `fduty member info-reset --member-name "New Name"`. The `--member-id` flag exists but the positional form is required per the `use` field. - **`role-grant / role-revoke / role-update` — role IDs are POSITIONAL.** All three verbs take role IDs as positional args: `fduty member role-grant [...] --member-id `. The `--role-ids` flag also exists but the positional form is authoritative. diff --git a/skills/flashduty/reference/schedule.md b/skills/flashduty/reference/schedule.md index 2a4faa5..c7bea34 100644 --- a/skills/flashduty/reference/schedule.md +++ b/skills/flashduty/reference/schedule.md @@ -37,15 +37,16 @@ fduty schedule info --start now --end +1h --output-format toon fduty oncall who --output-format toon ``` -Both return `person_ids` (integers), not names. Resolve names by joining `member list` client-side — its rows live under `.items[]` keyed by `member_id` (+ `member_name`): +Both return `person_ids` (integers), not names. Resolve every id in **one batch call** with `fduty person infos` (the sibling `person` group — takes positional ids or `--person-ids`): ```bash -members=$(fduty member list --json) -fduty schedule info --start now --end +1h --json | jq --argjson m "$members" ' - [.. | .person_ids? // empty | .[]] | unique | map(. as $id | ($m.items[]? | select(.member_id==$id) | .member_name))' -# If the join is fiddly, just report person_ids — do NOT loop refining jq. +# person_ids come straight from the schedule/oncall output above +fduty person infos [ …] --output-format toon +# → rows under .items[] with person_id + person_name; join on person_id client-side ``` +**`person_id` ≠ `member_id` — do NOT resolve schedule/oncall people via `member list`.** They are different id namespaces, so matching `member list` rows on `member_id == ` is wrong, and paginating the full roster (often 20+ pages) silently drops people who land on later pages — a real prod miss. Always feed the `person_id`s to `fduty person infos`. If a lookup genuinely fails, report the bare `person_id` rather than guessing. + ## Hot flow — inspect a schedule's upcoming shifts ```bash