From 83d1eb316d218f7b9a5d61892e24e4e7ae3fbbc7 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 4 Oct 2026 09:00:30 +0000 Subject: [PATCH 1/2] test(spec): automation test titles state each cited decision in words instead of a tracker number The 105 test-title and test-message literals under packages/spec/src/automation that carried a tracker id (110 ids, 55 records) now either state what the cited record decided, or drop a citation the title already explains. Text only: no assertion, fixture value, test count or code comment changes. Claude-Session: https://claude.ai/code/session_01T9u38rswFp5Rw8DswRUReJ Co-authored-by: Claude --- packages/spec/src/automation/approval.test.ts | 14 ++++----- .../automation/builtin-node-config.test.ts | 20 ++++++------- .../spec/src/automation/control-flow.test.ts | 12 ++++---- .../src/automation/end-node-outcome.test.ts | 8 ++--- .../spec/src/automation/execution.test.ts | 10 +++---- ...-decision-branch-expression-absent.test.ts | 6 ++-- .../flow-edge-condition-evaluated.test.ts | 4 +-- .../spec/src/automation/flow-function.test.ts | 6 ++-- .../flow-node-config-required.test.ts | 4 +-- .../flow-node-expression-paths.test.ts | 24 +++++++-------- .../flow-predicate-slot-blank.test.ts | 4 +-- .../src/automation/flow-region-cycle.test.ts | 2 +- .../flow-region-pause-and-end.test.ts | 4 +-- packages/spec/src/automation/flow.test.ts | 30 +++++++++---------- .../src/automation/io-node-config.test.ts | 18 +++++------ .../automation/region-normalization.test.ts | 16 +++++----- .../spec/src/automation/region-slots.test.ts | 4 +-- .../automation/schemaless-node-config.test.ts | 10 +++---- .../src/automation/sync-retirement.test.ts | 6 ++-- .../automation/time-relative-trigger.test.ts | 2 +- packages/spec/src/automation/webhook.test.ts | 6 ++-- 21 files changed, 105 insertions(+), 105 deletions(-) diff --git a/packages/spec/src/automation/approval.test.ts b/packages/spec/src/automation/approval.test.ts index a4554fe7ef5..bbddc96517f 100644 --- a/packages/spec/src/automation/approval.test.ts +++ b/packages/spec/src/automation/approval.test.ts @@ -132,7 +132,7 @@ describe('ORG_MEMBERSHIP_LEVELS derives from BUILTIN_MEMBERSHIP_ROLES', () => { // record-backed kinds MUST match the engine's resolution semantics // (`plugin-approvals` resolveApproverSpec / expand*Users) — these assertions // pin the object names and stored fields the engine actually queries. -describe('APPROVER_VALUE_BINDINGS (#3508)', () => { +describe('APPROVER_VALUE_BINDINGS — an approver value is picked from the records the engine resolves', () => { it('covers every ApproverType member', () => { for (const t of ApproverType.options) { expect(APPROVER_VALUE_BINDINGS[t]).toBeDefined(); @@ -173,7 +173,7 @@ describe('APPROVER_VALUE_BINDINGS (#3508)', () => { // #3508 follow-up: `xRef.map` names a picker KIND but never said where that // picker's candidates live — which is how the designer came to query the // metadata registry for data records. The data contract now ships on the wire. -describe('APPROVER_VALUE_SOURCES (#3508 follow-up)', () => { +describe('APPROVER_VALUE_SOURCES — where each picker finds its candidates, published on the wire', () => { it('covers every ApproverType member, exactly like the bindings it projects', () => { for (const t of ApproverType.options) { expect(APPROVER_VALUE_SOURCES[t], `no source published for '${t}'`).toBeDefined(); @@ -309,7 +309,7 @@ describe('ApprovalNodeConfigSchema', () => { expect(() => ApprovalNodeConfigSchema.parse({ ...minimal, behavior: 'weighted' })).toThrow(); }); - it('accepts quorum / per_group behaviors with minApprovals and grouped approvers (#3266)', () => { + it('accepts quorum / per_group behaviors with minApprovals and grouped approvers', () => { const quorum = ApprovalNodeConfigSchema.parse({ ...minimal, behavior: 'quorum', minApprovals: 2 }); expect(quorum.behavior).toBe('quorum'); expect(quorum.minApprovals).toBe(2); @@ -486,7 +486,7 @@ describe('ApprovalEscalationSchema', () => { // escalation block exists at all; within a block carrying timeoutHours, // escalation is ON unless explicitly turned off. Declared in // DEFAULT_CHANGES_BY_MAJOR (17) — this pin is what keeps the fingerprint honest. - it('defaults enabled to true — a block carrying timeoutHours is live unless explicitly off (#12278)', () => { + it('defaults enabled to true — a block carrying timeoutHours is live unless explicitly off', () => { const omitted = ApprovalEscalationSchema.parse({ timeoutHours: 24 }); expect(omitted.enabled).toBe(true); const explicit = ApprovalEscalationSchema.parse({ enabled: false, timeoutHours: 24 }); @@ -512,7 +512,7 @@ describe('normalizeDecisionOutputs', () => { ]); }); - it('carries the widget hints and the required flag through (objectui#2955)', () => { + it('carries the widget hints and the required flag through, for the decision dialog to render and enforce', () => { expect(normalizeDecisionOutputs([ { key: 'positions', label: 'Co-signers', type: 'position', multiple: true, required: true }, ])).toEqual([ @@ -540,7 +540,7 @@ describe('normalizeDecisionOutputs', () => { // a v17-new surface, tightened before stored volume exists. The published JSON // schema now carries additionalProperties:false into the Studio form AND // registerFlow()'s per-node config validation (#4027/#4040) — asserted below. -describe('unknown keys are rejected, not stripped (#4001)', () => { +describe('unknown keys are rejected, not stripped', () => { const unknownKeyIssue = (schema: { safeParse: (v: unknown) => any }, value: unknown) => { const result = schema.safeParse(value); expect(result.success).toBe(false); @@ -607,7 +607,7 @@ describe('unknown keys are rejected, not stripped (#4001)', () => { * cases fail loudly instead, which is what "declared = enforced" needs on * the declaring side. */ - it('accepts `required` — the key the runtime enforces (#4525)', () => { + it('accepts `required` — the key the runtime enforces', () => { expect(DecisionOutputDefSchema.parse({ key: 'next_reviewers', required: true })) .toEqual({ key: 'next_reviewers', required: true }); expect(DecisionOutputDefSchema.parse({ key: 'note', required: false })) diff --git a/packages/spec/src/automation/builtin-node-config.test.ts b/packages/spec/src/automation/builtin-node-config.test.ts index 52df800e0f5..1ee043454c6 100644 --- a/packages/spec/src/automation/builtin-node-config.test.ts +++ b/packages/spec/src/automation/builtin-node-config.test.ts @@ -52,7 +52,7 @@ function unknownKeyMessage(schema: Parseable, value: unknown): string | undefine return result.error!.issues.find((i) => i.code === 'unrecognized_keys')?.message; } -describe('CRUD config contracts — strict as of #4001 批 9', () => { +describe('CRUD config contracts — an unknown key is refused, not stripped', () => { it('accepts every declared key on each of the four', () => { expect(GetRecordConfigSchema.parse({ objectName: 'lead', filter: { status: 'new' }, fields: ['id'], limit: 5, outputVariable: 'leads', @@ -85,7 +85,7 @@ describe('CRUD config contracts — strict as of #4001 批 9', () => { ['update_record', UpdateRecordConfigSchema, { objectName: 'lead' }], ['delete_record', DeleteRecordConfigSchema, { objectName: 'lead' }], ] as ReadonlyArray<[string, Parseable, Record]>)( - '%s: prescribes `filter` for the retired `filters` spelling, and names the #3810 hazard', + '%s: prescribes `filter` for the retired `filters` spelling, and names the match-everything-write hazard', (_nodeType, schema, base) => { const message = unknownKeyMessage(schema, { ...base, filters: { status: 'stale' } })!; expect(message).toContain('flow-node-crud-filter-alias'); @@ -204,7 +204,7 @@ describe('CRUD config contracts — strict as of #4001 批 9', () => { }); }); -describe('ScreenConfigSchema / ScreenFieldConfigSchema — strict as of #4001 批 9', () => { +describe('ScreenConfigSchema / ScreenFieldConfigSchema — an unknown key is refused, not stripped', () => { it('accepts the flat and object-form shapes in full', () => { expect(ScreenConfigSchema.safeParse({ title: 'Details', description: 'Fill this in', waitForInput: true, @@ -249,7 +249,7 @@ describe('ScreenConfigSchema / ScreenFieldConfigSchema — strict as of #4001 }); }); -describe('ScreenFieldConfigSchema — the bound pair, help text and lookup target (#17306)', () => { +describe('ScreenFieldConfigSchema — the bound pair, help text and lookup target', () => { const BASE = { name: 'discount', type: 'number' }; // ── Direction 1: the three intents are now expressible ────────────────── @@ -397,7 +397,7 @@ describe('ScreenFieldConfigSchema — the bound pair, help text and lookup targe }); }); -describe('MapConfigSchema — strict as of #4001 批 9', () => { +describe('MapConfigSchema — an unknown key is refused, not stripped', () => { it('accepts every declared key', () => { expect(MapConfigSchema.parse({ collection: '{tasks}', flowName: 'one_task_signoff', iteratorVariable: 'item', @@ -430,7 +430,7 @@ describe('MapConfigSchema — strict as of #4001 批 9', () => { // ─── assignment (#14149) ───────────────────────────────────────────── -describe('assignment value contract — a CEL envelope beside `{token}` interpolation (#14149)', () => { +describe('assignment value contract — a CEL envelope beside `{token}` interpolation', () => { const DIGEST_SOURCE = 'joinNonEmpty(overdue_tasks.map(t, t.subject), "\\n")'; const DIGEST_ENVELOPE = { dialect: 'cel', source: DIGEST_SOURCE }; @@ -568,7 +568,7 @@ describe('assignment value contract — a CEL envelope beside `{token}` interpol * registered, and faulted at run time (the `ast`-only one with the engine's * own prescription; the blank one with a parse error on `" "`). */ -describe('assignment value envelope — an evaluated slot requires what the engine can evaluate (#15430)', () => { +describe('assignment value envelope — an evaluated slot requires what the engine can evaluate', () => { const AST_ONLY = { dialect: 'cel', ast: { kind: 'const', value: 1 } }; const BLANK_SOURCE = { dialect: 'cel', source: ' ' }; @@ -627,7 +627,7 @@ describe('assignment value envelope — an evaluated slot requires what the engi * same structural reason as the sibling slot: `z.record()`'s open-key branch * skips it before any key schema — including `.min(1)` — ever runs. */ -describe('AssignmentConfigSchema.assignments — __proto__ pre-parse guard, constructor/prototype UNCHANGED (#17852 / #18847)', () => { +describe('AssignmentConfigSchema.assignments — __proto__ pre-parse guard, constructor/prototype UNCHANGED', () => { it('refuses `assignments` carrying a `__proto__` own key, named at `assignments.__proto__`', () => { // `JSON.parse` is what makes `__proto__` an OWN enumerable key — an // object literal's `{ __proto__: ... }` sets the actual prototype @@ -688,7 +688,7 @@ describe('AssignmentConfigSchema.assignments — __proto__ pre-parse guard, cons * `__proto__` must be refused LOUDLY — told apart here from the two silent * outcomes it could otherwise have (silently dropped, silently kept). */ -describe('AssignmentConfigSchema — top-level __proto__ refused at the catchall (#19151)', () => { +describe('AssignmentConfigSchema — top-level __proto__ refused at the catchall', () => { /** * The three outcomes an authored key can meet, discriminated by one * function so a test cannot accidentally assert the wrong one. A bare @@ -807,7 +807,7 @@ describe('AssignmentConfigSchema — top-level __proto__ refused at the catchall * CEL value envelope), the edge #14149 accepted on `assignments.*`. Everything * else parses exactly as before. */ -describe('CRUD `fields` value contract — the CEL value envelope beside `{token}` templates (#19938)', () => { +describe('CRUD `fields` value contract — the CEL value envelope beside `{token}` templates', () => { const PRICE_ENVELOPE = { dialect: 'cel', source: 'round(price * 100) / 100.0' }; const configs = [ ['create_record', CreateRecordConfigSchema, (fields: unknown) => ({ objectName: 'quote', fields })], diff --git a/packages/spec/src/automation/control-flow.test.ts b/packages/spec/src/automation/control-flow.test.ts index 78267573739..041b38f6bd6 100644 --- a/packages/spec/src/automation/control-flow.test.ts +++ b/packages/spec/src/automation/control-flow.test.ts @@ -61,7 +61,7 @@ describe('LoopConfigSchema', () => { ).toThrow(); }); - it('emits the xExpression:"template" marker on `collection` through z.toJSONSchema (objectui #2670)', () => { + it('emits the xExpression:"template" marker on `collection` through z.toJSONSchema, so the flow designer renders it as a template', () => { // The marker rides the same `.meta()` → JSON-Schema channel as // `xRef` / `xEnumDeprecated`, telling the flow designer `collection` is an // `interpolate()` `{var}` template (not bare CEL). @@ -77,7 +77,7 @@ describe('LoopConfigSchema', () => { ); }); - it('accepts an inline array collection — the union map.collection declares (#4277)', () => { + it('accepts an inline array collection — the union map.collection declares', () => { // The executor has always resolved an already-an-array collection (shared // logic with `map`); the string-only declaration under-declared what it // reads, which the execute-time parse wiring surfaced. @@ -272,7 +272,7 @@ describe('validateControlFlow', () => { // ─── [#4001 批 10] unknown keys are rejected, not stripped ────────────────── -describe('[#4001] control-flow strictness — per shape', () => { +describe('control-flow strictness — an unknown key is refused, per shape', () => { it('FlowRegion: `name` and `label` get wrong-layer prescriptions, not renames', () => { for (const [key, expected] of [ ['name', 'A region is not named'], @@ -438,7 +438,7 @@ describe('TryCatchErrorValueSchema', () => { expect(TryCatchErrorValueSchema.parse(both)).toEqual(both); }); - it('`code` is an OPEN string, not a closed enum — a third-party or tenant-authored code parses (ADR-0112 D3/D4 + #9106)', () => { + it('`code` is an OPEN string, not a closed enum — a third-party or tenant-authored code parses (ADR-0112 D3/D4)', () => { // `NodeExecutor` is third-party-registrable and the code vocabulary is // `StandardErrorCode` ∪ registered ledger codes ∪ tenant-authored codes, // so a closed type would be false the moment anyone registers an executor. @@ -491,7 +491,7 @@ describe('TryCatchErrorValueSchema', () => { // `MAX_REGION_DEPTH` (32) `analyzeRegion`'s own `duplicate node id` line is // the only refusal of a within-region duplicate. `flow.test.ts`'s // `the seam at MAX_REGION_DEPTH` case pins that hand-off. -describe('[#4001] validateControlFlow and the key gate meet at the region-slot seam', () => { +describe('validateControlFlow and the unknown-key gate meet at the region-slot seam', () => { const flowWith = (cfg: Record, type = LOOP_NODE_TYPE) => ({ nodes: [{ ...node('c1', type), config: cfg }] } as never); @@ -540,7 +540,7 @@ describe('[#4001] validateControlFlow and the key gate meet at the region-slot s expect(() => validateControlFlow(flowWith({ collection: '{items}', iteratorVariable: 'x' }))).not.toThrow(); }); - it('nested regions are key-checked at depth, like the structural check (#4389)', () => { + it('nested regions are key-checked at depth, like the structural check', () => { let message = ''; try { validateControlFlow(flowWith({ diff --git a/packages/spec/src/automation/end-node-outcome.test.ts b/packages/spec/src/automation/end-node-outcome.test.ts index a98ec3e026d..61675d61528 100644 --- a/packages/spec/src/automation/end-node-outcome.test.ts +++ b/packages/spec/src/automation/end-node-outcome.test.ts @@ -40,7 +40,7 @@ const flowEndingWith = (config: Record | undefined): Flow => ({ const endConfigOf = (flow: { nodes: Array<{ config?: unknown }> }) => flow.nodes[1].config; -describe('EndConfigSchema — the `end` node contract (#14945)', () => { +describe('EndConfigSchema — the `end` node contract: it may refuse the run with a message', () => { it('defaults `outcome` to `completed` on an empty config', () => { expect(EndConfigSchema.parse({})).toEqual({ outcome: 'completed' }); expect(EndConfigSchema.parse({ outcome: 'completed' })).toEqual({ outcome: 'completed' }); @@ -127,7 +127,7 @@ describe('EndConfigSchema — the `end` node contract (#14945)', () => { }); }); -describe('FlowSchema applies the `end` contract — the structural node\'s only door (#14945)', () => { +describe('FlowSchema applies the `end` contract — the structural node\'s only door', () => { it('accepts the card-shape probe and writes the parsed config back', () => { const result = FlowSchema.safeParse(flowEndingWith({ outcome: 'refused', message: REFUSAL })); expect(result.success).toBe(true); @@ -217,7 +217,7 @@ describe('FlowSchema applies the `end` contract — the structural node\'s only expect(issues?.map((i) => [i.code, i.path])).toEqual([['custom', ['nodes', 1, 'config', 'message']]]); }); - it('a region-nested `end` is refused by the FLOW parse itself (#15646/#18112) — the region-door reading this test used to pin is unreachable, because the shape is gone', () => { + it('a region-nested `end` is refused by the FLOW parse itself — the region-door reading this test used to pin is unreachable, because the shape is gone', () => { // ⚠️ REPLACED, not re-spelled. This case used to assert that the flow parse // was GREEN here and that `validateControlFlow` was the door — a true // reading of `parseFlowNodeRegions` leaving a refused region raw (#4389). @@ -278,7 +278,7 @@ describe('FlowSchema applies the `end` contract — the structural node\'s only }); }); -describe('the run row carries the refusal (#14945)', () => { +describe('the run row carries the refusal', () => { const run = { id: 'exec_refused_001', flowName: 'lead_conversion', diff --git a/packages/spec/src/automation/execution.test.ts b/packages/spec/src/automation/execution.test.ts index d3a852f0312..4ecc70c80cd 100644 --- a/packages/spec/src/automation/execution.test.ts +++ b/packages/spec/src/automation/execution.test.ts @@ -24,7 +24,7 @@ describe('ExecutionStatus', () => { }); }); - it('names the refused terminal (#14945) — appended LAST, so every `.options` index reader keeps its positions', () => { + it('names the refused terminal — appended LAST, so every `.options` index reader keeps its positions', () => { expect(ExecutionStatus.options).toContain('refused'); expect(ExecutionStatus.options.at(-1)).toBe('refused'); expect(ExecutionStatus.options.slice(0, 8)).toEqual( @@ -204,7 +204,7 @@ describe('ExecutionStepLogSchema', () => { expect(step.branch).toBe(1); }); - it('a `success` step that delegated to a child carries the child\'s contained failures on `metrics.failures` (#15617)', () => { + it('a `success` step that delegated to a child carries the child\'s contained failures on `metrics.failures`', () => { // The card's shape: `loop { subflow(child) }`, one iteration whose child // COMPLETED while losing a row. The subflow step itself succeeded — the // failure is the child's, contained — so `status` stays `success` and the @@ -415,7 +415,7 @@ describe('FlowRunSummarySchema', () => { expect(summary.failed).toBe(summary.nodes.reduce((sum, node) => sum + node.failures, 0)); }); - it('`failed` is the fold INCLUDING what a delegating node rolled up from its child — the card\'s measured shape, as ruled (#15617)', () => { + it('`failed` is the fold INCLUDING what a delegating node rolled up from its child — it answers what the run caused', () => { // Parent `loop { subflow(child) }` over five rows; the child COMPLETED on // every iteration and contained one failure on the last. The subflow node // succeeded five times — `status: success`, its own executions never @@ -440,7 +440,7 @@ describe('FlowRunSummarySchema', () => { expect(call?.failures).toBe(1); }); - it('the control keeps counting as before: a child that FAILED is the delegating step\'s own failure, counted once (#15617)', () => { + it('the control keeps counting as before: a child that FAILED is the delegating step\'s own failure, counted once', () => { // Same parent, but the child FAILED on the last row rather than containing // the failure. That is the subflow step's own `status: failure` — one // execution failed — and nothing rides up on top of it: the child's own @@ -457,7 +457,7 @@ describe('FlowRunSummarySchema', () => { expect(summary.failed).toBe(summary.nodes.reduce((sum, node) => sum + node.failures, 0)); }); - it('declares the roll-up at the point of use — the field describes say so, not only the paragraph above the schema (#15617)', () => { + it('declares the roll-up at the point of use — the field describes say so, not only the paragraph above the schema', () => { // Triage's explicit failure mode for this card: a reconciliation that // leaves `failed`'s own `.describe()` saying the narrow thing. A consumer // reads the field's description, so the widened rule has to be there. diff --git a/packages/spec/src/automation/flow-decision-branch-expression-absent.test.ts b/packages/spec/src/automation/flow-decision-branch-expression-absent.test.ts index d268880f293..bf9da2de74d 100644 --- a/packages/spec/src/automation/flow-decision-branch-expression-absent.test.ts +++ b/packages/spec/src/automation/flow-decision-branch-expression-absent.test.ts @@ -60,14 +60,14 @@ const AT_BRANCH_0 = ['nodes', 1, 'config', 'conditions', 0, 'expression']; * refused row's message is the ONE judge's, byte for byte. */ const TABLE: Array<{ name: string; branch: Node; refused: boolean; refusedWith?: unknown }> = [ - { name: 'no `expression` key — the #19961 shape', branch: { label: 'y' }, refused: true, refusedWith: undefined }, + { name: 'no `expression` key', branch: { label: 'y' }, refused: true, refusedWith: undefined }, { name: '`expression: null`', branch: { label: 'y', expression: null }, refused: true, refusedWith: null }, { name: 'the predicate under the edge\'s spelling `condition`', branch: { label: 'y', condition: 'true' }, refused: true, refusedWith: undefined }, - { name: 'a blank string — the #17493 control', branch: { label: 'y', expression: ' ' }, refused: true, refusedWith: ' ' }, + { name: 'a blank string — the control: a blank predicate is already refused', branch: { label: 'y', expression: ' ' }, refused: true, refusedWith: ' ' }, { name: 'a real predicate — the accept control', branch: { label: 'y', expression: 'true' }, refused: false }, ]; -describe('FlowSchema.parse refuses a decision branch with no `expression` (#19961)', () => { +describe('FlowSchema.parse refuses a decision branch with no `expression`', () => { it.each(TABLE)('$name', ({ branch, refused, refusedWith }) => { const issues = issuesOf(flowWith(decision(branch))); if (!refused) { diff --git a/packages/spec/src/automation/flow-edge-condition-evaluated.test.ts b/packages/spec/src/automation/flow-edge-condition-evaluated.test.ts index 90b010e5f03..5d23146c20e 100644 --- a/packages/spec/src/automation/flow-edge-condition-evaluated.test.ts +++ b/packages/spec/src/automation/flow-edge-condition-evaluated.test.ts @@ -44,7 +44,7 @@ function issuesOf(value: unknown) { : result.error.issues.map((i) => ({ code: i.code, path: i.path.map(String).join('.'), message: i.message })); } -describe('FlowEdgeSchema.condition — an evaluated slot requires a non-blank `source` (#15807)', () => { +describe('FlowEdgeSchema.condition — an evaluated slot requires a non-blank `source`', () => { it('REFUSES an `ast`-only envelope: one issue at `condition`, the published sentence', () => { // Both union arms abort on this shape (the envelope arm's missing `source` // is an aborting `invalid_type`), so it surfaces as the union's own issue @@ -181,7 +181,7 @@ describe('FlowEdgeSchema.condition — an evaluated slot requires a non-blank `s }); }); -describe('EvaluatedExpressionInputSchema — the sibling of ExpressionInputSchema for an evaluated slot (#15807)', () => { +describe('EvaluatedExpressionInputSchema — the sibling of ExpressionInputSchema for an evaluated slot', () => { const direct = (value: unknown) => { const r = EvaluatedExpressionInputSchema.safeParse(value); return r.success diff --git a/packages/spec/src/automation/flow-function.test.ts b/packages/spec/src/automation/flow-function.test.ts index 13ba40e3cc7..280f9c119a1 100644 --- a/packages/spec/src/automation/flow-function.test.ts +++ b/packages/spec/src/automation/flow-function.test.ts @@ -11,7 +11,7 @@ import { } from './flow-function.zod'; import { defineStack } from '../stack.zod'; -describe('FlowFunctionEffectSchema (#4396)', () => { +describe('FlowFunctionEffectSchema — a function that writes says so; pure is the default', () => { it('declares exactly the two effects the runtime acts on', () => { expect(FlowFunctionEffectSchema.options).toEqual(['pure', 'writes']); }); @@ -147,7 +147,7 @@ describe('FlowFunctionEntrySchema', () => { }); }); -describe('defineStack({ functions }) — the authoring surface (#4396)', () => { +describe('defineStack({ functions }) — the authoring surface where a function declares its effect', () => { const base = { manifest: { id: 'com.example.demo', name: 'demo', version: '1.0.0', type: 'app' as const }, }; @@ -196,7 +196,7 @@ describe('defineStack({ functions }) — the authoring surface (#4396)', () => { // reading exactly like a dead sweep, on a flow that did its work; the `effect` // declaration is what would have kept it out (`unmeasured > 0`), and the // misspelling is what dropped it. -describe('unknown keys are rejected, not stripped (#4001 batch 11)', () => { +describe('unknown keys are rejected, not stripped', () => { const base = { manifest: { id: 'com.example.demo', name: 'demo', version: '1.0.0', type: 'app' as const }, }; diff --git a/packages/spec/src/automation/flow-node-config-required.test.ts b/packages/spec/src/automation/flow-node-config-required.test.ts index 4979d905d54..6013b465850 100644 --- a/packages/spec/src/automation/flow-node-config-required.test.ts +++ b/packages/spec/src/automation/flow-node-config-required.test.ts @@ -101,7 +101,7 @@ const CENSUS: Array<{ type: string; config: Config; key: string }> = [ { type: 'try_catch', config: { try: region('try'), catch: region('catch') }, key: 'try' }, ]; -describe('FlowSchema.parse refuses a key the node\'s executor contract requires, left out (#20316)', () => { +describe('FlowSchema.parse refuses a key the node\'s executor contract requires, left out', () => { it.each(CENSUS)('$type: the whole config parses — the accept control for `$key`', ({ type, config }) => { expect(issuesOf(flowWith(node(type, config)))).toEqual([]); }); @@ -187,7 +187,7 @@ describe('FlowSchema.parse refuses a key the node\'s executor contract requires, /** A decision whose `config` is written exactly as given. */ const decision = (config: Config): Node => ({ id: 'check', type: 'decision', label: 'Check', config }); -describe('FlowSchema.parse refuses a decision branch list the executor cannot read (#20316)', () => { +describe('FlowSchema.parse refuses a decision branch list the executor cannot read', () => { const AT = (...rest: (string | number)[]) => ['nodes', 1, 'config', ...rest]; it.each([ diff --git a/packages/spec/src/automation/flow-node-expression-paths.test.ts b/packages/spec/src/automation/flow-node-expression-paths.test.ts index 7cb9cc4a028..2ba1fd9f255 100644 --- a/packages/spec/src/automation/flow-node-expression-paths.test.ts +++ b/packages/spec/src/automation/flow-node-expression-paths.test.ts @@ -41,7 +41,7 @@ const TWO_VARIABLE_ASSIGNMENT = { }, }; -describe('FLOW_NODE_EXPRESSION_PATHS — the assignment value entry (#14149)', () => { +describe('FLOW_NODE_EXPRESSION_PATHS — the assignment value entry', () => { const entry = FLOW_NODE_EXPRESSION_PATHS.find((e) => e.nodeType === 'assignment'); it('declares exactly one slot for `assignment`: `assignments.*`, role `value`', () => { @@ -130,7 +130,7 @@ describe('FLOW_NODE_EXPRESSION_PATHS — the assignment value entry (#14149)', ( * an expression, a `{token}` string keeps its 17.x meaning and is not * resolved, and every other literal is data. */ -describe('FLOW_NODE_EXPRESSION_PATHS — the CRUD `fields.*` value entries (#19938)', () => { +describe('FLOW_NODE_EXPRESSION_PATHS — the CRUD `fields.*` value entries', () => { const PRICE_ENVELOPE = { dialect: 'cel', source: 'round(price * 100) / 100.0' }; it.each(['create_record', 'update_record'] as const)('declares exactly one slot for `%s`: `fields.*`, role `value`', (nodeType) => { @@ -185,7 +185,7 @@ describe('FLOW_NODE_EXPRESSION_PATHS — the CRUD `fields.*` value entries (#199 }); }); -describe('resolveFlowNodeValueSlots — every authored value of a `value` slot, strings included (#19938)', () => { +describe('resolveFlowNodeValueSlots — every authored value of a `value` slot, strings included', () => { it('hands over every non-absent value of the CRUD `fields` map and the assignment map, by the ledger\'s own walk', () => { const envelope = { dialect: 'cel', source: 'price * 2' }; expect(resolveFlowNodeValueSlots('create_record', { @@ -231,10 +231,10 @@ describe('isExpressionEnvelopeShaped — the recognizer a value slot discriminat }); }); -describe('every pre-#14149 entry resolves byte-identically (the ratchet\'s fixtures, restated)', () => { +describe('every entry older than the value role resolves byte-identically (the ratchet\'s fixtures, restated)', () => { const byKey = (e: FlowNodeExpressionPath) => `${e.nodeType}.${e.path} (${e.role})`; - it('the entries that existed before are still declared exactly as they were — #19938 added exactly two rows', () => { + it('the entries that existed before are still declared exactly as they were — the CRUD `fields.*` value slots added exactly two rows', () => { // The census: five rows before #19938, seven after. The two new rows are // the CRUD write map's `value` slots and sit at the end; every row above // them is byte-identical to what it was. @@ -315,7 +315,7 @@ describe('every pre-#14149 entry resolves byte-identically (the ratchet\'s fixtu * never parsed against any Zod schema, there is no schema pass, so the value * reached the evaluator with no validator having ever seen it. */ - it('emits a non-string in a predicate slot, so a consumer can refuse it (#15572)', () => { + it('emits a non-string in a predicate slot, so a consumer can refuse it', () => { const envelope = { dialect: 'cel', source: ' ' }; const decision = resolveFlowNodeExpressions('decision', { conditions: [{ label: 'Yes', expression: envelope }], @@ -339,7 +339,7 @@ describe('every pre-#14149 entry resolves byte-identically (the ratchet\'s fixtu * as "not authored", and the executor then evaluated the branch as a * condition with no `source` and failed the run there. */ - describe('a required predicate slot emits its absent value (#19961)', () => { + describe('a required predicate slot emits its absent value', () => { it('the required set is exactly the decision branch predicate — the absent arm is worded for it', () => { // `predicateSlotRefusal`'s absent arm names a decision branch and its // prescription; a second `required` entry must re-word it, so its @@ -378,7 +378,7 @@ describe('every pre-#14149 entry resolves byte-identically (the ratchet\'s fixtu }); }); - describe('predicateSlotRefusal (#15572)', () => { + describe('predicateSlotRefusal — a predicate slot holds bare CEL text', () => { it('says nothing about a non-blank string — what it SAYS is validateExpression\'s business', () => { expect(predicateSlotRefusal('record.rating >= 4')).toBeUndefined(); // Including a string that is itself malformed: the shape is right, so @@ -386,7 +386,7 @@ describe('every pre-#14149 entry resolves byte-identically (the ratchet\'s fixtu expect(predicateSlotRefusal('{record.rating} >= 4')).toBeUndefined(); }); - it('REFUSES a string that is blank after trimming, under the same sentence (#17493)', () => { + it('REFUSES a string that is blank after trimming, under the same sentence', () => { // RE-JUDGED IN PLACE (#17493, ruling A 5651023407), not deleted: the // test above used to end `expect(predicateSlotRefusal('')).toBeUndefined()` // on #15572's ground that the blank was treated the same on both sides. @@ -423,7 +423,7 @@ describe('every pre-#14149 entry resolves byte-identically (the ratchet\'s fixtu * predicate never evaluated — the run failed at the branch), so the * load-bearing clauses are pinned by name. */ - it('REFUSES no value at all — absent and `null` — under the same sentence, with the branch prescription (#19961)', () => { + it('REFUSES no value at all — absent and `null` — under the same sentence, with the branch prescription', () => { const absent = predicateSlotRefusal(undefined); const nulled = predicateSlotRefusal(null); for (const [refusal, found] of [[absent, 'Found nothing — the key is absent'], [nulled, 'Found `null`']] as const) { @@ -455,7 +455,7 @@ describe('every pre-#14149 entry resolves byte-identically (the ratchet\'s fixtu * "unified" them: an expression envelope is legitimate on this arm and must * be admitted, while `predicateSlotRefusal` refuses it. */ - describe('structuralConditionRefusal (#15662)', () => { + describe('structuralConditionRefusal — a structural condition is CEL text or an expression', () => { it('is NOT predicateSlotRefusal — an envelope is legitimate here and refused there', () => { const envelope = { dialect: 'cel', source: 'record.rating >= 4' }; // The measured reason: `FlowEdgeSchema.condition` is @@ -492,7 +492,7 @@ describe('every pre-#14149 entry resolves byte-identically (the ratchet\'s fixtu expect(structuralConditionRefusal({ dialect: 'cel', source: 'record.rating >= 4', ast: { kind: 'const' } })).toBeUndefined(); }); - it('REFUSES an `ast`-only envelope — the #15792 admission, revisited by #15807', () => { + it('REFUSES an `ast`-only envelope — admitted at first, refused once an evaluated slot required a `source`', () => { // FLIPPED. This admitted `{ dialect: 'cel', ast }` because the spec still // admitted the shape at `edge.condition` and refusing it here would have // decided #15430's question from the consumer side. #15807 decided it at diff --git a/packages/spec/src/automation/flow-predicate-slot-blank.test.ts b/packages/spec/src/automation/flow-predicate-slot-blank.test.ts index 63c9ce13ec0..1c460378efc 100644 --- a/packages/spec/src/automation/flow-predicate-slot-blank.test.ts +++ b/packages/spec/src/automation/flow-predicate-slot-blank.test.ts @@ -68,7 +68,7 @@ function issuesOf(flow: unknown) { const predicateIssues = (flow: unknown) => issuesOf(flow).filter((i) => String(i.message).startsWith(PREDICATE_SLOT_STRING_REFUSAL)); -describe('FlowSchema.parse refuses a blank string in a ledger predicate slot (#17493)', () => { +describe('FlowSchema.parse refuses a blank string in a ledger predicate slot', () => { describe.each(BLANKS)('the blank %j', (blank) => { it('decision branch `config.conditions[].expression` — code `custom`, anchored at the branch', () => { const issues = issuesOf(flowWith(decision(blank))); @@ -115,7 +115,7 @@ describe('FlowSchema.parse refuses a blank string in a ledger predicate slot (#1 expect(FlowSchema.safeParse(flowWith({ id: 'branch', type: 'decision', label: 'B', config: {} })).success).toBe(true); }); - it('a NON-string in a predicate slot is not this door\'s to refuse — #15572 refuses it at the other two', () => { + it('a NON-string in a predicate slot is not this door\'s to refuse — the other two doors refuse it', () => { // Scoped to what was ruled: the flow parse's accept set moves for blank // STRINGS only — and, since #19961, for the absent / `null` value of a // `required` slot (`flow-decision-branch-expression-absent.test.ts`), diff --git a/packages/spec/src/automation/flow-region-cycle.test.ts b/packages/spec/src/automation/flow-region-cycle.test.ts index dbcf7de6b59..0544a54ace9 100644 --- a/packages/spec/src/automation/flow-region-cycle.test.ts +++ b/packages/spec/src/automation/flow-region-cycle.test.ts @@ -76,7 +76,7 @@ const FLOW = new URL('./flow.zod.ts', import.meta.url).href; const BARREL = new URL('./index.ts', import.meta.url).href; const ENVELOPE = JSON.stringify({ dialect: 'cel', source: 'row.x > 1' }); -describe('#4415 — the flow ↔ control-flow schema cycle under OS_EAGER_SCHEMAS=1', () => { +describe('FlowNodeSchema parses its own regions — the flow ↔ control-flow schema cycle under OS_EAGER_SCHEMAS=1', () => { it('evaluates and parses regions through the automation barrel', () => { expect(importEagerly(BARREL, FLOW)).toBe(ENVELOPE); }, 60_000); diff --git a/packages/spec/src/automation/flow-region-pause-and-end.test.ts b/packages/spec/src/automation/flow-region-pause-and-end.test.ts index 9de9d33d9a2..287845b80d0 100644 --- a/packages/spec/src/automation/flow-region-pause-and-end.test.ts +++ b/packages/spec/src/automation/flow-region-pause-and-end.test.ts @@ -113,7 +113,7 @@ describe('FLOW_PAUSE_CAPABLE_NODE_TYPES — the declared set, and how it was der }); }); -describe('a region body refuses a pause-capable node (#15646)', () => { +describe('a region body refuses a pause-capable node', () => { it.each(FLOW_PAUSE_CAPABLE_NODE_TYPES)('refuses a `%s` node in a loop body, anchored on its `type`', (type) => { expect(issuesOf(flowWith([loopOver([pausingNode(type)])]))).toEqual([[ 'nodes.1.config.body.nodes.0.type', @@ -194,7 +194,7 @@ describe('a region body refuses a pause-capable node (#15646)', () => { }); }); -describe('a region body refuses an `end` node (#18112, absorbed into #15646)', () => { +describe('a region body refuses an `end` node', () => { it.each([ ['loop body', loopOver([{ id: 'stop', type: 'end', label: 'Stop' }]), 'nodes.1.config.body.nodes.0.type', "loop 'sweep' body"], ['try region', tryCatchOver([{ id: 'stop', type: 'end', label: 'Stop' }], [step('recover')]), 'nodes.1.config.try.nodes.0.type', "try_catch 'guard' try"], diff --git a/packages/spec/src/automation/flow.test.ts b/packages/spec/src/automation/flow.test.ts index f04a84a1e46..a85f79a30d1 100644 --- a/packages/spec/src/automation/flow.test.ts +++ b/packages/spec/src/automation/flow.test.ts @@ -102,7 +102,7 @@ describe('FlowVariableSchema', () => { // as `false` — the whole run stops (hotcrm#643). The engine half of the contract // is pinned in `service-automation/src/flow-variable-default.test.ts`; this half // is the authorable surface. - describe('defaultValue (#4697)', () => { + describe('defaultValue — a declared variable is bound on every path', () => { it('accepts a declared default, and keeps it as authored', () => { const parsed = FlowVariableSchema.parse({ name: 'createOpportunity', type: 'boolean', isInput: true, defaultValue: false, @@ -245,7 +245,7 @@ describe('FlowNodeSchema', () => { } }); - it('should accept node with inputSchema (outputSchema retired, #3896)', () => { + it('should accept node with inputSchema (outputSchema retired: declared, never validated)', () => { const result = FlowNodeSchema.safeParse({ id: 'script_1', type: 'script', @@ -367,7 +367,7 @@ describe('FlowSchema', () => { }); }); - it('REJECTS the retired `active` with the status prescription (#3896)', () => { + it('REJECTS the retired `active` with the status prescription', () => { let message = ''; try { FlowSchema.parse({ @@ -864,7 +864,7 @@ describe('FlowSchema - errorHandling', () => { * nobody wrote. A retry re-runs the WHOLE flow, side effects included; that * is not a count to guess on the author's behalf. */ - describe('#4247 — one default, and no zero-attempt "retry"', () => { + describe('maxRetries — one default, and no zero-attempt "retry"', () => { const retryFlow = (errorHandling: unknown) => FlowSchema.safeParse({ name: 'retry_flow', label: 'Retry Flow', @@ -926,7 +926,7 @@ describe('FlowSchema - errorHandling', () => { }); }); - it('REJECTS the retired errorHandling.fallbackNodeId — faults route via fault edges (#3896)', () => { + it('REJECTS the retired errorHandling.fallbackNodeId — faults route via fault edges', () => { expect(() => FlowSchema.parse({ name: 'fallback_flow', label: 'Fallback', @@ -1292,7 +1292,7 @@ describe('BPMN — Wait Event Configuration', () => { * (#4158). Retiring the pair is what flipped them, which is the point — the * schema now says what `wait` actually does. */ - it('rejects the retired timeout keys instead of stripping them (#4158)', () => { + it('rejects the retired timeout keys instead of stripping them', () => { for (const retired of [{ timeoutMs: 7_200_000 }, { onTimeout: 'fail' }]) { const result = FlowNodeSchema.safeParse({ id: 'wait_timer', @@ -1323,7 +1323,7 @@ describe('BPMN — Wait Event Configuration', () => { * hard-coded `'60000'` here would go green the moment someone reworded the * prose, which is precisely when this needs to be checked. */ - it('every `timerDuration` value the wait-timeout prescriptions print actually parses (#6758)', () => { + it('every `timerDuration` value the wait-timeout prescriptions print actually parses', () => { const waitNode = (waitEventConfig: Record) => ({ id: 'wait_timer', type: 'wait', label: 'Wait', waitEventConfig, }); @@ -1705,7 +1705,7 @@ describe('BPMN — Fault Edge Enhancement', () => { // surface (cloud#688 / #2419). A node's `config` record deliberately stays // OPEN: it is per-node-type, owned by the executor's `configSchema` // (#4027/#4040) and the ADR-0087 conversion layer. -describe('unknown keys are rejected, not stripped (#4001)', () => { +describe('unknown keys are rejected, not stripped', () => { const unknownKeyIssue = (schema: { safeParse: (v: unknown) => any }, value: unknown) => { const result = schema.safeParse(value); expect(result.success).toBe(false); @@ -1863,7 +1863,7 @@ describe('unknown keys are rejected, not stripped (#4001)', () => { .toContain('`is_input` → `isInput`'); }); - it('points `default` / `initialValue` at `defaultValue` (#4697)', () => { + it('points `default` / `initialValue` at `defaultValue`', () => { // The two words an author reaches for — `default` is what a page state // slot and an action param already alias, and `initialValue` is what the // designer calls it. Still REJECTED; the alias only makes the rejection @@ -1950,7 +1950,7 @@ describe('unknown keys are rejected, not stripped (#4001)', () => { expect(issue!.message).toContain('`cancelActivity` → `interrupting`'); }); - it('errorHandling: `backoffMs` is now ACCEPTED — it is the converged spelling (#4964)', () => { + it('errorHandling: `backoffMs` is now ACCEPTED — it is the converged spelling', () => { // This assertion used to be its exact inverse: the block demanded // `retryDelayMs` and rejected `backoffMs`, so an author who had read // `shared/retry-policy.zod.ts` (where `retryDelayMs` is tombstoned and @@ -1964,7 +1964,7 @@ describe('unknown keys are rejected, not stripped (#4001)', () => { expect(result.data!.errorHandling!.backoffMs).toBe(5000); }); - it('errorHandling: `retryDelayMs` is the tombstone and carries the rename (#4964)', () => { + it('errorHandling: `retryDelayMs` is the tombstone and carries the rename', () => { const result = FlowSchema.safeParse({ ...minimalFlow, errorHandling: { strategy: 'retry', maxRetries: 3, retryDelayMs: 5000 }, @@ -2057,7 +2057,7 @@ describe('unknown keys are rejected, not stripped (#4001)', () => { }); }); -describe('FlowSchema — edge ids are unique (#14964)', () => { +describe('FlowSchema — edge ids are unique', () => { // The card's probe, reproduced: two edges differing only in source/target, // both `id: 'dup'`, parsed on green through 17.2.0. The control beside it — // an invalid edge `type` on the SAME schema instance — is what proves the @@ -2161,7 +2161,7 @@ describe('FlowSchema — edge ids are unique (#14964)', () => { }); }); -describe('FlowSchema — top-level node ids are unique (#15713)', () => { +describe('FlowSchema — top-level node ids are unique', () => { // The card's probe, reproduced: a four-node flow with `nodes[1].id === // nodes[2].id === 'n'`, parsed on green (`origin/main` 1f2a02ba re-measured // before this rule landed). The two controls beside it — a node missing its @@ -2307,7 +2307,7 @@ describe('FlowSchema — top-level node ids are unique (#15713)', () => { // would move it rather than drift. Taken: the same shape is now refused, by // the same rule, in the same shape. The full region pin set is the #16134 // describe below; this one is the boundary itself. - it('a region node reusing a top-level id is refused — the #15713 boundary, moved by #16134', () => { + it('a region node reusing a top-level id is refused — one node-id space now spans every region', () => { const result = FlowSchema.safeParse(flowWith([ { id: 'start', type: 'start', label: 'Start' }, { @@ -2330,7 +2330,7 @@ describe('FlowSchema — top-level node ids are unique (#15713)', () => { }); }); -describe('FlowSchema — one node-id space across the top-level nodes[] and every region (#16134)', () => { +describe('FlowSchema — one node-id space across the top-level nodes[] and every region', () => { // The ruling (director seat, decision batch #61, 2026-09-07, maintainer // 「同意」): top-level `nodes[]` and every region body (`loop` / `try_catch` / // `parallel`, at every depth) share ONE id space; a collision is refused at diff --git a/packages/spec/src/automation/io-node-config.test.ts b/packages/spec/src/automation/io-node-config.test.ts index 931dc217dd7..bffe229c0ac 100644 --- a/packages/spec/src/automation/io-node-config.test.ts +++ b/packages/spec/src/automation/io-node-config.test.ts @@ -26,13 +26,13 @@ function unknownKeyMessage(schema: { safeParse(v: unknown): { success: boolean; return result.error!.issues.find((i) => i.code === 'unrecognized_keys')?.message; } -describe('NotifyConfigSchema — strict as of #4001 批 9', () => { +describe('NotifyConfigSchema — an unknown key is refused, not stripped', () => { // Since #9205 the declared keys split into TWO content paths that cannot // coexist on one node (see the mutual-exclusion pins below), so "accepts // every declared key" is two configs: the inline path carries every key // except `template`/`templateData`; the template path carries those two in // place of `title`/`message`. - it('accepts every declared key (inline content path — unchanged by #9205)', () => { + it('accepts every declared key (inline content path — unchanged by the template path)', () => { const full = { recipients: ['{record.assignee}'], title: 'New task', @@ -49,7 +49,7 @@ describe('NotifyConfigSchema — strict as of #4001 批 9', () => { expect(NotifyConfigSchema.parse(full)).toEqual(full); }); - it('accepts every declared key (template content path — #9205)', () => { + it('accepts every declared key (template content path)', () => { const full = { recipients: ['{record.assignee}'], template: 'crm.large_deal_won', @@ -125,7 +125,7 @@ describe('NotifyConfigSchema — strict as of #4001 批 9', () => { } }); - it('sourceObject/sourceId describes state the documented pair tolerance, not a phantom requirement (#7085)', () => { + it('sourceObject/sourceId describes state the documented pair tolerance, not a phantom requirement', () => { const shape = (NotifyConfigSchema as unknown as { shape: Record }).shape; for (const [key, partner] of [ ['sourceObject', 'sourceId'], @@ -170,7 +170,7 @@ describe('NotifyConfigSchema — strict as of #4001 批 9', () => { // downstream `switch`. The three surfaces that already agreed on the closed // set: this describe, `Notification['severity']`, and the // `sys_inbox_message.severity` select field. - describe('severity (#7086)', () => { + describe('severity — the closed info | warning | critical vocabulary', () => { /** The `severity` issues of a failed parse, or `[]` when it was accepted. */ function severityIssues(value: unknown): ReadonlyArray<{ code: string; message: string }> { const result = NotifyConfigSchema.safeParse({ recipients: 'u1', title: 't', severity: value }); @@ -249,7 +249,7 @@ describe('NotifyConfigSchema — strict as of #4001 批 9', () => { // wording: a future edit that says "one value for the whole notification" // or "not one per recipient" again turns these RED, because the wording an // author reads is the whole contract here — declared must equal enforced. - describe('template reference (#9205)', () => { + describe('template reference — notify content localized through an email template', () => { /** Custom (superRefine) issues at exactly `path`, or `[]` when accepted. */ function customIssuesAt(value: unknown, path: string): ReadonlyArray<{ code: string; message: string }> { const result = NotifyConfigSchema.safeParse(value); @@ -259,7 +259,7 @@ describe('NotifyConfigSchema — strict as of #4001 批 9', () => { ); } - it('accepts a template-only node (no inline title) — RED on origin/main pre-#9205, where `template` was an unrecognized key', () => { + it('accepts a template-only node (no inline title) — RED before the template path existed, when `template` was an unrecognized key', () => { expect(NotifyConfigSchema.safeParse({ recipients: ['u1'], template: 'crm.large_deal_won', @@ -306,7 +306,7 @@ describe('NotifyConfigSchema — strict as of #4001 批 9', () => { expect(issues[0]!.message).toContain('`template`'); }); - it('refuses a node with NEITHER inline title NOR template (at-least-one; a bare missing title refused pre-#9205 too, as invalid_type)', () => { + it('refuses a node with NEITHER inline title NOR template (at-least-one; a bare missing title was refused before the template path too, as invalid_type)', () => { const issues = customIssuesAt({ recipients: ['u1'] }, 'title'); expect(issues).toHaveLength(1); expect(issues[0]!.message).toContain('`template`'); @@ -360,7 +360,7 @@ describe('NotifyConfigSchema — strict as of #4001 批 9', () => { }); }); -describe('HttpConfigSchema — strict as of #4001 批 9', () => { +describe('HttpConfigSchema — an unknown key is refused, not stripped', () => { it('accepts every declared key', () => { const full = { url: 'https://example.test/hook', diff --git a/packages/spec/src/automation/region-normalization.test.ts b/packages/spec/src/automation/region-normalization.test.ts index ecd1b06609b..911737afaa6 100644 --- a/packages/spec/src/automation/region-normalization.test.ts +++ b/packages/spec/src/automation/region-normalization.test.ts @@ -68,7 +68,7 @@ const loopWith = (body: unknown, id = 'loop') => ({ id, type: LOOP_NODE_TYPE, label: 'Loop', config: { collection: '{rows}', iteratorVariable: 'row', body }, }); -describe('#4415 — FlowSchema.parse canonicalizes regions with no second call', () => { +describe('FlowSchema.parse canonicalizes regions with no second call', () => { it('envelopes a loop-body edge condition, matching what the top-level edge got', () => { const flow = flowWith(loopWith(gatedRegion())); @@ -209,7 +209,7 @@ describe('#4415 — FlowSchema.parse canonicalizes regions with no second call', }); }); -describe('#4415 — FlowNodeSchema is the parse seam, at any entry point', () => { +describe('FlowNodeSchema is the parse seam, at any entry point', () => { it('normalizes a region when a node is parsed on its own, not only via FlowSchema', () => { // The unwritten rule #4415 removed: a consumer holding a single node — the // Studio inspector, a plugin validating one step — used to have no way to @@ -219,7 +219,7 @@ describe('#4415 — FlowNodeSchema is the parse seam, at any entry point', () => }); }); -describe('#4347 — collectFlowGraphs', () => { +describe('collectFlowGraphs — every region is walked, not only the top level', () => { it('yields the flow graph plus every region, each scoped', () => { const flow = flowWith(loopWith(gatedRegion())); const graphs = collectFlowGraphs(flow); @@ -261,7 +261,7 @@ describe('#4347 — collectFlowGraphs', () => { ]); }); - it('carries each graph\'s key path beside its scope, so a finding can be anchored where the author wrote it (#16134)', () => { + it('carries each graph\'s key path beside its scope, so a finding can be anchored where the author wrote it', () => { const flow = flowWith(loopWith({ nodes: [{ id: 'tc', type: TRY_CATCH_NODE_TYPE, label: 'Guard', @@ -315,7 +315,7 @@ describe('#4347 — collectFlowGraphs', () => { * where the author wrote it, is pinned below to stay indexed over the RAW * list. */ - describe('#16752 — a non-record member never reaches a returned graph', () => { + describe('a non-record member never reaches a returned graph', () => { /** * The five shapes a raw node list holds that are not a node. `null` is the * one an author writes by accident (an empty YAML list item deserialises to @@ -366,7 +366,7 @@ describe('#4347 — collectFlowGraphs', () => { expect(graphs[graphs.length - 1]!.nodes.map(n => n.id)).toEqual(['gate_in', 'write_in']); }); - it('lets `FlowSchema.safeParse` return an envelope rather than throw (#16134)', () => { + it('lets `FlowSchema.safeParse` return an envelope rather than throw', () => { // This walk runs inside the parse, so the repair has to stay a drop and // a skip; a throw here escapes `safeParse` instead of becoming an issue. const result = FlowSchema.safeParse({ @@ -432,7 +432,7 @@ describe('#4347 — collectFlowGraphs', () => { * argument. ⛔ The repair is a drop, never a looser signature, and never a new * refusal — the accept set of every authoring door is unchanged. */ - describe('#18102 — a non-record edge member never reaches a returned graph', () => { + describe('a non-record edge member never reaches a returned graph', () => { /** The same five shapes the node-side pin sweeps; `null` is the authored one. */ const NON_EDGES: readonly (readonly [string, unknown])[] = [ ['null', null], @@ -490,7 +490,7 @@ describe('#4347 — collectFlowGraphs', () => { expect(innermost.nodes.map(n => n.id)).toEqual(['gate_in', 'write_in']); }); - it('lets `FlowSchema.safeParse` return an envelope rather than throw (#16134)', () => { + it('lets `FlowSchema.safeParse` return an envelope rather than throw', () => { // This walk runs inside the parse, so the repair has to stay a drop; a // throw here escapes `safeParse` instead of becoming an issue. const result = FlowSchema.safeParse({ diff --git a/packages/spec/src/automation/region-slots.test.ts b/packages/spec/src/automation/region-slots.test.ts index dc8e78606af..2754baceee3 100644 --- a/packages/spec/src/automation/region-slots.test.ts +++ b/packages/spec/src/automation/region-slots.test.ts @@ -106,7 +106,7 @@ function regionSlotsAccepted( const byKey = (a: { key: string }, b: { key: string }) => a.key.localeCompare(b.key); -describe('#4401 — FLOW_REGION_SLOTS reconciles with the ADR-0031 construct schemas', () => { +describe('FLOW_REGION_SLOTS, the one declaration of where regions live, reconciles with the ADR-0031 construct schemas', () => { it('declares exactly the slots each construct accepts, at the right arity', () => { for (const [nodeType, schema] of Object.entries(REGION_BEARING_CONFIGS)) { const declared = FLOW_REGION_SLOTS @@ -158,7 +158,7 @@ describe('#4401 — FLOW_REGION_SLOTS reconciles with the ADR-0031 construct sch }); }); -describe('#4401 — the derived views stay in step with the source list', () => { +describe('the derived views stay in step with the source list', () => { it('indexes every slot by its container type', () => { expect([...FLOW_REGION_SLOTS_BY_TYPE.values()].flat().sort(byKey)) .toEqual([...FLOW_REGION_SLOTS].sort(byKey)); diff --git a/packages/spec/src/automation/schemaless-node-config.test.ts b/packages/spec/src/automation/schemaless-node-config.test.ts index 90f1893e3ae..3fd4716de1f 100644 --- a/packages/spec/src/automation/schemaless-node-config.test.ts +++ b/packages/spec/src/automation/schemaless-node-config.test.ts @@ -61,7 +61,7 @@ const SCRIPT_RETIRED: ReadonlyArray<[string, unknown]> = [ ['script', 'return { ok: true };'], ]; -describe('ScriptConfigSchema (#4343 — converged to a function call)', () => { +describe('ScriptConfigSchema (converged to a function call)', () => { it('accepts the one shape the executor runs', () => { expect(ScriptConfigSchema.parse({ function: 'score_lead', @@ -119,7 +119,7 @@ describe('ScriptConfigSchema (#4343 — converged to a function call)', () => { }); }); -describe('SubflowConfigSchema (#4343 — parsed at execute time)', () => { +describe('SubflowConfigSchema (parsed at execute time)', () => { it('accepts the executor-read shape', () => { expect(SubflowConfigSchema.parse({ flowName: 'escalation_flow', @@ -141,7 +141,7 @@ describe('SubflowConfigSchema (#4343 — parsed at execute time)', () => { }); }); -describe('unknown keys — closed at #4001 批 9, and this class had no other gate', () => { +describe('unknown keys — refused, not stripped, and this class had no other gate', () => { // The asymmetry worth stating once: `registerFlow()`'s #4277 undeclared-key // rejection derives its declared set from a descriptor `configSchema`, and // these three node types publish none — so the walk skips them BY @@ -199,7 +199,7 @@ describe('unknown keys — closed at #4001 批 9, and this class had no other ga expect(timeout).toContain('FlowNodeSchema.timeoutMs'); }); - it('decision: `condition` gets the #4414 mechanism, NOT the one-edit rename to `conditions`', () => { + it('decision: `condition` is pointed at the out-edges, NOT given the one-edit rename to `conditions`', () => { // The finding-7 case this batch had to get right. `condition` → // `conditions` is one character, so a bare suggester proposes it with // confidence — and taking that advice produces the double-declaration @@ -240,7 +240,7 @@ describe('unknown keys — closed at #4001 批 9, and this class had no other ga }); }); -describe('DecisionConfigSchema.mode (#15429 item 2 — the contract half, declared ahead of the engine)', () => { +describe('DecisionConfigSchema.mode (taking every true branch must be declared — the contract half, declared ahead of the engine)', () => { it('accepts an omitted mode and both members, and injects nothing', () => { // No `.default('exclusive')`: "omitted means exclusive" is the contract's // prose and the future reader's job, so the parsed output stays exactly the diff --git a/packages/spec/src/automation/sync-retirement.test.ts b/packages/spec/src/automation/sync-retirement.test.ts index c709515eb75..583f8ddaf3e 100644 --- a/packages/spec/src/automation/sync-retirement.test.ts +++ b/packages/spec/src/automation/sync-retirement.test.ts @@ -65,7 +65,7 @@ import { // anti-vacuity guards; sabotage-verified in the PR (re-adding an automation // export, re-introducing a bare-name re-export on ./integration, and renaming // the ui side each turn it red). -describe('[#4738] sync/conflict dual-source retirement', () => { +describe('sync/conflict dual-source retirement', () => { it('resolves the export surface: one owner per name, across every public entry', () => { // Anti-vacuity: the baseline must cover the real surface. (This used to // enumerate package.json's exports map and build its own `ts.createProgram` @@ -117,7 +117,7 @@ describe('[#4738] sync/conflict dual-source retirement', () => { ]) { expect( automationNames, - `./automation must not export ${alsoRetired} (#6414, L2 retired on L1's reading)`, + `./automation must not export ${alsoRetired} (L2 retired on L1's reading)`, ).not.toContain(alsoRetired); } @@ -155,7 +155,7 @@ describe('[#4738] sync/conflict dual-source retirement', () => { const holders = holderOriginsOf(name); expect( holders.map((h) => `${h.sub} (${h.origin})`), - `${name} was retired with ui/offline.zod.ts at #4988 — no entry may re-adopt the bare name`, + `${name} was retired with ui/offline.zod.ts — no entry may re-adopt the bare name`, ).toEqual([]); } diff --git a/packages/spec/src/automation/time-relative-trigger.test.ts b/packages/spec/src/automation/time-relative-trigger.test.ts index bd2b7055556..9dc259aa776 100644 --- a/packages/spec/src/automation/time-relative-trigger.test.ts +++ b/packages/spec/src/automation/time-relative-trigger.test.ts @@ -93,7 +93,7 @@ describe('TimeRelativeTriggerSchema', () => { // // It also sits BELOW the deliberately-open node `config` slot (ADR-0018), so // the flow gate cannot see inside it. This schema is the only gate there is. -describe('unknown keys are rejected, not stripped (#4001 batch 11)', () => { +describe('unknown keys are rejected, not stripped', () => { const unknownKeyIssue = (value: unknown) => { const result = TimeRelativeTriggerSchema.safeParse(value); expect(result.success).toBe(false); diff --git a/packages/spec/src/automation/webhook.test.ts b/packages/spec/src/automation/webhook.test.ts index d05f304fcc2..7d8233e22e0 100644 --- a/packages/spec/src/automation/webhook.test.ts +++ b/packages/spec/src/automation/webhook.test.ts @@ -14,7 +14,7 @@ describe('WebhookTriggerType', () => { }); }); - it('should reject undelete / api — removed, no event source (#3196)', () => { + it('should reject undelete / api — removed, no event source', () => { // `undelete` had no soft-delete/restore producer; `api` had no manual fire // path. Removed rather than left as silent no-ops — authoring one now fails // loudly instead of registering a webhook that never fires. @@ -228,7 +228,7 @@ describe('WebhookSchema', () => { // every declared webhook before materializing it into `sys_webhook`, and a // failure there warns and SKIPS the subscription — so a rejection here is the // difference between a webhook that exists and one that does not. -describe('unknown keys are rejected, not stripped (#4001 batch 11)', () => { +describe('unknown keys are rejected, not stripped', () => { const valid = { name: 'wh_probe', url: 'https://hooks.example/x' }; const unknownKeyIssue = (value: unknown) => { const result = WebhookSchema.safeParse(value); @@ -290,7 +290,7 @@ describe('unknown keys are rejected, not stripped (#4001 batch 11)', () => { * defect was invisible to an accepts-shaped assertion, so the preservation * question gets an assertion over the complete key set, by value. */ - it('[#6362] PRESERVES all seven envelope keys — measured, not assumed', () => { + it('PRESERVES all seven envelope keys — measured, not assumed', () => { const envelope = { _lock: 'full', _lockReason: 'Ships with the package.', From f3dc3fab0348b197ff686d1fd9b33adffb6d87df Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 4 Oct 2026 09:04:35 +0000 Subject: [PATCH 2/2] test(spec): keep the blank-string row name short enough to print whole vitest prints a table row's `$name` truncated past about forty characters, so the rewritten row now states its decision in a name that prints whole. Claude-Session: https://claude.ai/code/session_01T9u38rswFp5Rw8DswRUReJ Co-authored-by: Claude --- .../automation/flow-decision-branch-expression-absent.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/spec/src/automation/flow-decision-branch-expression-absent.test.ts b/packages/spec/src/automation/flow-decision-branch-expression-absent.test.ts index bf9da2de74d..4f9c3359dab 100644 --- a/packages/spec/src/automation/flow-decision-branch-expression-absent.test.ts +++ b/packages/spec/src/automation/flow-decision-branch-expression-absent.test.ts @@ -63,7 +63,7 @@ const TABLE: Array<{ name: string; branch: Node; refused: boolean; refusedWith?: { name: 'no `expression` key', branch: { label: 'y' }, refused: true, refusedWith: undefined }, { name: '`expression: null`', branch: { label: 'y', expression: null }, refused: true, refusedWith: null }, { name: 'the predicate under the edge\'s spelling `condition`', branch: { label: 'y', condition: 'true' }, refused: true, refusedWith: undefined }, - { name: 'a blank string — the control: a blank predicate is already refused', branch: { label: 'y', expression: ' ' }, refused: true, refusedWith: ' ' }, + { name: 'a blank string — blanks are refused', branch: { label: 'y', expression: ' ' }, refused: true, refusedWith: ' ' }, { name: 'a real predicate — the accept control', branch: { label: 'y', expression: 'true' }, refused: false }, ];