ecoportal-api-graphql 1.3.13 → 1.3.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +87 -0
- data/lib/ecoportal/api/common/graphql/client.rb +0 -2
- data/lib/ecoportal/api/common/graphql/http_client.rb +6 -0
- data/lib/ecoportal/api/graphql/base/ai_summary_version.rb +17 -17
- data/lib/ecoportal/api/graphql/base/file_container.rb +14 -14
- data/lib/ecoportal/api/graphql/base/location_classification_type.rb +15 -15
- data/lib/ecoportal/api/graphql/base/location_structure.rb +27 -27
- data/lib/ecoportal/api/graphql/base/organization.rb +15 -15
- data/lib/ecoportal/api/graphql/base/page/task.rb +24 -0
- data/lib/ecoportal/api/graphql/base/page.rb +17 -16
- data/lib/ecoportal/api/graphql/base/template.rb +35 -0
- data/lib/ecoportal/api/graphql/base.rb +37 -35
- data/lib/ecoportal/api/graphql/builder/contractor_entity.rb +41 -41
- data/lib/ecoportal/api/graphql/compat/response.rb +35 -35
- data/lib/ecoportal/api/graphql/connection/action.rb +11 -11
- data/lib/ecoportal/api/graphql/connection/action_category.rb +11 -11
- data/lib/ecoportal/api/graphql/connection/contractor_entity.rb +11 -11
- data/lib/ecoportal/api/graphql/connection/page.rb +11 -11
- data/lib/ecoportal/api/graphql/connection/person_member.rb +11 -11
- data/lib/ecoportal/api/graphql/connection/preview_page.rb +11 -11
- data/lib/ecoportal/api/graphql/connection.rb +17 -17
- data/lib/ecoportal/api/graphql/file_upload/client.rb +21 -10
- data/lib/ecoportal/api/graphql/fragment/field_configuration.rb +38 -0
- data/lib/ecoportal/api/graphql/fragment/force.rb +14 -10
- data/lib/ecoportal/api/graphql/fragment/location_node.rb +26 -26
- data/lib/ecoportal/api/graphql/fragment/page_task.rb +39 -0
- data/lib/ecoportal/api/graphql/fragment/template.rb +51 -0
- data/lib/ecoportal/api/graphql/fragment.rb +3 -0
- data/lib/ecoportal/api/graphql/input/contractor_entity.rb +14 -14
- data/lib/ecoportal/api/graphql/input/preset_view/update.rb +16 -16
- data/lib/ecoportal/api/graphql/input/workflow_command/add_stage.rb +18 -18
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_field_configuration.rb +21 -21
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_page.rb +28 -28
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_page_creator_permissions.rb +18 -18
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/cross_reference.rb +23 -23
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/date.rb +20 -20
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/image_gallery.rb +20 -20
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/people.rb +24 -24
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/plain_text.rb +20 -20
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/rich_text.rb +20 -20
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/select.rb +20 -20
- data/lib/ecoportal/api/graphql/input/workflow_command/move_field.rb +18 -18
- data/lib/ecoportal/api/graphql/input/workflow_command/reorder_forces.rb +18 -18
- data/lib/ecoportal/api/graphql/input/workflow_command/reorder_section.rb +18 -18
- data/lib/ecoportal/api/graphql/input/workflow_command.rb +251 -251
- data/lib/ecoportal/api/graphql/input.rb +24 -24
- data/lib/ecoportal/api/graphql/logic/connection.rb +34 -34
- data/lib/ecoportal/api/graphql/model/page/task.rb +16 -0
- data/lib/ecoportal/api/graphql/model/page.rb +16 -15
- data/lib/ecoportal/api/graphql/model/person_member.rb +15 -15
- data/lib/ecoportal/api/graphql/model/template.rb +15 -0
- data/lib/ecoportal/api/graphql/model.rb +32 -30
- data/lib/ecoportal/api/graphql/mutation/ai_summary/generate.rb +45 -45
- data/lib/ecoportal/api/graphql/mutation/ai_summary/submit_feedback.rb +40 -40
- data/lib/ecoportal/api/graphql/mutation/contractor_entity.rb +14 -14
- data/lib/ecoportal/api/graphql/mutation/page/approve_review_task.rb +40 -40
- data/lib/ecoportal/api/graphql/mutation/page/batch_update_review_task.rb +38 -40
- data/lib/ecoportal/api/graphql/mutation/page/create_draft.rb +38 -40
- data/lib/ecoportal/api/graphql/mutation/page/delete_draft.rb +38 -40
- data/lib/ecoportal/api/graphql/mutation/page/execute_force_commands.rb +7 -7
- data/lib/ecoportal/api/graphql/mutation/page/execute_workflow_commands.rb +8 -7
- data/lib/ecoportal/api/graphql/mutation/page/publish_draft.rb +38 -40
- data/lib/ecoportal/api/graphql/mutation/page/reject_review_task.rb +40 -40
- data/lib/ecoportal/api/graphql/mutation/page/restart_review_task.rb +40 -40
- data/lib/ecoportal/api/graphql/mutation/page/undo_review_task.rb +40 -40
- data/lib/ecoportal/api/graphql/mutation/preset_view/destroy.rb +34 -35
- data/lib/ecoportal/api/graphql/mutation/register/destroy.rb +35 -35
- data/lib/ecoportal/api/graphql/mutation/smart_fill/generate.rb +36 -36
- data/lib/ecoportal/api/graphql/mutation/smart_fill/submit_feedback.rb +40 -40
- data/lib/ecoportal/api/graphql/mutation/smart_fill.rb +13 -13
- data/lib/ecoportal/api/graphql/mutation/template/create_related_page.rb +46 -46
- data/lib/ecoportal/api/graphql/mutation/template/destroy_related_page.rb +1 -1
- data/lib/ecoportal/api/graphql/mutation/template/update_information.rb +1 -1
- data/lib/ecoportal/api/graphql/mutation.rb +20 -20
- data/lib/ecoportal/api/graphql/payload/contractor_entity.rb +14 -14
- data/lib/ecoportal/api/graphql/payload/ok_payload.rb +36 -21
- data/lib/ecoportal/api/graphql/payload/page/draft.rb +26 -13
- data/lib/ecoportal/api/graphql/payload/page/review_task.rb +13 -13
- data/lib/ecoportal/api/graphql/payload/page/review_task_batch.rb +23 -0
- data/lib/ecoportal/api/graphql/payload/page.rb +20 -19
- data/lib/ecoportal/api/graphql/payload/preset_view.rb +15 -11
- data/lib/ecoportal/api/graphql/payload/register.rb +15 -11
- data/lib/ecoportal/api/graphql/payload/template/create_related_page.rb +1 -1
- data/lib/ecoportal/api/graphql/payload/template/destroy_related_page.rb +1 -1
- data/lib/ecoportal/api/graphql/payload/template/update_information.rb +1 -1
- data/lib/ecoportal/api/graphql/payload.rb +23 -23
- data/lib/ecoportal/api/graphql/query/location_structures.rb +57 -57
- data/lib/ecoportal/api/graphql/query/page.rb +45 -45
- data/lib/ecoportal/api/graphql/query/page_with_forces.rb +9 -3
- data/lib/ecoportal/api/graphql/query/pages_workflow_commands.rb +9 -3
- data/lib/ecoportal/api/graphql/query/register_preset_views.rb +78 -78
- data/lib/ecoportal/api/graphql/query.rb +27 -27
- data/lib/ecoportal/api/graphql.rb +9 -5
- data/lib/ecoportal/api/graphql_version.rb +1 -1
- metadata +9 -180
- data/.ai-assistance/bridge/CLAUDE.md +0 -338
- data/.ai-assistance/bridge/archive/.gitkeep +0 -0
- data/.ai-assistance/bridge/archive/oscar-a1b2c3d-gitlab-mcp-doc-update.inbox.md +0 -29
- data/.ai-assistance/bridge/archive/oscar-a1b2c3d-gitlab-mcp-doc-update.outbox.md +0 -18
- data/.ai-assistance/bridge/archive/oscar-c912c25-gemini-design-review.inbox.md +0 -42
- data/.ai-assistance/bridge/archive/oscar-c912c25-gemini-design-review.outbox.md +0 -115
- data/.ai-assistance/bridge/context/gemini-review-prompt.txt +0 -48
- data/.ai-assistance/bridge/context/gemini-review-response.md +0 -104
- data/.ai-assistance/bridge/context/project.md +0 -42
- 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 +0 -48
- data/.ai-assistance/bridge/queue/.gitkeep +0 -1
- data/.ai-assistance/capabilities/CLAUDE.md +0 -27
- data/.ai-assistance/capabilities/assumptions-log.md +0 -80
- data/.ai-assistance/capabilities/code.md +0 -47
- data/.ai-assistance/capabilities/connectors.md +0 -37
- data/.ai-assistance/capabilities/cowork.md +0 -55
- data/.ai-assistance/code/OVERVIEW.md +0 -155
- data/.ai-assistance/code/data_fields.md +0 -242
- data/.ai-assistance/code/dependencies.md +0 -151
- data/.ai-assistance/code/diff_as_input.md +0 -234
- data/.ai-assistance/code/diff_pairing_engine.md +0 -243
- data/.ai-assistance/code/diff_service_deep_dive.md +0 -192
- data/.ai-assistance/code/ecoPortal_architecture/00_overview_and_index.md +0 -55
- data/.ai-assistance/code/ecoPortal_architecture/01_terminology_dictionary.md +0 -181
- data/.ai-assistance/code/ecoPortal_architecture/02_data_model.md +0 -192
- data/.ai-assistance/code/ecoPortal_architecture/03_api_layers.md +0 -147
- data/.ai-assistance/code/ecoPortal_architecture/04_graphql_queries_mutations.md +0 -277
- data/.ai-assistance/code/ecoPortal_architecture/05_page_workflows.md +0 -200
- data/.ai-assistance/code/ecoPortal_architecture/06_search_and_filters.md +0 -228
- data/.ai-assistance/code/ecoPortal_architecture/07_data_fields.md +0 -197
- data/.ai-assistance/code/ecoPortal_architecture/08_stages_sections.md +0 -243
- data/.ai-assistance/code/ecoPortal_architecture/09_people_contractors_locations.md +0 -196
- data/.ai-assistance/code/ecoPortal_architecture/10_forces_workflow_builder.md +0 -132
- data/.ai-assistance/code/ecoPortal_architecture/11_integration_gems.md +0 -187
- data/.ai-assistance/code/ecoPortal_architecture/12_ai_documentation_sources_gaps.md +0 -236
- data/.ai-assistance/code/ecoPortal_architecture/13_ai_infrastructure.md +0 -183
- data/.ai-assistance/code/ecoportal_schema_reference.md +0 -240
- data/.ai-assistance/code/filter_contract_matrix.md +0 -177
- data/.ai-assistance/code/graphql_domain_knowledge.md +0 -240
- data/.ai-assistance/code/refactoring/datafield-readwrite-shape-asymmetry.md +0 -71
- data/.ai-assistance/code/refactoring/opportunities.md +0 -251
- data/.ai-assistance/code/schema_analysis.md +0 -321
- data/.ai-assistance/code/search_filters.md +0 -868
- data/.ai-assistance/code/spec_coverage.md +0 -73
- data/.ai-assistance/code/template_diff_pairing_domain.md +0 -175
- data/.ai-assistance/code/workflow-command-guide.md +0 -466
- data/.ai-assistance/code/workflow-space.md +0 -353
- data/.ai-assistance/conventions/CLAUDE.md +0 -30
- data/.ai-assistance/conventions/code-working-tree-protocol.md +0 -199
- data/.ai-assistance/conventions/gitignore-rules.md +0 -42
- data/.ai-assistance/conventions/permission-guidance.md +0 -120
- data/.ai-assistance/integrations/README.md +0 -70
- data/.ai-assistance/integrations/gitkraken-mcp.md +0 -107
- data/.ai-assistance/integrations/gitlab-mcp.md +0 -123
- data/.ai-assistance/integrations/local-git.md +0 -60
- data/.ai-assistance/local_paths.example.md +0 -17
- data/.ai-assistance/projects/TODO.md +0 -118
- data/.ai-assistance/projects/api-v2-to-graphql-migration/DECISIONS.md +0 -168
- data/.ai-assistance/projects/api-v2-to-graphql-migration/INTENT.md +0 -60
- data/.ai-assistance/projects/api-v2-to-graphql-migration/TODO.md +0 -267
- data/.ai-assistance/projects/api-v2-to-graphql-migration/UPSTREAM.md +0 -53
- data/.ai-assistance/projects/api-v2-to-graphql-migration/notes/csv-template-pipeline-design.md +0 -102
- data/.ai-assistance/projects/api-v2-to-graphql-migration/notes/cutover-usecase-gap-audit.md +0 -139
- data/.ai-assistance/projects/compat-layer-audit/COMPAT_AUDIT.md +0 -244
- data/.ai-assistance/projects/dynamic-model-generation/INTENT.md +0 -93
- data/.ai-assistance/projects/eco-helpers-compat/INTENT.md +0 -244
- data/.ai-assistance/projects/eco-helpers-compat/MIGRATION_GUIDE.md +0 -266
- data/.ai-assistance/projects/eco-helpers-compat/TODO.md +0 -86
- data/.ai-assistance/projects/ecoportal-api-v2-doublemodel-review/INTENT.md +0 -101
- data/.ai-assistance/projects/graphql-agent/GAP_ANALYSIS.md +0 -177
- data/.ai-assistance/projects/ooze-graphql-native-migration/DECISIONS.md +0 -161
- data/.ai-assistance/projects/ooze-graphql-native-migration/INTENT.md +0 -125
- data/.ai-assistance/projects/ooze-graphql-native-migration/INVENTORY.md +0 -136
- data/.ai-assistance/projects/ooze-graphql-native-migration/RISKS.md +0 -126
- data/.ai-assistance/projects/ooze-graphql-native-migration/TODO.md +0 -261
- data/.ai-assistance/projects/ooze-graphql-native-migration/analysis/2026-06-30-cutover-workflow-deep-review.md +0 -122
- data/.ai-assistance/projects/ooze-graphql-native-migration/analysis/2026-07-01-forces-via-workflow-commands-miss-rca.md +0 -148
- data/.ai-assistance/projects/page-model/DECISIONS.md +0 -245
- data/.ai-assistance/projects/page-model/TODO.md +0 -190
- data/.ai-assistance/projects/qa-services-delivery/DECISIONS.md +0 -93
- data/.ai-assistance/projects/qa-services-delivery/INTENT.md +0 -76
- data/.ai-assistance/projects/qa-services-delivery/PHASE3-SCOPE.md +0 -115
- data/.ai-assistance/projects/qa-services-delivery/ROADMAP.md +0 -99
- data/.ai-assistance/projects/qa-services-delivery/TODO.md +0 -81
- data/.ai-assistance/projects/search-filter-builder/INTENT.md +0 -107
- data/.ai-assistance/projects/search-filter-builder/TODO.md +0 -131
- data/.ai-assistance/projects/template-automatic-build-maintenance/INTENT.md +0 -87
- data/.ai-assistance/projects/template-automatic-build-maintenance/TODO.md +0 -108
- data/.ai-assistance/projects/template-diff-deploy/INTENT.md +0 -12
- data/.ai-assistance/projects/template-diff-deploy/TODO.md +0 -9
- data/.ai-assistance/projects/template-maintenance/DESIGN.md +0 -134
- data/.ai-assistance/projects/template-maintenance/PHASE0-FINDINGS.md +0 -93
- data/.ai-assistance/projects/template-maintenance/README.md +0 -14
- data/.ai-assistance/projects/template-model-logic/CATEGORY_CATALOG.md +0 -236
- data/.ai-assistance/projects/template-model-logic/CLASSIFICATION_SPIKE.md +0 -243
- data/.ai-assistance/projects/template-model-logic/DESIGN_NOTE.md +0 -154
- data/.ai-assistance/projects/workflow-space/TODO.md +0 -213
- data/.ai-assistance/reinstall-claude-desktop-windows.md +0 -136
- data/.ai-assistance/scripts/CLAUDE.md +0 -150
- data/.ai-assistance/scripts/bridge-inbox-check.sh +0 -75
- data/.ai-assistance/scripts/bridge-init.sh +0 -86
- data/.ai-assistance/scripts/bridge-status.sh +0 -44
- data/.ai-assistance/scripts/capabilities-check.ts +0 -104
- data/.ai-assistance/scripts/check-outbox.sh +0 -43
- data/.ai-assistance/scripts/dep_graph.rb +0 -91
- data/.ai-assistance/scripts/lock-acquire.sh +0 -103
- data/.ai-assistance/scripts/lock-multi.sh +0 -124
- data/.ai-assistance/scripts/lock-queue.sh +0 -94
- data/.ai-assistance/scripts/setup-mcps.test.ts +0 -188
- data/.ai-assistance/scripts/setup-mcps.ts +0 -234
- data/.ai-assistance/scripts/task-complete.ts +0 -74
- data/.ai-assistance/scripts/task-create.ts +0 -75
- data/.ai-assistance/scripts/task-read.ts +0 -125
- data/.ai-assistance/scripts/token-logger.js +0 -220
- data/.ai-assistance/scripts/token-report.ts +0 -158
- data/.ai-assistance/scripts/token-session-start.js +0 -66
- data/.ai-assistance/skills/ai-instructions/SKILL.md +0 -48
- data/.ai-assistance/skills/code-specs/SKILL.md +0 -69
- data/.ai-assistance/skills/corporate-policies/SKILL.md +0 -201
- data/.ai-assistance/skills/dep-graph/SKILL.md +0 -139
- data/.ai-assistance/skills/ep-ai-manager/SKILL.md +0 -417
- data/.ai-assistance/skills/gemini-assist/SKILL.md +0 -63
- data/.ai-assistance/skills/gemini-assist/gemini-mcp-server.js +0 -205
- data/.ai-assistance/skills/gemini-assist/gemini_ask.py +0 -1
- data/.ai-assistance/skills/gemini-assist/gemini_ask.rb +0 -240
- data/.ai-assistance/skills/gemini-assist/prompts/cycle_end_review.txt +0 -25
- data/.ai-assistance/skills/graphql-schema-analysis/SKILL.md +0 -261
- data/.ai-assistance/skills/procedural-memory/SKILL.md +0 -319
- data/.ai-assistance/skills/project-cycle/SKILL.md +0 -177
- data/.ai-assistance/skills/project-self-docs/SKILL.md +0 -181
- data/.ai-assistance/skills/project-self-docs/scripts/self_docs_scan.py +0 -378
- data/.ai-assistance/skills/refactor/SKILL.md +0 -62
- data/.ai-assistance/skills/rubocop/SKILL.md +0 -93
- data/.ai-assistance/skills/ruby-scripting/SKILL.md +0 -215
- data/.ai-assistance/skills/spec-generation/SKILL.md +0 -72
- data/.ai-assistance/standards-version.json +0 -22
- data/.ai-assistance/token-budget.json +0 -32
- data/.ai-assistance/version.json +0 -39
- data/.claude/settings.json +0 -150
- data/.env.example +0 -18
- data/.gitattributes +0 -15
- data/.gitignore +0 -37
- data/.gitlab-ci.yml +0 -45
- data/.markdownlint.json +0 -4
- data/.rspec +0 -3
- data/.rubocop.yml +0 -121
- data/.ruby-version +0 -1
- data/.yardopts +0 -10
- data/CLAUDE.md +0 -243
- data/Gemfile +0 -30
- data/Rakefile +0 -90
- data/bin/console +0 -14
- data/bin/setup +0 -8
- data/bin/setup.ps1 +0 -6
- data/docs/self-docs/ARCHITECTURE.md +0 -88
- data/docs/self-docs/CHANGES.jsonl +0 -12
- data/docs/self-docs/COMPLIANCE.md +0 -79
- data/docs/self-docs/CONVENTIONS.md +0 -74
- data/docs/self-docs/INTEGRATIONS.md +0 -65
- data/docs/self-docs/OPERATIONS.md +0 -76
- data/docs/self-docs/OVERVIEW.md +0 -64
- data/docs/self-docs/STATUS.md +0 -73
- data/docs/self-docs/self-docs-index.json +0 -51
- data/docs/worklog.md +0 -977
- data/ecoportal-api-graphql.gemspec +0 -40
- data/scripts/auto-worker-scheduler.sh +0 -386
- data/tests/actions_get.rb +0 -7
- data/tests/contractor_entities_get.rb +0 -20
- data/tests/contractor_entity_create.rb +0 -19
- data/tests/contractor_entity_udpate.rb +0 -20
- data/tests/dump_page_model.rb +0 -74
- data/tests/dump_template_model.rb +0 -90
- data/tests/loc_structure_get.rb +0 -10
- data/tests/loc_structure_update.rb +0 -51
- data/tests/loc_structures_get.rb +0 -15
- data/tests/local_libs.rb +0 -20
- data/tests/validate_queries.rb +0 -127
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
# Cutover gap audit — 3 use cases on GraphQL (TODO 8.5)
|
|
2
|
-
|
|
3
|
-
## Update — 2026-06-29
|
|
4
|
-
|
|
5
|
-
> Status refresh after the WRITE/value/submit path went **live-green** on `mini`. The full
|
|
6
|
-
> mini automated suite now runs **35/35**. Several items the 2026-06-28 audit listed as gaps
|
|
7
|
-
> or "coded-but-untested" are now RESOLVED and live-validated. History below is preserved;
|
|
8
|
-
> read the per-use-case lines together with this block.
|
|
9
|
-
|
|
10
|
-
**RESOLVED since the 2026-06-28 audit:**
|
|
11
|
-
- **Field value round-trips (TODO 8.1) — DONE & LIVE-GREEN.** PlainText, Number, Select,
|
|
12
|
-
People (`people_ids`), CrossReference (`page_ids`/`reference_ids`) all round-trip
|
|
13
|
-
(set → `updatePage` → re-read → persisted). The P2 "coded-but-untested array writes"
|
|
14
|
-
(People `<<`, CrossRef `add`/`clear`) are now **validated live** — full mini suite 35/35.
|
|
15
|
-
- **`submit!` / stage completion (TODO 8.2) — DONE & LIVE-GREEN.** Root cause of the old
|
|
16
|
-
stuck-stage failure: the stage carries a **review-task config**, so `completePageTask`
|
|
17
|
-
ALONE moves it to "reviewing" and never advances. Fix =
|
|
18
|
-
`updatePage(submit: true, task: { completePageTask: { signOff: true } })` — the inline
|
|
19
|
-
sign-off auto-approves the review and advances the stage. Gem gained sugar:
|
|
20
|
-
`Input::Page::Update.from_model(complete_page_task: { sign_off:, forced_complete:, notes: })`.
|
|
21
|
-
New test `compat_v2/page/submit_signoff_on_create` passes; old `stage_submit` flipped to the
|
|
22
|
-
confirmed call.
|
|
23
|
-
- **Phased write-path identity (was P0 — "the most important gem fix") — RESOLVED & validated**
|
|
24
|
-
via `compat_v2/page/stage_write`: a value set through `stage.components` now persists through
|
|
25
|
-
`updatePage`. The `stage.components` vs flat `page.field_collection` dup'd-doc risk is closed.
|
|
26
|
-
- **`get_by_name(type:)` — DONE** (2026-06-28).
|
|
27
|
-
- **FilterTranslator `text_filter`→`match_filter`, `options_filter`→`one_of`/`none_of` — LANDED**
|
|
28
|
-
(commit 7725f96). Reclassified from a **code gap** to a **validation item**: still needs LIVE
|
|
29
|
-
validation against a real `registers.search` (see 8.3 below). Not a blocker for the translator
|
|
30
|
-
existing.
|
|
31
|
-
|
|
32
|
-
**STILL OUTSTANDING (carry forward):**
|
|
33
|
-
- **BasicPage reads (TODO 8.4)** — `CommonPageUnion` lacks `... on BasicPage { sections }`,
|
|
34
|
-
so basic pages get `corePageData` only. **IN PROGRESS** on branch `cutover/basicpage-sections`.
|
|
35
|
-
- **Live-validate translated text/options filters (TODO 8.3)** — confirm `match_filter` /
|
|
36
|
-
`one_of`/`none_of` against a real `registers.search` on `mini`.
|
|
37
|
-
- **Gem RSpec read-path regression specs (TODO 8.6)** — **IN PROGRESS** on branch
|
|
38
|
-
`cutover/regression-specs-8-6`.
|
|
39
|
-
- **Collection-level write review (TODO 8.7)** — add/remove/reorder fields, multi-section
|
|
40
|
-
identity; deferred from the phased-flatten work.
|
|
41
|
-
- **eco-helpers** — farmers must `include OozeRedirect` (else hits the dead v2 server);
|
|
42
|
-
`submit!` must pass `stageId` + map `force:` → `forced_complete:` (the gem now supports
|
|
43
|
-
`forced_complete:`; eco-helpers draft in progress).
|
|
44
|
-
- **cans dedup rework** — membranes previews carry no field values (customer script).
|
|
45
|
-
- **Release/pin the `pages` branch — HARD PREREQUISITE.** Released 1.3.4 lacks `base/page/`;
|
|
46
|
-
FieldPatches silently no-op against it.
|
|
47
|
-
|
|
48
|
-
---
|
|
49
|
-
|
|
50
|
-
> Audited 2026-06-28 (background pass). Gem `pages` branch + eco-helpers OozeRedirect.
|
|
51
|
-
> Two compat layers: the **gem** (`Compat::Pages`/`Registers` + native `DataField` DSL) and
|
|
52
|
-
> **eco-helpers `OozeRedirect`** (`FieldPatches.apply!` monkey-patches the gem field classes
|
|
53
|
-
> to add the v2-API methods `select`/`values`/`options`, CrossRef `add`/`clear`/`reference_ids`,
|
|
54
|
-
> dirty `people_ids <<`, `submit!`, and the v2 `===` dispatch). The v2-API field methods come
|
|
55
|
-
> from FieldPatches, NOT the gem. Memory: [[project-apiv2-cutover-usecases]].
|
|
56
|
-
|
|
57
|
-
## Cross-cutting facts (verified)
|
|
58
|
-
- `session.api(version: :oozes)` → `:v2` → **dead v2 server** unless `OozeRedirect#api_v2/apiv2`
|
|
59
|
-
aliases it to `graphql`. Only classes that `include OozeRedirect` get the redirect.
|
|
60
|
-
- `Collection#get_by_name` took **one arg** (no `type:`) — **FIXED 2026-06-28** (added `type:`).
|
|
61
|
-
- **Phased write-path identity risk (HIGH)** — **RESOLVED 2026-06-29** (see Update block).
|
|
62
|
-
*Original concern:* `DataField.new`/`Section.new` `.dup` their raw doc; a phased page builds
|
|
63
|
-
TWO independent `DataField::Collection`s (flat `page.field_collection` vs `Stage#components`
|
|
64
|
-
→ `sections.components`), so mutating a field from `stage.components` might not reach the page
|
|
65
|
-
update payload. *Outcome:* `compat_v2/page/stage_write` confirms a value set via
|
|
66
|
-
`stage.components` now persists through `updatePage`. cans + toocs `with_fields` writes reach
|
|
67
|
-
the payload.
|
|
68
|
-
|
|
69
|
-
## Per-use-case status
|
|
70
|
-
**farmers / supplier_documents** (`Custom::UseCase`, **no OozeRedirect**, no stages):
|
|
71
|
-
- 🔴 `api_v2 = session.api(version: :oozes)` → dead v2 server (no redirect). **Biggest gap** —
|
|
72
|
-
`include OozeRedirect` or switch to `session.api(version: :graphql)`. Despite the old "do
|
|
73
|
-
FIRST / most compat-friendly" note, farmers is the **least ready** (bypasses OozeRedirect).
|
|
74
|
-
- 🟠 `options_filter` → `one_of`/`none_of` now **translated** in FilterTranslator (commit 7725f96);
|
|
75
|
-
needs LIVE validation against a real `registers.search` (8.3).
|
|
76
|
-
- 🔴 Select `.values`/`.select`, CrossRef `.add` — FieldPatches-only; won't load for a
|
|
77
|
-
non-OozeRedirect class → NoMethodError.
|
|
78
|
-
- ✅ (now) `get_by_name(..., type:)` — gem fix landed.
|
|
79
|
-
- ✅ `registers.search` date_filter, `pages.get`/`get_new`/`create`/`update` (flat).
|
|
80
|
-
- ✅ Field value round-trips (PlainText/Number/Select/People/CrossRef) — LIVE-GREEN 2026-06-29.
|
|
81
|
-
|
|
82
|
-
**jamestrong / cans_upsert** (`OozeSamples::TargetOozesUpdateCase`, includes OozeRedirect, phased 'Details'):
|
|
83
|
-
- 🟠 `text_filter` → `match_filter` now **translated** (commit 7725f96); needs LIVE validation (8.3).
|
|
84
|
-
- 🔴 dedup via `page_result.membranes` — previews carry no field values; rework to fetch full
|
|
85
|
-
page per candidate or server-side filter.
|
|
86
|
-
- 🟠 `submit!` sent with no `stageId` (script submits a specific stage) — eco-helpers must pass
|
|
87
|
-
`stageId`; draft in progress. (Stage *completion* mechanics now confirmed — see ✅.)
|
|
88
|
-
- ✅ **phased write-path identity** — RESOLVED 2026-06-29 (`stage.components` writes persist via
|
|
89
|
-
`updatePage`; `compat_v2/page/stage_write`).
|
|
90
|
-
- ✅ `submit!`/stage completion mechanics — confirmed 2026-06-29:
|
|
91
|
-
`updatePage(submit: true, task: { completePageTask: { signOff: true } })` advances a
|
|
92
|
-
review-task stage (`compat_v2/page/submit_signoff_on_create`).
|
|
93
|
-
- ✅ search query, stage lookup, v2 `===` dispatch, PlainText/Number `value=`, Select
|
|
94
|
-
`select`/`values`/`options` (live-validated).
|
|
95
|
-
|
|
96
|
-
**act-gov / toocs_coding** (`OozeSamples::TargetOozesUpdateCase`, includes OozeRedirect, phased 'Coding'):
|
|
97
|
-
- ✅ People `people_ids <<` + CrossRef `add`/`clear` — **VALIDATED LIVE 2026-06-29** (the
|
|
98
|
-
previously-skipped array writes; full mini suite 35/35).
|
|
99
|
-
- 🟠 `submit!(force: true)` — gem now supports `forced_complete:` (via
|
|
100
|
-
`from_model(complete_page_task: { forced_complete: })`); eco-helpers still needs to map
|
|
101
|
-
`force:` → `forced_complete:` and pass `stageId`. Draft in progress.
|
|
102
|
-
- ✅ **phased write-path identity** — RESOLVED 2026-06-29 (same fix as cans; `stage_write`).
|
|
103
|
-
- ✅ v2 `===` (People/CrossRef), CrossRef `reference_ids`/`clear`, stage lookup.
|
|
104
|
-
|
|
105
|
-
## Prioritized remaining work
|
|
106
|
-
|
|
107
|
-
> Re-prioritized 2026-06-29. The old P0 gem blockers (phased write-path identity, value
|
|
108
|
-
> round-trips, submit!/stage advance) are RESOLVED & live-green. What remains is mostly
|
|
109
|
-
> validation, eco-helpers/script wiring, and the release gate.
|
|
110
|
-
|
|
111
|
-
**P0 (blockers):**
|
|
112
|
-
1. **Release/pin `pages`** — released 1.3.4 lacks `base/page/`; FieldPatches silently no-op.
|
|
113
|
-
**HARD PREREQUISITE** for everything downstream.
|
|
114
|
-
2. **farmers** — wire `include OozeRedirect` (or `session.api(version: :graphql)`) so it stops
|
|
115
|
-
hitting the dead v2 server. (script/eco-helpers)
|
|
116
|
-
|
|
117
|
-
**P0 — RESOLVED 2026-06-29 (kept for history):**
|
|
118
|
-
- ✅ **Phased write-path identity** — `stage.components` mutations now reach `updatePage`
|
|
119
|
-
(cans+toocs); validated `compat_v2/page/stage_write`. Was "most important gem fix".
|
|
120
|
-
- ✅ **Field value round-trips (8.1)** — PlainText/Number/Select/People/CrossRef live-green.
|
|
121
|
-
- ✅ **`submit!`/stage completion (8.2)** — review-task stage advances via inline sign-off.
|
|
122
|
-
|
|
123
|
-
**P1 (functional gaps / validation):**
|
|
124
|
-
3. ✅ `Collection#get_by_name(type:)` — DONE 2026-06-28.
|
|
125
|
-
4. ✅ `FilterTranslator`: `text_filter`→`match_filter`, `options_filter`→`one_of`/`none_of`
|
|
126
|
-
— LANDED 2026-06-29 (commit 7725f96). **Now a validation item, not a code gap:** LIVE-validate
|
|
127
|
-
against a real `registers.search` (8.3). `compat/filter_translator.rb`.
|
|
128
|
-
5. **BasicPage reads (8.4)** — add `... on BasicPage { sections }` to `CommonPageUnion`.
|
|
129
|
-
IN PROGRESS on branch `cutover/basicpage-sections`.
|
|
130
|
-
6. **Gem RSpec read-path regression specs (8.6)** — IN PROGRESS on branch
|
|
131
|
-
`cutover/regression-specs-8-6`.
|
|
132
|
-
7. **Collection-level write review (8.7)** — add/remove/reorder fields, multi-section identity.
|
|
133
|
-
8. cans dedup rework (membranes → full-page fetch / server-side filter). (script)
|
|
134
|
-
9. eco-helpers `submit!` — pass `stageId` + map `force:` → `forced_complete:` (gem supports it).
|
|
135
|
-
Draft in progress.
|
|
136
|
-
|
|
137
|
-
**P2 (validate coded-but-untested):** ✅ People `<<` + CrossRef `add`/`clear` array writes
|
|
138
|
-
— VALIDATED LIVE 2026-06-29 (mini suite 35/35). Remaining P2 validation = search filters
|
|
139
|
-
live (8.3, folded into P1#4 above).
|
|
@@ -1,244 +0,0 @@
|
|
|
1
|
-
# GraphQL COMPAT Layer Audit — contract fidelity vs ecoportal-api-v2
|
|
2
|
-
|
|
3
|
-
> READ-ONLY audit. No code changed, no git touched. Date: 2026-07-08.
|
|
4
|
-
> Scope: every place the GraphQL gem re-expresses a v2 public API, measured against the
|
|
5
|
-
> v2 contract as source of truth. Consumers surveyed: `multi_org_api/*/config/ooze_cases`,
|
|
6
|
-
> eco-helpers `usecases/graphql` + `OozeRedirect` + `ooze_samples`.
|
|
7
|
-
|
|
8
|
-
---
|
|
9
|
-
|
|
10
|
-
## 1. Executive verdict — AD-HOC PATCH, not a faithful mirror
|
|
11
|
-
|
|
12
|
-
Oscar is **right**. The compat layer is a set of reactive, per-symptom patches, not a
|
|
13
|
-
contract-faithful mirror of the v2 API. Concrete evidence:
|
|
14
|
-
|
|
15
|
-
1. **Same method, three different return-type decisions, no shared contract.** `get_by_name`
|
|
16
|
-
is a COLLECTION in v2 for components, forces, and bindings, but a SINGLE for stages. The
|
|
17
|
-
gem got forces (`base/force/collection.rb:16` → `select`), bindings
|
|
18
|
-
(`base/force/binding_collection.rb:19` → `select`), and stages
|
|
19
|
-
(`compat/stage_collection.rb:34` → `find`, correct) right — but got **components wrong**
|
|
20
|
-
(`base/page/data_field/collection.rb:35` → `find`) and **sections' `get_by_heading` wrong**
|
|
21
|
-
(`base/page/section_collection.rb:31` → `find`, v2 is `select`). Three files, four
|
|
22
|
-
independent return-type choices. A faithful mirror would have one rule per v2 method; this
|
|
23
|
-
has ad-hoc choices that happen to match in some files and not others.
|
|
24
|
-
|
|
25
|
-
2. **The downstream consumer already contains a workaround for the gem's wrong return type.**
|
|
26
|
-
eco-helpers `OozeRedirect#with_fields` wraps the component lookup:
|
|
27
|
-
`[collection.get_by_name(label)].compact` (`ooze_redirect.rb:187`) — i.e. it treats
|
|
28
|
-
`get_by_name` as returning a SINGLE and re-wraps it into an array to fake the v2 collection
|
|
29
|
-
contract. That is a patch compensating for a patch. When the gem is made faithful (returns a
|
|
30
|
-
collection), this line double-wraps → `[[Field]]`. Whack-a-mole in the flesh.
|
|
31
|
-
|
|
32
|
-
3. **Two conflicting `#components` definitions on the same object.** `Concerns::PageCompat#components`
|
|
33
|
-
returns `dataFields || []` (`page_compat.rb:22`); `Concerns::DataFieldAccess#components`
|
|
34
|
-
returns `field_collection` (`data_field_access.rb:22`). Both are `include`d in
|
|
35
|
-
`Interface::BasePage` (`base_page.rb:6-7`), DataFieldAccess second so it wins — but the dead
|
|
36
|
-
PageCompat version returning a raw array is a fossil of an earlier, incompatible attempt.
|
|
37
|
-
|
|
38
|
-
4. **Methods the v2 contract guarantees are simply absent** (not deliberately dropped —
|
|
39
|
-
nobody enumerated the contract): `DataField::Collection` has no `get_by_id`, no
|
|
40
|
-
`get_by_type` returning a `reference?`-style API, no `unattached`/`multi_section`;
|
|
41
|
-
`SectionCollection` has no `get_by_id`, no `ordered`-by-weight, no `between`. Consumers call
|
|
42
|
-
`components.get_by_id` and `sections.get_by_id` today (§3).
|
|
43
|
-
|
|
44
|
-
5. **`components.add` has different semantics** — v2 `upsert!`s into the live collection so a
|
|
45
|
-
later `get_by_name` finds it; the gem stashes into a private `@additions` array
|
|
46
|
-
(`collection.rb:53-60`) that `each`/`get_by_name` never see.
|
|
47
|
-
|
|
48
|
-
The through-line: each method was added when a specific script broke, choosing whatever return
|
|
49
|
-
shape that one script needed — never derived from the v2 method's documented contract. That is
|
|
50
|
-
the definition of ad-hoc.
|
|
51
|
-
|
|
52
|
-
---
|
|
53
|
-
|
|
54
|
-
## 2. Divergence catalog
|
|
55
|
-
|
|
56
|
-
Severity: **S1** = silent wrong result / breaks live consumers; **S2** = raises / missing method;
|
|
57
|
-
**S3** = latent (no current consumer but contract-divergent).
|
|
58
|
-
|
|
59
|
-
| # | Method | v2 contract (file:line) | gem compat (file:line) | Divergence | Sev | Affected consumers |
|
|
60
|
-
|---|--------|-------------------------|------------------------|------------|-----|--------------------|
|
|
61
|
-
| C1 | `components.get_by_name(name, type:)` | `select` → **Array** (`v2/page/components.rb:37`) | `find` → **single DataField** (`base/page/data_field/collection.rb:35`) | Return type: collection vs single | **S1** | act-gov `.first`/`.last`, farmers `.first`, and ~120 `components.get_by_name(...).first` call-sites across multi_org_api (twg, tng, briscoes, alexander, argenta, whittlesea…); eco-helpers `ooze_redirect.rb:184,187` |
|
|
62
|
-
| C2 | `sections.get_by_heading(h, mild:)` | `ordered.select` → **Array** (`v2/page/sections.rb:61`) | `find` → **single Section** (`base/page/section_collection.rb:31`) | Return type + drops `mild:` + no weight-ordering | **S1** | `tng_env_update_case.rb:19` (`.get_by_heading("Details").first`) |
|
|
63
|
-
| C3 | `components.get_by_id(id)` | `find` → single (`v2/page/components.rb:21`) | **absent** on `DataField::Collection` | Missing method → `NoMethodError` | **S2** | `event_changes_case.rb:50` (`components.get_by_id(fld.reference_id)`); eco-helpers `ooze_update_case.rb:10` |
|
|
64
|
-
| C4 | `sections.get_by_id(id)` | `find` → single (`v2/page/sections.rb:46`) | **absent** on `SectionCollection` | Missing method → `NoMethodError` | **S2** | `TnG_Active_sitefix_part2_case.rb:106` |
|
|
65
|
-
| C5 | `components.add(...)` | `upsert!` into live collection; found by later `get_by_name`/`each` (`v2/page/components.rb:53`) | stashes in private `@additions`; NOT in `@fields`; later `get_by_name`/`each` miss it (`collection.rb:53-60`) | Mutation semantics diverge | S2 | any multi-step add-then-read script; `add` kwargs also differ (`id:` required, `doc:` shape) |
|
|
66
|
-
| C6 | `sections.get_by_type(t)` | `ordered.select` → Array (`v2/page/sections.rb:53`) | `select` → Array but **not weight-ordered** (`section_collection.rb:25`) | Ordering: v2 orders by weight, gem uses response order | S3 | ordering-sensitive section scripts (latent) |
|
|
67
|
-
| C7 | `components.get_by_type(t)` | `select` → Array, no ordering (`v2/page/components.rb:28`) | `select` → Array (`collection.rb:27`) | **Match** (return type) | ok | argenta `remove_edit_events_case.rb:21,29` (uses `.select` on result — works only because both are Arrays) |
|
|
68
|
-
| C8 | `forces.get_by_name(name)` | `select` → Array (`v2/page/forces.rb:36`) | `select` → Array (`base/force/collection.rb:16`) | **Match** | ok | all `forces.get_by_name(...).first` sites |
|
|
69
|
-
| C9 | `force.bindings.get_by_name(name, type:)` | `select` → Array (`v2/page/force/bindings.rb:102`) | `select` → Array but **drops `type:` kwarg** (`binding_collection.rb:19`) | Partial: arity narrower | S3 | bindings callers pass name only today; `type:` unused |
|
|
70
|
-
| C10 | `stages.get_by_name(name)` | `find` → single (`v2/page/stages.rb:17`) | `find` → single (`compat/stage_collection.rb:34`) | **Match** | ok | eco-helpers `ooze_base_case.rb:109,144`, `register_export_case.rb:137` |
|
|
71
|
-
| C11 | `stages[id_or_name]` | v2 CollectionModel `[]` by key (id) | id **or** name (`stage_collection.rb:27-30`) | Superset (name-fallback) — benign but non-contract | S3 | eco-helpers `stages[id] || stages.get_by_name` (belt-and-braces) |
|
|
72
|
-
| C12 | `forces.get_by_id`, `.ordered`, `.bindings_by_reference` | present (`v2/page/forces.rb:29,64,20`) | **absent** on gem `Force::Collection` | Missing methods | S3 | not called by surveyed consumers (latent) |
|
|
73
|
-
| C13 | `bindings.get_by_id / get_by_type / get_by_reference / reference? / by_name / by_reference` | present (`v2/page/force/bindings.rb:82,92,68,61,26,42`) | **absent** on gem `BindingCollection` | Missing methods | S3 | not called by surveyed consumers (latent) |
|
|
74
|
-
| C14 | `sections.ordered` (by weight) | `sort_by weight` (`v2/page/sections.rb:86`) | returns `@sections` as-is (`section_collection.rb:41`) | Ordering not applied | S3 | latent |
|
|
75
|
-
| C15 | `page.components` (page-level) | v2 components collection | **two conflicting defs**: PageCompat returns `dataFields`/`[]` array (`page_compat.rb:22`), DataFieldAccess returns `Collection` (`data_field_access.rb:22`); include order (`base_page.rb:6-7`) makes DataFieldAccess win, PageCompat one is dead code | Latent footgun / dead code | S2 | any refactor reordering includes silently swaps behaviour |
|
|
76
|
-
| C16 | `entry.components.get_by_name(...).detect{…}` | Array#detect works on v2 collection | gem returns single → `.detect` = `Enumerable#detect` on a **DataField** (iterates its doc?) | Return-type breakage | **S1** | `risks_migration_case.rb:89` (`.get_by_name("Review frequency:").detect{…}`) |
|
|
77
|
-
| C17 | `force.bindings.get_by_name(x).empty?` | Array#empty? | gem Array → ok (C8/C9 correct) | ok | tng `tng_env_update_case.rb:112` |
|
|
78
|
-
|
|
79
|
-
### Folded-in prior findings (verified against current code)
|
|
80
|
-
|
|
81
|
-
These are not `get_by_name`-style return-type bugs but are part of the same "compat built ad hoc"
|
|
82
|
-
thread — the read/write CONVERTER contract was never systematically mirrored. Cross-referenced
|
|
83
|
-
against `.ai-assistance/code/model_input_mapping/SYNTHESIS.md` (2026-07-07). **Note:** SYNTHESIS
|
|
84
|
-
marks several as FIXED on `feature/model-input-fixes` (current branch); status below reflects that.
|
|
85
|
-
|
|
86
|
-
| # | Prior finding | Current status (verified) | File:line |
|
|
87
|
-
|---|---------------|---------------------------|-----------|
|
|
88
|
-
| P1 | `passarray`/`embeds_many` don't diff via `as_update` (otherTags, locations, filterTags) | **FIXED** — `DIFF_CLASS = Diffable::LeafDiffService` now on `Interface::BasePage` | `interface/base_page.rb:13` |
|
|
89
|
-
| P2 | `IdDiff` set-diff machinery non-functional (ContractorEntity/Action) | Reported FIXED via `id_diff_fields` macro (SYNTHESIS §3.2); **not re-verified in this pass** — flagged for confirm | — |
|
|
90
|
-
| P3 | File/Image/Contractor readers use write-key → `[]` | Reported FIXED (SYNTHESIS §3.3); Image fragment `images[].id` was the blocker | `base/page/data_field/{file_field,image_gallery,contractor_entities}.rb` |
|
|
91
|
-
| P4 | DataField read-key ≠ write-key (shape asymmetry) | Partly FIXED (CrossReference was template); File/Image/Contractor per P3 | `.ai-assistance/code/refactoring/datafield-readwrite-shape-asymmetry.md` |
|
|
92
|
-
| P5 | `SnakeCamelAccess` is a one-way method_missing shim, no specs | **STILL TRUE** — `concerns/snake_camel_access.rb`; no spec file exists (`Glob spec/**/snake_camel*` → none). One-way (snake→camel only); silently no-ops single-word methods (`parts.length < 2` → returns as-is) | `concerns/snake_camel_access.rb:50-54` |
|
|
93
|
-
|
|
94
|
-
---
|
|
95
|
-
|
|
96
|
-
## 3. Comprehensive fix plan (contract-faithful) + spec risk
|
|
97
|
-
|
|
98
|
-
The organising principle: **derive each collection method from the v2 method it mirrors, not from
|
|
99
|
-
the one script that broke.** Recommend a small shared helper module so components/sections/forces/
|
|
100
|
-
bindings collections share one contract per method name.
|
|
101
|
-
|
|
102
|
-
### Fix C1 — `DataField::Collection#get_by_name` → collection (`select`)
|
|
103
|
-
|
|
104
|
-
Faithful fix: return `pool.select { … }` (mirror `v2/page/components.rb:37`), keeping `type:`.
|
|
105
|
-
|
|
106
|
-
**Risks these EXISTING gem specs (they assume single return):**
|
|
107
|
-
- `spec/.../base/page/data_field_spec.rb:397-399` — `coll.get_by_name('name').id` → must become `.first.id`
|
|
108
|
-
- `data_field_spec.rb:408` — `coll.get_by_name('Name').value = 'Bob'` → `.first.value =`
|
|
109
|
-
- `data_field_spec.rb:419` — same
|
|
110
|
-
- `data_field_spec.rb:463` — `field = coll.get_by_name('Name')` → `.first`
|
|
111
|
-
- `base/page/phased/stage_spec.rb:72` — `stage.components.get_by_name('Description').value` → `.first.value`
|
|
112
|
-
- `compat/stage_collection_spec.rb:92` — `stage.components.get_by_name('Description').value` → `.first.value`
|
|
113
|
-
- `compat/stage_view_spec.rb:57` — `view.components.get_by_name('Summary').value` → `.first.value`
|
|
114
|
-
- `input/page/update_spec.rb:136` — `page_with_fields.components.get_by_name('Note').value = 'New'` → `.first.value =`
|
|
115
|
-
- `integration/toocs_submit_replay_spec.rb:38` — `page.components.get_by_name('Coding completed by:')` → `.first`
|
|
116
|
-
|
|
117
|
-
These 9 spec sites LOCK IN the wrong behaviour and must be updated in lockstep with the fix
|
|
118
|
-
(add `.first`). They also confirm the gem's own test suite was written to the ad-hoc behaviour,
|
|
119
|
-
not the v2 contract.
|
|
120
|
-
|
|
121
|
-
**Also requires a coordinated eco-helpers change:** `ooze_redirect.rb:184-187` — line 187
|
|
122
|
-
`[collection.get_by_name(label)].compact` must become `collection.get_by_name(label)` (already an
|
|
123
|
-
Array), and line 184-185 `field = collection.get_by_name(label); … [field] : []` must select over
|
|
124
|
-
the collection. This is the cross-repo lockstep the audit brief warns about: a "just remove
|
|
125
|
-
`.first`" workaround in org scripts is itself a dirty patch that re-breaks here.
|
|
126
|
-
|
|
127
|
-
### Fix C2 — `SectionCollection#get_by_heading` → collection (`select`), add `mild:`, order by weight
|
|
128
|
-
|
|
129
|
-
Faithful: `ordered.select { same_string?(s.heading, h, mild: mild) }`. Add a `same_string?`
|
|
130
|
-
helper (case-insensitive; `mild:` = alnum-only compare per v2). Requires §Fix-C14 (`ordered` by
|
|
131
|
-
weight) for exact parity.
|
|
132
|
-
|
|
133
|
-
**Spec risk:** no existing gem spec asserts `get_by_heading` (Grep found none) → **no green
|
|
134
|
-
specs go red.** Add new specs (§4). Consumer `tng_env_update_case.rb:19` already does `.first`, so
|
|
135
|
-
it starts working correctly.
|
|
136
|
-
|
|
137
|
-
### Fix C3 / C4 — add `get_by_id` to `DataField::Collection` and `SectionCollection`
|
|
138
|
-
|
|
139
|
-
`find { |x| x.id == id }` (mirror v2). **No spec risk** (new methods). Add coverage.
|
|
140
|
-
|
|
141
|
-
### Fix C5 — `components.add` upserts into the live collection
|
|
142
|
-
|
|
143
|
-
Faithful: push the built field into `@fields` (or an upsert-by-id) so later `get_by_name`/`each`
|
|
144
|
-
find it, and keep `dirty_additions` sourced from those. **Spec risk:** check `data_field_spec.rb`
|
|
145
|
-
add-section (`:451-465`) — the deletion test reads `get_by_name('Name')` (existing field, fine);
|
|
146
|
-
the add tests assert `dirty_additions` only, so upserting into `@fields` needs a guard that
|
|
147
|
-
`dirty_inputs` (updates) does not double-count additions. Design the split carefully; lock with a
|
|
148
|
-
"add then get_by_name finds it" spec.
|
|
149
|
-
|
|
150
|
-
### Fix C6 / C14 — order `get_by_type`/`ordered` by weight in `SectionCollection`
|
|
151
|
-
|
|
152
|
-
Only if sections carry a weight in the GraphQL doc (verify fragment exposes it; if not, response
|
|
153
|
-
order is the only signal and this stays a documented gap). **No current spec risk.**
|
|
154
|
-
|
|
155
|
-
### Fix C9 / C12 / C13 — fill missing force/binding contract methods + `type:` on bindings
|
|
156
|
-
|
|
157
|
-
Add `get_by_id`, `get_by_type`, `get_by_reference`, `reference?`, `by_name`, `by_reference`,
|
|
158
|
-
`ordered`, `bindings_by_reference`, and honour `type:` in `binding.get_by_name`. These are S3
|
|
159
|
-
(no live consumer) — do them to make the mirror complete, not urgently. **No spec risk.**
|
|
160
|
-
|
|
161
|
-
### Fix C15 — delete the dead `PageCompat#components`
|
|
162
|
-
|
|
163
|
-
Remove `PageCompat#components` (`page_compat.rb:21-24`); it is shadowed and returns the wrong
|
|
164
|
-
shape if include order ever changes. `page_compat_spec.rb:39-43` asserts `components` is a
|
|
165
|
-
`DataField::Collection` — that stays green (DataFieldAccess provides it). **No spec risk.**
|
|
166
|
-
|
|
167
|
-
### Fix P5 — add specs (and ideally make two-way) for `SnakeCamelAccess`
|
|
168
|
-
|
|
169
|
-
At minimum add characterization specs. Consider reusing eco-helpers' polished hash-level
|
|
170
|
-
snake/camel module rather than the bespoke `method_missing` shim (per memory
|
|
171
|
-
`project_snake_camel_access`). Scope decision for Oscar.
|
|
172
|
-
|
|
173
|
-
### Recommended structural change (kills the class of bug)
|
|
174
|
-
|
|
175
|
-
Extract a shared `Concerns::V2CollectionContract` (or a `Base::Page::CollectionModel`) that
|
|
176
|
-
defines `get_by_id` (single), `get_by_name`/`get_by_heading`/`get_by_type` (collection, per v2),
|
|
177
|
-
`ordered`, `same_string?(mild:)` **once**, and have DataField/Section/Force/Binding collections
|
|
178
|
-
include it. This turns "one return-type decision per file" into "one contract, four includes" —
|
|
179
|
-
the actual remedy for the ad-hoc philosophy.
|
|
180
|
-
|
|
181
|
-
---
|
|
182
|
-
|
|
183
|
-
## 4. Test strategy
|
|
184
|
-
|
|
185
|
-
### Gem rspec additions (lock the CONTRACT, not the current behaviour)
|
|
186
|
-
- **Return-type contract specs**, one per collection, asserting `get_by_name`/`get_by_heading`
|
|
187
|
-
return `Array` (C1, C2) and `get_by_id` return a single (C3, C4). Assert `.first` on a
|
|
188
|
-
multi-match returns the first; assert empty match returns `[]` (not nil) for the collection
|
|
189
|
-
methods — this is the exact shape act-gov `.first`/`.last` and farmers `.first` depend on.
|
|
190
|
-
- **Add-then-find spec** (C5): `coll.add(id:…){…}; expect(coll.get_by_name(label)).to include(the added)`.
|
|
191
|
-
- **`mild:` parity spec** for `get_by_heading` (C2).
|
|
192
|
-
- **Cross-object consistency meta-spec:** a single spec that asserts all four collections agree
|
|
193
|
-
on the return type of `get_by_name` (guards against future drift — the root cause here).
|
|
194
|
-
- Update the 9 spec sites listed under Fix-C1 to `.first` in the SAME commit as the fix.
|
|
195
|
-
- Add `SnakeCamelAccess` characterization spec (P5).
|
|
196
|
-
|
|
197
|
-
### eco-helpers spec additions
|
|
198
|
-
- Update `OozeRedirect#with_fields` (`ooze_redirect.rb:184-189`) and add a spec proving it
|
|
199
|
-
returns the same shape (Array) whether the field exists or not, against a faithful collection.
|
|
200
|
-
- Regression spec replaying an act-gov-style `get_by_name(...).first` / `.last` through the
|
|
201
|
-
OozeRedirect path.
|
|
202
|
-
|
|
203
|
-
### Integration coverage (parity harness, training mini-site)
|
|
204
|
-
- On the all-21-fields template mini-org, run the A/B parity harness (memory
|
|
205
|
-
`project_parity_test_plan`): execute one representative ooze case using `.get_by_name(...).first`
|
|
206
|
-
and `.get_by_heading(...).first` against BOTH v2 and GraphQL, assert identical selected field
|
|
207
|
-
IDs and identical emitted mutation input. **Needs live creds** (mini-site API token) — the only
|
|
208
|
-
part of this plan that cannot run in CI without secrets.
|
|
209
|
-
- Replay act-gov `20240130_act_disease_title_update_case.rb` (`.first`+`.last`) and the farmers
|
|
210
|
-
case in `-simulate` mode post-fix to confirm no `.first`-on-single or double-wrap breakage.
|
|
211
|
-
|
|
212
|
-
---
|
|
213
|
-
|
|
214
|
-
## 5. Open questions / could not verify
|
|
215
|
-
|
|
216
|
-
1. **P2/P3 fix status not re-verified.** SYNTHESIS says the IdDiff macro and File/Image/Contractor
|
|
217
|
-
readers were fixed on this branch; I did not re-open those files this pass. Confirm before
|
|
218
|
-
relying on them.
|
|
219
|
-
2. **Section weight in the GraphQL fragment.** C6/C14 (order-by-weight) only achievable if the
|
|
220
|
-
section fragment actually returns a `weight`/ordering field — not confirmed. If absent, response
|
|
221
|
-
order is the contract and these stay documented gaps.
|
|
222
|
-
3. **`components.add` write path.** Whether an added field can even be created via the current
|
|
223
|
-
`dataFields.updates`/additions mutation shape without a server-side `buildFromTemplate` ID is a
|
|
224
|
-
separate question (the collection comment at `collection.rb:47` says it "must reference an
|
|
225
|
-
existing server-side ID"). Faithful `add` semantics may be bounded by the mutation API.
|
|
226
|
-
4. **Full green-suite baseline.** I did not run `bundle exec rspec`; the 9 spec sites are
|
|
227
|
-
identified statically. Run the suite before/after to get exact red counts.
|
|
228
|
-
5. **`get_by_type` ordering for components (C7).** v2 does not order components by weight either,
|
|
229
|
-
so gem matches — but confirm no consumer relies on component order.
|
|
230
|
-
|
|
231
|
-
---
|
|
232
|
-
|
|
233
|
-
## Appendix — files inspected
|
|
234
|
-
|
|
235
|
-
v2 contract: `ecoportal-api-v2/lib/ecoportal/api/v2/page/{components,forces,sections,stages}.rb`,
|
|
236
|
-
`.../page/force/bindings.rb`.
|
|
237
|
-
Gem compat: `lib/.../base/page/data_field/collection.rb`, `.../base/page/section_collection.rb`,
|
|
238
|
-
`.../base/force/{collection,binding_collection,force}.rb`,
|
|
239
|
-
`.../compat/{pages,registers,stage_collection,stage_view}.rb`,
|
|
240
|
-
`.../concerns/{page_compat,data_field_access,snake_camel_access,deprecation}.rb`,
|
|
241
|
-
`.../interface/base_page.rb`.
|
|
242
|
-
Consumers: `multi_org_api/*/config/ooze_cases/*` (grep, ~120 sites),
|
|
243
|
-
`eco-helpers/lib/eco/api/usecases/graphql/compat/ooze_redirect.rb`, `.../ooze_samples/*`.
|
|
244
|
-
Prior findings: `.ai-assistance/code/model_input_mapping/SYNTHESIS.md`.
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
# Project: Dynamic / Auto-generated GraphQL Models
|
|
2
|
-
|
|
3
|
-
**Created:** 2026-06-05
|
|
4
|
-
**Status:** idea — not started
|
|
5
|
-
**Depends on:** `ecoportal-api-v2-doublemodel-review` project (DoubleModel must be stable first)
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## Goal
|
|
10
|
-
|
|
11
|
-
Explore generating the `ecoportal-api-graphql` model layer from the GraphQL schema, rather
|
|
12
|
-
than hand-authoring Ruby classes for every type. Two variants to evaluate:
|
|
13
|
-
|
|
14
|
-
- **Static generation** — run a generator at gem-build time (or as a developer task) that
|
|
15
|
-
produces Ruby source files from schema introspection. Output is committed and readable.
|
|
16
|
-
- **Dynamic generation** — generate model classes at Ruby load time (per execution), from
|
|
17
|
-
the live schema or a cached schema file.
|
|
18
|
-
|
|
19
|
-
---
|
|
20
|
-
|
|
21
|
-
## Motivation
|
|
22
|
-
|
|
23
|
-
The current hand-authored model layer requires manual updates whenever the ecoPortal GraphQL
|
|
24
|
-
schema evolves. Auto-generation would eliminate that maintenance burden and make the client
|
|
25
|
-
automatically up to date with the schema.
|
|
26
|
-
|
|
27
|
-
---
|
|
28
|
-
|
|
29
|
-
## Hard Constraints
|
|
30
|
-
|
|
31
|
-
These are non-negotiable design requirements, arising from how the `ecoportal-api-*` gem
|
|
32
|
-
family is used in practice:
|
|
33
|
-
|
|
34
|
-
### 1. Transparency to the source of backend issues
|
|
35
|
-
|
|
36
|
-
The `ecoportal-api-*` gems are deliberately designed so that when an ecoPortal backend
|
|
37
|
-
returns an unexpected response, the problem is easy to trace — there is static code to
|
|
38
|
-
read and point to. Integration teams and the engineering team both rely on this to avoid
|
|
39
|
-
prolonged debates about whether a bug is client-side or server-side.
|
|
40
|
-
|
|
41
|
-
Any model generation approach must preserve this traceability. Concretely:
|
|
42
|
-
|
|
43
|
-
- A generated (or dynamically created) model class must produce a log entry (at an
|
|
44
|
-
appropriate level) when it encounters a field it did not expect, or when a field it
|
|
45
|
-
expected is absent from the response.
|
|
46
|
-
- Silent field drops, silent type coercions, and silent diff misses are not acceptable.
|
|
47
|
-
- Where auto-generation is used, there must be a deterministic and inspectable record
|
|
48
|
-
of what was generated and from which schema version — ideally committed source files
|
|
49
|
-
for the static variant, or a structured schema-version log for the dynamic variant.
|
|
50
|
-
|
|
51
|
-
### 2. Integration with `ecoportal-api-v2` DoubleModel
|
|
52
|
-
|
|
53
|
-
The `as_update` / `as_input` diff pipeline relies on the `DoubleModel` contract:
|
|
54
|
-
`doc` (current state), `original_doc` (server-confirmed state), `initial_doc` (state
|
|
55
|
-
at render time). Auto-generated models must honour this contract fully — including
|
|
56
|
-
cascaded diff, `root?` / `read_only?` semantics, and `patch_ver` propagation.
|
|
57
|
-
|
|
58
|
-
This is why this project depends on the DoubleModel review being complete first: the
|
|
59
|
-
contract must be stable and well-specified before we try to generate classes that
|
|
60
|
-
implement it.
|
|
61
|
-
|
|
62
|
-
### 3. Render-to-mutation conversion gap
|
|
63
|
-
|
|
64
|
-
GraphQL schema definitions cannot express how a render model converts to a mutation
|
|
65
|
-
input model. This is a permanent gap in the GraphQL specification. Any model generation
|
|
66
|
-
approach must either:
|
|
67
|
-
- Generate the render model only, leaving mutation input classes hand-authored (acceptable),
|
|
68
|
-
- Or provide a deterministic, scriptable convention for deriving mutation input shapes
|
|
69
|
-
from render models — not an AI-generated approximation.
|
|
70
|
-
|
|
71
|
-
Ad-hoc or AI-generated conversion code is not acceptable as the primary mechanism here,
|
|
72
|
-
because it cannot be deterministically verified.
|
|
73
|
-
|
|
74
|
-
---
|
|
75
|
-
|
|
76
|
-
## Open Questions
|
|
77
|
-
|
|
78
|
-
- Static vs dynamic: the dynamic variant is technically more interesting but harder to
|
|
79
|
-
debug when a field silently misroutes a diff. Static generation + commit is more
|
|
80
|
-
transparent. Which is the right default?
|
|
81
|
-
- Can the `DoubleModel` contract be expressed as a generator template robustly enough
|
|
82
|
-
to produce correct `doc` / `original_doc` handling for Array-indexed (CollectionModel)
|
|
83
|
-
paths? This is likely the hardest part.
|
|
84
|
-
- How do we handle schema evolution between gem releases? Version-lock the schema file?
|
|
85
|
-
Validate at load time?
|
|
86
|
-
|
|
87
|
-
---
|
|
88
|
-
|
|
89
|
-
## Out of scope until DoubleModel review is complete
|
|
90
|
-
|
|
91
|
-
Do not begin design or implementation of this project until
|
|
92
|
-
`.ai-assistance/projects/ecoportal-api-v2-doublemodel-review` reaches a stable conclusion
|
|
93
|
-
on the `doc` memoization and sync semantics.
|