ecoportal-api-graphql 1.3.13 → 1.3.16

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 (275) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +87 -0
  3. data/lib/ecoportal/api/common/graphql/client.rb +0 -2
  4. data/lib/ecoportal/api/common/graphql/http_client.rb +6 -0
  5. data/lib/ecoportal/api/graphql/base/ai_summary_version.rb +17 -17
  6. data/lib/ecoportal/api/graphql/base/file_container.rb +14 -14
  7. data/lib/ecoportal/api/graphql/base/location_classification_type.rb +15 -15
  8. data/lib/ecoportal/api/graphql/base/location_structure.rb +27 -27
  9. data/lib/ecoportal/api/graphql/base/organization.rb +15 -15
  10. data/lib/ecoportal/api/graphql/base/page/task.rb +24 -0
  11. data/lib/ecoportal/api/graphql/base/page.rb +17 -16
  12. data/lib/ecoportal/api/graphql/base/template.rb +35 -0
  13. data/lib/ecoportal/api/graphql/base.rb +37 -35
  14. data/lib/ecoportal/api/graphql/builder/contractor_entity.rb +41 -41
  15. data/lib/ecoportal/api/graphql/compat/response.rb +35 -35
  16. data/lib/ecoportal/api/graphql/connection/action.rb +11 -11
  17. data/lib/ecoportal/api/graphql/connection/action_category.rb +11 -11
  18. data/lib/ecoportal/api/graphql/connection/contractor_entity.rb +11 -11
  19. data/lib/ecoportal/api/graphql/connection/page.rb +11 -11
  20. data/lib/ecoportal/api/graphql/connection/person_member.rb +11 -11
  21. data/lib/ecoportal/api/graphql/connection/preview_page.rb +11 -11
  22. data/lib/ecoportal/api/graphql/connection.rb +17 -17
  23. data/lib/ecoportal/api/graphql/file_upload/client.rb +21 -10
  24. data/lib/ecoportal/api/graphql/fragment/field_configuration.rb +38 -0
  25. data/lib/ecoportal/api/graphql/fragment/force.rb +14 -10
  26. data/lib/ecoportal/api/graphql/fragment/location_node.rb +26 -26
  27. data/lib/ecoportal/api/graphql/fragment/page_task.rb +39 -0
  28. data/lib/ecoportal/api/graphql/fragment/template.rb +51 -0
  29. data/lib/ecoportal/api/graphql/fragment.rb +3 -0
  30. data/lib/ecoportal/api/graphql/input/contractor_entity.rb +14 -14
  31. data/lib/ecoportal/api/graphql/input/preset_view/update.rb +16 -16
  32. data/lib/ecoportal/api/graphql/input/workflow_command/add_stage.rb +18 -18
  33. data/lib/ecoportal/api/graphql/input/workflow_command/edit_field_configuration.rb +21 -21
  34. data/lib/ecoportal/api/graphql/input/workflow_command/edit_page.rb +28 -28
  35. data/lib/ecoportal/api/graphql/input/workflow_command/edit_page_creator_permissions.rb +18 -18
  36. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/cross_reference.rb +23 -23
  37. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/date.rb +20 -20
  38. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/image_gallery.rb +20 -20
  39. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/people.rb +24 -24
  40. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/plain_text.rb +20 -20
  41. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/rich_text.rb +20 -20
  42. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/select.rb +20 -20
  43. data/lib/ecoportal/api/graphql/input/workflow_command/move_field.rb +18 -18
  44. data/lib/ecoportal/api/graphql/input/workflow_command/reorder_forces.rb +18 -18
  45. data/lib/ecoportal/api/graphql/input/workflow_command/reorder_section.rb +18 -18
  46. data/lib/ecoportal/api/graphql/input/workflow_command.rb +251 -251
  47. data/lib/ecoportal/api/graphql/input.rb +24 -24
  48. data/lib/ecoportal/api/graphql/logic/connection.rb +34 -34
  49. data/lib/ecoportal/api/graphql/model/page/task.rb +16 -0
  50. data/lib/ecoportal/api/graphql/model/page.rb +16 -15
  51. data/lib/ecoportal/api/graphql/model/person_member.rb +15 -15
  52. data/lib/ecoportal/api/graphql/model/template.rb +15 -0
  53. data/lib/ecoportal/api/graphql/model.rb +32 -30
  54. data/lib/ecoportal/api/graphql/mutation/ai_summary/generate.rb +45 -45
  55. data/lib/ecoportal/api/graphql/mutation/ai_summary/submit_feedback.rb +40 -40
  56. data/lib/ecoportal/api/graphql/mutation/contractor_entity.rb +14 -14
  57. data/lib/ecoportal/api/graphql/mutation/page/approve_review_task.rb +40 -40
  58. data/lib/ecoportal/api/graphql/mutation/page/batch_update_review_task.rb +38 -40
  59. data/lib/ecoportal/api/graphql/mutation/page/create_draft.rb +38 -40
  60. data/lib/ecoportal/api/graphql/mutation/page/delete_draft.rb +38 -40
  61. data/lib/ecoportal/api/graphql/mutation/page/execute_force_commands.rb +7 -7
  62. data/lib/ecoportal/api/graphql/mutation/page/execute_workflow_commands.rb +8 -7
  63. data/lib/ecoportal/api/graphql/mutation/page/publish_draft.rb +38 -40
  64. data/lib/ecoportal/api/graphql/mutation/page/reject_review_task.rb +40 -40
  65. data/lib/ecoportal/api/graphql/mutation/page/restart_review_task.rb +40 -40
  66. data/lib/ecoportal/api/graphql/mutation/page/undo_review_task.rb +40 -40
  67. data/lib/ecoportal/api/graphql/mutation/preset_view/destroy.rb +34 -35
  68. data/lib/ecoportal/api/graphql/mutation/register/destroy.rb +35 -35
  69. data/lib/ecoportal/api/graphql/mutation/smart_fill/generate.rb +36 -36
  70. data/lib/ecoportal/api/graphql/mutation/smart_fill/submit_feedback.rb +40 -40
  71. data/lib/ecoportal/api/graphql/mutation/smart_fill.rb +13 -13
  72. data/lib/ecoportal/api/graphql/mutation/template/create_related_page.rb +46 -46
  73. data/lib/ecoportal/api/graphql/mutation/template/destroy_related_page.rb +1 -1
  74. data/lib/ecoportal/api/graphql/mutation/template/update_information.rb +1 -1
  75. data/lib/ecoportal/api/graphql/mutation.rb +20 -20
  76. data/lib/ecoportal/api/graphql/payload/contractor_entity.rb +14 -14
  77. data/lib/ecoportal/api/graphql/payload/ok_payload.rb +36 -21
  78. data/lib/ecoportal/api/graphql/payload/page/draft.rb +26 -13
  79. data/lib/ecoportal/api/graphql/payload/page/review_task.rb +13 -13
  80. data/lib/ecoportal/api/graphql/payload/page/review_task_batch.rb +23 -0
  81. data/lib/ecoportal/api/graphql/payload/page.rb +20 -19
  82. data/lib/ecoportal/api/graphql/payload/preset_view.rb +15 -11
  83. data/lib/ecoportal/api/graphql/payload/register.rb +15 -11
  84. data/lib/ecoportal/api/graphql/payload/template/create_related_page.rb +1 -1
  85. data/lib/ecoportal/api/graphql/payload/template/destroy_related_page.rb +1 -1
  86. data/lib/ecoportal/api/graphql/payload/template/update_information.rb +1 -1
  87. data/lib/ecoportal/api/graphql/payload.rb +23 -23
  88. data/lib/ecoportal/api/graphql/query/location_structures.rb +57 -57
  89. data/lib/ecoportal/api/graphql/query/page.rb +45 -45
  90. data/lib/ecoportal/api/graphql/query/page_with_forces.rb +9 -3
  91. data/lib/ecoportal/api/graphql/query/pages_workflow_commands.rb +9 -3
  92. data/lib/ecoportal/api/graphql/query/register_preset_views.rb +78 -78
  93. data/lib/ecoportal/api/graphql/query.rb +27 -27
  94. data/lib/ecoportal/api/graphql.rb +9 -5
  95. data/lib/ecoportal/api/graphql_version.rb +1 -1
  96. metadata +9 -180
  97. data/.ai-assistance/bridge/CLAUDE.md +0 -338
  98. data/.ai-assistance/bridge/archive/.gitkeep +0 -0
  99. data/.ai-assistance/bridge/archive/oscar-a1b2c3d-gitlab-mcp-doc-update.inbox.md +0 -29
  100. data/.ai-assistance/bridge/archive/oscar-a1b2c3d-gitlab-mcp-doc-update.outbox.md +0 -18
  101. data/.ai-assistance/bridge/archive/oscar-c912c25-gemini-design-review.inbox.md +0 -42
  102. data/.ai-assistance/bridge/archive/oscar-c912c25-gemini-design-review.outbox.md +0 -115
  103. data/.ai-assistance/bridge/context/gemini-review-prompt.txt +0 -48
  104. data/.ai-assistance/bridge/context/gemini-review-response.md +0 -104
  105. data/.ai-assistance/bridge/context/project.md +0 -42
  106. data/.ai-assistance/bridge/inbox/.gitkeep +0 -0
  107. data/.ai-assistance/bridge/outbox/.gitkeep +0 -0
  108. data/.ai-assistance/bridge/outbox/request-for-standards-discovery.md +0 -48
  109. data/.ai-assistance/bridge/queue/.gitkeep +0 -1
  110. data/.ai-assistance/capabilities/CLAUDE.md +0 -27
  111. data/.ai-assistance/capabilities/assumptions-log.md +0 -80
  112. data/.ai-assistance/capabilities/code.md +0 -47
  113. data/.ai-assistance/capabilities/connectors.md +0 -37
  114. data/.ai-assistance/capabilities/cowork.md +0 -55
  115. data/.ai-assistance/code/OVERVIEW.md +0 -155
  116. data/.ai-assistance/code/data_fields.md +0 -242
  117. data/.ai-assistance/code/dependencies.md +0 -151
  118. data/.ai-assistance/code/diff_as_input.md +0 -234
  119. data/.ai-assistance/code/diff_pairing_engine.md +0 -243
  120. data/.ai-assistance/code/diff_service_deep_dive.md +0 -192
  121. data/.ai-assistance/code/ecoPortal_architecture/00_overview_and_index.md +0 -55
  122. data/.ai-assistance/code/ecoPortal_architecture/01_terminology_dictionary.md +0 -181
  123. data/.ai-assistance/code/ecoPortal_architecture/02_data_model.md +0 -192
  124. data/.ai-assistance/code/ecoPortal_architecture/03_api_layers.md +0 -147
  125. data/.ai-assistance/code/ecoPortal_architecture/04_graphql_queries_mutations.md +0 -277
  126. data/.ai-assistance/code/ecoPortal_architecture/05_page_workflows.md +0 -200
  127. data/.ai-assistance/code/ecoPortal_architecture/06_search_and_filters.md +0 -228
  128. data/.ai-assistance/code/ecoPortal_architecture/07_data_fields.md +0 -197
  129. data/.ai-assistance/code/ecoPortal_architecture/08_stages_sections.md +0 -243
  130. data/.ai-assistance/code/ecoPortal_architecture/09_people_contractors_locations.md +0 -196
  131. data/.ai-assistance/code/ecoPortal_architecture/10_forces_workflow_builder.md +0 -132
  132. data/.ai-assistance/code/ecoPortal_architecture/11_integration_gems.md +0 -187
  133. data/.ai-assistance/code/ecoPortal_architecture/12_ai_documentation_sources_gaps.md +0 -236
  134. data/.ai-assistance/code/ecoPortal_architecture/13_ai_infrastructure.md +0 -183
  135. data/.ai-assistance/code/ecoportal_schema_reference.md +0 -240
  136. data/.ai-assistance/code/filter_contract_matrix.md +0 -177
  137. data/.ai-assistance/code/graphql_domain_knowledge.md +0 -240
  138. data/.ai-assistance/code/refactoring/datafield-readwrite-shape-asymmetry.md +0 -71
  139. data/.ai-assistance/code/refactoring/opportunities.md +0 -251
  140. data/.ai-assistance/code/schema_analysis.md +0 -321
  141. data/.ai-assistance/code/search_filters.md +0 -868
  142. data/.ai-assistance/code/spec_coverage.md +0 -73
  143. data/.ai-assistance/code/template_diff_pairing_domain.md +0 -175
  144. data/.ai-assistance/code/workflow-command-guide.md +0 -466
  145. data/.ai-assistance/code/workflow-space.md +0 -353
  146. data/.ai-assistance/conventions/CLAUDE.md +0 -30
  147. data/.ai-assistance/conventions/code-working-tree-protocol.md +0 -199
  148. data/.ai-assistance/conventions/gitignore-rules.md +0 -42
  149. data/.ai-assistance/conventions/permission-guidance.md +0 -120
  150. data/.ai-assistance/integrations/README.md +0 -70
  151. data/.ai-assistance/integrations/gitkraken-mcp.md +0 -107
  152. data/.ai-assistance/integrations/gitlab-mcp.md +0 -123
  153. data/.ai-assistance/integrations/local-git.md +0 -60
  154. data/.ai-assistance/local_paths.example.md +0 -17
  155. data/.ai-assistance/projects/TODO.md +0 -118
  156. data/.ai-assistance/projects/api-v2-to-graphql-migration/DECISIONS.md +0 -168
  157. data/.ai-assistance/projects/api-v2-to-graphql-migration/INTENT.md +0 -60
  158. data/.ai-assistance/projects/api-v2-to-graphql-migration/TODO.md +0 -267
  159. data/.ai-assistance/projects/api-v2-to-graphql-migration/UPSTREAM.md +0 -53
  160. data/.ai-assistance/projects/api-v2-to-graphql-migration/notes/csv-template-pipeline-design.md +0 -102
  161. data/.ai-assistance/projects/api-v2-to-graphql-migration/notes/cutover-usecase-gap-audit.md +0 -139
  162. data/.ai-assistance/projects/compat-layer-audit/COMPAT_AUDIT.md +0 -244
  163. data/.ai-assistance/projects/dynamic-model-generation/INTENT.md +0 -93
  164. data/.ai-assistance/projects/eco-helpers-compat/INTENT.md +0 -244
  165. data/.ai-assistance/projects/eco-helpers-compat/MIGRATION_GUIDE.md +0 -266
  166. data/.ai-assistance/projects/eco-helpers-compat/TODO.md +0 -86
  167. data/.ai-assistance/projects/ecoportal-api-v2-doublemodel-review/INTENT.md +0 -101
  168. data/.ai-assistance/projects/graphql-agent/GAP_ANALYSIS.md +0 -177
  169. data/.ai-assistance/projects/ooze-graphql-native-migration/DECISIONS.md +0 -161
  170. data/.ai-assistance/projects/ooze-graphql-native-migration/INTENT.md +0 -125
  171. data/.ai-assistance/projects/ooze-graphql-native-migration/INVENTORY.md +0 -136
  172. data/.ai-assistance/projects/ooze-graphql-native-migration/RISKS.md +0 -126
  173. data/.ai-assistance/projects/ooze-graphql-native-migration/TODO.md +0 -261
  174. data/.ai-assistance/projects/ooze-graphql-native-migration/analysis/2026-06-30-cutover-workflow-deep-review.md +0 -122
  175. data/.ai-assistance/projects/ooze-graphql-native-migration/analysis/2026-07-01-forces-via-workflow-commands-miss-rca.md +0 -148
  176. data/.ai-assistance/projects/page-model/DECISIONS.md +0 -245
  177. data/.ai-assistance/projects/page-model/TODO.md +0 -190
  178. data/.ai-assistance/projects/qa-services-delivery/DECISIONS.md +0 -93
  179. data/.ai-assistance/projects/qa-services-delivery/INTENT.md +0 -76
  180. data/.ai-assistance/projects/qa-services-delivery/PHASE3-SCOPE.md +0 -115
  181. data/.ai-assistance/projects/qa-services-delivery/ROADMAP.md +0 -99
  182. data/.ai-assistance/projects/qa-services-delivery/TODO.md +0 -81
  183. data/.ai-assistance/projects/search-filter-builder/INTENT.md +0 -107
  184. data/.ai-assistance/projects/search-filter-builder/TODO.md +0 -131
  185. data/.ai-assistance/projects/template-automatic-build-maintenance/INTENT.md +0 -87
  186. data/.ai-assistance/projects/template-automatic-build-maintenance/TODO.md +0 -108
  187. data/.ai-assistance/projects/template-diff-deploy/INTENT.md +0 -12
  188. data/.ai-assistance/projects/template-diff-deploy/TODO.md +0 -9
  189. data/.ai-assistance/projects/template-maintenance/DESIGN.md +0 -134
  190. data/.ai-assistance/projects/template-maintenance/PHASE0-FINDINGS.md +0 -93
  191. data/.ai-assistance/projects/template-maintenance/README.md +0 -14
  192. data/.ai-assistance/projects/template-model-logic/CATEGORY_CATALOG.md +0 -236
  193. data/.ai-assistance/projects/template-model-logic/CLASSIFICATION_SPIKE.md +0 -243
  194. data/.ai-assistance/projects/template-model-logic/DESIGN_NOTE.md +0 -154
  195. data/.ai-assistance/projects/workflow-space/TODO.md +0 -213
  196. data/.ai-assistance/reinstall-claude-desktop-windows.md +0 -136
  197. data/.ai-assistance/scripts/CLAUDE.md +0 -150
  198. data/.ai-assistance/scripts/bridge-inbox-check.sh +0 -75
  199. data/.ai-assistance/scripts/bridge-init.sh +0 -86
  200. data/.ai-assistance/scripts/bridge-status.sh +0 -44
  201. data/.ai-assistance/scripts/capabilities-check.ts +0 -104
  202. data/.ai-assistance/scripts/check-outbox.sh +0 -43
  203. data/.ai-assistance/scripts/dep_graph.rb +0 -91
  204. data/.ai-assistance/scripts/lock-acquire.sh +0 -103
  205. data/.ai-assistance/scripts/lock-multi.sh +0 -124
  206. data/.ai-assistance/scripts/lock-queue.sh +0 -94
  207. data/.ai-assistance/scripts/setup-mcps.test.ts +0 -188
  208. data/.ai-assistance/scripts/setup-mcps.ts +0 -234
  209. data/.ai-assistance/scripts/task-complete.ts +0 -74
  210. data/.ai-assistance/scripts/task-create.ts +0 -75
  211. data/.ai-assistance/scripts/task-read.ts +0 -125
  212. data/.ai-assistance/scripts/token-logger.js +0 -220
  213. data/.ai-assistance/scripts/token-report.ts +0 -158
  214. data/.ai-assistance/scripts/token-session-start.js +0 -66
  215. data/.ai-assistance/skills/ai-instructions/SKILL.md +0 -48
  216. data/.ai-assistance/skills/code-specs/SKILL.md +0 -69
  217. data/.ai-assistance/skills/corporate-policies/SKILL.md +0 -201
  218. data/.ai-assistance/skills/dep-graph/SKILL.md +0 -139
  219. data/.ai-assistance/skills/ep-ai-manager/SKILL.md +0 -417
  220. data/.ai-assistance/skills/gemini-assist/SKILL.md +0 -63
  221. data/.ai-assistance/skills/gemini-assist/gemini-mcp-server.js +0 -205
  222. data/.ai-assistance/skills/gemini-assist/gemini_ask.py +0 -1
  223. data/.ai-assistance/skills/gemini-assist/gemini_ask.rb +0 -240
  224. data/.ai-assistance/skills/gemini-assist/prompts/cycle_end_review.txt +0 -25
  225. data/.ai-assistance/skills/graphql-schema-analysis/SKILL.md +0 -261
  226. data/.ai-assistance/skills/procedural-memory/SKILL.md +0 -319
  227. data/.ai-assistance/skills/project-cycle/SKILL.md +0 -177
  228. data/.ai-assistance/skills/project-self-docs/SKILL.md +0 -181
  229. data/.ai-assistance/skills/project-self-docs/scripts/self_docs_scan.py +0 -378
  230. data/.ai-assistance/skills/refactor/SKILL.md +0 -62
  231. data/.ai-assistance/skills/rubocop/SKILL.md +0 -93
  232. data/.ai-assistance/skills/ruby-scripting/SKILL.md +0 -215
  233. data/.ai-assistance/skills/spec-generation/SKILL.md +0 -72
  234. data/.ai-assistance/standards-version.json +0 -22
  235. data/.ai-assistance/token-budget.json +0 -32
  236. data/.ai-assistance/version.json +0 -39
  237. data/.claude/settings.json +0 -150
  238. data/.env.example +0 -18
  239. data/.gitattributes +0 -15
  240. data/.gitignore +0 -37
  241. data/.gitlab-ci.yml +0 -45
  242. data/.markdownlint.json +0 -4
  243. data/.rspec +0 -3
  244. data/.rubocop.yml +0 -121
  245. data/.ruby-version +0 -1
  246. data/.yardopts +0 -10
  247. data/CLAUDE.md +0 -243
  248. data/Gemfile +0 -30
  249. data/Rakefile +0 -90
  250. data/bin/console +0 -14
  251. data/bin/setup +0 -8
  252. data/bin/setup.ps1 +0 -6
  253. data/docs/self-docs/ARCHITECTURE.md +0 -88
  254. data/docs/self-docs/CHANGES.jsonl +0 -12
  255. data/docs/self-docs/COMPLIANCE.md +0 -79
  256. data/docs/self-docs/CONVENTIONS.md +0 -74
  257. data/docs/self-docs/INTEGRATIONS.md +0 -65
  258. data/docs/self-docs/OPERATIONS.md +0 -76
  259. data/docs/self-docs/OVERVIEW.md +0 -64
  260. data/docs/self-docs/STATUS.md +0 -73
  261. data/docs/self-docs/self-docs-index.json +0 -51
  262. data/docs/worklog.md +0 -977
  263. data/ecoportal-api-graphql.gemspec +0 -40
  264. data/scripts/auto-worker-scheduler.sh +0 -386
  265. data/tests/actions_get.rb +0 -7
  266. data/tests/contractor_entities_get.rb +0 -20
  267. data/tests/contractor_entity_create.rb +0 -19
  268. data/tests/contractor_entity_udpate.rb +0 -20
  269. data/tests/dump_page_model.rb +0 -74
  270. data/tests/dump_template_model.rb +0 -90
  271. data/tests/loc_structure_get.rb +0 -10
  272. data/tests/loc_structure_update.rb +0 -51
  273. data/tests/loc_structures_get.rb +0 -15
  274. data/tests/local_libs.rb +0 -20
  275. data/tests/validate_queries.rb +0 -127
