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

手改是**兜 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
+24
View File
@@ -0,0 +1,24 @@
-- 工具未命中转人(2026-07-30,§6.2):**人是工具的一种实现**。
-- 系统里没有这件工具(无契约,或有契约无实现)时,不报错、不空转 —— 开一张执行卡请人做,
-- 人填回的表单值就是这次调用的出参,下一拍 invoke 直接取到。
-- 面向人的作业指导段:与面向 AI 的 description 分开写,随包版本冻结。
alter table sys.tool add column guide jsonb;
create table sys.tool_handoff (
id text primary key,
task_id text not null,
tool text not null,
-- 内容地址(工具 + 入参指纹):同一次调用只问人一次,重问拿同一份答案。
-- 没有它,Loop 每拍都会为同一件事再发一张卡。
call_key text not null,
input jsonb not null,
work_order_id text not null,
state text not null default 'pending',
-- 人填回的值 = 工具出参
output jsonb,
created_at timestamptz not null default now(),
answered_at timestamptz
);
create unique index tool_handoff_call_key on sys.tool_handoff (task_id, call_key);
create index tool_handoff_order_idx on sys.tool_handoff (work_order_id);
+6
View File
@@ -0,0 +1,6 @@
-- 任务起单来源(2026-07-30):这一单是从哪儿起的 —— 流程节点 / 登记直起 / **设计台试跑**。
-- 试跑单必须认得出来:「仿真不是生产,试跑留下的东西不该在库里、在别人工作台上过夜」,
-- 而工作流那侧靠 source->>'ref' = 'testbed' 认,任务这侧从前没有对应的记号 ——
-- 于是「试跑一个活动」(不挂工作流)起出来的单与登记直起单长得一模一样,拔不掉也认不出。
alter table sys.task add column origin text;
create index task_origin_idx on sys.task (origin) where origin is not null;
+29
View File
@@ -0,0 +1,29 @@
-- 试跑日志(2026-07-30):**运行数据不过夜,观测记录要留下**。
--
-- 「停止仿真 = 连根拔掉」这条不变 —— 试跑起的是真任务,不该在别人工作台上过夜。
-- 但拔掉的同时把这一单的**观测快照**存下来:逐拍轨迹、写下的台账草稿、发过的卡、
-- 预算读数与终态。开发活动是反复试的活,「上一版跑了几拍、卡在哪一步」正是
-- 要拿来比对的东西;拔干净等于每改一次就把上一次的账一并烧了。
--
-- 存的是**快照不是外键**:原任务早已不存在,这里的 task_id 只作编号回溯。
create table sys.testbed_run (
id text primary key,
-- 两种试法:activity(单活动)/ package(整条流程包)
kind text not null,
subject text not null,
-- 试的是谁:activityId 或 packageId
target text not null,
task_id text,
workflow_id text,
-- 终态名;null = 人中途停的(那也是一次值得留的账)
terminal text,
reason text,
used jsonb not null default '{}'::jsonb,
caps jsonb not null default '{}'::jsonb,
trail jsonb not null default '[]'::jsonb,
drafts jsonb not null default '[]'::jsonb,
cards jsonb not null default '[]'::jsonb,
started_at timestamptz,
archived_at timestamptz not null default now()
);
create index testbed_run_time_idx on sys.testbed_run (archived_at desc);
+16
View File
@@ -0,0 +1,16 @@
-- 上传件 —— 附件要能真正进活动,文件本身就得留着。
--
-- 存两样:**原字节**(留得住才叫「真实的文件」,人回头点得开)与**读出来的文本**
-- (活动那一侧读得懂的只有文字)。读不出文本的类型 text 留空、note 说明为什么。
create table sys.upload (
id text primary key,
name text not null,
content_type text not null,
size integer not null,
bytes bytea not null,
text text,
note text not null default '',
uploaded_by text,
uploaded_at timestamptz not null default now()
);
create index upload_time_idx on sys.upload (uploaded_at desc);
+20
View File
@@ -0,0 +1,20 @@
-- 沟通记录 —— 一单往来的**原件存档**。
--
-- 「跟客户、供应商往来的邮件和消息按单归档」这件事,从前只有一屏诚实的空态:
-- 数据在 channel / event 里确有,按单的投影一直没做。现在有了落点。
--
-- 进来的那一封(direction='in')是**开案的那份料** —— 活动的入参就是它;
-- 出去的(direction='out')是放行后系统真发出去的件。两向同表,按时刻排。
create table sys.task_comm (
id text primary key,
task_id text not null,
at timestamptz not null default now(),
direction text not null, -- 'in' | 'out'
channel text not null, -- 'mail' | 'im' | 'phone' | …
party text not null default '',-- 对方(邮箱 / 账号 / 号码)
subject text not null default '',
body text not null default '',
attachments jsonb not null default '[]'::jsonb,
note text not null default ''
);
create index task_comm_task_idx on sys.task_comm (task_id, at);
+22
View File
@@ -0,0 +1,22 @@
-- 台账对象的**性质**落成一等事实(2026-07-31)。
--
-- 起因是一次自找的性能退化:治理台「数据域」那一屏要按性质(单据/主数据/派生)分区,
-- 而性质只写在活动清单里 —— 于是路由每次请求都去把 12 个活动的清单捞回来重建一遍。
-- `manifestOf` 是 `select *`:拉该活动**所有版本**的清单加产物,再整份 zod parse。
-- 光 quote-intake 一个就是 26 个版本、798 kB,一次请求约 1.5 MB JSON ——
-- 热连接 73ms,并发八次就掉到 350ms,而慢请求占住浏览器连接,点别的页跟着排队。
--
-- 物化的东西就该记在物化侧:表建出来的那一刻性质就定了,不必每次去清单里问。
-- 与人读名同一个道理 —— 那个落在表注释上,这个落在这张小表上
-- (性质不是列属性,注释挂不上,故单立一张)。
--
-- `__` 前缀:与 `ledger.__draft` 同一约定,`listObjects` 按前缀把它排除在数据对象之外。
create table if not exists ledger.__object_meta (
domain text not null,
object text not null,
kind text not null default 'record',
case_key text,
primary key (domain, object)
);
comment on table ledger.__object_meta is '台账对象性质:record 单据 / master 主数据 / derived 派生';
+11
View File
@@ -0,0 +1,11 @@
-- 沟通记录的**未读**(2026-07-31 用户定)。
--
-- 一封客户来件落进沟通记录之后,人是"看没看过"这件事从前没人记 ——
-- 于是这一屏永远一个样:新到的信和三天前的信长得一模一样,人只能靠时间戳自己比。
--
-- `read_at` 为空 = 未读。**不由打开页面自动清**:自动清等于替人宣布"你看过了",
-- 而他可能只是路过那个页签。用户定的口径是**按钮说了算** ——
-- 标记已读/未读都由人按,气泡计数跟着那一下走。
alter table sys.task_comm add column if not exists read_at timestamptz;
comment on column sys.task_comm.read_at is '读过的时刻;空 = 未读(只由人按按钮改,不随打开页面自动清)';
+11
View File
@@ -0,0 +1,11 @@
-- 记住**这一帧用的是哪张模版**(2026-08-01)。
--
-- 件是**投影**,而从前只存渲染好的 HTML —— 那一帧就成了快照。
-- 人在件上改完几格按保存,只读那份跟着变了(那是他自己敲的),
-- 而由数据算出来的东西(类徽 A/B/C、分布条、结论横幅那条去向)全停在渲染那一刻:
-- 屏上一半新一半旧。**那不是没更新,是界面在撒谎。**
--
-- 存下模版名,才重得出来:数据一变,同一张模版用新数据再渲一遍(见 `views.repush`)。
alter table sys.task_view add column if not exists template text;
comment on column sys.task_view.template is '这一帧用的模版名 —— 数据变了要按同一张重渲(件是投影,不是快照)';
+57 -1
View File
@@ -148,6 +148,62 @@
"when": 1785130115173,
"tag": "0020_paradigm_retired",
"breakpoints": true
},
{
"idx": 21,
"version": "7",
"when": 1785130116173,
"tag": "0021_tool_handoff",
"breakpoints": true
},
{
"idx": 22,
"version": "7",
"when": 1785130117173,
"tag": "0022_task_origin",
"breakpoints": true
},
{
"idx": 23,
"version": "7",
"when": 1785130118173,
"tag": "0023_testbed_log",
"breakpoints": true
},
{
"idx": 24,
"version": "7",
"when": 1785130118174,
"tag": "0024_upload",
"breakpoints": true
},
{
"idx": 25,
"version": "7",
"when": 1785130118175,
"tag": "0025_task_comm",
"breakpoints": true
},
{
"idx": 26,
"version": "7",
"when": 1785130119175,
"tag": "0026_object_meta",
"breakpoints": true
},
{
"idx": 27,
"version": "7",
"when": 1785130120175,
"tag": "0027_comm_read",
"breakpoints": true
},
{
"idx": 28,
"version": "7",
"when": 1785130120176,
"tag": "0028_view_template",
"breakpoints": true
}
]
}
}