@toloka-platform/sdk 0.11.2 → 0.11.4

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.
Files changed (76) hide show
  1. package/dist/cli/toloka.js +158 -154
  2. package/dist/cli/toloka.js.jsc +0 -0
  3. package/dist/cli/toloka.js.jsc.sha256 +1 -1
  4. package/dist/cli/toloka.js.sha256 +1 -1
  5. package/docs/authoring.md +6 -4
  6. package/docs/cli.md +30 -11
  7. package/docs/limitations.md +2 -2
  8. package/docs/testing.md +4 -2
  9. package/examples/README.md +11 -0
  10. package/examples/app-crowdtesting/README.md +41 -0
  11. package/examples/app-crowdtesting/fields.ts +6 -0
  12. package/examples/app-crowdtesting/nodes/app-flow-test/node.ts +381 -0
  13. package/examples/app-crowdtesting/nodes/collection/node.ts +8 -0
  14. package/examples/app-crowdtesting/pipeline.browser.integration.spec.ts +77 -0
  15. package/examples/app-crowdtesting/pipeline.ts +17 -0
  16. package/examples/egocentric-video-collection/README.md +35 -0
  17. package/examples/egocentric-video-collection/fields.ts +24 -0
  18. package/examples/egocentric-video-collection/nodes/collection/node.ts +5 -0
  19. package/examples/egocentric-video-collection/nodes/record-activity/node.ts +760 -0
  20. package/examples/egocentric-video-collection/pipeline.browser.integration.spec.ts +65 -0
  21. package/examples/egocentric-video-collection/pipeline.ts +17 -0
  22. package/examples/product-moderation/README.md +49 -0
  23. package/examples/product-moderation/fields.ts +37 -0
  24. package/examples/product-moderation/nodes/collection/node.ts +16 -0
  25. package/examples/product-moderation/nodes/moderate-product/instruction.ts +77 -0
  26. package/examples/product-moderation/nodes/moderate-product/node.ts +368 -0
  27. package/examples/product-moderation/pipeline.browser.integration.spec.ts +48 -0
  28. package/examples/product-moderation/pipeline.ts +33 -0
  29. package/examples/video-pair-rating/fields.ts +16 -4
  30. package/examples/video-pair-rating/nodes/adjudicate/node.ts +78 -3
  31. package/examples/video-pair-rating/nodes/adjudicate_op/node.ts +28 -3
  32. package/examples/video-pair-rating/nodes/overall_preference_pick/node.ts +28 -3
  33. package/examples/video-pair-rating/nodes/rate_pair/node.ts +65 -2
  34. package/openapi/gen/api.ts +22 -0
  35. package/openapi/gen/models/generationBudget.ts +8 -0
  36. package/openapi/gen/models/generationBudgetReasoningEffort.ts +2 -0
  37. package/openapi/gen/models/generationModel.ts +12 -0
  38. package/openapi/gen/models/generationModelDefaultReasoningEffort.ts +2 -0
  39. package/openapi/gen/models/generationModelId.ts +2 -0
  40. package/openapi/gen/models/index.ts +8 -0
  41. package/openapi/gen/models/invalidFieldSchema.ts +6 -0
  42. package/openapi/gen/models/listGenerationModels200.ts +7 -0
  43. package/openapi/gen/models/listGenerationModels200DefaultGenerationModelId.ts +2 -0
  44. package/openapi/gen/models/pipelineGraphSnapshot.ts +2 -0
  45. package/package.json +2 -2
  46. package/skills/catalog.json +16 -12
  47. package/skills/toloka-build/SKILL.md +44 -58
  48. package/skills/toloka-build/references/human-work.md +156 -0
  49. package/skills/toloka-build/references/local-setup.md +136 -0
  50. package/skills/toloka-build/references/node-checks.md +11 -0
  51. package/skills/toloka-build/references/node-semantics.md +22 -213
  52. package/skills/toloka-build/references/task-ui.md +61 -0
  53. package/skills/toloka-build/references/workflow-and-cli.md +34 -228
  54. package/skills/toloka-fine-tuning/SKILL.md +1 -1
  55. package/skills/toloka-get-started/SKILL.md +1 -1
  56. package/skills/toloka-gisting/SKILL.md +1 -1
  57. package/src/authoring/index.ts +26 -7
  58. package/src/checks/task-ui-typecheck.ts +3 -3
  59. package/src/cli/analytics.ts +1 -0
  60. package/src/cli/check.ts +83 -12
  61. package/src/cli/commands/generation-model.ts +18 -0
  62. package/src/cli/commands/pipeline.ts +1 -1
  63. package/src/cli/commands/source.ts +14 -3
  64. package/src/cli/data.ts +5 -2
  65. package/src/cli/format-error.ts +3 -0
  66. package/src/cli/generation-models.ts +46 -0
  67. package/src/cli/program.ts +2 -0
  68. package/src/cli/project.ts +288 -138
  69. package/src/cli/trainings.ts +12 -0
  70. package/src/cli/ui.ts +3 -1
  71. package/src/client.ts +5 -0
  72. package/src/graph-rules.json +11 -0
  73. package/src/importer.ts +46 -40
  74. package/src/index.ts +4 -0
  75. package/src/transport.ts +23 -5
  76. package/src/validate.ts +183 -0
@@ -3,7 +3,7 @@
3
3
  {
4
4
  "id": "toloka-build",
5
5
  "name": "Build Toloka pipelines as code",
6
- "description": "Build, test, inspect, or change Toloka platform pipeline projects as TypeScript source with @toloka-platform/sdk, toloka check, and toloka apply. Use when the user has selected pipeline authoring or wants to inspect, plan, apply, test, check, or run a pipeline project as code.",
6
+ "description": "Build, test, inspect, or change Toloka platform pipeline projects as TypeScript source with @toloka-platform/sdk and the toloka CLI. Use for datasets and their uploads, pipeline nodes (code, generation, quorum, match), labeling Task UIs, stored Checks test cases, toloka check, validate, plan, and apply, run cost forecasts, and starting or monitoring pipeline runs.",
7
7
  "tags": [
8
8
  "pipelines",
9
9
  "authoring",
@@ -11,11 +11,15 @@
11
11
  "testing",
12
12
  "checks"
13
13
  ],
14
- "version": "0.11.2",
15
- "digest": "f97f94dd6eff745884e07d9f19cc414fdc2fe5d9b7992e062e7beb0058dcce59",
14
+ "version": "0.11.4",
15
+ "digest": "2a3f1b1cfa72c726b6255e3e93158c52d6a96108575327dd73479c2536c63167",
16
16
  "files": [
17
17
  "SKILL.md",
18
+ "references/human-work.md",
19
+ "references/local-setup.md",
20
+ "references/node-checks.md",
18
21
  "references/node-semantics.md",
22
+ "references/task-ui.md",
19
23
  "references/workflow-and-cli.md"
20
24
  ]
21
25
  },
@@ -29,7 +33,7 @@
29
33
  "bug",
30
34
  "report"
31
35
  ],
32
- "version": "0.11.2",
36
+ "version": "0.11.4",
33
37
  "digest": "70f0bd2c80b32f87896aeb27c363b8a2d37f40e22424f57fe1aad142e125ad67",
34
38
  "files": [
35
39
  "SKILL.md",
@@ -46,8 +50,8 @@
46
50
  "getting-started",
47
51
  "agent"
48
52
  ],
49
- "version": "0.11.2",
50
- "digest": "ccf148c682de4e452bb031db95d3933257899006b1766f0fdbc3d15265a63bb9",
53
+ "version": "0.11.4",
54
+ "digest": "2278adeb46a792356579395fcf73c42322cb23bcd0c61e20856ccabdad6762d1",
51
55
  "files": [
52
56
  "SKILL.md"
53
57
  ]
