@company-semantics/contracts 95.0.0 → 96.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1763,6 +1763,66 @@ export interface paths {
1763
1763
  patch?: never;
1764
1764
  trace?: never;
1765
1765
  };
1766
+ "/api/analysis-workflows/{id}/continue": {
1767
+ parameters: {
1768
+ query?: never;
1769
+ header?: never;
1770
+ path?: never;
1771
+ cookie?: never;
1772
+ };
1773
+ get?: never;
1774
+ put?: never;
1775
+ /**
1776
+ * Start another execution of a stopped analysis workflow
1777
+ * @description Reopens a STOPPED workflow in a new execution epoch and starts the execution its type serves for continue — only for a type whose execution support declares continue (otherwise 409 not_supported). Answers 202 when started; 409 not_stopped or execution_in_flight otherwise. Runtime posture: intent write, impersonation restricted (it spends model calls); the billing pre-flight runs before anything is created, and a refusal is the billing refusal envelope. An Idempotency-Key header replays the first answer for the same workflow and action. Org-scoped: a workflow in another workspace answers 404.
1778
+ */
1779
+ post: operations["continueAnalysisWorkflow"];
1780
+ delete?: never;
1781
+ options?: never;
1782
+ head?: never;
1783
+ patch?: never;
1784
+ trace?: never;
1785
+ };
1786
+ "/api/analysis-workflows/{id}/retry": {
1787
+ parameters: {
1788
+ query?: never;
1789
+ header?: never;
1790
+ path?: never;
1791
+ cookie?: never;
1792
+ };
1793
+ get?: never;
1794
+ put?: never;
1795
+ /**
1796
+ * Retry a failed analysis workflow in the same workflow
1797
+ * @description Reopens a FAILED workflow in a new execution epoch (never a new workflow id) and starts the execution its type serves for retry — only for a type whose execution support declares retry (otherwise 409 not_supported). Answers 202 when started; 409 not_failed or execution_in_flight otherwise. Runtime posture: intent write, impersonation restricted (it spends model calls); the billing pre-flight runs before anything is created, and a refusal is the billing refusal envelope. An Idempotency-Key header replays the first answer for the same workflow and action. Org-scoped: a workflow in another workspace answers 404.
1798
+ */
1799
+ post: operations["retryAnalysisWorkflow"];
1800
+ delete?: never;
1801
+ options?: never;
1802
+ head?: never;
1803
+ patch?: never;
1804
+ trace?: never;
1805
+ };
1806
+ "/api/analysis-workflows/{id}/run-again": {
1807
+ parameters: {
1808
+ query?: never;
1809
+ header?: never;
1810
+ path?: never;
1811
+ cookie?: never;
1812
+ };
1813
+ get?: never;
1814
+ put?: never;
1815
+ /**
1816
+ * Run a settled analysis workflow again as a new workflow
1817
+ * @description Launches a NEW workflow from the settled one’s parameters under the caller’s current authorization, recording relaunchedFrom, and anchors it in the launching conversation named by chatId so its settlement is delivered there. The old workflow is never written. Only for a type whose execution support declares runAgain (otherwise 409 not_supported); a workflow already open for the same launch answers 409 run_in_progress with its id — never joined, never duplicated. A conversation the caller may not write in answers 404 before anything is created. Runtime posture: intent write, impersonation restricted (it spends model calls); the billing pre-flight runs before anything is created, and a refusal is the billing refusal envelope. An Idempotency-Key header replays the first answer for the same workflow and action. Org-scoped: a workflow in another workspace answers 404.
1818
+ */
1819
+ post: operations["runAnalysisWorkflowAgain"];
1820
+ delete?: never;
1821
+ options?: never;
1822
+ head?: never;
1823
+ patch?: never;
1824
+ trace?: never;
1825
+ };
1766
1826
  "/api/affordances/state": {
1767
1827
  parameters: {
1768
1828
  query?: never;
@@ -7263,6 +7323,34 @@ export interface components {
7263
7323
  args: {
7264
7324
  executionId: string;
7265
7325
  };
7326
+ } | {
7327
+ /** @constant */
7328
+ id: "workflow.stop";
7329
+ args: {
7330
+ /** Format: uuid */
7331
+ workflowId: string;
7332
+ };
7333
+ } | {
7334
+ /** @constant */
7335
+ id: "workflow.continue";
7336
+ args: {
7337
+ /** Format: uuid */
7338
+ workflowId: string;
7339
+ };
7340
+ } | {
7341
+ /** @constant */
7342
+ id: "workflow.retry";
7343
+ args: {
7344
+ /** Format: uuid */
7345
+ workflowId: string;
7346
+ };
7347
+ } | {
7348
+ /** @constant */
7349
+ id: "workflow.runAgain";
7350
+ args: {
7351
+ /** Format: uuid */
7352
+ workflowId: string;
7353
+ };
7266
7354
  })[];
7267
7355
  } | {
7268
7356
  /** @constant */
@@ -7361,6 +7449,34 @@ export interface components {
7361
7449
  args: {
7362
7450
  executionId: string;
7363
7451
  };
7452
+ } | {
7453
+ /** @constant */
7454
+ id: "workflow.stop";
7455
+ args: {
7456
+ /** Format: uuid */
7457
+ workflowId: string;
7458
+ };
7459
+ } | {
7460
+ /** @constant */
7461
+ id: "workflow.continue";
7462
+ args: {
7463
+ /** Format: uuid */
7464
+ workflowId: string;
7465
+ };
7466
+ } | {
7467
+ /** @constant */
7468
+ id: "workflow.retry";
7469
+ args: {
7470
+ /** Format: uuid */
7471
+ workflowId: string;
7472
+ };
7473
+ } | {
7474
+ /** @constant */
7475
+ id: "workflow.runAgain";
7476
+ args: {
7477
+ /** Format: uuid */
7478
+ workflowId: string;
7479
+ };
7364
7480
  })[];
