人手改的那一手真正落得下去;界面不撒谎那几处补齐

手改是**兜 AI 的错**的那一手 —— 这一轮把它从「摆在那儿但落不了地」做成真的:

件上就地改
· 保存**按地址收**,不看当下那张卡:载荷从前借道工单的 `blocks[i]` 取列名,
  于是熔断卡(没有 blocks)在屏上时,人补的那一格一个字都送不出去 ——
  而他要补的恰恰是把这一单卡住的那个必填格。授权面改由活动清单的台账声明把关。
· **能增删行**:错不止「这一格填错了」,还有「这一行不该在」与「漏了一行」。
  删挂记号不当场抹掉(看得见、可后悔),且**删要说出来**(`drops`)——
  「没回传就是删了」会把一次不完整的回传变成一次删表。
· **必填没填按不下提交**:与放行门 L1 同一个数同一套算法;闸上摆出差在哪一行哪一格。
· 只写真改了的那几行 —— 改一格却留「修订 4 行」的痕,那句话是假的。

判据与门
· 裁量判据带谓词时**谓词说了算**:「选填缺口已补齐」基座数得出来,
  人填好的目标价它照样判「客户未提供」的毛病由此消掉。
· 验收卡判据**读时现算** —— 人在成果件上补一格,判据跟着变。
· 放行门认「**办完了没有**」不认「有人写过」:从前写个 `false` 就把门推开,
  于是一单没打标就进了放行门。三个数全由基座现数。
· 拒回把「活没干完」说成「数或行对不上」的毛病:判据点名的表一行都没写时直说那一步没办。
  **指向两扇打不开的门,比不指还糟。**

界面不撒谎
· 日志只有三色:负责人绿 · 智能体蓝 · 系统灰(归侧五种是度量的分法,不是给人看的)。
· 验收收口答两件事:落了什么(按**交付物**点名,一份成果的几张表并成一行)、
  往哪儿去(转出哪一口、带过去哪些字段);一个口都没发就直说到此为止。
· 签完到收尾之间那一段有自己的话「字已签下,正在落地」—— 中间态本来就该说出来,只是要说对。
· 消息不再被内部事件刷屏:只有从通道进来的件才谈得上「无人认领」。
· 建客户公司与联系人**一次确认落两行**;联系人编码自增不问人;卡面摆表的人读名。