@@ -1,466 +0,0 @@
1
- # WorkflowCommand Porting Guide
2
-
3
- *For developers and Claude: porting old operations to the `executeWorkflowCommands` command bus.*
4
-
5
- ---
6
-
7
- ## Why This Exists
8
-
9
- Most template and page structural mutations go through `executeWorkflowCommands`.
10
- This is a single GraphQL mutation that accepts an ordered array of
11
- `WorkflowCommandInput` objects. There are no individual mutations for "add a stage",
12
- "rename a field", "add a select option", etc. — they all route through this one endpoint.
13
-
14
- Old scripts that manipulated template structure via the APIv2 REST layer or direct
15
- back-end access need to be ported to this command bus.
16
-
17
- ---
18
-
19
- ## The Command Bus Pattern
20
-
21
- One mutation. N commands per call. Commands execute in array order server-side.
22
-
23
- ```ruby
24
- # Build individual commands
25
- cmd1 = Input::WorkflowCommand.build(:editPage, name: 'Incident Report', icon: 'warning')
26
- cmd2 = Input::WorkflowCommand.build(:editStage, stageId: 's1_id', name: 'Initial Report')
27
- cmd3 = Input::WorkflowCommand.build(:editStage, stageId: 's2_id', name: 'Investigation')
28
-
29
- # Batch all three into one mutation call — more efficient than three separate calls
30
- payload = Mutation::Page::ExecuteWorkflowCommands.new(client).query(
31
- id: template_id,
32
- patch_ver: template.patchVer, # fetch before mutating
33
- commands: [cmd1, cmd2, cmd3]
34
- )
35
-
36
- raise "Commands failed: #{payload.body.inspect}" unless payload.success?
37
- puts "New patchVer: #{payload.patchVer}"
38
- ```
39
-
40
- ### patchVer requirement
41
-
42
- `ExecuteWorkflowCommandsInput` requires `patchVer: Int!` (non-null). Always fetch the
43
- current page or template before sending commands:
44
-
45
- ```ruby
46
- page = graphql.currentOrganization.page(id: page_id) do
47
- id; patchVer
48
- end
49
- # ... build commands ...
50
- payload = Mutation::Page::ExecuteWorkflowCommands.new(client).query(
51
- id: page_id, patch_ver: page.patchVer, commands: cmds
52
- )
53
- ```
54
-
55
- ### Error handling
56
-
57
- ```ruby
58
- payload = Mutation::Page::ExecuteWorkflowCommands.new(client).query(
59
- id: page_id, patch_ver: page.patchVer, commands: cmds
60
- )
61
-
62
- if payload.success?
63
- puts "Done. New patchVer: #{payload.patchVer}"
64
- else
65
- # payload.body → raw errors array from the server
66
- warn "Workflow command failed: #{payload.body.inspect}"
67
- end
68
- ```
69
-
70
- ---
71
-
72
- ## Complete Command Mapping Table
73
-
74
- Grouped by category. Every key listed here corresponds to one field in `WorkflowCommandInput`.
75
- All map to a Ruby sub-input module under `Input::WorkflowCommand::`.
76
-
77
- ### Page-level
78
-
79
- | Goal | Command key | Required fields | Optional fields |
80
- |------|-------------|-----------------|-----------------|
81
- | Edit page metadata / settings | `editPage` | _(none required)_ | `name`, `icon`, `themeId`, `timeZone`, `counterEnabled`, `counterPrefix`, `counterPostfix`, `counter`, `showCreator`, `disableComments`, `enableDashboardImport`, `enableActionsOnFields`, `mobileEnabled`, `useSectionsOnMobile`, `showStrategyForRestrictedStages`, `showAssigneeNamesForRestrictedStages`, `showTaskDueDateForRestrictedStages`, `hideActivityStream`, `disableDirectPermissions`, `active`, `addLocationIds`, `removeLocationIds`, `addBaseTags`, `removeBaseTags`, `addOtherTags`, `removeOtherTags`, `addFolders`, `removeFolders`, `creatorEnabled`, `creatorEditable`, `creatorFlags` |
82
- | Edit page creator permissions | `editPageCreatorPermissions` | _(see schema)_ | various permission flags |
83
-
84
- ### Stage structural
85
-
86
- | Goal | Command key | Required fields | Optional fields |
87
- |------|-------------|-----------------|-----------------|
88
- | Add a stage | `addStage` | `name`, `ordering` | `placeholderId` |
89
- | Remove a stage | `removeStage` | `stageId` | |
90
- | Rename / configure a stage | `editStage` | `stageId` | `name`, `description`, `lockAfterCompletion`, `disableDirectPermissions` |
91
- | Move a stage (reorder) | `moveStage` | `stageId`, `ordering` | |
92
-
93
- ### Stage permissions
94
-
95
- | Goal | Command key | Required fields | Optional fields |
96
- |------|-------------|-----------------|-----------------|
97
- | Edit creator permissions (stage) | `editCreatorPermissions` | _(see schema)_ | |
98
- | Toggle restrict comment tagging | `editRestrictCommentTagging` | _(see schema)_ | |
99
- | Add user group to comment tagging | `addCommentTaggingUserGroup` | `userGroupId` | |
100
- | Remove user group from comment tagging | `removeCommentTaggingUserGroup` | `userGroupId` | |
101
- | Toggle restrict task assignment | `editRestrictTaskAssignment` | _(see schema)_ | |
102
- | Add user group to task assignment | `addTaskAssignmentUserGroup` | `userGroupId` | |
103
- | Remove user group from task assignment | `removeTaskAssignmentUserGroup` | `userGroupId` | |
104
- | Add a tag to a stage | `addStageTag` | `stageId`, `tag` | |
105
- | Remove a tag from a stage | `removeStageTag` | `stageId`, `tag` | |
106
-
107
- ### Section
108
-
109
- | Goal | Command key | Required fields | Optional fields |
110
- |------|-------------|-----------------|-----------------|
111
- | Add a section (BasicPage / PhasedPage) | `addSection` | `layout` | `placeholderId` |
112
- | Remove a section (BasicPage) | `removeSection` | `sectionId` | |
113
- | Add a section to a stage | `addStageSection` | `stageId`, `layout` | `placeholderId` |
114
- | Remove a section from a stage | `removeStageSection` | `stageId`, `sectionId` | |
115
- | Edit section heading | `editSectionHeader` | `sectionId` | `header`, `leftHeader`, `rightHeader` |
116
- | Collapse section by default | `collapseSection` | `sectionId` | |
117
- | Expand section by default | `expandSection` | `sectionId` | |
118
- | Reorder sections | `reorderSection` | `sectionId`, `ordering` | |
119
-
120
- ### Task
121
-
122
- | Goal | Command key | Required fields | Optional fields |
123
- |------|-------------|-----------------|-----------------|
124
- | Add a task to a stage | `addTask` | `stageId`, `taskType` | `placeholderId` |
125
- | Remove a task from a stage | `removeTask` | `stageId`, `taskId` | |
126
- | Set task due date config | `editTaskDue` | `stageId`, `taskId` | `dueInValue`, `dueInUnit`, `dueExcludeWeekends` |
127
- | Remove task due date config | `removeTaskDue` | `stageId`, `taskId` | |
128
- | Remove task priority level | `removeTaskPriorityLevel` | `stageId`, `taskId` | |
129
- | Edit required sign-offs | `editRequiredSignOffs` | `stageId`, `taskId` | `required`, `minimum` |
130
- | Edit reminder | `editReminder` | `stageId`, `taskId` | `enabled`, `value`, `unit` |
131
-
132
- ### Strategy (default assignment)
133
-
134
- | Goal | Command key | Required fields | Optional fields |
135
- |------|-------------|-----------------|-----------------|
136
- | Add default assignment strategy | `addDefaultStrategy` | `stageId`, `taskId`, `strategy` | `placeholderId` |
137
- | Edit default strategy | `editDefaultStrategy` | `stageId`, `taskId`, `strategyId` | `strategy` |
138
- | Remove default strategy | `removeDefaultStrategy` | `stageId`, `taskId`, `strategyId` | |
139
- | Add user to direct default strategy | `addDefaultDirectStrategyUser` | `stageId`, `taskId`, `strategyId`, `userId` | |
140
- | Remove user from direct default strategy | `removeDefaultDirectStrategyUser` | `stageId`, `taskId`, `strategyId`, `userId` | |
141
-
142
- ### Strategy (task assignment)
143
-
144
- | Goal | Command key | Required fields | Optional fields |
145
- |------|-------------|-----------------|-----------------|
146
- | Add task assignment strategy | `addStrategy` | `stageId`, `taskId`, `strategy` | `placeholderId` |
147
- | Edit task strategy | `editStrategy` | `stageId`, `taskId`, `strategyId` | `strategy` |
148
- | Remove task strategy | `removeStrategy` | `stageId`, `taskId`, `strategyId` | |
149
- | Add user to direct strategy | `addDirectStrategyUser` | `stageId`, `taskId`, `strategyId`, `userId` | |
150
- | Remove user from direct strategy | `removeDirectStrategyUser` | `stageId`, `taskId`, `strategyId`, `userId` | |
151
-
152
- ### Strategy (operation)
153
-
154
- | Goal | Command key | Required fields | Optional fields |
155
- |------|-------------|-----------------|-----------------|
156
- | Add operation strategy | `addOperationStrategy` | `stageId`, `callbackId`, `operationId`, `strategy` | `taskId`, `placeholderId` |
157
- | Edit operation strategy | `editOperationStrategy` | `stageId`, `callbackId`, `operationId`, `strategyId` | `taskId`, `strategy` |
158
- | Remove operation strategy | `removeOperationStrategy` | `stageId`, `callbackId`, `operationId`, `strategyId` | `taskId` |
159
- | Add user to direct op strategy | `addOperationDirectStrategyUser` | `stageId`, `callbackId`, `operationId`, `strategyId`, `userId` | `taskId` |
160
- | Remove user from direct op strategy | `removeOperationDirectStrategyUser` | `stageId`, `callbackId`, `operationId`, `strategyId`, `userId` | `taskId` |
161
-
162
- ### Callback + Operation
163
-
164
- | Goal | Command key | Required fields | Optional fields |
165
- |------|-------------|-----------------|-----------------|
166
- | Add a workflow callback | `addWorkflowCallback` | `stageId`, `triggerCondition` | `placeholderId`, `taskId`, `triggers`, `operations` |
167
- | Remove a callback | `removeCallback` | `stageId`, `callbackId` | `taskId` |
168
- | Edit callback trigger | `editTrigger` | `stageId`, `callbackId`, `triggers` | `taskId` |
169
- | Add an operation to a callback | `addOperation` | `stageId`, `callbackId`, `operation` | `taskId`, `placeholderId` |
170
- | Edit an operation | `editOperation` | `stageId`, `callbackId`, `operationId`, `operation` | `taskId` |
171
- | Remove an operation | `removeOperation` | `stageId`, `callbackId`, `operationId` | `taskId` |
172
-
173
- ### Recipient (10 variants)
174
-
175
- | Goal | Command key | Required fields |
176
- |------|-------------|-----------------|
177
- | Add a specific user as recipient | `addRecipientUser` | `stageId`, `callbackId`, `operationId`, `userId` |
178
- | Remove a specific user | `removeRecipientUser` | `stageId`, `callbackId`, `operationId`, `userId` |
179
- | Add a people field as recipient source | `addRecipientPeopleField` | `stageId`, `callbackId`, `operationId`, `peopleFieldId` |
180
- | Remove a people field | `removeRecipientPeopleField` | `stageId`, `callbackId`, `operationId`, `peopleFieldId` |
181
- | Add a task config as recipient source | `addRecipientTaskConfig` | `stageId`, `callbackId`, `operationId`, `taskConfigId` |
182
- | Remove a task config | `removeRecipientTaskConfig` | `stageId`, `callbackId`, `operationId`, `taskConfigId` |
183
- | Add an action type as recipient source | `addRecipientActionType` | `stageId`, `callbackId`, `operationId`, `actionTypeId` |
184
- | Remove an action type | `removeRecipientActionType` | `stageId`, `callbackId`, `operationId`, `actionTypeId` |
185
- | Add a filter-based recipient | `addRecipientFilter` | `stageId`, `callbackId`, `operationId`, `filter` |
186
- | Remove a filter-based recipient | `removeRecipientFilter` | `stageId`, `callbackId`, `operationId`, `filter` |
187
-
188
- All 10 recipient commands also accept optional `taskId`.
189
-
190
- ### Scheduled callbacks
191
-
192
- | Goal | Command key | Required fields | Optional fields |
193
- |------|-------------|-----------------|-----------------|
194
- | Add a scheduled callback | `addScheduledCallback` | `stageId`, `taskId` | `placeholderId`, `dueInValue`, `dueInUnit`, `dueExcludeWeekends`, `recurs`, `recursInValue`, `recursInUnit`, `recursExcludeWeekends`, `actions` |
195
- | Edit a scheduled callback | `editScheduledCallback` | `stageId`, `taskId`, `scheduledCallbackId` | `dueInValue`, `dueInUnit`, `recurs`, etc. |
196
- | Remove a scheduled callback | `removeScheduledCallback` | `stageId`, `taskId`, `scheduledCallbackId` | |
197
- | Add action to scheduled callback | `addScheduledCallbackAction` | `stageId`, `taskId`, `scheduledCallbackId`, `action` | |
198
- | Add action tag | `addActionTag` | `stageId`, `taskId`, `scheduledCallbackId`, `tag` | |
199
- | Remove action tag | `removeActionTag` | `stageId`, `taskId`, `scheduledCallbackId`, `tag` | |
200
-
201
- ### Field structural
202
-
203
- | Goal | Command key | Required fields | Optional fields |
204
- |------|-------------|-----------------|-----------------|
205
- | Add a field to a stage section | `addField` | `fieldType`, `stageId`, `sectionId` | `placeholderId`, `label`, `column` |
206
- | Move a field to another section/position | `moveField` | `dataFieldId`, `sectionId` | `column`, `ordering` |
207
- | Remove a field | `removeField` | `dataFieldId` | |
208
-
209
- ### Field configuration (12 type variants)
210
-
211
- All field configuration changes go through a single command key with a nested `byType` dispatcher:
212
-
213
- ```ruby
214
- Input::WorkflowCommand.build(
215
- :editFieldConfiguration,
216
- data_field_id: 'FIELD_ID',
217
- label: 'New Label', # optional base-level
218
- tooltip: 'Help text', # optional base-level
219
- description: 'Longer desc', # optional base-level
220
- hide_view: false, # optional base-level (snake_case → camelCase)
221
- byType: {
222
- people: { # one of the 12 type keys below
223
- singular: true,
224
- personSchemaId: 'SCHEMA_ID'
225
- }
226
- }
227
- )
228
- ```
229
-
230
- Base-level fields (all optional): `label`, `tooltip`, `description`, `hideView`,
231
- `hiddenOnMobile`, `enableActions`, `globalBinding`.
232
-
233
- The `byType` hash accepts exactly one of these keys:
234
-
235
- | `byType` key | Schema input | Configures |
236
- |---|---|---|
237
- | `plainText` | `WorkflowEditFieldConfigurationPlainTextInput` | `value`, `maxLength`, `embeddingEnabled`, `smartFillConfiguration` |
238
- | `richText` | `WorkflowEditFieldConfigurationRichTextInput` | `content`, `markdown`, `embeddingEnabled`, `smartFillConfiguration` |
239
- | `date` | `WorkflowEditFieldConfigurationDateInput` | `showTime`, `pastOnly`, `todayButton`, `smartFillConfiguration` |
240
- | `gauge` | `WorkflowEditFieldConfigurationGaugeInput` | `max` |
241
- | `select` | `WorkflowEditFieldConfigurationSelectInput` | `dataType`, `multiple`, `flat`, `other`, `otherDesc`, `smartFillConfiguration` |
242
- | `people` | `WorkflowEditFieldConfigurationPeopleInput` | `personSchemaId`, `singular`, `requiresNumber`, `attachMode`, `isMeButton`, `autoSelectMode`, `addViewableFields`, `removeViewableFields` |
243
- | `crossReference` | `WorkflowEditFieldConfigurationCrossReferenceInput` | `registerId`, `singleSelectMode`, `displayFields`, `hideCreate`, `hideAttach`, `hideDashboards` |
244
- | `imageGallery` | `WorkflowEditFieldConfigurationImageGalleryInput` | `layout`, `stretch`, `noPopup`, `hideOptions` |
245
- | `locationField` | `WorkflowEditFieldConfigurationLocationFieldInput` | `buttonText`, `minimumRequired`, `singleSelect`, `autoselectDefaultLocation`, `restrictByClassification`, `addAllowedClassifications`, `removeAllowedClassifications`, `addAllowedStructures`, `removeAllowedStructures` |
246
- | `contractorEntities` | `WorkflowEditFieldConfigurationContractorEntitiesInput` | `singular`, `requiresNumber`, `isMeButton`, `showApprovalStatus`, `grantPermissionsEnabled`, `adminAccess`, `regularAccess` |
247
- | `signature` | `WorkflowEditFieldConfigurationSignatureInput` | `color` |
248
- | `table` | `WorkflowEditFieldConfigurationTableInput` | `tableType`, `jurisdictionFieldRef`, various date/award fields |
249
-
250
- ### Select options
251
-
252
- | Goal | Command key | Required fields | Optional fields |
253
- |------|-------------|-----------------|-----------------|
254
- | Add a select option | `addSelectFieldOption` | `dataFieldId`, `label` | `placeholderId`, `weight` |
255
- | Edit a select option | `editSelectFieldOption` | `dataFieldId`, `optionId` | `label`, `weight` |
256
- | Remove a select option | `removeSelectFieldOption` | `dataFieldId`, `optionId` | |
257
-
258
- ### Gauge stops
259
-
260
- | Goal | Command key | Required fields | Optional fields |
261
- |------|-------------|-----------------|-----------------|
262
- | Add a gauge stop | `addGaugeFieldStop` | `dataFieldId`, `threshold`, `color` | `placeholderId` |
263
- | Edit a gauge stop | `editGaugeFieldStop` | `dataFieldId`, `stopId` | `threshold`, `color` |
264
- | Remove a gauge stop | `removeGaugeFieldStop` | `dataFieldId`, `stopId` | |
265
-
266
- ### Linked fields
267
-
268
- | Goal | Command key | Required fields | Optional fields |
269
- |------|-------------|-----------------|-----------------|
270
- | Add a linked field config | `addLinkedFieldConfig` | `dataFieldId`, `sourceFieldKey`, `crossReferenceId` | `attachedMode` |
271
- | Edit a linked field config | `editLinkedFieldConfig` | `dataFieldId`, `linkedFieldConfigId` | `sourceFieldKey` |
272
- | Remove a linked field config | `removeLinkedFieldConfig` | `dataFieldId`, `linkedFieldConfigId` | |
273
-
274
- ### Forces and bindings (advanced)
275
-
276
- | Goal | Command key | Required fields | Optional fields |
277
- |------|-------------|-----------------|-----------------|
278
- | Add a force | `addForce` | `name`, `script` | `placeholderId` |
279
- | Remove a force | `removeForce` | `forceId` | |
280
- | Edit a force | `editForce` | `forceId` | `name`, `script` |
281
- | Reorder forces | `reorderForces` | `forceIds` | |
282
- | Add a binding | `addBinding` | `forceId`, `fieldId`, `name` | `placeholderId` |
283
- | Edit a binding | `editBinding` | `forceId`, `bindingId` | `fieldId`, `name` |
284
- | Remove a binding | `removeBinding` | `forceId`, `bindingId` | |
285
- | Add linked helper | `addLinkedHelper` | _(see schema)_ | |
286
- | Edit linked helper | `editLinkedHelper` | _(see schema)_ | |
287
- | Remove linked helper | `removeLinkedHelper` | _(see schema)_ | |
288
-
289
- ---
290
-
291
- ## Usage Examples
292
-
293
- ### 1. Rename a stage
294
-
295
- ```ruby
296
- page = graphql.currentOrganization.page(id: page_id) { id; patchVer }
297
-
298
- payload = Mutation::Page::ExecuteWorkflowCommands.new(client).query(
299
- id: page_id,
300
- patch_ver: page.patchVer,
301
- commands: [
302
- Input::WorkflowCommand.build(:editStage, stageId: stage_id, name: 'Investigation Phase')
303
- ]
304
- )
305
- raise payload.body.inspect unless payload.success?
306
- ```
307
-
308
- ### 2. Add a workflow callback (send notification on stage submit)
309
-
310
- ```ruby
311
- page = graphql.currentOrganization.page(id: page_id) { id; patchVer }
312
-
313
- payload = Mutation::Page::ExecuteWorkflowCommands.new(client).query(
314
- id: page_id,
315
- patch_ver: page.patchVer,
316
- commands: [
317
- Input::WorkflowCommand.build(
318
- :addWorkflowCallback,
319
- stageId: stage_id,
320
- triggerCondition: 'on_stage_complete'
321
- )
322
- ]
323
- )
324
- raise payload.body.inspect unless payload.success?
325
- ```
326
-
327
- ### 3. Edit page icon and counter format
328
-
329
- ```ruby
330
- page = graphql.currentOrganization.page(id: page_id) { id; patchVer }
331
-
332
- payload = Mutation::Page::ExecuteWorkflowCommands.new(client).query(
333
- id: page_id,
334
- patch_ver: page.patchVer,
335
- commands: [
336
- Input::WorkflowCommand.build(
337
- :editPage,
338
- icon: 'clipboard',
339
- counterEnabled: true,
340
- counterPrefix: 'INC-',
341
- counterPostfix: ''
342
- )
343
- ]
344
- )
345
- raise payload.body.inspect unless payload.success?
346
- ```
347
-
348
- ### 4. Edit a field label and tooltip
349
-
350
- ```ruby
351
- page = graphql.currentOrganization.page(id: page_id) { id; patchVer }
352
-
353
- payload = Mutation::Page::ExecuteWorkflowCommands.new(client).query(
354
- id: page_id,
355
- patch_ver: page.patchVer,
356
- commands: [
357
- Input::WorkflowCommand.build(
358
- :editFieldConfiguration,
359
- data_field_id: field_id,
360
- label: 'Incident Description',
361
- tooltip: 'Describe what happened, where, and who was involved'
362
- )
363
- ]
364
- )
365
- raise payload.body.inspect unless payload.success?
366
- ```
367
-
368
- ### 5. Add a select field option
369
-
370
- ```ruby
371
- page = graphql.currentOrganization.page(id: page_id) { id; patchVer }
372
-
373
- payload = Mutation::Page::ExecuteWorkflowCommands.new(client).query(
374
- id: page_id,
375
- patch_ver: page.patchVer,
376
- commands: [
377
- Input::WorkflowCommand.build(
378
- :addSelectFieldOption,
379
- dataFieldId: field_id,
380
- label: 'Under Review',
381
- weight: 50
382
- )
383
- ]
384
- )
385
- raise payload.body.inspect unless payload.success?
386
- ```
387
-
388
- ### 6. Configure a people field (singular, person schema)
389
-
390
- ```ruby
391
- page = graphql.currentOrganization.page(id: page_id) { id; patchVer }
392
-
393
- payload = Mutation::Page::ExecuteWorkflowCommands.new(client).query(
394
- id: page_id,
395
- patch_ver: page.patchVer,
396
- commands: [
397
- Input::WorkflowCommand.build(
398
- :editFieldConfiguration,
399
- data_field_id: field_id,
400
- byType: {
401
- people: {
402
- singular: true,
403
- personSchemaId: person_schema_id,
404
- attachMode: 'ATTACH_ONLY'
405
- }
406
- }
407
- )
408
- ]
409
- )
410
- raise payload.body.inspect unless payload.success?
411
- ```
412
-
413
- ### Batching multiple commands (efficiency)
414
-
415
- Commands are ordered — the server executes them in sequence. Batch unrelated or
416
- sequential changes into a single mutation call to reduce round-trips and avoid
417
- intermediate patchVer staleness:
418
-
419
- ```ruby
420
- page = graphql.currentOrganization.page(id: page_id) { id; patchVer }
421
-
422
- cmds = [
423
- Input::WorkflowCommand.build(:editPage, name: 'Safety Incident Report', icon: 'warning'),
424
- Input::WorkflowCommand.build(:editStage, stageId: s1, name: 'Initial Report'),
425
- Input::WorkflowCommand.build(:editStage, stageId: s2, name: 'Investigation'),
426
- Input::WorkflowCommand.build(:editStage, stageId: s3, name: 'Close-out'),
427
- Input::WorkflowCommand.build(:addSelectFieldOption, dataFieldId: severity_field, label: 'Critical', weight: 1),
428
- Input::WorkflowCommand.build(:addSelectFieldOption, dataFieldId: severity_field, label: 'High', weight: 2),
429
- ]
430
-
431
- payload = Mutation::Page::ExecuteWorkflowCommands.new(client).query(
432
- id: page_id,
433
- patch_ver: page.patchVer,
434
- commands: cmds
435
- )
436
- raise "Commands failed: #{payload.body.inspect}" unless payload.success?
437
- puts "Applied #{cmds.size} commands. New patchVer: #{payload.patchVer}"
438
- ```
439
-
440
- ---
441
-
442
- ## Schema realities — input-key gotchas (verified 2026-07-04 against the live introspection dump)
443
-
444
- These are the ways the command bus does **not** behave the way you'd expect. Verifying against the
445
- schema dump (`.ai-assistance/tmp/*_live_ep_graphql_schema.graphql.json`) before assuming a key exists
446
- saves a live round trip.
447
-
448
- - **`addField` (`WorkflowAddFieldInput`) keys = EXACTLY** `placeholderId, fieldType, label, stageId`
449
- (NON_NULL), `sectionId` (NON_NULL), `column`. It does **not** accept `description` or `required`.
450
- - **A field's `description` is set via `editFieldConfiguration`** (`WorkflowEditFieldConfigurationInput`
451
- has a top-level `description: String`), NOT via `addField`. To build a field *with* a description
452
- (e.g. a CSV / hidden-field **identity token**), emit `addField` then a follow-up
453
- `editFieldConfiguration(dataFieldId: <field>, description:)`. This is the seam `Diff::CommandSynthesizer`
454
- and `Builder::TemplateBuilder` use (via `placeholderId`/`ref` when the field is created in the same batch).
455
- - **`required` cannot be set through the command bus at all.** There is **no `required` input key
456
- anywhere** — not on `WorkflowAddFieldInput`, not on `WorkflowEditFieldConfigurationInput` (top-level),
457
- not on any of its **12 `byType` sub-inputs**. Treat field-`required` as **read-only / out-of-band**:
458
- read it from the template, don't try to mutate it. (ecoportal-qa `:skip`s `required`-readiness for
459
- this reason; `VersionDiff`'s `BYTYPE_CONFIG` omits it.)
460
- - **Structural back-refs:** an added field's `addField` carries its parent `sectionId` + `stageId`;
461
- an added **section** has no stage-id key, so wire it with a follow-up
462
- `addStageSection(stageId:, sectionId:)`. `Diff::CommandSynthesizer` threads all of these via
463
- `placeholderId`/`ref()` (parent placeholder when same-batch, else real id; omitted when unknown).
464
-
465
- **Rule of thumb:** before adding a key to a `WorkflowCommand` builder, confirm it exists on that input
466
- type in the schema dump. Absent keys are silently dropped (or rejected) — they do not error informatively.