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/api-report/apps/api/src/modules/release/contract.d.ts
T
xcsandClaude Fable 5 cec19adc85 fix(engine): 打不回的验收卡不摆那颗钮 —— 全 auto 的放行步没有模型能接住那句意见
用户:「评审放行与落账确认这一步的验收卡不应该有重做的选项,因为这里都没有接入 ai」。

W05 的 T_release 整个由配方跑完(guide 是空串,不问模型),件又是只读的 ——
打回之后没有任何东西能接住那句意见:配方只会原样再提交一次,撞在「打回之后台账没动过
就不许再提交」那道闸上,连撞两拍落成一张「连续撞在同一条判据上」的兜底卡。
一颗按下去只会把单子推进死胡同的钮,不如不摆(墙要配路;没有路就别立那扇门)。

· 契约:AcceptanceWorkOrder.redoable(不写 = 打得回,老卡老行为);
· 装配层按放行那一步的声明现算 —— releaseRedoable 纯函数(有 auto 且 guide 空 → 打不回;
  半 auto 与模型驱动照旧打得回,那儿真有模型会读意见),与 decisionCardFace /
  executionCardVariant 同一种做法、同一个测试位;
· 卡面收起理由框与那颗钮,换一句真路:「这一步只落账,退不回上一步 —— 有异议就别确认,
  去终止这一单重开」;
· **服务端才是门**:redoable:false 的卡收到非 pass 的回传当场拒(redo-unavailable),
  直调 API 绕不过;拒回把真路指出来。

S3 结论审核那张审核卡不受影响 —— 它的重做真会带着意见重判(昨夜那一轮)。
测:card-rules 3 条 + releaseRedoable 4 条,两处变异验证;e2e w05 5/5 released、被拒 0。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LKMZDwMbyKzjw6Hembwvet
2026-09-01 01:34:16 +08:00

78 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 declare class PrecheckFailedError extends Error {
readonly report: PrecheckReport;
constructor(report: PrecheckReport);
}
export declare class DeliverablesMissingError extends Error {
readonly missing: readonly DeliverableCheck[];
constructor(missing: readonly DeliverableCheck[]);
}
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>;
/** 这张卡打回得了吗 —— `false` = 打回之后没人接得住(见契约 `AcceptanceWorkOrder.redoable`) */
readonly redoable?: boolean;
/** 报告可修订: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>;
};