/** * 落地预检 —— 纯判定,零 IO(编码规范 §5.3;语义出处 OS 7.3,AM 06)。 * * 「**检查可落地,才允许放行**:发放行卡前,系统对全部动作意向执行预检 —— * ①入参 schema 校验 ②工具可用(未停用)与授权有效 ③连接可达 * ④目标预校验(工具契约含 validate 能力时)⑤数据冲突检查。 * 预检全过才发放行卡,卡面呈现的即已验证的动作清单;预检不过的意向打回环内修正,**不发卡**。」 */ import type { AcceptanceLevel } from '@contracts'; export const PRECHECK_ITEMS = [ 'input-schema', 'tool-available', 'connection-reachable', 'target-validate', 'data-conflict', ] as const; export type PrecheckItem = (typeof PRECHECK_ITEMS)[number]; export const PRECHECK_ITEM_LABEL: Readonly> = { 'input-schema': '入参 schema 校验', 'tool-available': '工具可用与授权有效', 'connection-reachable': '连接可达', 'target-validate': '目标预校验', 'data-conflict': '数据冲突检查', }; export type PrecheckFinding = { readonly item: PrecheckItem; /** 关联的动作意向;数据冲突项无意向,留空 */ readonly intentId?: string; readonly message: string; }; export type PrecheckReport = { /** 全过才可发卡 */ readonly passed: boolean; readonly findings: readonly PrecheckFinding[]; /** 已验证的动作清单 —— 通过时即验收工单卡面呈现的那份 */ readonly verified: ReadonlyArray<{ id: string; label: string; effect: 'read' | 'write'; detail: string }>; }; export function summarize( findings: readonly PrecheckFinding[], verified: PrecheckReport['verified'], ): PrecheckReport { return { passed: findings.length === 0, findings, verified }; } /* ── 必交付物与判据 ─────────────────────────────────────────────────── */ export type DeliverableCheck = { readonly key: string; readonly label: string; readonly present: boolean }; export type CriterionCheck = { readonly key: string; readonly label: string; readonly level: AcceptanceLevel; readonly pass: boolean; /** 裁量项(L3/L4)裁过没有 —— 机检项与 L5 不带这一维 */ readonly settled?: boolean | undefined; /** 裁断的理由:裁成「不满足」时,这句话才是签字的人要看的东西 */ readonly rationale?: string | undefined; }; /** 必交付物**缺一不得提交放行**(AM 01) */ export function missingDeliverables(checks: readonly DeliverableCheck[]): DeliverableCheck[] { return checks.filter((c) => !c.present); } /** * 判据全绿只是**可提交**,完成只出自放行通过(AM 10.2)。 * L1/L2 由引擎预检;L3–L5 按分级执行 —— L5 是责任关,不参与「可提交」判定。 */ export function submittable(checks: readonly CriterionCheck[]): boolean { return checks.filter((c) => c.level !== 'L5').every((c) => c.pass); } /* ── 落地收敛 ───────────────────────────────────────────────────────── */ export type LandingOutcome = { readonly id: string; readonly ok: boolean; readonly error?: string; readonly retryable: boolean; }; export type LandingVerdict = /** 落地收敛 —— 输出口可发射,终态方成「放行完成」 */ | { readonly kind: 'converged' } /** 落地受阻 —— **运行态**不是终态;走落地失败卡,处置后仍收敛于终态名录 */ | { readonly kind: 'blocked'; readonly failures: readonly LandingOutcome[] }; /** * 「放行通过即刻执行(附幂等键);落地收敛,输出口才发射 —— 下游只见落地完成的任务。 * 已成动作留存**不回滚**。」 */ export function landingVerdict(outcomes: readonly LandingOutcome[]): LandingVerdict { const failures = outcomes.filter((o) => !o.ok); return failures.length === 0 ? { kind: 'converged' } : { kind: 'blocked', failures }; } /** 幂等键:任务 × 意向 —— 重放不重复触达世界(OS 7.3) */ export function idempotencyKey(taskId: string, intentId: string): string { return `${taskId}:${intentId}`; }