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
+31 -3
View File
@@ -48,9 +48,29 @@ export type DraftWrite = {
readonly patch: LedgerRow;
readonly tombstone?: boolean;
};
/**
* **放行写的范围**(2026-08-27,数据工单确认即入库)。
*
* 不给 = 整单放行:草稿层全部并进正式表、清空。
* 给了 = 只并这几张表 —— 它们的门不是放行卡,是**数据工单的确认**(那张卡的提交闸
* 盯的就是这几张表:必填齐了才按得下确认,确认那一刻就入库)。并过的行**留在草稿层、
* 打上已落地记号**:它仍是本单写下的行(任务视图 / `mine:` / `_rows` 照旧认它),
* 只是整单放行时不再写它、不再为它抛事件。
* `cause` 落进数据事件的归因(`ledger-write:<cause>`),回看时认得出是哪张卡签下去的。
*/
export type ReleaseScope = {
readonly only: readonly ObjectAddress[];
readonly cause: string;
};
export type ReleaseWriteResult = {
readonly mergedRows: number;
readonly emittedEvents: number;
/**
* **早已落地、这次不再写的行数**(2026-08-27)—— 数据工单确认时并进去的那几行,
* 整单放行时只把它们当事实读回来(出口载荷要它们),不再写、不再抛事件。
* 放行痕上要分开说:「合并 N 行」里若混着这几行,那句话就多报了。
*/
readonly landedEarlierRows: number;
/**
* **试跑单被挡下的主数据行数** —— 合到出参里去,是因为界面不撒谎:
* 放行痕上写「合并 N 行」而其中几行根本没进表,那句话就是假的。
@@ -100,7 +120,13 @@ export type LedgerService = {
address: ObjectAddress;
key: Record<string, unknown>;
}): Promise<boolean>;
releaseWrite(taskId: TaskId): Promise<ReleaseWriteResult>;
/**
* 放行写。`scope` 见 `ReleaseScope`:不给 = 整单;给了 = 只并那几张表(数据工单确认那一道门),
* 并过的行留在草稿层打记号。**不是第四种写**,也不是绕门:同一条冲突检查 → 原子合并 → 抛事件的路,
* 只是门换成了那张卡的确认闸 —— 落哪几张表由发卡的人说了算(`gateLedgers`),调用方指不了别的表进来
* (清单没声明的表这一单本就写不进草稿层)。
*/
releaseWrite(taskId: TaskId, scope?: ReleaseScope): Promise<ReleaseWriteResult>;
/** 正式版查询 —— 跨任务只见过门的事实 */
query(query: LedgerQuery): Promise<LedgerPage>;
/** 任务视图 = 正式版 + 本任务草稿层 */
@@ -115,8 +141,10 @@ export type LedgerService = {
object: string;
key: Record<string, unknown>;
patch: Record<string, unknown>;
/** 已在数据工单确认那一道门上并进正式表(见 `ReleaseScope`);仍是本单写下的行 */
landed: boolean;
}>>;
/** 落地预检第五项:数据冲突检查 */
checkConflicts(taskId: TaskId): Promise<ConflictFinding[]>;
/** 落地预检第五项:数据冲突检查;`only` 给了就只查那几张表(与 `releaseWrite` 的 scope 同一口径) */
checkConflicts(taskId: TaskId, only?: readonly ObjectAddress[]): Promise<ConflictFinding[]>;
discardDrafts(taskId: TaskId): Promise<void>;
};
+1 -1
View File
@@ -1,7 +1,7 @@
/**
* module: ledger —— 唯一出口。只做 re-export,不写逻辑(编码规范 §10.1)。
*/
export type { ConflictFinding, DraftWrite, LedgerAddress, LedgerKey, LedgerPage, LedgerQuery, LedgerRow, LedgerService, MaterializedObject, MergeConflict, MergeNotice, MergedObject, ObjectAddress, ObjectDeclaration, ReleaseWriteResult, SchemaApplyResult, SystemWrite, WriteKind, } from './contract.ts';
export type { ConflictFinding, DraftWrite, LedgerAddress, LedgerKey, LedgerPage, LedgerQuery, LedgerRow, LedgerService, MaterializedObject, MergeConflict, MergeNotice, MergedObject, ObjectAddress, ObjectDeclaration, ReleaseScope, ReleaseWriteResult, SchemaApplyResult, SystemWrite, WriteKind, } from './contract.ts';
export { DraftConflictError, ObjectNotMaterializedError, SchemaConflictError } from './contract.ts';
export type { Clock, DraftStore, EventPublisher, IdGenerator, LedgerStore, ObjectRef } from './port.ts';
export type { LedgerServiceDeps } from './internal/usecase/ledger-service.ts';
+9
View File
@@ -77,5 +77,14 @@ export type DraftStore = {
* (唯一能改的是那个数,改了别的判据又不对),13 次拒回、23 拍、234k token 才熔断。
*/
drop(taskId: string, ref: ObjectRef, key: LedgerKey): Promise<void>;
/**
* 给本单草稿层的一行打上「已落地」记号(2026-08-27,数据工单确认即入库)。
*
* 那一行刚经一道更早的门并进了正式表:条目**留着**(它仍是本单写下的行,
* 任务视图 / `mine:` / `_rows` 照旧认它),只是放行时不再写它。
* `baseline` 换成落地后正式表里的值 —— 之后再往这一行写一笔(记号随之擦掉),
* 冲突检查比的才是「我改之前表里是什么」,而不是落地前那份早已过时的基线。
*/
markLanded(taskId: string, ref: ObjectRef, key: LedgerKey, baseline: LedgerRow): Promise<void>;
clear(taskId: string): Promise<void>;
};