7365
7481
  } | {
7366
7482
  /** @constant */
@@ -7461,6 +7577,34 @@ export interface components {
7461
7577
  args: {
7462
7578
  executionId: string;
7463
7579
  };
7580
+ } | {
7581
+ /** @constant */
7582
+ id: "workflow.stop";
7583
+ args: {
7584
+ /** Format: uuid */
7585
+ workflowId: string;
7586
+ };
7587
+ } | {
7588
+ /** @constant */
7589
+ id: "workflow.continue";
7590
+ args: {
7591
+ /** Format: uuid */
7592
+ workflowId: string;
7593
+ };
7594
+ } | {
7595
+ /** @constant */
7596
+ id: "workflow.retry";
7597
+ args: {
7598
+ /** Format: uuid */
7599
+ workflowId: string;
7600
+ };
7601
+ } | {
7602
+ /** @constant */
7603
+ id: "workflow.runAgain";
7604
+ args: {
7605
+ /** Format: uuid */
7606
+ workflowId: string;
7607
+ };
7464
7608
  })[];
7465
7609
  } | {
7466
7610
  /** @constant */
@@ -7561,6 +7705,34 @@ export interface components {
7561
7705
  args: {
7562
7706
  executionId: string;
7563
7707
  };
7708
+ } | {
7709
+ /** @constant */
7710
+ id: "workflow.stop";
7711
+ args: {
7712
+ /** Format: uuid */
7713
+ workflowId: string;
7714
+ };
7715
+ } | {
7716
+ /** @constant */
7717
+ id: "workflow.continue";
7718
+ args: {
7719
+ /** Format: uuid */
7720
+ workflowId: string;
7721
+ };
7722
+ } | {
7723
+ /** @constant */
7724
+ id: "workflow.retry";
7725
+ args: {
7726
+ /** Format: uuid */
7727
+ workflowId: string;
7728
+ };
7729
+ } | {
7730
+ /** @constant */
7731
+ id: "workflow.runAgain";
7732
+ args: {
7733
+ /** Format: uuid */
7734
+ workflowId: string;
7735
+ };
7564
7736
  })[];
