Archived
2026-08-31 用户三连: ① 「提示两颗料不是同一个芯片类型…就不应该能写入并继续下一步」—— 缺格闸只数必填空不空,管不了跨行一致性。平台加**确认闸条件档**:配方 card 声明 gateWhen(S-FEEL,只读基座读数)+ gateWhenSay,受理回传前在 submitGate 现算 (rows/missing/tally/distinct 全套读数按声明表现读),为假 400、拒回用发卡人那句话; 装包静态审与动作级 when 同一套审;评估不出的条件不成墙(坏表达式装包就拦)。 W05 钉 parts_profile_distinct_chip_type_id <= 1 —— 钉 profile 本表(草稿现读零滞后; 钉 sub_eval.part 那份要等配方 tick,人存完就点确认会被误拦),profile.chip_type_id 加 distinct 声明。e2e 案例 2 的空手探针从此吃的就是这道闸。 ② 「页面底部没东西还能向下滑一截」—— ViewContainer 量高从 max(documentElement.scrollHeight, body) 改 body 优先:documentElement 以 iframe 自身 高度为下限,内容缩回后它缩不回去,量高**只涨不缩**(参数编辑态把卡背拉长过一次, 底部从此留一截空白滚动)。body(margin 0)才是内容自己的高。 ③ 「两张卡片中间做出可替换的动画」—— 单点单向信号换成**对向双信号点**(左右互穿, 走在卡后、只在缝里现身)+ 中央 ⇄ 徽轻呼吸 —— 这界面是判「可否替换」的,动画说的 就是这件事。reduced-motion 全静。 测:契约 gateWhen 解析 + runner 透传(变异红)+ conditionGateOf 3 例(含坏表达式不成墙) + steps/activity 锚;2531 全仓四门绿;2.12.0 装库核过(gateWhen 入库/swapfx); :8787 已重建重启。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LKMZDwMbyKzjw6Hembwvet
79 lines
3.7 KiB
TypeScript
79 lines
3.7 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
import { autoRecipeSchema } from '../auto-recipe.ts';
|
|
|
|
describe('auto 配方契约', () => {
|
|
it('收下一份用全了五个动词的配方', () => {
|
|
const parsed = autoRecipeSchema.safeParse({
|
|
let: { evalRef: { cat: ['W05-', { fmt: { in: 'case:openedAt' }, as: 'digits' }] } },
|
|
do: [
|
|
{ kind: 'project', into: 'sub_eval.part', prune: true, from: { rows: [{ pn: { in: 'originalInternalPn' } }] }, fields: { internal_pn: { col: 'pn' } } },
|
|
{ kind: 'analyze', model: 'deepseek-v4-flash', into: 'items', instruction: '逐条判四态', input: { from: { each: 'parts.type_param' }, fields: { name: { col: 'param_name' } } }, output: { type: 'object' } },
|
|
{ kind: 'card', as: 'execution', variant: 'data', title: '补数据', basis: [{ k: '原 PN', v: { in: 'originalInternalPn' } }], gateLedgers: ['parts.profile'] },
|
|
{ kind: 'submit', rationale: '结论已备好' },
|
|
{ kind: 'say', text: '这一步办完了' },
|
|
],
|
|
});
|
|
expect(parsed.success).toBe(true);
|
|
});
|
|
|
|
it('不认识的动词当场拒 —— 没实现的形状不许装进来', () => {
|
|
const parsed = autoRecipeSchema.safeParse({ do: [{ kind: 'drop', into: 'a.b' }] });
|
|
expect(parsed.success).toBe(false);
|
|
});
|
|
|
|
it('嵌套只许两层:第三层当场拒', () => {
|
|
const parsed = autoRecipeSchema.safeParse({
|
|
do: [{ kind: 'project', into: 'a.b', from: { each: 'a.b', then: { each: 'c.d', then: { each: 'e.f' } } }, fields: {} }],
|
|
});
|
|
expect(parsed.success).toBe(false);
|
|
});
|
|
|
|
it("prune 收 'live' 档 —— quiet 拍也撤,只给人不会在件上加行的表用(其余字符串拒)", () => {
|
|
const live = autoRecipeSchema.safeParse({ do: [{ kind: 'project', into: 'a.b', prune: 'live', from: { once: true }, fields: { k: 'v' } }] });
|
|
expect(live.success).toBe(true);
|
|
const junk = autoRecipeSchema.safeParse({ do: [{ kind: 'project', into: 'a.b', prune: 'always', from: { once: true }, fields: { k: 'v' } }] });
|
|
expect(junk.success).toBe(false);
|
|
});
|
|
|
|
it('card 收确认闸条件档 gateWhen/gateWhenSay(2026-08-31,类型不一致不许确认)', () => {
|
|
const ok = autoRecipeSchema.safeParse({
|
|
do: [{ kind: 'card', as: 'execution', title: 't', gateWhen: 'a_b_distinct_c <= 1', gateWhenSay: '先改对再确认' }],
|
|
});
|
|
expect(ok.success).toBe(true);
|
|
});
|
|
|
|
it('prune 只许挂在 project 上', () => {
|
|
const parsed = autoRecipeSchema.safeParse({ do: [{ kind: 'say', text: 'x', prune: true }] });
|
|
expect(parsed.success).toBe(false);
|
|
});
|
|
});
|
|
|
|
import { planStepSchema } from '../manifest.ts';
|
|
|
|
describe('全 auto 的步可以没有 guide', () => {
|
|
/* brief 原样缺了 intent(required,非空)—— 缺了它 safeParse 恒失败,前两条测试就都验不到「guide 允不允许空」这件事本身 */
|
|
const base = { item: 'S1', intent: '这一步交出什么', guide: '', writes: [], reads: [], tools: [] };
|
|
|
|
it('声明了 auto 就允许 guide 为空 —— 那一步压根不问模型', () => {
|
|
const parsed = planStepSchema.safeParse({
|
|
...base,
|
|
auto: { do: [{ kind: 'say', text: '办完了' }] },
|
|
});
|
|
expect(parsed.success).toBe(true);
|
|
});
|
|
|
|
it('没有 auto 又不写 guide → 拒 —— 「作者忘了写做法」这个老错照旧要拦', () => {
|
|
const parsed = planStepSchema.safeParse(base);
|
|
expect(parsed.success).toBe(false);
|
|
});
|
|
|
|
it('有 auto 但 guide 写了内容 → 照收(半 auto:确定的先做完,剩下的仍问模型)', () => {
|
|
const parsed = planStepSchema.safeParse({
|
|
...base,
|
|
guide: '把结论写实',
|
|
auto: { do: [{ kind: 'say', text: 'x' }] },
|
|
});
|
|
expect(parsed.success).toBe(true);
|
|
});
|
|
});
|