ecoportal-api-graphql 1.3.5 → 1.3.9

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 (499) hide show
  1. checksums.yaml +4 -4
  2. data/.ai-assistance/bridge/CLAUDE.md +338 -0
  3. data/.ai-assistance/bridge/archive/.gitkeep +0 -0
  4. data/.ai-assistance/bridge/archive/oscar-a1b2c3d-gitlab-mcp-doc-update.inbox.md +29 -0
  5. data/.ai-assistance/bridge/archive/oscar-a1b2c3d-gitlab-mcp-doc-update.outbox.md +18 -0
  6. data/.ai-assistance/bridge/archive/oscar-c912c25-gemini-design-review.inbox.md +42 -0
  7. data/.ai-assistance/bridge/archive/oscar-c912c25-gemini-design-review.outbox.md +115 -0
  8. data/.ai-assistance/bridge/context/gemini-review-prompt.txt +48 -0
  9. data/.ai-assistance/bridge/context/gemini-review-response.md +104 -0
  10. data/.ai-assistance/bridge/context/project.md +42 -0
  11. data/.ai-assistance/bridge/inbox/.gitkeep +0 -0
  12. data/.ai-assistance/bridge/outbox/.gitkeep +0 -0
  13. data/.ai-assistance/bridge/outbox/request-for-standards-discovery.md +48 -0
  14. data/.ai-assistance/bridge/queue/.gitkeep +1 -0
  15. data/.ai-assistance/capabilities/CLAUDE.md +27 -0
  16. data/.ai-assistance/capabilities/assumptions-log.md +80 -0
  17. data/.ai-assistance/capabilities/code.md +47 -0
  18. data/.ai-assistance/capabilities/connectors.md +37 -0
  19. data/.ai-assistance/capabilities/cowork.md +55 -0
  20. data/.ai-assistance/code/OVERVIEW.md +155 -0
  21. data/.ai-assistance/code/data_fields.md +242 -0
  22. data/.ai-assistance/code/dependencies.md +151 -0
  23. data/.ai-assistance/code/diff_as_input.md +234 -0
  24. data/.ai-assistance/code/diff_service_deep_dive.md +192 -0
  25. data/.ai-assistance/code/ecoPortal_architecture/00_overview_and_index.md +55 -0
  26. data/.ai-assistance/code/ecoPortal_architecture/01_terminology_dictionary.md +181 -0
  27. data/.ai-assistance/code/ecoPortal_architecture/02_data_model.md +192 -0
  28. data/.ai-assistance/code/ecoPortal_architecture/03_api_layers.md +147 -0
  29. data/.ai-assistance/code/ecoPortal_architecture/04_graphql_queries_mutations.md +277 -0
  30. data/.ai-assistance/code/ecoPortal_architecture/05_page_workflows.md +200 -0
  31. data/.ai-assistance/code/ecoPortal_architecture/06_search_and_filters.md +228 -0
  32. data/.ai-assistance/code/ecoPortal_architecture/07_data_fields.md +197 -0
  33. data/.ai-assistance/code/ecoPortal_architecture/08_stages_sections.md +243 -0
  34. data/.ai-assistance/code/ecoPortal_architecture/09_people_contractors_locations.md +196 -0
  35. data/.ai-assistance/code/ecoPortal_architecture/10_forces_workflow_builder.md +132 -0
  36. data/.ai-assistance/code/ecoPortal_architecture/11_integration_gems.md +187 -0
  37. data/.ai-assistance/code/ecoPortal_architecture/12_ai_documentation_sources_gaps.md +236 -0
  38. data/.ai-assistance/code/ecoPortal_architecture/13_ai_infrastructure.md +183 -0
  39. data/.ai-assistance/code/ecoportal_schema_reference.md +240 -0
  40. data/.ai-assistance/code/graphql_domain_knowledge.md +230 -0
  41. data/.ai-assistance/code/refactoring/datafield-readwrite-shape-asymmetry.md +71 -0
  42. data/.ai-assistance/code/refactoring/opportunities.md +251 -0
  43. data/.ai-assistance/code/schema_analysis.md +321 -0
  44. data/.ai-assistance/code/search_filters.md +868 -0
  45. data/.ai-assistance/code/spec_coverage.md +73 -0
  46. data/.ai-assistance/code/workflow-command-guide.md +438 -0
  47. data/.ai-assistance/code/workflow-space.md +353 -0
  48. data/.ai-assistance/conventions/CLAUDE.md +30 -0
  49. data/.ai-assistance/conventions/code-working-tree-protocol.md +199 -0
  50. data/.ai-assistance/conventions/gitignore-rules.md +42 -0
  51. data/.ai-assistance/conventions/permission-guidance.md +120 -0
  52. data/.ai-assistance/integrations/README.md +70 -0
  53. data/.ai-assistance/integrations/gitkraken-mcp.md +107 -0
  54. data/.ai-assistance/integrations/gitlab-mcp.md +123 -0
  55. data/.ai-assistance/integrations/local-git.md +60 -0
  56. data/.ai-assistance/local_paths.example.md +17 -0
  57. data/.ai-assistance/projects/TODO.md +97 -0
  58. data/.ai-assistance/projects/api-v2-to-graphql-migration/DECISIONS.md +168 -0
  59. data/.ai-assistance/projects/api-v2-to-graphql-migration/INTENT.md +60 -0
  60. data/.ai-assistance/projects/api-v2-to-graphql-migration/TODO.md +267 -0
  61. data/.ai-assistance/projects/api-v2-to-graphql-migration/UPSTREAM.md +53 -0
  62. data/.ai-assistance/projects/api-v2-to-graphql-migration/notes/csv-template-pipeline-design.md +102 -0
  63. data/.ai-assistance/projects/api-v2-to-graphql-migration/notes/cutover-usecase-gap-audit.md +139 -0
  64. data/.ai-assistance/projects/dynamic-model-generation/INTENT.md +93 -0
  65. data/.ai-assistance/projects/eco-helpers-compat/INTENT.md +244 -0
  66. data/.ai-assistance/projects/eco-helpers-compat/MIGRATION_GUIDE.md +266 -0
  67. data/.ai-assistance/projects/eco-helpers-compat/TODO.md +86 -0
  68. data/.ai-assistance/projects/ecoportal-api-v2-doublemodel-review/INTENT.md +101 -0
  69. data/.ai-assistance/projects/graphql-agent/GAP_ANALYSIS.md +177 -0
  70. data/.ai-assistance/projects/ooze-graphql-native-migration/DECISIONS.md +161 -0
  71. data/.ai-assistance/projects/ooze-graphql-native-migration/INTENT.md +125 -0
  72. data/.ai-assistance/projects/ooze-graphql-native-migration/RISKS.md +126 -0
  73. data/.ai-assistance/projects/ooze-graphql-native-migration/TODO.md +256 -0
  74. data/.ai-assistance/projects/ooze-graphql-native-migration/analysis/2026-06-30-cutover-workflow-deep-review.md +122 -0
  75. data/.ai-assistance/projects/ooze-graphql-native-migration/analysis/2026-07-01-forces-via-workflow-commands-miss-rca.md +148 -0
  76. data/.ai-assistance/projects/page-model/DECISIONS.md +245 -0
  77. data/.ai-assistance/projects/page-model/TODO.md +190 -0
  78. data/.ai-assistance/projects/search-filter-builder/INTENT.md +107 -0
  79. data/.ai-assistance/projects/search-filter-builder/TODO.md +131 -0
  80. data/.ai-assistance/projects/template-maintenance/DESIGN.md +134 -0
  81. data/.ai-assistance/projects/workflow-space/TODO.md +213 -0
  82. data/.ai-assistance/reinstall-claude-desktop-windows.md +136 -0
  83. data/.ai-assistance/scripts/CLAUDE.md +150 -0
  84. data/.ai-assistance/scripts/bridge-init.sh +86 -0
  85. data/.ai-assistance/scripts/bridge-status.sh +44 -0
  86. data/.ai-assistance/scripts/capabilities-check.ts +104 -0
  87. data/.ai-assistance/scripts/check-outbox.sh +43 -0
  88. data/.ai-assistance/scripts/dep_graph.rb +91 -0
  89. data/.ai-assistance/scripts/lock-acquire.sh +103 -0
  90. data/.ai-assistance/scripts/lock-multi.sh +124 -0
  91. data/.ai-assistance/scripts/lock-queue.sh +94 -0
  92. data/.ai-assistance/scripts/setup-mcps.test.ts +188 -0
  93. data/.ai-assistance/scripts/setup-mcps.ts +234 -0
  94. data/.ai-assistance/scripts/task-complete.ts +74 -0
  95. data/.ai-assistance/scripts/task-create.ts +75 -0
  96. data/.ai-assistance/scripts/task-read.ts +125 -0
  97. data/.ai-assistance/scripts/token-logger.js +220 -0
  98. data/.ai-assistance/scripts/token-report.ts +158 -0
  99. data/.ai-assistance/scripts/token-session-start.js +66 -0
  100. data/.ai-assistance/skills/ai-instructions/SKILL.md +48 -0
  101. data/.ai-assistance/skills/code-specs/SKILL.md +69 -0
  102. data/.ai-assistance/skills/corporate-policies/SKILL.md +201 -0
  103. data/.ai-assistance/skills/dep-graph/SKILL.md +139 -0
  104. data/.ai-assistance/skills/ep-ai-manager/SKILL.md +417 -0
  105. data/.ai-assistance/skills/gemini-assist/SKILL.md +63 -0
  106. data/.ai-assistance/skills/gemini-assist/gemini-mcp-server.js +205 -0
  107. data/.ai-assistance/skills/gemini-assist/gemini_ask.py +1 -0
  108. data/.ai-assistance/skills/gemini-assist/gemini_ask.rb +240 -0
  109. data/.ai-assistance/skills/gemini-assist/prompts/cycle_end_review.txt +25 -0
  110. data/.ai-assistance/skills/graphql-schema-analysis/SKILL.md +261 -0
  111. data/.ai-assistance/skills/project-cycle/SKILL.md +177 -0
  112. data/.ai-assistance/skills/refactor/SKILL.md +62 -0
  113. data/.ai-assistance/skills/rubocop/SKILL.md +93 -0
  114. data/.ai-assistance/skills/ruby-scripting/SKILL.md +215 -0
  115. data/.ai-assistance/skills/spec-generation/SKILL.md +72 -0
  116. data/.ai-assistance/standards-version.json +21 -0
  117. data/.ai-assistance/token-budget.json +32 -0
  118. data/.ai-assistance/version.json +39 -0
  119. data/.claude/settings.json +146 -0
  120. data/.env.example +18 -0
  121. data/.gitattributes +15 -0
  122. data/.gitignore +13 -0
  123. data/.rubocop.yml +121 -97
  124. data/CHANGELOG.md +673 -477
  125. data/CLAUDE.md +232 -0
  126. data/Gemfile +30 -6
  127. data/Rakefile +90 -38
  128. data/docs/worklog.md +574 -0
  129. data/ecoportal-api-graphql.gemspec +40 -40
  130. data/lib/ecoportal/api/common/graphql/CLAUDE.md +36 -0
  131. data/lib/ecoportal/api/common/graphql/client.rb +1 -1
  132. data/lib/ecoportal/api/common/graphql/http_client.rb +35 -3
  133. data/lib/ecoportal/api/common/graphql/model/CLAUDE.md +28 -0
  134. data/lib/ecoportal/api/common/graphql/model/as_input.rb +8 -5
  135. data/lib/ecoportal/api/common/graphql/model/diffable/classic_diff_service.rb +3 -1
  136. data/lib/ecoportal/api/common/graphql/model/diffable/diff_service.rb +31 -23
  137. data/lib/ecoportal/api/common/graphql/model/diffable/hash_diff_nesting.rb +54 -1
  138. data/lib/ecoportal/api/graphql/CLAUDE.md +37 -0
  139. data/lib/ecoportal/api/graphql/base/CLAUDE.md +50 -0
  140. data/lib/ecoportal/api/graphql/base/ai_summary_version.rb +17 -0
  141. data/lib/ecoportal/api/graphql/base/delta_result.rb +16 -0
  142. data/lib/ecoportal/api/graphql/base/force/binding.rb +19 -0
  143. data/lib/ecoportal/api/graphql/base/force/binding_collection.rb +62 -0
  144. data/lib/ecoportal/api/graphql/base/force/collection.rb +47 -0
  145. data/lib/ecoportal/api/graphql/base/force.rb +65 -0
  146. data/lib/ecoportal/api/graphql/base/kickstand/job.rb +17 -0
  147. data/lib/ecoportal/api/graphql/base/kickstand/workflow.rb +18 -0
  148. data/lib/ecoportal/api/graphql/base/kickstand.rb +13 -0
  149. data/lib/ecoportal/api/graphql/base/page/basic.rb +38 -0
  150. data/lib/ecoportal/api/graphql/base/page/data_field/actions_list.rb +9 -0
  151. data/lib/ecoportal/api/graphql/base/page/data_field/ai_summary.rb +18 -0
  152. data/lib/ecoportal/api/graphql/base/page/data_field/checklist.rb +29 -0
  153. data/lib/ecoportal/api/graphql/base/page/data_field/collection.rb +112 -0
  154. data/lib/ecoportal/api/graphql/base/page/data_field/contractor_entities.rb +28 -0
  155. data/lib/ecoportal/api/graphql/base/page/data_field/cross_reference.rb +54 -0
  156. data/lib/ecoportal/api/graphql/base/page/data_field/date_field.rb +23 -0
  157. data/lib/ecoportal/api/graphql/base/page/data_field/file_field.rb +25 -0
  158. data/lib/ecoportal/api/graphql/base/page/data_field/gauge.rb +19 -0
  159. data/lib/ecoportal/api/graphql/base/page/data_field/geo.rb +24 -0
  160. data/lib/ecoportal/api/graphql/base/page/data_field/image_gallery.rb +24 -0
  161. data/lib/ecoportal/api/graphql/base/page/data_field/law.rb +8 -0
  162. data/lib/ecoportal/api/graphql/base/page/data_field/mailbox.rb +9 -0
  163. data/lib/ecoportal/api/graphql/base/page/data_field/number.rb +20 -0
  164. data/lib/ecoportal/api/graphql/base/page/data_field/people.rb +35 -0
  165. data/lib/ecoportal/api/graphql/base/page/data_field/plain_text.rb +17 -0
  166. data/lib/ecoportal/api/graphql/base/page/data_field/rich_text.rb +26 -0
  167. data/lib/ecoportal/api/graphql/base/page/data_field/select.rb +41 -0
  168. data/lib/ecoportal/api/graphql/base/page/data_field/signature.rb +9 -0
  169. data/lib/ecoportal/api/graphql/base/page/data_field/smart_fill.rb +17 -0
  170. data/lib/ecoportal/api/graphql/base/page/data_field/table.rb +9 -0
  171. data/lib/ecoportal/api/graphql/base/page/data_field/tag_field.rb +21 -0
  172. data/lib/ecoportal/api/graphql/base/page/data_field.rb +137 -12
  173. data/lib/ecoportal/api/graphql/base/page/phased/stage.rb +68 -14
  174. data/lib/ecoportal/api/graphql/base/page/phased.rb +1 -0
  175. data/lib/ecoportal/api/graphql/base/page/section.rb +36 -0
  176. data/lib/ecoportal/api/graphql/base/page/section_collection.rb +79 -0
  177. data/lib/ecoportal/api/graphql/base/page.rb +2 -0
  178. data/lib/ecoportal/api/graphql/base/pages_workflow/action_type_selection.rb +17 -0
  179. data/lib/ecoportal/api/graphql/base/pages_workflow/callback_type.rb +28 -0
  180. data/lib/ecoportal/api/graphql/base/pages_workflow/command_change.rb +17 -0
  181. data/lib/ecoportal/api/graphql/base/pages_workflow/command_change_message.rb +15 -0
  182. data/lib/ecoportal/api/graphql/base/pages_workflow/command_es_change.rb +17 -0
  183. data/lib/ecoportal/api/graphql/base/pages_workflow/command_interface.rb +36 -0
  184. data/lib/ecoportal/api/graphql/base/pages_workflow/email_config.rb +18 -0
  185. data/lib/ecoportal/api/graphql/base/pages_workflow/escalation_level.rb +19 -0
  186. data/lib/ecoportal/api/graphql/base/pages_workflow/in_system_config.rb +16 -0
  187. data/lib/ecoportal/api/graphql/base/pages_workflow/mailbox_field_selection.rb +17 -0
  188. data/lib/ecoportal/api/graphql/base/pages_workflow/operation_interface.rb +39 -0
  189. data/lib/ecoportal/api/graphql/base/pages_workflow/operations/assign_to.rb +27 -0
  190. data/lib/ecoportal/api/graphql/base/pages_workflow/operations/create_page.rb +21 -0
  191. data/lib/ecoportal/api/graphql/base/pages_workflow/operations/send_notification.rb +30 -0
  192. data/lib/ecoportal/api/graphql/base/pages_workflow/people_field_selection.rb +17 -0
  193. data/lib/ecoportal/api/graphql/base/pages_workflow/recipient_config.rb +34 -0
  194. data/lib/ecoportal/api/graphql/base/pages_workflow/register_field.rb +17 -0
  195. data/lib/ecoportal/api/graphql/base/pages_workflow/task_config_selection.rb +17 -0
  196. data/lib/ecoportal/api/graphql/base/pages_workflow/time_delay_config.rb +16 -0
  197. data/lib/ecoportal/api/graphql/base/pages_workflow/trigger_interface.rb +26 -0
  198. data/lib/ecoportal/api/graphql/base/pages_workflow/triggers/conditional_logic.rb +17 -0
  199. data/lib/ecoportal/api/graphql/base/pages_workflow/user_selection.rb +16 -0
  200. data/lib/ecoportal/api/graphql/base/pages_workflow.rb +35 -0
  201. data/lib/ecoportal/api/graphql/base/preset_view.rb +17 -0
  202. data/lib/ecoportal/api/graphql/base/preview_page.rb +23 -0
  203. data/lib/ecoportal/api/graphql/base/register.rb +18 -0
  204. data/lib/ecoportal/api/graphql/base.rb +11 -0
  205. data/lib/ecoportal/api/graphql/builder/CLAUDE.md +65 -0
  206. data/lib/ecoportal/api/graphql/builder/kickstand.rb +73 -0
  207. data/lib/ecoportal/api/graphql/builder/page.rb +210 -41
  208. data/lib/ecoportal/api/graphql/builder/register/preset_view.rb +84 -0
  209. data/lib/ecoportal/api/graphql/builder/register.rb +27 -19
  210. data/lib/ecoportal/api/graphql/builder/template.rb +80 -0
  211. data/lib/ecoportal/api/graphql/builder.rb +2 -0
  212. data/lib/ecoportal/api/graphql/compat/filter_translator.rb +107 -0
  213. data/lib/ecoportal/api/graphql/compat/page_reference.rb +23 -0
  214. data/lib/ecoportal/api/graphql/compat/pages.rb +212 -0
  215. data/lib/ecoportal/api/graphql/compat/registers.rb +84 -0
  216. data/lib/ecoportal/api/graphql/compat/response.rb +35 -0
  217. data/lib/ecoportal/api/graphql/compat/search_results.rb +33 -0
  218. data/lib/ecoportal/api/graphql/compat/stage_collection.rb +70 -0
  219. data/lib/ecoportal/api/graphql/compat/stage_view.rb +76 -0
  220. data/lib/ecoportal/api/graphql/compat.rb +17 -0
  221. data/lib/ecoportal/api/graphql/concerns/data_field_access.rb +71 -0
  222. data/lib/ecoportal/api/graphql/concerns/deprecation.rb +20 -0
  223. data/lib/ecoportal/api/graphql/concerns/fragment_definitions.rb +21 -28
  224. data/lib/ecoportal/api/graphql/concerns/page_compat.rb +51 -0
  225. data/lib/ecoportal/api/graphql/concerns/snake_camel_access.rb +60 -0
  226. data/lib/ecoportal/api/graphql/concerns.rb +4 -0
  227. data/lib/ecoportal/api/graphql/connection/page.rb +11 -0
  228. data/lib/ecoportal/api/graphql/connection/pages_workflow_command.rb +13 -0
  229. data/lib/ecoportal/api/graphql/connection/preset_view.rb +11 -0
  230. data/lib/ecoportal/api/graphql/connection/preview_page.rb +11 -0
  231. data/lib/ecoportal/api/graphql/connection.rb +4 -0
  232. data/lib/ecoportal/api/graphql/file_upload/client.rb +181 -0
  233. data/lib/ecoportal/api/graphql/file_upload.rb +10 -0
  234. data/lib/ecoportal/api/graphql/fragment/action.rb +1 -1
  235. data/lib/ecoportal/api/graphql/fragment/action_category.rb +1 -1
  236. data/lib/ecoportal/api/graphql/fragment/contractor_entity.rb +1 -1
  237. data/lib/ecoportal/api/graphql/fragment/force.rb +30 -0
  238. data/lib/ecoportal/api/graphql/fragment/location_draft.rb +2 -2
  239. data/lib/ecoportal/api/graphql/fragment/location_node.rb +1 -1
  240. data/lib/ecoportal/api/graphql/fragment/locations_error.rb +1 -1
  241. data/lib/ecoportal/api/graphql/fragment/page.rb +85 -0
  242. data/lib/ecoportal/api/graphql/fragment/pages/common_page_union.rb +395 -0
  243. data/lib/ecoportal/api/graphql/fragment/pages.rb +15 -0
  244. data/lib/ecoportal/api/graphql/fragment/pages_workflow.rb +172 -0
  245. data/lib/ecoportal/api/graphql/fragment/pagination.rb +1 -1
  246. data/lib/ecoportal/api/graphql/fragment.rb +37 -27
  247. data/lib/ecoportal/api/graphql/input/contractor_entity/update.rb +25 -0
  248. data/lib/ecoportal/api/graphql/input/delta_input.rb +16 -0
  249. data/lib/ecoportal/api/graphql/input/page/archive.rb +14 -0
  250. data/lib/ecoportal/api/graphql/input/page/build_from_template.rb +13 -0
  251. data/lib/ecoportal/api/graphql/input/page/create_draft.rb +13 -0
  252. data/lib/ecoportal/api/graphql/input/page/create_from_template.rb +18 -0
  253. data/lib/ecoportal/api/graphql/input/page/delete_draft.rb +13 -0
  254. data/lib/ecoportal/api/graphql/input/page/publish_draft.rb +13 -0
  255. data/lib/ecoportal/api/graphql/input/page/review_task.rb +14 -0
  256. data/lib/ecoportal/api/graphql/input/page/unarchive.rb +14 -0
  257. data/lib/ecoportal/api/graphql/input/page/update.rb +140 -0
  258. data/lib/ecoportal/api/graphql/input/page.rb +26 -0
  259. data/lib/ecoportal/api/graphql/input/preset_view/create.rb +18 -0
  260. data/lib/ecoportal/api/graphql/input/preset_view/permission.rb +16 -0
  261. data/lib/ecoportal/api/graphql/input/preset_view/update.rb +16 -0
  262. data/lib/ecoportal/api/graphql/input/preset_view.rb +14 -0
  263. data/lib/ecoportal/api/graphql/input/register/create.rb +18 -0
  264. data/lib/ecoportal/api/graphql/input/register/update.rb +15 -0
  265. data/lib/ecoportal/api/graphql/input/register.rb +13 -0
  266. data/lib/ecoportal/api/graphql/input/search_conf/ai_generator.rb +234 -0
  267. data/lib/ecoportal/api/graphql/input/search_conf.rb +367 -0
  268. data/lib/ecoportal/api/graphql/input/variable_binding.rb +20 -0
  269. data/lib/ecoportal/api/graphql/input/workflow_command/add_action_tag.rb +18 -0
  270. data/lib/ecoportal/api/graphql/input/workflow_command/add_binding.rb +18 -0
  271. data/lib/ecoportal/api/graphql/input/workflow_command/add_comment_tagging_user_group.rb +18 -0
  272. data/lib/ecoportal/api/graphql/input/workflow_command/add_default_direct_strategy_user.rb +18 -0
  273. data/lib/ecoportal/api/graphql/input/workflow_command/add_default_strategy.rb +18 -0
  274. data/lib/ecoportal/api/graphql/input/workflow_command/add_direct_strategy_user.rb +18 -0
  275. data/lib/ecoportal/api/graphql/input/workflow_command/add_field.rb +18 -0
  276. data/lib/ecoportal/api/graphql/input/workflow_command/add_force.rb +18 -0
  277. data/lib/ecoportal/api/graphql/input/workflow_command/add_gauge_field_stop.rb +19 -0
  278. data/lib/ecoportal/api/graphql/input/workflow_command/add_linked_field_config.rb +23 -0
  279. data/lib/ecoportal/api/graphql/input/workflow_command/add_linked_helper.rb +18 -0
  280. data/lib/ecoportal/api/graphql/input/workflow_command/add_operation.rb +18 -0
  281. data/lib/ecoportal/api/graphql/input/workflow_command/add_operation_direct_strategy_user.rb +18 -0
  282. data/lib/ecoportal/api/graphql/input/workflow_command/add_operation_strategy.rb +18 -0
  283. data/lib/ecoportal/api/graphql/input/workflow_command/add_recipient_action_type.rb +18 -0
  284. data/lib/ecoportal/api/graphql/input/workflow_command/add_recipient_filter.rb +18 -0
  285. data/lib/ecoportal/api/graphql/input/workflow_command/add_recipient_people_field.rb +18 -0
  286. data/lib/ecoportal/api/graphql/input/workflow_command/add_recipient_task_config.rb +18 -0
  287. data/lib/ecoportal/api/graphql/input/workflow_command/add_recipient_user.rb +18 -0
  288. data/lib/ecoportal/api/graphql/input/workflow_command/add_scheduled_callback.rb +23 -0
  289. data/lib/ecoportal/api/graphql/input/workflow_command/add_scheduled_callback_action.rb +18 -0
  290. data/lib/ecoportal/api/graphql/input/workflow_command/add_section.rb +18 -0
  291. data/lib/ecoportal/api/graphql/input/workflow_command/add_select_field_option.rb +19 -0
  292. data/lib/ecoportal/api/graphql/input/workflow_command/add_stage.rb +18 -0
  293. data/lib/ecoportal/api/graphql/input/workflow_command/add_stage_section.rb +18 -0
  294. data/lib/ecoportal/api/graphql/input/workflow_command/add_stage_tag.rb +18 -0
  295. data/lib/ecoportal/api/graphql/input/workflow_command/add_strategy.rb +18 -0
  296. data/lib/ecoportal/api/graphql/input/workflow_command/add_task.rb +18 -0
  297. data/lib/ecoportal/api/graphql/input/workflow_command/add_task_assignment_user_group.rb +18 -0
  298. data/lib/ecoportal/api/graphql/input/workflow_command/add_workflow_callback.rb +18 -0
  299. data/lib/ecoportal/api/graphql/input/workflow_command/collapse_section.rb +18 -0
  300. data/lib/ecoportal/api/graphql/input/workflow_command/edit_binding.rb +18 -0
  301. data/lib/ecoportal/api/graphql/input/workflow_command/edit_creator_permissions.rb +18 -0
  302. data/lib/ecoportal/api/graphql/input/workflow_command/edit_default_strategy.rb +18 -0
  303. data/lib/ecoportal/api/graphql/input/workflow_command/edit_field_configuration.rb +21 -0
  304. data/lib/ecoportal/api/graphql/input/workflow_command/edit_force.rb +18 -0
  305. data/lib/ecoportal/api/graphql/input/workflow_command/edit_gauge_field_stop.rb +19 -0
  306. data/lib/ecoportal/api/graphql/input/workflow_command/edit_linked_field_config.rb +19 -0
  307. data/lib/ecoportal/api/graphql/input/workflow_command/edit_linked_helper.rb +18 -0
  308. data/lib/ecoportal/api/graphql/input/workflow_command/edit_operation.rb +18 -0
  309. data/lib/ecoportal/api/graphql/input/workflow_command/edit_operation_strategy.rb +18 -0
  310. data/lib/ecoportal/api/graphql/input/workflow_command/edit_page.rb +28 -0
  311. data/lib/ecoportal/api/graphql/input/workflow_command/edit_page_creator_permissions.rb +18 -0
  312. data/lib/ecoportal/api/graphql/input/workflow_command/edit_reminder.rb +18 -0
  313. data/lib/ecoportal/api/graphql/input/workflow_command/edit_required_sign_offs.rb +18 -0
  314. data/lib/ecoportal/api/graphql/input/workflow_command/edit_restrict_comment_tagging.rb +18 -0
  315. data/lib/ecoportal/api/graphql/input/workflow_command/edit_restrict_task_assignment.rb +18 -0
  316. data/lib/ecoportal/api/graphql/input/workflow_command/edit_scheduled_callback.rb +22 -0
  317. data/lib/ecoportal/api/graphql/input/workflow_command/edit_section_header.rb +18 -0
  318. data/lib/ecoportal/api/graphql/input/workflow_command/edit_select_field_option.rb +19 -0
  319. data/lib/ecoportal/api/graphql/input/workflow_command/edit_stage.rb +18 -0
  320. data/lib/ecoportal/api/graphql/input/workflow_command/edit_strategy.rb +18 -0
  321. data/lib/ecoportal/api/graphql/input/workflow_command/edit_task_due.rb +18 -0
  322. data/lib/ecoportal/api/graphql/input/workflow_command/edit_trigger.rb +18 -0
  323. data/lib/ecoportal/api/graphql/input/workflow_command/expand_section.rb +18 -0
  324. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/contractor_entities.rb +24 -0
  325. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/cross_reference.rb +23 -0
  326. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/date.rb +20 -0
  327. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/gauge.rb +20 -0
  328. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/image_gallery.rb +20 -0
  329. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/location_field.rb +24 -0
  330. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/people.rb +24 -0
  331. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/plain_text.rb +20 -0
  332. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/rich_text.rb +20 -0
  333. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/select.rb +20 -0
  334. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/signature.rb +20 -0
  335. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/table.rb +25 -0
  336. data/lib/ecoportal/api/graphql/input/workflow_command/move_field.rb +18 -0
  337. data/lib/ecoportal/api/graphql/input/workflow_command/move_stage.rb +18 -0
  338. data/lib/ecoportal/api/graphql/input/workflow_command/remove_action_tag.rb +18 -0
  339. data/lib/ecoportal/api/graphql/input/workflow_command/remove_binding.rb +18 -0
  340. data/lib/ecoportal/api/graphql/input/workflow_command/remove_callback.rb +18 -0
  341. data/lib/ecoportal/api/graphql/input/workflow_command/remove_comment_tagging_user_group.rb +18 -0
  342. data/lib/ecoportal/api/graphql/input/workflow_command/remove_default_direct_strategy_user.rb +18 -0
  343. data/lib/ecoportal/api/graphql/input/workflow_command/remove_default_strategy.rb +18 -0
  344. data/lib/ecoportal/api/graphql/input/workflow_command/remove_direct_strategy_user.rb +18 -0
  345. data/lib/ecoportal/api/graphql/input/workflow_command/remove_field.rb +18 -0
  346. data/lib/ecoportal/api/graphql/input/workflow_command/remove_force.rb +18 -0
  347. data/lib/ecoportal/api/graphql/input/workflow_command/remove_gauge_field_stop.rb +17 -0
  348. data/lib/ecoportal/api/graphql/input/workflow_command/remove_linked_field_config.rb +17 -0
  349. data/lib/ecoportal/api/graphql/input/workflow_command/remove_linked_helper.rb +18 -0
  350. data/lib/ecoportal/api/graphql/input/workflow_command/remove_operation.rb +18 -0
  351. data/lib/ecoportal/api/graphql/input/workflow_command/remove_operation_direct_strategy_user.rb +18 -0
  352. data/lib/ecoportal/api/graphql/input/workflow_command/remove_operation_strategy.rb +18 -0
  353. data/lib/ecoportal/api/graphql/input/workflow_command/remove_recipient_action_type.rb +18 -0
  354. data/lib/ecoportal/api/graphql/input/workflow_command/remove_recipient_filter.rb +18 -0
  355. data/lib/ecoportal/api/graphql/input/workflow_command/remove_recipient_people_field.rb +18 -0
  356. data/lib/ecoportal/api/graphql/input/workflow_command/remove_recipient_task_config.rb +18 -0
  357. data/lib/ecoportal/api/graphql/input/workflow_command/remove_recipient_user.rb +18 -0
  358. data/lib/ecoportal/api/graphql/input/workflow_command/remove_scheduled_callback.rb +18 -0
  359. data/lib/ecoportal/api/graphql/input/workflow_command/remove_section.rb +18 -0
  360. data/lib/ecoportal/api/graphql/input/workflow_command/remove_select_field_option.rb +17 -0
  361. data/lib/ecoportal/api/graphql/input/workflow_command/remove_stage.rb +18 -0
  362. data/lib/ecoportal/api/graphql/input/workflow_command/remove_stage_section.rb +18 -0
  363. data/lib/ecoportal/api/graphql/input/workflow_command/remove_stage_tag.rb +18 -0
  364. data/lib/ecoportal/api/graphql/input/workflow_command/remove_strategy.rb +18 -0
  365. data/lib/ecoportal/api/graphql/input/workflow_command/remove_task.rb +18 -0
  366. data/lib/ecoportal/api/graphql/input/workflow_command/remove_task_assignment_user_group.rb +18 -0
  367. data/lib/ecoportal/api/graphql/input/workflow_command/remove_task_due.rb +18 -0
  368. data/lib/ecoportal/api/graphql/input/workflow_command/remove_task_priority_level.rb +18 -0
  369. data/lib/ecoportal/api/graphql/input/workflow_command/reorder_forces.rb +18 -0
  370. data/lib/ecoportal/api/graphql/input/workflow_command/reorder_section.rb +18 -0
  371. data/lib/ecoportal/api/graphql/input/workflow_command.rb +251 -0
  372. data/lib/ecoportal/api/graphql/input.rb +8 -0
  373. data/lib/ecoportal/api/graphql/interface/base_page.rb +100 -58
  374. data/lib/ecoportal/api/graphql/interface/location_structure/nodes.rb +27 -28
  375. data/lib/ecoportal/api/graphql/logic/base_model.rb +2 -0
  376. data/lib/ecoportal/api/graphql/logic/base_query.rb +45 -2
  377. data/lib/ecoportal/api/graphql/logic/input.rb +15 -0
  378. data/lib/ecoportal/api/graphql/model/ai_summary_version.rb +10 -0
  379. data/lib/ecoportal/api/graphql/model/organization.rb +65 -55
  380. data/lib/ecoportal/api/graphql/model/page/basic.rb +14 -0
  381. data/lib/ecoportal/api/graphql/model/page/phased.rb +82 -20
  382. data/lib/ecoportal/api/graphql/model/page.rb +1 -0
  383. data/lib/ecoportal/api/graphql/model/page_union.rb +21 -0
  384. data/lib/ecoportal/api/graphql/model/pages_workflow.rb +20 -0
  385. data/lib/ecoportal/api/graphql/model/preset_view.rb +10 -0
  386. data/lib/ecoportal/api/graphql/model/preview_page.rb +10 -0
  387. data/lib/ecoportal/api/graphql/model/register.rb +10 -0
  388. data/lib/ecoportal/api/graphql/model.rb +8 -0
  389. data/lib/ecoportal/api/graphql/mutation/ai_summary/generate.rb +45 -0
  390. data/lib/ecoportal/api/graphql/mutation/ai_summary/submit_feedback.rb +40 -0
  391. data/lib/ecoportal/api/graphql/mutation/ai_summary.rb +13 -0
  392. data/lib/ecoportal/api/graphql/mutation/kickstand/bulk_update_jobs.rb +43 -0
  393. data/lib/ecoportal/api/graphql/mutation/kickstand/bulk_update_workflows.rb +43 -0
  394. data/lib/ecoportal/api/graphql/mutation/kickstand/fail_job.rb +39 -0
  395. data/lib/ecoportal/api/graphql/mutation/kickstand/fail_workflow.rb +39 -0
  396. data/lib/ecoportal/api/graphql/mutation/kickstand/start_job.rb +39 -0
  397. data/lib/ecoportal/api/graphql/mutation/kickstand/start_workflow.rb +39 -0
  398. data/lib/ecoportal/api/graphql/mutation/kickstand/stop_workflow.rb +39 -0
  399. data/lib/ecoportal/api/graphql/mutation/kickstand.rb +18 -0
  400. data/lib/ecoportal/api/graphql/mutation/location_structure/apply_commands.rb +3 -3
  401. data/lib/ecoportal/api/graphql/mutation/location_structure/draft/add_commands.rb +2 -2
  402. data/lib/ecoportal/api/graphql/mutation/location_structure/draft/create.rb +2 -2
  403. data/lib/ecoportal/api/graphql/mutation/location_structure/draft/drop_bad_commands.rb +3 -3
  404. data/lib/ecoportal/api/graphql/mutation/location_structure/draft/publish.rb +3 -3
  405. data/lib/ecoportal/api/graphql/mutation/page/approve_review_task.rb +40 -0
  406. data/lib/ecoportal/api/graphql/mutation/page/archive.rb +40 -0
  407. data/lib/ecoportal/api/graphql/mutation/page/batch_update_review_task.rb +40 -0
  408. data/lib/ecoportal/api/graphql/mutation/page/build_from_template.rb +50 -0
  409. data/lib/ecoportal/api/graphql/mutation/page/create_draft.rb +40 -0
  410. data/lib/ecoportal/api/graphql/mutation/page/create_from_template.rb +43 -0
  411. data/lib/ecoportal/api/graphql/mutation/page/delete_draft.rb +40 -0
  412. data/lib/ecoportal/api/graphql/mutation/page/execute_force_commands.rb +69 -0
  413. data/lib/ecoportal/api/graphql/mutation/page/execute_workflow_commands.rb +51 -0
  414. data/lib/ecoportal/api/graphql/mutation/page/publish_draft.rb +40 -0
  415. data/lib/ecoportal/api/graphql/mutation/page/reject_review_task.rb +40 -0
  416. data/lib/ecoportal/api/graphql/mutation/page/restart_review_task.rb +40 -0
  417. data/lib/ecoportal/api/graphql/mutation/page/unarchive.rb +40 -0
  418. data/lib/ecoportal/api/graphql/mutation/page/undo_review_task.rb +40 -0
  419. data/lib/ecoportal/api/graphql/mutation/page/update.rb +40 -0
  420. data/lib/ecoportal/api/graphql/mutation/page/update_variable_bindings.rb +44 -0
  421. data/lib/ecoportal/api/graphql/mutation/page.rb +28 -0
  422. data/lib/ecoportal/api/graphql/mutation/preset_view/create.rb +35 -0
  423. data/lib/ecoportal/api/graphql/mutation/preset_view/destroy.rb +35 -0
  424. data/lib/ecoportal/api/graphql/mutation/preset_view/permission.rb +37 -0
  425. data/lib/ecoportal/api/graphql/mutation/preset_view/update.rb +35 -0
  426. data/lib/ecoportal/api/graphql/mutation/preset_view.rb +15 -0
  427. data/lib/ecoportal/api/graphql/mutation/register/create.rb +35 -0
  428. data/lib/ecoportal/api/graphql/mutation/register/destroy.rb +35 -0
  429. data/lib/ecoportal/api/graphql/mutation/register/update.rb +35 -0
  430. data/lib/ecoportal/api/graphql/mutation/register.rb +14 -0
  431. data/lib/ecoportal/api/graphql/mutation/smart_fill/generate.rb +36 -0
  432. data/lib/ecoportal/api/graphql/mutation/smart_fill/submit_feedback.rb +40 -0
  433. data/lib/ecoportal/api/graphql/mutation/smart_fill.rb +13 -0
  434. data/lib/ecoportal/api/graphql/mutation/template/create.rb +39 -0
  435. data/lib/ecoportal/api/graphql/mutation/template/create_related_page.rb +46 -0
  436. data/lib/ecoportal/api/graphql/mutation/template/destroy_related_page.rb +43 -0
  437. data/lib/ecoportal/api/graphql/mutation/template/publish.rb +39 -0
  438. data/lib/ecoportal/api/graphql/mutation/template/unpublish.rb +39 -0
  439. data/lib/ecoportal/api/graphql/mutation/template/update.rb +43 -0
  440. data/lib/ecoportal/api/graphql/mutation/template/update_information.rb +43 -0
  441. data/lib/ecoportal/api/graphql/mutation/template.rb +18 -0
  442. data/lib/ecoportal/api/graphql/mutation.rb +8 -0
  443. data/lib/ecoportal/api/graphql/payload/ai_summary_generate.rb +12 -0
  444. data/lib/ecoportal/api/graphql/payload/execute_workflow_commands.rb +36 -0
  445. data/lib/ecoportal/api/graphql/payload/force_commands.rb +31 -0
  446. data/lib/ecoportal/api/graphql/payload/kickstand/bulk_update_jobs.rb +36 -0
  447. data/lib/ecoportal/api/graphql/payload/kickstand/bulk_update_workflows.rb +36 -0
  448. data/lib/ecoportal/api/graphql/payload/kickstand/job.rb +13 -0
  449. data/lib/ecoportal/api/graphql/payload/kickstand/workflow.rb +13 -0
  450. data/lib/ecoportal/api/graphql/payload/kickstand.rb +15 -0
  451. data/lib/ecoportal/api/graphql/payload/location_structure/draft/create.rb +33 -34
  452. data/lib/ecoportal/api/graphql/payload/ok_payload.rb +21 -0
  453. data/lib/ecoportal/api/graphql/payload/page/archive.rb +13 -0
  454. data/lib/ecoportal/api/graphql/payload/page/build_from_template.rb +13 -0
  455. data/lib/ecoportal/api/graphql/payload/page/create_from_template.rb +13 -0
  456. data/lib/ecoportal/api/graphql/payload/page/draft.rb +13 -0
  457. data/lib/ecoportal/api/graphql/payload/page/review_task.rb +13 -0
  458. data/lib/ecoportal/api/graphql/payload/page/unarchive.rb +13 -0
  459. data/lib/ecoportal/api/graphql/payload/page/update.rb +13 -0
  460. data/lib/ecoportal/api/graphql/payload/page/update_variable_bindings.rb +13 -0
  461. data/lib/ecoportal/api/graphql/payload/page.rb +19 -0
  462. data/lib/ecoportal/api/graphql/payload/preset_view.rb +11 -0
  463. data/lib/ecoportal/api/graphql/payload/register.rb +11 -0
  464. data/lib/ecoportal/api/graphql/payload/template/create.rb +13 -0
  465. data/lib/ecoportal/api/graphql/payload/template/create_related_page.rb +13 -0
  466. data/lib/ecoportal/api/graphql/payload/template/destroy_related_page.rb +13 -0
  467. data/lib/ecoportal/api/graphql/payload/template/publish.rb +13 -0
  468. data/lib/ecoportal/api/graphql/payload/template/unpublish.rb +13 -0
  469. data/lib/ecoportal/api/graphql/payload/template/update.rb +13 -0
  470. data/lib/ecoportal/api/graphql/payload/template/update_information.rb +13 -0
  471. data/lib/ecoportal/api/graphql/payload/template.rb +18 -0
  472. data/lib/ecoportal/api/graphql/payload.rb +11 -0
  473. data/lib/ecoportal/api/graphql/query/action.rb +1 -1
  474. data/lib/ecoportal/api/graphql/query/action_categories.rb +1 -1
  475. data/lib/ecoportal/api/graphql/query/actions.rb +2 -2
  476. data/lib/ecoportal/api/graphql/query/contractor_entities.rb +1 -1
  477. data/lib/ecoportal/api/graphql/query/file_upload_signature.rb +76 -0
  478. data/lib/ecoportal/api/graphql/query/location_structure/draft.rb +2 -2
  479. data/lib/ecoportal/api/graphql/query/location_structure.rb +1 -1
  480. data/lib/ecoportal/api/graphql/query/location_structures.rb +1 -1
  481. data/lib/ecoportal/api/graphql/query/page.rb +45 -0
  482. data/lib/ecoportal/api/graphql/query/page_delta.rb +47 -0
  483. data/lib/ecoportal/api/graphql/query/page_with_forces.rb +43 -0
  484. data/lib/ecoportal/api/graphql/query/pages.rb +59 -0
  485. data/lib/ecoportal/api/graphql/query/pages_workflow_commands.rb +59 -0
  486. data/lib/ecoportal/api/graphql/query/register_preset_views.rb +78 -0
  487. data/lib/ecoportal/api/graphql/query/register_preview_pages.rb +83 -0
  488. data/lib/ecoportal/api/graphql/query/templates.rb +53 -0
  489. data/lib/ecoportal/api/graphql/query.rb +11 -0
  490. data/lib/ecoportal/api/graphql.rb +60 -2
  491. data/lib/ecoportal/api/graphql_version.rb +5 -5
  492. data/scripts/auto-worker-scheduler.sh +386 -0
  493. data/tests/contractor_entity_create.rb +19 -19
  494. data/tests/contractor_entity_udpate.rb +20 -20
  495. data/tests/dump_page_model.rb +74 -0
  496. data/tests/loc_structure_get.rb +1 -2
  497. data/tests/loc_structure_update.rb +51 -51
  498. data/tests/loc_structures_get.rb +15 -15
  499. metadata +436 -5