7565
7737
  }) | null;
7566
7738
  error?: string;
@@ -7586,10 +7758,44 @@ export interface components {
7586
7758
  /** @enum {string} */
7587
7759
  result: "delivered" | "deferred" | "busy" | "skipped" | "not_settled";
7588
7760
  };
7761
+ WorkflowExecutionStartedResponse: {
7762
+ /** @constant */
7763
+ started: true;
7764
+ /** Format: uuid */
7765
+ workflowId: string;
7766
+ executionEpoch: number;
7767
+ /** @constant */
7768
+ state: "pending";
7769
+ };
7770
+ WorkflowExecutionRefusal: {
7771
+ /** @constant */
7772
+ refused: true;
7773
+ /** @enum {string} */
7774
+ reason: "not_stopped" | "not_failed" | "execution_in_flight" | "not_supported" | "run_in_progress";
7775
+ /** @enum {string} */
7776
+ state: "pending" | "running" | "draining" | "stopped" | "complete" | "failed";
7777
+ /** Format: uuid */
7778
+ workflowId: string;
7779
+ openWorkflowId?: string | null;
7780
+ };
7781
+ WorkflowRunAgainResponse: {
7782
+ /** @constant */
7783
+ launched: true;
7784
+ /** Format: uuid */
7785
+ workflowId: string;
7786
+ /** Format: uuid */
7787
+ relaunchedFrom: string;
7788
+ /** @constant */
7789
+ state: "pending";
7790
+ };
7791
+ RunAnalysisWorkflowAgainRequest: {
7792
+ /** Format: uuid */
7793
+ chatId: string;
7794
+ };
7589
7795
  AffordanceStateResponse: {
7590
7796
  entries: {
7591
7797
  /** @enum {string} */
7592
- id: "sourceSync.findFiles" | "integrations.connectGoogleDrive" | "sourceSync.enable" | "billing.open" | "orgStructure.reanalyze" | "hris.resyncDirectory" | "review.open" | "integrations.open" | "hris.connect" | "account.editProfile" | "workspace.openOrgSettings" | "sourceSync.addFile" | "sourceSync.openUpdate" | "orgStructure.openReview" | "chat.open" | "companyMd.openDoc" | "companyMd.openHistory" | "team.open" | "execution.open";
7798
+ id: "sourceSync.findFiles" | "integrations.connectGoogleDrive" | "sourceSync.enable" | "billing.open" | "orgStructure.reanalyze" | "hris.resyncDirectory" | "review.open" | "integrations.open" | "hris.connect" | "account.editProfile" | "workspace.openOrgSettings" | "sourceSync.addFile" | "sourceSync.openUpdate" | "orgStructure.openReview" | "chat.open" | "companyMd.openDoc" | "companyMd.openHistory" | "team.open" | "execution.open" | "workflow.stop" | "workflow.continue" | "workflow.retry" | "workflow.runAgain";
7593
7799
  /** @enum {string} */
7594
7800
  policy: "allowed" | "blocked";
7595
7801
  availability: {
@@ -8763,6 +8969,34 @@ export interface components {
8763
8969
  args: {
8764
8970
  executionId: string;
8765
8971
  };
8972
+ } | {
8973
+ /** @constant */
8974
+ id: "workflow.stop";
8975
+ args: {
8976
+ /** Format: uuid */
8977
+ workflowId: string;
8978
+ };
8979
+ } | {
8980
+ /** @constant */
8981
+ id: "workflow.continue";
8982
+ args: {
8983
+ /** Format: uuid */
8984
+ workflowId: string;
8985
+ };
8986
+ } | {
8987
+ /** @constant */
8988
+ id: "workflow.retry";
8989
+ args: {
8990
+ /** Format: uuid */
8991
+ workflowId: string;
8992
+ };
8993
+ } | {
8994
+ /** @constant */
8995
+ id: "workflow.runAgain";
8996
+ args: {
8997
+ /** Format: uuid */
8998
+ workflowId: string;
8999
+ };
8766
9000
  } | {
8767
9001
  /** @constant */
8768
9002
  id: "review.open";
@@ -8869,6 +9103,34 @@ export interface components {
8869
9103
  args: {
8870
9104
  executionId: string;
8871
9105
  };
9106
+ } | {
9107
+ /** @constant */
9108
+ id: "workflow.stop";
9109
+ args: {
9110
+ /** Format: uuid */
9111
+ workflowId: string;
9112
+ };
9113
+ } | {
9114
+ /** @constant */
9115
+ id: "workflow.continue";
9116
+ args: {
9117
+ /** Format: uuid */
9118
+ workflowId: string;
9119
+ };
9120
+ } | {
9121
+ /** @constant */
9122
+ id: "workflow.retry";
9123
+ args: {
9124
+ /** Format: uuid */
9125
+ workflowId: string;
9126
+ };
9127
+ } | {
9128
+ /** @constant */
9129
+ id: "workflow.runAgain";
9130
+ args: {
9131
+ /** Format: uuid */
9132
+ workflowId: string;
9133
+ };
8872
9134
  } | {
8873
9135
  /** @constant */
8874
9136
  id: "review.open";
@@ -14118,6 +14380,145 @@ export interface operations {
14118
14380
  };
14119
14381
  };
14120
14382
  };
14383
+ continueAnalysisWorkflow: {
14384
+ parameters: {
14385
+ query?: never;
14386
+ header?: never;
14387
+ path: {
14388
+ id: string;
14389
+ };
14390
+ cookie?: never;
14391
+ };
14392
+ requestBody?: never;
14393
+ responses: {
14394
+ /** @description Another execution of the same workflow is under way */
14395
+ 202: {
14396
+ headers: {
14397
+ [name: string]: unknown;
14398
+ };
14399
+ content: {
14400
+ "application/json": components["schemas"]["WorkflowExecutionStartedResponse"];
14401
+ };
14402
+ };
14403
+ /** @description The workflow id is not a uuid */
14404
+ 400: {
14405
+ headers: {
14406
+ [name: string]: unknown;
14407
+ };
14408
+ content?: never;
14409
+ };
14410
+ /** @description No such workflow in this workspace */
14411
+ 404: {
14412
+ headers: {
14413
+ [name: string]: unknown;
14414
+ };
14415
+ content?: never;
14416
+ };
14417
+ /** @description Nothing was started: the reason and the workflow’s authoritative current state */
14418
+ 409: {
14419
+ headers: {
14420
+ [name: string]: unknown;
14421
+ };
14422
+ content: {
14423
+ "application/json": components["schemas"]["WorkflowExecutionRefusal"];
14424
+ };
14425
+ };
14426
+ };
14427
+ };
14428
+ retryAnalysisWorkflow: {
14429
+ parameters: {
14430
+ query?: never;
14431
+ header?: never;
14432
+ path: {
14433
+ id: string;
14434
+ };
14435
+ cookie?: never;
14436
+ };
14437
+ requestBody?: never;
14438
+ responses: {
14439
+ /** @description Another execution of the same workflow is under way */
14440
+ 202: {
14441
+ headers: {
14442
+ [name: string]: unknown;
14443
+ };
14444
+ content: {
14445
+ "application/json": components["schemas"]["WorkflowExecutionStartedResponse"];
14446
+ };
14447
+ };
14448
+ /** @description The workflow id is not a uuid */
14449
+ 400: {
14450
+ headers: {
14451
+ [name: string]: unknown;
14452
+ };
14453
+ content?: never;
14454
+ };
14455
+ /** @description No such workflow in this workspace */
14456
+ 404: {
14457
+ headers: {
14458
+ [name: string]: unknown;
14459
+ };
14460
+ content?: never;
14461
+ };
14462
+ /** @description Nothing was started: the reason and the workflow’s authoritative current state */
14463
+ 409: {
14464
+ headers: {
14465
+ [name: string]: unknown;
14466
+ };
14467
+ content: {
14468
+ "application/json": components["schemas"]["WorkflowExecutionRefusal"];
14469
+ };
14470
+ };
14471
+ };
14472
+ };
14473
+ runAnalysisWorkflowAgain: {
14474
+ parameters: {
14475
+ query?: never;
14476
+ header?: never;
14477
+ path: {
14478
+ id: string;
14479
+ };
14480
+ cookie?: never;
14481
+ };
14482
+ requestBody: {
14483
+ content: {
14484
+ "application/json": components["schemas"]["RunAnalysisWorkflowAgainRequest"];
14485
+ };
14486
+ };
14487
+ responses: {
14488
+ /** @description A new workflow was launched and anchored in the conversation */
14489
+ 202: {
14490
+ headers: {
14491
+ [name: string]: unknown;
14492
+ };
14493
+ content: {
14494
+ "application/json": components["schemas"]["WorkflowRunAgainResponse"];
14495
+ };
14496
+ };
14497
+ /** @description The workflow id or the chat id is not a uuid */
14498
+ 400: {
14499
+ headers: {
14500
+ [name: string]: unknown;
14501
+ };
14502
+ content?: never;
14503
+ };
14504
+ /** @description No such workflow, or no such conversation the caller may write in */
14505
+ 404: {
14506
+ headers: {
14507
+ [name: string]: unknown;
14508
+ };
14509
+ content?: never;
14510
+ };
14511
+ /** @description Nothing was started: the reason and the workflow’s authoritative current state */
14512
+ 409: {
14513
+ headers: {
14514
+ [name: string]: unknown;
14515
+ };
14516
+ content: {
14517
+ "application/json": components["schemas"]["WorkflowExecutionRefusal"];
14518
+ };
14519
+ };
14520
+ };
14521
+ };
14121
14522
  getAffordanceState: {
14122
14523
  parameters: {
14123
14524
  query: {
@@ -11,6 +11,9 @@ export const openApiRoutes = {
11
11
  '/api/account/sessions/{sessionId}': ['DELETE'],
12
12
  '/api/affordances/state': ['GET'],
13
13
  '/api/analysis-workflows/{id}': ['GET'],
14
+ '/api/analysis-workflows/{id}/continue': ['POST'],
15
+ '/api/analysis-workflows/{id}/retry': ['POST'],
16
+ '/api/analysis-workflows/{id}/run-again': ['POST'],
14
17
  '/api/analysis-workflows/{id}/settlement': ['POST'],
15
18
  '/api/analysis-workflows/{id}/stop': ['POST'],
16
19
  '/api/auth/consent/grant': ['POST'],
@@ -215,9 +215,41 @@ export type {
215
215
  // chat part and by the generic projection read. Namespaced `<domain>/<flow>`
216
216
  // so domains cannot collide, and a CLOSED const array so the discriminator is
217
217
  // validated and handled exhaustively. See src/workflows/README.md.
218
- export { ANALYSIS_WORKFLOW_TYPES, isWorkflowType } from "../workflows/index";
218
+ export {
219
+ ANALYSIS_WORKFLOW_STATES,
220
+ ANALYSIS_WORKFLOW_TYPES,
221
+ isWorkflowType,
222
+ } from "../workflows/index";
223
+
224
+ export type { AnalysisWorkflowState, WorkflowType } from "../workflows/index";
225
+
226
+ // Workflow execution actions (ADR-CONTRACTS-227): `executionAffordancesFor` is
227
+ // the one total offer table from a workflow's state, its type's support and
228
+ // its frozen outcome to the workflow.* affordances. See
229
+ // src/workflows/execution-affordances.ts.
230
+ export {
231
+ DOMAIN_RELAUNCH_AFFORDANCE_IDS,
232
+ WORKFLOW_EXECUTION_ACTIONS,
233
+ executionAffordancesFor,
234
+ } from "../workflows/index";
235
+
236
+ export type {
237
+ ExecutionAffordancesInput,
238
+ WorkflowExecutionAction,
239
+ WorkflowExecutionAffordance,
240
+ WorkflowExecutionSupport,
241
+ } from "../workflows/index";
242
+
243
+ // Workflow execution projection fields (ADR-CONTRACTS-227): the offered
244
+ // workflow.* affordances, relaunch lineage and per-epoch timing the backend
245
+ // composes into its (backend-local) workflow projection. See
246
+ // src/workflows/projection-fields.ts.
247
+ export {
248
+ WorkflowExecutionAffordanceSchema,
249
+ WorkflowExecutionProjectionFieldsSchema,
250
+ } from "../workflows/index";
219
251
 
220
- export type { WorkflowType } from "../workflows/index";
252
+ export type { WorkflowExecutionProjectionFields } from "../workflows/index";
221
253
 
222
254
  // The typed outcome of a workflow's terminal transition (control ADR-CTRL-540):
223
255
  // per-type closed reasons, typed facts and an explicit disposition, classified
@@ -317,6 +349,7 @@ export {
317
349
  ReviewOpenArgsSchema,
318
350
  SourceSyncOpenUpdateArgsSchema,
319
351
  TeamOpenArgsSchema,
352
+ WorkflowExecutionArgsSchema,
320
353
  sameAffordances,
321
354
  } from "../affordances/index";
322
355
 
@@ -62,13 +62,37 @@ so every producer, validator and renderer agrees on it.
62
62
  the backend verifies the covering occurrence at route time), and `silent`
63
63
  exactly for `stopped_by_user`. A `produced`, `empty` or `partial` ending is
64
64
  never explained.
65
+ - **`ANALYSIS_WORKFLOW_STATES` is the backend's six states, in order**
66
+ (`pending`, `running`, `draining`, `stopped`, `complete`, `failed`). A
67
+ workflow id is the logical run; the backend's execution epoch is the attempt.
68
+ - **Execution actions come from one total table** (ADR-CONTRACTS-227).
69
+ `executionAffordancesFor` maps a workflow's state, its type's
70
+ `WorkflowExecutionSupport` and its frozen outcome offer to the `workflow.*`
71
+ affordances: `pending`/`running` → stop; `draining` → nothing; `stopped` →
72
+ continue, runAgain; `failed` → retry, runAgain; `complete` → runAgain. An
73
+ unsupported action is never offered, and `workflow.runAgain` is dropped
74
+ beside a frozen domain relaunch (`DOMAIN_RELAUNCH_AFFORDANCE_IDS`) — one
75
+ relaunch control, the domain's. It never emits `review.open`.
76
+ - **Projection fields, not the projection.** The workflow projection is
77
+ backend-local; `WorkflowExecutionProjectionFieldsSchema` is the one wire
78
+ shape for the fields it composes (`executionAffordances`, `relaunchedFrom`,
79
+ `epochStartedAt`, `epochCompletedAt`), every key required. Contracts does not
80
+ touch the projection's `capabilities` flags.
65
81
  - **Workflows never imports proactive.** The covering kinds are literal
66
82
  strings pinned against `PROACTIVE_EVENT_KIND_IDS` by a test; the dependency
67
83
  runs proactive → workflows only.
68
84
 
69
85
  ## Public API
70
86
 
71
- - `ANALYSIS_WORKFLOW_TYPES`, `WorkflowType`, `isWorkflowType` (`types.ts`).
87
+ - `ANALYSIS_WORKFLOW_TYPES`, `WorkflowType`, `isWorkflowType`,
88
+ `ANALYSIS_WORKFLOW_STATES`, `AnalysisWorkflowState` (`types.ts`).
89
+ - `WORKFLOW_EXECUTION_ACTIONS`, `WorkflowExecutionAction`,
90
+ `WorkflowExecutionSupport`, `WorkflowExecutionAffordance`,
91
+ `DOMAIN_RELAUNCH_AFFORDANCE_IDS`, `ExecutionAffordancesInput`,
92
+ `executionAffordancesFor` (`execution-affordances.ts`).
93
+ - `WorkflowExecutionAffordanceSchema`,
94
+ `WorkflowExecutionProjectionFieldsSchema` /
95
+ `WorkflowExecutionProjectionFields` (`projection-fields.ts`).
72
96
  - `WorkflowOutcomeSchema` / `WorkflowOutcome`, the per-type member schemas and
73
97
  `WorkflowOutcomeDispositionSchema` (`outcome.ts`).
74
98
  - `WORKFLOW_OUTCOME_KINDS` and the per-type reason tables and fact schemas
@@ -88,5 +112,6 @@ so every producer, validator and renderer agrees on it.
88
112
 
89
113
  `zod` (outcome schemas), `../input-requests/types` (the review disposition's
90
114
  request type) and `../affordances/affordance` (the offered-affordance schema,
91
- its sanity bound and `sameAffordances`). Otherwise pure vocabulary data, one
115
+ its sanity bound and `sameAffordances`) and `../affordances/args` (the
116
+ `workflow.*` args schema). Otherwise pure vocabulary data, one
92
117
  guard and pure helpers.
@@ -11,7 +11,22 @@ wire value against it.
11
11
  `<domain>/<flow>` with exactly one separator, which is the collision guard
12
12
  between domains. For `isWorkflowType`, the load-bearing cases are the
13
13
  rejections: a bare `hris-connect` without its namespace, the namespace on
14
- its own, a trailing separator, an unknown flow, and non-string inputs.
14
+ its own, a trailing separator, an unknown flow, and non-string inputs. Also
15
+ pins `ANALYSIS_WORKFLOW_STATES` as the backend's six states in order.
16
+
17
+ - `execution-affordances.test.ts` — pins `WORKFLOW_EXECUTION_ACTIONS` and
18
+ `DOMAIN_RELAUNCH_AFFORDANCE_IDS`; `executionAffordancesFor` offers the
19
+ per-state table with full support, never offers an unsupported action,
20
+ drops `workflow.runAgain` beside a frozen domain relaunch (one relaunch
21
+ control), never emits `review.open`, and every instance is a valid
22
+ `Affordance` carrying `{ workflowId }`.
23
+
24
+ - `projection-fields.test.ts` — `WorkflowExecutionAffordanceSchema` accepts
25
+ every instance the offer table emits and refuses non-`workflow.*` ids,
26
+ non-uuid `workflowId`s and extra keys; `WorkflowExecutionProjectionFieldsSchema`
27
+ requires every key (also in its JSON Schema), refuses extra keys, more than
28
+ four offers and malformed lineage/timing, and both schemas reach the package
29
+ root.
15
30
 
16
31
  - `outcome.test.ts` — the outcome union covers every registered workflow type
17
32
  (compile-time), each reason table's kinds are valid, the schema accepts a
@@ -51,5 +66,6 @@ None — test-only.
51
66
  ## Dependencies
52
67
 
53
68
  `vitest`, `node:fs`, `../types`, `../outcome`, `../affordances-of-outcome`,
54
- `../deferred-route`, `../../affordances/affordance` and
69
+ `../execution-affordances`, `../projection-fields`, `../deferred-route`, `../index`,
70
+ `../../index` (root reachability), `../../affordances/affordance` and
55
71
  `../../proactive/kinds` (test-only: pins the covering kinds).