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,126 +0,0 @@
|
|
|
1
|
-
# Risks & Blockers — Ooze → Native GraphQL Migration
|
|
2
|
-
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
## BLOCKER (external dependency, UNCONFIRMED): GraphQL forces not yet verified end-to-end
|
|
6
|
-
|
|
7
|
-
**~50% of all ooze cases use forces** (`target.forces`, `force.bindings.{get_by_name,add,
|
|
8
|
-
delete!}`, `force.custom_script`, `force.script`).
|
|
9
|
-
|
|
10
|
-
**Correction (2026-06-30):** the GraphQL force endpoint is NOT simply "missing" — the gem
|
|
11
|
-
already carries client code for BOTH read and mutate:
|
|
12
|
-
- **Read:** `Ecoportal::API::GraphQL::Query::PageWithForces` fetches `page.forces { ...ForceFields }`.
|
|
13
|
-
- **Mutate:** `Mutation::Page::ExecuteForceCommands` → the `executeWorkflowCommands` mutation,
|
|
14
|
-
supporting `editForce { id, customScript }`, `addBinding`, `removeBinding`, `removeForce`
|
|
15
|
-
(plus `addForce`/`reorderForces` `WorkflowCommandInput` variants). So a force WRITE path
|
|
16
|
-
exists via the workflow-command bus — it is **not** read-only at the client layer.
|
|
17
|
-
|
|
18
|
-
What is still UNCONFIRMED (and why this stays a blocker until verified live, not via code-read):
|
|
19
|
-
- `OozeRedirect.force_support?` is hard-wired to return `false`
|
|
20
|
-
(`lib/eco/api/usecases/graphql/compat/ooze_redirect.rb`) — forces are gated OFF.
|
|
21
|
-
- The `ooze_redirect.rb` comment claims `PageWithForces` currently fails schema validation
|
|
22
|
-
(selections on PageUnion; `id` on `DataFieldBinding`/`SectionBinding`; unused `ForceFields`)
|
|
23
|
-
and that the backend is "in progress" — but that note may be STALE given the mutation classes
|
|
24
|
-
now present. **Phase 0 must live-test PageWithForces + a no-op editForce against a real org**
|
|
25
|
-
to establish actual readiness rather than trusting the comment.
|
|
26
|
-
- Activating `ForceCompat` on the mere *existence* of those classes would make **every**
|
|
27
|
-
OozeRedirect case (even non-force ones like TOOCS) fetch via a possibly-broken force query.
|
|
28
|
-
|
|
29
|
-
**Impact:** Force-dependent cases are **held pending the Phase 0 live readiness test** of
|
|
30
|
-
`PageWithForces` + `executeWorkflowCommands`. If that test passes, forces come INTO scope and
|
|
31
|
-
these cases migrate like any other (just with an extra force-command write path). If it fails,
|
|
32
|
-
they are partitioned into the "blocked on forces" table in `INVENTORY.md` and remain on the v2
|
|
33
|
-
path, and the `OozeRedirect` shim cannot be deleted in full until either (a) all blocked cases
|
|
34
|
-
are retired by the customer, or (b) the endpoint is fixed and a follow-up project migrates them.
|
|
35
|
-
|
|
36
|
-
**Blocked-on-forces seed list** (from `ooze_redirect.rb` lines 68–77 — re-verify in Phase 0):
|
|
37
|
-
|
|
38
|
-
| Org | Cases |
|
|
39
|
-
|---|---|
|
|
40
|
-
| act-gov | 5× `20240130_act_*_case`, `rearrage_page_sites_case` |
|
|
41
|
-
| briscoes | `remove_induction_sections`, `310524_Briscoes_Remove_Tasks` |
|
|
42
|
-
| chorus | 4× `audit_update` |
|
|
43
|
-
| hcc | `update_enterprise_risk_case` |
|
|
44
|
-
| lic | `update_life_cycle_force_case` |
|
|
45
|
-
| mitre10 | `rich_text_update`, `update_location_force`, `updating_template` |
|
|
46
|
-
| npdc | `contractor_title_force`, `risk_titile_force`, `fix_title_syncing`, `reminder_date_fields`, `10092024_NPDC_CP_Add_Force` |
|
|
47
|
-
| profile-group | `int_training_review`, `20231026_profile_wellness` |
|
|
48
|
-
| turners-growers | `event_changes`, `inj_cost_calc`, `remove_line_force` |
|
|
49
|
-
| twg | `hide_attached_risks`, `add_new_force` |
|
|
50
|
-
|
|
51
|
-
**Mitigation / trigger:** Phase 0 live-tests `PageWithForces` (read) and a no-op
|
|
52
|
-
`editForce`/`addBinding` via `executeWorkflowCommands` (write) against a real org. If both pass,
|
|
53
|
-
restore a real `force_support?` readiness check, fold forces into the main migration scope, and
|
|
54
|
-
drop this from the blocker list. If either fails, track the fix with Engineering and keep the
|
|
55
|
-
cases above on v2; do not delete `force_compat.rb` or the v2 fallback path that serves them.
|
|
56
|
-
|
|
57
|
-
---
|
|
58
|
-
|
|
59
|
-
## Risk: monkeypatch regressions during coexistence
|
|
60
|
-
|
|
61
|
-
While native and shim coexist, the global `FieldPatches` (v2-class `===`/`is_a?` reopening,
|
|
62
|
-
GraphQL field `prepend`s) remain process-wide. A native case loaded in the same process as
|
|
63
|
-
a shimmed case shares those patches.
|
|
64
|
-
|
|
65
|
-
**Mitigation:** Native cases must not *depend* on the patches (they dispatch on GraphQL
|
|
66
|
-
types directly). Spec the native classes in isolation **without** loading `OozeRedirect`, to
|
|
67
|
-
prove independence. Only retire a given `FieldPatch` once the last case needing it is
|
|
68
|
-
flipped (tracked in DECISIONS.md).
|
|
69
|
-
|
|
70
|
-
---
|
|
71
|
-
|
|
72
|
-
## Risk: silent behavioural divergence (the bug that motivated this)
|
|
73
|
-
|
|
74
|
-
The 2026-06-30 incident (KPIs read 0, dry-run diff suppressed) was a *silent* divergence
|
|
75
|
-
between the shim and the base loop. Native rewrites can re-introduce silent divergence
|
|
76
|
-
(e.g. a KPI counter or dedup edge missed).
|
|
77
|
-
|
|
78
|
-
**Mitigation:** Per-case A/B parity gate against the captured v2 baseline (KPI block + diff)
|
|
79
|
-
is mandatory before flipping. Specs must assert the full KPI set and the dry-run diff shape
|
|
80
|
-
(`get_body(page)['page']`), not just "it ran".
|
|
81
|
-
|
|
82
|
-
---
|
|
83
|
-
|
|
84
|
-
## Risk: BC surface drift (a missed override point)
|
|
85
|
-
|
|
86
|
-
If a native class omits an override point a customer script relies on (e.g. `search`,
|
|
87
|
-
`filters`, `custom_processing`, `excluded_field_hooks`, `paired_fields_post_callback`,
|
|
88
|
-
`to_field`, `before_loading_new_target`), that script breaks — a goal regression.
|
|
89
|
-
|
|
90
|
-
**Mitigation:** Phase 0 `INVENTORY.md` enumerates every override method per consumer
|
|
91
|
-
script. Native classes must expose every one. Re-run each affected live script unchanged as
|
|
92
|
-
the final per-phase check.
|
|
93
|
-
|
|
94
|
-
---
|
|
95
|
-
|
|
96
|
-
## Risk: write-path / field-type gaps in the gem
|
|
97
|
-
|
|
98
|
-
The compat layer has known gaps (from `eco-helpers-compat/INTENT.md`): `add_field` /
|
|
99
|
-
`components.add` (`dataFields.additions`) not implemented; file/image upload unimplemented;
|
|
100
|
-
some field types read-only. A case that needs an unsupported write cannot reach parity.
|
|
101
|
-
|
|
102
|
-
**Mitigation:** The 21-type field matrix (parity plan) classifies clean-write vs partial vs
|
|
103
|
-
read-only. A case requiring a gap is **held** (logged in DECISIONS.md) until the gem closes
|
|
104
|
-
the gap — not flipped. `RegisterMigrationCase` (typed field copy) is the highest-exposure
|
|
105
|
-
case here.
|
|
106
|
-
|
|
107
|
-
---
|
|
108
|
-
|
|
109
|
-
## Risk: interactive prompts in automated runs
|
|
110
|
-
|
|
111
|
-
The base loop reintroduces the v2-faithful `prompt_user` "proceed (y/N)" preview
|
|
112
|
-
(local default 'N', 10s timeout). Native cases reproduce this; an automated/remote run that
|
|
113
|
-
expects no prompt could hang or abort.
|
|
114
|
-
|
|
115
|
-
**Mitigation:** Preserve the existing `run_mode_remote?` → default 'Y' behaviour and the
|
|
116
|
-
timeout exactly as the v2 cases have it. Cover it in specs.
|
|
117
|
-
|
|
118
|
-
---
|
|
119
|
-
|
|
120
|
-
## Risk: scope creep into the compat façade or forces
|
|
121
|
-
|
|
122
|
-
This project retires the **OozeRedirect monkeypatch**, not the `Compat::Pages`/`Registers`
|
|
123
|
-
façade (native cases call it) and not forces.
|
|
124
|
-
|
|
125
|
-
**Mitigation:** Non-goals are explicit in INTENT.md. Forces work is a separate project
|
|
126
|
-
gated on the endpoint.
|
|
@@ -1,261 +0,0 @@
|
|
|
1
|
-
# TODOs — Ooze → Native GraphQL Migration
|
|
2
|
-
|
|
3
|
-
Legend: `[ ]` todo · `[~]` in progress · `[x]` done · `[!]` blocked (see Risks/DECISIONS)
|
|
4
|
-
|
|
5
|
-
Each phase ends with a gate. **Do not flip an old class name to delegate until that
|
|
6
|
-
case's parity result is recorded in DECISIONS.md.**
|
|
7
|
-
|
|
8
|
-
> **STATUS 2026-07-02:** Phase 0 inventory DONE → see `INVENTORY.md`. Scope narrowed by Oscar:
|
|
9
|
-
> **build the native GraphQL classes ONLY this cycle** — no delegation flip, no shim removal yet
|
|
10
|
-
> (those come "long after we know everything works on the native samples"). So Phases 1–2 (native
|
|
11
|
-
> classes + specs) are IN; the flip/removal steps stay `[ ]` until Oscar green-lights.
|
|
12
|
-
|
|
13
|
-
---
|
|
14
|
-
|
|
15
|
-
## Phase 0 — Inventory & Baseline (no code changes) ✅ DONE 2026-07-02 (see INVENTORY.md)
|
|
16
|
-
|
|
17
|
-
### 0a. Map the full ooze case inheritance/include tree
|
|
18
|
-
- [ ] Confirm the inheritance chain (verified 2026-06-30, re-confirm before building):
|
|
19
|
-
- `Common::Loaders::UseCase`
|
|
20
|
-
- `OozeSamples::OozeBaseCase` — `include Helpers`, `include Helpers::Rescuable`
|
|
21
|
-
- `OozeSamples::OozeRunBaseCase` (single-ooze runner)
|
|
22
|
-
- `OozeSamples::OozeUpdateCase`
|
|
23
|
-
- `OozeSamples::OozeFromDocCase`
|
|
24
|
-
- `OozeSamples::RegisterUpdateCase` — `include Helpers::Creatable`
|
|
25
|
-
- `OozeSamples::TargetOozesUpdateCase` ← **first cutover case** (act-gov TOOCS)
|
|
26
|
-
- `OozeSamples::RegisterMigrationCase` — `include HelpersMigration`
|
|
27
|
-
- `OozeSamples::RegisterExportCase` (standalone — NOT under OozeBaseCase)
|
|
28
|
-
- `OozeCases::ExportRegisterCase` — `include Helpers::ExportableRegister`
|
|
29
|
-
- [ ] Map the helper module surface each case relies on:
|
|
30
|
-
- `OozeSamples::Helpers` aggregate → `Shortcuts`, `Filters`, `OozeHandlers`,
|
|
31
|
-
`Creatable`, `Rescuable`, `ExportableOoze`, `ExportableRegister`
|
|
32
|
-
- `OozeSamples::HelpersMigration` → `Copying`, `TypedFieldsPairing`
|
|
33
|
-
- [ ] For each helper, classify: **v2-coupled** (references
|
|
34
|
-
`Ecoportal::API::V2::Page::*`, e.g. `OozeHandlers#merge_values`, `Shortcuts#object_reference`,
|
|
35
|
-
`Filters#field_key_name`) vs **pure** (string/array utils — `Shortcuts#same_string?`,
|
|
36
|
-
`simplify_string`, `OozeHandlers#merge_arrays`). Pure helpers port verbatim; v2-coupled
|
|
37
|
-
helpers need GraphQL-typed re-expression.
|
|
38
|
-
- [ ] Record which case methods are leaf v2 ops vs control flow (the line that the shim bug
|
|
39
|
-
blurred): control flow = `main`, `with_each_entry`, `update_ooze`, `update_oozes`,
|
|
40
|
-
`process_ooze`, `ooze`, `new_target`, the KPI counters, dry-run feedback. Leaf ops =
|
|
41
|
-
field/stage access, `apiv2.pages.{get,get_new,create,update,get_body}`,
|
|
42
|
-
`apiv2.registers.search`.
|
|
43
|
-
|
|
44
|
-
### 0b. Inventory every downstream script include site (BC surface)
|
|
45
|
-
- [ ] In the training repo (`C:\ruby_scripts\implementation\training`) and any other
|
|
46
|
-
consumer repos, grep for the public names that scripts subclass/include:
|
|
47
|
-
- `OozeSamples::OozeBaseCase`, `OozeRunBaseCase`, `OozeUpdateCase`, `OozeFromDocCase`
|
|
48
|
-
- `OozeSamples::RegisterUpdateCase`, `TargetOozesUpdateCase`, `RegisterMigrationCase`
|
|
49
|
-
- `OozeSamples::RegisterExportCase`, `OozeCases::ExportRegisterCase`
|
|
50
|
-
- `OozeSamples::Helpers::Creatable` and any other helper included directly
|
|
51
|
-
- `GraphQL::Compat::OozeRedirect` (the include line scripts add today)
|
|
52
|
-
- [ ] Produce `INVENTORY.md` in this folder: per public name, list (a) every consumer
|
|
53
|
-
script that subclasses/includes it, (b) which overridable methods that script defines
|
|
54
|
-
(`process_ooze`, `search`, `filters`, `custom_processing`, `excluded_field_hooks`, etc.),
|
|
55
|
-
(c) whether the script touches forces (→ blocked partition).
|
|
56
|
-
- [ ] **Forces live readiness test (decides the partition below).** Do NOT assume forces are
|
|
57
|
-
blocked — the gem ships read (`Query::PageWithForces`) AND write
|
|
58
|
-
(`executeWorkflowCommands`: `editForce`/`addBinding`/`removeBinding`/`removeForce`) client
|
|
59
|
-
code, gated off via `OozeRedirect.force_support? == false`. Against a real org: (a) run
|
|
60
|
-
`PageWithForces` on a force-bearing page and confirm the query is schema-valid + returns
|
|
61
|
-
populated forces; (b) run a no-op `editForce`/`addBinding` via `executeWorkflowCommands` and
|
|
62
|
-
confirm it round-trips. Record the verdict — it determines whether forces are IN scope.
|
|
63
|
-
- [ ] **Partition the inventory into two tables: "migratable now" vs "blocked on forces"**
|
|
64
|
-
— gated on the readiness test above. If forces pass, there is NO blocked partition. If they
|
|
65
|
-
fail, seed the blocked list from `ooze_redirect.rb` lines 68–77 (act-gov, briscoes, chorus,
|
|
66
|
-
hcc, lic, mitre10, npdc, profile-group, turners-growers, twg). This partition is the
|
|
67
|
-
master schedule for Phases 2..N.
|
|
68
|
-
|
|
69
|
-
### 0c. Capture the v2 baseline behaviour (parity reference)
|
|
70
|
-
- [ ] For each migratable case, run the existing v2 path under `-simulate` against the
|
|
71
|
-
`mini` test org and save the dry-run diff + KPI block as the golden reference
|
|
72
|
-
(`baselines/<case>.txt`). This is the A side of every later A/B comparison.
|
|
73
|
-
- [ ] Confirm the A/B parity harness exists / is buildable — see memory
|
|
74
|
-
`project-parity-test-plan` (all-21-field template in `mini`, A/B standalone harness in
|
|
75
|
-
e.g. `mini/graphql_parity/`, plus the eco-helpers session-backend swap). If the harness
|
|
76
|
-
is not yet built, that is a prerequisite sub-task here, not in Phase 2.
|
|
77
|
-
|
|
78
|
-
**Gate 0:** INVENTORY.md complete, partitioned, and baselines captured for the migratable set.
|
|
79
|
-
|
|
80
|
-
---
|
|
81
|
-
|
|
82
|
-
## Phase 1 — Extract shared concerns to `graphql/helpers/pages/*`
|
|
83
|
-
|
|
84
|
-
Goal: build the native shared substrate **before** any case, so case classes stay thin.
|
|
85
|
-
Mirror the existing native helper convention (`graphql/helpers/base/{case_env,graphql_env,
|
|
86
|
-
error_handling}.rb`, `graphql/samples/pages/page/base.rb`).
|
|
87
|
-
|
|
88
|
-
- [ ] `graphql/helpers/pages.rb` — namespace aggregator (mirrors `helpers/location.rb`).
|
|
89
|
-
- [ ] `graphql/helpers/pages/shortcuts.rb` — port the **pure** `OozeSamples::Helpers::Shortcuts`
|
|
90
|
-
methods (`same_string?`, `simplify_string`, `titleize`, `normalize_string`,
|
|
91
|
-
`clean_question`, `to_i`, `is_number?`). Re-express `object_reference` for GraphQL
|
|
92
|
-
page/section/component model types (drop the `Ecoportal::API::V2::*` `case/when`).
|
|
93
|
-
- [ ] `graphql/helpers/pages/filters.rb` — port `Filters`, re-expressing `field_key_name`
|
|
94
|
-
for GraphQL field types (`value.ref_backend` / `value.label` → GraphQL equivalents).
|
|
95
|
-
- [ ] `graphql/helpers/pages/ooze_handlers.rb` — re-express `merge_values` `case/when` against
|
|
96
|
-
`Base::Page::DataField::*` subclasses instead of `V2::Page::Component::*`; `merge_arrays`
|
|
97
|
-
is pure → port verbatim.
|
|
98
|
-
- [ ] `graphql/helpers/pages/rescuable.rb` — port `Rescuable` (validate base type ==
|
|
99
|
-
`GraphQL::Base` instead of `Common::Loaders::Base`).
|
|
100
|
-
- [ ] `graphql/helpers/pages/creatable.rb` — native `Creatable`: `creating_new_page`,
|
|
101
|
-
`drafting_entry` (→ `graphql.pages.get_new`), `create_entry`/`create_ooze`
|
|
102
|
-
(→ `graphql.pages.create`), with dry-run feedback. Base-type guard → native register case.
|
|
103
|
-
- [ ] `graphql/helpers/pages/patch_feedback.rb` — extract the dry-run/dirty machinery that
|
|
104
|
-
the shim bug exposed: `dirty?(page)` (`!as_update.nil?` OR pending submit/sign-off),
|
|
105
|
-
`display_patch` / `backup_patch!` reading `graphql.pages.get_body(page)['page']`,
|
|
106
|
-
`dry_run_feedback` + `DRY_COUNT` sampling. **This is the one-source-of-truth replacement
|
|
107
|
-
for the bug-prone shim-vs-baseloop split.**
|
|
108
|
-
- [ ] Spec each helper module in `spec/eco/api/usecases/graphql/helpers/pages/*_spec.rb`.
|
|
109
|
-
- [ ] `bundle exec rubocop` clean on all new helper files.
|
|
110
|
-
|
|
111
|
-
**Gate 1:** helper specs green; no production case yet depends on them (pure addition).
|
|
112
|
-
|
|
113
|
-
---
|
|
114
|
-
|
|
115
|
-
## Phase 2 — `RegisterUpdateCase` + `Helpers::Creatable` (jamestrong CANS upsert)
|
|
116
|
-
|
|
117
|
-
> Sequenced first alongside Phase 3 because both are exercised in the live cutover and
|
|
118
|
-
> `TargetOozesUpdateCase` **inherits** `RegisterUpdateCase`. Build the parent first.
|
|
119
|
-
|
|
120
|
-
- [ ] Build native `GraphQL::Samples::Pages::Register::Base` (working title) under
|
|
121
|
-
`graphql/samples/pages/register/base.rb`, modelled on the existing
|
|
122
|
-
`graphql/samples/pages/page/base.rb` (KPIs, `each_page`, `update_page`, `simulate?` guard)
|
|
123
|
-
but reproducing the **RegisterUpdateCase** semantics faithfully:
|
|
124
|
-
- batched search via `graphql.registers.search` / `graphql.pages.each(searchConf:)`
|
|
125
|
-
- dedup by page id (`ooze_result_ids`), queue/`enqueue`/`queue_shift` batching
|
|
126
|
-
- full KPI set: total_search / retrieved / non_retrieved / dupped / updated /
|
|
127
|
-
failed_update / attempted_updates / created / create_attempts (match `kpis_message`)
|
|
128
|
-
- `before_loading_new_target` flush-on-requeue behaviour
|
|
129
|
-
- `results_preview` + interactive `prompt_user` proceed (y/N) (v2-faithful)
|
|
130
|
-
- [ ] `include GraphQL::Helpers::Pages::Creatable` + `PatchFeedback` + `Shortcuts`.
|
|
131
|
-
- [ ] **Specs first:** `spec/eco/api/usecases/graphql/samples/pages/register/base_spec.rb`
|
|
132
|
-
— cover KPI counting, dedup, dry-run diff printing, create path, submit/sign-off fold.
|
|
133
|
-
Port the assertions from `spec/.../compat/pages_spec.rb` regression specs where relevant.
|
|
134
|
-
- [ ] **Parity-prove** against the v2 `RegisterUpdateCase` baseline using the A/B harness on
|
|
135
|
-
`mini` (read-only first, then a 1-row CANS-style upsert). Record result in DECISIONS.md.
|
|
136
|
-
- [ ] **Flip the old name:** make
|
|
137
|
-
`Eco::API::UseCases::OozeSamples::RegisterUpdateCase` a thin subclass/delegator of the
|
|
138
|
-
native class (preserve `name 'register-update-case'`, `batch_size`, attr_readers,
|
|
139
|
-
`process_ooze` override point, `main(..., mode: :legacy|:delegate)` signature).
|
|
140
|
-
`OozeSamples::Helpers::Creatable` → delegate to / alias the native `Creatable`
|
|
141
|
-
(keep `validate_base_type!` accepting the native register base).
|
|
142
|
-
- [ ] **Remove shim code for this case:** delete the redirect paths now dead for register
|
|
143
|
-
cases. (Keep `FieldPatches` until the *last* case that needs them is flipped — track in
|
|
144
|
-
DECISIONS.md which patches each flip retires.)
|
|
145
|
-
- [ ] Re-run jamestrong CANS script **unchanged** on `mini`; confirm parity with baseline.
|
|
146
|
-
|
|
147
|
-
**Gate 2:** CANS parity recorded; old `RegisterUpdateCase` name resolves to native; eco-helpers suite green.
|
|
148
|
-
|
|
149
|
-
---
|
|
150
|
-
|
|
151
|
-
## Phase 3 — `TargetOozesUpdateCase` (act-gov TOOCS coding)
|
|
152
|
-
|
|
153
|
-
- [ ] Build native counterpart subclassing the Phase-2 native register base, reproducing
|
|
154
|
-
`TargetOozesUpdateCase`: CSV `target_ids` source, `batched_target_ids`,
|
|
155
|
-
`target_ids_preview` (duplicate detection + proceed prompt), `with_each_entry` over ids.
|
|
156
|
-
- [ ] **Specs first:** id-batching, duplicate detection, requeue-flush, KPI counts,
|
|
157
|
-
cross-reference set + submit (the TOOCS coding shape), dry-run diff.
|
|
158
|
-
- [ ] **Parity-prove** against the v2 `TargetOozesUpdateCase` baseline (act-gov TOOCS,
|
|
159
|
-
1-row CSV) on `mini`. Record in DECISIONS.md.
|
|
160
|
-
- [ ] **Flip the old name** `OozeSamples::TargetOozesUpdateCase` → native subclass.
|
|
161
|
-
- [ ] Remove now-dead shim code for this case.
|
|
162
|
-
- [ ] Re-run act-gov TOOCS script **unchanged**; confirm parity.
|
|
163
|
-
|
|
164
|
-
**Gate 3:** TOOCS parity recorded; old name resolves to native; both live cutover scripts green on native.
|
|
165
|
-
|
|
166
|
-
---
|
|
167
|
-
|
|
168
|
-
## Phase 4 — `OozeBaseCase` / `OozeRunBaseCase` / `OozeUpdateCase` / `OozeFromDocCase` (single-ooze chain)
|
|
169
|
-
|
|
170
|
-
> Single-ooze runners (`options[:source][:ooze_id]`). Lower live-traffic but needed for
|
|
171
|
-
> completeness and as the base several scripts subclass directly.
|
|
172
|
-
|
|
173
|
-
- [ ] Native `GraphQL::Samples::Pages::Ooze::Base` reproducing `OozeBaseCase`
|
|
174
|
-
(target, `process_ooze` block contract, `new_page`/`create_page`, `with_fields`/
|
|
175
|
-
`with_sections`/`with_stage`, dry-run feedback via `PatchFeedback`).
|
|
176
|
-
- [ ] Native single-ooze runner (`OozeRunBaseCase`: `ooze_id`/`stage_id` from options,
|
|
177
|
-
`exit_if_no_changes!`, `prompt_to_confirm!`).
|
|
178
|
-
- [ ] Native `OozeUpdateCase` (`to_field` resolver — drop the v2 `Component`/`Binding`
|
|
179
|
-
branches; resolve via GraphQL `components.get_by_id` / name match).
|
|
180
|
-
- [ ] Native `OozeFromDocCase` (docx table reading is v2-agnostic — port; only the field
|
|
181
|
-
access underneath changes).
|
|
182
|
-
- [ ] Specs for each; parity-prove each single-ooze runner on `mini`.
|
|
183
|
-
- [ ] Flip names `OozeBaseCase` → `OozeRunBaseCase` → `OozeUpdateCase` → `OozeFromDocCase`
|
|
184
|
-
bottom-up; remove dead shim code per flip.
|
|
185
|
-
|
|
186
|
-
**Gate 4:** single-ooze chain on native; names preserved; specs + parity recorded.
|
|
187
|
-
|
|
188
|
-
---
|
|
189
|
-
|
|
190
|
-
## Phase 5 — `RegisterMigrationCase` (+ `HelpersMigration`)
|
|
191
|
-
|
|
192
|
-
> Heaviest helper surface (`copy_pairings`, `copy_generic_paired_fields`,
|
|
193
|
-
> `copy_mapped_fields`, typed-field pairing). Confirm none of the target customer
|
|
194
|
-
> migrations rely on forces before scheduling (Phase 0 partition decides this).
|
|
195
|
-
|
|
196
|
-
- [ ] Port `HelpersMigration::{Copying,TypedFieldsPairing}` to
|
|
197
|
-
`graphql/helpers/pages/migration/*`, re-expressing typed-field copy against GraphQL
|
|
198
|
-
`DataField::*` types (the v2 `Component` type matrix → GraphQL type matrix).
|
|
199
|
-
- [ ] Native `RegisterMigrationCase` subclassing the native register base; reproduce the
|
|
200
|
-
field-maps json loading, `custom_processing`/block contract, `report_*` pairing reports.
|
|
201
|
-
- [ ] Specs (typed copy correctness is the high-risk area — cover each field type's copy).
|
|
202
|
-
- [ ] Parity-prove a real migration on `mini` (src→dst page, diff field-by-field via the
|
|
203
|
-
21-type matrix from the parity plan).
|
|
204
|
-
- [ ] Flip name; remove dead shim code.
|
|
205
|
-
|
|
206
|
-
**Gate 5:** migration parity recorded (field-type matrix); name preserved.
|
|
207
|
-
|
|
208
|
-
---
|
|
209
|
-
|
|
210
|
-
## Phase 6 — Export cases (`RegisterExportCase`, `OozeCases::ExportRegisterCase`)
|
|
211
|
-
|
|
212
|
-
> Read-only (no update path) → safest. `RegisterExportCase` is **not** under `OozeBaseCase`
|
|
213
|
-
> and has its own `ooze`/`stage`/`apiv2` — note `build_full_ooze` stitches all stages into
|
|
214
|
-
> one `PageStage` (a v2-specific merge GraphQL gets for free by fetching the full page).
|
|
215
|
-
|
|
216
|
-
- [ ] Native `GraphQL::Samples::Pages::Register::Export` reproducing `RegisterExportCase`
|
|
217
|
-
(batched search, `build_full_ooze` → simply the full GraphQL PageUnion, no stage stitch).
|
|
218
|
-
- [ ] Port `Helpers::ExportableRegister` / `ExportableOoze` to native (CSV header/values
|
|
219
|
-
generation over GraphQL fields; honour `only_indexed`/`only_labeled`/`only_with_ref`).
|
|
220
|
-
- [ ] Native `ExportRegisterCase` (tags/date-range filters via native `Filters`).
|
|
221
|
-
- [ ] Specs (CSV header + row parity against v2 export of the same register on `mini`).
|
|
222
|
-
- [ ] Flip names; remove dead shim code.
|
|
223
|
-
|
|
224
|
-
**Gate 6:** export CSV byte-parity (or documented intentional diffs) on `mini`.
|
|
225
|
-
|
|
226
|
-
---
|
|
227
|
-
|
|
228
|
-
## Phase 7 — Retire the OozeRedirect shim entirely
|
|
229
|
-
|
|
230
|
-
- [ ] Confirm every **migratable** case is flipped and no migratable consumer still
|
|
231
|
-
`include`s `GraphQL::Compat::OozeRedirect`.
|
|
232
|
-
- [ ] Delete `lib/eco/api/usecases/graphql/compat/ooze_redirect.rb` and the
|
|
233
|
-
`ooze_redirect/{dirty_array,field_patches}.rb` parts **for all retired patches**.
|
|
234
|
-
- [ ] **Keep** `ooze_redirect/force_compat.rb` + the minimal include path **iff** any
|
|
235
|
-
force-blocked case still rides the v2 path and needs it. Otherwise delete too.
|
|
236
|
-
- [ ] Remove the `FieldPatches.apply!` global v2-class reopening (`patch_v2_type_dispatch!`)
|
|
237
|
-
and GraphQL field `prepend`s — these only existed to make v2 `case/when` dispatch work;
|
|
238
|
-
native cases dispatch on GraphQL types directly.
|
|
239
|
-
- [ ] Verify **no customer script edits were needed** against the Phase 0 inventory; any
|
|
240
|
-
script that still references a removed symbol is a defect to fix in this project, not a
|
|
241
|
-
customer change.
|
|
242
|
-
- [ ] Full `bundle exec rspec` green in eco-helpers; gem suite green; rubocop clean.
|
|
243
|
-
- [ ] Update `eco-helpers` CHANGELOG; update memory + this project's status → complete.
|
|
244
|
-
|
|
245
|
-
**Final gate:** shim deleted (modulo the explicitly-documented forces holdout), all names
|
|
246
|
-
preserved, zero script edits, suites green.
|
|
247
|
-
|
|
248
|
-
---
|
|
249
|
-
|
|
250
|
-
## Standing constraints (apply in every phase)
|
|
251
|
-
|
|
252
|
-
- [ ] Specs-first for each native class (parity-proving) — never flip a name before its
|
|
253
|
-
spec suite and recorded parity result exist.
|
|
254
|
-
- [ ] Native class is the **real implementation**; old `OozeSamples::*` name is a thin
|
|
255
|
-
subclass/delegator. **Never reopen/monkeypatch a class to migrate it.**
|
|
256
|
-
- [ ] Preserve every public class name, `name '...'` registration, `type :other`,
|
|
257
|
-
class-level `batch_size`/`register_id`, attr_readers, and documented override points.
|
|
258
|
-
- [ ] Each flip removes the shim code it makes dead — but only retire a `FieldPatch` once
|
|
259
|
-
the last case needing it is flipped (track in DECISIONS.md).
|
|
260
|
-
- [ ] Follow the working-tree safety protocol
|
|
261
|
-
(`.ai-assistance/conventions/code-working-tree-protocol.md`) for every eco-helpers change.
|
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
# Deep review — TOOCS + CANS cutover workflow (2026-06-30)
|
|
2
|
-
|
|
3
|
-
Exhaustive pre-live audit of the two production dry-runs (act-gov TOOCS coding, jamestrong
|
|
4
|
-
CANS upsert) on branch `fix/ooze-redirect-faithful-dryrun`. Goal: trust nothing that "looks
|
|
5
|
-
clean", enumerate every hypothesis (however unlikely), prove/disprove each with code evidence,
|
|
6
|
-
fix what's real, and harden what's latent. Four parallel sub-investigations fed this; verdicts
|
|
7
|
-
and fixes below. All gem fixes are committed with specs; full suite 465/0/2 pending, rubocop clean.
|
|
8
|
-
|
|
9
|
-
## The two dry-run bodies under audit
|
|
10
|
-
|
|
11
|
-
TOOCS (after the stageId fix — now correct):
|
|
12
|
-
```
|
|
13
|
-
{:id=>"6a3225532b97b00073c23aa8", :patchVer=>229,
|
|
14
|
-
:stageId=>"6a3225522b97b00073c22d7d", :submit=>true,
|
|
15
|
-
:task=>{:completePageTask=>{:forcedComplete=>true}},
|
|
16
|
-
:dataFields=>{:updates=>[{:people=>{:id=>"6a3225522b97b00073c22cea",
|
|
17
|
-
:peopleIds=>["65d6d3dcacb0b3000773f547"]}}]}}
|
|
18
|
-
```
|
|
19
|
-
CANS (update-shaped body, but the entry was actually a CREATE — see H8/H-create):
|
|
20
|
-
```
|
|
21
|
-
{:id=>"656e802f2d489c005ad0a6af", :patchVer=>22,
|
|
22
|
-
:dataFields=>{:updates=>[ 5×plainText, 2×number (one =0.0), 1×select ]}}
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
---
|
|
26
|
-
|
|
27
|
-
## Findings table (every hypothesis explored)
|
|
28
|
-
|
|
29
|
-
| # | Hypothesis | Verdict | Action |
|
|
30
|
-
|---|---|---|---|
|
|
31
|
-
| H1 | People `<<` REPLACES (wipes) existing people | **NOT a bug on normal path** — DirtyArray seeds from the read; backend is full-replace but gem sends the full set. | — |
|
|
32
|
-
| H1b | People reader has no fallback → wipe if read returns `peopleIds:null` while `people{id}` nodes exist | **LATENT risk** (real, not active under $content reads) | **FIXED** — reader falls back to `people` nodes |
|
|
33
|
-
| H2 | `peopleIds` is the wrong input key | **NOT a bug** — backend `PeopleInput.people_ids: [ID]`, flat array (not IdDiff). | — |
|
|
34
|
-
| H3 | Number empty CSV cell → `0.0` written over server value | **CONFIRMED footgun** — `"".to_f == 0.0`, no blank guard | **FIXED** — `value=` blank→nil |
|
|
35
|
-
| H4 | Select shape (all options w/ selected flags) wrong | **NOT a bug** — matches `OptionInput{id,selected}`; merge+deselect semantics; sending only-selected would fail to deselect | — |
|
|
36
|
-
| H5 | PlainText `""` clear is unintended | **NOT a bug** — schema String, real clear; dirty vs baseline | — |
|
|
37
|
-
| H6 | Phantom-dirty (PlainText/Number/Select) vs baseline | **NOT a bug** — diff uses `original_doc`; no read/write key asymmetry for these types | — |
|
|
38
|
-
| H7 | Value types wrong (Float/String/Boolean) | **NOT a bug** — match backend input types | — |
|
|
39
|
-
| H8 | CANS upsert mis-routes existing page → create (duplicate risk) | **NOT a bug** — routing by `search_by_id`; the entry genuinely was NOT found → correct CREATE; no duplicate risk | — |
|
|
40
|
-
| H9 | CANS KPIs lie ("Total 0 / Created out of 1 / Updated 0") | **NOT a bug** — numerically correct: 0 existing targets, 1 create attempt, dry-run so 0 created | — |
|
|
41
|
-
| H-create | CANS create dry-run previews as "would **update**" (wrong envelope: draft id+patchVer, no templateId) | **CONFIRMED display bug** — `new_draft?` only checked `patchVer.nil?`, but buildFromTemplate drafts carry a patchVer | **FIXED** — `_compat_source_template_id` marker |
|
|
42
|
-
| H10 | The new stageId guard breaks other ooze cases | **NOT a bug** — only TOOCS+CANS submit on the GraphQL path, both via `with_stage` → stage resolves; metlifecare is pure APIv2 | — |
|
|
43
|
-
| H11 | TOOCS recorded stageId is the wrong stage | **NOT a bug (by construction)** — StageView records the RESOLVED 'Coding' stage id; replay spec asserts it | — (verify id in UI) |
|
|
44
|
-
|
|
45
|
-
---
|
|
46
|
-
|
|
47
|
-
## Confirmed bugs + fixes (all gem, all spec-covered)
|
|
48
|
-
|
|
49
|
-
### 1. Number blank → 0.0 (live-corruption footgun) — `base/page/data_field/number.rb`
|
|
50
|
-
`def value=(numeric); doc['value'] = numeric&.to_f; end` coerces `""` to `0.0` (Ruby `"".to_f`).
|
|
51
|
-
The CANS case assigns `fld.value = row[csv_header]&.strip` with no blank guard, so an empty CSV
|
|
52
|
-
numeric cell wrote a real `0.0`, and the diff (correctly) shipped it over the server value.
|
|
53
|
-
**Fix:** blank (nil / empty / whitespace string) → `nil`, never `0.0`; genuine numbers still
|
|
54
|
-
coerce to Float. Specs: 8 cases (string/Numeric/"0"/""/whitespace/nil/clear-over-value/no-op).
|
|
55
|
-
**Residual:** a non-numeric garbage string (`"abc"`) still `.to_f`→`0.0` — lesser concern, noted.
|
|
56
|
-
**Caller policy:** whether a blank should CLEAR vs be LEFT ALONE is the case's call (TOOCS skips
|
|
57
|
-
blanks for people; CANS does not for numbers) — the gem only guarantees blank ≠ 0.0.
|
|
58
|
-
|
|
59
|
-
### 2. People reader has no node fallback (latent wipe) — `base/page/data_field/people.rb`
|
|
60
|
-
Reader read only `doc['peopleIds']`; if a response ever returned it null/empty while the
|
|
61
|
-
`people{id}` nodes were populated, `people_ids << x` would seed from `[]` and the full-replace
|
|
62
|
-
backend would WIPE the field. **Fix:** fall back to the `people` nodes when `peopleIds` is blank
|
|
63
|
-
(mirrors CrossReference's `references.nodes` fallback). Read key == write key, so no phantom-dirty.
|
|
64
|
-
Specs: fallback read, append-preserves-from-nodes, prefer-peopleIds-when-both-present.
|
|
65
|
-
|
|
66
|
-
### 3. CANS create dry-run mislabel — `compat/pages.rb` + `interface/base_page.rb`
|
|
67
|
-
A `buildPageFromTemplate` draft carries a server patchVer, so `new_draft?` (patchVer-nil only)
|
|
68
|
-
classified it as an update → the create previewed as "would update" with a misleading envelope.
|
|
69
|
-
The read fragment fetches neither `draft` nor `sourceTemplateId`, so neither could be used.
|
|
70
|
-
**Fix:** `Compat::Pages#get_new` records `_compat_source_template_id` (new accessor on
|
|
71
|
-
`Interface::BasePage`); `new_draft?` treats that marker as the authoritative create signal;
|
|
72
|
-
`create_body` uses it for the templateId. Specs: get_new sets marker, marked-draft-with-patchVer
|
|
73
|
-
previews as create (templateId, no patchVer). Affects DRY-RUN ONLY (live create already correct).
|
|
74
|
-
|
|
75
|
-
---
|
|
76
|
-
|
|
77
|
-
## Verified-correct (no action)
|
|
78
|
-
- **People append preserves** existing people (DirtyArray seeds from read; gem sends full set;
|
|
79
|
-
backend `set_people_ids` is full-replace, so sending the full set is exactly right). `peopleIds`
|
|
80
|
-
is the correct flat `[ID]` key (backend `PeopleInput`).
|
|
81
|
-
- **Select** "all options with selected flags" is correct and is the only shape that reliably
|
|
82
|
-
DESELECTS (`SelectBuilder` merges by id; options not sent are untouched).
|
|
83
|
-
- **PlainText `""`** is a legitimate clear; **dirty** baselines on `original_doc` for all three
|
|
84
|
-
scalar/array types; **value types** match backend inputs.
|
|
85
|
-
- **CANS routing**: existing→update, missing→create, decided by `search_by_id`; no duplicate-create.
|
|
86
|
-
The KPIs are numerically correct. (The "would update" wording was the only defect — fixed.)
|
|
87
|
-
- **Guard blast radius**: only TOOCS + CANS submit on the GraphQL path; both via `with_stage`
|
|
88
|
-
(records the active stage) → guard satisfied. metlifecare `resident_events` is pure APIv2.
|
|
89
|
-
|
|
90
|
-
## Backend evidence (from C:\docker\ecoPortal_master, via sub-investigations)
|
|
91
|
-
- `app/graphql/types/fill_in_page/inputs/data_fields/people_input.rb` → `people_ids: [ID]` flat.
|
|
92
|
-
- `app/services/new_ep/pages/assign_attributes_service.rb:175` → `set_people_ids` = full replace.
|
|
93
|
-
- `select_builder.rb` → merge-by-id; deselect requires sending `selected:false`.
|
|
94
|
-
- `{plain_text,number}_input.rb` → `String` / `Float` value types.
|
|
95
|
-
|
|
96
|
-
---
|
|
97
|
-
|
|
98
|
-
## Open questions — RESOLVED / remaining (updated 2026-07-01)
|
|
99
|
-
1. **CANS field `...61` `value=>0.0` — RESOLVED: real zero, not an artifact.** The CANS CSV row
|
|
100
|
-
`FE15TR04715` has `STANDARD COST` = `0` (UNQUOTED literal) → `"0".to_f == 0.0`, correctly sent.
|
|
101
|
-
(`SITE="15"` → `…60 = 15.0`.) Confirmed against `QEST_Components_20260629.csv`. The Number fix
|
|
102
|
-
was never implicated in this value.
|
|
103
|
-
- **Eco::CSV empty-cell behavior (verified, `eco-helpers/lib/eco/csv.rb`):** `Eco::CSV.parse`
|
|
104
|
-
= `{headers: true, skip_blanks: true}` + stdlib `::CSV` with NO `nil_value`/`empty_value`
|
|
105
|
-
override → **unquoted** empty (`,,`) becomes `nil`; **quoted** empty (`""`) stays `""`. The
|
|
106
|
-
feed mixes both (e.g. `CUSTOMER_ITEM=""` → `""` → surfaced as `plainText value:""`). So a
|
|
107
|
-
quoted-empty NUMERIC cell WOULD hit `"".to_f → 0.0` — the Number/Gauge `blank→nil` fix is the
|
|
108
|
-
correct safety net even though this particular row didn't trigger it. ("empties → nil" only
|
|
109
|
-
holds for unquoted empties.) `skip_blanks` skips whole-blank ROWS, not empty cells.
|
|
110
|
-
- **Gauge had the identical footgun** (`numeric&.to_f`) — now fixed the same way. Both Number
|
|
111
|
-
and Gauge route through a single shared `DataField#numeric_or_nil` helper so they can't drift.
|
|
112
|
-
2. **Created CANS pages** unsubmitted (first stage): parked — out of scope for now (Oscar).
|
|
113
|
-
3. **TOOCS stage**: confirm `6a3225522b97b00073c22d7d` is the 'Coding' stage in act-gov (the
|
|
114
|
-
model dump tool can verify against the live page). Non-blocking.
|
|
115
|
-
|
|
116
|
-
## Tooling delivered
|
|
117
|
-
- `tests/dump_page_model.rb` — pulls a page's GraphQL model (CommonPageUnion doc) to JSON,
|
|
118
|
-
before/after a submit, for capturing real fixtures + diffing what a submit changed.
|
|
119
|
-
- `spec/fixtures/pages/toocs_coding_page.json` — TOOCS page fixture (observed ids).
|
|
120
|
-
- `spec/ecoportal/api/graphql/integration/toocs_submit_replay_spec.rb` — replays the case flow,
|
|
121
|
-
asserts the EXACT observed body, and proves the regression (stageless submit raises; stage view
|
|
122
|
-
resolves it).
|