@@ -0,0 +1,73 @@
1
+ # Spec Coverage Map
2
+
3
+ *Last updated: 2026-06-07*
4
+
5
+ ---
6
+
7
+ ## Areas WITH specs (117 examples total)
8
+
9
+ | Spec file | What it covers |
10
+ |---|---|
11
+ | `common/graphql/model/as_input_spec.rb` | `AsInput#as_input`, `Logic::Input.from_model`, `ContractorEntity::Update.from_model` |
12
+ | `common/graphql/model/diff_service_spec.rb` | `DiffService#diff` — no-change, single prop, nested, root! exclusion |
13
+ | `base/page/data_field_spec.rb` | `DataField.from_doc` dispatch, dirty tracking, `as_input` for PlainText/RichText/Select/People/Checklist, `Collection` get_by_type/get_by_name/dirty_inputs |
14
+ | `concerns/fragment_definitions_spec.rb` | `FragmentDefinitions.assemble`, `register_namespace` cross-namespace discovery, `Fragment::Pages` integration |
15
+ | `input/page/update_spec.rb` | `Input::Page::Update.from_model` — no-change nil, patchVer injection, publish flag, clientMutationId |
16
+ | `input/search_conf_spec.rb` | `SearchConf` builder — all filter types, sort, query, `#with` parametrization, `as_json` |
17
+ | `logic/assemble_fragments_spec.rb` | `BaseQuery#assemble_fragments` — single, recursive (PageFields→LocationNode), cycle safety, deduplication |
18
+ | `model/page_union_spec.rb` | `Model::PageUnion.new` — `__typename` dispatch to Basic/Phased/fallback, opts forwarded |
19
+ | `api_spec.rb` | Version constant smoke test |
20
+
21
+ ---
22
+
23
+ ## Areas WITHOUT specs (by design or deferred)
24
+
25
+ ### Query / Mutation / Payload / Builder classes
26
+ No unit specs. These classes primarily wire DSL blocks to HTTP + response wrapping —
27
+ meaningful tests require a live or stubbed GraphQL server. Integration testing via
28
+ `tests/` scripts (manual) is the current approach.
29
+
30
+ Includes: `Query::Page`, `Query::Pages`, `Query::Templates`, `Query::RegisterPreviewPages`,
31
+ `Query::PageDelta`, all `Mutation::Page::*`, all `Payload::Page::*`, `Builder::Page`.
32
+
33
+ **Gap severity: Low** — the classes are thin wrappers; bugs show up on integration.
34
+ If stubs become practical, priority order: `Query::Page`, `Query::Pages`.
35
+
36
+ ### Compat layer
37
+ No unit specs for `Compat::Pages`, `Compat::Registers`, `Compat::StageCollection`,
38
+ `Compat::SearchResults`. These require either a live GraphQL connection or deep mocking.
39
+
40
+ **Gap severity: Medium** — integration testing with the end-script repo (pending access)
41
+ will cover this.
42
+
43
+ ### Model classes (stubs and pass-through)
44
+ `Base::Page::Basic`, `Base::Page::Phased`, `Model::Page::Basic`, `Model::Page::Phased`,
45
+ `Base::PreviewPage`, `Base::DeltaResult`, `Base::Page::DataField::TagField/Geo/Gauge/Date/Number`
46
+ — these are mostly DSL declarations with no business logic. Not worth unit-testing.
47
+
48
+ ### Fragment definitions (GRAPHQL strings)
49
+ `Fragment::PageFields`, `BasicPageFields`, `PhasedPageFields` — assembly is tested via
50
+ `assemble_fragments_spec.rb`. Individual fragment content is validated in integration.
51
+
52
+ ### Input stubs
53
+ `Input::DeltaInput`, `Input::Page::Archive`, `Input::Page::Unarchive`,
54
+ `Input::Page::BuildFromTemplate`, `Input::Page::CreateFromTemplate` — simple passthrough
55
+ classes. Worth adding if any logic is added.
56
+
57
+ ### Concerns
58
+ `Concerns::DataFieldAccess`, `Concerns::PageCompat`, `Concerns::PhasedPageCompat` —
59
+ tested indirectly via `data_field_spec.rb` and `page_union_spec.rb`.
60
+
61
+ ---
62
+
63
+ ## Recommended next specs (priority order)
64
+
65
+ 1. **`Input::Page::Update.from_model` with `dataFields`** — now that field changes are
66
+ included, add a test that dirty fields appear in `dataFields.updates`.
67
+ File: extend `spec/ecoportal/api/graphql/input/page/update_spec.rb`
68
+
69
+ 2. **`StageCollection`** — `stages[name]`, `stages.get_by_name`, `stages.ordered`.
70
+ File: `spec/ecoportal/api/graphql/compat/stage_collection_spec.rb`
71
+
72
+ 3. **`SearchConf` filter translation in Registers** — v2 `date_filter` lbound→gte.
73
+ File: `spec/ecoportal/api/graphql/compat/registers_spec.rb` (filter translation only)
@@ -0,0 +1,438 @@
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
+ ```