@lark-people/cli 0.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/CHANGELOG.md +324 -0
  2. package/LICENSE +21 -0
  3. package/README.md +232 -0
  4. package/README.zh.md +232 -0
  5. package/bin/people-cli_darwin_amd64 +0 -0
  6. package/bin/people-cli_darwin_arm64 +0 -0
  7. package/bin/people-cli_linux_amd64 +0 -0
  8. package/bin/people-cli_linux_arm64 +0 -0
  9. package/bin/people-cli_windows_amd64.exe +0 -0
  10. package/bin/people-cli_windows_arm64.exe +0 -0
  11. package/package.json +41 -0
  12. package/scripts/install-wizard.js +700 -0
  13. package/scripts/install.js +56 -0
  14. package/scripts/run.js +36 -0
  15. package/skills/people-attendance/SKILL.md +667 -0
  16. package/skills/people-attendance/references/people-attendance-submission.md +426 -0
  17. package/skills/people-attendance/scripts/resolve_date.py +894 -0
  18. package/skills/people-corehr/references/people-corehr-pre-hire-search.md +0 -0
  19. package/skills/people-corehr-employee/SKILL.md +111 -0
  20. package/skills/people-corehr-employee/references/people-corehr-employee-basic-info-query.md +97 -0
  21. package/skills/people-corehr-employee/references/people-corehr-employee-fields-list.md +87 -0
  22. package/skills/people-corehr-employee/references/people-corehr-employee-filter.md +403 -0
  23. package/skills/people-corehr-employee/references/people-corehr-employee-search.md +73 -0
  24. package/skills/people-corehr-job-change/SKILL.md +212 -0
  25. package/skills/people-corehr-job-change/references/people-job-change-business-rules.md +113 -0
  26. package/skills/people-corehr-job-change/references/people-job-change-lookup-filters.md +82 -0
  27. package/skills/people-corehr-job-change/references/people-job-change-output-and-empty.md +207 -0
  28. package/skills/people-corehr-job-change/references/people-job-change-search-advanced.md +226 -0
  29. package/skills/people-corehr-job-change/references/people-job-change-search-fields.md +119 -0
  30. package/skills/people-corehr-job-change/references/people-job-change-search-option.md +72 -0
  31. package/skills/people-corehr-job-change/references/people-job-change-search.md +215 -0
  32. package/skills/people-corehr-offboarding/SKILL.md +188 -0
  33. package/skills/people-corehr-offboarding/references/people-corehr-offboarding-business-knowledge.md +27 -0
  34. package/skills/people-corehr-offboarding/references/people-corehr-offboarding-search-option.md +187 -0
  35. package/skills/people-corehr-offboarding/references/people-corehr-offboarding-search.md +54 -0
  36. package/skills/people-corehr-organization/SKILL.md +42 -0
  37. package/skills/people-corehr-organization/references/aggregate.md +11 -0
  38. package/skills/people-corehr-organization/references/detail.md +39 -0
  39. package/skills/people-corehr-organization/references/field-values.md +44 -0
  40. package/skills/people-corehr-organization/references/hierarchy.md +61 -0
  41. package/skills/people-corehr-organization/references/lookup.md +41 -0
  42. package/skills/people-corehr-organization/references/metadata.md +40 -0
  43. package/skills/people-corehr-organization/references/tree.md +45 -0
  44. package/skills/people-corehr-prehire/SKILL.md +160 -0
  45. package/skills/people-corehr-prehire/references/command-resolution.md +48 -0
  46. package/skills/people-corehr-prehire/references/filter-fields.md +151 -0
  47. package/skills/people-corehr-prehire/references/return-fields.md +153 -0
  48. package/skills/people-corehr-prehire/references/templates.md +202 -0
  49. package/skills/people-corehr-prehire/references/troubleshooting.md +93 -0
  50. package/skills/people-corehr-query-id-by-name/SKILL.md +154 -0
  51. package/skills/people-corehr-renewal/SKILL.md +186 -0
  52. package/skills/people-corehr-renewal/references/people-corehr-renewal-fields-query.md +62 -0
  53. package/skills/people-corehr-renewal/references/people-corehr-renewal-routing.md +54 -0
  54. package/skills/people-corehr-renewal/references/people-corehr-renewal-search.md +137 -0
  55. package/skills/people-corehr-renewal/references/people-corehr-renewal.md +39 -0
  56. package/skills/people-corehr-workforce-plan/SKILL.md +52 -0
  57. package/skills/people-corehr-workforce-plan/references/people-corehr-workforce-plan-detail-list.md +238 -0
  58. package/skills/people-corehr-workforce-plan/references/people-corehr-workforce-plan-detail-summary.md +221 -0
  59. package/skills/people-corehr-workforce-plan/references/people-corehr-workforce-plan.md +79 -0
  60. package/skills/people-hire/SKILL.md +255 -0
  61. package/skills/people-hire/references/people-hire-application.md +334 -0
  62. package/skills/people-hire/references/people-hire-evaluation-task-list.md +233 -0
  63. package/skills/people-hire/references/people-hire-evaluation.md +127 -0
  64. package/skills/people-hire/references/people-hire-interview-record.md +109 -0
  65. package/skills/people-hire/references/people-hire-interview-task-list.md +250 -0
  66. package/skills/people-hire/references/people-hire-interview.md +146 -0
  67. package/skills/people-hire/references/people-hire-job-process.md +93 -0
  68. package/skills/people-hire/references/people-hire-job-requirement.md +227 -0
  69. package/skills/people-hire/references/people-hire-job.md +277 -0
  70. package/skills/people-hire/references/people-hire-minutes.md +91 -0
  71. package/skills/people-hire/references/people-hire-talent.md +105 -0
  72. package/skills/people-hire/references/people-hire-test.md +197 -0
  73. package/skills/people-overtime/SKILL.md +992 -0
  74. package/skills/people-overtime/references/people-attendance-overtime-apply.md +491 -0
  75. package/skills/people-overtime/references/people-attendance-overtime.md +51 -0
  76. package/skills/people-overtime/references/people-attendance-submission.md +203 -0
  77. package/skills/people-overtime/scripts/resolve_date.py +894 -0
  78. package/skills/people-shared/SKILL.md +94 -0
