harness 与工作台同日修:数据工单确认即入库 · 叫了人不再自动推进(两道结构闸)· 审核卡 = 终局验收卡结构 · 验收清单人点达标 · 迟到守卫不丢放行裁决 · 画面跟着这一拍发出去的卡走 · 成果详情只翻页 · 占位居中 · 进度条

human-tool / ledger / loop-engine / release / task / interaction 六模块与 app 层(desk 路由、engines、consumers、
data-order-landing、case-stamp、reset-runs、seed-activities、容器与 server 装配),web 的 desk-task
(ViewRegion / chat-bubbles / review-face)与 app.css、ui-kit 图标;契约 card / manifest;
迁移 0034_task_seq 与迁移日志;api-report 快照;CLAUDE.md 快照、debt、活动开发规范、HTML 报告规范同步。
逐条口径见 CLAUDE.md 快照(2026-08-27 下午至晚)。另一会话做的,一直留在工作树没入库;与同批另两条提交互相依赖。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0167qWjeyBwvfdGovd7FWbCu
This commit is contained in:
xcs
2026-08-27 23:20:16 +08:00
co-authored by Claude Fable 5
parent 909b1fe4b7
commit 7b85a79323
79 changed files with 3903 additions and 1297 deletions
@@ -316,7 +316,10 @@ create table if not exists ${DRAFT_TABLE} (
tombstone boolean not null default false,
updated_at timestamptz not null default now(),
primary key (task_id, domain, object, key_hash)
);`;
);
-- 已落地记号(2026-08-27,数据工单确认即入库):非空 = 这一行已在一道更早的门上并进正式表,
-- 放行时不再写它。加列走 if not exists —— 这张表由启动时的 DDL 自建,不走迁移。
alter table ${DRAFT_TABLE} add column if not exists landed_at timestamptz;`;
type DraftRow = {
task_id: string;
@@ -326,6 +329,7 @@ type DraftRow = {
patch: LedgerRow;
baseline: LedgerRow;
tombstone: boolean;
landed_at: Date | string | null;
};
function toEntry(row: DraftRow): DraftEntry & ObjectRef {
@@ -336,6 +340,7 @@ function toEntry(row: DraftRow): DraftEntry & ObjectRef {
patch: row.patch,
baseline: row.baseline,
tombstone: row.tombstone,
landed: row.landed_at !== null && row.landed_at !== undefined,
};
}
@@ -366,6 +371,8 @@ export function createDraftStore(runner: Queryable): DraftStore {
-- 后续步新写的字段就没有基线,冲突检查会把它们一律当成「他单改过」。
baseline = excluded.baseline || ${DRAFT_TABLE}.baseline,
tombstone = excluded.tombstone,
-- 再写一笔就不再是「已落地」:新的这一笔要等它自己的门(放行)
landed_at = null,
updated_at = now()`,
[
taskId,
@@ -394,6 +401,13 @@ export function createDraftStore(runner: Queryable): DraftStore {
[taskId, ref.domain, ref.object, keyOf(key)],
);
},
async markLanded(taskId, ref, key, baseline) {
await runner.query(
`update ${DRAFT_TABLE} set landed_at = now(), baseline = $5
where task_id = $1 and domain = $2 and object = $3 and key_hash = $4`,
[taskId, ref.domain, ref.object, keyOf(key), JSON.stringify(baseline)],
);
},
async clear(taskId) {
await runner.query(`delete from ${DRAFT_TABLE} where task_id = $1`, [taskId]);
},