This repository has been archived on 2026-09-13. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
BPOS-TMP-REPO/apps/api/src/modules/release/contract.ts
T
xcsandClaude Fable 5 7b85a79323 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
2026-08-27 23:20:16 +08:00

104 lines
3.5 KiB
TypeScript

/**
* module: release —— 对外类型(编码规范 §10.1)。
*
* 放行门:草稿态 → 事实态的**唯一通道**。门归系统,启门归人(OS 10)。
*/
import type { ActionIntent, StaffId, TaskId } from '@contracts';
import type {
CriterionCheck,
DeliverableCheck,
LandingOutcome,
LandingVerdict,
PrecheckFinding,
PrecheckItem,
PrecheckReport,
} from './internal/domain/precheck.ts';
export type {
ActionIntent,
CriterionCheck,
DeliverableCheck,
LandingOutcome,
LandingVerdict,
PrecheckFinding,
PrecheckItem,
PrecheckReport,
};
export class PrecheckFailedError extends Error {
constructor(readonly report: PrecheckReport) {
super(`落地预检未过,不发放行卡:${report.findings.map((f) => f.message).join('; ')}`);
this.name = 'PrecheckFailedError';
}
}
export class DeliverablesMissingError extends Error {
constructor(readonly missing: readonly DeliverableCheck[]) {
super(`必交付物缺一不得提交放行:${missing.map((d) => d.label).join('、')}`);
this.name = 'DeliverablesMissingError';
}
}
export type SubmitForReleaseInput = {
readonly taskId: TaskId;
readonly ownerId: StaffId;
readonly humanCallCap: number;
readonly deliverableId: string;
readonly title: string;
readonly basis: ReadonlyArray<{ k: string; v: string }>;
readonly deliverables: readonly DeliverableCheck[];
readonly criteria: readonly CriterionCheck[];
/** 人工验收清单(剧本声明,固定):卡上一条一枚开关,全部达标才能通过 */
readonly checklist?: ReadonlyArray<string>;
/** 报告可修订:AI 拟值已填的表单字段 */
readonly fields?: ReadonlyArray<Record<string, unknown>>;
/**
* 验收页的正文块 —— 与执行工单同一套件,可含**绑台账的可编辑表**。
* 验收是最重的一道门:人得能在成果本身上改,不只是改几个整单级字段。
*/
readonly blocks?: ReadonlyArray<Record<string, unknown>>;
};
export type SubmitOutcome = {
readonly report: PrecheckReport;
/** 预检全过才发卡;这里是发出的验收工单 ID */
readonly workOrderId: string;
};
export type LandInput = {
readonly taskId: TaskId;
readonly ownerId: StaffId;
readonly humanCallCap: number;
readonly selectedPorts: Readonly<Record<string, string>>;
};
export type LandOutcome = {
readonly verdict: LandingVerdict;
/** 落地收敛后才发射的输出口 */
readonly emittedPorts: readonly string[];
readonly ledgerRowsMerged: number;
/** 已落地的事实 —— 输出口发射的载荷取自这里 */
readonly merged: ReadonlyArray<{
readonly domain: string;
readonly object: string;
readonly key: Record<string, unknown>;
readonly values: Record<string, unknown>;
}>;
/** 落地受阻时发出的落地失败卡 */
readonly failureWorkOrderId?: string;
};
export type ReleaseService = {
/** 登记写类动作意向(入参冻结,存入草稿态) */
registerIntent(taskId: TaskId, intent: Omit<ActionIntent, 'taskId' | 'state'>): Promise<ActionIntent>;
listIntents(taskId: TaskId): Promise<ActionIntent[]>;
/** 预检 → 全过才发验收工单;不过即抛 `PrecheckFailedError`,打回环内修正 */
submitForRelease(input: SubmitForReleaseInput): Promise<SubmitOutcome>;
/** 只跑预检不发卡 —— 环内随时可看「还差什么」 */
precheck(taskId: TaskId): Promise<PrecheckReport>;
/** 放行通过即刻落地:草稿合并 + 动作执行(附幂等键)→ 收敛才发射输出口 */
land(input: LandInput): Promise<LandOutcome>;
};