feat(contracts): auto 配方契约 —— 确定的活由引擎按声明做,五个动词四种地址

配方是数据不是代码(ADR-004:不执行包代码即知包为何物),装进来可静态审、可回放。
只声明真实现了的那几式;嵌套两层封顶,没实现的形状 zod 当场拒。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LKMZDwMbyKzjw6Hembwvet
This commit is contained in:
xcs
2026-08-29 03:04:56 +08:00
co-authored by Claude Opus 5
parent 04234d2fda
commit 16fe8ba71b
9 changed files with 385 additions and 0 deletions
@@ -0,0 +1 @@
export {};
+1
View File
@@ -2238,6 +2238,7 @@ export declare const installActivityRoute: {
}>>;
acceptanceChecklist: z.ZodOptional<z.ZodArray<z.ZodString>>;
humanWrites: z.ZodOptional<z.ZodArray<z.ZodString>>;
auto: z.ZodOptional<z.ZodType<import("../auto-recipe.ts").AutoRecipe, unknown, z.core.$ZodTypeInternals<import("../auto-recipe.ts").AutoRecipe, unknown>>>;
}, z.core.$strip>>>;
phases: z.ZodOptional<z.ZodArray<z.ZodObject<{
name: z.ZodString;
+135
View File
@@ -0,0 +1,135 @@
/**
* 确定性步骤的**声明式配方**(ADR-014 / spec 2026-08-29 §5.1)。
*
* 配方是**数据不是代码**:装进来仍然只是数据,可静态审、可回放、可在治理台上摆出
* 「这一步系统会做什么」。执行第三方代码则相反 —— ADR-004 的立场是「不执行包代码即知包为何物」。
*
* **只声明真实现了的那几式。** 表达力有上限是刻意的:上限之外的不要硬塞,
* 退回模型,或者把那一段判断从这一步里切出去。
*/
import { z } from 'zod';
/** 表达式 —— 递归,`z.lazy` 是唯一写法(zod 的自引用) */
export type AutoExpr = string | number | boolean
/** 入参 / 基座读数 / `let` 里算好的值 —— 三者同一个命名空间,`let` 优先 */
| {
readonly in: string;
}
/** 本行的列 */
| {
readonly col: string;
}
/** 外层那一行的列(两层嵌套时) */
| {
readonly outer: string;
}
/** 拼接,一律按字符串 */
| {
readonly cat: readonly AutoExpr[];
}
/** 只留数字(铸号:`case:openedAt` → `20260829215103`) */
| {
readonly fmt: AutoExpr;
readonly as: 'digits';
}
/** 查另一张表的一列;查不到给 `else`(缺省空串) */
| {
readonly lookup: string;
readonly by: Readonly<Record<string, AutoExpr>>;
readonly take: string;
readonly else?: AutoExpr | undefined;
}
/** S-FEEL 条件(可嵌套)—— 已算出的同行字段进它的作用域 */
| {
readonly when: string;
readonly then: AutoExpr;
readonly else: AutoExpr;
};
export declare const autoExprSchema: z.ZodType<AutoExpr>;
/**
* 数据源 —— 这一笔要对着几行办。
*
* 地址只有四种(spec §5.1):`域.对象`(**任务视图 = 正式表 + 本单草稿叠加**,默认该用的那一种)·
* `mine:域.对象`(只有本单草稿写下的行)· `in:入参数组` · `result:xxx`(本拍 analyze 的出参)。
* **没有「纯正式表」那一种** —— 要区分「本单写的」与「别人放行的」,`mine:` 就够了。
*/
export type AutoSource = {
readonly once: true;
} | {
readonly rows: readonly Readonly<Record<string, AutoExpr>>[];
} | {
readonly each: string;
readonly where?: Readonly<Record<string, AutoExpr>> | undefined;
/** 第二层,**到此为止** —— 三层以上就别 auto 了 */
readonly then?: {
readonly each: string;
readonly where?: Readonly<Record<string, AutoExpr>> | undefined;
} | undefined;
};
export declare const autoSourceSchema: z.ZodType<AutoSource>;
/** 五个动词 —— `when` 为假就跳过这一笔 */
export type AutoAction = {
readonly kind: 'project';
readonly when?: string | undefined;
/** 台账地址「域.对象」—— 必须在 `declarations.ledger` 里(静态审) */
readonly into: string;
/** 这一笔投影出来的行**就是这张表在本单草稿里的全部**,多出来的撤掉。只动草稿层 */
readonly prune?: boolean | undefined;
readonly from: AutoSource;
readonly fields: Readonly<Record<string, AutoExpr>>;
} | {
readonly kind: 'analyze';
readonly when?: string | undefined;
/** 活动声明过的模型名 */
readonly model: string;
/** 出参落进拍内作用域 `result:<into>`,供后面的 project 用 `each`/`lookup` 消费 */
readonly into: string;
/** 给模型的 system 段 —— 说清判什么、四态各是什么意思 */
readonly instruction: string;
/** 入参由声明组装:一行一条,`fields` 决定每条摆哪几个键 */
readonly input: {
readonly from: AutoSource;
readonly fields: Readonly<Record<string, AutoExpr>>;
};
/** 出参 JSON Schema —— 顶层必须是 object */
readonly output: Readonly<Record<string, unknown>>;
} | {
readonly kind: 'card';
readonly when?: string | undefined;
readonly as: 'execution' | 'decide';
readonly variant?: ('data' | 'review') | undefined;
readonly title: AutoExpr;
/** 决策卡问的那句话 */
readonly ask?: AutoExpr | undefined;
/** 作业指导书 —— 一条一句,静态文本 */
readonly guide?: readonly string[] | undefined;
readonly standard?: AutoExpr | undefined;
/** 调用必附上下文 —— **基座拒发 basis 为空的工单**,别指望兜底(它摆的是内部家具) */
readonly basis?: readonly {
readonly k: string;
readonly v: AutoExpr;
}[] | undefined;
/** 这张卡的提交闸盯哪几张表 */
readonly gateLedgers?: readonly string[] | undefined;
/** 决策卡的选项;`variant:'review'` 时允许只有一个 */
readonly options?: readonly {
readonly value: string;
readonly label: string;
readonly detail?: string | undefined;
}[] | undefined;
} | {
readonly kind: 'submit';
readonly when?: string | undefined;
readonly rationale: AutoExpr;
} | {
readonly kind: 'say';
readonly when?: string | undefined;
readonly text: AutoExpr;
};
export declare const autoActionSchema: z.ZodType<AutoAction>;
export type AutoRecipe = {
/** 配方级局部值:先算一遍,后面所有表达式都能 `{in:'名'}` 引用 —— 整单只有一个案号,靠它 */
readonly let?: Readonly<Record<string, AutoExpr>> | undefined;
/** 按序执行 */
readonly do: readonly AutoAction[];
};
export declare const autoRecipeSchema: z.ZodType<AutoRecipe>;
+1
View File
@@ -15,4 +15,5 @@ export * from './manifest.ts';
export * from './org.ts';
export * from './mail.ts';
export * from './activity-ops.ts';
export * from './auto-recipe.ts';
export * from './api/index.ts';
+5
View File
@@ -208,6 +208,7 @@ export declare const planStepSchema: z.ZodObject<{
}>>;
acceptanceChecklist: z.ZodOptional<z.ZodArray<z.ZodString>>;
humanWrites: z.ZodOptional<z.ZodArray<z.ZodString>>;
auto: z.ZodOptional<z.ZodType<import("./auto-recipe.ts").AutoRecipe, unknown, z.core.$ZodTypeInternals<import("./auto-recipe.ts").AutoRecipe, unknown>>>;
}, z.core.$strip>;
export type PlanStep = z.infer<typeof planStepSchema>;
/**
@@ -274,6 +275,7 @@ export declare const loopModelSchema: z.ZodObject<{
}>>;
acceptanceChecklist: z.ZodOptional<z.ZodArray<z.ZodString>>;
humanWrites: z.ZodOptional<z.ZodArray<z.ZodString>>;
auto: z.ZodOptional<z.ZodType<import("./auto-recipe.ts").AutoRecipe, unknown, z.core.$ZodTypeInternals<import("./auto-recipe.ts").AutoRecipe, unknown>>>;
}, z.core.$strip>>>;
phases: z.ZodOptional<z.ZodArray<z.ZodObject<{
name: z.ZodString;
@@ -334,6 +336,7 @@ export declare const businessModelSchema: z.ZodObject<{
}>>;
acceptanceChecklist: z.ZodOptional<z.ZodArray<z.ZodString>>;
humanWrites: z.ZodOptional<z.ZodArray<z.ZodString>>;
auto: z.ZodOptional<z.ZodType<import("./auto-recipe.ts").AutoRecipe, unknown, z.core.$ZodTypeInternals<import("./auto-recipe.ts").AutoRecipe, unknown>>>;
}, z.core.$strip>>>;
phases: z.ZodOptional<z.ZodArray<z.ZodObject<{
name: z.ZodString;
@@ -492,6 +495,7 @@ export declare const manifestAssetsSchema: z.ZodObject<{
}>>;
acceptanceChecklist: z.ZodOptional<z.ZodArray<z.ZodString>>;
humanWrites: z.ZodOptional<z.ZodArray<z.ZodString>>;
auto: z.ZodOptional<z.ZodType<import("./auto-recipe.ts").AutoRecipe, unknown, z.core.$ZodTypeInternals<import("./auto-recipe.ts").AutoRecipe, unknown>>>;
}, z.core.$strip>>>;
phases: z.ZodOptional<z.ZodArray<z.ZodObject<{
name: z.ZodString;
@@ -798,6 +802,7 @@ export declare const activityManifestSchema: z.ZodObject<{
}>>;
acceptanceChecklist: z.ZodOptional<z.ZodArray<z.ZodString>>;
humanWrites: z.ZodOptional<z.ZodArray<z.ZodString>>;
auto: z.ZodOptional<z.ZodType<import("./auto-recipe.ts").AutoRecipe, unknown, z.core.$ZodTypeInternals<import("./auto-recipe.ts").AutoRecipe, unknown>>>;
}, z.core.$strip>>>;
phases: z.ZodOptional<z.ZodArray<z.ZodObject<{
name: z.ZodString;