@@ -0,0 +1,212 @@
1
+ ---
2
+ name: people-corehr-job-change
3
+ version: 2.0.25
4
+ description: "飞书人事 - 异动管理:搜索员工异动记录、按员工/部门/状态/时间/异动类型/异动原因筛选异动、获取异动筛选项与字段信息。触发词:异动、调动、转岗、晋升、异动查询、异动记录、人员异动、job change。适用边界:仅处理异动(job_change)查询,不覆盖离职、编制、员工信息、审批操作、数据导出等其他模块。"
5
+ metadata:
6
+ requires:
7
+ bins: ["people-cli"]
8
+ cliHelp: "people-cli corehr job_change --help"
9
+ ---
10
+
11
+ # corehr job_change
12
+
13
+ ## Scope
14
+
15
+ 只处理异动记录查询:按员工、部门、状态、时间、异动类型、异动原因检索;获取当前运行时的筛选项、枚举与返回字段。显式列举类型/原因可用兼容接口,普通查询不前置。
16
+
17
+ 不处理审批、修改、删除、导出文件、离职、编制、纯员工信息查询或跨模块复杂统计。命中边界时按 [output-and-empty.md](references/people-job-change-output-and-empty.md) 拒答。
18
+
19
+ ## Required Flow
20
+
21
+ 1. **意图判定**:确认是 job_change 查询;否则拒答,不调用 CLI。
22
+ 2. **短路径执行**:A) 最多 1 次 `search-option --as user --jq ...`;B) 名称型 lookup 用 `--lookup-filters`;C) 1 次真实 `+job-change-search`;D) 仅在用户明确翻页/全部,或属于统计/汇总/分组等全量才准确场景时按分页策略有界翻页;E) 输出最终答案。禁止用 shell 管道/临时文件/脚本处理校准或搜索结果。
23
+ 3. **有界校准**:`search-option` 必须带内置 `--jq`,在一个 JSON 对象里同时返回本题需要的筛选字段和返回列;不要 dump 全量。
24
+ 4. **最终搜索**:条件可执行后必须真实执行 `+job-change-search ... --format json --as user`。一旦返回合法 `data.total/items`,立即回答;缺少非关键字段写“未返回”。`search-option` / `help` / `schema` 都不是终点。
25
+ 5. **完成态校验并回答**:答案必须来自最后一次成功搜索(或不可完成原因)。非空给数量+摘要,空给空结果说明+条件,解析/工具失败给失败类别+已执行条件;禁止空输出、过程句结尾或无搜索结果时编造人数/名单。
26
+
27
+ ## Route Templates
28
+
29
+ | 意图 | 最短路径 |
30
+ | --- | --- |
31
+ | 时间范围/某月生效 | `search-option` 校准状态与 `effective_date`;用户语义为"已生效/生效的异动"才追加严格已生效状态集合 |
32
+ | 某部门的异动/有哪些异动 | 未指明员工部门/异动前/异动后时默认 `target_department`,输出说明按异动后部门查询 |
33
+ | 调入/目标部门 | `target_department` + `--lookup-filters` + `details_of_job_status_change=department` |
34
+ | 多个目标部门/地点分组 | 同一 lookup 字段的 `values` 放多个名称表达 OR;搜索后按返回目标字段分组 |
35
+ | 调出/来源部门 | `original_department` + `--lookup-filters` + `details_of_job_status_change=department` |
36
+ | 调入/调出 + 另一字段发生变化 | 部门分支(含目标/来源部门 lookup + `details=department`)与另一变更内容分支(同时间/状态/lookup + 对应 details)分别搜索后按 `job_change_id` 取交集 |
37
+ | 当前所属/员工部门 | `--lookup-filters field_name="employment.department"` |
38
+ | 新/旧工作地点 | `target_work_location` / `original_work_location` 走 `--lookup-filters` |
39
+ | 都去了哪些/汇总/统计/数量/分组 | 必要返回字段 + 最多按 `page_token` 聚合 200 条;仍有更多说明部分统计 |
40
+ | 异动异常没处理完/异常类型 | 校准异常处理状态=未处理,并同时校准/返回异常类型字段;缺异常类型字段时说明未返回,禁止用异动状态或异动变更内容替代 |
41
+ | 自定义字段有值/不为空 | 先校准该字段;能服务端筛选才搜索;不能筛选时不可完成,禁止省略该条件后宽搜 |
42
+ | 职位描述/岗位描述变化 | 按职位描述语义校准字段或变更内容;禁止改成职务/职位变更 |
43
+ | 多变更同时发生 | 见下方 Critical Discipline §1(必须分别搜索后取交集)|
44
+ | 多状态全景 | 见 §2(每个状态各发一次搜索后合并)|
45
+
46
+ ## Hard Rules
47
+
48
+ - 禁止 MCP、飞书文档接口或非 `people-cli corehr` 路径绕行;禁止读取本 skill 目录外的项目指引、源码、配置或二进制版本来调试业务查询。
49
+ - 禁止把 `people-cli` 当作 Python 模块或 skill 目录内文件调用;不得使用 `python3 -m people_cli`、`./people-cli`、`find ... people-cli`、`ls`/`grep` 探索 skill 目录来定位 CLI。CLI 不可用时只报告 PATH/命令注册问题。
50
+ - 跨平台命令规则:所有代码块换行仅用于阅读;真实执行时必须作为一条裸 `people-cli` 命令传递参数,不使用 Bash `\`、PowerShell反引号、CMD `^` 续行,也不套 `sh -c` / `powershell -Command`。JSON 与 jq 表达式各自作为单个参数传入,避免由 shell 二次解析。
51
+ - 用户要求导出/下载/生成 Excel/CSV/文件时,即使命中"我有导出权限",也直接回复"当前接口不支持数据导出功能",不调用 `search-option`、`+job-change-search`、`schema` 或 `help`。
52
+ - 普通查询唯一允许的校准形态是 `people-cli corehr job_change search-option --as user --jq '<single jq object>'`,且最多 1 次;把筛选字段语义候选、返回字段白名单、枚举关键词过滤一次写进 `--jq`。禁止输出完整 enums/tree,禁止无 `--jq` 的 `search-option`,禁止 `--format json` 后再管道解析,禁止为补字段第二次调用 `search-option` / `--help` / `schema`。字段缺失时按不可返回/不可解析处理。
53
+ - search-option 校准必须遵守"业务语义 → 运行时字段 → 运行时枚举"协议:先把用户条件转成业务语义(如异常处理状态、异动状态、人员类型、职级、地点、合同、试用期),再用 `names[].value`、字段名和英文语义关键词找候选字段;不得先假设单个 API 字段名后精确过滤。枚举值必须在已选字段的 `enums` 内按用户语义/label 校准,禁止把用户输入或英文猜测值直接传入。
54
+ - 校准 `--jq` 应窄化到本题语义,避免把大枚举字段混在一起造成输出过大:查异常只匹配"异常/exception/abnormal",查合同只匹配"合同/contract",查人员类型只匹配"人员类型/employee type/workforce",查职级只匹配"职级/level",查地点只匹配"地点/location"。除非本题确实同时需要,禁止把 `details_of_job_status_change`、状态、异动类型等大字段无差别放入同一次校准结果。
55
+ - 字段/枚举校准为空、候选多且无法唯一判断、或运行时拒绝字段时必须停止并按不可完成输出;禁止猜字段名/枚举值,禁止删除失败条件后宽搜,禁止用相邻字段兜底(如用异动状态代替异常处理状态、用异动变更内容代替异常类型/异常处理状态),禁止全量搜索后本地过滤来模拟服务端筛选。
56
+ - 禁止命令形态:`head`、`tail`、`wc`、`grep`、临时 `/tmp/*.json`、临时 Python/脚本解析、`people-cli schema`、`+job-change-search --help`、`search-option --format json`。`+job-change-search --format json` 的返回也必须由模型直接读取 `data.items/total/has_more`,禁止再 pipe 给脚本提取字段。若已经误用这些探索命令,下一步只能输出基于已返回 JSON 的答案或不可完成原因,不能继续探索。
57
+ - `filter_str` 中除日期区间外所有字段值必须是数组。
58
+ - 默认 `--page-size 10`;单次用户请求最多返回/聚合 200 条。不要通过增大 page size、重复首屏、`grep/head` 或脚本截断模拟翻页。
59
+ - 最终 search 必须加 `--format json`;只读 `data.items[]` / `data.has_more` / `data.page_token` / `data.total`。"总数/共有/一共"必须来自 `data.total`;本页数量写"本页返回 N 条",分页聚合写"已聚合 N 条"。`data.total` 缺失时写"接口未返回总数"。只要能可靠读取到非空 `items`,最终答案不能只输出总数;默认展示当前页全部记录明细(默认 `page_size=10`),翻页/聚合场景展示本次已聚合的全部记录,除非工具输出截断导致无法可靠读取。
60
+ - 最终 search 默认不要加 `--jq`。若为避免大输出必须加 `--jq`,只能做元信息包装并原样保留 `items:.data.items`(可另带 `total/has_more/page_token/page_count/reject_export`),禁止只返回 total/has_more、只返回 groups、或把 `items` 投影成少数字段。若已因 `--jq` 裁剪导致 `total>0` 但没有原始 `items`,该搜索结果不可作为最终答案,必须用相同筛选条件重新执行一次保留原始 `items` 的最终 search;禁止基于 meta-only 结果回答“只有总数”。
61
+ - 异动详情基础展示字段强制契约:凡最终答案展示任意异动记录明细,必须逐条展示姓名、工号、头像、生效日期、异动类型、异动状态。用户额外要求的业务字段(如原/新人员类型、原/新部门、原因、是否调薪)只能追加,不能替代这 6 个基础字段;字段在原始 `items` 中存在就必须展示,确实缺失或无权限时写"未返回/无权限",禁止省略列、禁止用 ID 替代工号。纯统计且不列记录明细时不适用;只要列代表记录/样例/当前页明细就适用。
62
+ - 用户未指定返回字段时默认展示:姓名、工号、头像、生效日期、异动类型、状态。命令层优先不传 `--select-fields`;若用户点名额外字段,`--select-fields` 只负责追加业务字段,不能让最终答案丢失基础展示字段。普通查询不传 `--user-id-type open_id`,保持默认 `people_corehr_id`。
63
+ - 工号只能来自 `employment.employee_number` 或运行时明确返回的 `employee_number` 字段。禁止用 `employment_id`、`employment.wk_id`、`person_id`、`open_id`、`user_id`、任职 ID 等任何 ID 字段替代工号。如果工号字段缺失、为空或因权限未返回,则不展示工号列,或写"未返回/无权限"。
64
+ - 名称型 lookup 一律用 `--lookup-filters`,不要写成 `--dynamic-filters`。标准 job_change lookup 字段只写 `field_name` 和 `values` 即可,由 shortcut 自动补齐 `target_object_api_name`;非标准/自定义字段只有在 `search-option` 明确返回目标对象时才显式传 `target_object_api_name`。`select_query` / `select_query_all` / `tree_query_all` 类型同样按引用字段处理。
65
+ - shortcut 内置 lookup 目标对象以运行时代码为准:人员类型字段 `original_workforce_type` / `target_workforce_type` 解析目标是 `employee_type`,不是 `workforce_type`;部门、工作地点、职务、序列、职级等标准字段也会自动补齐目标对象。
66
+ - 职级/序列/职务等对象字段给的是展示名(如 `L6`、`L2`)时必须走 `--lookup-filters`,不能写进 `--dynamic-filters`。用户说"职级从 X 变更到 Y"固定表达为 `original_job_level` + `target_job_level` 两个 lookup 条件,并返回 `original_job_level` / `target_job_level`;标准字段 target 由 shortcut 自动补齐。
67
+ - `details_of_job_status_change` 是异动查询的必检门禁字段:每次最终 search 前必须判断本题是否在筛"某字段发生变更"。若用户语义包含"变更/变化/调整/异动到/调到/调入/调出/转入/转出/转为/变为/从 X 到 Y/去其他/涉及/同步变/同时发生"且该语义对应异动前后字段,就必须追加对应变更内容;若用户只是要求"工作地点是否变更/职级是否变更"作为输出标注,不把该变更内容加入筛选,只返回原/新字段并打标。
68
+ - 字段统计/展示目标值不是字段发生变更:如"新职级分类统计"、"新部门是 X 的记录"、"新工作地点分布"只筛选或统计对应目标字段;只有明确说"发生变更/变化/调整/涉及 X 变更"时才追加对应 `details_of_job_status_change`。
69
+ - 常用变更内容映射:部门=`department`,工作地点=`work_location`,序列=`job_family`,职级=`job_level`,职务=`job`,直属上级=`direct_manager`,虚线上级=`dotted_manager`,人员类型=`employee_type`,合同=`contract`,司龄起算日期=`seniority_date`;试用期用运行时"试用期"父节点/合法值校准。职位描述/岗位描述不是职务/职位,必须按"描述/description"语义另行校准,禁止退化成职务变更。运行时不可确认或用户使用自定义字段时,只通过 `search-option --jq` 校准合法值;禁止写死组织名称、字段展示名或候选 ID。
70
+ - 部门语义有三类:员工当前部门 `employment.department`、异动前部门 `original_department`、异动后部门 `target_department`。用户未明确是哪类部门时默认按异动后部门 `target_department` 查询,并在答案口径中提示"本次按异动后部门查询;如需员工当前部门或异动前部门口径需另行说明"。调入/转入/目标用 `target_department`;调出/转出/原/来源用 `original_department`;"当前所属/员工.部门"用 `employment.department`。部门 target 由 shortcut 自动补齐;不用 `--employment-department-ids`。
71
+ - 部门方向性动作必须体现部门真的发生变化:用户说"调入/调出/转入/转出/调入到/从某部门调出/去了哪些部门/调到哪些部门"时,除部门 lookup 外必须追加 `--dynamic-filters '[{"field_name":"details_of_job_status_change","values":["department"]}]'`。不要只按 `original_department` 或 `target_department` 宽搜。
72
+ - 部门口径决策表:调出 → `original_department` 筛选 + `details_of_job_status_change=department`,并输出 `target_department` 分组;调入/异动到 → `target_department` + `details_of_job_status_change=department`;当前所属 → `employment.department`;是否发生部门变更 → `details_of_job_status_change=department`;用户未明确部门口径 → 默认 `target_department` 并在答案中提示口径。
73
+ - "调出的人/调入的人/已经调出/已经调入/去了哪些部门"表示已发生的人员流动,默认追加严格已生效状态(运行时已生效值,如 `Transformed`);若用户明确要求全部状态或单据全景,才不默认加已生效。
74
+ - 工作地点名称走 `--lookup-filters`:`target_work_location` / `original_work_location` 的 target 由 shortcut 自动补齐为 `location`。不要写成 `work_location`,也不要在 lookup 失败后退回 `--dynamic-filters target_work_location=<地点名>`;地点名是引用对象展示名,不是动态枚举值。
75
+ - 员工姓名用 `--lookup-filters` 的 `field_name="employment"`。
76
+ - "我管理范围/我可见范围/我支持范围内/我管理的部门中/我的团队/团队里/团队内/下属范围"默认由 `--as user` 的当前用户权限承载;不要把这些短语当部门名做 lookup,不要反查或传当前用户所在部门,不要查询组织/员工接口探索管理部门、`data_scope` 或额外身份参数。若无明确部门名,不加部门 lookup。
77
+ - 生效日期/生效时间只代表 `effective_date`;"已生效/生效的异动/某月生效的所有异动"代表 `effective_date` + 严格已生效状态集合。异动状态运行时值固定口径:审批中=`Approving`,审批通过=`Approved`,无需审批=`NoNeedApproval`,已生效=`Transformed`,已撤销=`Cancelled`,已拒绝=`Rejected`。异动状态业务口径:审批中、审批通过、无需审批、已生效、已撤销、已拒绝;**已生效只包含已生效**。`Approved` / 审批通过 / 已批准是待生效;"无需审批/免审批/直接异动"属于未生效口径,禁止纳入已生效。
78
+ - 所有相对日期(今天、本周、本月、今年、本季度、近半年、近一个月、近期等)最终答案必须展示绝对日期范围(如 `2026-05-13 至 2026-06-12`);异动存在未来生效,"今年/本年"按自然年 `2026-01-01` 至 `2026-12-31`,不要截断到当前日;本季度按当前日期所在自然季度的完整起止日期,上季度按当前自然季度的前一个自然季度完整起止日期,禁止把上季度算成本季度至昨日;季度类时间范围都按完整自然季度,不截断到当前日。近半年/近一个月不得隐式扩大到更长区间;无法确定基准日时,必须在答案中写明本次采用的"当前日期"。
79
+ - 状态、异常状态、异常类型、异动类型、异动原因、enum/tree/select 必须用 `search-option` 校准(如"已取消"映射到运行时"已撤销")。校准 `system_filters` 字段时,字段名统一按 `(.field // .field_api_name // .filter_api_name)` 读取和匹配,禁止只用 `.field_api_name`;例如异动状态 `status` 在运行时可能只出现在 `.field`,若校准为空不得猜测枚举值。异常类型运行时可能展示为"异常类型"/`exception_type`,底层 api_name 可能是 `transform_exception_type`,枚举业务项包括异动记录异常、合同记录异常、任职记录异常、组织架构调整异常、异动变更同步异常;筛选和展示仍以本次 `search-option` 返回的合法字段和值为准。查询"异动异常未处理/没处理完/待处理异常"时,业务语义是"异常处理状态=未处理",必须用异常处理状态字段的"未处理"枚举;禁止映射到异动状态或审批状态。
80
+ - 用户未明确说"已生效/已经生效"时禁止默认追加已生效状态集合(`Transformed` 等);所有"状态全景/各状态分别多少/审批中+已生效+已撤销+已拒绝同时统计"必须按状态分别发起搜索后分别记录 `data.total`,禁止用一次无 status 搜索 + 客户端分桶代替。
81
+ - 常见业务口径:异常没处理完=异常处理状态未处理/待处理;用户问"异常类型"时必须返回异常类型字段,找不到或未返回只能写"异常类型未返回/无法确认",禁止用 `details_of_job_status_change`、异动状态、审批状态替代。转正式成功=已生效 + 新人员类型正式(`target_workforce_type`) + 人员类型变更,禁止只查 `details=employee_type` 后本地找正式,禁止加入转正日期/试用期/实习生转正式条件;实习生转正式类型=异动类型而非人员类型;"异动后有新试用期/有新试用期的同学"=生效日期在用户时间范围内(今年用 `2026-01-01` 至 `2026-12-31`)+ 异动变更内容含试用期 + 返回"是否有试用期"字段,最终只把该字段为 true 的记录算作符合条件,禁止按实习生转正式/人员类型推断;司龄起算日期变了吗=今年已生效 + 变更内容含司龄起算日期 + 异动原因;近一个月/近期=以当前日期前一天为结束日向前一个自然月;近一个月按类型统计=已生效 + 日期范围 + 按 `transfer_type_unique_identifier` 末级名分组;未生效=审批通过+无需审批,直接异动=无需审批,需分别取 `data.total`。
82
+ - 用户说"<名称>类型的异动"、"<名称>异动类型的单据"或"某类型单据"时,这是异动类型条件,字段固定走运行时异动类型/`transform_type` 候选;禁止改查同名/近名自定义标记字段、员工字段或"命中=true"字段。若还说"部门也同步变/部门也变了",在同一次搜索追加 `details_of_job_status_change=department`,不要拆成类型分支与部门分支取交集。数量默认按异动单据 `data.total` 回答;只有明确要求"去重人数"才按人员去重。
83
+ - 用户说"调薪/是否调薪/今年调薪的人员"时,优先校准并筛选布尔字段"是否调薪"(运行时通常为 `is_adjust_salary`)为 true;不要把"调薪"等同于"调级调薪"异动类型。只有用户明确说"调级调薪类型的异动"才走异动类型条件。
84
+ - "涉及某类变更内容"先从 `system_filters` 找"异动变更内容/Details of job status change"枚举值,写入 `details_of_job_status_change` 的 `--dynamic-filters`;命中该筛选即代表该变更发生,不再拉明细本地对比证明。"变更/变化/调整"是后缀;用户说"直属上级变更"则取 label "直属上级"/value `direct_manager`,不能写"直属上级变更"。职级、序列、工作地点、人员类型、合同、司龄等都先过 details 门禁判断。**多变更同时发生**遵守 Critical Discipline §1。
85
+ - 异动有"变更前/变更后"业务语义。用户问"异动到/调到/变更到/转为/变为 X 的同学"时,除非明确查原值,否则筛选目标侧字段(如新工作地点/目标部门/新职级/新人员类型)并同时追加对应 `details_of_job_status_change`,确保该字段确实发生变更;例如"异动到北京"=新工作地点为北京 AND 异动变更内容包含工作地点。
86
+ - 用户问"已经异动到/已调到/成功调到 <地点>"时,地点查询固定表达为 `--lookup-filters '[{"field_name":"target_work_location","values":["<地点>"]}]'` + `--dynamic-filters '[{"field_name":"details_of_job_status_change","values":["work_location"]},{"field_name":"status","values":["Transformed"]}]'`,并返回 `original_work_location` / `target_work_location`。不要使用 `target_object_api_name="work_location"`,不要把地点名放进 `--dynamic-filters`。
87
+ - 用户问"职级从 X 变更到 Y / 从 X 到 Y 的职级异动"时,不需要先宽搜或本地比较,直接用 `--lookup-filters '[{"field_name":"original_job_level","values":["X"]},{"field_name":"target_job_level","values":["Y"]}]'`;不要把 `X/Y` 作为 `dynamic-filters` values。示例:"职级从 L6 变更到 L2" → `original_job_level=L6` AND `target_job_level=L2`。
88
+ - 用户问"去其他部门/调到其他部门/部门有没有变化"且未给目标部门名称时,用 `details_of_job_status_change=department` 表示部门变更,并返回原/新部门;不要 lookup "其他部门"。用户问"工作地点有没有变化/是否变更"、"职级是否变更"时只返回原/新工作地点或原/新职级并按稳定标识或返回值标注是否变化,不把 `work_location` / `job_level` 追加为筛选条件,除非用户明确要求"工作地点发生变化的记录"或"职级发生变化的记录"。
89
+ - 多字段变化标注题必须显式请求字段,不能依赖默认返回。用户问"职务、序列、职级、人员类型、工作地点分别有没有变化,并标注异动原因和是否调薪"这类明细时,最终 search 的 `--select-fields` 必须包含基础字段、原/新部门、每个被标注维度的原/新字段,以及原因/调薪字段:`effective_date,status,transform_type,transform_reason,original_department,target_department,original_job,target_job,original_job_family,target_job_family,original_job_level,target_job_level,original_workforce_type,target_workforce_type,original_work_location,target_work_location,is_adjust_salary`。若响应只返回原因标识字段,则答案层读取实际返回的原因字段;缺字段只能写"未返回/无法判断",不能省略用户点名字段。
90
+ - 目标侧变更查询遵守"目标值筛选 + 变更内容 + 状态/时间"组合规则:目标值用 lookup/enum 的运行时合法值;"成功/已生效"只映射严格已生效状态;只问"到/转为 Y"时不要再拉全量本地比较 original/target,只有用户明确"从 X 到 Y"才同时加原字段。
91
+ - 用户说"有值/不为空"时,先校准字段;enum/tree/select 有候选则把全部合法候选放进 `values` 数组;无候选且无非空操作符时停止。自定义字段的"有值"是必需条件,禁止省略该条件后只按部门、状态或变更内容宽搜。
92
+ - 自定义字段不得写死:作筛选先校准 `system_filters`;作返回先校准 `system_columns`;不可返回时按 §5 输出不可完成。
93
+ - 多候选必须澄清;必需条件解析失败时停止并输出不可用结果。禁止删条件后宽搜、自动选第一个、把类型改原因、先拉全量再本地文本匹配。
94
+ - 分页策略:未明确翻页时不翻页,只返回当前页并说明 `total/has_more/page_size`;用户要全部时默认最多 200 条;统计/汇总类同样最多 200 条;任一页失败/缺 `page_token`/JSON 异常 → §5。
95
+ - 最终答案只能是结果摘要、空结果说明或结构化不可完成原因;禁止输出推理过程、执行计划、推荐命令、runner JSON 或"让我/现在/下一步/将要/我将要"等过程文本(与 §2 一致)。
96
+
97
+ ## Command Patterns
98
+
99
+ ```bash
100
+ # 运行时语义校准:唯一允许形态。按本题把 FIELD_SEMANTIC_REGEX / ENUM_SEMANTIC_REGEX / 返回字段白名单收窄;不要 pipe/head/python/tmp。
101
+ people-cli corehr job_change search-option --as user --jq '{filters:[.data.system_filters[]? | select((((.field // .field_api_name // .filter_api_name // "")+" "+([.names[]?.value] | join(" "))) | test("FIELD_SEMANTIC_REGEX"; "i"))) | {field:(.field // .field_api_name // .filter_api_name),type,names,target_object_api_name,enums:([.enums[]? | select((((.label // "")+" "+(.value // "")+" "+(.description // "")) | test("ENUM_SEMANTIC_REGEX"; "i")))] )}],columns:[.data.system_columns[]? | select((.field_api_name // .field) as $f | ["employment.employee_number","effective_date","status","transform_type","transform_reason","original_department","target_department","original_work_location","target_work_location"] | index($f)) | {field:(.field_api_name // .field),type,names}]}'
102
+
103
+ # 通用搜索(按需替换/组合 dynamic-filters / lookup-filters / 日期 / select-fields;标准 lookup 字段可省略 target_object_api_name)
104
+ people-cli corehr +job-change-search \
105
+ --page-size 10 --format json \
106
+ --effective-date-start '<DATE_START>' --effective-date-end '<DATE_END>' \
107
+ --dynamic-filters '[{"field_name":"<FIELD_API_NAME>","values":["<VAL>"]}]' \
108
+ --lookup-filters '[{"field_name":"<FIELD>","values":["<NAME>"]}]' \
109
+ --as user
110
+ ```
111
+
112
+ 常用 `field_name → target_object_api_name` 由 shortcut 自动补齐;标准字段直接写 `field_name` + `values`。非标准字段对照 [lookup-filters.md](references/people-job-change-lookup-filters.md) 或运行时 `search-option`。
113
+
114
+ 返回变更前后字段示例:`--select-fields '["effective_date","status","transform_type","original_job_family","target_job_family","original_work_location","target_work_location"]'`;多字段变化标注题按用户点名字段补齐全部 original/target 对;展示名/自定义返回字段用 `--select-field-names '["<展示名>"]'`。
115
+
116
+ ## Critical Discipline
117
+
118
+ 下列规则优先级最高,与 Hard Rules 冲突时以本节为准。
119
+
120
+ ### -1. 禁止向用户暴露 API 字段名
121
+
122
+ 最终答案面向业务用户,只能输出业务展示名和业务口径,禁止输出具体 API 字段名、JSON path、filter field、select field、enum value、lookup field、内部 ID 或命令参数片段(如 `target_department`、`details_of_job_status_change`、`Transformed`、`employment.employee_number`、`--dynamic-filters`)。字段名只允许出现在内部命令构造中;对用户说明时改写为"异动后部门"、"异动变更内容"、"已生效"、"工号"等业务名称。若需要说明缺字段,写"异常类型未返回/工号未返回",不要写缺哪个 API 字段。
123
+
124
+ ### -0.5. 相对季度必须按自然季度计算
125
+
126
+ 遇到"本季度/上季度/上一季度/季度"先用当前日期确定自然季度,再构造完整起止日期。Q1=`01-01..03-31`,Q2=`04-01..06-30`,Q3=`07-01..09-30`,Q4=`10-01..12-31`;"上季度"永远是当前自然季度的前一个完整自然季度。禁止把上季度算成滚动近三个月、近 90 天、上月到本月、或截至当前日的区间。若当前日期在 Q2,则上季度必须是当年 Q1 的 `01-01..03-31`;答案和命令中的季度标签与日期范围必须一致,不能写"Q1"却传 `03-01..05-31`。
127
+
128
+ ### 0. 导出/文件请求直接拒答
129
+
130
+ 只要用户要求"导出/下载/生成 Excel/CSV/文件/明细表",即使同时给出部门、时间、状态、变更字段或声明"有导出权限",都不执行任何 CLI。直接答:"无法执行:当前接口不支持数据导出功能。people-cli可以查询异动记录并以JSON格式返回结果,但无法生成文件。"
131
+
132
+ ### 1. 多变更内容 AND(同时/都/并且/又)
133
+
134
+ `details_of_job_status_change` 多值是 OR,**不能**单次传多值表达 AND。用户要求多个变更内容"同时/都/并且/既...又..."发生时:
135
+
136
+ 1. 用 `search-option` 校准每个变更内容的运行时合法 value(如 `department` / `job_level` / `direct_manager` / `work_location`)。
137
+ 2. 只有多个条件都属于 `details_of_job_status_change` 变更内容时才分支;普通字段/自定义字段取值 + 一个变更内容发生,直接放在同一次 `--dynamic-filters` 数组里表达 AND,不要拆两支。需要分支时按语义组建分支:普通单项变更每组 1 个 value;合同变更组固定用父节点 `contract`,不要展开合同子项;试用期等集合型变更按运行时父节点优先。保持其它筛选条件完全一致,对每个语义组发起一次 `+job-change-search` 后按组间 `job_change_id` 取 AND 交集,禁止把组内每个子项都拆成独立分支,禁止为了提取 ID 重跑同一分支。
138
+ 3. 保守交集优先:用户未明确要求完整列表/继续翻页时,默认只用每个分支当前页 `items` 求交集,不主动翻页,避免大输出截断后编造。只有用户明确要求全部/继续,才按 `page_token` 有界翻页,最多 200 条。
139
+ 4. 只读每个分支原始 JSON 响应里的 `data.items[].job_change_id`(缺失用 `wk_id` 兜底),在回答逻辑中按 `job_change_id` 取**交集**。禁止对最终搜索结果使用管道、`python3`、`grep`、`head`、`wc`、临时文件或静默重跑来提取 ID;如果当前上下文无法可靠读取 JSON,就按不可完成说明输出。
140
+ 5. 答案的"同时变更"数量写"当前页交集命中 N 条 / 已聚合交集 N 条";**禁止**把任一分支 `data.total`、本页数量、单次多值 OR 的 `data.total` 当成"同时发生"的总数。若当前页交集为空但任一分支 `has_more=true`,禁止回答"没有符合条件";只能写"当前已返回记录内未发现交集,但仍有更多记录,不能确认全量为空",并给出各分支 `data.total`、本页数量和 `has_more`。
141
+ 6. 分支搜索后必须立即收口成最终答案:输出交集命中数、名单/明细和分支完整性口径;禁止以"发起两个分支搜索"、"正在聚合"、"下一步取交集"等过程文本结尾,禁止再用任何 shell 命令加工已返回的 JSON。
142
+ 7. 任一分支 `has_more=true` 且已聚合到 200 条时,交集只能标为前 200 条内的部分口径,并询问是否继续。
143
+
144
+ 骨架:
145
+
146
+ ```bash
147
+ # 分支 A:部门变更
148
+ people-cli corehr +job-change-search --page-size 10 --format json \
149
+ --effective-date-start '<S>' --effective-date-end '<E>' \
150
+ --dynamic-filters '[{"field_name":"details_of_job_status_change","values":["department"]}]' --as user
151
+ # 分支 B:职级变更(其它条件完全相同)
152
+ people-cli corehr +job-change-search --page-size 10 --format json \
153
+ --effective-date-start '<S>' --effective-date-end '<E>' \
154
+ --dynamic-filters '[{"field_name":"details_of_job_status_change","values":["job_level"]}]' --as user
155
+ # 回答逻辑:直接读取两个响应的 data.items[].job_change_id,取 setA ∩ setB;不要再运行 shell 提取 ID。
156
+ ```
157
+
158
+ "跨城市/跨地区"等细粒度变更:先按 `details_of_job_status_change=work_location` 取候选集,再用稳定标识比较 `original_work_location.city` 与 `target_work_location.city`,未变更或同城市的剔除并在口径说明。
159
+
160
+ ### 2. 复杂聚合/全景题必须输出最终结论
161
+
162
+ 多状态全景、按某维度分组、跨字段聚合题,**禁止**以"现在让我..."、"接下来将..."、"搜索成功,将聚合..."、"我会并行发起..."等过程文本结尾。最终答案必须同时包含:
163
+
164
+ - **最终结论**:直接给出用户问的数量、名单或分组结果。
165
+ - **聚合表**:按用户要的维度(状态/异动类型/目标部门等)成表,列每组数量与代表记录;多维度并列各一张表。
166
+ - **数据口径**:列已执行查询条件(时间、部门字段、状态集合、变更字段、是否含自定义字段)。
167
+ - **完整性说明**:写 `data.total`、本页/已聚合数量、`has_more`;任一分支聚合到 200 条仍 `has_more=true` 时,标"前 200 条的部分统计 / 部分口径"并询问是否继续;不得把首屏当全量。
168
+
169
+ 多目标 lookup 分组题(如多个目标部门/地点)用同一个 `--lookup-filters.values` 表达 OR;搜索后按返回的目标字段分组,不能停在临时文件、`wc` 或"准备聚合"。用户要求"标注是否变更"时,基于原/新字段或 `details_of_job_status_change` 给每条记录打标,不把该变更项追加为筛选条件;字段缺失写未返回/无法判断,不能继续查 schema/help。
170
+
171
+ 多状态全景(同时统计已生效/审批中/已撤销/已拒绝)必须**对每个状态各发一次** `+job-change-search`,分别记录 `data.total`,再合并出表;不能用一次无 status 搜索 + 客户端分桶代替。
172
+
173
+ ### 3. Lookup 信任:禁止 lookup 命中后名称二次过滤
174
+
175
+ `--lookup-filters` 命中即可信,由 `+job-change-search` 内部解析为 ID 后写入 `filter_str`,结果集已经是该部门/地点对象(含同名下级节点)的全部命中。命中后**禁止**:
176
+
177
+ - 对 `original_department.name` / `target_department.name` / `employment.department.name` / `*_work_location.name` 做等值或字符串包含的二次过滤。
178
+ - 以"原部门 ≠ 目标部门"作为"调走/调入"的二次过滤——**同部门内异动也属于调入/调出语义**,必须保留。
179
+ - 以展示名是否等于用户输入的部门名作为剔除条件。
180
+
181
+ 只有用户显式给了"必须跨城市/必须跨部门/必须不同 X"等额外约束时,才可对**稳定 ID**(不是 name)做客户端比较;比较前先在最终 search 的 `select_fields` 里请求对应原/新字段。
182
+
183
+ ### 4. 按异动类型分类必须用二级名称
184
+
185
+ "按异动类型分类/统计/分组"时,必须使用 `transfer_type_unique_identifier` 的二级运行时 `name`(末级类型名)作为分组 key,**不能**把所有记录归到一级"异动"或公共父类型,也不能写死枚举。若 `transfer_type_unique_identifier` 是层级路径(如 `异动/活水转岗`),分组 key 取最后一级("活水转岗");若运行时只返回标识符,按标识符分组并附运行时 `name`。聚合表样例:
186
+
187
+ ```text
188
+ | 异动类型 | 数量 |
189
+ | --- | --- |
190
+ | <二级 name A> | <N1> |
191
+ | <二级 name B> | <N2> |
192
+ 合计:<N>,与 data.total 对齐。
193
+ ```
194
+
195
+ ### 5. 工具失败/字段不可返回 → 结构化不可完成
196
+
197
+ `+job-change-search` 报错、`--lookup-filters` 解析失败、`has_more=true` 缺 `page_token`、JSON 形态不符固定对象、`select_fields` 字段被运行时拒绝、自定义字段(如属地协议标签、原并购前公司)不在 `system_columns` 时,按 [output-and-empty.md](references/people-job-change-output-and-empty.md) 的不可完成模板输出失败类别 + 已执行条件,不编造记录、不暗示"再试一次"、不在同 case 内 help/schema 反复重试。
198
+
199
+ ### 6. 异动业务口径补充
200
+
201
+ - **未生效**包含待生效/审批通过/已批准和无需审批/直接异动;**已生效**只包含已生效。
202
+ - 用户问"异动到/变更到/调到/转为/变为某目标值"时必须体现异动发生:目标侧字段 lookup/枚举筛选 + `details_of_job_status_change` 对应变更内容;不要只按当前/目标字段值宽搜。目标值同义词校准到运行时合法值后立即搜索,不继续试英文/别名或拉全集验证;"从 X 到 Y"才同时加原侧字段。
203
+ - "合同信息/合同变更"筛选发生变更时只用"异动变更内容"父节点 `contract`:`{"field_name":"details_of_job_status_change","values":["contract"]}`;合同类型、合同编号、公司、开始/预计结束日期、签订/期限类型等下级字段只用于展示或用户明确要求子项统计,不要展开成多个 details values。若同时涉及试用期变更,只做 `contract` 分支与试用期父节点/运行时合法值分支并按 `job_change_id` 取交集;用户要求展示合同/试用期信息时,交集非空后必须最多补一次具体合同/试用期返回字段,答案不能只写"包含合同/试用期变更"。
204
+ - 用户查询某返回字段(如"异动内容是什么/为什么/为啥/原因")时,即使没有明确说"展示",最终答案也必须补充该字段;"为什么/原因"展示运行时异动原因字段。若默认结果未返回,最多补一次合法返回字段重新搜索;仍缺失则说明未返回,不继续试 `--help` 或 nested path。
205
+
206
+ ## Minimal References
207
+
208
+ - [people-job-change-search.md](references/people-job-change-search.md): 构造 `+job-change-search` 的核心规则。
209
+ - [people-job-change-search-option.md](references/people-job-change-search-option.md): 首步运行时校准规则。
210
+ - [people-job-change-search-advanced.md](references/people-job-change-search-advanced.md): 多变更 AND、变更字段对比、聚合输出规范。
211
+ - [people-job-change-lookup-filters.md](references/people-job-change-lookup-filters.md): 名称型引用字段映射。
212
+ - [people-job-change-output-and-empty.md](references/people-job-change-output-and-empty.md): 最终答案、空结果与不可完成模板。
@@ -0,0 +1,113 @@
1
+ # Job Change Business Rules
2
+
3
+ 本文件沉淀可复用业务口径。不要把评测集里的具体组织名、员工名、自定义字段名、枚举值写死到主 skill;运行时字段和枚举仍以 `search-option` 为准。
4
+
5
+ ## 状态
6
+
7
+ | 中文 | 运行时值 | 说明 |
8
+ | --- | --- | --- |
9
+ | 审批中 | `Approving` | 流程仍在审批 |
10
+ | 审批通过 | `Approved` | 待生效,不是已生效 |
11
+ | 无需审批 / 直接异动 | `NoNeedApproval` | 未生效口径的一部分 |
12
+ | 已生效 | `Transformed` | 只包含已生效 |
13
+ | 已撤销 / 已取消 | `Cancelled` | 取消类单据 |
14
+ | 已拒绝 | `Rejected` | 审批拒绝 |
15
+
16
+ - “未生效/还未生效” = `Approved` + `NoNeedApproval`。
17
+ - “直接异动” = `NoNeedApproval`,不要用异动类型名称猜。
18
+ - “成功/已成功/转成功”通常按 `Transformed`;如果用户明确说“审批成功但未生效”,按 `Approved`。
19
+ - 不要默认加状态筛选;只有用户明确表达状态语义时才过滤状态。
20
+
21
+ ## 时间
22
+
23
+ - “今年” = 当前自然年完整起止日期,例如 2026 年为 `2026-01-01` 到 `2026-12-31`。
24
+ - “本季度” = 当前日期所在自然季度完整起止日期。
25
+ - “上季度” = 当前自然季度的前一个自然季度完整起止日期;如果当前日期在 Q2,上季度就是 Q1 的 `01-01` 到 `03-31`,不是滚动近三个月。
26
+ - 异动存在未来生效,季度和年度范围都按完整自然周期,不截断到当前日。
27
+ - 月份按自然月完整范围,例如 2026 年 4 月为 `2026-04-01` 到 `2026-04-30`。
28
+ - 默认日期字段为生效日期 `effective_date`,除非用户明确说创建时间、发起时间、审批时间。
29
+ - 执行时生效日期范围必须使用 `--effective-date-start` / `--effective-date-end`;不要在 `--dynamic-filters` 里写 `effective_date`、`operator=between/gte/lte`。
30
+
31
+ ## 部门方向
32
+
33
+ 异动部门有三个概念:
34
+
35
+ | 概念 | 字段 |
36
+ | --- | --- |
37
+ | 员工当前所属部门 | `employment.department` |
38
+ | 异动前部门 / 调出部门 / 原部门 | `original_department` |
39
+ | 异动后部门 / 调入部门 / 目标部门 | `target_department` |
40
+
41
+ - 用户只说“某部门的异动”且未说明方向,默认按异动后部门 `target_department` 查询,并在答案中说明口径。
42
+ - “我的团队/团队里/团队内/我管理范围/我管理的部门中”不是部门名称,默认只表示当前用户可见或管理范围,由 `--as user` 承载;不要把当前用户所在部门、任职部门或管理部门作为额外部门筛选。
43
+ - “调出/从某部门出去/之前调出”用 `original_department`。
44
+ - “调入/转入/异动到某部门”用 `target_department`。
45
+ - “新部门/异动后部门是某部门”也是 `target_department`,不代表状态是已生效。
46
+ - 查询部门变更时必须加 `details_of_job_status_change=department`,否则会把目标部门相同但未发生部门变化的记录也算入。
47
+ - “调出的人/调入的人/去了哪些部门”在异动查询中默认按异动记录计数,数量来自 `data.total`;只有用户明确要求“去重人数/多少人”时才按人员去重。不要把记录数改写成去重人数,也不要自行补一个人数。
48
+ - 默认返回中部门名称常见在 `transfer_info.original_department_name.name.zh_cn` / `transfer_info.target_department_name.name.zh_cn`;不要假设顶层 `.target_department.names[0].value`。如果路径不确定,必须基于完整 raw item 判断,不能把路径错误造成的 null 解释为没有数据或无权限。
49
+
50
+ ## 变更内容
51
+
52
+ 用户问“某字段有没有变/发生变化/涉及某变更内容/异动到某值/从 A 到 B”时,必须检查并加入对应 `details_of_job_status_change`。
53
+
54
+ | 用户说法 | details 值 |
55
+ | --- | --- |
56
+ | 部门变更 | `department` |
57
+ | 工作地点变更 / 异动到某工作地点 | `work_location` |
58
+ | 职级变更 / 从 Lx 到 Ly | `job_level` |
59
+ | 职务变更 | `job` |
60
+ | 序列变更 | `job_family` |
61
+ | 人员类型变更 / 转正式 | `employee_type` |
62
+ | 合同信息变更 | `contract` |
63
+ | 司龄起算日期变更 | `seniority_date` |
64
+ | 直属上级变更 | `direct_manager` |
65
+ | 虚线上级变更 | `dotted_manager` |
66
+
67
+ - `details_of_job_status_change` 多值是 OR,不是 AND。
68
+ - “同时发生/同时涉及 A 和 B”必须分别查询 A、B 后按 `job_change_id` 取交集;不能把 `values:["A","B"]` 的 OR 结果当成同时发生,也不能只说明 OR 限制后返回 OR 结果。
69
+ - “转入/调入某部门的员工中涉及工作地点/职级/序列等变更”包含两个变更语义:部门变更和另一个字段变更。部门 lookup 条件要保留在两个分支中,分别查 `details=department` 与另一个 details,再按 `job_change_id` 取交集;不能只查另一个 details,也不能单次 OR。
70
+ - `details_of_job_status_change` 的值只能来自该字段运行时枚举;不要把 lookup 目标对象名当作变更内容值。筛选值校验失败时,不能删掉该条件降级成宽查询。
71
+ - “涉及合同变更”用父项 `contract`;不要展开成 `contract_type`、`contract_number` 等子项作为主筛选,除非用户明确问某个合同子字段。
72
+ - “异动到北京的同学”不是只查目标工作地点北京,还要加 `details_of_job_status_change=work_location`。
73
+ - “职级从 L6 到 L2”应使用 `original_job_level` + `target_job_level` lookup,并加 `details_of_job_status_change=job_level`。
74
+ - “新职级分类统计/新部门是某部门/新工作地点分布”是目标字段筛选或统计,不等于该字段发生变更;只有用户明确说“发生变更/变化/调整/涉及 X 变更”时才追加对应 details 条件。
75
+ - “工作地点变更/工作地点有没有变化”是变更内容或原新字段对比,不是“跨境异动类型”;只有用户明确说“跨境异动类型”时才筛异动类型。
76
+ - “职位描述/岗位描述改变”不是职务/职位变更。必须按“描述/description”语义校准运行时字段或变更内容;校准不到就不可完成,禁止用职务/职位替代。
77
+
78
+ ## 异动类型与原因
79
+
80
+ - “跨境异动类型”“业务线变更类型”“offer 异动”等是异动类型,筛选 `transform_type`。
81
+ - 用户说“因为/由于/出于某原因/某原因的异动”时,优先在 `transform_reason` 枚举中找完整短语;用户说“某类型/类型为...”时,优先在 `transform_type` 枚举中找完整短语。
82
+ - 异动类型/原因是枚举,需通过 `search-option` 校准;不要用 `details_of_job_status_change` 替代。
83
+ - 异动异常的异常类型/异常处理状态是异常维度,不能用异动变更内容替代;校准不到异常相关字段或枚举时,按不可完成输出,不宽搜。
84
+ - 用户问“异常类型是啥/哪些异常类型”时,异常类型是必返字段;如果 search-option 或最终结果没有可返回字段,只能说明异常类型未返回,不能用 pending/未处理、审批状态或异动变更内容充当异常类型。
85
+ - 异常类型的运行时字段可能展示为“异常类型”/`exception_type`,底层 api_name 可能是 `transform_exception_type`;校准时要同时用中文展示名、exception/type 语义和运行时字段对象识别,不能只按单一字段名精确匹配。异常类型常见业务枚举为:异动记录异常、合同记录异常、任职记录异常、组织架构调整异常、异动变更同步异常;最终筛选值必须来自本次 `search-option` 返回的合法枚举。
86
+ - 用户问“异常单据未处理/没处理完”不默认追加已生效状态;只有明确说“已生效异常”才加已生效口径。若用户问“异动内容是什么”,必须返回异动变更内容或说明未返回,不能只返回异常处理状态。
87
+ - 枚举匹配优先级是:完整短语精确命中的单字段枚举 > 更长/更具体的叶子枚举 > 宽泛父类枚举。不要把一个枚举 label 的前缀、分隔符或子词拆到其他字段形成额外 AND 条件。
88
+ - 只有用户明确同时限定两个维度时,才同时筛选 `transform_type` 和 `transform_reason`;否则如果 `transform_reason` 已完整覆盖用户说的原因短语,就不要再从原因 label 中推导 `transform_type`。
89
+
90
+ ## 人员类型与试用期
91
+
92
+ - “转正式/人员类型转正式”是人员类型变化:目标人员类型 `target_workforce_type` + `details_of_job_status_change=employee_type`,通常还要 `status=Transformed`。
93
+ - “由 A 转为 B / 从 A 到 B”的人员类型查询,应同时下推:原人员类型 lookup、目标人员类型 lookup、人员类型变更 details。`original_workforce_type` / `target_workforce_type` 使用 lookup 目标对象;`details_of_job_status_change` 使用运行时“人员类型/Employee type”枚举值,两者不是同一类值。
94
+ - 目标人员类型名称应通过 `lookup-filters` 解析,常见展示可能是“正式”而不是“正式员工”。
95
+ - “新试用期/试用期变更”与“实习生转正式”无关;它属于试用期字段变化。
96
+ - “今年有没有异动后有新试用期的同学”:生效日期在今年全年,details 包含试用期,返回字段包含是否有试用期,并且只有运行时返回值为 true 才算符合。
97
+
98
+ ## 合同与调薪
99
+
100
+ - 合同信息变更主筛选为 `details_of_job_status_change=contract`。
101
+ - 用户要求展示合同信息或试用期信息时,返回字段应包含运行时可返回的具体合同/试用期原新信息;字段名需运行时校准。答案不能只写“包含合同变更/包含试用期变更”,字段未返回就写未返回。
102
+ - 调薪不是只看异动类型。用户问“是否调薪/今年调薪人员”时,返回并判断运行时的调薪字段;如果字段未返回,说明无法确认,不要猜。
103
+
104
+ ## 字段与输出
105
+
106
+ - 自定义字段、标签、协议等必须运行时精确校准字段名和枚举值。找不到唯一字段时,应说明无法确认或请用户澄清,不能用相近字段替代。
107
+ - 自定义字段“有值/不为空”是筛选条件,不是展示后再猜;能枚举时用所有合法值表达有值,不能枚举且没有非空筛选能力时停止,不得删除该条件后宽搜。
108
+ - 用户查询了某字段或要求展示某字段,即使没有明确说“返回该字段”,答案也应包含该字段或说明该字段未返回。
109
+ - `--select-fields` 只能填写运行时 `system_columns` 明确返回的字段名;默认响应里的嵌套路径不等于合法选择字段。姓名等基础展示信息可从默认响应读取,不能因为默认响应有 `employment.name` 就主动把 `employment.name` 作为 `select-fields` 传入。
110
+ - 如果本地过滤或投影后 `items` 数量改变,原始 `.data.total` 不再是过滤后命中数;不要用原始 total 回答过滤后的数量。优先把筛选下推到服务端并保留完整 raw items。
111
+ - 字段未返回时,不代表字段值为空;要区分“无数据”和“字段未返回/无权限/被 select-fields 或 jq 裁剪”。
112
+ - `access_control.export_require_l4` 表示导出权限控制,不等于查询字段不可见;只有列/行权限 deny map 或完整 raw item 明确缺字段时,才可说“未返回/无权限”。
113
+ - 对“去向/流向/去了哪些部门或地点”的统计,必须保留原/目标字段和 item 明细;如果显示路径不明确,先说明字段路径未返回,不能把所有记录归为“未返回”。
@@ -0,0 +1,82 @@
1
+ # job_change lookup-filters
2
+
3
+ 当用户给的是对象展示名/名称,而 `search-option.system_filters` 中该字段为 `employee`、`department`、`tree_query_all`、`select_query`、`select_query_all` 等引用/查询类型时,最终搜索用 `--lookup-filters`,不要把名称直接放进 `--dynamic-filters`。
4
+
5
+ ## Resolution Rule
6
+
7
+ 1. 先用 `job_change search-option --as user` 校准字段是否存在。
8
+ 2. `field_name` 取运行时 `filter_api_name`,没有则取 `field`。
9
+ 3. 标准 job_change 字段只在 `--lookup-filters` 中传 `field_name` 和 `values`,由 shortcut 自动补齐 `target_object_api_name`。
10
+ 4. 非标准/自定义字段才显式传 `target_object_api_name`:优先取运行时 `target_object_api_name`;缺失时取运行时 `api_name`。
11
+ 5. 只有运行时也无法确认目标对象时,才使用下表的稳定系统字段聚类;仍不能确认时停止并说明无法安全解析。
12
+
13
+ ## Common Mapping
14
+
15
+ | 用户意图 | field_name | target_object_api_name |
16
+ | --- | --- | --- |
17
+ | 按员工筛选 | `employment` | `employment` |
18
+ | 按发起人筛选 | `initiator` | `employment` |
19
+ | 按异常处理人筛选 | `exception_handler` | `employment` |
20
+ | 按目标/调入部门筛选 | `target_department` | `department` |
21
+ | 按原/调出部门筛选 | `original_department` | `department` |
22
+ | 按当前所属部门筛选 | `employment.department` | `department` |
23
+ | 按新工作地点筛选 | `target_work_location` | `location` |
24
+ | 按原工作地点筛选 | `original_work_location` | `location` |
25
+ | 按新直属上级筛选 | `target_direct_manager` | `employment` |
26
+ | 按原直属上级筛选 | `original_direct_manager` | `employment` |
27
+ | 按新虚线上级筛选 | `target_dotted_manager` | `employment` |
28
+ | 按原虚线上级筛选 | `original_dotted_manager` | `employment` |
29
+ | 按新职务筛选 | `target_job` | `job` |
30
+ | 按原职务筛选 | `original_job` | `job` |
31
+ | 按新序列筛选 | `target_job_family` | `job_family` |
32
+ | 按原序列筛选 | `original_job_family` | `job_family` |
33
+ | 按新职级筛选 | `target_job_level` | `job_level` |
34
+ | 按原职级筛选 | `original_job_level` | `job_level` |
35
+ | 按新人员类型筛选 | `target_workforce_type` | `employee_type` |
36
+ | 按原人员类型筛选 | `original_workforce_type` | `employee_type` |
37
+ | 按新合同主体筛选 | `target_company` | `company` |
38
+ | 按原合同主体筛选 | `original_company` | `company` |
39
+ | 按新任职公司筛选 | `target_service_company` | `service_company` |
40
+ | 按原任职公司筛选 | `original_service_company` | `service_company` |
41
+ | 按新工时制度筛选 | `target_working_hours_type` | `working_hours_type` |
42
+ | 按原工时制度筛选 | `original_working_hours_type` | `working_hours_type` |
43
+ | 按新工作日历筛选 | `target_working_calendar` | `working_calendar` |
44
+ | 按原工作日历筛选 | `origin_working_calendar` | `working_calendar` |
45
+ | 按新社保城市筛选 | `target_social_security_city` | `social_security_city` |
46
+ | 按原社保城市筛选 | `origin_social_security_city` | `social_security_city` |
47
+
48
+ ## Command Shape
49
+
50
+ ```bash
51
+ people-cli corehr +job-change-search \
52
+ --format json \
53
+ --lookup-filters '[{"field_name":"<FIELD_NAME>","values":["<NAME>"]}]' \
54
+ --as user
55
+ ```
56
+
57
+ ## Job Level Transition
58
+
59
+ 职级是 `job_level` 引用对象。用户说"职级从 X 变更到 Y / 从 X 到 Y 的职级异动"时,`X/Y` 是职级展示名,必须用 `--lookup-filters` 解析为对象 ID;不要写成 `--dynamic-filters original_job_level/target_job_level`,否则会返回 0 或漏数。
60
+
61
+ ```bash
62
+ people-cli corehr +job-change-search \
63
+ --page-size 10 \
64
+ --format json \
65
+ --lookup-filters '[{"field_name":"original_job_level","values":["L6"]},{"field_name":"target_job_level","values":["L2"]}]' \
66
+ --select-fields '["effective_date","status","transform_type","original_job_level","target_job_level"]' \
67
+ --as user
68
+ ```
69
+
70
+ ## Work Location Target
71
+
72
+ 工作地点字段是 `location` 引用对象。`target_work_location` / `original_work_location` 的 target 由 shortcut 自动补齐为 `location`,不要手写 `work_location`;地点名称也不要放进 `--dynamic-filters`。如果用户说"已经异动到/已调到/成功调到 <地点>",同时追加工作地点变更内容和严格已生效状态。
73
+
74
+ ```bash
75
+ people-cli corehr +job-change-search \
76
+ --page-size 10 \
77
+ --format json \
78
+ --lookup-filters '[{"field_name":"target_work_location","values":["北京"]}]' \
79
+ --dynamic-filters '[{"field_name":"details_of_job_status_change","values":["work_location"]},{"field_name":"status","values":["Transformed"]}]' \
80
+ --select-fields '["effective_date","status","transform_type","original_work_location","target_work_location"]' \
81
+ --as user
82
+ ```