A1 三案例端到端全 released:全 A 类直通 12 拍 / 客户点名跳一条 10 拍 / 新客户缺必填 14 拍。
五道门禁全绿(971 passed)。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JsTDjoHovERXyy6Wmw1ALp
This commit is contained in:
2026-08-02 13:41:44 +08:00
co-authored by Claude Opus 5
parent 94f1c7a4ef
commit 259192f736
228 changed files with 27850 additions and 2847 deletions
+84
View File
@@ -24,6 +24,27 @@ export const contractInputSchema = z.object({
/** message:委托消息(自然语言),可为空;**不得携带扩大授权的效力** */
messageAllowed: z.boolean().default(true),
messageHint: z.string().optional(),
/**
* **这一单是被一封信叫起来的** —— 声明入参里哪几个字段合起来是那封来件。
*
* 声明了,基座在起单那一刻就把它归进任务的**沟通记录**(工作台那一屏),
* 原件与附件一并存下:谈过什么、什么时候谈的,回头查得到。
*
* 为什么是**声明**而不是活动跑起来之后再做一遍:这件事没有临场判断的成分 ——
* 「入参的 subject 就是来件主题」是活动作者写清单时就知道的事实。
* 交给模型每单认一遍,是拿一整拍的 token 去换一个常量。
* 值填的是**入参里的字段名**,不是字面内容。
*/
inboundComm: z
.object({
channel: z.string().default('mail'),
/** 对方是谁 —— 填入参里那个字段的名字(如 `customerEmail`) */
partyField: z.string().min(1),
subjectField: z.string().optional(),
bodyField: z.string().optional(),
attachmentsField: z.string().optional(),
})
.optional(),
});
export type ContractInput = z.infer<typeof contractInputSchema>;
@@ -34,6 +55,19 @@ export const outputPortSchema = z.object({
/** 交付物 schema —— 调用方仅凭口名与 schema 即可衔接下游 */
payload: jsonSchemaSchema,
description: z.string().optional(),
/**
* **这一口什么时候走** —— 对任务视图求值的 S-FEEL 谓词(选择组内**按序求值,首个命中即出**)。
*
* 组内每一口都写了 `when`,去向就是**算出来的**:放行时基座自己判,
* 卡上只如实告诉人走哪一口、凭哪一条,不摆成选择题。
* 「这一单往哪走」多半是台账里那几个数的函数(有没有 C 类、有没有 B 类)——
* 让人凭印象点一下,等于把一个可回放的判定换成一次不可回放的手感;
* 让模型选,又多一处它可以说了算的地方。
*
* 有一口没写,整组就算不出来,退回「人选一口」那条老路(不是所有分支都算得出来:
* 议价的 成交/有异议/拒绝 就得人裁)。
*/
when: z.string().optional(),
});
export type OutputPort = z.infer<typeof outputPortSchema>;
@@ -59,6 +93,35 @@ export const requiredDeliverableSchema = z.object({
label: z.string(),
/** 缺一不得提交放行 —— 验收工单「成果清单」的来源 */
schema: jsonSchemaSchema.optional(),
/**
* 「有没有产出」的**可机检依据**:台账地址 `域.对象`,该地址在任务视图里有行即算有。
*
* 不给依据的话,「缺一不得提交放行」就只能靠活动自报 —— 自报等于没有门。
* 声明了地址,预检就能自己数行数:活动说交付了、台账里一行没有,当场拒收。
*/
ledger: z.string().optional(),
/**
* **这份成果由哪几张表承载**(2026-08-02 用户当场指出:「料号分类表和受理结论
* 不都是包含在询价受理记录的结构里的吗,为啥单独陈列?」)。
*
* 一份成果常常不止一张表:A1 交出的是**一份询价受理记录**,而它由受理记录、
* 料号分类表(判据来源)、受理结论(结论栏)三张表共同承载。
* 从前三张表各占一条 `requiredDeliverables`,人在成果面上就看到三样东西 ——
* 而在业务上他只拿到一份。
*
* 声明了它,落地那一屏按**交付物**点名,三张表的行数并成一行;
* 不声明就退回 `ledger` 那一张 —— 老清单不必改一个字。
*/
ledgers: z.array(z.string()).optional(),
/**
* **验收页上让人就地改的那几列** —— 台账列名,顺序即列序。
*
* 验收是这一单最重的一道门:人得能在**成果本身**上改,而不只是在旁边几个整单级字段上改。
* 给了这几列,基座在放行卡上铺一张绑着 `ledger` 的可编辑表(整份行都在),
* 人改完由基座写回草稿层、随放行合并 —— AI 不经手。
* 不给就没有这张表:哪些列该让人动,是写清单时就该定的事,不是临场发挥。
*/
editableAtRelease: z.array(z.string()).optional(),
});
export type RequiredDeliverable = z.infer<typeof requiredDeliverableSchema>;
@@ -133,6 +196,27 @@ export const sevenPartContractSchema = z.object({
output: outputPortsSchema,
requiredDeliverables: z.array(requiredDeliverableSchema).default([]),
acceptanceCriteria: z.array(acceptanceCriterionSchema).default([]),
/**
* **放行时人可当场改的值** —— 验收报告「AI 已填好、可编辑」改的就是这几个。
*
* 它是**设计期的事实**,和验收判据一样:哪几个值该让负责人有机会覆盖、
* 改完落回哪个台账地址,由做这个活动的人一次定死,过安装审。
* 让 Agent 每单临场重述一遍是不可靠的 —— 实测它会漏(说了「可直接编辑」而没给字段),
* 而漏掉的后果是验收报告只能看不能改,人工修订形同虚设。
*
* `ai` 不在这儿:拟值是**运行期**的事实 —— 放行前由基座从台账现读活动写下的那个值,
* 不让模型重述一遍(重述就会和台账里的值不一致,而以哪个为准说不清)。
*/
revisableAtRelease: z
.array(
z.object({
key: z.string().min(1),
label: z.string(),
/** 改完落回哪儿:`域.对象`;只改本单在该对象的那一行 */
ledger: z.string().min(1),
}),
)
.default([]),
prohibitions: z.array(prohibitionSchema).default([]),
authorization: authorizationBoundarySchema,
resources: resourceDeclarationSchema,