M4: 范式引擎与任务运行时

skill-engine(L4):载方法不载权力(白名单外工具即拒)、结晶片段经 ToolInvoker 留痕、
  装配入信封、技能目录渐进披露

flow-engine(L5):四种步型、确定性谓词跳步、重试与声明给定的兜底、
  异步步即监听(时限必配)、写类工具登记动作意向、步序位置持久

loop-engine(L5):自研 CMMN 子集解析器(表外构件直接报错,子集封顶可机器证明)、
  两副标准生命周期与迁移拓扑(引擎不得私改)、Enabled ≠ Active、
  语义性前提标待裁量评估(引擎不代裁量)、DMN 确定性求值 + 命中行留痕、
  DRD 缺口演绎与拓扑序、双向驱动与交集导航(断点即人环)、三型行动、
  终局唯放行与 Harness

task(L6):终态五名裁定(released 唯一成功)、Harness 预算环外强制与停滞熔断
  (监听中是健康态)、控制三语义(叫停不是终态,记最重档纠正)、改派留痕通知双方、
  断点续跑三份持久状态、封卷触发蒸馏钩子

301 个测试通过,门禁五道全绿

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
This commit is contained in:
JCAI Main Agent
2026-07-27 01:51:22 +08:00
co-authored by Claude Opus 5
parent 2850e6d4ef
commit 3c974d2860
55 changed files with 7113 additions and 1 deletions
@@ -0,0 +1,112 @@
/**
* 任务生命周期与终态五名裁定 —— 纯逻辑,零 IO(编码规范 §5.3;语义出处 OS 4.3,AM 01/10)。
*
* 「**完成由框架裁定,终态由系统命名**」—— 终态是封闭枚举,活动不得增删。
*/
import type { ControlSemantic, TaskRuntimeState, TerminalState } from '@contracts';
export type TaskSnapshot = {
readonly runtime: TaskRuntimeState;
readonly terminal?: TerminalState;
readonly reason?: string;
};
export const RUNNING: TaskSnapshot = { runtime: 'running' };
/* ── 控制三语义(OS 06) ────────────────────────────────────────────── */
export type ControlOutcome =
/** 暂停 = 可恢复冻结(监听与时限停摆) */
| { readonly kind: 'suspended'; readonly resumable: true }
/** 叫停 = 负责人紧急中断:挂起并**记最重档纠正**,恢复归负责人 */
| { readonly kind: 'halted'; readonly resumable: true; readonly correctionSignal: 'heaviest' }
/** 终止 = 不可恢复关闭 */
| { readonly kind: 'terminated'; readonly resumable: false; readonly terminal: TerminalState };
export function applyControl(semantic: ControlSemantic): ControlOutcome {
switch (semantic) {
case 'pause':
return { kind: 'suspended', resumable: true };
case 'halt':
return { kind: 'halted', resumable: true, correctionSignal: 'heaviest' };
case 'terminate':
return { kind: 'terminated', resumable: false, terminal: 'terminated' };
}
}
/** 叫停**不是终态** —— 转挂起待纠偏,处置后恢复,或由负责人终止 */
export function isTerminalControl(semantic: ControlSemantic): boolean {
return semantic === 'terminate';
}
/* ── 终态裁定 ───────────────────────────────────────────────────────── */
export type TerminalCause =
/** 放行通过且落地收敛,输出口已发射 —— **唯一成功终态** */
| { readonly kind: 'released' }
/** 无法推进,封卷待治理处置 */
| { readonly kind: 'blocked'; readonly reason: string }
| { readonly kind: 'stalled'; readonly evidence: string }
| { readonly kind: 'exhausted'; readonly detail: string }
| { readonly kind: 'terminated'; readonly reason: string };
export function decideTerminal(cause: TerminalCause): { terminal: TerminalState; reason: string } {
switch (cause.kind) {
case 'released':
return { terminal: 'released', reason: '放行通过且落地收敛,输出口已发射' };
case 'blocked':
return { terminal: 'blocked', reason: cause.reason };
case 'stalled':
return { terminal: 'stalled', reason: cause.evidence };
case 'exhausted':
return { terminal: 'exhausted', reason: cause.detail };
case 'terminated':
return { terminal: 'terminated', reason: cause.reason };
}
}
export function isSuccess(terminal: TerminalState): boolean {
return terminal === 'released';
}
/** 非完成终态触发流程层的**失败走向**(OS 03) */
export function triggersFailureDisposition(terminal: TerminalState): boolean {
return terminal !== 'released';
}
/* ── 「不是终态」的三样(OS 4.3) ──────────────────────────────────── */
/** 驳回是**环内回转**,任务继续 —— 不出活动 */
export function rejectionKeepsRunning(): TaskSnapshot {
return { runtime: 'running' };
}
/** 落地受阻是**运行态**,处置后仍收敛于终态名录 */
export function landingBlocked(reason: string): TaskSnapshot {
return { runtime: 'landing-blocked', reason };
}
/* ── 断点续跑:三份持久状态(OS 09) ──────────────────────────────── */
export const RESUME_SOURCES = ['task-memory', 'draft-layer', 'runtime-state'] as const;
export type ResumeSource = (typeof RESUME_SOURCES)[number];
export type ResumeReadiness = {
readonly ready: boolean;
readonly missing: readonly ResumeSource[];
};
/**
* 「任务做一半的续跑由三份持久状态**共同**保证:
* 任务记忆(按窗口重建上下文)、草稿层(截至断点的过程产物与动作意向)、
* 运行时实例状态(loop 的模型定位与就绪集 / flow 的步序位置)。」
*/
export function resumeReadiness(present: Readonly<Record<ResumeSource, boolean>>): ResumeReadiness {
const missing = RESUME_SOURCES.filter((s) => !present[s]);
return { ready: missing.length === 0, missing };
}
/** 「打开任务只是打开呈现,不是启动过程」—— 过程要么在跑,要么挂起在等 */
export function isPassiveOpen(state: TaskRuntimeState): boolean {
return state !== 'running';
}