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,230 @@
|
|
|
1
|
+
# GraphQL Domain Knowledge — Agent Reference
|
|
2
|
+
|
|
3
|
+
*Accumulated from developer context, backend source code, and production Insomnia queries.*
|
|
4
|
+
*This document is for AI agents. Read it before analysing or generating any GraphQL query or mutation.*
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## GraphQL is a Language — Not a Fixed REST Schema
|
|
9
|
+
|
|
10
|
+
**Critical for agents:** GraphQL queries are client-defined. The same server resource can be
|
|
11
|
+
queried in infinitely many ways — with different field selections, variable names, fragment
|
|
12
|
+
compositions, and directive combinations. Variability between queries is **intentional and
|
|
13
|
+
expected**, not an error. Do not assume a query "should look like" any specific previous example.
|
|
14
|
+
|
|
15
|
+
Specific implications:
|
|
16
|
+
- **Multiple operations per request** are valid GraphQL. A single HTTP request can contain
|
|
17
|
+
multiple `query` or `mutation` definitions, separated by blank lines. The server executes
|
|
18
|
+
them in declaration order. The `operationName` field in the JSON payload identifies which
|
|
19
|
+
named definition is the primary one. This is used when a stateless client middleware cannot
|
|
20
|
+
sequence separate requests (e.g. `ArchivePage` blanks `externalId` then archives, in one call).
|
|
21
|
+
- **Fragment composition varies** — one team member's query may inline all fields; another's
|
|
22
|
+
uses the shared `CommonPageUnion` fragment. Both are correct.
|
|
23
|
+
- **Variable names are arbitrary** — `$search`, `$searchConf`, `$conf` all refer to the
|
|
24
|
+
same `Search` argument type.
|
|
25
|
+
- **Field selection is partial** — a query that omits `patchVer` is not wrong; it just
|
|
26
|
+
means the caller doesn't need it for that use case.
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Backend Naming Conventions — Rosetta Stone
|
|
31
|
+
|
|
32
|
+
The same concept appears under different names depending on which layer you're looking at.
|
|
33
|
+
This causes confusion when reading source code alongside API output.
|
|
34
|
+
|
|
35
|
+
| Concept | Backend Enzyme (old) | Backend NewEp (current) | APIv2 endpoint | GraphQL endpoint |
|
|
36
|
+
|---|---|---|---|---|
|
|
37
|
+
| Workflow phases | `stages` | `stages` | `stages` | `stages` |
|
|
38
|
+
| Content containers within a stage | `flow_nodes` | `sections` | `sections` | `sections` |
|
|
39
|
+
| Content fields within a section | `membranes` | `dataFields` | `components` | `dataFields` |
|
|
40
|
+
|
|
41
|
+
**Note:** Enzyme is the original Rails backend namespace. NewEp is the revamp that the team
|
|
42
|
+
is progressively migrating to. React front-end components that have been migrated to React
|
|
43
|
+
use GraphQL; anything still on AngularJS uses the old APIv2. A model being available via
|
|
44
|
+
GraphQL implies it has a NewEp backend class.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## The Sorter `key` Field — aka `ref` — aka the Future Field ID
|
|
49
|
+
|
|
50
|
+
The `key` field in searchConf sorters (and similarly in many filter params) is NOT the
|
|
51
|
+
MongoDB `id` of the field. It is the **field's ES index key**, also called the `ref` property
|
|
52
|
+
in the backend model (`Enzyme::Membrane` / `NewEp::DataField`).
|
|
53
|
+
|
|
54
|
+
**Composition of `ref`:**
|
|
55
|
+
```
|
|
56
|
+
<type_shorthand>.<truncated_hash_of_label>
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
- `type_shorthand`: e.g. `date`, `gauge`, `files`, `select_str`, `select_num`,
|
|
60
|
+
`rich_text`, `plain_text`, `actions_list`
|
|
61
|
+
- `.` separator
|
|
62
|
+
- Hash of the label name (truncated when label > 3 characters)
|
|
63
|
+
- Formula: `Ecoportal::API::Common::Content::StringDigest` in `ecoportal-api-v2`
|
|
64
|
+
|
|
65
|
+
**Why this matters:**
|
|
66
|
+
- This `ref` is how Elasticsearch identifies and indexes the field
|
|
67
|
+
- It is used in: dashboard charts, filter configs, cross-register configs (linked fields,
|
|
68
|
+
visitor management), exports
|
|
69
|
+
- A field's `ref` is stable as long as its label doesn't change
|
|
70
|
+
- The team refers to this as the "Field ID" — a future project aims to formalise it as a
|
|
71
|
+
proper System ID (as opposed to the internal MongoDB `id`)
|
|
72
|
+
|
|
73
|
+
**Known problem:** When tech scripts added fields to existing pages without copying from
|
|
74
|
+
the template (e.g. bulk backfills), fields were created with random generation-time IDs
|
|
75
|
+
rather than inheriting the template's `ref`. This creates duplicate/conflicting refs and
|
|
76
|
+
causes issues in exports (missing CSV values) and some chart types.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## The Genome Signature — ⚠️ IMPORTANT — Will Be Revisited
|
|
81
|
+
|
|
82
|
+
**Record this carefully. This topic will be picked up again.**
|
|
83
|
+
|
|
84
|
+
The genome signature is an identifier designed to pair fields across pages and their
|
|
85
|
+
source templates. It enables knowing that "this field in page X is the same field as
|
|
86
|
+
this field in template Y", even after the page was created, cloned, or restored.
|
|
87
|
+
|
|
88
|
+
**Original use:** The `Migrator` Rails Service (under the Rails Services loadable path)
|
|
89
|
+
had a full solution using the genome to pair fields during template changes and page
|
|
90
|
+
restorations (backup to YAML + restore).
|
|
91
|
+
|
|
92
|
+
**Current state:**
|
|
93
|
+
- Mostly **unused** — the Migrator solution was abandoned due to maintenance cost and
|
|
94
|
+
low usage
|
|
95
|
+
- **Not indexed** — the genome is not sent to Elasticsearch
|
|
96
|
+
- **Unpaired on many pages** — tech scripts that added fields without copying from the
|
|
97
|
+
template introduced fields with random creation-time genome signatures, breaking the
|
|
98
|
+
pairing with the template
|
|
99
|
+
- **NewEp port status:** Uncertain — unclear whether the NewEp namespace fully ported
|
|
100
|
+
the Genome functionality from the Enzyme namespace
|
|
101
|
+
- The genome is NOT currently exploitable for scripting or integration purposes
|
|
102
|
+
|
|
103
|
+
**Why it matters for the future:** The genome was the intended foundation for:
|
|
104
|
+
- Automatically applying template changes to existing pages
|
|
105
|
+
- Correctly pairing fields across page versions for cross-register configurations
|
|
106
|
+
- The Field ID project (see above) may supersede or build on this concept
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## DataField Input — The `dataFields.updates` Structure
|
|
111
|
+
|
|
112
|
+
When creating or updating page data fields via `createFromTemplate` or `updatePage`,
|
|
113
|
+
field updates use a typed union pattern in `dataFields.updates`:
|
|
114
|
+
|
|
115
|
+
```json
|
|
116
|
+
{
|
|
117
|
+
"dataFields": {
|
|
118
|
+
"updates": [
|
|
119
|
+
{ "date": { "id": "FIELD_ID", "value": "2024-11-25T08:30+13:00" } },
|
|
120
|
+
{ "people": { "id": "FIELD_ID", "peopleIds": ["PERSON_ID"] } },
|
|
121
|
+
{ "plainText": { "id": "FIELD_ID", "value": "JOB-0777" } },
|
|
122
|
+
{ "richText": { "id": "FIELD_ID", "content": "<p>HTML content</p>" } },
|
|
123
|
+
{ "select": { "id": "FIELD_ID", "options": [{ "id": "OPT_ID", "selected": true }] } },
|
|
124
|
+
{ "geo": { "id": "FIELD_ID", "address": "...", "coordinates": { "lat": -36.86, "lon": 174.76 } } }
|
|
125
|
+
]
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
The `id` in each field update is the **data field's MongoDB ObjectId** (from the built
|
|
131
|
+
draft — obtained via `buildFromTemplate`), not the `ref`/Field ID.
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Filter Rules — Silent Failure Traps
|
|
136
|
+
|
|
137
|
+
**snake_case is mandatory for filter operations.** If a CamelCase operation name is used
|
|
138
|
+
(e.g. `ExactFilter` instead of `exact_filter`), the server returns no error — it silently
|
|
139
|
+
returns zero results. This is one of the hardest bugs to diagnose for customers.
|
|
140
|
+
|
|
141
|
+
**`filters` should always be an Array.** The server normalises a single filter object to
|
|
142
|
+
an array internally, so both formats work. However, always use the array form to be
|
|
143
|
+
consistent and avoid edge cases.
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## Compound Mutations — Multiple Operations Per Request
|
|
148
|
+
|
|
149
|
+
GraphQL allows combining multiple mutations in a single request. They execute in
|
|
150
|
+
declaration order on the server. Use cases:
|
|
151
|
+
|
|
152
|
+
1. **Stateless middleware:** When a client framework cannot maintain session state between
|
|
153
|
+
requests, combining dependent mutations into one request guarantees correct sequencing.
|
|
154
|
+
Example: `ArchivePage` blanks `externalId` first (to avoid duplicate ID conflicts on
|
|
155
|
+
unarchive+recreate), then calls `archivePage`.
|
|
156
|
+
|
|
157
|
+
2. **Atomic-ish operations:** While GraphQL doesn't provide true ACID transactions, running
|
|
158
|
+
mutations in one request at least avoids partial state where a network failure between
|
|
159
|
+
two separate requests could leave data in an inconsistent state.
|
|
160
|
+
|
|
161
|
+
The `operationName` field in the HTTP JSON payload names the primary definition. In a
|
|
162
|
+
compound mutation, this is conventionally the name of the encompassing `mutation` block.
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## Template vs Instance Pages
|
|
167
|
+
|
|
168
|
+
- **Template** (`templatesOnly: true` in org search): Source pages that define field
|
|
169
|
+
structure. Used with `buildFromTemplate` / `createFromTemplate` workflows.
|
|
170
|
+
- **Instance page**: A page created from a template. Field IDs are assigned by the DB
|
|
171
|
+
on creation — they must be fetched (via `buildFromTemplate` result or subsequent org
|
|
172
|
+
search) before constructing field update inputs.
|
|
173
|
+
- **`showHiddenData: Boolean`**: Controls whether fields marked as hidden in the template
|
|
174
|
+
are included in query results. Set to `true` for integration scripts that need all fields.
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## Stage Rendering: APIv2 vs GraphQL (critical)
|
|
179
|
+
|
|
180
|
+
**APIv2:** Instance pages (pages WITH stages) are rendered and saved ONE STAGE PER REQUEST.
|
|
181
|
+
`pages.get(id, stage_id: id)` returns a single-stage view. This was an architectural
|
|
182
|
+
limitation. Templates and stageless pages are the only ones rendered in full by v2.
|
|
183
|
+
|
|
184
|
+
**GraphQL:** Full page in one request. `page(id:)` returns all stages, all sections,
|
|
185
|
+
all data fields the user has access to. Can update all stages at once, OR target a
|
|
186
|
+
specific stage via `stageId: ID` in `UpdatePageInput`.
|
|
187
|
+
|
|
188
|
+
**Stage-specific operations that REQUIRE `stageId`:**
|
|
189
|
+
- Stage close-out / submit (triggers fill-in task creation on next stage)
|
|
190
|
+
- Stage review sign-off (task completion triggers stage N+1 activation)
|
|
191
|
+
- People fields scoped to a specific stage (permission grants are stage-scoped)
|
|
192
|
+
Without `stageId`, these operations may succeed but not trigger the expected workflows.
|
|
193
|
+
|
|
194
|
+
**Stage permissions in GraphQL:** No access errors — stages the user cannot access
|
|
195
|
+
are simply absent from the response. APIv2 returned explicit errors per stage.
|
|
196
|
+
Scripts that relied on stage-access errors need to check for stage presence instead.
|
|
197
|
+
|
|
198
|
+
**Template updates:** Engineering explicitly does NOT want templates updated via GraphQL
|
|
199
|
+
while the AngularJS template editor is still in use. Block template mutation endpoints.
|
|
200
|
+
Read-only template queries (`templates(...)`) are fine.
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## Forces — Being Replaced by Workflow Builder
|
|
205
|
+
|
|
206
|
+
**Forces** are AngularJS front-end snippets that attach to specific stages via bindings.
|
|
207
|
+
They implement conditional field behaviour (show/hide sections, computed values, risk
|
|
208
|
+
matrices). Forces are NOT accessible or meaningful via GraphQL. Low scripting priority.
|
|
209
|
+
|
|
210
|
+
**Workflow Builder** (`pagesWorkflow`) is the replacement:
|
|
211
|
+
- Deployed: notifications, automated page creation, task assignments
|
|
212
|
+
- NOT yet deployed: conditional field/section workflows (show this section only when
|
|
213
|
+
field X has value Y; compute gauge value from severity × likelihood matrix)
|
|
214
|
+
- Recently refactored — active development, high change velocity, quick CI/CD fixes
|
|
215
|
+
- Do NOT design scripting against workflow builder internals — API is unstable
|
|
216
|
+
|
|
217
|
+
**Implication for scripts:** Workflow triggers (task creation, stage transitions) fire
|
|
218
|
+
as server-side side effects of `updatePage`. Scripts should check mutation payloads for
|
|
219
|
+
unexpected errors, but should not attempt to directly manage workflow state.
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## Two Build Patterns — Legacy vs Standard
|
|
224
|
+
|
|
225
|
+
**Build - Model (legacy):** Uses own inline fragment definitions per query. No shared
|
|
226
|
+
`CommonPageUnion`. Still in use in some older Insomnia requests. Avoid in new code.
|
|
227
|
+
|
|
228
|
+
**Build - Standard (current):** Uses `CommonPageUnion` with `$fields/$content/$only_content`
|
|
229
|
+
variables. This is the team-wide standard — designed for customer-facing documentation
|
|
230
|
+
and team knowledge sharing. New scripts should use this pattern.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Review: DataField read/write shape asymmetry + dirty-detection baseline
|
|
2
|
+
|
|
3
|
+
**Status:** OPEN — needs a thorough, dedicated review pass.
|
|
4
|
+
**Raised:** 2026-06-30 (after a real bug found + fixed on `CrossReference`).
|
|
5
|
+
**Owner cue:** Oscar flagged this for thorough review.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## The bug class
|
|
10
|
+
|
|
11
|
+
Several `DataField` subtypes are **READ** from the GraphQL response under one key/shape and
|
|
12
|
+
**WRITTEN** (staged for mutation) under a *different* key/shape. This breaks two things:
|
|
13
|
+
|
|
14
|
+
1. **Reading current values** — the typed reader reads the WRITE key, which the read response
|
|
15
|
+
never populates → returns `[]` (or stale) on a freshly-fetched page.
|
|
16
|
+
2. **Dirty detection** — the default leaf diff compares `doc` vs `original_doc` at the key
|
|
17
|
+
level. A write adds a brand-new key (e.g. `pages`) absent from the read shape, so the field
|
|
18
|
+
looks dirty the moment any setter runs — even when the effective value is unchanged
|
|
19
|
+
(e.g. `clear` on an already-empty reference → phantom `referenceIds: []`). Under APIv2 the
|
|
20
|
+
equivalent no-op was correctly not-dirty; this is a v2-parity regression.
|
|
21
|
+
|
|
22
|
+
## Per-field audit (2026-06-30)
|
|
23
|
+
|
|
24
|
+
| Field | READ (fragment `common_page_union.rb`) | WRITE key | Reader reads | Verdict |
|
|
25
|
+
|---|---|---|---|---|
|
|
26
|
+
| `CrossReference` | `references { nodes { id … } }` | `pages` | refs→pages | **FIXED** (set-based `dirty?` vs `original_doc`; shared `ref_ids_from`) |
|
|
27
|
+
| `FileField` | `items { fileContainer { id … } }` | `fileContainers` | `fileContainers` | **BROKEN reader** (reads key the response never has → `[]`) + phantom-dirty |
|
|
28
|
+
| `ImageGallery` | `images { downloadUrl, caption … }` (no `id` even fetched) | `fileContainers` | `fileContainers` | **BROKEN reader** + phantom-dirty; read fragment also omits ids |
|
|
29
|
+
| `ContractorEntities` | `contractorEntities { id, name … }` | `contractors` | `contractors` | **BROKEN reader** + phantom-dirty |
|
|
30
|
+
| `TagField` | `locations { …locationNode }` | `locations` | `locations` | key matches, but write narrows shape (`{id,name,…}`→`{id}`); `as_input` is nil (page-level locations) → low impact, still verify |
|
|
31
|
+
| `People`, `Select`, `Checklist`, `PlainText`, `RichText`, `Number`, `Gauge`, `DateField`, `Geo` | read key == write key | same | same | OK (no asymmetry) |
|
|
32
|
+
|
|
33
|
+
## Recommended review/fix direction
|
|
34
|
+
|
|
35
|
+
Two layers, decide per field:
|
|
36
|
+
|
|
37
|
+
- **Reader correctness:** make `*_ids` read the actual response key (`items[].fileContainer.id`,
|
|
38
|
+
`images[].id` (needs the fragment to fetch it), `contractorEntities[].id`) — falling back to
|
|
39
|
+
the staged write key when present (so post-write reads reflect the staged value). The shared
|
|
40
|
+
`ref_ids_from(doc)` pattern in `cross_reference.rb` is the template.
|
|
41
|
+
- **Dirty baseline:** any custom `dirty?`/`as_input` MUST diff the effective value against
|
|
42
|
+
**`original_doc`** (the diff `prev_doc` — see `Diffable::ClassicDiffService#prev_doc`), NOT
|
|
43
|
+
`doc`. Better still, where shapes can be normalised, defer to the inherited `DiffService`
|
|
44
|
+
rather than hand-rolling. Add a `consolidate!`-cycle assertion to every such field's spec
|
|
45
|
+
(read → mutate → as_input → `consolidate!` → re-check `dirty? == false`).
|
|
46
|
+
|
|
47
|
+
These fields are NOT exercised by the 3 cutover use cases (toocs = CrossReference + People;
|
|
48
|
+
cans = PlainText + Number + Select), so this is not a 1-Jul blocker — but it is a real
|
|
49
|
+
correctness gap for full parity and any script touching files/images/contractors.
|
|
50
|
+
|
|
51
|
+
## Retro — why the `CrossReference` bug went unnoticed (so we don't repeat it)
|
|
52
|
+
|
|
53
|
+
1. **Hand-rolled the baseline from `doc` instead of `original_doc`.** I wrote a custom `dirty?`
|
|
54
|
+
from first principles instead of reading the existing diff contract first. Had I checked
|
|
55
|
+
`ClassicDiffService#prev_doc` (returns `original_doc`) before writing it, I'd have used the
|
|
56
|
+
right baseline. Root cause: built a new abstraction parallel to an existing one without
|
|
57
|
+
consulting it.
|
|
58
|
+
2. **Incidental-correctness masked it in tests AND live.** My reader and my baseline both read
|
|
59
|
+
`references.nodes` from `doc`; since the setter only writes `pages`, the two always agreed on
|
|
60
|
+
the fetch-then-mutate path — the only path the specs and the live run exercised. The error is
|
|
61
|
+
invisible until `consolidate!` puts `pages` into `original_doc`.
|
|
62
|
+
3. **No lifecycle (`consolidate!`) test.** The test matrix covered read→mutate but not
|
|
63
|
+
read→mutate→update→consolidate→re-diff, where the bug actually surfaces.
|
|
64
|
+
4. **Conflated "read key isn't mutated" with "doc == baseline".** True premise, wrong
|
|
65
|
+
conclusion. Fragile coupling to current setter behaviour.
|
|
66
|
+
|
|
67
|
+
**Guardrails going forward:**
|
|
68
|
+
- Never compute a dirty baseline from `doc`; use `original_doc` or the `DiffService`.
|
|
69
|
+
- Every field with a staged-write setter gets a `consolidate!`-cycle spec.
|
|
70
|
+
- When adding a typed field, cross-check the fragment READ key against the setter WRITE key;
|
|
71
|
+
if they differ, normalise reads and baseline dirty on `original_doc`.
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
# Refactoring Opportunities
|
|
2
|
+
|
|
3
|
+
Low-priority items noted for future consideration. Not blocking current work.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## [LOW] Review graphlient DSL for future method chaining support
|
|
8
|
+
|
|
9
|
+
**Logged:** 2026-06-13
|
|
10
|
+
**Upstream repo:** `C:\ruby_scripts\git\graphlient` — branch `feature/directives-dsl-support`
|
|
11
|
+
|
|
12
|
+
**Context:** The current graphlient DSL passes directives as arguments:
|
|
13
|
+
```ruby
|
|
14
|
+
spread :InvoiceFields, _skip(if: :skip_invoice)
|
|
15
|
+
on(:DraftInvoice, _skip(if: :skip_drafts)) { draft_id }
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
A fluent chain-style equivalent (`spread(:InvoiceFields).skip(if: :x)`) would require
|
|
19
|
+
DSL methods to return a builder object rather than appending to `@query_str` and returning
|
|
20
|
+
`nil`. The current approach (directives as arguments) does **not block** future chaining —
|
|
21
|
+
both can coexist as alternative interfaces.
|
|
22
|
+
|
|
23
|
+
**Before the next graphlient upstream PR:** verify no API decisions in the current MR
|
|
24
|
+
force a hard dependency on the argument-passing style that would make a chain builder
|
|
25
|
+
impossible to introduce later without a breaking change.
|
|
26
|
+
|
|
27
|
+
**When to revisit:** When MR #116 is merged upstream. Low urgency — chaining is optional,
|
|
28
|
+
current syntax is functional.
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## [LOW] Fragment definitions as `.graphql` files instead of Ruby HEREDOCs
|
|
33
|
+
|
|
34
|
+
**Logged:** 2026-06-05
|
|
35
|
+
**Files affected:** `lib/ecoportal/api/graphql/fragment/*.rb`
|
|
36
|
+
|
|
37
|
+
**Idea:** Define named fragments in `.graphql` files (e.g.
|
|
38
|
+
`lib/ecoportal/api/graphql/fragment/action.graphql`) and load them at startup via
|
|
39
|
+
`File.read`, rather than embedding them as Ruby HEREDOCs.
|
|
40
|
+
|
|
41
|
+
**Benefits:**
|
|
42
|
+
- GraphQL files get syntax highlighting and editor tooling (linting, autocomplete).
|
|
43
|
+
- Cleaner separation — `.graphql` is the DSL, `.rb` is the Ruby wrapper.
|
|
44
|
+
- Easier to diff fragment changes in git without Ruby noise.
|
|
45
|
+
|
|
46
|
+
**Open questions / why it's low priority:**
|
|
47
|
+
- HEREDOCs work fine and there is no string interpolation in fragments, so the
|
|
48
|
+
only gain is cosmetic/tooling.
|
|
49
|
+
- Client scripts may define custom queries as HEREDOCs in their own code. Whether
|
|
50
|
+
those should auto-load into the fragment registry (and how) is unresolved.
|
|
51
|
+
`FragmentDefinitions.assemble(*syms)` only knows about fragments registered via
|
|
52
|
+
`fragment :Sym, string` — any `.graphql` file loader would need to register them
|
|
53
|
+
the same way.
|
|
54
|
+
- Until the auto-loading story for custom script fragments is clear, standardising
|
|
55
|
+
on `.graphql` files for the gem's own fragments may create inconsistency.
|
|
56
|
+
|
|
57
|
+
**When to revisit:** Once there is a concrete script use case that benefits from
|
|
58
|
+
`.graphql` file loading, or when editor tooling for HEREDOCs becomes a pain point.
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## [MEDIUM] Upstream-stack friction points — candidates for future graphql-client / graphlient MRs
|
|
63
|
+
|
|
64
|
+
**Logged:** 2026-06-16
|
|
65
|
+
**Scope:** `graphql-client` (fork: `rellampec/graphql-client`) and `graphlient` (fork: `rellampec/graphlient`)
|
|
66
|
+
**Origin:** Adoption-friction analysis while documenting inline named fragments (graphql-client
|
|
67
|
+
issue [#76](https://github.com/github-community-projects/graphql-client/issues/76)).
|
|
68
|
+
|
|
69
|
+
These are the genuine reasons a large Ruby shop tends to avoid or rip out the
|
|
70
|
+
`graphlient → graphql-client → graphql-ruby → faraday` stack. None is confirmed as the
|
|
71
|
+
cause of any specific org's removal (see note below); they are the real ergonomic/architectural
|
|
72
|
+
frictions worth addressing if we want the forks to be community-scalable.
|
|
73
|
+
|
|
74
|
+
1. **Layered indirection for an HTTP POST.** Four abstraction layers to send a query string
|
|
75
|
+
and parse JSON. *MR angle:* keep graphlient a genuinely thin, optional convenience layer;
|
|
76
|
+
don't deepen coupling. Make the "drop graphlient, use graphql-client directly" path easy.
|
|
77
|
+
|
|
78
|
+
2. **Heavy/opinionated dependency footprint.** graphql-client pulls in **ActiveSupport**
|
|
79
|
+
(only for `constantize`/Inflector at `lib/graphql/client.rb:161`) and the *full*
|
|
80
|
+
**graphql-ruby** gem to act as a client. *MR angle:* scope down the ActiveSupport surface
|
|
81
|
+
(the Inflector use is small and replaceable) — a frequent complaint for client-only use.
|
|
82
|
+
|
|
83
|
+
3. **Design-philosophy mismatch — forced component isolation.** The constant-bound,
|
|
84
|
+
colocated-fragment model raises `ImplicitlyFetchedFieldError` on reuse-only fragments.
|
|
85
|
+
This is exactly issue #76. *MR angle:* the inline-named-fragment convention (documented)
|
|
86
|
+
+ the planned anchored-regex parse fix together give a sanctioned "fragments for pure
|
|
87
|
+
reuse" path. Land both.
|
|
88
|
+
|
|
89
|
+
4. **Client-side schema coupling.** Parse-time validation needs a vendored schema artifact
|
|
90
|
+
kept in sync with the server. *MR angle:* document/support a dynamic-query path
|
|
91
|
+
(`allow_dynamic_queries`) clearly so teams that build queries at runtime aren't forced
|
|
92
|
+
into static constants.
|
|
93
|
+
|
|
94
|
+
5. **Maintenance / bus-factor optics.** graphlient last released 0.8.0 (Jan 2024); graphql-client
|
|
95
|
+
moved to the low-staff `github-community-projects/` org. *MR angle (non-code):* CHANGELOG +
|
|
96
|
+
CONTRIBUTING hygiene (already in flight on `chore/add-changelog-contributing`) and steady,
|
|
97
|
+
well-scoped PRs are the cheapest way to improve adoption confidence.
|
|
98
|
+
|
|
99
|
+
6. **Parse-step robustness.** The unanchored `str.match(/fragment\s*#{const_name}/)` heuristic
|
|
100
|
+
at `lib/graphql/client.rb:161` misfires on prefix collisions (`...UserFields` vs
|
|
101
|
+
`fragment UserFieldsExtended`) and `\s*` even matches `fragmentUserFields`. *MR angle:*
|
|
102
|
+
the planned **Step 5** anchored fix (`fragment\s+Name\s+on\b`), stacked on the
|
|
103
|
+
characterization specs. Note upstream tried + reverted a fix here once (`c576c2e` →
|
|
104
|
+
`b5a4612`), so characterization-first is the right order.
|
|
105
|
+
|
|
106
|
+
**Note on the "GitLab removed it" premise:** a GitLab.com group search for `graphql-client`
|
|
107
|
+
MRs (2026-06-16) surfaced **dependency *updates*, not removals** — e.g. triage-ops bumping
|
|
108
|
+
graphql-client to `~> 0.26.0` (merged Feb 2026). i.e. GitLab appears to actively maintain the
|
|
109
|
+
dep, the opposite of dropping it. Treat the rendered search as indicative only (may be
|
|
110
|
+
login-gated/partial); no verified evidence of a major-org removal exists. ecoPortal's own
|
|
111
|
+
CI/CD removal was an internal decision, not an industry trend. See memory
|
|
112
|
+
`project-fork-revival-strategy`.
|
|
113
|
+
|
|
114
|
+
**When to revisit:** Items 3 & 6 are active (the #76 docs MR + Step-5 fix). Items 1, 2, 4 are
|
|
115
|
+
future upstream MRs once the fork-revival sequence (hygiene → characterization → parse fix) lands.
|
|
116
|
+
|
|
117
|
+
**Update (2026-06-16):** the fork-revival PRs are OPEN upstream — graphql-client #79 (hygiene),
|
|
118
|
+
#80 (inline-fragment docs), #81 (characterization tests), #82 (the anchored parse fix). #82
|
|
119
|
+
verified RuboCop-clean + tests green locally. See memory `session-handoff-graphql-client-revival`.
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## [LOW] graphql-client 1.0 (#15) — aligned contribution candidates
|
|
124
|
+
|
|
125
|
+
**Logged:** 2026-06-23
|
|
126
|
+
**Upstream:** `github-community-projects/graphql-client` issue
|
|
127
|
+
[#15](https://github.com/github-community-projects/graphql-client/issues/15) (1.0.0 roadmap,
|
|
128
|
+
rmosolgo, Feb 2024). Triggered by our #76 comment pinging the maintainer.
|
|
129
|
+
**Priority:** LOW for us — opportunistic, only as the fork-revival PRs (#79–#82) progress.
|
|
130
|
+
|
|
131
|
+
**State of the #15 roadmap (verified 2026-06-23 via issue + comments):** rmosolgo listed three
|
|
132
|
+
pre-1.0 items and invited community suggestions ("If anyone has other suggestions for 1.0, please
|
|
133
|
+
share them in a comment below").
|
|
134
|
+
|
|
135
|
+
1. **Performance audit** (view helpers + runtime) — rmosolgo reported "performance audit work"
|
|
136
|
+
complete (Nov 14 2024). No formal closure; the runtime hot path includes `Client#parse`.
|
|
137
|
+
2. **Subscription support** — **STILL OPEN** (the one unaddressed 1.0 item), and **genuinely out of
|
|
138
|
+
our lane.** A brief 2026-06-23 detour considered that the upcoming ecoPortal webhooks feature
|
|
139
|
+
might use GraphQL subscriptions, but the Confluence draft settles it: webhooks are **outbound
|
|
140
|
+
HTTP POST** (Standard Webhooks / Ed25519), and the "subscription" there is just a
|
|
141
|
+
**webhook-registration entity** CRUD'd via ordinary mutations — NOT a GraphQL `subscription` root
|
|
142
|
+
type. So webhooks do not pull #15 item 2 into scope. The webhook-registration CRUD *is* in our
|
|
143
|
+
lane, but as plain queries/mutations in this gem once it hits the PROD schema — no upstream
|
|
144
|
+
graphql-client change needed. See memory `project-webhooks-subscriptions`. Revisit only if some
|
|
145
|
+
*other* future need exposes a real `subscription` root type.
|
|
146
|
+
3. **Response metadata in HTTP results** — **DONE** via billybonks' PR #43 (rate-limit headers etc.);
|
|
147
|
+
rmosolgo closed the item Nov 14 2024.
|
|
148
|
+
|
|
149
|
+
So the literal roadmap is mostly closed except subscriptions. The real opening is the maintainer's
|
|
150
|
+
**open invitation for 1.0 suggestions** — a 1.0 is the semver moment to land convention/cleanup
|
|
151
|
+
changes that overlap exactly with our aim. Candidate contributions, each already partly in flight:
|
|
152
|
+
|
|
153
|
+
- **[in flight] Land the parse-robustness fix (#82) as a 1.0 correctness item.** Anchored
|
|
154
|
+
`fragment\s+Name\s+on\b` regex at `client.rb:161`. Touches the "runtime code" the perf audit
|
|
155
|
+
named; converts a crash into a clean `ValidationError`. Cheapest, most defensible 1.0 contribution.
|
|
156
|
+
- **[in flight] Bless "fragments for pure reuse" as a documented 1.0 convention (#76 + #80/#81).**
|
|
157
|
+
Inline named fragments, Apollo-aligned, backwards-compatible (constant-bound isolation kept as the
|
|
158
|
+
opt-in boundary). A behaviour/philosophy clarification is best made at a 1.0 boundary — frame it
|
|
159
|
+
to the maintainer that way.
|
|
160
|
+
- **[new] Scope down the ActiveSupport dependency.** graphql-client pulls full ActiveSupport for
|
|
161
|
+
`constantize`/Inflector around `client.rb:161`. A 1.0 is when you'd drop/loosen a heavy dep;
|
|
162
|
+
classic adoption-friction win (friction item #2 above). Spec out a small internal constantize or
|
|
163
|
+
a narrower require before proposing.
|
|
164
|
+
- **[new] Document/support the dynamic-query path (`allow_dynamic_queries`).** Lets teams build
|
|
165
|
+
queries at runtime without static constants — pairs with the fragments work and the schema-coupling
|
|
166
|
+
friction (item #4 above). Likely docs + a small guard test.
|
|
167
|
+
- **[new] Named operations.** Optional operation names for server-side logging / APM / persisted
|
|
168
|
+
queries — also the natural identifier subscriptions would need later, so it nudges item #2 forward
|
|
169
|
+
without committing us to transports. Couples with the graphlient named-query DSL
|
|
170
|
+
(`query(:GetInvoice)`) already noted in memory `project-graphql-client-redesign`.
|
|
171
|
+
|
|
172
|
+
**Suggested action (low urgency):** once #79–#82 are merged, post a single comment on #15 offering
|
|
173
|
+
the parse-fix + inline-fragment convention + ActiveSupport scope-down as concrete 1.0 suggestions,
|
|
174
|
+
and noting subscriptions are out of our scope (we drive query/mutation over HTTP POST; ecoPortal's
|
|
175
|
+
webhooks are outbound HTTP, not GraphQL subscriptions — see item 2). Do not post before the revival
|
|
176
|
+
PRs land (keeps our credibility — ship the easy ones first).
|
|
177
|
+
|
|
178
|
+
**When to revisit:** after graphql-client #79–#82 merge. See memories
|
|
179
|
+
`project-fork-revival-strategy`, `session-handoff-graphql-client-revival`.
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## [MEDIUM] graphlient masks client-side graphql-client errors (lost `inner_exception`)
|
|
184
|
+
|
|
185
|
+
**Logged:** 2026-06-16
|
|
186
|
+
**Upstream repo:** `C:\ruby_scripts\git\graphlient` — fork `rellampec/graphlient`, branch `feature/directives-dsl-support`
|
|
187
|
+
|
|
188
|
+
**Problem:** `lib/graphlient/client.rb` rescues `GraphQL::Client::Error` in both `parse` (L19-20)
|
|
189
|
+
and `execute` (L41-42) and re-raises `ClientError, e.message` — passing only the message string.
|
|
190
|
+
graphlient's base `Error#initialize(message, inner_exception = nil)` is built to carry the
|
|
191
|
+
original, and `FaradayServerError` uses it correctly (`super(inner_exception.message, inner_exception)`),
|
|
192
|
+
but these two rescues leave `inner_exception = nil`. Lost: the original error's class and the
|
|
193
|
+
source-location backtrace graphql-client deliberately sets (e.g. `uninitialized constant X`,
|
|
194
|
+
static-validation messages). Related inconsistency: `faraday_adapter.rb:73` passes the exception
|
|
195
|
+
as the *message* arg, so it also leaves `inner_exception` nil.
|
|
196
|
+
|
|
197
|
+
**Fix:** `raise Graphlient::Errors::ClientError.new(e.message, e)` (matches FaradayServerError).
|
|
198
|
+
If the symptom is a *blank* message rather than a lost cause, also audit the
|
|
199
|
+
`GraphQLError`/`ExecutionError#to_s` path (formats from `errors.details`, can render empty).
|
|
200
|
+
|
|
201
|
+
**Note:** user recalls patching BOTH graphql-client and graphlient for this — so there may be a
|
|
202
|
+
graphql-client-side aspect too (the #82 anchoring fix already converts one crash into a clean
|
|
203
|
+
`ValidationError`). Own graphlient PR, separate from #115/#116. Test-first (repro spec asserting
|
|
204
|
+
`inner_exception` populated). Full detail: memory `graphlient-error-masking`.
|
|
205
|
+
|
|
206
|
+
**When to revisit:** after the #116 DSL work; or sooner if error opacity bites again during the
|
|
207
|
+
template-update / Workflow* work.
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## [VERY LOW] Extract `SnakeCamelIndifferentAccess` into its own gem
|
|
212
|
+
|
|
213
|
+
**Logged:** 2026-06-05
|
|
214
|
+
**Origin:** `eco-helpers` — `lib/eco/data/hashes/sanke_camel_indifferent_access.rb`
|
|
215
|
+
(note: filename has a typo — `sanke` instead of `snake`)
|
|
216
|
+
**Specs:** already exist in `eco-helpers` spec suite
|
|
217
|
+
|
|
218
|
+
**Idea:** Extract `Eco::Data::Hashes::SnakeCamelIndifferentAccess` (and its dependencies
|
|
219
|
+
`Eco::Data::Strings::SnakeCase`, `Eco::Data::Strings::CamelCase`) into a standalone gem.
|
|
220
|
+
Then use it in `ecoportal-api-graphql`'s base model so that GraphQL response docs (stored
|
|
221
|
+
internally in camelCase as the API returns them) are also accessible via snake_case Ruby
|
|
222
|
+
methods — without a full key rename on every read.
|
|
223
|
+
|
|
224
|
+
**What the module does:**
|
|
225
|
+
Hash accessor that treats `fooBar` and `foo_bar` as the same key. Configurable preferred
|
|
226
|
+
form (defaults to `:snake_case`). Operations: `get`, `set`, `merge!`, `each`, `slice`,
|
|
227
|
+
`camelize_keys`, `snakeize_keys`, all case-indifferent. Uses round-trip conversion via
|
|
228
|
+
`snake_case(camelCase) ↔ camelCase(snake_case)`.
|
|
229
|
+
|
|
230
|
+
**Why this matters for the GraphQL gem:**
|
|
231
|
+
Currently `ecoportal-api-graphql` models map every field explicitly via `passthrough`,
|
|
232
|
+
`passboolean`, etc. using camelCase names matching the API (e.g. `passthrough :patchVer`).
|
|
233
|
+
Ruby callers must use `model.patchVer`. With indifferent access, `model.patch_ver` and
|
|
234
|
+
`model.patchVer` would both work without any change to the field declarations. This
|
|
235
|
+
eliminates the Ruby style inconsistency that has been a known pain point for 4+ years.
|
|
236
|
+
|
|
237
|
+
**Proposed gem name:** `hash_case_indifferent` or `camel_snake_hash` (TBD)
|
|
238
|
+
|
|
239
|
+
**Work involved:**
|
|
240
|
+
1. Extract module + string helpers + specs into new gem repo
|
|
241
|
+
2. Add gem as dependency of `eco-helpers` and `ecoportal-api-graphql`
|
|
242
|
+
3. Include in `Common::GraphQL::Model` (or `Logic::BaseModel`) so all model
|
|
243
|
+
instances support both `model.patchVer` and `model.patch_ver`
|
|
244
|
+
4. Verify no regressions in downstream `eco-helpers` scripts that use camelCase access
|
|
245
|
+
|
|
246
|
+
**Prerequisite:** `as_update`/`as_input` pipeline (Group 4) should be stable first,
|
|
247
|
+
since that pipeline reads field values off models. Once indifferent access is in place,
|
|
248
|
+
the diff/input code may need to handle both key forms for lookups.
|
|
249
|
+
|
|
250
|
+
**When to revisit:** After Group 4 + Page model Phase A/B are stable. New project
|
|
251
|
+
milestone, not a small refactor.
|