纵向业务挂载:salary-smartcalc 与 attendance-tally
平台 × 业务接缝
aida-plugins 包 com.caidao.salary-smartcalc(薪资智算)以 plugin.json + contracts/tools.json 声明 hostApi、targets 与工具合同;runtime 自 594ef08c 起由 native sidecar 改为 Python(runtime.kind: python,entry salary_plugin.provider:create_plugin)(如 analyze_salary_logic);包本身不持有服务端 Run 状态。
Desktop Main PluginHost 发现/加载不可变包,经 taskProjections / listProjections 产出 PluginToolProjection 广告。企业 chat 流把投影带进 Agent;resolveExplicitPluginTask 按显式选择解析,失败不得静默退回内置能力。钉点 e2adc9a3c325 起,「用 xxx-cli」若与已安装独立 Skill 同名且没有命中插件,则跳过、交给 Skill 目录,不再当作插件选择失败。
调用 / 回执
PluginCallJournal 相位 admitted → dispatched → settled:dispatch 屏障失败则落 uncertain / failed 回执,禁止重启后盲重放。Agent 侧 parseBoundPluginReply 校验 pluginId/version/toolId/contractDigest(及 optional runtimeRevision)与 outputSchema / maxResultBytes;不一致返回 null。
归属边与非目标
- Owner:包合同在 aida-plugins;Host/Journal 在 Desktop Main;绑定校验在 Agent。
- 非目标:不把 Worker 画进服务端 Runtime;不展开全部薪资算法实现。
- 相关:
capability-plugins、plugin-v2-host-runtime、plugin-run-projection、trust-boundaries。
视图
-
main— 合同 → Host → 投影 → 解析。 -
call-receipt— salary-smartcalc 工具调用与回执校验。 -
fail-plugin-settle— 调用失败 / 回执拒收 / journal settle。 -
fail-manifest— Manifest/投影缺工具。 -
ok-plugin-settle— Plugin journal settle 成功(对偶fail-plugin-settle)。 -
ok-manifest— Manifest/投影命中工具(对偶fail-manifest)。 -
attendance-workflow— 考勤核算(attendance-tally):7 阶段端到端工作流、M01–M11 编译与单向算子 DAG。 -
attendance-desktop-loop— Desktop × 考勤核算(attendance-tally):React 视图桥接、CAS/只读保护与userActionOnly闭环。 -
attendance-rework-compile— 考勤深潜:Rework 局部失效状态机、M01–M11 编译冲突裁决与 M11 额度批次扣减。
成功对偶(与失败链入口相同)
- ok-plugin-settle:
markDispatched→ settle succeeded →parseBoundPluginReply接受。 - ok-manifest:
taskProjections含 skills →resolveExplicit唯一候选。
失败链(深挖)
- fail-plugin-settle:dispatch 屏障失败 → uncertain/failed;
parseBoundPluginReplynull;禁重启盲重放。 - fail-manifest:空投影 / 无 skills →
PLUGIN_TASK_UNAVAILABLE;resolveExplicitPluginTask同码;不静默退回内置。
普通入口冻结已选插件(钉点 e2adc9a3c325)
以前只有显式带 pluginTask 的入口会冻结插件绑定。现在普通 Work 入口也会:路由选中某个插件能力时,从本轮 Desktop 已公布的插件投影里解析出这个插件,冻结绑定,并把唯一匹配的那份投影随 Work 存下。对不上(不是恰好一个、投影里没工具、能力 id 不符)就拒绝受理,错误码 RUNTIME_WORK_PLUGIN_SOURCE_INVALID,不会静默换成别的插件。
Agent 内 verticals/ 接缝(MR-6a~6g,钉点 e2adc9a3c325)
7 个提交把内核里的垂直特例平移到同层 verticals/ 目录:6a 路由注释去垂直词;6b VMS 入职批次路由→gateway/verticals/route-packs.ts;6c 确认/续办工具特征与权限拒绝→orchestrator/**/verticals;6d 入职批次工具与 SOW 定时处理器→runtime/work/verticals、scheduler/verticals;6e VMS 角色守卫→routing/verticals/operation-role-guard.ts;6f 业务对象意图表→routing/verticals/business-intent-catalog.ts;6g Child Kernel 招聘分支→agent-as-tool/verticals/recruit-child-run-policy.ts。
决定:不单独成题、不画新图。 理由:全是行为不变的搬家,没有新运行时边、状态、持久化或信任边界;现有图的节点和箭头都不变。只在这里记下「内核不带垂直知识、由组合根接线」这条约定。残留:child-run-orchestrator.ts L2916 仍有 recruit 字面量。未运行 Agent 测试。
证据与范围
-
aida-plugins·plugins/salary-smartcalc/plugin.jsonL1–38 ·"kind": "python"·a33ce3733365 -
aida-plugins·plugins/salary-smartcalc/contracts/tools.jsonL5–35 ·analyze_salary_logic·a33ce3733365 -
aida-desktop·apps/desktop/electron/plugin-host/plugin-host.tsL195–199 ·PluginHost·4346d79eb364 -
aida-desktop·apps/desktop/electron/plugin-host/plugin-host.tsL625–655 ·taskProjections·4346d79eb364 -
aida-desktop·apps/desktop/electron/agent-loop/enterprise-adapter.tsL92–123 ·preparePluginTools·4346d79eb364 -
aida-desktop·apps/desktop/electron/plugin-host/plugin-call-journal.tsL29–61 ·phase·4346d79eb364 -
aida-desktop·apps/desktop/electron/plugin-host/plugin-call-journal.tsL266–297 ·settle·4346d79eb364 -
aida-agent·packages/agent/src/runtime/local/plugin-task.tsL17–47 ·resolveExplicitPluginTask·e2adc9a3c325 -
aida-agent·packages/agent/src/runtime/local/plugin-task.tsL72–77 ·isStandaloneSkill·e2adc9a3c325 -
aida-agent·packages/agent/src/runtime/local/plugin-tool-receipt.tsL33–64 ·parseBoundPluginReply·e2adc9a3c325 -
aida-desktop·apps/desktop/electron/plugin-host/plugin-host.tsL625–645 ·taskProjections/PLUGIN_TASK_UNAVAILABLE·4346d79eb364 -
aida-desktop·apps/desktop/electron/plugin-host/plugin-call-journal.tsL263–327 ·settle/markDispatched·4346d79eb364 -
aida-desktop·apps/desktop/electron/plugin-host/plugin-host.tsL625–655 ·taskProjections·4346d79eb364
结论来自固定版本的静态源码与合同阅读;实现存在、默认开关和生产启用分别判断。本站代码证据面板列出声明状态与具体限制。
aida-agent·packages/agent/src/gateway/workbench-route-preparation.tsL108–115 ·resolveExplicitPluginTask·e2adc9a3c325aida-agent·packages/agent/src/session/chat-submission-store.tsL759–769 ·RUNTIME_WORK_PLUGIN_SOURCE_INVALID·e2adc9a3c325aida-agent·packages/agent/src/gateway/verticals/route-packs.tsL1–18 ·mountGatewayVerticalRoutes·e2adc9a3c325aida-agent·packages/agent/src/routing/verticals/operation-role-guard.tsL14–47 ·roleGuardOwnsSlotCollection·e2adc9a3c325aida-agent·packages/agent/src/orchestrator/agent-as-tool/verticals/recruit-child-run-policy.tsL28–199 ·prepareChildCapabilityRequest·e2adc9a3c325aida-agent·packages/agent/src/routing/router.tsL2740–2744 ·NO_INTENT_PACKS·e2adc9a3c325
考勤核算(com.caidao.attendance-tally 2.1.16)完整架构拆解(视图 attendance-workflow & attendance-desktop-loop,钉点 d220086aa495)
1. 四大核心设计铁律:AI 负责“语义理解”,Plugin 负责“台账、编译与确定性计算”
- 原话证据链(Fact & Provenance):用户每说一句话,Agent 必须先通过
attendance_task_record_turn登记原话并切分句子(sentenceRanges),将提取出的规则字段与客户原话片段绑定(factId/sourceText);明确政策写入changes,缺失细节登记为ask追问,推断项记为propose,跨领域记为unsupported,严禁大模型脑补默认政策。 - 双模型分离与确定性编译(
RuleModel → CalculationModel):RuleModel(M01–M11):客户审阅确认后的业务政策唯一真源(rule-model-2.0.schema.json)。CalculationModel:由编译器(domain/compiler.py:compile_rule_model)将已确认的RuleModel确定性编译出的算子有向无环图(DAG,calculation-model-2.0.schema.json)。- 本地确定性执行:计算引擎(
domain/runtime.py:CalculationEngine.run)在本地执行 Excel 数据核算,员工原始数据、中间结果与导出工作簿只留在本机。
- 四道人工门禁(
userActionOnly)与乐观锁(expectedRevisionCAS):- 规则确认(
attendance_task_confirm)、员工日计划确认、发起计算(attendance_task_calculate)、模型发布四个关键写操作声明userActionOnly: true,必须由用户在 UI 视图亲自点击并携带宿主签发的userActionReceipt,Agent 无法代点或绕过。 AttendanceTaskWorkbench所有状态修改强制校验expectedRevision === self.revision。
- 规则确认(
- 随时局部返工(Rework)与跨月客户模型复用(Registry & Customer):
- 用户在后续步骤修改规则或替换输入文件时,通过
input_rework/rule_workbook/rule_rebase触发ReworkChangeSet与ReworkProgress,精确标记受波及的下游确认项(如日计划确认、实绩检查),未受影响阶段无需推倒重来。 - 通过
attendance-model-registry(声明suggestedBaseUrl)发布或拉取已确认的CustomerRuleModelSnapshot与CustomerCalculationModelSnapshot,支持跨会话/下月一键复用。
- 用户在后续步骤修改规则或替换输入文件时,通过
2. 端到端 7 阶段工作流与 10 个前端视图(plugin.json + task-tools.json)
插件声明 10 个前端视图(rules、sources、mapping、input_rework、rule_workbook、plan、calculation、results、registry、customer)与 39 个工具,每次调用在 workflow.nextAction 返回唯一确定的下一步指引:
- 阶段 1–2(规则采集 → 审阅确认):自然语言访谈或导入 v3 访谈表(
rule_workbook)→rules视图展开 M01–M11 核对纠错并点击确认 → 编译生成CalculationModel。 - 阶段 3–4(周期与文件导入 → 表头映射与预检):
sources视图设置核算周期与上传花名册/日历/打卡/休假/加班/覆盖声明 →mapping视图完成字段映射与关联表预检。 - 阶段 5–7(员工日计划与实绩预检 → 确定性计算 → 结果复核与发布):
plan视图生成并人工确认《员工日计划表》后执行attendance_task_check_actuals→calculation视图人工点击触发CalculationEngine→results/registry视图查看日明细、月汇总、异常表并导出 Artifact 或发布至模型库。
3. 考勤领域模型(M01–M11)与单向确定性计算顺序
业务规则拆分为 11 个正交子模型(每个子模型统一包含 definitions 可复用定义与 policies 适用范围策略):
| 模块 | 名称 | 核心职责 |
|---|---|---|
| M01 | 日历与考勤周期 | 考勤周期起止边界、政策统一有效期(policyEffectivePeriod)、法定节假日与企业调休历 |
| M02 | 员工资格与适用范围 | 标准花名册字段要求、人员分组(scope)、入离职折算边界 |
| M03 | 班次与排班 | 固定班次、弹性班次(flex_shifts)、跨夜班次、休息时段、最低出勤要求 |
| M04 | 打卡与出勤凭证 | 原始打卡窗口识别、免打卡人群/一次到岗(day_only)规则、打卡证据有效性 |
| M05 | 异常考勤 | 迟到、早退、缺卡、旷工判定阈值、宽限期与计量方式 |
| M06 | 假期与休假考勤 | 假期类型定义、计假单位/取整、休假对出勤义务的免除效果 |
| M07 | 加班与调休 | 工作日/休息日/节假日三类加班方案、来源路由(审批单 vs 打卡识别)、转调休比例 |
| M08 | 特殊出勤 | 出差、外勤、培训等特殊事项对工作日/休息日工时的贡献边界 |
| M09 | 补卡与更正 | 补卡记录替换原始缺卡、次数上限控制、幂等与重算范围 |
| M10 | 工时归集与结算 | 汇总实际出勤、休假、特殊出勤与异常,完成每日评价与周期结算小计 |
| M11 | 额度变动与结转 | 期初余额 + 本期新增(含 M07 加班转调休)汇总,按假种与批次优先级(先到期/先旧后新)扣减,输出非负余额与不足异常 |
- 单向确定性计算 DAG(严禁循环试算与反向推翻):
基准员工日计划 (C04)➔原始打卡筛选与有效补卡 (C09) 及弹性班次顺延 (C04F)➔实际工作事实固定 (C10A)➔休假规范化与出勤义务计算 (M06)➔加班认定与转调休新增 (M07)➔期初与新增额度汇总及按批次扣减 (M11)➔正常出勤/迟到早退/旷工最终裁决与汇总导出 (M05/M10)。例如额度不足只报额度异常,绝不反向推翻已认定的休假或重算加班。
4. Desktop × 考勤 React UI 双端交互与状态保护(视图 attendance-desktop-loop)
-
window.aida桥接与只读横幅(mayAct):前端ui/src/app.tsx挂载在 DesktopPluginMainView中,通过getTaskContext()与只读stateToolId(attendance_view_state)拉取快照;当用户在历史卡片查看旧视图(!task.context.mayAct)时,顶部展示黄色告警横幅“此视图当前仅供查看。请在主任务打开新的操作入口”,禁用全部提交按钮(app.tsxL45–49)。 -
未保存草稿防切页丢稿保护(
task.dirty):ui/src/state/use-task.ts维护编辑缓冲区dirtyCount;当用户在规则或映射界面存在未保存修改(task.dirty === true)而主任务在后台推进requestedView时,app.tsx(L19, L32–35)拦截自动切页并提示“主任务已切换页面,此处仍有未保存输入”,直至用户确认放弃草稿或完成保存。 -
task_provider.py纯路由与准入前确定性拒绝(2.1.16):入口收敛为 55 行纯路由;无规则基线、未采用草稿或缺少连接等准入前拒绝由calculation_rejection.py在零写入前提下显式标记executionState = "completed"(配套AdmissionOutcome.tla),避免 Host 将未发生副作用的业务拒绝误判为unknown;工作簿与回执摘要化使单任务状态体积约减三成。 -
aida-plugins·plugins/attendance-tally/plugin.jsonL1–69 ·com.caidao.attendance-tally/mainView·a33ce3733365 -
aida-plugins·plugins/attendance-tally/runtime/src/attendance_plugin/contracts/task-tools.jsonL215–234 / L1663–1672 / L2054–2063 ·attendance_task_record_turn/userActionOnly·a33ce3733365 -
aida-plugins·plugins/attendance-tally/runtime/src/attendance_plugin/application/task_workbench.pyL77–113 / L1275–1305 ·AttendanceTaskWorkbench/expectedRevision·a33ce3733365 -
aida-plugins·plugins/attendance-tally/runtime/src/attendance_plugin/domain/compiler.pyL486–535 ·compile_rule_model·a33ce3733365 -
aida-plugins·plugins/attendance-tally/runtime/src/attendance_plugin/domain/runtime.pyL176–268 ·CalculationEngine·a33ce3733365 -
aida-plugins·plugins/attendance-tally/ui/src/app.tsxL14–52 ·task.dirty/task.context.mayAct·a33ce3733365 -
aida-plugins·plugins/attendance-tally/ui/src/state/use-task.tsL15–130 ·getTaskContext/submitAction·a33ce3733365
5. Rework 局部失效状态机、M01–M11 编译冲突裁决与额度批次扣减(视图 attendance-rework-compile)
-
Rework 事务与闭包影响分析(
rework_lifecycle.py/rework_impact.py/rework_transaction.py):begin_change与stage_change绑定baseRevision与draftVersion,经过四路预检(preflight_rule_change、preflight_workbook_change、preflight_profile_change、preflight_input_change)。rework_impact.py:analyze_change比较变更前后状态,并沿 M01–M11 模块依赖图求传递闭包(_closure),生成ReworkChangeSet。ReworkTransaction._invalidate(rework_transaction.pyL625–676)仅清除受波及的下游确认位(例如仅更换打卡表时不退回规则确认),并通过rework_input_history.py:preserve_input_baseline保留未受影响的输入基线。
-
M01–M11 编译期冲突检测与引用完整性(
scope_overlap.py/rework_rule_references.py):domain/scope_overlap.py(policies_may_overlap、expressions_disjoint、periods_disjoint)在编译期静态判定同一模块内两条策略的适用人群与有效期是否可能重叠且缺少显式优先级。application/rework_rule_references.py(reference_issues、cycles)校验跨模块实体引用(班次、假种、日历、排班周期)的存在性与有向图无环。
-
M11 额度批次扣减与 Run 依赖快照发布(
quota_period.py/rework_run_publication.py):domain/quota_period.py(apply_policy、expired)将期初余额与 M07 加班转调休新增按假种与批次有效期排序(先过滤已过期批次,再按先到期/先旧后新单向扣减),输出非负余额与不足异常,绝不反向推翻已认定的休假。application/rework_run_publication.py(RunPublication.register/publish)绑定CalculationDependencies快照指纹,并对回执做摘要化保留(rework_receipt_retention.py:compact_receipts)。
-
aida-plugins·plugins/attendance-tally/runtime/src/attendance_plugin/application/rework_lifecycle.pyL137–235 ·begin_change/stage_change·a33ce3733365 -
aida-plugins·plugins/attendance-tally/runtime/src/attendance_plugin/application/rework_impact.pyL154–215 ·_closure/analyze_change·a33ce3733365 -
aida-plugins·plugins/attendance-tally/runtime/src/attendance_plugin/application/rework_transaction.pyL633–698 ·_invalidate/apply·a33ce3733365 -
aida-plugins·plugins/attendance-tally/runtime/src/attendance_plugin/domain/scope_overlap.pyL68–105 ·expressions_disjoint/policies_may_overlap·a33ce3733365 -
aida-plugins·plugins/attendance-tally/runtime/src/attendance_plugin/domain/quota_period.pyL70–105 ·apply_policy/expired·a33ce3733365 -
aida-plugins·plugins/attendance-tally/runtime/src/attendance_plugin/application/rework_run_publication.pyL276–385 ·class RunPublication·a33ce3733365