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.
- checksums.yaml +4 -4
- data/.ai-assistance/bridge/CLAUDE.md +338 -0
- data/.ai-assistance/bridge/archive/.gitkeep +0 -0
- data/.ai-assistance/bridge/archive/oscar-a1b2c3d-gitlab-mcp-doc-update.inbox.md +29 -0
- data/.ai-assistance/bridge/archive/oscar-a1b2c3d-gitlab-mcp-doc-update.outbox.md +18 -0
- data/.ai-assistance/bridge/archive/oscar-c912c25-gemini-design-review.inbox.md +42 -0
- data/.ai-assistance/bridge/archive/oscar-c912c25-gemini-design-review.outbox.md +115 -0
- data/.ai-assistance/bridge/context/gemini-review-prompt.txt +48 -0
- data/.ai-assistance/bridge/context/gemini-review-response.md +104 -0
- data/.ai-assistance/bridge/context/project.md +42 -0
- data/.ai-assistance/bridge/inbox/.gitkeep +0 -0
- data/.ai-assistance/bridge/outbox/.gitkeep +0 -0
- data/.ai-assistance/bridge/outbox/request-for-standards-discovery.md +48 -0
- data/.ai-assistance/bridge/queue/.gitkeep +1 -0
- data/.ai-assistance/capabilities/CLAUDE.md +27 -0
- data/.ai-assistance/capabilities/assumptions-log.md +80 -0
- data/.ai-assistance/capabilities/code.md +47 -0
- data/.ai-assistance/capabilities/connectors.md +37 -0
- data/.ai-assistance/capabilities/cowork.md +55 -0
- data/.ai-assistance/code/OVERVIEW.md +155 -0
- data/.ai-assistance/code/data_fields.md +242 -0
- data/.ai-assistance/code/dependencies.md +151 -0
- data/.ai-assistance/code/diff_as_input.md +234 -0
- data/.ai-assistance/code/diff_service_deep_dive.md +192 -0
- data/.ai-assistance/code/ecoPortal_architecture/00_overview_and_index.md +55 -0
- data/.ai-assistance/code/ecoPortal_architecture/01_terminology_dictionary.md +181 -0
- data/.ai-assistance/code/ecoPortal_architecture/02_data_model.md +192 -0
- data/.ai-assistance/code/ecoPortal_architecture/03_api_layers.md +147 -0
- data/.ai-assistance/code/ecoPortal_architecture/04_graphql_queries_mutations.md +277 -0
- data/.ai-assistance/code/ecoPortal_architecture/05_page_workflows.md +200 -0
- data/.ai-assistance/code/ecoPortal_architecture/06_search_and_filters.md +228 -0
- data/.ai-assistance/code/ecoPortal_architecture/07_data_fields.md +197 -0
- data/.ai-assistance/code/ecoPortal_architecture/08_stages_sections.md +243 -0
- data/.ai-assistance/code/ecoPortal_architecture/09_people_contractors_locations.md +196 -0
- data/.ai-assistance/code/ecoPortal_architecture/10_forces_workflow_builder.md +132 -0
- data/.ai-assistance/code/ecoPortal_architecture/11_integration_gems.md +187 -0
- data/.ai-assistance/code/ecoPortal_architecture/12_ai_documentation_sources_gaps.md +236 -0
- data/.ai-assistance/code/ecoPortal_architecture/13_ai_infrastructure.md +183 -0
- data/.ai-assistance/code/ecoportal_schema_reference.md +240 -0
- data/.ai-assistance/code/graphql_domain_knowledge.md +230 -0
- data/.ai-assistance/code/refactoring/datafield-readwrite-shape-asymmetry.md +71 -0
- data/.ai-assistance/code/refactoring/opportunities.md +251 -0
- data/.ai-assistance/code/schema_analysis.md +321 -0
- data/.ai-assistance/code/search_filters.md +868 -0
- data/.ai-assistance/code/spec_coverage.md +73 -0
- data/.ai-assistance/code/workflow-command-guide.md +438 -0
- data/.ai-assistance/code/workflow-space.md +353 -0
- data/.ai-assistance/conventions/CLAUDE.md +30 -0
- data/.ai-assistance/conventions/code-working-tree-protocol.md +199 -0
- data/.ai-assistance/conventions/gitignore-rules.md +42 -0
- data/.ai-assistance/conventions/permission-guidance.md +120 -0
- data/.ai-assistance/integrations/README.md +70 -0
- data/.ai-assistance/integrations/gitkraken-mcp.md +107 -0
- data/.ai-assistance/integrations/gitlab-mcp.md +123 -0
- data/.ai-assistance/integrations/local-git.md +60 -0
- data/.ai-assistance/local_paths.example.md +17 -0
- data/.ai-assistance/projects/TODO.md +97 -0
- data/.ai-assistance/projects/api-v2-to-graphql-migration/DECISIONS.md +168 -0
- data/.ai-assistance/projects/api-v2-to-graphql-migration/INTENT.md +60 -0
- data/.ai-assistance/projects/api-v2-to-graphql-migration/TODO.md +267 -0
- data/.ai-assistance/projects/api-v2-to-graphql-migration/UPSTREAM.md +53 -0
- data/.ai-assistance/projects/api-v2-to-graphql-migration/notes/csv-template-pipeline-design.md +102 -0
- data/.ai-assistance/projects/api-v2-to-graphql-migration/notes/cutover-usecase-gap-audit.md +139 -0
- data/.ai-assistance/projects/dynamic-model-generation/INTENT.md +93 -0
- data/.ai-assistance/projects/eco-helpers-compat/INTENT.md +244 -0
- data/.ai-assistance/projects/eco-helpers-compat/MIGRATION_GUIDE.md +266 -0
- data/.ai-assistance/projects/eco-helpers-compat/TODO.md +86 -0
- data/.ai-assistance/projects/ecoportal-api-v2-doublemodel-review/INTENT.md +101 -0
- data/.ai-assistance/projects/graphql-agent/GAP_ANALYSIS.md +177 -0
- data/.ai-assistance/projects/ooze-graphql-native-migration/DECISIONS.md +161 -0
- data/.ai-assistance/projects/ooze-graphql-native-migration/INTENT.md +125 -0
- data/.ai-assistance/projects/ooze-graphql-native-migration/RISKS.md +126 -0
- data/.ai-assistance/projects/ooze-graphql-native-migration/TODO.md +256 -0
- data/.ai-assistance/projects/ooze-graphql-native-migration/analysis/2026-06-30-cutover-workflow-deep-review.md +122 -0
- data/.ai-assistance/projects/ooze-graphql-native-migration/analysis/2026-07-01-forces-via-workflow-commands-miss-rca.md +148 -0
- data/.ai-assistance/projects/page-model/DECISIONS.md +245 -0
- data/.ai-assistance/projects/page-model/TODO.md +190 -0
- data/.ai-assistance/projects/search-filter-builder/INTENT.md +107 -0
- data/.ai-assistance/projects/search-filter-builder/TODO.md +131 -0
- data/.ai-assistance/projects/template-maintenance/DESIGN.md +134 -0
- data/.ai-assistance/projects/workflow-space/TODO.md +213 -0
- data/.ai-assistance/reinstall-claude-desktop-windows.md +136 -0
- data/.ai-assistance/scripts/CLAUDE.md +150 -0
- data/.ai-assistance/scripts/bridge-init.sh +86 -0
- data/.ai-assistance/scripts/bridge-status.sh +44 -0
- data/.ai-assistance/scripts/capabilities-check.ts +104 -0
- data/.ai-assistance/scripts/check-outbox.sh +43 -0
- data/.ai-assistance/scripts/dep_graph.rb +91 -0
- data/.ai-assistance/scripts/lock-acquire.sh +103 -0
- data/.ai-assistance/scripts/lock-multi.sh +124 -0
- data/.ai-assistance/scripts/lock-queue.sh +94 -0
- data/.ai-assistance/scripts/setup-mcps.test.ts +188 -0
- data/.ai-assistance/scripts/setup-mcps.ts +234 -0
- data/.ai-assistance/scripts/task-complete.ts +74 -0
- data/.ai-assistance/scripts/task-create.ts +75 -0
- data/.ai-assistance/scripts/task-read.ts +125 -0
- data/.ai-assistance/scripts/token-logger.js +220 -0
- data/.ai-assistance/scripts/token-report.ts +158 -0
- data/.ai-assistance/scripts/token-session-start.js +66 -0
- data/.ai-assistance/skills/ai-instructions/SKILL.md +48 -0
- data/.ai-assistance/skills/code-specs/SKILL.md +69 -0
- data/.ai-assistance/skills/corporate-policies/SKILL.md +201 -0
- data/.ai-assistance/skills/dep-graph/SKILL.md +139 -0
- data/.ai-assistance/skills/ep-ai-manager/SKILL.md +417 -0
- data/.ai-assistance/skills/gemini-assist/SKILL.md +63 -0
- data/.ai-assistance/skills/gemini-assist/gemini-mcp-server.js +205 -0
- data/.ai-assistance/skills/gemini-assist/gemini_ask.py +1 -0
- data/.ai-assistance/skills/gemini-assist/gemini_ask.rb +240 -0
- data/.ai-assistance/skills/gemini-assist/prompts/cycle_end_review.txt +25 -0
- data/.ai-assistance/skills/graphql-schema-analysis/SKILL.md +261 -0
- data/.ai-assistance/skills/project-cycle/SKILL.md +177 -0
- data/.ai-assistance/skills/refactor/SKILL.md +62 -0
- data/.ai-assistance/skills/rubocop/SKILL.md +93 -0
- data/.ai-assistance/skills/ruby-scripting/SKILL.md +215 -0
- data/.ai-assistance/skills/spec-generation/SKILL.md +72 -0
- data/.ai-assistance/standards-version.json +21 -0
- data/.ai-assistance/token-budget.json +32 -0
- data/.ai-assistance/version.json +39 -0
- data/.claude/settings.json +146 -0
- data/.env.example +18 -0
- data/.gitattributes +15 -0
- data/.gitignore +13 -0
- data/.rubocop.yml +121 -97
- data/CHANGELOG.md +673 -477
- data/CLAUDE.md +232 -0
- data/Gemfile +30 -6
- data/Rakefile +90 -38
- data/docs/worklog.md +574 -0
- data/ecoportal-api-graphql.gemspec +40 -40
- data/lib/ecoportal/api/common/graphql/CLAUDE.md +36 -0
- data/lib/ecoportal/api/common/graphql/client.rb +1 -1
- data/lib/ecoportal/api/common/graphql/http_client.rb +35 -3
- data/lib/ecoportal/api/common/graphql/model/CLAUDE.md +28 -0
- data/lib/ecoportal/api/common/graphql/model/as_input.rb +8 -5
- data/lib/ecoportal/api/common/graphql/model/diffable/classic_diff_service.rb +3 -1
- data/lib/ecoportal/api/common/graphql/model/diffable/diff_service.rb +31 -23
- data/lib/ecoportal/api/common/graphql/model/diffable/hash_diff_nesting.rb +54 -1
- data/lib/ecoportal/api/graphql/CLAUDE.md +37 -0
- data/lib/ecoportal/api/graphql/base/CLAUDE.md +50 -0
- data/lib/ecoportal/api/graphql/base/ai_summary_version.rb +17 -0
- data/lib/ecoportal/api/graphql/base/delta_result.rb +16 -0
- data/lib/ecoportal/api/graphql/base/force/binding.rb +19 -0
- data/lib/ecoportal/api/graphql/base/force/binding_collection.rb +62 -0
- data/lib/ecoportal/api/graphql/base/force/collection.rb +47 -0
- data/lib/ecoportal/api/graphql/base/force.rb +65 -0
- data/lib/ecoportal/api/graphql/base/kickstand/job.rb +17 -0
- data/lib/ecoportal/api/graphql/base/kickstand/workflow.rb +18 -0
- data/lib/ecoportal/api/graphql/base/kickstand.rb +13 -0
- data/lib/ecoportal/api/graphql/base/page/basic.rb +38 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/actions_list.rb +9 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/ai_summary.rb +18 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/checklist.rb +29 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/collection.rb +112 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/contractor_entities.rb +28 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/cross_reference.rb +54 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/date_field.rb +23 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/file_field.rb +25 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/gauge.rb +19 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/geo.rb +24 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/image_gallery.rb +24 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/law.rb +8 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/mailbox.rb +9 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/number.rb +20 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/people.rb +35 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/plain_text.rb +17 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/rich_text.rb +26 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/select.rb +41 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/signature.rb +9 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/smart_fill.rb +17 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/table.rb +9 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/tag_field.rb +21 -0
- data/lib/ecoportal/api/graphql/base/page/data_field.rb +137 -12
- data/lib/ecoportal/api/graphql/base/page/phased/stage.rb +68 -14
- data/lib/ecoportal/api/graphql/base/page/phased.rb +1 -0
- data/lib/ecoportal/api/graphql/base/page/section.rb +36 -0
- data/lib/ecoportal/api/graphql/base/page/section_collection.rb +79 -0
- data/lib/ecoportal/api/graphql/base/page.rb +2 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/action_type_selection.rb +17 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/callback_type.rb +28 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/command_change.rb +17 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/command_change_message.rb +15 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/command_es_change.rb +17 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/command_interface.rb +36 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/email_config.rb +18 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/escalation_level.rb +19 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/in_system_config.rb +16 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/mailbox_field_selection.rb +17 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/operation_interface.rb +39 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/operations/assign_to.rb +27 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/operations/create_page.rb +21 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/operations/send_notification.rb +30 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/people_field_selection.rb +17 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/recipient_config.rb +34 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/register_field.rb +17 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/task_config_selection.rb +17 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/time_delay_config.rb +16 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/trigger_interface.rb +26 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/triggers/conditional_logic.rb +17 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/user_selection.rb +16 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow.rb +35 -0
- data/lib/ecoportal/api/graphql/base/preset_view.rb +17 -0
- data/lib/ecoportal/api/graphql/base/preview_page.rb +23 -0
- data/lib/ecoportal/api/graphql/base/register.rb +18 -0
- data/lib/ecoportal/api/graphql/base.rb +11 -0
- data/lib/ecoportal/api/graphql/builder/CLAUDE.md +65 -0
- data/lib/ecoportal/api/graphql/builder/kickstand.rb +73 -0
- data/lib/ecoportal/api/graphql/builder/page.rb +210 -41
- data/lib/ecoportal/api/graphql/builder/register/preset_view.rb +84 -0
- data/lib/ecoportal/api/graphql/builder/register.rb +27 -19
- data/lib/ecoportal/api/graphql/builder/template.rb +80 -0
- data/lib/ecoportal/api/graphql/builder.rb +2 -0
- data/lib/ecoportal/api/graphql/compat/filter_translator.rb +107 -0
- data/lib/ecoportal/api/graphql/compat/page_reference.rb +23 -0
- data/lib/ecoportal/api/graphql/compat/pages.rb +212 -0
- data/lib/ecoportal/api/graphql/compat/registers.rb +84 -0
- data/lib/ecoportal/api/graphql/compat/response.rb +35 -0
- data/lib/ecoportal/api/graphql/compat/search_results.rb +33 -0
- data/lib/ecoportal/api/graphql/compat/stage_collection.rb +70 -0
- data/lib/ecoportal/api/graphql/compat/stage_view.rb +76 -0
- data/lib/ecoportal/api/graphql/compat.rb +17 -0
- data/lib/ecoportal/api/graphql/concerns/data_field_access.rb +71 -0
- data/lib/ecoportal/api/graphql/concerns/deprecation.rb +20 -0
- data/lib/ecoportal/api/graphql/concerns/fragment_definitions.rb +21 -28
- data/lib/ecoportal/api/graphql/concerns/page_compat.rb +51 -0
- data/lib/ecoportal/api/graphql/concerns/snake_camel_access.rb +60 -0
- data/lib/ecoportal/api/graphql/concerns.rb +4 -0
- data/lib/ecoportal/api/graphql/connection/page.rb +11 -0
- data/lib/ecoportal/api/graphql/connection/pages_workflow_command.rb +13 -0
- data/lib/ecoportal/api/graphql/connection/preset_view.rb +11 -0
- data/lib/ecoportal/api/graphql/connection/preview_page.rb +11 -0
- data/lib/ecoportal/api/graphql/connection.rb +4 -0
- data/lib/ecoportal/api/graphql/file_upload/client.rb +181 -0
- data/lib/ecoportal/api/graphql/file_upload.rb +10 -0
- data/lib/ecoportal/api/graphql/fragment/action.rb +1 -1
- data/lib/ecoportal/api/graphql/fragment/action_category.rb +1 -1
- data/lib/ecoportal/api/graphql/fragment/contractor_entity.rb +1 -1
- data/lib/ecoportal/api/graphql/fragment/force.rb +30 -0
- data/lib/ecoportal/api/graphql/fragment/location_draft.rb +2 -2
- data/lib/ecoportal/api/graphql/fragment/location_node.rb +1 -1
- data/lib/ecoportal/api/graphql/fragment/locations_error.rb +1 -1
- data/lib/ecoportal/api/graphql/fragment/page.rb +85 -0
- data/lib/ecoportal/api/graphql/fragment/pages/common_page_union.rb +395 -0
- data/lib/ecoportal/api/graphql/fragment/pages.rb +15 -0
- data/lib/ecoportal/api/graphql/fragment/pages_workflow.rb +172 -0
- data/lib/ecoportal/api/graphql/fragment/pagination.rb +1 -1
- data/lib/ecoportal/api/graphql/fragment.rb +37 -27
- data/lib/ecoportal/api/graphql/input/contractor_entity/update.rb +25 -0
- data/lib/ecoportal/api/graphql/input/delta_input.rb +16 -0
- data/lib/ecoportal/api/graphql/input/page/archive.rb +14 -0
- data/lib/ecoportal/api/graphql/input/page/build_from_template.rb +13 -0
- data/lib/ecoportal/api/graphql/input/page/create_draft.rb +13 -0
- data/lib/ecoportal/api/graphql/input/page/create_from_template.rb +18 -0
- data/lib/ecoportal/api/graphql/input/page/delete_draft.rb +13 -0
- data/lib/ecoportal/api/graphql/input/page/publish_draft.rb +13 -0
- data/lib/ecoportal/api/graphql/input/page/review_task.rb +14 -0
- data/lib/ecoportal/api/graphql/input/page/unarchive.rb +14 -0
- data/lib/ecoportal/api/graphql/input/page/update.rb +140 -0
- data/lib/ecoportal/api/graphql/input/page.rb +26 -0
- data/lib/ecoportal/api/graphql/input/preset_view/create.rb +18 -0
- data/lib/ecoportal/api/graphql/input/preset_view/permission.rb +16 -0
- data/lib/ecoportal/api/graphql/input/preset_view/update.rb +16 -0
- data/lib/ecoportal/api/graphql/input/preset_view.rb +14 -0
- data/lib/ecoportal/api/graphql/input/register/create.rb +18 -0
- data/lib/ecoportal/api/graphql/input/register/update.rb +15 -0
- data/lib/ecoportal/api/graphql/input/register.rb +13 -0
- data/lib/ecoportal/api/graphql/input/search_conf/ai_generator.rb +234 -0
- data/lib/ecoportal/api/graphql/input/search_conf.rb +367 -0
- data/lib/ecoportal/api/graphql/input/variable_binding.rb +20 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_action_tag.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_binding.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_comment_tagging_user_group.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_default_direct_strategy_user.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_default_strategy.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_direct_strategy_user.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_field.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_force.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_gauge_field_stop.rb +19 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_linked_field_config.rb +23 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_linked_helper.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_operation.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_operation_direct_strategy_user.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_operation_strategy.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_recipient_action_type.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_recipient_filter.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_recipient_people_field.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_recipient_task_config.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_recipient_user.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_scheduled_callback.rb +23 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_scheduled_callback_action.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_section.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_select_field_option.rb +19 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_stage.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_stage_section.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_stage_tag.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_strategy.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_task.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_task_assignment_user_group.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_workflow_callback.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/collapse_section.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_binding.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_creator_permissions.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_default_strategy.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_field_configuration.rb +21 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_force.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_gauge_field_stop.rb +19 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_linked_field_config.rb +19 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_linked_helper.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_operation.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_operation_strategy.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_page.rb +28 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_page_creator_permissions.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_reminder.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_required_sign_offs.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_restrict_comment_tagging.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_restrict_task_assignment.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_scheduled_callback.rb +22 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_section_header.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_select_field_option.rb +19 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_stage.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_strategy.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_task_due.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_trigger.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/expand_section.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/contractor_entities.rb +24 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/cross_reference.rb +23 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/date.rb +20 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/gauge.rb +20 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/image_gallery.rb +20 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/location_field.rb +24 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/people.rb +24 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/plain_text.rb +20 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/rich_text.rb +20 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/select.rb +20 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/signature.rb +20 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/table.rb +25 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/move_field.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/move_stage.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_action_tag.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_binding.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_callback.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_comment_tagging_user_group.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_default_direct_strategy_user.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_default_strategy.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_direct_strategy_user.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_field.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_force.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_gauge_field_stop.rb +17 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_linked_field_config.rb +17 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_linked_helper.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_operation.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_operation_direct_strategy_user.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_operation_strategy.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_recipient_action_type.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_recipient_filter.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_recipient_people_field.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_recipient_task_config.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_recipient_user.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_scheduled_callback.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_section.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_select_field_option.rb +17 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_stage.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_stage_section.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_stage_tag.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_strategy.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_task.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_task_assignment_user_group.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_task_due.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_task_priority_level.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/reorder_forces.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/reorder_section.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command.rb +251 -0
- data/lib/ecoportal/api/graphql/input.rb +8 -0
- data/lib/ecoportal/api/graphql/interface/base_page.rb +100 -58
- data/lib/ecoportal/api/graphql/interface/location_structure/nodes.rb +27 -28
- data/lib/ecoportal/api/graphql/logic/base_model.rb +2 -0
- data/lib/ecoportal/api/graphql/logic/base_query.rb +45 -2
- data/lib/ecoportal/api/graphql/logic/input.rb +15 -0
- data/lib/ecoportal/api/graphql/model/ai_summary_version.rb +10 -0
- data/lib/ecoportal/api/graphql/model/organization.rb +65 -55
- data/lib/ecoportal/api/graphql/model/page/basic.rb +14 -0
- data/lib/ecoportal/api/graphql/model/page/phased.rb +82 -20
- data/lib/ecoportal/api/graphql/model/page.rb +1 -0
- data/lib/ecoportal/api/graphql/model/page_union.rb +21 -0
- data/lib/ecoportal/api/graphql/model/pages_workflow.rb +20 -0
- data/lib/ecoportal/api/graphql/model/preset_view.rb +10 -0
- data/lib/ecoportal/api/graphql/model/preview_page.rb +10 -0
- data/lib/ecoportal/api/graphql/model/register.rb +10 -0
- data/lib/ecoportal/api/graphql/model.rb +8 -0
- data/lib/ecoportal/api/graphql/mutation/ai_summary/generate.rb +45 -0
- data/lib/ecoportal/api/graphql/mutation/ai_summary/submit_feedback.rb +40 -0
- data/lib/ecoportal/api/graphql/mutation/ai_summary.rb +13 -0
- data/lib/ecoportal/api/graphql/mutation/kickstand/bulk_update_jobs.rb +43 -0
- data/lib/ecoportal/api/graphql/mutation/kickstand/bulk_update_workflows.rb +43 -0
- data/lib/ecoportal/api/graphql/mutation/kickstand/fail_job.rb +39 -0
- data/lib/ecoportal/api/graphql/mutation/kickstand/fail_workflow.rb +39 -0
- data/lib/ecoportal/api/graphql/mutation/kickstand/start_job.rb +39 -0
- data/lib/ecoportal/api/graphql/mutation/kickstand/start_workflow.rb +39 -0
- data/lib/ecoportal/api/graphql/mutation/kickstand/stop_workflow.rb +39 -0
- data/lib/ecoportal/api/graphql/mutation/kickstand.rb +18 -0
- data/lib/ecoportal/api/graphql/mutation/location_structure/apply_commands.rb +3 -3
- data/lib/ecoportal/api/graphql/mutation/location_structure/draft/add_commands.rb +2 -2
- data/lib/ecoportal/api/graphql/mutation/location_structure/draft/create.rb +2 -2
- data/lib/ecoportal/api/graphql/mutation/location_structure/draft/drop_bad_commands.rb +3 -3
- data/lib/ecoportal/api/graphql/mutation/location_structure/draft/publish.rb +3 -3
- data/lib/ecoportal/api/graphql/mutation/page/approve_review_task.rb +40 -0
- data/lib/ecoportal/api/graphql/mutation/page/archive.rb +40 -0
- data/lib/ecoportal/api/graphql/mutation/page/batch_update_review_task.rb +40 -0
- data/lib/ecoportal/api/graphql/mutation/page/build_from_template.rb +50 -0
- data/lib/ecoportal/api/graphql/mutation/page/create_draft.rb +40 -0
- data/lib/ecoportal/api/graphql/mutation/page/create_from_template.rb +43 -0
- data/lib/ecoportal/api/graphql/mutation/page/delete_draft.rb +40 -0
- data/lib/ecoportal/api/graphql/mutation/page/execute_force_commands.rb +69 -0
- data/lib/ecoportal/api/graphql/mutation/page/execute_workflow_commands.rb +51 -0
- data/lib/ecoportal/api/graphql/mutation/page/publish_draft.rb +40 -0
- data/lib/ecoportal/api/graphql/mutation/page/reject_review_task.rb +40 -0
- data/lib/ecoportal/api/graphql/mutation/page/restart_review_task.rb +40 -0
- data/lib/ecoportal/api/graphql/mutation/page/unarchive.rb +40 -0
- data/lib/ecoportal/api/graphql/mutation/page/undo_review_task.rb +40 -0
- data/lib/ecoportal/api/graphql/mutation/page/update.rb +40 -0
- data/lib/ecoportal/api/graphql/mutation/page/update_variable_bindings.rb +44 -0
- data/lib/ecoportal/api/graphql/mutation/page.rb +28 -0
- data/lib/ecoportal/api/graphql/mutation/preset_view/create.rb +35 -0
- data/lib/ecoportal/api/graphql/mutation/preset_view/destroy.rb +35 -0
- data/lib/ecoportal/api/graphql/mutation/preset_view/permission.rb +37 -0
- data/lib/ecoportal/api/graphql/mutation/preset_view/update.rb +35 -0
- data/lib/ecoportal/api/graphql/mutation/preset_view.rb +15 -0
- data/lib/ecoportal/api/graphql/mutation/register/create.rb +35 -0
- data/lib/ecoportal/api/graphql/mutation/register/destroy.rb +35 -0
- data/lib/ecoportal/api/graphql/mutation/register/update.rb +35 -0
- data/lib/ecoportal/api/graphql/mutation/register.rb +14 -0
- data/lib/ecoportal/api/graphql/mutation/smart_fill/generate.rb +36 -0
- data/lib/ecoportal/api/graphql/mutation/smart_fill/submit_feedback.rb +40 -0
- data/lib/ecoportal/api/graphql/mutation/smart_fill.rb +13 -0
- data/lib/ecoportal/api/graphql/mutation/template/create.rb +39 -0
- data/lib/ecoportal/api/graphql/mutation/template/create_related_page.rb +46 -0
- data/lib/ecoportal/api/graphql/mutation/template/destroy_related_page.rb +43 -0
- data/lib/ecoportal/api/graphql/mutation/template/publish.rb +39 -0
- data/lib/ecoportal/api/graphql/mutation/template/unpublish.rb +39 -0
- data/lib/ecoportal/api/graphql/mutation/template/update.rb +43 -0
- data/lib/ecoportal/api/graphql/mutation/template/update_information.rb +43 -0
- data/lib/ecoportal/api/graphql/mutation/template.rb +18 -0
- data/lib/ecoportal/api/graphql/mutation.rb +8 -0
- data/lib/ecoportal/api/graphql/payload/ai_summary_generate.rb +12 -0
- data/lib/ecoportal/api/graphql/payload/execute_workflow_commands.rb +36 -0
- data/lib/ecoportal/api/graphql/payload/force_commands.rb +31 -0
- data/lib/ecoportal/api/graphql/payload/kickstand/bulk_update_jobs.rb +36 -0
- data/lib/ecoportal/api/graphql/payload/kickstand/bulk_update_workflows.rb +36 -0
- data/lib/ecoportal/api/graphql/payload/kickstand/job.rb +13 -0
- data/lib/ecoportal/api/graphql/payload/kickstand/workflow.rb +13 -0
- data/lib/ecoportal/api/graphql/payload/kickstand.rb +15 -0
- data/lib/ecoportal/api/graphql/payload/location_structure/draft/create.rb +33 -34
- data/lib/ecoportal/api/graphql/payload/ok_payload.rb +21 -0
- data/lib/ecoportal/api/graphql/payload/page/archive.rb +13 -0
- data/lib/ecoportal/api/graphql/payload/page/build_from_template.rb +13 -0
- data/lib/ecoportal/api/graphql/payload/page/create_from_template.rb +13 -0
- data/lib/ecoportal/api/graphql/payload/page/draft.rb +13 -0
- data/lib/ecoportal/api/graphql/payload/page/review_task.rb +13 -0
- data/lib/ecoportal/api/graphql/payload/page/unarchive.rb +13 -0
- data/lib/ecoportal/api/graphql/payload/page/update.rb +13 -0
- data/lib/ecoportal/api/graphql/payload/page/update_variable_bindings.rb +13 -0
- data/lib/ecoportal/api/graphql/payload/page.rb +19 -0
- data/lib/ecoportal/api/graphql/payload/preset_view.rb +11 -0
- data/lib/ecoportal/api/graphql/payload/register.rb +11 -0
- data/lib/ecoportal/api/graphql/payload/template/create.rb +13 -0
- data/lib/ecoportal/api/graphql/payload/template/create_related_page.rb +13 -0
- data/lib/ecoportal/api/graphql/payload/template/destroy_related_page.rb +13 -0
- data/lib/ecoportal/api/graphql/payload/template/publish.rb +13 -0
- data/lib/ecoportal/api/graphql/payload/template/unpublish.rb +13 -0
- data/lib/ecoportal/api/graphql/payload/template/update.rb +13 -0
- data/lib/ecoportal/api/graphql/payload/template/update_information.rb +13 -0
- data/lib/ecoportal/api/graphql/payload/template.rb +18 -0
- data/lib/ecoportal/api/graphql/payload.rb +11 -0
- data/lib/ecoportal/api/graphql/query/action.rb +1 -1
- data/lib/ecoportal/api/graphql/query/action_categories.rb +1 -1
- data/lib/ecoportal/api/graphql/query/actions.rb +2 -2
- data/lib/ecoportal/api/graphql/query/contractor_entities.rb +1 -1
- data/lib/ecoportal/api/graphql/query/file_upload_signature.rb +76 -0
- data/lib/ecoportal/api/graphql/query/location_structure/draft.rb +2 -2
- data/lib/ecoportal/api/graphql/query/location_structure.rb +1 -1
- data/lib/ecoportal/api/graphql/query/location_structures.rb +1 -1
- data/lib/ecoportal/api/graphql/query/page.rb +45 -0
- data/lib/ecoportal/api/graphql/query/page_delta.rb +47 -0
- data/lib/ecoportal/api/graphql/query/page_with_forces.rb +43 -0
- data/lib/ecoportal/api/graphql/query/pages.rb +59 -0
- data/lib/ecoportal/api/graphql/query/pages_workflow_commands.rb +59 -0
- data/lib/ecoportal/api/graphql/query/register_preset_views.rb +78 -0
- data/lib/ecoportal/api/graphql/query/register_preview_pages.rb +83 -0
- data/lib/ecoportal/api/graphql/query/templates.rb +53 -0
- data/lib/ecoportal/api/graphql/query.rb +11 -0
- data/lib/ecoportal/api/graphql.rb +60 -2
- data/lib/ecoportal/api/graphql_version.rb +5 -5
- data/scripts/auto-worker-scheduler.sh +386 -0
- data/tests/contractor_entity_create.rb +19 -19
- data/tests/contractor_entity_udpate.rb +20 -20
- data/tests/dump_page_model.rb +74 -0
- data/tests/loc_structure_get.rb +1 -2
- data/tests/loc_structure_update.rb +51 -51
- data/tests/loc_structures_get.rb +15 -15
- metadata +436 -5
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# Decisions — APIv2 → GraphQL Migration
|
|
2
|
+
|
|
3
|
+
## 2026-06-04 — Bypass `graphql-client` for HTTP dispatch, retain DSL
|
|
4
|
+
|
|
5
|
+
**Context:** `graphql-client` requires fragments to be parsed into Ruby constants, making
|
|
6
|
+
fragment reuse across query helpers impossible for large models like Page.
|
|
7
|
+
|
|
8
|
+
**Options considered:**
|
|
9
|
+
1. Patch `graphql-client` to relax the constant requirement.
|
|
10
|
+
2. Fork `graphql-client` fully and rewrite fragment handling.
|
|
11
|
+
3. Bypass `graphql-client` for HTTP dispatch only; keep `graphlient` DSL for query building.
|
|
12
|
+
|
|
13
|
+
**Decision:** Option 3 — bypass dispatch, retain DSL.
|
|
14
|
+
|
|
15
|
+
**Reason:** Least invasive. The DSL value is in query construction, not request execution.
|
|
16
|
+
A plain HTTP client posting `{ query, operationName, variables }` is sufficient and
|
|
17
|
+
well-understood (matches Insomnia/Postman behaviour). Avoids a full fork maintenance burden.
|
|
18
|
+
|
|
19
|
+
**Consequences:** Need to contribute a PR to `graphlient` fork allowing DSL-only mode
|
|
20
|
+
(returns String without firing request). Fragment strings assembled manually before dispatch.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## 2026-06-04 — Fragment strategy: plain strings assembled at query time
|
|
25
|
+
|
|
26
|
+
**Context:** `graphql-client` parses fragments into anonymous Ruby constants at load time,
|
|
27
|
+
preventing reuse across multiple query helpers.
|
|
28
|
+
|
|
29
|
+
**Options considered:**
|
|
30
|
+
1. Define one mega-fragment constant per query (duplication, unmaintainable for large Page model).
|
|
31
|
+
2. Use `graphql-client` anonymous fragments (current blocker).
|
|
32
|
+
3. Define fragments as plain Ruby strings; append to query string before dispatch.
|
|
33
|
+
|
|
34
|
+
**Decision:** Option 3.
|
|
35
|
+
|
|
36
|
+
**Reason:** Simple, no gem dependency for fragment definition. Aligns with how the GraphQL
|
|
37
|
+
server (graphql-ruby pro, persistent queries) already handles this server-side.
|
|
38
|
+
|
|
39
|
+
**Consequences:** Fragment strings need to be validated once against schema. No dynamic
|
|
40
|
+
introspection of fragment fields from client code (acceptable for now).
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## 2026-06-05 — Fragment spread in query blocks: preserve custom block capability
|
|
45
|
+
|
|
46
|
+
**Context:** The `___ConstantName` convention (graphql-client) is used inside both the gem's
|
|
47
|
+
own `default_block` procs and any caller-supplied blocks (from end-scripts, `eco-helpers`,
|
|
48
|
+
integration repos). Dropping graphql-client breaks this convention everywhere it is used.
|
|
49
|
+
|
|
50
|
+
**Options considered:**
|
|
51
|
+
1. Remove custom block capability entirely; provide a utility/DSL for custom queries instead.
|
|
52
|
+
2. Preserve custom block capability; change the fragment-spread syntax and document the new convention.
|
|
53
|
+
3. Preserve for now; accept a major version bump + clean break if the migration causes a
|
|
54
|
+
development loop.
|
|
55
|
+
|
|
56
|
+
**Decision:** Option 2 as the starting point, with Option 3 as an explicit fallback.
|
|
57
|
+
|
|
58
|
+
**Reason:** Custom blocks are rare in practice and were introduced before the author was
|
|
59
|
+
fully fluent with GraphQL. However, removing them without a replacement utility would break
|
|
60
|
+
the handful of integration repos that do use them. Preserving the capability with a new
|
|
61
|
+
syntax is lower friction. If the `___Const` → new-syntax migration causes repeated
|
|
62
|
+
back-and-forth complexity, a major version bump with a clean break (plus a utility/DSL
|
|
63
|
+
replacement) is explicitly on the table.
|
|
64
|
+
|
|
65
|
+
**Consequences:** The fragment-spread syntax inside all blocks (default and custom) changes.
|
|
66
|
+
The new convention must be documented clearly and the change tagged as a major version bump.
|
|
67
|
+
Custom block authors need to migrate; the number of affected sites is small.
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## 2026-06-05 — `as_input` conversion ownership: input class, not model
|
|
72
|
+
|
|
73
|
+
**Context:** When building a GraphQL mutation input from a model diff, something must
|
|
74
|
+
own the logic of converting `as_update` output into the specific shape required by a
|
|
75
|
+
given mutation input type. Two natural homes: the model (via `as_update(target_class:)`)
|
|
76
|
+
or the input class (via `InputClass.from_model(model)`).
|
|
77
|
+
|
|
78
|
+
**Options considered:**
|
|
79
|
+
1. Model owns it: `model.as_update(target_class: SomeInputClass)` — model knows about
|
|
80
|
+
its input types.
|
|
81
|
+
2. Input class owns it: `SomeInputClass.from_model(model)` — input class knows how to
|
|
82
|
+
interpret a model diff into its own shape.
|
|
83
|
+
|
|
84
|
+
**Decision:** Option 2 — input class owns the conversion.
|
|
85
|
+
|
|
86
|
+
**Reason:** The model should not need to know which mutation it is feeding. The cascade
|
|
87
|
+
(`as_update` → nested `as_update`) still runs on the model side; the input class wraps
|
|
88
|
+
it at the top and applies any structural reshaping needed for that specific mutation.
|
|
89
|
+
Cleaner separation of concerns; easier to add new input types without touching model code.
|
|
90
|
+
|
|
91
|
+
**Consequences:** Each mutation input class needs a `from_model(model)` (or equivalent)
|
|
92
|
+
class method. The `as_input` instance method on the model becomes a convenience delegator
|
|
93
|
+
to the resolved input class.
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## 2026-06-04 — `as_update` diff: changed props only, no patch operations
|
|
98
|
+
|
|
99
|
+
**Context:** APIv2 `as_update` builds a JSON Patch diff across nested models. GraphQL
|
|
100
|
+
mutations target one model at a time and only need the final changed-property values,
|
|
101
|
+
not patch operations. `patch_ver` is only required at the top level of a Page record.
|
|
102
|
+
|
|
103
|
+
**Options considered:**
|
|
104
|
+
1. Reuse APIv2 `as_update` as-is (produces wrong format for GraphQL).
|
|
105
|
+
2. Add a `graphql:` mode flag to APIv2 `as_update`.
|
|
106
|
+
3. Implement a separate `as_update` adapted for GraphQL in `ecoportal-api-graphql`.
|
|
107
|
+
|
|
108
|
+
**Decision:** Option 3.
|
|
109
|
+
|
|
110
|
+
**Reason:** Keeps GraphQL concerns in the GraphQL gem. Avoids coupling APIv2 model
|
|
111
|
+
definitions to GraphQL-specific behaviour. Per-model override support (`as_update(target_class:)`)
|
|
112
|
+
keeps it flexible for custom mutation input types.
|
|
113
|
+
|
|
114
|
+
**Consequences:** Some duplication of diff logic vs APIv2, but the logic is simpler (no
|
|
115
|
+
patch ops). Must maintain in parallel with APIv2 `as_update` for now.
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## 2026-06-05 — Fragment spread syntax in DSL blocks: `spread :Name`
|
|
120
|
+
|
|
121
|
+
**Context:** The `___Const` convention (graphql-client) is no longer viable after removing
|
|
122
|
+
`graphql-client` from fragment parsing. A new syntax is needed for fragment spreads in
|
|
123
|
+
both default and custom query/mutation blocks.
|
|
124
|
+
|
|
125
|
+
**Options considered:**
|
|
126
|
+
A. Add a `spread(name)` helper to `Graphlient::Query` (in the fork). Usage: `spread :Action`
|
|
127
|
+
emits `...Action` in the query string. DSL blocks remain fully functional.
|
|
128
|
+
B. Drop the DSL block for selection bodies that contain fragment spreads; use heredoc strings
|
|
129
|
+
for those sections. More invasive; harder for custom blocks.
|
|
130
|
+
|
|
131
|
+
**Decision:** Option A — add `Graphlient::Query#spread(fragment_name)`.
|
|
132
|
+
|
|
133
|
+
**Reason:** Preserves the DSL convention. `spread :FragmentName` is readable and
|
|
134
|
+
aligns with the existing `:Symbol` argument style throughout the query DSL. Custom
|
|
135
|
+
blocks (from end-scripts, eco-helpers) only need the method name replaced — a mechanical
|
|
136
|
+
change. Requires one small graphlient fork addition (already committed on
|
|
137
|
+
`feature/dsl-only-mode` in the graphlient repo).
|
|
138
|
+
|
|
139
|
+
**Consequences:**
|
|
140
|
+
- All `___Ecoportal__API__GraphQL__Fragment__X` references in query/mutation blocks
|
|
141
|
+
replaced with `spread :X` (items 3.4).
|
|
142
|
+
- Fragment heredoc strings must be named: `fragment X on Type { ... }` (item 3.5).
|
|
143
|
+
- Fragment name = the Ruby symbol key (e.g., `:Action` → `...Action` → `fragment Action on ...`).
|
|
144
|
+
- End-script and eco-helpers authors using custom blocks must migrate `___Const` → `spread :Name`.
|
|
145
|
+
- Major version bump required when shipping (existing API decision from 2026-06-05).
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## 2026-06-05 — HTTP dispatch client ownership: stored on Common::GraphQL::Client
|
|
150
|
+
|
|
151
|
+
**Context:** BaseQuery needs both a DSL client (`to_query_string`) and an HTTP client
|
|
152
|
+
(`execute`). Two options: pass both separately, or carry both on one object.
|
|
153
|
+
|
|
154
|
+
**Options considered:**
|
|
155
|
+
1. Pass `http_client:` as a separate argument to BaseQuery (changes constructor signature
|
|
156
|
+
and all callsites).
|
|
157
|
+
2. Store `http_client` as an attribute on `Common::GraphQL::Client` (single entry point,
|
|
158
|
+
no callsite changes needed).
|
|
159
|
+
|
|
160
|
+
**Decision:** Option 2 — add `attr_accessor :http_client` to `Common::GraphQL::Client`.
|
|
161
|
+
Set from `Ecoportal::API::GraphQL#initialize` after constructing the graphql client.
|
|
162
|
+
|
|
163
|
+
**Reason:** Minimal callsite changes. BaseQuery already receives `client`; adding
|
|
164
|
+
`client.http_client` requires zero changes to how query/mutation objects are instantiated.
|
|
165
|
+
|
|
166
|
+
**Consequences:** `Common::GraphQL::Client` holds a reference to `Common::GraphQL::HttpClient`.
|
|
167
|
+
If the auth context changes, both clients need updating. Acceptable for now; can be
|
|
168
|
+
refactored to a unified facade later.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Project: APIv2 → GraphQL Migration
|
|
2
|
+
|
|
3
|
+
**Created:** 2026-06-04
|
|
4
|
+
**Status:** active
|
|
5
|
+
**Branch:** ai_dev_process
|
|
6
|
+
**Target branch:** main
|
|
7
|
+
|
|
8
|
+
## Goal
|
|
9
|
+
|
|
10
|
+
Migrate ecoPortal integrations off the deprecated REST `/api/v2/pages` endpoint onto the
|
|
11
|
+
GraphQL endpoint, by completing the `ecoportal-api-graphql` gem so it can serve as the
|
|
12
|
+
primary client for page record queries and mutations — without requiring full rewrites of
|
|
13
|
+
existing end scripts.
|
|
14
|
+
|
|
15
|
+
## Motivation
|
|
16
|
+
|
|
17
|
+
The `/api/v2/pages` endpoint has been deprecated and will be removed. All page-record
|
|
18
|
+
integrations must move to GraphQL. The `ecoportal-api-graphql` gem exists for this purpose
|
|
19
|
+
but has gaps: fragment reuse is blocked by `graphql-client` limitations, the HTTP client
|
|
20
|
+
layer is incomplete, and the mutation input / diff model hasn't been fully designed.
|
|
21
|
+
|
|
22
|
+
## Scope
|
|
23
|
+
|
|
24
|
+
**In scope:**
|
|
25
|
+
- Implement a standalone HTTP client in `ecoportal-api-graphql` that bypasses `graphql-client`
|
|
26
|
+
for request dispatch, while retaining the `graphlient` DSL for query/mutation building.
|
|
27
|
+
- Solve the fragment reuse problem: define page model fragments as plain strings that are
|
|
28
|
+
assembled/appended at query time, not parsed into Ruby constants.
|
|
29
|
+
- Design and implement the mutation diff model: adapted `as_update` that produces the final
|
|
30
|
+
changed-properties body (no patch operations, no nested diffs), with per-model override support.
|
|
31
|
+
- Provide a DSL compatibility layer in `eco-helpers` so existing end scripts can swap to
|
|
32
|
+
GraphQL with minimal changes.
|
|
33
|
+
- Contribute a PR to the `graphlient` fork to allow DSL usage without triggering a request
|
|
34
|
+
(returns query string only).
|
|
35
|
+
|
|
36
|
+
**Out of scope:**
|
|
37
|
+
- Migrating the actual end scripts themselves (that's downstream work).
|
|
38
|
+
- Dynamic response model generation (desirable future state, not this project).
|
|
39
|
+
- Full replacement of `graphql-client` — only bypass its request/fragment constraints.
|
|
40
|
+
|
|
41
|
+
## Dependencies
|
|
42
|
+
|
|
43
|
+
| Gem | Role | Location |
|
|
44
|
+
|-----|------|----------|
|
|
45
|
+
| `ecoportal-api` | HTTP client base | `c:\ruby_scripts\git\ecoportal-api\` |
|
|
46
|
+
| `ecoportal-api-v2` | Model definitions (`DoubleModel`, `as_update`) | `c:\ruby_scripts\git\ecoportal-api-v2\` |
|
|
47
|
+
| `graphlient` | GraphQL DSL (fork) | https://github.com/rellampec/graphlient |
|
|
48
|
+
| `graphql-client` | GraphQL base (fork, to be bypassed for requests) | https://github.com/rellampec/graphql-client |
|
|
49
|
+
| `eco-helpers` | **Downstream** consumer (uses this gem); DSL compat layer target | `c:\ruby_scripts\git\eco-helpers\` |
|
|
50
|
+
|
|
51
|
+
Open upstream issue: https://github.com/ashkan18/graphlient/issues/114
|
|
52
|
+
|
|
53
|
+
## Success Criteria
|
|
54
|
+
|
|
55
|
+
- Page queries and mutations can be executed via `ecoportal-api-graphql` without
|
|
56
|
+
`graphql-client` handling the HTTP dispatch.
|
|
57
|
+
- Fragment strings for the page model can be defined once and reused across queries.
|
|
58
|
+
- `as_update` produces correct GraphQL mutation input bodies (changed props only, no patch ops).
|
|
59
|
+
- Existing `eco-helpers`-based scripts require only minor adjustments to target GraphQL.
|
|
60
|
+
- CI green, rubocop clean.
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
# TODOs — APIv2 → GraphQL Migration
|
|
2
|
+
|
|
3
|
+
> Granulated during session 2026-06-04. Items are numbered for reference in discussion.
|
|
4
|
+
> Natural implementation order: 1.1 → 2.1 → 2.2 → 3.1 → 3.2 → 3.3 decision → 3.4+3.5 → 2.3 → 4.x → 5.x → 6.x
|
|
5
|
+
> Items 1.2, 6.1, and 6.4 are continuous throughout.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Group 1 — `graphlient` fork: DSL-only mode
|
|
10
|
+
|
|
11
|
+
- [x] **1.1** Add `to_query_string(**kargs, &block)` to `Graphlient::Client` (fork): builds the full
|
|
12
|
+
query document from the DSL block and returns a `String` — without touching Faraday/HTTP.
|
|
13
|
+
*Done 2026-06-05 — `graphlient/lib/graphlient/client.rb`, branch `feature/dsl-only-mode`*
|
|
14
|
+
|
|
15
|
+
- [x] **1.2** Open a PR from the fork to upstream `ashkan18/graphlient` for the DSL-only mode change
|
|
16
|
+
(ref issue #114). *Done — PR #115 "Add DSL-only mode: to_query_string + spread" MERGED into
|
|
17
|
+
`ashkan18/graphlient` master (verified via `git ls-remote upstream` 2026-06-13). NOT yet released,
|
|
18
|
+
so still open to coordinated changes; we are the authors. See memory `project-fork-revival-strategy`.*
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Group 2 — HTTP dispatch layer in `HttpClient`
|
|
23
|
+
|
|
24
|
+
- [x] **2.1** Add `execute(query_string, variables: {}, operation_name: nil)` to `HttpClient`:
|
|
25
|
+
POSTs `{ query:, variables:, operationName: }` as JSON to `/api/:org_id/graphql`, returns
|
|
26
|
+
the parsed response hash.
|
|
27
|
+
*Done 2026-06-05 — `lib/ecoportal/api/common/graphql/http_client.rb`*
|
|
28
|
+
|
|
29
|
+
- [x] **2.2** Add response error handling in `execute`: surface GraphQL `errors` from the response
|
|
30
|
+
body as typed exceptions consistent with the existing `Ecoportal::API::GraphQL::Error` hierarchy.
|
|
31
|
+
*Done 2026-06-05 — raises `Common::GraphQL::ResponseError` for GraphQL errors, `Client::Error::UnexpectedServerError` for HTTP errors*
|
|
32
|
+
|
|
33
|
+
- [x] **2.3** Wire dispatch end-to-end in `BaseQuery#graphql_query`:
|
|
34
|
+
(a) `client.to_query_string(&block)` builds query string,
|
|
35
|
+
(b) `assemble_fragments` scans for `...Name` and appends named fragment strings,
|
|
36
|
+
(c) `client.http_client.execute(full_query, variables: query_params)` dispatches,
|
|
37
|
+
(d) raw JSON hash returned → `wrap_response` navigates `data.*path`.
|
|
38
|
+
Decision: `http_client` stored as attr on `Common::GraphQL::Client` (see DECISIONS.md).
|
|
39
|
+
*Done 2026-06-05 — base_query.rb, common/graphql/client.rb, graphql.rb*
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Group 3 — Fragment plain-string strategy
|
|
44
|
+
|
|
45
|
+
- [x] **3.1** Strip `client.parse` and Ruby constant assignment from `FragmentDefinitions#define`.
|
|
46
|
+
Fragment strings are already stored via `fragment :Sym, heredoc` — keep the storage, drop the parse step.
|
|
47
|
+
*Done 2026-06-05 — `lib/ecoportal/api/graphql/concerns/fragment_definitions.rb`*
|
|
48
|
+
|
|
49
|
+
- [x] **3.2** Add `Fragment.assemble(*syms)`: returns concatenated fragment definition strings for the
|
|
50
|
+
given symbols, ready to append to a query string before dispatch.
|
|
51
|
+
*Done 2026-06-05 — `ClassMethods#assemble` in `fragment_definitions.rb`*
|
|
52
|
+
|
|
53
|
+
- [x] **3.3** **Decision item** — resolved: Option A — `spread :Name` DSL helper in `Graphlient::Query`.
|
|
54
|
+
*Done 2026-06-05 — documented in `DECISIONS.md`; `spread` committed to graphlient `feature/dsl-only-mode`*
|
|
55
|
+
|
|
56
|
+
- [x] **3.4** Update all existing query `default_block` procs to use `spread :Name`:
|
|
57
|
+
Action, Actions, ActionCategories, ContractorEntities, LocationStructure, LocationDraft, etc.
|
|
58
|
+
*Done 2026-06-05 — 12 query/mutation files updated*
|
|
59
|
+
|
|
60
|
+
- [x] **3.5** Update all `Fragment::*` class definitions to use named fragment syntax.
|
|
61
|
+
*Done 2026-06-05 — 7 fragment files updated (e.g., `fragment Action on Action { ... }`)*
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Group 4 — `as_update` / `as_input` pipeline
|
|
66
|
+
|
|
67
|
+
- [x] **4.1** Verify `DiffService` output for a realistic Page model: confirm no patch-op keys,
|
|
68
|
+
only changed prop values. Write/update the code-spec doc for this area.
|
|
69
|
+
*Done 2026-06-05 — `.ai-assistance/code/diff_as_input.md` written.*
|
|
70
|
+
*Finding: DiffService DOES produce patch-op keys (`api_operation`, `change_data`) at the top
|
|
71
|
+
level — this is wrong for GraphQL. Fix is part of 4.2/4.3 work. `patch_ver` is tracked on
|
|
72
|
+
`BasePage` via `passthrough :patchVer` but not yet injected in mutation input.*
|
|
73
|
+
|
|
74
|
+
- [x] **4.2** Inject `patch_ver` at the top level in `AsInput#as_input`: read from the subject
|
|
75
|
+
model and include in the mutation input body. Currently not handled.
|
|
76
|
+
*Done 2026-06-05 — also fixed `DiffService#classic_diff` to return flat changed-prop hash
|
|
77
|
+
(no `api_operation`/`change_data` wrapper). `as_input` now returns nil when no changes.*
|
|
78
|
+
|
|
79
|
+
- [x] **4.3** Implement `as_input(target_class:)` support: map diff output through a specified
|
|
80
|
+
`Input` subclass for key renaming / reshaping per mutation type (the "per-model override" pattern
|
|
81
|
+
from `DECISIONS.md`).
|
|
82
|
+
*Done 2026-06-05 — Logic::Input.from_model + AsInput#as_input(target_class:) +
|
|
83
|
+
ContractorEntity::Update override for IdDiff reshaping.*
|
|
84
|
+
|
|
85
|
+
- [x] **4.4** RSpec specs for `DiffService` and `AsInput` covering: no-change → nil/empty,
|
|
86
|
+
single-prop change, nested model change, `root?` objects excluded, `patch_ver` present at top level.
|
|
87
|
+
*Done 2026-06-06 — 33 examples, 0 failures. Fixed: dig_path? Hash#key? check,
|
|
88
|
+
ContractorEntity::Update.from_model nil-diff + doc[] comparison, as_input_spec
|
|
89
|
+
Base::ContractorEntity + array field mutation via doc[].*
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Group 5 — `eco-helpers` DSL compat layer
|
|
94
|
+
|
|
95
|
+
> Blocked on Groups 1–3 being functional.
|
|
96
|
+
|
|
97
|
+
- [ ] **5.1** Audit the existing end-script API surface in `eco-helpers`: list the exact methods
|
|
98
|
+
scripts currently call against `ecoportal-api-v2` Page objects (fetch, update, create, etc.),
|
|
99
|
+
so the compat interface can be defined precisely.
|
|
100
|
+
|
|
101
|
+
- [ ] **5.2** Design and implement a compat module in `eco-helpers` that proxies those methods
|
|
102
|
+
to the new GraphQL gem.
|
|
103
|
+
|
|
104
|
+
- [ ] **5.3** Write a short migration guide for end-script authors.
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## Group 6 — Validation & cleanup
|
|
109
|
+
|
|
110
|
+
- [x] **6.0** Build a rubocop skill before writing any code: runs `rubocop --format json`
|
|
111
|
+
filtered to in-scope files, surfaces only actionable offences. Wire `rake spec` into
|
|
112
|
+
the same skill. `rubocop:disable` comments are handled by rubocop itself — the skill
|
|
113
|
+
does not need to second-guess them.
|
|
114
|
+
*Done 2026-06-05 — `.ai-assistance/skills/rubocop/SKILL.md`*
|
|
115
|
+
|
|
116
|
+
- [ ] **6.1** Rubocop clean on all new/modified files — run continuously as work progresses,
|
|
117
|
+
not deferred to end.
|
|
118
|
+
|
|
119
|
+
- [ ] **6.2** RSpec coverage for: `HttpClient#execute`, `Fragment.assemble`, and end-to-end
|
|
120
|
+
`BaseQuery#query` with stubs.
|
|
121
|
+
|
|
122
|
+
- [x] **6.3** Manual integration test against `live.ecoportal.com` once dispatch is wired (after 2.3).
|
|
123
|
+
*Done 2026-06-05 — fetching reporting structure + Excel generation verified working.*
|
|
124
|
+
*Fixed during test: `ENDPOINT_PATH` constant in `api_url`, `request ||= HTTP` guard in `base_request`.*
|
|
125
|
+
|
|
126
|
+
- [ ] **6.4** Update `DECISIONS.md` for any choices made during implementation (especially 3.3).
|
|
127
|
+
|
|
128
|
+
- [ ] **6.5** Cycle-end Gemini review (see `project-cycle` skill).
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## Group 7 — Fork packaging & portable test harness
|
|
133
|
+
|
|
134
|
+
> Added 2026-06-27. Both items unblock day-to-day use of the revived forks and ongoing
|
|
135
|
+
> backwards-compat validation ahead of the APIv2-cutover deadline (1 Jul 2026).
|
|
136
|
+
> See memory `project-fork-revival-strategy`, `session-handoff-graphql-client-revival`,
|
|
137
|
+
> `project-parity-test-plan`.
|
|
138
|
+
|
|
139
|
+
- [x] **7.1** **Merged `graphql-client` revival branch + point the Gemfile at it.**
|
|
140
|
+
*Done 2026-06-27.* Built `integration/revival` on the fork (`rellampec/graphql-client`),
|
|
141
|
+
off `master`, cherry-picking the unique content of all four PRs in clean order (#79 base →
|
|
142
|
+
#80 docs → #81 char-tests → #82 parse fix) + a single `ci: pin i18n` commit (the four
|
|
143
|
+
branches each carried an identical copy). Applying #79 before #80 sidestepped the 1-line
|
|
144
|
+
CHANGELOG conflict. **Pushed; green:** 176 runs, 0 failures/errors, 4 skips; rubocop clean
|
|
145
|
+
(61 files). Wired into this gem via the **Gemfile** (not the gemspec — gemspecs can't carry
|
|
146
|
+
git sources; graphlient is a public gem we can't fork-point, so graphql-client is overridden
|
|
147
|
+
in the highest Gemfile we control). Commit `8827b2f`. **Reversible** — remove once the parse
|
|
148
|
+
fix ships upstream. `UPSTREAM.md` refreshed.
|
|
149
|
+
- ⏳ **Remaining (dev shell):** `bundle install` couldn't complete from the agent sandbox
|
|
150
|
+
(rubygems.org TLS interception — the git source itself fetched fine). Run `bundle install`
|
|
151
|
+
in your own shell to regenerate `Gemfile.lock` and confirm resolution, then a quick
|
|
152
|
+
`bundle exec rspec`.
|
|
153
|
+
- Upstream PRs stay OPEN — this branch is a convenience, not a substitute for merging.
|
|
154
|
+
- Mirror this for `graphlient` #116 only if needed (already fork-pinned separately).
|
|
155
|
+
|
|
156
|
+
- [x] **7.2** **Portable `mini/automated-tests/` case folder (training repo).**
|
|
157
|
+
*Done 2026-06-27 (training repo, uncommitted pending dev).* Built a self-contained suite at
|
|
158
|
+
`mini/automated-tests/`:
|
|
159
|
+
- **Harness** (`lib/`): `asserter.rb` (pass/fail/skip recorder + green/red summary),
|
|
160
|
+
`test.rb` (base class + auto-registry via `inherited`), `fixtures.rb` (loads `fixtures.json`).
|
|
161
|
+
- **Runner** `automated_tests_case.rb` → CLI `-automated-tests` (one PASS/FAIL summary;
|
|
162
|
+
`-list`, `-only <Test>`, `-page-id`, `-fixtures` flags). Auto-loaded by one added line in
|
|
163
|
+
`mini/config/session.rb`.
|
|
164
|
+
- **Seed tests** (`tests/`): `org_read_test.rb` (auth smoke, no fixtures, env-agnostic) +
|
|
165
|
+
`field_dispatch_test.rb` (assertion-based evolution of `gql_read_probe_case.rb` — v2 `===`
|
|
166
|
+
dispatch on real fields).
|
|
167
|
+
- **(a) Portable** — org-specifics live only in `fixtures.json` (org_id pinned by `-mini`,
|
|
168
|
+
never embedded); `fixtures.example.json` + a documented 3-step port flow (copy folder →
|
|
169
|
+
edit fixtures → add one session.rb line). Missing fixture ⇒ test SKIPS, never fails.
|
|
170
|
+
- **(b) Reusable** — run against any gem branch (`pages`, released, fork-pinned per 7.1).
|
|
171
|
+
- **Verified offline**: harness wiring (registry/asserter/fixtures/runner) proven green via a
|
|
172
|
+
throwaway mock-graphql driver. **Live run is the dev's** (sandbox TLS-blocked to
|
|
173
|
+
`live.ecoportal.com`): `ruby main.rb -mini -automated-tests -page-id <all-21-fields ID>`.
|
|
174
|
+
Cross-ref `project-parity-test-plan`. Folder/convention doc: `mini/automated-tests/CLAUDE.md`.
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## Group 8 — Cutover parity test coverage (live harness + gem specs)
|
|
179
|
+
|
|
180
|
+
> Added 2026-06-28 after the page READ path went green live (8 gem bugs fixed; see
|
|
181
|
+
> worklog 2026-06-28). READ + create-blank are validated; the WRITE/value/submit path
|
|
182
|
+
> and the actual use cases are the remaining cutover risk. Live tests go in
|
|
183
|
+
> `training/mini/automated-tests/tests/`; gem specs under `spec/`.
|
|
184
|
+
> Memory: [[project-apiv2-cutover-usecases]], [[project-parity-test-plan]].
|
|
185
|
+
|
|
186
|
+
- [x] **8.1** **Field value round-trip test** (`compat_v2/fields/values`) — HIGHEST VALUE,
|
|
187
|
+
entirely unexercised. create → set value → `updatePage` → re-read → assert persisted, per
|
|
188
|
+
type: PlainText/Number `value=`, Select `.select`/`.values`, People append, CrossReference
|
|
189
|
+
`.add`/`.clear`/`.reference_ids`. Several of these compat methods are flagged **missing** in
|
|
190
|
+
`project-apiv2-cutover-usecases` — this proves/exposes each and exercises the update path
|
|
191
|
+
(first time). Write-gated, on the seeded page.
|
|
192
|
+
*Done & LIVE-GREEN 2026-06-29 — PlainText/Number/Select/People (`people_ids`)/CrossReference
|
|
193
|
+
(`page_ids`/`reference_ids`) all round-trip. The P2 coded-but-untested array writes (People
|
|
194
|
+
`<<`, CrossRef `add`/`clear`) are now validated live; full mini suite 35/35.*
|
|
195
|
+
- [x] **8.2** **`submit!` / stage completion test** — wires to `updatePage` task input
|
|
196
|
+
(see [[page-stage-submission]]); the cutover scripts call it.
|
|
197
|
+
*Done & LIVE-GREEN 2026-06-29. Root cause of the old stuck-stage failure: the stage has a
|
|
198
|
+
review-task config, so `completePageTask` ALONE enters "reviewing" and never advances. Fix =
|
|
199
|
+
`updatePage(submit: true, task: { completePageTask: { signOff: true } })` (inline sign-off
|
|
200
|
+
auto-approves the review). Gem gained
|
|
201
|
+
`Input::Page::Update.from_model(complete_page_task: { sign_off:, forced_complete:, notes: })`.
|
|
202
|
+
New test `compat_v2/page/submit_signoff_on_create` passes; old `stage_submit` flipped to the
|
|
203
|
+
confirmed call.*
|
|
204
|
+
- [ ] **8.3** **Search test** — `registers.search` with `text_filter`/`options_filter`,
|
|
205
|
+
`get_by_name(name, type:)`, cans preview-dedup (`page_result.membranes` — search preview
|
|
206
|
+
exposes no field values).
|
|
207
|
+
*Partial 2026-06-29: FilterTranslator now translates `text_filter`→`match_filter` and
|
|
208
|
+
`options_filter`→`one_of`/`none_of` (commit 7725f96), and `get_by_name(type:)` landed
|
|
209
|
+
(2026-06-28). REMAINING = LIVE-validate the translated text/options filters against a real
|
|
210
|
+
`registers.search`, and the membranes dedup rework.*
|
|
211
|
+
- [ ] **8.4** **BasicPage read test** — surfaces the known gap: `CommonPageUnion` has no
|
|
212
|
+
`... on BasicPage { sections }`, so basic pages get `corePageData` only.
|
|
213
|
+
*IN PROGRESS 2026-06-29 on branch `cutover/basicpage-sections`.*
|
|
214
|
+
- [ ] **8.5** **Run the 3 prod use cases** (farmers / jamestrong / act-gov) against `mini` —
|
|
215
|
+
the ultimate parity, ideally A/B vs APIv2 per [[project-parity-test-plan]].
|
|
216
|
+
*Gap audit done + refreshed: `notes/cutover-usecase-gap-audit.md` (Update — 2026-06-29).*
|
|
217
|
+
Blockers BEFORE they can run, re-prioritized 2026-06-29:
|
|
218
|
+
**P0** — release/pin `pages` (HARD PREREQUISITE); farmers must include OozeRedirect (hits dead
|
|
219
|
+
v2 server today). ✅ **Phased write-path identity RESOLVED** (`stage.components` writes persist
|
|
220
|
+
via `updatePage`; `compat_v2/page/stage_write`). **P1** — ✅ `get_by_name(type:)` done;
|
|
221
|
+
✅ `text_filter`+`options_filter` translated (now a LIVE-validation item, 8.3); cans `membranes`
|
|
222
|
+
dedup rework; eco-helpers `submit!` to pass `stageId` + map `force:`→`forced_complete:` (gem
|
|
223
|
+
supports it, draft in progress).
|
|
224
|
+
- [ ] **8.6** **Gem RSpec regression specs** — the page-read path had ZERO coverage (8 bugs
|
|
225
|
+
lurked). Lock in: fragment-name assembly, DateTime sub-selection, `PageUnion` class dispatch,
|
|
226
|
+
`base_path` navigation, phased flatten/dedup, create `dataFields`. Use the `spec-generation`
|
|
227
|
+
skill.
|
|
228
|
+
*IN PROGRESS 2026-06-29 on branch `cutover/regression-specs-8-6`.*
|
|
229
|
+
- [ ] **8.7** **Write/collection-level compat review** — single-element mutations forward via
|
|
230
|
+
shared doc refs; collection ops (add/remove/reorder fields, multi-section identity) need
|
|
231
|
+
review (the piece deferred from the 2026-06-28 phased flatten work). *Still outstanding 2026-06-29.*
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
## Group 9 — Template & field-structure edits (tests + the CSV/diff deliverables)
|
|
236
|
+
|
|
237
|
+
> Added 2026-06-28 (dev). Tests for STRUCTURE edits (not just value writes), plus two
|
|
238
|
+
> deadline-bearing deliverables. Behavioral precedent = the old one-off scripts under
|
|
239
|
+
> `C:\ruby_scripts\implementation\orgs\*/config/ooze_cases` (multi-org-idle, multi_org_api):
|
|
240
|
+
> `OozeSamples::RegisterUpdateCase` helpers — `with_target_stage`/`with_sections`/
|
|
241
|
+
> `with_target_field`/`add_field(…, after:)`/`add_option`/`delete!`/`add_section`
|
|
242
|
+
> (`components.add`/`add_component` ~120×, `add_section` ~23×). Backwards-compat with those
|
|
243
|
+
> old scripts NOT required (nice-to-have). Memory: [[project-template-csv-pipeline]],
|
|
244
|
+
> [[project-template-diff-deploy]], [[project-template-update-architecture]].
|
|
245
|
+
|
|
246
|
+
- [ ] **9.1** **Page field-structure tests** — add / move (reorder) / delete a field on a
|
|
247
|
+
page via the GraphQL path; re-read and assert. Mirrors the most common past ops. Likely
|
|
248
|
+
exposes gem gaps (field add/delete + reposition via `updatePage` / WorkflowCommandInput).
|
|
249
|
+
- [ ] **9.2** **Template edit tests** — create + update a template (add/edit/delete section
|
|
250
|
+
& field, set labels/options) via `Builder::Template#create/#update(commands:)`. Most
|
|
251
|
+
WorkflowCommandInput command types are unwrapped — this maps the gap.
|
|
252
|
+
- [ ] **9.3** **CSV → templates pipeline** *(DEADLINE — see [[project-template-csv-pipeline]])*
|
|
253
|
+
— standard solution (eco-helpers?) to create/maintain ~300 templates from an input CSV
|
|
254
|
+
(sections/fields/labels columns). **Format agreed with customer ~mid-Jul; deliver Sept 2026.**
|
|
255
|
+
Identity: field id ← field internal **description**; section id ← a **hidden+deindex
|
|
256
|
+
PlainText marker field** (section external id) as the first field of each section. Needs
|
|
257
|
+
9.1/9.2 commands + a CSV→WorkflowCommandInput mapper.
|
|
258
|
+
*Design drafted: `notes/csv-template-pipeline-design.md`.* **First build step (also unblocks
|
|
259
|
+
the 9.2 "maintain" path): add `description` + `hideView` to the dataField read fragment
|
|
260
|
+
(`fragment/pages/common_page_union.rb` `dataFieldInterface`) + `passthrough` on
|
|
261
|
+
`Base::Page::DataField` — the identity scheme cannot pair fields/sections without reading
|
|
262
|
+
them back. Then a template-structure read entry-point (`Builder::Template` has no read).**
|
|
263
|
+
- [ ] **9.4** **UAT→PROD diff-deploy** *(future — see [[project-template-diff-deploy]])* — a
|
|
264
|
+
deploy function applying a **UAT changelog** (not a raw snapshot diff) to PROD, preserving
|
|
265
|
+
PROD-only additions. Capturing UAT edits as the WorkflowCommandInput stream → replay on
|
|
266
|
+
PROD sidesteps the diff→command compiler. Page/template diff = nice-to-have for monitoring /
|
|
267
|
+
draft-from-diff.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Upstream Dependencies — APIv2 → GraphQL Migration
|
|
2
|
+
|
|
3
|
+
## graphlient (fork)
|
|
4
|
+
|
|
5
|
+
**Remote:** https://github.com/rellampec/graphlient (fork of https://github.com/ashkan18/graphlient)
|
|
6
|
+
**Required change:** DSL-only mode — allow a `graphlient` block to return the query String
|
|
7
|
+
without triggering HTTP dispatch. See open issue: https://github.com/ashkan18/graphlient/issues/114
|
|
8
|
+
|
|
9
|
+
**Approach:** Fork change + upstream PR contribution.
|
|
10
|
+
**Status:** Pending — PR not yet opened.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## graphql-client (fork)
|
|
15
|
+
|
|
16
|
+
**Remote:** https://github.com/rellampec/graphql-client (fork of
|
|
17
|
+
`github-community-projects/graphql-client`)
|
|
18
|
+
**Original migration need:** None — we bypass its HTTP dispatch layer and avoid the fragment
|
|
19
|
+
constant requirement via the plain-string fragment strategy.
|
|
20
|
+
**Revival effort (since 2026-06-13):** four upstream PRs are OPEN, awaiting a maintainer to
|
|
21
|
+
approve the first-time-contributor CI run:
|
|
22
|
+
- **#79** hygiene (CHANGELOG/CONTRIBUTING) — base
|
|
23
|
+
- **#80** docs (stacked on #79)
|
|
24
|
+
- **#81** characterization tests
|
|
25
|
+
- **#82** parse-robustness fix (anchored regex; rspec+rubocop clean)
|
|
26
|
+
|
|
27
|
+
**Status:** Revival in progress. Planned: merge all four into one fork branch (`integration/revival`)
|
|
28
|
+
and source this gem's gemspec/Gemfile from it as a stopgap until upstream merges/releases — see
|
|
29
|
+
TODO **7.1**. See memory `project-fork-revival-strategy`, `session-handoff-graphql-client-revival`.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## ecoportal-api-v2
|
|
34
|
+
|
|
35
|
+
**Remote:** https://gitlab.ecoportal.co.nz/oscar/ecoportal-api-v2.git
|
|
36
|
+
**Local:** `c:\ruby_scripts\git\ecoportal-api-v2\`
|
|
37
|
+
**Required change:** Per-model `as_update` override support (define behaviour per subclass
|
|
38
|
+
rather than relying solely on the base path-diff). This has been partially added already.
|
|
39
|
+
**Status:** In progress — confirm extent of existing implementation before adding more.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## eco-helpers (downstream — not upstream)
|
|
44
|
+
|
|
45
|
+
> Note: `eco-helpers` is a **downstream** consumer of `ecoportal-api-graphql`, not an
|
|
46
|
+
> upstream dependency. Changes here flow *down* to it, not up from it.
|
|
47
|
+
> Tracked here for awareness; full scope documented in INTENT.md.
|
|
48
|
+
|
|
49
|
+
**Remote:** https://gitlab.ecoportal.co.nz/oscar/script_api_helpers.git
|
|
50
|
+
**Local:** `c:\ruby_scripts\git\eco-helpers\`
|
|
51
|
+
**Required change:** DSL compat layer module so existing end scripts can target GraphQL
|
|
52
|
+
with minimal edits.
|
|
53
|
+
**Status:** Not started — design depends on `ecoportal-api-graphql` HTTP client being complete first.
|
data/.ai-assistance/projects/api-v2-to-graphql-migration/notes/csv-template-pipeline-design.md
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# Design — CSV → GraphQL Templates Pipeline (TODO 9.3)
|
|
2
|
+
|
|
3
|
+
> Drafted 2026-06-28 (background design pass). Deliverable: a standard solution to
|
|
4
|
+
> create + maintain ~300 templates for a customer from an input CSV (format agreed with
|
|
5
|
+
> customer ~mid-Jul; delivery Sept 2026). Memory: [[project-template-csv-pipeline]],
|
|
6
|
+
> [[project-template-update-architecture]].
|
|
7
|
+
|
|
8
|
+
## Headline finding — the #1 gap to fix first (read side)
|
|
9
|
+
|
|
10
|
+
The gem's command-bus foundation is solid: `Builder::Template#create(commands:)` /
|
|
11
|
+
`#update(model, commands:, patch_ver:)` feed `WorkflowCommandInput[]`, and the structural
|
|
12
|
+
section/field/option/stage commands are **already wrapped** (see §3). **But the identity
|
|
13
|
+
scheme depends on reading back data, and the read fragments don't expose it:**
|
|
14
|
+
|
|
15
|
+
- `fragment dataFieldInterface` (`fragment/pages/common_page_union.rb`) exposes only
|
|
16
|
+
`id, label, deindex, linkedFieldConfig` (+ per-type props) — **no `description`, no `hideView`**.
|
|
17
|
+
- `Base::Page::DataField` (`base/page/data_field.rb`) `passthrough`s only `label, deindex, type`.
|
|
18
|
+
|
|
19
|
+
Identity uses `description` (field key) and the hidden marker field (section key) — neither
|
|
20
|
+
is currently readable. **FIRST BUILD STEP:** add `description` + `hideView` (and
|
|
21
|
+
`hiddenOnMobile`) to `dataFieldInterface` and `passthrough :description, :hideView` on the
|
|
22
|
+
base model. (Verify those are valid read fields on `DataFieldsInterface` — a re-run of the
|
|
23
|
+
mini dispatch test will catch it if not, like the earlier fragment bugs.) Also needs a
|
|
24
|
+
**template-structure read entry-point** (`Builder::Template` has no read method today).
|
|
25
|
+
|
|
26
|
+
## 1. CSV schema (canonical internal model — adapt customer headers to this)
|
|
27
|
+
|
|
28
|
+
One row per **field**; section identity repeated on each row (section implied by its rows).
|
|
29
|
+
|
|
30
|
+
| Column | Purpose |
|
|
31
|
+
|---|---|
|
|
32
|
+
| `template_key` / `template_name` | external id (groups rows into a template) / display name |
|
|
33
|
+
| `stage` | stage name/key (phased; constant default for single-stage) |
|
|
34
|
+
| `section_key` | **external id of section** (→ hidden marker field, §2) |
|
|
35
|
+
| `section_heading` / `section_layout` (`content`/`split`) / `section_order` | heading / layout / ordinal |
|
|
36
|
+
| `field_key` | **external id of field** (→ field `description`, §2) |
|
|
37
|
+
| `field_label` / `field_type` | label / type token (plainText, number, select, date, people, crossReference, …) |
|
|
38
|
+
| `required` / `hidden` / `deindex` | per-field config |
|
|
39
|
+
| `column` (0/1) / `field_order` | split-section side / ordinal (ordering via `moveField`) |
|
|
40
|
+
| `options` (`Name:value|Name:value`) / `multiple` / `flat` | select config |
|
|
41
|
+
| `tooltip` / `config_json` (escape hatch) | extra config |
|
|
42
|
+
|
|
43
|
+
Keep additive/tolerant: unknown columns ignored, missing optionals defaulted. Write a thin
|
|
44
|
+
**adapter** from the customer's headers to this model once their format lands.
|
|
45
|
+
|
|
46
|
+
## 2. Identity / pairing
|
|
47
|
+
|
|
48
|
+
- **Field id ← `description`.** After `addField` (no description arg), issue
|
|
49
|
+
`editFieldConfiguration(dataFieldId:, description: field_key)`. On maintain, read all fields,
|
|
50
|
+
map `description → dataFieldId`, pair CSV rows by `field_key` (match→update, none→add,
|
|
51
|
+
absent→delete-or-leave per config).
|
|
52
|
+
- **Section id ← hidden marker field.** First field of each section = a hidden+deindex
|
|
53
|
+
PlainText whose `description` carries `section_key`. On maintain, read each section's first
|
|
54
|
+
component → `section_key → sectionId`. (Store key in `description`, not `value`, for uniform
|
|
55
|
+
extraction + safety if hide fails.)
|
|
56
|
+
- **Create vs maintain.** Create: one ordered `commands:` array using `placeholderId`
|
|
57
|
+
cross-refs (addSection→addField(sectionId: placeholder)…), then `create(commands:)`.
|
|
58
|
+
Maintain: read → identity maps → diff desired-vs-actual → delta commands →
|
|
59
|
+
`update(model, commands:, patch_ver:)`. The **diff/keyed-pairing engine is the core**
|
|
60
|
+
(robust version of the v2 `unless get_by_name(...)` guards, keyed by stable ids not labels).
|
|
61
|
+
|
|
62
|
+
## 3. CSV-row → WorkflowCommandInput mapping (all verified in COMMAND_MAP)
|
|
63
|
+
|
|
64
|
+
| Op | Command(s) |
|
|
65
|
+
|---|---|
|
|
66
|
+
| add stage | `addStage` |
|
|
67
|
+
| add section | `addSection` + `addStageSection` |
|
|
68
|
+
| section heading / reorder / delete | `editSectionHeader` / `reorderSection` / `removeSection`(+`removeStageSection`) |
|
|
69
|
+
| add field | `addField{placeholderId, fieldType, label, stageId, sectionId, column}` |
|
|
70
|
+
| configure field (label, **description=id**, hideView, deindex, tooltip, byType config) | `editFieldConfiguration` |
|
|
71
|
+
| move/reorder field | `moveField{id, sectionId, column}` |
|
|
72
|
+
| delete field | `removeField` |
|
|
73
|
+
| select options | `addSelectFieldOption` / `editSelectFieldOption` / `removeSelectFieldOption` |
|
|
74
|
+
| per-type config | `editFieldConfiguration byType:` via the 12 `field_config/*` builders |
|
|
75
|
+
|
|
76
|
+
## 4. Wrapped vs MISSING
|
|
77
|
+
- **Wrapped/usable:** all structural commands above + 12 `field_config` builders;
|
|
78
|
+
`editFieldConfiguration` already has `description`/`hideView` as BASE_KEYS;
|
|
79
|
+
`Builder::Template#create/#update/#publish`.
|
|
80
|
+
- **MISSING (build):** (1) **read-side `description`+`hideView`** on fragment + base model
|
|
81
|
+
[headline]; (2) **template-structure read entry-point** (hydrate stages→sections→fields +
|
|
82
|
+
patchVer, with `$fields`/`$content` flags); (3) **the pipeline** (CSV adapter → canonical
|
|
83
|
+
model → identity maps → diff → command builder → create/maintain/publish + retry); (4)
|
|
84
|
+
**verify `placeholderId`-as-reference** resolves server-side in one batch (else two-phase
|
|
85
|
+
create→read→configure); (5) hidden-marker helper/convention; (6) `Builder::Register` is a
|
|
86
|
+
stub — confirm whether templates are standalone or per-register.
|
|
87
|
+
|
|
88
|
+
## 5. Open questions for the customer + risks
|
|
89
|
+
- Headers + how sections are grouped; are `field_key`/`section_key` present or must we
|
|
90
|
+
synthesise stable keys (label-edit orphan risk if synthesised); phased vs single-stage;
|
|
91
|
+
in-scope field types; **delete semantics on maintain** (data-loss risk); auto-`publish` vs
|
|
92
|
+
leave drafts for review.
|
|
93
|
+
- **Risks:** read-gap (high — de-risk first); `placeholderId` resolution (high — verify early,
|
|
94
|
+
have two-phase fallback); marker fragility (medium — `hideView`+`deindex`+`enableActions:false`,
|
|
95
|
+
treat missing marker as unknown→warn); `description` collides with human-visible descriptions
|
|
96
|
+
(use a sentinel prefix like `__key:`); scale/API volume (batch + patchVer-conflict retry);
|
|
97
|
+
`WorkflowCommandInput` is volatile → keep row→command mapping in ONE isolated translation layer.
|
|
98
|
+
|
|
99
|
+
## Build order
|
|
100
|
+
1. Read-side `description`/`hideView` + template-structure read. 2. Verify `placeholderId`
|
|
101
|
+
cross-ref. 3. Canonical model + CSV adapter. 4. Diff + command translator (isolated).
|
|
102
|
+
5. create/maintain/publish + retry. 6. Pilot on a few templates in `mini` before the 300 run.
|