{
  "$comment": [
    "BE↔FE deep-link contract — the single source of truth for 'where does a",
    "notification land on a phone?'.",
    "",
    "WHY THIS FILE EXISTS: the backend emits ~90 distinct desktop paths in",
    "notification / Feishu-card / email URLs. The mobile shell rewrites them",
    "through web/src/lib/mobileDeepLink.ts. Nothing tied the two together, so",
    "the drift was invisible and expensive: `/my/requests` — the single",
    "most-emitted URL in the codebase (16 emitters) — had no mobile mapping at",
    "all while `/m/requests` had existed for months, and six paths were being",
    "emitted that are not routes on EITHER shell (guaranteed 404s in",
    "production, found 2026-07-28).",
    "",
    "TWO TESTS CONSUME THIS FILE, one per language:",
    "  - server/tests/test_mobile/test_deep_link_contract.py — scans the",
    "    backend for emitted path literals; a path that is not listed here",
    "    fails the test. That is the gate: a new notification URL cannot ship",
    "    without a decision about where it lands on mobile.",
    "  - web/src/lib/mobileDeepLink.contract.test.ts — asserts the mapper",
    "    actually produces the `mobile` value for every `mapped` entry, and",
    "    `null` for every `desktopOnly` entry.",
    "",
    "HOW TO ADD AN ENTRY: use `:id`-style placeholders for path params; keep",
    "query strings when (and only when) a query value decides WHICH resource",
    "opens. Put the entry in `mapped` with its `/m/...` target, or in",
    "`desktopOnly` with an honest `reason`. 'No mobile page yet' is a valid",
    "reason — an unmapped path falls through to the desktop page rendered",
    "inside the webview, which beats pretending a mobile surface exists.",
    "",
    "OPTIONAL FLAG `legacyInbound: true` on a mapped entry: the desktop path is a shape that only ever arrives INBOUND (historical notification rows), with no current backend emitter and no desktop route. Such entries are exempt from the route-table assertion; the `note` must say why the mapper rule is still worth keeping."
  ],
  "mapped": [
    {
      "desktop": "/admin/approvals",
      "mobile": "/m/admin/approvals",
      "note": "审批总览（观察面）"
    },
    {
      "desktop": "/admin/assets",
      "mobile": "/m/admin/assets",
      "note": "资产工作台 — AI 大脑 assets 维度的处置落点；子页规则都要求带段，裸路径此前落空"
    },
    {
      "desktop": "/admin/assets/:id",
      "mobile": "/m/admin/assets/abc123",
      "note": "资产详情（分配/换人/归还）"
    },
    {
      "desktop": "/admin/assets/api-keys",
      "mobile": "/m/admin/api-keys",
      "note": "API Key 预算告警"
    },
    {
      "desktop": "/admin/assets/api-keys?idle=1",
      "mobile": "/m/admin/api-keys",
      "note": "API Key 闲置月报给 IT 的那张卡。与已登记的裸路径同一个面,筛选参数按惯例丢弃(移动页不渲染桌面侧筛选态)。"
    },
    {
      "desktop": "/admin/assets/inventory",
      "mobile": "/m/admin/assets",
      "note": "静态子页，非资产 id"
    },
    {
      "desktop": "/admin/assets/list",
      "mobile": "/m/admin/assets",
      "note": "静态子页，非资产 id"
    },
    {
      "desktop": "/admin/assets/seat-allocations",
      "mobile": "/m/admin/software-seats",
      "note": "席位对账处置落点（软件席位队列同页）"
    },
    {
      "desktop": "/admin/assets/seat-allocations?user_id=:pid",
      "mobile": "/m/admin/software-seats",
      "note": "席位分配 → 移动端席位队列（绝不能落 /m/admin/assets/:id，会被当成资产 id）"
    },
    {
      "desktop": "/admin/assets/software-catalog",
      "mobile": "/m/admin/software-seats",
      "note": "软件目录 → 移动端席位队列（同上，避免 :id 吞噬）"
    },
    {
      "desktop": "/admin/assets/software-overview",
      "mobile": "/m/admin/software-seats",
      "note": "软件总览 — software_api 维度默认处置落点"
    },
    {
      "desktop": "/admin/attendance?report=:rid",
      "mobile": "/m/attendance/abc123",
      "note": "query 决定打开哪张考勤报表"
    },
    {
      "desktop": "/admin/cloud/dns",
      "mobile": "/m/admin/cloud-dns",
      "note": "DNS 审批 / 四眼绕过同行通告"
    },
    {
      "desktop": "/admin/cloud/domains",
      "mobile": "/m/admin/cloud-domains",
      "note": "域名审批 / 到期洞察"
    },
    {
      "desktop": "/admin/cloud/domains?search=:label",
      "mobile": "/m/admin/cloud-domains",
      "note": "search 是桌面筛选，移动端列表自带搜索"
    },
    {
      "desktop": "/admin/cloud/iam-users",
      "mobile": "/m/admin/cloud/iam-users",
      "note": "IAM 同步异常 / 离职清理"
    },
    {
      "desktop": "/admin/cloud/leaver-residue",
      "mobile": "/m/admin/cloud/iam-users",
      "note": "离职人员云权限残留告警的落点。桌面上它是 IAM 用户页的一个 tab（?tab=residue），移动端归到同一张 IAM 用户页 —— 清理动作不可撤销且限 global_admin，不适合在手机上做，手机端只需要能看到「谁还留着权限」。"
    },
    {
      "desktop": "/admin/cloud/overview",
      "mobile": "/m/admin/cloud/overview",
      "note": "云总览 — cloud_network 维度默认处置落点"
    },
    {
      "desktop": "/admin/cloud/overview?tab=billing",
      "mobile": "/m/admin/cloud/overview",
      "note": "多云账单聚合"
    },
    {
      "desktop": "/admin/cloud/overview?tab=billing&month=:month&integration_id=:iid",
      "mobile": "/m/admin/cloud/overview",
      "note": "账期告警：month/integration 是桌面筛选态，移动总览按当期展示"
    },
    {
      "desktop": "/admin/cloud/resources?tab=reports",
      "mobile": "/m/cloud/resources?tab=reports",
      "note": "云资源目录 · 报表 tab（cloud_admin 收件人）—— 移动端同页支持 reports tab。(#3181 起后端在发，契约漏登记。)"
    },
    {
      "desktop": "/admin/cloud/scopes",
      "mobile": "/m/admin/cloud/scopes",
      "note": "云订阅列表"
    },
    {
      "desktop": "/admin/cloud/scopes/:sid",
      "mobile": "/m/admin/cloud/scopes/abc123",
      "note": "云订阅详情（管理员）"
    },
    {
      "desktop": "/admin/cloud/scopes/:sid?tab=members",
      "mobile": "/m/admin/cloud/scopes/abc123",
      "note": "tab 是桌面内部状态"
    },
    {
      "desktop": "/admin/cloud/scopes?tab=requests",
      "mobile": "/m/admin/cloud/scopes",
      "note": "无 id 时落列表"
    },
    {
      "desktop": "/admin/cloud/scopes?tab=requests&id=:rid",
      "mobile": "/m/cloud/scope-requests/abc123",
      "note": "id 决定展开哪条申请"
    },
    {
      "desktop": "/admin/cloud/servers/:id",
      "mobile": "/m/admin/cloud-servers/abc123",
      "note": "特权读者的 AI 分析证据链接（cloud_scope_projection）。此前无规则，H5 上点击静默无反应"
    },
    {
      "desktop": "/admin/hr/sync",
      "mobile": "/m/admin/hr-sync",
      "note": "HRIS 同步失败告警；也是 people_org 新鲜度扣分的处置落点"
    },
    {
      "desktop": "/admin/intelligence",
      "mobile": "/m/admin/intelligence",
      "note": "AI 大脑。关键健康卡片 + 跨域建议的处置落点都是这里；此前无规则，跨域「开始处理」会把 H5 用户踢到桌面版同一页"
    },
    {
      "desktop": "/admin/intelligence/domains/:domain",
      "mobile": "/m/admin/intelligence",
      "note": "领域工作区 — 移动端在中心页的领域详情弹层里给同一份指标拆解"
    },
    {
      "desktop": "/admin/intelligence?recommendation=:id",
      "mobile": "/m/admin/intelligence?recommendation=abc123",
      "note": "建议推送卡片。query 决定打开哪条建议，因此跨端保留（移动端读回并直接展开该条详情）"
    },
    {
      "desktop": "/admin/leaver-blocked/override/:id",
      "mobile": "/m/admin/leaver-override/abc123",
      "note": "双签放行审批"
    },
    {
      "desktop": "/admin/lifecycle/onboarding?tab=strategy",
      "mobile": "/m/admin/onboarding",
      "note": "入职管理的策略 tab。移动页只有流程列表没有策略 tab,落在同一页的默认 tab —— 与已登记的 /admin/offboarding?tab=progress 同样的处理。"
    },
    {
      "desktop": "/admin/lifecycle/person/:pid",
      "mobile": "/m/admin/users/abc123",
      "note": "人员生命周期 → 移动端用户详情"
    },
    {
      "desktop": "/admin/mdm/devices",
      "mobile": "/m/admin/mdm-devices",
      "note": "MDM 设备台账 —— 清理提醒卡的落地页。移动端只读:确认「我已从 MDM 移除」是一句会写进审计的断言,刻意只留飞书卡片一键与桌面抽屉两个入口。"
    },
    {
      "desktop": "/admin/mdm/devices?state=pending_cleanup",
      "mobile": "/m/admin/mdm-devices?state=pending_cleanup",
      "note": "同上,带筛选。查询串保留是因为它决定打开哪一批 —— 催办卡指向的是待清理队列,落到全量台账上就等于让管理员自己再筛一次。"
    },
    {
      "desktop": "/admin/notifications/outbox",
      "mobile": "/m/admin/outbox",
      "note": "通知投递失败的处置落点（桌面 redirect 到 /admin/audit?tab=outbox，移动端是同一个队列）"
    },
    {
      "desktop": "/admin/offboarding",
      "mobile": "/m/admin/offboarding",
      "note": "离职队列"
    },
    {
      "desktop": "/admin/offboarding/process/:pid",
      "mobile": "/m/admin/offboarding/abc123",
      "note": "离职流程详情"
    },
    {
      "desktop": "/admin/offboarding?tab=progress",
      "mobile": "/m/admin/offboarding",
      "note": "桌面 tab 选择器在移动端被丢弃：移动队列本身就是单一进度流"
    },
    {
      "desktop": "/admin/onboarding/cockpit",
      "mobile": "/m/admin/onboarding",
      "note": "入职就位驾驶舱 — Day-1/SLA 扣分的处置落点"
    },
    {
      "desktop": "/admin/onboarding/process/:pid",
      "mobile": "/m/admin/onboarding/abc123",
      "note": "入职流程详情"
    },
    {
      "desktop": "/admin/provisioning",
      "mobile": "/m/admin/provisioning",
      "note": "开通队列"
    },
    {
      "desktop": "/admin/provisioning/tasks",
      "mobile": "/m/admin/provisioning",
      "note": "开通队列 — 自动开通失败率的处置落点（带 query 的变体已单列）"
    },
    {
      "desktop": "/admin/provisioning/tasks?person_id=:pid",
      "mobile": "/m/admin/provisioning",
      "note": "person 筛选是桌面态"
    },
    {
      "desktop": "/admin/provisioning/tasks?status=failed",
      "mobile": "/m/admin/provisioning",
      "note": "status 筛选是桌面态"
    },
    {
      "desktop": "/admin/provisioning/tasks?status=in_progress",
      "mobile": "/m/admin/provisioning",
      "note": "洞察卡 status 筛选是桌面态"
    },
    {
      "desktop": "/admin/provisioning/tasks?status=notified",
      "mobile": "/m/admin/provisioning",
      "note": "待人工完成任务；移动队列默认含此状态"
    },
    {
      "desktop": "/admin/role-changes?review=:id",
      "mobile": "/m/me/role-change-review/abc123",
      "note": "转岗复核包裹。这条从 desktopOnly 移过来:原来的理由写的是「RBAC 授权层,手机上做不了」,而那个前提是错的 —— 卡片的收件人不是管理员,是转岗同事的新经理(普通员工),触发媒介是飞书卡片,飞书卡片就是在手机上打开的。2026-09-05 发出的 10 张卡在桌面和移动端全部是死链。移动端只做类别级决断(保留/不再需要 整类),逐条拆分去桌面。"
    },
    {
      "desktop": "/admin/support/tickets/:id",
      "mobile": "/m/admin/support/tickets/abc123",
      "note": "处理工单"
    },
    {
      "desktop": "/admin/users",
      "mobile": "/m/admin/users",
      "note": "人员花名册。邮箱名不一致告警（hr.email_name_reconcile）的落点 —— 卡片正文已列全受影响的人，按钮只是「把人翻出来」的入口，桌面和移动端两侧都是带搜索框 + 邮箱列的列表，所以不是 desktopOnly。mobileDeepLink.ts 的规则早就在了，此前只是没有 emitter 让它被契约覆盖。"
    },
    {
      "desktop": "/admin/users/:pid?tab=cloudGrants",
      "mobile": "/m/admin/users/abc123",
      "note": "取证时间线 → 用户详情"
    },
    {
      "desktop": "/admin/users/:pid?tab=seats",
      "mobile": "/m/admin/users/abc123",
      "note": "取证时间线席位行 → 用户详情"
    },
    {
      "desktop": "/auditor/cert-expiry",
      "mobile": "/m/auditor/cert-expiry",
      "note": "证书到期侦测控制"
    },
    {
      "desktop": "/auditor/evidence-packs",
      "mobile": "/m/auditor/evidence-packs",
      "note": "安全证据新鲜度扣分的处置落点"
    },
    {
      "desktop": "/auditor/mfa",
      "mobile": "/m/auditor/mfa",
      "note": "MFA 覆盖率扣分的处置落点"
    },
    {
      "desktop": "/auditor/pat-audit",
      "mobile": "/m/auditor/pat-audit",
      "note": "PAT 审计侦测控制"
    },
    {
      "desktop": "/auditor/public-exposure",
      "mobile": "/m/auditor/public-exposure",
      "note": "公开暴露未解决扣分的处置落点"
    },
    {
      "desktop": "/auditor/risk-score",
      "mobile": "/m/auditor/risk-score",
      "note": "风险分侦测控制"
    },
    {
      "desktop": "/auditor/secret-rotation",
      "mobile": "/m/auditor/secret-rotation",
      "note": "密钥/PAT 风险扣分的处置落点"
    },
    {
      "desktop": "/auditor/signin-anomaly",
      "mobile": "/m/auditor/signin-anomaly",
      "note": "登录异常侦测控制"
    },
    {
      "desktop": "/cloud/scopes/:id?renewals=1",
      "mobile": "/m/admin/cloud/approvals",
      "note": "云权限续期的「即将超期」汇总卡（一次覆盖同一订阅上的多条申请，没有唯一行可定位）。落到移动端云审批队列 —— 该队列由 action_inbox 的 cloud_renewal_approval provider 供给，逐条点进 /m/cloud/renewal-approval/:group 决策。刻意不落 /m/cloud/grants（那是本人的权限页，没有批准按钮）。"
    },
    {
      "desktop": "/cloud/scopes/:id?renewals=1&group=:id",
      "mobile": "/m/cloud/renewal-approval/abc123",
      "note": "单条续期申请的审批卡 / 复核卡（2026-07-31 起带 group）。桌面端落在订阅详情的「续期审批」分段并把该行置顶+高亮滚动；移动端直接开这条的决策页，不再让审批人在队列里找。group 非法时回落队列。"
    },
    {
      "desktop": "/cloud/scopes/:id?tab=pending&grant=:id",
      "mobile": "/m/cloud/grant-approval/abc123",
      "note": "云访问申请待审批卡保留桌面端按角色分流的订阅 URL，并携带精确 grant；移动端直接打开该授权的批准 / 驳回页。"
    },
    {
      "desktop": "/cloud/scopes/:sid",
      "mobile": "/m/cloud/scopes/abc123",
      "note": "owner/有效成员视角 → 共享订阅详情与按需 AI 分析"
    },
    {
      "desktop": "/cloud/scopes/:sid?ownerAction=:action&confirmationId=:cid",
      "mobile": "/m/cloud/grants",
      "note": "owner 确认动作族（semiannual_* / zero_spend_*）统一落我的云订阅"
    },
    {
      "desktop": "/cloud/scopes/:sid?ownerAction=semiannual_confirm&confirmationId=:cid",
      "mobile": "/m/cloud/grants",
      "note": "owner 半年确认（移动端从列表进详情完成）"
    },
    {
      "desktop": "/cloud/scopes/:sid?tab=pending",
      "mobile": "/m/cloud/grants",
      "note": "待审成员 tab → 我的云订阅（移动端从行进详情决策）"
    },
    {
      "desktop": "/company/mail-groups",
      "mobile": "/m/mail-groups",
      "note": "我拥有的邮件组"
    },
    {
      "desktop": "/company/mail-groups?review=1",
      "mobile": "/m/mail-groups/join-approvals",
      "note": "review=1 决定进入待复核 → 移动端专属审批页"
    },
    {
      "desktop": "/dashboard",
      "mobile": "/m/home",
      "note": "门户首页"
    },
    {
      "desktop": "/feed/celebrate/:id",
      "mobile": "/m/feed/celebrate/abc123",
      "note": "生日/周年祝福"
    },
    {
      "desktop": "/feed/p/:id",
      "mobile": "/m/feed",
      "note": "帖子永久链接是桌面概念"
    },
    {
      "desktop": "/me/access-review",
      "mobile": "/m/access-review",
      "note": "半年访问自证"
    },
    {
      "desktop": "/me/api-keys",
      "mobile": "/m/api-keys",
      "note": "我的 API Key"
    },
    {
      "desktop": "/me/api-keys/:aid",
      "mobile": "/m/api-keys",
      "note": "详情并入列表行"
    },
    {
      "desktop": "/me/budget",
      "mobile": "/m/budget",
      "note": "个人预算 → 移动端预算详情"
    },
    {
      "desktop": "/me/handovers",
      "mobile": "/m/handovers",
      "note": "我的交接（列表 + 改派）——离职交接推送落点"
    },
    {
      "desktop": "/me/inventory/:cid",
      "mobile": "/m/inventory",
      "note": "盘点应答（移动端列表已按人过滤）"
    },
    {
      "desktop": "/me/security-faq",
      "mobile": "/m/security-faq",
      "note": "安全 FAQ —— 员工可读的安全答案库"
    },
    {
      "desktop": "/me/security-faq?entry=:entryId",
      "mobile": "/m/security-faq/abc123",
      "note": "安全 FAQ 单条深链(桌面「复制链接」发到飞书,多半在手机上被点开)"
    },
    {
      "desktop": "/me/security-learning",
      "mobile": "/m/security-learning",
      "note": "安全宣贯资料库"
    },
    {
      "desktop": "/me/security-learning/:id",
      "mobile": "/m/security-learning/abc123",
      "note": "安全宣贯素材 —— 活动卡片与催办阶梯的落点。卡片在飞书里到达，所以第一次点击本来就在手机上；此前无映射，一路落回首页"
    },
    {
      "desktop": "/me/settings?tab=aliases",
      "mobile": "/m/me/settings?tab=aliases",
      "note": "个人邮箱别名 — 移动端 /m/me/settings 的别名页（PR6 落地）。tab 是少数被带过去的 query：它决定打开哪个面，移动页从 ?tab= 读回"
    },
    {
      "desktop": "/me/settings?tab=groups",
      "mobile": "/m/me/settings?tab=groups",
      "note": "我的邮件组（我是成员的，非我拥有的 /m/mail-groups）— 移动端 PR6 落地，可查看 + 退出"
    },
    {
      "desktop": "/me/settings?tab=leave",
      "mobile": "/m/leave",
      "note": "假期余额/到期提醒。tab 决定进入哪个面，移动端有独立的 /m/leave 页"
    },
    {
      "desktop": "/me/support",
      "mobile": "/m/support",
      "note": "IT 求助入口,员工面,移动端有同名页。"
    },
    {
      "desktop": "/me/support/:id",
      "mobile": "/m/support/abc123",
      "note": "我的工单详情"
    },
    {
      "desktop": "/my/approval-flows",
      "mobile": "/m/my/approval-flows",
      "note": "流程台账 · 我负责的流程 —— 半年确认卡、转交/接手卡的落地页。卡片是在飞书里读的,而确认与转交的控件就在这一页上,所以必须落在能动手的那一页,不是只读目录 /m/approval-flows。"
    },
    {
      "desktop": "/my/bounty/:id",
      "mobile": "/m/bounty/abc123",
      "note": "漏洞赏金 · 业务确认页 —— 安全团队指派/催办卡片的落地页。确认控件就在这一页上(不是只读详情),移动端同样能提交结论、改修复状态、留言。"
    },
    {
      "desktop": "/my/cloud/dns",
      "mobile": "/m/cloud/dns",
      "note": "DNS 记录转移通知"
    },
    {
      "desktop": "/my/cloud/efficiency",
      "mobile": "/m/cloud/efficiency",
      "note": "云效率 Owner 周报 → 移动端效率页"
    },
    {
      "desktop": "/my/cloud/grants",
      "mobile": "/m/cloud/grants",
      "note": "我的云订阅"
    },
    {
      "desktop": "/my/cloud/resources?tab=reports",
      "mobile": "/m/cloud/resources?tab=reports",
      "note": "云资源目录 · 报表 tab（普通收件人）—— 同一移动端页面，按角色收窄在页面内完成。"
    },
    {
      "desktop": "/my/cloud/scope-requests",
      "mobile": "/m/requests",
      "note": "无 id 时落统一申请列表"
    },
    {
      "desktop": "/my/cloud/scope-requests?id=:rid",
      "mobile": "/m/cloud/scope-requests/abc123",
      "note": "id 决定展开哪条申请"
    },
    {
      "desktop": "/my/cloud/scopes/:sid",
      "mobile": "/m/cloud/scopes/abc123",
      "note": "员工订阅详情 → 已授权订阅的共享分析详情"
    },
    {
      "desktop": "/my/cloud/scopes/:sid?renew=:gid",
      "mobile": "/m/cloud/grants?renew=abc123",
      "note": "renew 决定高亮哪条 grant 的续期按钮"
    },
    {
      "desktop": "/my/cloud/servers",
      "mobile": "/m/cloud/servers",
      "note": "服务器归属确认"
    },
    {
      "desktop": "/my/cloud/servers/:id",
      "mobile": "/m/cloud/servers/abc123",
      "note": "非特权读者的 AI 分析证据链接（cloud_scope_projection）"
    },
    {
      "desktop": "/my/cloud/servers?confirmationId=:cid",
      "mobile": "/m/cloud/servers",
      "note": "confirmationId 是桌面回写参数"
    },
    {
      "desktop": "/my/cloud/servers?confirmationId=:cid&action=confirm_all",
      "mobile": "/m/cloud/servers",
      "note": "一键全部确认：移动端在服务器列表逐条确认（不做无回顾的批量提交）"
    },
    {
      "desktop": "/my/inventory",
      "mobile": "/m/inventory",
      "note": "全员盘点提醒（此前无映射，静默落空）"
    },
    {
      "desktop": "/my/offboarding",
      "mobile": "/m/lifecycle",
      "note": "我的离职清单"
    },
    {
      "desktop": "/my/requests",
      "mobile": "/m/requests",
      "note": "我的申请 — 后端出现频次最高的 URL（16 处），此前无映射"
    },
    {
      "desktop": "/my/requests/:id",
      "mobile": "/m/requests/abc123",
      "note": "历史入站形态：桌面端从未有 /my/requests/:id 路由（详情是 ?focus= 弹窗），当前也无后端发出点（同名的后端路径是 API 端点 /api/v1/approval/my/requests/{id}）。规则保留是为了老通知行里可能残留的这个形状。2026-07-28 修正落地页：原先与 /admin/approvals/:id 共用 /m/approval/:id，导致同一条申请按卡片携带的形状不同落在两个页面 —— /my/requests 是申请人自己的视角，应与 ?focus= 一致落在 /m/requests/:id；/m/approval/:id 是审批人视角。legacyInbound 使其豁免「必须能被前端路由表解析」断言。",
      "legacyInbound": true
    },
    {
      "desktop": "/my/requests?focus=:id",
      "mobile": "/m/requests/abc123",
      "note": "focus 决定展开哪条申请 → 移动端直接开详情"
    },
    {
      "desktop": "/my/team-leavers",
      "mobile": "/m/team/leavers",
      "note": "经理视角团队离职"
    },
    {
      "desktop": "/my/todos",
      "mobile": "/m/todos",
      "note": "我的待办"
    },
    {
      "desktop": "/my/todos?tab=apikey-release",
      "mobile": "/m/todos",
      "note": "tab 是桌面态，移动收件箱是单一流"
    },
    {
      "desktop": "/my/todos?tab=cloudGrantReview",
      "mobile": "/m/todos",
      "note": "转岗后的云授权决断,发给云 scope 负责人(常常是普通员工)。与已登记的 ?tab=apikey-release 同样落在移动待办首页 —— 移动待办不按 tab 深链。这条卡此前指向 /admin/role-changes,而负责人既打不开那个页面、端点也对他 403;2026-09-05 一并修好。"
    },
    {
      "desktop": "/my/todos?tab=githubId",
      "mobile": "/m/github-id/approvals",
      "note": "GitHub ID 修改确认 —— 与 apikey-release 那条不同,这个 tab 有专属移动决策页。审批人(申请人的 HR Ops / HRBP)是在飞书卡片上被触达的,也就是在手机上;丢掉 tab 会把他丢回通用收件箱,再去找那条刚被通知的记录。"
    },
    {
      "desktop": "/my/todos?tab=permissionApprovals",
      "mobile": "/m/todos",
      "note": "软件权限审批 —— 收件人是软件负责人,普通员工。与已登记的 ?tab=apikey-release 同样落在移动待办首页(移动待办不按 tab 深链)。"
    },
    {
      "desktop": "/my/transfers",
      "mobile": "/m/todos",
      "note": "资产转让待接收并入待办"
    }
  ],
  "desktopOnly": [
    {
      "path": "/",
      "reason": "门户根 — 未登录/通用落地，移动端由 FeishuMobileGuard 自己接管"
    },
    {
      "path": "/admin/announcements",
      "reason": "公告管理（编写面）。员工侧公告阅读在 PR5 上移动端；管理编写留桌面"
    },
    {
      "path": "/admin/approval-flows?q=:id",
      "reason": "流程归属争议的通知落点（approval_registry）。与已登记的 /admin/approval-flows?tab=* 同一个 IT 处理面，?q= 只是按 approval_code 预填搜索；这条流程的终点仍然是去飞书审批控制台改，手机不是这项工作的设备。2026-09-04 由深链扫描器补上 .format() 形态后才可见"
    },
    {
      "path": "/admin/approval-flows?tab=feishu-drift",
      "reason": "飞书流程漂移页签。与已登记的 /admin/approval-flows?tab=requests 同一个面:处理的终点是去飞书审批控制台改流程定义,手机不是这项工作的设备。"
    },
    {
      "path": "/admin/approval-flows?tab=requests",
      "reason": "新建流程申请的 IT 处理队列。批/驳可以在手机上做,但这条流程的终点是「去飞书审批控制台把流程建出来、再把 approval_code 回填回来」—— 那是桌面上的活,队列本身也只有桌面有(移动端 /m/approval-flows 是全员只读目录)。卡片走桌面 WebView。"
    },
    {
      "path": "/admin/assets/financial",
      "reason": "硬件财务面（采购价/折旧/保修字段批量补录）无移动页；AI 大脑资产财务完整度的处置落点，补录本身是桌面表格活儿"
    },
    {
      "path": "/admin/assistant-eval?run=:id",
      "reason": "助手评测台的单次运行明细。周报告警落在这里,而处理它的动作是:读原始回答、对着它读到的文档核对、再决定补哪篇知识库文档 —— 三件事都要一次看很多文字,手机不是这项工作的设备。移动端没有对应页面,卡片走桌面 WebView。"
    },
    {
      "path": "/admin/audit?tab=assistant",
      "reason": "助手对话审计是审计日志页的一个 tab —— 逐条对话的取证阅读面,与 /admin/audit?trace_id=:tid 同理保留桌面 WebView。(#3117 起后端在发,契约漏登记。)"
    },
    {
      "path": "/admin/audit?trace_id=:tid",
      "reason": "审计追踪查询 — 宽表 + 多维筛选，手机不可用"
    },
    {
      "path": "/admin/cloud/certificates",
      "reason": "证书管理无移动页；域名与证书健康度的处置落点，续期是桌面/厂商侧动作"
    },
    {
      "path": "/admin/cloud/certificates?search=:label",
      "reason": "证书管理无移动页（证书到期 owner 提醒本身走 /cmdb/expiry/ack token 页）"
    },
    {
      "path": "/admin/cloud/efficiency",
      "reason": "云效率洞察 — 规则引擎 + 多图表，桌面面"
    },
    {
      "path": "/admin/cloud/sync-jobs",
      "reason": "云同步作业台无移动页；订阅同步新鲜度的处置落点，重跑同步是桌面运维动作"
    },
    {
      "path": "/admin/compliance-incidents",
      "reason": "合规事件管理：事件建档 + 处置流转 + 证据挂接，是审计员的桌面工作台，手机上无法完成"
    },
    {
      "path": "/admin/data-warehouse/grants",
      "reason": "数仓授权清单与生命周期,管理台。六张 KPI + 逐行延长/回收/时间线抽屉,移动端无对应页;收件人是 IT(日报),不是员工。"
    },
    {
      "path": "/admin/finance/budgets",
      "reason": "预算 builder：多维规则编辑器（BU × 科目 × 期间），本就是明确留桌面的配置面"
    },
    {
      "path": "/admin/finance/close",
      "reason": "月结关账台 — 多表联动，桌面面（移动端有 /m/close-tasks 承接个人任务）"
    },
    {
      "path": "/admin/finance/close-cockpit",
      "reason": "关账驾驶舱：跨 6 个信号源的联动大屏，手机屏放不下且无操作价值"
    },
    {
      "path": "/admin/finance/cost-centers",
      "reason": "成本中心映射维护无移动页；成本分摊完整度的处置落点，是多维映射表编辑"
    },
    {
      "path": "/admin/finance/explorer",
      "reason": "财务钻取：任意维度下钻 + 透视表，交互依赖鼠标与宽屏"
    },
    {
      "path": "/admin/finance/external-recon",
      "reason": "外部对账：左右双栏逐行比对差异，手机不可用"
    },
    {
      "path": "/admin/finance/netsuite-gl",
      "reason": "NetSuite GL 明细：宽表 + 多列排序筛选，属桌面财务面"
    },
    {
      "path": "/admin/finance/overview",
      "reason": "财务总览是多图表大屏，cost_efficiency 维度默认处置落点；手机上无对应视图（/m/cloud-cost 只覆盖云账单）"
    },
    {
      "path": "/admin/github?tab=actions",
      "reason": "GitHub 组织治理待办。每周摘要推给 github_admin / global_admin,而这一页的活是**逐条判断**:看一个 handle 的 GitHub 公开画像(姓名 / company / 邮箱)、比对几个候选员工各自的命中理由、然后决定「这是谁」还是「确实是外部人员」—— 一屏要同时容纳证据和选项,手机不是这项工作的设备,而判错的代价是那个人离职时别人的访问权被撤。移除按钮同理:它立刻在 GitHub 上生效。\n刻意留桌面 WebView 而不是做一个 H5 版:一个只能看不能判的移动页,会让人在手机上点开、看不出依据、然后按印象点确认。\n注意摘要里**最适合手机的那一项已经绕开了这一页**:坐席不足那条的按钮直接指向 github.com 的账单页(加坐席只能在 GitHub 做),不经过 Helix 路由,所以不在本契约的覆盖范围里。"
    },
    {
      "path": "/admin/health",
      "reason": "健康控制台（连接器/作业/错误率联动大屏）无移动页；platform_ops 维度默认处置落点"
    },
    {
      "path": "/admin/identity-sync?tab=runs&target=:tid",
      "reason": "身份同步 run 明细：堆栈 + 逐字段 diff，与 tab=targets 同属桌面配置面"
    },
    {
      "path": "/admin/identity-sync?tab=targets&target=:tid",
      "reason": "身份同步台账：target 配置 + run 明细 + 字段映射，是配置面（ADR 明确留桌面）"
    },
    {
      "path": "/admin/identity/consumers",
      "reason": "身份消费方接入审批 — 字段级授权，桌面面"
    },
    {
      "path": "/admin/identity/data-quality",
      "reason": "HRIS 数据质量：批量修正 + 逐字段比对，手机上不可操作"
    },
    {
      "path": "/admin/integrations",
      "reason": "集成与连接器配置面无移动页，且涉及凭证编辑，明确不上手机"
    },
    {
      "path": "/admin/knowledge",
      "reason": "知识库编写面（KB authoring）是桌面权力面；2026-08-17 起 KB 迁到这里，移动端只消费 /m/help"
    },
    {
      "path": "/admin/lifecycle",
      "reason": "生命周期总控台 — 桌面面（人员维度已映射到移动用户详情）"
    },
    {
      "path": "/admin/offboarding?tab=assurance",
      "reason": "「账号终态」—— 离职者在各身份系统的最终状态 + 身份链路心跳。两条 IT 治理告警(离职账号仍未停用 / 目录同步已停止)指向这里。留桌面的理由不是「页面窄」:处理的终点在别人的控制台 —— admin.atlassian.com 的 Identity providers 页,或 Google 管理台。手机上能看到数字却做不了下一步,那种落地页只会让人重新打开电脑。页内的「关闭账号」也是 global_admin 的不可逆操作,不该做成在手机上顺手点的东西。"
    },
    {
      "path": "/admin/permissions?tab=grants&status=pending_approval",
      "reason": "权限审批的 IT 管理台。核过 permission/lifecycle.py:这个 URL 只在 routed_to_it 或升级(is_escalation)时使用,收件人确实是 IT;负责人本人收到的是 /my/todos?tab=permissionApprovals(已登记为 mapped)。"
    },
    {
      "path": "/admin/process-approval",
      "reason": "统一审批处理台:多来源审批的逐条决策 + 表单快照阅读,移动端有观察面 /m/admin/approvals 但没有处理面。(#3121 起后端在发,契约漏登记。)"
    },
    {
      "path": "/admin/procurement/contracts/:cid",
      "reason": "采购合同 — 附件 + 多步审批，桌面面"
    },
    {
      "path": "/admin/procurement/orders/:oid",
      "reason": "采购单：附件预览 + 多步审批 + 行项编辑，桌面面"
    },
    {
      "path": "/admin/role-changes",
      "reason": "转岗复核的 IT 控制台本体（列表 + 云授权决断），与 /admin/rbac 同属留桌面的配置层。注意这条路径目前也被 role_change_review_30d 卡片发给云 scope owner，而 scope owner 未必是管理员、也无权决断 grant —— 那张卡的收件人与落点要在 role_change.scope_review_sweep 收窄时一起修，不在这里用一个猜出来的移动目标盖过去。"
    },
    {
      "path": "/admin/scheduled-jobs",
      "reason": "定时任务台无移动页；定时任务失败率的处置落点，重跑/改 cron 是桌面运维动作"
    },
    {
      "path": "/admin/scheduled-jobs/runs?keyword=:key&status=failed",
      "reason": "定时任务运行台：失败堆栈 + 重跑，运维桌面面（与不带 keyword 的那条同因）"
    },
    {
      "path": "/admin/scheduled-jobs/runs?status=failed",
      "reason": "定时任务运行台：失败堆栈 + 重跑 + 参数编辑，运维桌面面"
    },
    {
      "path": "/admin/security-insights",
      "reason": "安全洞察是多模块洞察页，security_compliance 维度默认处置落点；单项侦测控制各自已有 /m/auditor/* 移动页并已单独映射"
    },
    {
      "path": "/admin/software/cancellations",
      "reason": "软件退订：涉及厂商合同期与账单影响，需桌面核对后操作"
    },
    {
      "path": "/admin/sso-apps?highlight=:aid",
      "reason": "SSO 应用编目：应用注册 + 断言配置，属连接器/配置层（明确留桌面）"
    },
    {
      "path": "/admin/sso-apps?tab=grants&removal=open",
      "reason": "SSO 撤销落地台账,管理台。移动端无对应页,催办与合规事件的处置动作(标记已停用/上传凭证)都在桌面。"
    },
    {
      "path": "/admin/systems?q=:id",
      "reason": "系统归属争议的通知落点（system_registry）。台账的登记与转交在桌面管理面完成，?q= 只是按 slug 预填搜索；移动端无对应页。2026-09-04 由深链扫描器补上 .format() 形态后才可见"
    },
    {
      "path": "/assistant/confirm",
      "reason": "token 落地页：签名 proposal token 即凭证（路由本身是 public，飞书内置浏览器无需 Helix 会话），必须原样渲染。已补入 FeishuMobileGuard 的 TOKEN_ACTION_PATHS —— 此前缺失，卡片「查看并确认」在手机上要先走一次静默 SSO 弹跳"
    },
    {
      "path": "/auditor/evidence-query?posture=:id",
      "reason": "证据取证工作台：宽表 + 多维参数 + 冻结证据包导出，手机上无法使用；且展示具名个人访问历史，属桌面取证面"
    },
    {
      "path": "/auditor/security-questionnaire",
      "reason": "安全问卷：数十题长表单 + 附件上传，手机填写体验不可接受"
    },
    {
      "path": "/auth/feishu/callback",
      "reason": "OAuth 回调中转页：FeishuMobileGuard 显式豁免，重写它会打断登录回调"
    },
    {
      "path": "/bounty",
      "reason": "漏洞赏金管理台是安全团队的多 tab 操作面(回信模板渲染 + 逐字存档 + 档位/预算配置),手机不是这项工作的设备;卡片走桌面 WebView。业务负责人的确认页 /my/bounty/:id 有原生移动端页面。"
    },
    {
      "path": "/bounty/reports/:id",
      "reason": "白帽子报告详情 —— 收件人是安全团队,与已登记的 /bounty 同一个操作面(回信模板渲染 + 逐字存档 + 定级/赏金),手机不是这项工作的设备。业务负责人的确认页 /my/bounty/:id 另有原生移动端页面。"
    },
    {
      "path": "/bounty?intake=1",
      "reason": "赏金收件箱。与已登记的 /bounty 同一个操作面(回信模板渲染 + 逐字存档 + 定级/预算),?intake=1 只是默认打开收件页签,不改变它是桌面工作台这件事。"
    },
    {
      "path": "/bounty?report=:id",
      "reason": "赏金报告的通知落点。与已登记的 /bounty、/bounty?intake=1、/bounty/reports/:id 同一个安全团队操作面（回信模板渲染 + 逐字存档 + 定级/赏金），收件人是安全团队本身；?report= 只是预选一条。2026-09-04 由深链扫描器补上 .format() 形态后才可见"
    },
    {
      "path": "/cloud/grants/renew?token=:tok",
      "reason": "token 落地页：URL 本身即凭证，必须原样渲染（FeishuMobileGuard 的 TOKEN_ACTION_PATHS 豁免）"
    },
    {
      "path": "/cmdb/expiry/ack?token=:tok",
      "reason": "token 落地页：URL 本身即凭证，必须原样渲染（FeishuMobileGuard 的 TOKEN_ACTION_PATHS 豁免）"
    },
    {
      "path": "/compliance/controls",
      "reason": "控制目录（含特权访问复核 drill-in）无移动页；特权复核完成率的处置落点"
    },
    {
      "path": "/me",
      "reason": "IT 宇宙自助页：闲置坐席卡的「保留坐席」动作在这里，移动端 /m/permissions 是只读的 —— 故意不映射，让桌面页在 webview 里渲染，用户才真能保留坐席"
    },
    {
      "path": "/me/github",
      "reason": "个人 GitHub 组织成员资格。目前没有移动端页面;落到 WebView 里的桌面页,好过假装存在一个移动面。有了 /m/... 页面再改成 mapped。"
    },
    {
      "path": "/me/settings?tab=profile",
      "reason": "个人设置 · 基本信息 —— GitHub ID 修改的结果回执落在这里。这个 tab 没有移动端孪生页,而 /m/me 展示的不是同一件事(它没有 GitHub ID 这一格,也没有在途单状态),映射过去等于把人送到一个看不到通知所说内容的页面。webview 里桌面页能正常渲染,与 profile tab 其它通知的现状一致。"
    },
    {
      "path": "/me/wrapped/:year",
      "reason": "年度报告是整页海报 + 分享图，移动端专门版在 PR6 落地"
    },
    {
      "path": "/my/data-access/grants",
      "reason": "⚠️ 这一条是**员工面**却没有移动端页面 —— 数据集授权的到期续期 / 释放 / 服务账号确认卡片(data_access/lifecycle.py)是发给持有人和技术负责人的,他们多数在飞书里点开,会落到桌面路由。之所以先登记为 desktopOnly 而不是猜一个目标:这一族深链带 ?renew= / ?release= / ?confirm= 三种动作参数,移动端要的是三个真的能点的页面,不是一个落地就没有下一步的列表。补移动页时把这四条(含带参形态)一起移到 mapped。"
    },
    {
      "path": "/my/data-access/requests",
      "reason": "数据仓库权限申请：数据集多选、Group/服务账号主体和审批上下文均无可完成的移动端表单；保留桌面 WebView。"
    },
    {
      "path": "/my/data-access/requests/:id",
      "reason": "数据仓库权限申请的单条详情页 —— 和列表页 /my/data-access/requests 同一个理由:数据集多选、Group/服务账号主体与审批上下文没有可完成的移动端表单,保留桌面 WebView。(契约此前只登记了列表路径。)"
    },
    {
      "path": "/oauth/authorize?:q",
      "reason": "OAuth 同意页：URL 携带授权参数，属 TOKEN_ACTION_PATHS 豁免集"
    }
  ]
}