@@ -55,7 +59,7 @@
55
59
  {
56
60
  "id": "toloka-fine-tuning",
57
61
  "name": "Fine-tune a model with Toloka",
58
- "description": "Create, estimate, start, monitor, and verify a project-owned supervised fine-tuning Training through the Toloka CLI. Use when the user wants to adapt a base model or existing Model Version from labeled conversations.",
62
+ "description": "Create, estimate, start, monitor, and verify a project-owned supervised fine-tuning (SFT with LoRA adapters) Training through the Toloka CLI. Use when the user wants to adapt a base model or an existing LoRA Model Version from labeled conversations.",
59
63
  "tags": [
60
64
  "toloka",
61
65
  "training",
@@ -63,8 +67,8 @@
63
67
  "sft",
64
68
  "models"
65
69
  ],
66
- "version": "0.11.2",
67
- "digest": "279c69977eef170dada20b664ee0c30858681e84a2cabb2fdff18b8bb1bdc055",
70
+ "version": "0.11.4",
71
+ "digest": "b7ae3d76a6f1cba8d26a0dec30f540ef5a0298a9234580f418831c38cdc45bbb",
68
72
  "files": [
69
73
  "SKILL.md"
70
74
  ]
@@ -72,7 +76,7 @@
72
76
  {
73
77
  "id": "toloka-gisting",
74
78
  "name": "Compress a prompt with gisting",
75
- "description": "Create, estimate, start, monitor, and verify a project-owned prompt-gisting Training through the Toloka CLI. Use when the user wants a compact prompt representation from example conversations and a prompt file.",
79
+ "description": "Create, estimate, start, monitor, and verify a project-owned prompt-gisting Training through the Toloka CLI, which learns soft prompt tokens that stand in for a long static system prompt. Use when the user wants a compact or cheaper replacement for a fixed prompt, learned from example conversations and the prompt file.",
76
80
  "tags": [
77
81
  "toloka",
78
82
  "training",
@@ -80,8 +84,8 @@
80
84
  "prompt",
81
85
  "models"
82
86
  ],
83
- "version": "0.11.2",
84
- "digest": "b9f314eb6b39754bc8d2ae79aca3dc680fced5f14948c975d1e084a83c2e0a8c",
87
+ "version": "0.11.4",
88
+ "digest": "25388767c582e064f9ba366b04ed3a9883e7e5926301efb2b352f06cd2fa1bab",
85
89
  "files": [
86
90
  "SKILL.md"
87
91
  ]
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: toloka-build
3
- description: Build, test, inspect, or change Toloka platform pipeline projects as TypeScript source with @toloka-platform/sdk, toloka check, and toloka apply. Use when the user has selected pipeline authoring or wants to inspect, plan, apply, test, check, or run a pipeline project as code.
3
+ description: Build, test, inspect, or change Toloka platform pipeline projects as TypeScript source with @toloka-platform/sdk and the toloka CLI. Use for datasets and their uploads, pipeline nodes (code, generation, quorum, match), labeling Task UIs, stored Checks test cases, toloka check, validate, plan, and apply, run cost forecasts, and starting or monitoring pipeline runs.
4
4
  ---
5
5
 
6
6
  # Build Toloka pipelines as code
@@ -11,16 +11,22 @@ Help the user get a working pipeline that fits their task: understand the data a
11
11
 
12
12
  ## Enter the pipeline workflow
13
13
 
14
- For first-time setup or help choosing a workflow, install and read `toloka-get-started` and consult the matching public runbook. Use its onboarding steps where needed; an existing project or a focused inspection request does not need the full first-run journey. A demo is useful for learning, not a prerequisite for the user's own task.
15
-
16
14
  Use your expertise for routine choices, and briefly explain decisions that affect quality, cost, or maintainability. Ask a focused question when missing requirements or conflicting constraints would materially change the result; do not ask the user to choose SDK mechanics you can determine yourself. Preserve explicit requirements and existing project intent. Credentials belong in the user's `toloka login` prompt, paid runs need cost approval, and destructive or out-of-scope changes need agreement before proceeding.
17
15
 
16
+ ## Set up the machine and the checkout
17
+
18
+ Read [local setup](references/local-setup.md) when the CLI or SDK is missing, the checkout has no `toloka.json`, a command reports missing or rejected credentials, the user wants to choose, create, or register a project, or a trial limit blocks a project or pipeline. For first-time onboarding or help choosing a workflow, also install and read `toloka-get-started`; an existing project or a focused inspection request does not need the full first-run journey. These rules hold in every setup:
19
+
20
+ - If credentials are missing, run `toloka login --browser` yourself: it opens the sign-in page in the user's browser and waits, so ask the user to pick their provider and finish signing in there. Never request a key in chat.
21
+ - Never assume a project ID from conversation context. Resolve it from `--project-id`, `TOLOKA_PROJECT_ID`, `toloka.json`, or `toloka project current`.
22
+ - Never hand-edit `toloka.json`, and never delete one that holds live bindings without the user's approval.
23
+
18
24
  ## Choose a design that fits the task
19
25
 
20
26
  - Start with representative inputs and the output the user needs. Reuse an existing pipeline or node when it already serves that purpose; prefer the simplest graph that meets the requirements.
21
- - Use `code` for deterministic transformations, scripts, or programmatic API/LLM calls; `generation` for the platform's human or synthetic generation journey, including original content collection; `quorum` for independent annotations where agreement or disagreement matters; and `match` for conditional routing. `root` defines the input/output boundary.
27
+ - Choose node types by behavior, not by data format: `code` for computation without a human task, including programmatic LLM calls; `generation` for one human or synthetic annotation; `quorum` for several independent human annotations whose disagreement matters; `match` for conditional routing; `root` for the dataset boundary. [Node semantics](references/node-semantics.md) gives the full rules.
22
28
  - Choose data contracts, audience, instructions, and quality criteria together: the person doing the task should be able to produce the declared output and understand how it will be judged. Let the task and observed data guide these choices rather than copying an example's settings.
23
- - Treat quality, turnaround, and cost as tradeoffs. Explain meaningful assumptions, and seek clarification for unresolved acceptance criteria rather than inventing business rules. Read [node semantics](references/node-semantics.md) for each selected node's actual capabilities and constraints.
29
+ - Treat quality, turnaround, and cost as tradeoffs. Explain meaningful assumptions, and seek clarification for unresolved acceptance criteria rather than inventing business rules.
24
30
 
25
31
  ## Follow the reconciliation loop
26
32
 
@@ -34,96 +40,76 @@ For an applied change, the dependencies are read → edit → check/validate →
34
40
  toloka validate
35
41
  ```
36
42
  4. Run `toloka plan`. Read the complete diff and resolve every conflict or missing prerequisite.
37
- 5. Show the plan and run `toloka apply` when its changes match the requested work. Resolve removals, immutable-field conflicts, or changes outside that scope with the user first. Apply reruns the complete local gate and proceeds only when it passes.
38
- 6. Run `toloka plan` again and require `No changes.`
43
+ 5. Show the plan and run `toloka apply` when its changes match the requested work. Resolve removals, immutable-field conflicts, or changes outside that scope with the user first. Apply reruns the complete local gate and proceeds only when it passes. It takes no options and never asks for confirmation, so run it as plain `toloka apply`.
44
+ 6. Run `toloka plan` again and require `No changes.`, then run `toloka validate --wait` and act on the lint findings it reports.
39
45
 
40
46
  The CLI reads source, compares it with live state, and reconciles the platform. Edit files; never mutate a pipeline through raw HTTP, SDK client methods, or internal platform tool calls. Do not make a live edit and then reverse-engineer it into source.
41
47
 
42
48
  ## Orient before editing
43
49
 
44
- Use the directory containing `toloka.json` as the source root. Commands default to the current directory; use `--source-root <directory>` from elsewhere.
50
+ Use the directory containing `toloka.json` as the source root. Commands find it by walking up from the current directory to the nearest `toloka.json`; `init` binds the current directory only. Use `--source-root <directory>` to point elsewhere.
45
51
 
46
- - If `toloka.json` exists, read it as CLI-managed identity state and confirm its `projectId` matches `toloka project current` before any plan or apply. It maps the project, pipeline source directories, and dataset names to live IDs. Do not hand-edit it.
47
- - If it is absent and the user is adopting an existing project, run `toloka project add <alias> <projectId>`, then run `toloka import <projectId>` in the intended source root before `toloka init`. Import refuses an existing `pipelines/` directory unless you pass `--force`.
52
+ - Read `toloka.json` as CLI-managed identity state and confirm its `projectId` matches `toloka project current` before any plan or apply. It maps the project, pipeline source directories, and dataset names to live IDs.
48
53
  - After importing an existing project, run `toloka plan` before editing and require `No changes.`. Resolve importer or live-state drift separately so it cannot be mistaken for your change.
49
- - If it is absent and the user is authoring from scratch, create a project with a task-derived name when a new project is needed. For an intended existing empty project, use `toloka project add <alias> <projectId>` and `toloka --project-id <projectId> init`. Confirm `toloka project current` and the generated `toloka.json` name the intended project before authoring; do not create a duplicate merely because the checkout is unbound.
50
-
51
- If `toloka project current` reports `from toloka.json` for a project you did not select in this checkout, stop: project create/add/switch does not rebind an existing checkout. A newly generated state file with empty `pipelines` and `datasets` can be removed before selecting the intended project and rerunning `toloka init`; any state file with live bindings may be someone else's checkout and must not be deleted without user approval.
52
-
53
- Never assume a project ID from conversation context. Resolve it from `--project-id`, `TOLOKA_PROJECT_ID`, `toloka.json`, or `toloka project current`.
54
-
55
- An unverified trial account holds one project and one pipeline, and cannot deploy or run. `project create` then fails with `Your trial allows a single project.` and pipeline creation with `Your trial allows a single pipeline.` Adopt the project that already exists instead: register it with `toloka project add <alias> <projectId>`, bind the checkout with `toloka import <projectId>`, and author inside its existing pipeline; the platform has no project delete, so there is nothing to clear. Both limits lift when the user completes identity or business verification from the banner in the platform.
56
-
57
- `project create`, `project add`, and `project switch` also change the machine-level current-project registry used outside a source root. For temporary or evaluation projects, record the previous alias and restore it before finishing. Without `--team-id`, create uses the account's only writable team; when `toloka whoami` lists several teams, ask the user which one owns the project and pass it explicitly. Confirm the new project's team in `toloka project url`.
58
54
 
59
55
  ## Author with the typed graph API
60
56
 
61
57
  Import authoring helpers from `@toloka-platform/sdk`.
62
58
 
63
59
  - Declare every data contract once with `field(name, jsonSchema)`.
64
- - Decide entity cardinality from the task before choosing field schemas or Task UI components. One logical output from one labeler is a static entity, even when a component represents it with an array; only multiple independent outputs are dynamic. For dynamic entities, choose a tight task-grounded `maxEntities` instead of defaulting to 50.
65
60
  - Ground enum, length, range, format, label-precedence, tie-break, default, exact-phrase, and conditional-requiredness rules in the request, observed data, or documented platform requirements. Derive criteria, quiz answers, and UI validation from that evidence. Surface assumptions that affect accepted outputs before apply; if materially different interpretations remain, ask instead of silently deciding the user's business rules.
66
61
  - The supported node constructors are `root`, `code`, `generation`, `match`, and `quorum`.
67
- - Connect typed ports with `connect(from, to)`: `started`, `completed`, `input`, `output`, `matchNode.matched(0)`, and `default`.
68
- - Export a default `definePipeline({ dataset, fields, nodes, connections })` from every `pipelines/**/pipeline.ts`.
62
+ - Name every non-root node (the constructor's first argument, or `about.name` when set) with 4 to 32 characters: a lowercase letter first, then lowercase letters, digits, or underscores, ending with a letter or digit, unique within the pipeline. Any other name, such as `Moderate product`, is a `toloka check` warning, and `toloka apply` refuses to write the pipeline until it is fixed. `root({ started, completed })` takes no name.
63
+ - Decide each field's JSON schema, including enum, length, and format constraints, before the first `toloka dataset upload` or `toloka apply`: the dataset column is created with it and can never change afterwards.
64
+ - Connect typed ports with `connect(from, to)`: `started` and `completed` on root, `input` and `output` on code, generation, and quorum, and `input`, `matched(index)`, and `default` on match.
65
+ - Export a default `definePipeline({ dataset, fields, nodes, connections })` from every `pipelines/**/pipeline.ts`. `dataset` is optional: a pipeline without one, such as a pipeline created from a template in the UI, is imported and applied without it, but cannot run until a dataset is bound. Add `dataset` when the user wants one; never drop it from a pipeline that has one, because apply refuses to unbind it.
69
66
  - Keep the graph acyclic. Put review, retry, training, exam, appeal, and payment behavior in the owning human-work node rather than adding loop nodes.
70
67
 
71
- Let constructors mint IDs for new declarations. Preserve `id` options generated by `toloka import`, but never invent or hand-edit raw `fp_…`, `ds.…`, `pl.…`, or `pp.…` values in authored settings. Never add a `layout` block: layout is not authored, existing layout is preserved, and the server supplies defaults.
72
-
73
- Use `node_modules/@toloka-platform/sdk/examples/face-image-collection/` as a concrete authoring pattern when relevant; borrow its structure, not its task-specific choices.
68
+ Let constructors mint IDs for new declarations. Preserve `id` options generated by `toloka import`, but never invent or hand-edit raw `fp_…`, `ds.…`, `pl.…`, or `pp.…` values in authored settings. Never add a `layout` block: layout is not authored, existing nodes keep their canvas position, and the server places new nodes one column after their rightmost input and moves End to the right when they reach it.
74
69
 
75
- ## Get human-work settings right the first time
70
+ `node_modules/@toloka-platform/sdk/examples/README.md` lists complete example projects (a single-node classification task to start from, image annotation, side-by-side rating with quorum and adjudication, video recording and upload collection) and what each demonstrates. Read the one closest to the task as a concrete authoring pattern; borrow its structure, not its task-specific choices, and design each interface for its own task with [Task UI](references/task-ui.md).
76
71
 
77
- Distinguish server requirements from optional design choices. The following constraints and defaults are not all checked by `definePipeline`:
72
+ ## Read the references before writing a node
78
73
 
79
- - **Specializations require a verified audience.** Pair `audience.specializations` with `verifiedExperts: true`. Any project type may use the broad unverified crowd; the default is verified, so set `verifiedExperts: false` only when the task asks for it.
80
- - **Training is part of the node, not extra.** A quorum node requires `onboarding`, and while it is enabled the platform wants at least three steps and at least one quiz block. Preserve an explicit `enabled: false` that a user or `toloka import` put there; never switch Training on to satisfy your own sense of completeness.
81
- - **Optional settings should serve the task.** Exams, non-default QA, audience reuse, and smart search can be useful when the requirements call for them. Omit blocks that add no value rather than copying placeholders; an empty disabled block is still authored state. Preserve imported choices unless changing them is part of the task, and explain additions that affect cost or expert eligibility.
82
- - **Run scope belongs to the platform.** `itemFilter` and `itemLimit` on the root node are set from the platform, and apply preserves whatever is live unless source declares its own value. Do not add an item limit to source to "restore" one you saw in the UI.
83
- - **Entities use a closed vocabulary, and label entities need choices.** `entityType` must be one of the platform core types listed in [node semantics](references/node-semantics.md): `CONTEXT` for any non-media input the expert reads (text, numbers, objects), `IMAGE`/`VIDEO`/`AUDIO`/`DOCUMENT` for media inputs, `SINGLE_LABEL` or `MULTI_LABEL` for fixed choices, `SHORT_ANSWER` or `RESPONSE` for produced text, `EXPLANATION` only for reasoning about another value. Never invent `TEXT`, `LABEL`, or another name. Every `SINGLE_LABEL`/`MULTI_LABEL` output needs `allowedLabels` with at least two `{ label, value }` entries whose `value` is snake_case. The SDK checks these when it loads the source, so `toloka check` (and `toloka plan`, `toloka apply`, `toloka validate`) fails locally with `PipelineGraphValidationError` before any platform request; read the reference before writing a node instead of discovering them from a failed check.
74
+ - Read [node semantics](references/node-semantics.md) before writing or changing any node: it covers the graph, ports, `root`, `code`, and `match`.
75
+ - Read [human work](references/human-work.md) before writing or changing a `generation` or `quorum` node: entities, quality criteria, instruction, audience and pricing, QA, Training, Exam, synthetic generation, and the settings the SDK does not check when it loads the source.
76
+ - Read [Task UI](references/task-ui.md) before writing or changing a human node's `ui`: component discovery, how the platform evaluates `ui.code`, `preprocess` and `postprocess`, the validation rules apply enforces, screen design, and the screenshot check.
77
+ - Read [node checks](references/node-checks.md) before writing a node's stored test cases. Every new `code`, `generation`, and `quorum` node gets them; `root` and `match` have none.
84
78
 
85
79
  ## Know the validation boundary
86
80
 
87
81
  `definePipeline` and typed ports check local declaration and connection invariants. The published JSON contract is still available as `validate(graph)` for importer and fixture tests; it makes no server call.
88
82
 
89
- `toloka check` is the required local gate. It runs the project TypeScript compiler, typechecks every authored Task UI against declarations bundled with this SDK version, runs Vitest, and requires passing typed `test.code`, `test.ui`, and `test.pipeline` evidence for every checkable node and pipeline. Use `toloka check <pipeline> --node <name-or-id>` while iterating, then run the unfiltered command before plan or run. Status `missing` means required test evidence does not exist; `failed` means a check ran and failed; `partial` means hardware-backed behavior remains unverified; `infrastructure_error` means the checker could not run. All four block apply.
83
+ `toloka check` is the required local gate. It runs the project TypeScript compiler, typechecks every authored Task UI against declarations bundled with this SDK version, runs Vitest, and requires passing typed `test.code`, `test.ui`, and `test.pipeline` evidence for every checkable node and pipeline. Use `toloka check <pipeline> --node <name-or-id>` while iterating, where `<name-or-id>` is the node's name or ID, not the name of the TypeScript constant that holds it, then run the unfiltered command before plan or run. Status `missing` means required test evidence does not exist; `failed` means a check ran and failed; `infrastructure_error` means the checker could not run. All three block apply. `partial` means a Task UI has upload or recording fields the headless browser cannot exercise; it does not block apply, but tell the user to try the task on a real device before launching a run. `warning` on `platform-rules` lists nodes connected to the root that break a platform rule (names, quality elements, thresholds, review time, price, data collection media, exam limits): check still passes, but apply refuses to write that pipeline until they are fixed, so fix them before apply.
90
84
 
91
- `toloka validate` posts each bound graph to the platform. Treat source/spec errors as blocking and warnings as informational. A `not_ran_node_check` concerns a separate Remote Node Check and does not replace a passing Local Check Gate, but its remote-validation severity still matters: lint checks report it as a blocking error while other checks can report it as a warning. A pipeline not yet on the platform is skipped until `toloka apply` creates it. When a reviewed plan adds a dataset field already bound by an existing live pipeline, pre-apply validation can report that exact field as missing; apply only the reviewed additive plan, then require post-apply validation to clear source/spec errors. Never rewrite valid source for a missing Remote Node Check.
85
+ `toloka validate` posts each bound graph to the platform and prints one status per pipeline. It exits 1 when any pipeline is `invalid` or `checks-running`, otherwise 0.
92
86
 
93
- Before choosing Task UI components, list them from the launcher with `toloka ui components` (one line per component) and read the contract of the ones you intend to use with `toloka ui components <name> [name...]`; never guess component names or props from memory. If this SDK version has no `ui` command, the same data comes from the `ui` fixture of the `test` exported by `@toloka-platform/sdk/testing` (`ui` is a fixture argument, not an export): write a throwaway `probe.spec.ts` with `test("components", async ({ ui }) => { console.log(JSON.stringify(await ui.componentDocumentation(["View.Image"]), null, 2)); });`, run `bunx vitest run probe.spec.ts`, and delete the file before `toloka check`. A component's usable contract is the returned `propsType` plus its returned `valueType` and `example`; shared `Field` props such as `path`, `label`, `hint`, and `validation` can be confirmed from any current `Field.*` example, but do not invent any other prop. For structured or array-valued Fields, derive the dataset field schema from `valueType`, then feed the documented example value through `setValue`, `getValue`, and `submit` in the UI scenario so upstream contract drift fails locally. Never translate undocumented property names or replace missing values with defaults. Every identifier in `ui.code` must be a returned component or documented `actions` API, and JSX must have one root element. Register each required UI scenario with `test.ui(pipeline, node, name, callback)` and submit through its bound `render` helper. Run `toloka check <pipeline> --node <name-or-id>` after every Task UI edit; require passing UI types, empty browser validation errors, valid postprocessed entity output, and visual inspection where relevant. Never weaken authored validation merely to make a test pass.
87
+ | Status | Meaning |
88
+ | --- | --- |
89
+ | `valid` | No blocking error. Warnings are informational. |
90
+ | `checks-pending` | The only remaining issues are stored test cases or lints that have not run on this graph (`not_ran_node_check`). The user runs them from the node's Checks tab; they do not replace a passing local gate. |
91
+ | `invalid` | A source/spec error, a failed check (`failed_node_check`), or a lint error. Fix source/spec errors before plan or apply. Failed checks and lint errors do not block apply, so you can apply a fix for them and validate again, but a run cannot start until they are gone. |
92
+ | `checks-running` | Only with `--wait`: a lint was still running when the wait ended. |
93
+ | `skipped` | The pipeline or its dataset is not on the platform yet; `toloka apply` creates it. |
94
94
 
95
- `ui.code` accepts TSX, including TypeScript annotations. `preprocess` and `postprocess` are JavaScript function bodies; do not put TypeScript-only syntax in either transform.
95
+ The platform's lints, such as the Task UI interface lint and the quality-criteria lint, start by themselves a few seconds after every apply and take about a minute. Until they finish, plain `toloka validate` lists each as a `running_node_check` warning and can still print `valid` with exit 0, so it does not prove the lints passed. After applying a change, run `toloka validate --wait`: it validates again every 5 seconds, for up to 5 minutes, until no lint is running, and does not wait for a pipeline whose source has unapplied changes. Report the pipeline as valid only after that. When a reviewed plan adds a dataset field already bound by an existing live pipeline, pre-apply validation can report that exact field as missing; apply only the reviewed additive plan, then require post-apply validation to clear source/spec errors. Never rewrite valid source because a stored test case on the Checks tab has not run.
96
96
 
97
- Register code behavior with `test.code(pipeline, node, name, callback)` and execute the bound `run` helper. Add at least one `test.pipeline(pipeline, name, callback)` scenario. Choose representative fixtures from available data, redacting sensitive values while preserving field names, nesting, optionality, and media/value shapes. Use synthetic cases when needed for privacy or to exercise boundaries absent from the sample. Treat the fixture as `root.started` item state, execute connected nodes in order with the callback's bound code and UI helpers, merge only each node's declared outputs, and assert the final `root.completed` fields. Cover meaningful match branches, optional paths, and failures as well as the happy path.
97
+ Register every code-node behavior with `test.code(pipeline, node, name, callback)`; its callback receives a bound `run(inputs, options?)` helper with the node's Python execution contract, and the test counts only after `run` executes, an assertion runs, and the callback passes. Register required human-work behavior with `test.ui(pipeline, node, name, callback)`; its callback receives a bound `render(options?)`, and the test counts only after a successful `submit`, at least one assertion, and a passing callback. Add at least one `test.pipeline(pipeline, name, callback)` scenario: treat the fixture as `root.started` item state, execute connected nodes in order with the callback's bound `runCode` and `renderUi` helpers, merge only each node's declared outputs, and assert the final `root.completed` fields. Cover meaningful match branches, optional paths, and failures as well as the happy path.
98
+
99
+ Choose representative fixtures from available data, redacting sensitive values while preserving field names, nesting, optionality, and media/value shapes. Use synthetic cases when needed for privacy or to exercise boundaries absent from the sample. Plain Vitest tests still run and can fail `toloka check`, but only the typed wrappers satisfy required coverage. `preprocess` and `postprocess` remain runtime JavaScript function bodies, not TypeScript.
98
100
 
99
101
  ## Keep data and credentials out of source
100
102
 
101
- - Never put dataset items in pipeline source or `toloka.json`. After apply has created or resolved the dataset, upload `.json`, `.jsonl`, or `.csv` rows with `toloka dataset upload <dataset> <file>`. If a later upload fails as schema-incompatible, inspect `toloka dataset fields <dataset>` for stored names and base types, but preserve stricter authored constraints; the printed inference can omit enum, length, range, and format constraints.
103
+ - Never put dataset items in pipeline source or `toloka.json`. Upload rows with `toloka dataset upload <dataset> <file>` as [Add dataset rows](references/workflow-and-cli.md#add-dataset-rows) describes; it creates a missing dataset that a pipeline in source declares, so the upload can come before or after apply.
102
104
  - Put secret references in node settings, but never secret values. Set values through stdin with `toloka secret set <name>`, or use `toloka secret set <name> --from-env <variable>`.
103
105
 
104
- ## Credentials
105
-
106
- `toloka login` signs the user in through the browser, or stores an API key when they choose that, and
107
- keeps the login with owner-only permissions, so no later command needs `--api-key`. Precedence is flag,
108
- then environment variable (`TOLOKA_SCOPED_TOKEN`, then `TOLOKA_API_KEY`; `TOLOKA_BASE_URL`), then the
109
- stored API key, then the browser session. `TOLOKA_SCOPED_TOKEN` is a project-scoped token minted for the
110
- user by the platform (for example inside an agent sandbox); it never grants more than that user has. `toloka auth-status` reports what is in effect and where it came from; `toloka logout`
111
- ends the browser session and removes the stored files. If credentials are missing, run `toloka login --browser`
112
- yourself: it opens the sign-in page in the user's browser and waits, so ask the user to pick their
113
- provider and finish signing in there. Never request a key in chat.
114
- Anonymous command telemetry is on by default; set `TOLOKA_TELEMETRY=0` or `DO_NOT_TRACK=1` to disable it.
115
- Standalone and Bun-global CLI installations check for eligible public releases at most daily; turn that off with `toloka config set auto-update false`. See [workflow and CLI recipes](references/workflow-and-cli.md) for manual updates, installer overrides, and version-pin behavior.
116
-
117
106
  ## Recover from expected failures
118
107
 
119
- - **Dataset field schema conflict:** Stop trying to edit the field. Dataset fields are immutable after creation: they can be added, never altered or removed. Declare a new column name with the wanted schema, or bind the pipeline to a new dataset, then plan again.
120
- - **Missing secret:** Set every name listed by plan with `toloka secret set <name>`, keep the value out of files and shell arguments, then rerun plan and apply.
121
- - **409 stale version:** Another writer changed the graph after it was read. Do not retry blindly. Run `toloka plan` to re-read live state, review the new diff, preserve intentional remote changes in source when needed, then run `toloka apply` again.
122
- - **Server 400 after partial apply:** Dataset and field writes can land before pipeline import is rejected. Fix the source and run `toloka plan` again. Continue from the remaining diff; do not recreate resources that remain valid. If the rejection means a newly created field schema is wrong, that field is already immutable: apply the field-conflict rule by choosing a new column name or a new dataset, prefer the option that preserves names fixed by the request, and report the orphan instead of deleting it.
108
+ When plan, apply, or validate fails, follow [Recover safely](references/workflow-and-cli.md#recover-safely). It covers a dataset field schema conflict, an unreadable field schema, a missing secret, a 409 stale graph version, node drift after apply, a server 400 after a partial apply, and a lost platform connection. Never retry blindly, and never work around reconciliation with raw API calls.
123
109
 
124
- ## Run a deployed pipeline
110
+ ## Run an applied pipeline
125
111
 
126
- Before starting a run, require a passing `toloka check` and no blocking error from `toloka validate`. A warning-severity `not_ran_node_check` concerns a separate Remote Node Check and does not block the Local Check Gate; an error-severity instance remains a blocking remote-validation result. Run `toloka pipeline cost <name>` and present the forecast for user approval before starting the run. If it skips a billed node, report the authored rate and a labeled labor floor instead of presenting `$0.00` as the price; make the missing pricing evidence clear when seeking approval.
112
+ Before starting a run, require a passing `toloka check` and no blocking error from `toloka validate`. A `not_ran_node_check` or `running_node_check` warning does not block a run. Run `toloka pipeline cost <name>` and present the forecast for user approval before starting the run. If it skips a billed node, report the authored rate and a labeled labor floor instead of presenting `$0.00` as the price; make the missing pricing evidence clear when seeking approval.
127
113
 
128
114
  Start a run with `toloka pipeline run <name> --wait --timeout <ms>`, then read its exit code: `0` succeeded, `1` reached a failed terminal state, `2` still running when the window closed. Without `--wait`, exit `0` only means the run was accepted. Nothing reports back later, so never describe a started run as a finished one. Name the live pipeline; there is no implicit only-pipeline.
129
115
 
@@ -131,6 +117,6 @@ Keep monitoring bounded so the user receives a useful update even when expert wo
131
117
 
132
118
  ## Report with evidence
133
119
 
134
- Explain what changed, how it meets the task, what you verified, and what remains unresolved. Include relevant project/pipeline links, meaningful design assumptions, and observed run state and cost. Distinguish applied, validated, started, and completed; do not promise a later update unless a real reporting mechanism exists.
120
+ Explain what changed, how it meets the task, what you verified, and what remains unresolved. Call a pipeline that `toloka apply` saved to the platform applied, not deployed: the platform UI uses Deploy for starting a run. Include relevant project/pipeline links, meaningful design assumptions, and observed run state and cost. Distinguish applied, validated, started, and completed; do not promise a later update unless a real reporting mechanism exists.
135
121
 
136
122
  Keep enough command output and exit-status evidence to support claims about checks, mutations, and convergence, redacting secrets and sensitive data. For an audited task, retain the requested detailed records, including skill versions and project-registry changes. State when evidence is missing, and limit visual claims to surfaces you actually inspected. Use `toloka-report-issue` for product defects rather than presenting a workaround as normal workflow.
@@ -0,0 +1,156 @@
1
+ # Human work
2
+
3
+ Read this before writing or changing a `generation` or `quorum` node. Before writing its `ui`, also read [Task UI](task-ui.md); for its stored test cases, read [node checks](node-checks.md).
4
+
5
+ Distinguish server requirements from optional design choices; not every constraint below is checked when the source loads. Optional settings such as an Exam, non-default QA, audience reuse, and smart search should serve the task: add them when the requirements call for them, and omit blocks that add no value rather than copying placeholders, because an empty disabled block is still authored state. Preserve imported choices unless changing them is part of the task, and explain additions that affect cost or expert eligibility.
6
+
7
+ ## `generation`
8
+
9
+ Use `about.projectType: 'general'` when experts answer in the form: annotation, classification, judgment, ranking, rating, comparison, rewriting, and new written content such as answers, opinions, or survey responses.
10
+
11
+ Use `about.projectType: 'data_collection'` only when experts upload or record media or files. `toloka check` warns about a human `data_collection` node whose `ui.code` has no `Field.VideoUpload`, `Field.VideoRecord`, or `Field.FileUpload`.
12
+
13
+ ### Configure it
14
+
15
+ `generation(name, settings)` accepts the public `GenerationAuthoringSettings`, derived from `GenerationNodeSettings`:
16
+
17
+ - `about`: optional `name`, `description`, and `projectType`. The constructor uses its first argument as `about.name` when omitted.
18
+ - `publicName`: brand-neutral, human-readable title shown to experts.
19
+ - `entities.input` and `.output`: map declared fields into the labeler data model.
20
+ - `qualityCriteria`: semantic pass/fail rubrics targeting output `Field` objects.
21
+ - `instruction`: English labeler guidance reflecting the actual entities, UI, and criteria.
22
+ - `ui`: `{ code, data, preprocess, postprocess?, constants }` for the task interface.
23
+ - `qualityAssurance`: `llm_only`, `hybrid`, or `human_only`.
24
+ - `audienceAndPricing`: either a human audience or synthetic generation.
25
+ - `onboarding`: built-in Training stage.
26
+ - `exam`: optional built-in qualification gate.
27
+ - `reuseAudienceWithNodeId`, `smartSearch`, and `checks`: source-representable advanced settings; `checks` holds stored test cases (see [node checks](node-checks.md)).
28
+
29
+ #### Entities
30
+
31
+ An authored entity references a declared `field`. Choose its cardinality from the task's meaning before choosing the field schema or Task UI component:
32
+
33
+ - One logical result from one labeler is static. A caption, verdict, rating, recording, or upload remains one entity even when its value is an object or a component holds it in an array. Omit `dynamic` and `maxEntities`, and use a `jsonPath` without `[*]`.
34
+ - Multiple independent results from one labeler are dynamic. Examples include one box per visible face and one defect record per discovered defect. Set `dynamic: true`, use exactly one `[*]` in `jsonPath`, and set `maxEntities` to the tightest upper bound justified by the task. Never use 50 as an unexamined default.
35
+ - Do not choose `dynamic` from a TypeScript or JSON container shape. Ask whether the task expects one logical result or a repeated collection; the answer owns the entity model.
36
+ - Use `allowedLabels: [{ label, value }]` for fixed choices. Use `SINGLE_LABEL` for exactly one stored value and `MULTI_LABEL` for multiple values. Every `SINGLE_LABEL`/`MULTI_LABEL` output needs at least two entries, and each `value` must be snake_case. Answer each label entity in the UI with a choice field whose value matches it, never a boolean field (see [Task UI](task-ui.md)).
37
+ - Set media duration bounds only when the expert produces the media through an upload or recording output. Input media used for annotation does not require duration bounds.
38
+ - Give every output entity at least one relation to each input it needs, so the evaluator sees that input: `{ field, rel_type }`. Use `context` when the input says what the output is about (the question for an answer, the image for a caption), `references` when the output quotes or summarizes the input (a summary of a document), `evaluates` when the output judges or rates another entity (a verdict on a response, a score for an answer), and `depends_on` when the output is derived from another entity (an explanation of a label, a correction of a text). A conditional relation, `{ field, rel_type: 'conditional', condition: { operator, value } }`, applies only when the related value meets the condition: `EQ` and `NEQ` take a string, `IN` and `NOT_IN` an array of strings, and `NOT_EMPTY` checks that the value is present.
39
+
40
+ `entityType` is a closed platform vocabulary even where a generated TypeScript shape is currently broad. Use `CONTEXT` for any non-media input the expert reads, including text, numbers, and objects. Use `SHORT_ANSWER` for short produced text, `RESPONSE` for long produced text, and `EXPLANATION` only for reasoning about another value. Use `SINGLE_LABEL` or `MULTI_LABEL` for fixed choices, and `IMAGE`, `VIDEO`, `AUDIO`, or `DOCUMENT` for media. Never invent `TEXT` or another natural-language type name; consult the documented vocabulary when these categories do not fit. The full vocabulary, generated from the server schema into the SDK's `core-entity-types.json`, is `JUDGEMENT`, `EXPLANATION`, `PROMPT`, `USER_PROMPT`, `RESPONSE`, `RESPONSE_EVALUATION`, `RUBRIC`, `RUBRICS_GROUP`, `DIALOG`, `DIALOG_STEP`, `DIALOG_EVALUATION`, `SHORT_ANSWER`, `FEEDBACK`, `CONTEXT`, `IMAGE`, `ANNOTATION`, `SINGLE_LABEL`, `MULTI_LABEL`, `VIDEO`, `DOCUMENT`, `GOLDEN_SET`, `LOGS`, `SOLUTION`, `CODE`, `METADATA`, `AUDIO`, `AGENT_TRAJECTORY`, `MCP_SERVER`, `CONTAINER`, `CUSTOM`. The SDK validates `entityType` and the `allowedLabels` rules when it loads the source, so `toloka check` fails locally with `PipelineGraphValidationError` before anything is sent to the platform.
41
+
42
+ Entities enforce format, not meaning. Put types, ranges, cardinality, requiredness, and labels in the field schema and entity. Put accuracy, correctness, completeness, and clarity in quality criteria.
43
+
44
+ For a single-item upload or recording control, the component value is still an array, but the task produces one logical entity. Declare a scalar output field, keep the entity static, and use a non-wildcard path to the completed first value, such as `$.video_file[0].downloadLink`. Do not model the component's array container as `dynamic: true`. Use the matching media or document entity type. For video, also set both entity duration bounds and align them with the UI component.
45
+
46
+ #### Quality and instructions
47
+
48
+ Write at least one criterion for every output entity. Each criterion needs an authored UUID `id`, a `qualityElement` that no other criterion of the node uses (compared in snake_case), mutually exclusive and exhaustive `thresholds.pass` and `thresholds.fail` of at least 10 characters each, and `targetEntity: outputField`. Every criterion must resolve to pass or fail for every item; express edge cases as conditional clauses inside an always-applicable criterion. Criteria judge meaning, not an exact phrase you authored unless the request fixes that phrase. Before apply, walk every sample row through the instruction and all criteria: each criterion must yield one verdict, and no two authored rules may demand different values for the same row. Invert the task into an observable check: “tag every car” becomes “every visible car has exactly one tag.” Keep format validation out of criteria.
49
+
50
+ Use `llmQaInstruction` only when the evaluator needs a specific verification method, authoritative source, tool, or pinned edge case beyond the thresholds. It is evaluator guidance, not labeler guidance, and has no effect in `human_only` mode.
51
+
52
+ Default QA is `qualityAssurance: { qaMode: 'llm_only' }`. Keep it when it fits the task. `hybrid` adds sampled Human QA while retaining LLM review; `human_only` is appropriate when LLM grading is prohibited or human review alone is required. Recommend a mode based on the user's quality and privacy requirements, explaining cost and turnaround implications before changing it. Human-bearing modes require `humanQaTimeForTask` of at least 30 seconds and at least 3 seconds per quality criterion of the node, whichever is larger; `smartSamplingPercent` defaults to 30 for hybrid and 100 for human-only. Use those defaults unless the task justifies a different rate. Human QA on a node is capped at the node's expected review count from the frozen estimate, which uses the items the estimate expects at that node. Behind a `match`, the estimate assumes an even split across branches, so a branch that receives more items reaches the cap early and its later items skip Human QA; say so in the cost forecast when branch volumes are known to be uneven. QA mode applies to the whole node, not individual criteria. The redo cap is platform-controlled and is not an SDK setting.
53
+
54
+ The platform also writes annotator fields on human-expert generation nodes. `<snake_cased node name>_annotator_id` is an optional string: the ID of the expert whose answer was accepted, not of earlier rejected attempts. `<snake_cased node name>_qa_annotator_id` exists only in `human_only` and `hybrid` modes: the ID of the expert who made the last human review decision, missing when sampling skipped human review. Both are missing on canceled items and on items completed before they existed; synthetic nodes have neither. The platform also writes one `*_evaluation_result` field per quality criterion with LLM or Human QA verdicts, `<snake_cased node name>_qa_metadata`, and, on a synthetic node with LLM QA, `<snake_cased node name>_evaluation_summary`. Never declare any of these with `field()`: the platform owns them, and an authored field with that name collides with it. Read them from the dataset with `toloka dataset load`.
55
+
56
+ Keep `instruction` actionable and in English. Include the workflow, concepts, quality rules, and at least one pass and fail example grounded in the task. Do not mention project schedules, dataset volume, workforce requirements, or compensation in labeler instructions.
57
+
58
+ #### Audience and pricing
59
+
60
+ For humans, set `audienceType: 'human'`, `verifiedExperts`, all three audience filters, `pricePerTask`, and `timeForTask`. Set `verifiedExperts: true` unless the task explicitly asks for the broad unverified crowd. The public shapes differ by filter: languages use `{ type: 'and' | 'or', values: [{ value: 'English' }] }`; specializations use `{ type: 'and' | 'or', values: [{ value, qualificationId }] }`; countries use ISO 3166-1 alpha-2 codes, for example `{ type: 'or', values: ['US'] }`. Verify every country value matches `/^[A-Z]{2}$/`; apply currently accepts arbitrary strings that can match no experts. Derive languages and expertise from the task and its inputs, leaving specialization and country filters unrestricted unless needed. English is a reasonable starting language for an English-language task, not a universal audience default. Ask when an unresolved audience requirement changes who can do the work. Do not put specializations on an unverified audience. A specialization's `qualificationId` is platform identity: preserve an imported value, and discover new ones with `toloka audience specialization list`, copying `ID` into `qualificationId` and `NAME` into `value`; never invent one.
61
+
62
+ `$0.20` and 120 seconds are a starting point for a short task, not a universal rate. Estimate effort from the work and required expertise, respect explicit rates, and explain meaningful adjustments in the cost forecast. The per-expert cap is normally off. For collection tasks, choose a cap based on contributor diversity and repetition requirements; 1 fits one-response-per-expert collection. Avoid copying an arbitrary cap into a task that does not need one.
63
+
64
+ Use `audienceType: 'synthetic'` only when the user explicitly asks for model-generated output instead of human work; otherwise the audience is human. Explain the quality and cost tradeoff when you set it up. Set the required `maxCostPerAttempt`, the per-attempt ceiling in charged US dollars across fresh input, cached input, and output together, and configure the optional `generationModelId`, `reasoningEffort`, and `llmInstruction`; do not include human pricing or audience fields. Pick the model, its reasoning effort and the budget from `toloka generation-model list`: copy `ID` into `generationModelId` (it must also be in the `generationModelId` union of the installed SDK; a newer model needs an SDK update), set `reasoningEffort` only for a model that lists reasoning efforts (apply rejects it on any other model), and keep `maxCostPerAttempt` between `MIN` and `MAX`, at or above `TYPICAL`. Use a model suited to the task when there is evidence for that choice, or omit `generationModelId` to use the default model the command names; do not guess IDs or capabilities. Synthetic generation is incompatible with `data_collection`, human QA, audience reuse, expert sourcing, and Training.
65
+
66
+ #### Training, Exam, UI, and advanced settings
67
+
68
+ Treat `onboarding` as the node's Training course. It has `enabled`, `steps`, and `info` (`estimatedTime`, `role`, `goal`, `successCriteria`). Give every new human node a real course built from the instruction, criteria, UI, edge cases, and verified examples; the constructor's placeholder is not one. While it is enabled, validation requires non-empty `info.role`, `info.goal`, and `info.successCriteria`, three to six steps, and at least one quiz block; a course uses either a practice block or an examples block, not both, and an examples block needs a built UI. A practice block together with an enabled Exam draws a warning, because the Exam already tests experts on real tasks. Preserve an explicit `enabled: false`. Never invent golden answers or media URLs. Training teaches with retries; it is not an admission gate.
69
+
70
+ Treat `exam` as the optional one-attempt pass/fail gate after Training and before production. Configure it before finalizing Training. `tasksPerExpert` is 1–10; `passThreshold` is a count from 1 through `tasksPerExpert`. Each `gradedEntities` entry targets an output `Field` and sets `mode: 'ground_truth' | 'quality_criteria' | 'not_graded'`, `groundTruthType: 'direct' | 'custom'`, `customInstruction` (at least 10 characters for custom ground truth, otherwise `''`), and `disabledCriterionIds` (`[]` to keep every criterion). Exact labels favor direct ground truth; free-form work with criteria favors quality criteria; structured comparisons that need tolerance favor custom ground truth. `goldenDatasetId` is a live dataset ID and cannot be derived from a dataset name by the authoring helper; only preserve an imported ID or obtain a real one. Never fabricate one.
71
+
72
+ The `ui` strings are authored directly. Build one expert's task view, ensure component value shapes match entity schemas, read inputs as [Task UI](task-ui.md) describes, and use `postprocess` when a component's native value needs reshaping. Hardware-backed upload and recording controls require real UI verification.
73
+
74
+ Use `reuseAudienceWithNodeId` only with real imported `{ pipelineId, nodeId }` values from a compatible deployed task in another pipeline; never invent IDs. `smartSearch` can hold the public sourcing profile, but `sourceFingerprint` is server-derived. Preserve an imported fingerprint; do not invent one for new source.
75
+
76
+ ### Traps
77
+
78
+ - Do not represent QA, review, redo, Training, or Exam as graph nodes.
79
+ - Do not omit relations from outputs or confuse format validation with semantic quality.
80
+ - Do not add fields, explanations, comments, or labor the task does not require.
81
+ - Do not treat the constructor's generated placeholder Training or blank UI as production-ready configuration.
82
+ - Do not pair `audience.specializations` with `verifiedExperts: false`. Specializations are qualification-backed, and only verified experts hold them.
83
+ - Do not flip an explicitly requested `verifiedExperts: false` to `true`. Every project type accepts either audience mode.
84
+ - Do not set a synthetic `maxCostPerAttempt` below the `TYPICAL` cost `toloka generation-model list` shows for the selected model and reasoning effort: generation stops once the budget is spent and can truncate results. Tell the user when that raises the cost forecast.
85
+ - Do not omit `maxCostPerAttempt` from a synthetic `audienceAndPricing`. Without it the source fails to load with `must have required property 'maxCostPerAttempt'` next to misleading errors from the human branch, such as `must have required property 'verifiedExperts'`.
86
+ - Do not treat the server's materialized defaults as your configuration. An applied node reports `qualityAssurance`, `exam`, `reuseAudienceWithNodeId`, and `smartSearch` even when source never set them. Leave them out unless you mean to control them. Omitted top-level object keys are preserved, but defaults materialized inside list elements can still cause drift; use the generic import-and-diff recovery flow.
87
+
88
+ ## `quorum`
89
+
90
+ ### Configure it
91
+
92
+ `quorum(name, settings)` accepts `QuorumAuthoringSettings`, derived from `QuorumNodeSettings`:
93
+
94
+ - `about`, `publicName`, `entities`, `qualityCriteria`, `instruction`, `ui`, `audienceAndPricing`, `onboarding`, `exam`, `reuseAudienceWithNodeId`, `smartSearch`, and `checks` follow the human-node rules above.
95
+ - `overlap` is the fixed number of independent labelers per item: 1–100, though below 2 validation warns that one annotation per item calls for a `generation` node instead. Default to 3 when the user does not specify it; 3 gives a majority, 5 gives stronger consensus, and cost grows linearly.
96
+ - `qualityAssurance` is either `llm_only` or `none`.
97
+ - `offboardingRules` supports majority-vote agreement rules in No-QA mode.
98
+
99
+ Quorum is human-only in the current public shape; its `audienceAndPricing.audienceType` is `'human'`.
100
+
101
+ #### The quorum data shape
102
+
103
+ **Every quorum output `field()` must have a top-level array JSON schema.** The array is the collected-annotation dimension: one element per labeler, nominally `overlap` elements. Its `items` schema is one labeler's contribution.
104
+
105
+ Leave the outer array's length unbounded: it varies per item (fewer than `overlap` on a canceled item, up to `2 × overlap` under `llm_only` escalation). Validation rejects an outer `minItems` above 1 and an outer `maxItems` below `overlap` (below `2 × overlap` with `llm_only` QA). It also rejects `allOf`, `anyOf` or `oneOf` on the outer array; set length limits directly on it and put other constraints in `items`.
106
+
107
+ Configure entities for one labeler's contribution, not for the outer array. A single label per person therefore uses `dynamic: false` and `jsonPath: '$.label'`, while the declared output field is `{ type: 'array', items: { type: 'string' } }`. `dynamic: true` means an array inside each labeler's contribution and therefore produces an array of arrays. Build the UI to submit one value at `$.label`, never `$.label[0]`; the platform assembles the outer array.
108
+
109
+ When a quorum output entity is `optional: true`, its outer field's `items` schema must also accept `null`, for example `{ type: 'array', items: { type: ['string', 'null'] } }`. The platform reserves a null annotation slot when that labeler omits the value and rejects an optional entity backed by non-nullable items.
110
+
111
+ Quorum does not aggregate. It writes all raw annotations back, including rejected ones. Add a downstream `code` node when the requested deliverable needs one consensus value, and make it tolerate arrays longer than `overlap`.
112
+
113
+ The platform also writes an annotator field, `<snake_cased node name>_annotator_ids`, on every quorum node in both QA modes. It is an optional array of annotator ID strings, one per collected annotation, aligned by position with every output array and every `*_evaluation_result` array. Rejected annotations keep their positions, and the verdicts at the same position show the review outcome. One labeler can hold more than one position. The field is missing on items completed before it existed and on canceled items with no annotations; a canceled item with some annotations carries their IDs. Never declare it with `field()`: the platform owns it, and an authored field with that name collides with it. Read it from the dataset with `toloka dataset load`.
114
+
115
+ #### Explanation-driven quality
116
+
117
+ With `llm_only` QA, include a required output entity of type `EXPLANATION` and a corresponding top-level array string field unless the task makes that impossible. Put the strongest criterion on this explanation. Evaluate whether the reasoning is substantive and applies the task's definitions; do not rely primarily on judging the raw label. Different labels can be reasonable, while reasoning reveals annotation quality. Label outputs do not each require their own criterion on quorum.
118
+
119
+ With `qaMode: 'none'`, no LLM reads the explanation. Do not require an explanation by default unless the user asks for written reasoning or comments. Keep at least one quality criterion as labeler-facing Quality Panel guidance, even though no model evaluates it.
120
+
121
+ #### QA and escalation
122
+
123
+ Default to `qualityAssurance: { qaMode: 'llm_only' }`. The LLM accepts or rejects each annotation. If all initial annotations are rejected, the platform adds fresh annotations one at a time until one is accepted or the total reaches `2 × overlap`. Therefore result arrays may be longer than `overlap`.
124
+
125
+ **Quorum has no redo cycle.** A rejected annotation is never reopened or sent back to the same expert. Escalation adds a fresh annotation, and all collected annotations—accepted and rejected—remain in the output arrays. Hitting the cap with zero accepted annotations still returns the collected results.
126
+
127
+ Use `qaMode: 'none'` when agreement-based quality control fits the task better than LLM grading, explaining the tradeoff before changing an existing QA strategy. This mode requires:
128
+
129
+ - set `overlap` to at least 3;
130
+ - disable the per-expert cap;
131
+ - add at least one `{ id, type: 'mv_agreement', agreementScale }` offboarding rule;
132
+ - set `agreementScale` to the authored output field ID for a top-level `SINGLE_LABEL` entity.
133
+
134
+ The authoring helper does not translate `offboardingRules.agreementScale` from `Field` to ID. Use `agreementScale: labelField.id`; this is a derived field reference, not an invented raw ID. Do not combine No-QA mode with a per-expert cap.
135
+
136
+ ### Traps
137
+
138
+ - Do not model the quorum array twice. The field schema owns the outer annotation array; entity `dynamic` owns repetition inside one annotation.
139
+ - Do not promise exactly `overlap` results or exactly `overlap` accepted results.
140
+ - Do not add majority-vote or averaging logic inside the node.
141
+ - Do not call escalation dynamic overlap. Per-item or agreement-threshold-dependent overlap is unsupported.
142
+ - Do not configure human-only or hybrid QA; quorum supports only `llm_only` and `none`.
143
+ - Do not invent a redo path.
144
+
145
+ ## Public-surface gaps
146
+
147
+ When a requirement depends on one of these capabilities, state the gap instead of inventing source syntax:
148
+
149
+ - Audience discovery beyond specializations has no SDK or CLI path: valid-language/country suggestions, audience-size statistics for a composed filter, and recommended-rate calculation. Specializations and their expert counts come from `toloka audience specialization list`.
150
+ - Audience-reuse candidate discovery has no SDK or CLI path. Source can store a known cross-pipeline pointer, but cannot search candidates.
151
+ - Smart Search rendering, source-fingerprint computation, and stale-profile diagnosis have no SDK or CLI path. Source can carry the public profile; it cannot generate the server-owned fingerprint or preview rendered sourcing documents.
152
+ - Training's examples playbooks and automatic course authoring have no SDK/CLI path. Source can set `onboarding`, but cannot request geometry/numeric check templates or validate hands-on examples locally beyond the public graph schema.
153
+ - Exam golden-dataset discovery, creation by symbolic dataset name, dataset lint execution, and generated-golden confirmation flow have no high-level SDK authoring path. `exam.goldenDatasetId` requires a real ID.
154
+ - Generation's platform-controlled redo cap, appeal behavior, payment retry, and exact terminal handling are intentionally not configurable SDK settings.
155
+ - Dynamic quorum and per-item overlap are unsupported by both surfaces; this is a platform limitation, not missing TypeScript syntax.
156
+ - Server-owned outputs (`<node>_annotator_id`, `<node>_qa_annotator_id`, and `<node>_annotator_ids`, `*_evaluation_result`, `<node>_qa_metadata`, `<node>_evaluation_summary`) have no authoring path. Source cannot declare them or wire them into a downstream node; read them from the dataset instead.