Runsignup connector: field_mappings plumbing for question → Effort routing#2002
Merged
Merged
Conversation
Adds a per-event-Connection JSON column (field_mappings) that the
sync pipeline reads and applies, routing Runsignup question_responses
into the Effort model's comments / emergency_contact / emergency_phone
columns.
Mapping shape:
[
{ source_question_id: 100, destination: "emergency_contact" },
{ source_question_id: 200, destination: "comments",
suppress_when: "No", value_when_present: "First Attempt" },
{ source_question_id: 201, destination: "comments" },
]
- destination: one of comments / emergency_contact / emergency_phone
- suppress_when: skip this mapping when the response equals this string
- value_when_present: use this string instead of the raw response
(only meaningful for comments)
- multiple comments-mapped questions concatenate in mapping order
via ", "
Layers:
- Migration: add_column :connections, :field_mappings, :jsonb,
default: [], null: false.
- Connectors::Runsignup::Request::GetParticipants now passes
include_questions=T so question_responses come back from AWS.
- Connectors::Runsignup::Models::Participant adds :comments,
:emergency_contact, :emergency_phone slots.
- Connectors::Runsignup::FetchEventParticipants accepts a
field_mappings: kwarg, applies it inside participant_from_raw via
a new attributes_from_field_mappings helper.
- Interactors::SyncRunsignupParticipants reads field_mappings off
each per-event runsignup Connection and forwards. The new attrs
are added to RELEVANT_ATTRIBUTES so the sync loop assigns them
onto the Effort.
This is the plumbing PR. UI for race-director-side configuration is
follow-up work; for now the mapping is set via console:
conn = event.connections.from_service(:runsignup).find_by(source_type: "Event")
conn.update!(field_mappings: [...])
Refs: #1998
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The default belongs at the constructor; .perform is just a thin forwarder. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Previously: `cache-version: ${{ env.ImageOS }}-${{ env.ImageVersion }}`.
GitHub Actions' `${{ env.X }}` only resolves workflow-level `env:`
declarations, not runtime environment variables set by the runner —
so this evaluated to a literal `-` (both fragments empty). The intent
was to bust the bundler cache when the runner image rotates so the
smarter_csv native extension gets rebuilt; in practice it busted the
cache exactly once (when the line was first added) and never again.
Today's CI on PR #2002 hit the same SIGILL in smarter_csv's native
parse_context_c that the original fix was meant to prevent.
Capture ImageOS / ImageVersion via a shell step (where they ARE set
by the runner as actual env vars) and reference its outputs as the
cache key. Now image rotations naturally invalidate the cache.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The connector now passes include_questions=T on every participants request so question_responses come back. The four existing cassettes under spec/fixtures/vcr/runsignup/get_participants matched on the full URI and have been updated to include the new param in its alphabetical position (Faraday sorts query params alphabetically on the wire). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Refs #1998. This is the plumbing PR — UI for race-director-side configuration is follow-up.
What it does
Adds a per-event-Connection JSON column (
field_mappings) that the Runsignup sync pipeline reads and applies, routing question responses into the Effort model'scomments/emergency_contact/emergency_phonecolumns.Mapping shape
Stored on
connections.field_mappings(jsonb, defaults to[]):[ { "source_question_id": 100, "destination": "emergency_contact" }, { "source_question_id": 200, "destination": "comments", "suppress_when": "No", "value_when_present": "First Attempt" }, { "source_question_id": 201, "destination": "comments" } ]destination: one ofcomments,emergency_contact,emergency_phone.suppress_when: skip this mapping when the response exactly matches this string.value_when_present: use this string instead of the raw response (mostly relevant for comments — e.g. emit"First Attempt"rather than the literal"Yes").", ".Layers changed
add_column :connections, :field_mappings, :jsonb, default: [], null: falseConnectors::Runsignup::Request::GetParticipantsinclude_questions=Tsoquestion_responsescome back from AWSConnectors::Runsignup::Models::Participant:comments,:emergency_contact,:emergency_phoneslotsConnectors::Runsignup::FetchEventParticipantsfield_mappings:kwarg, applies it via newattributes_from_field_mappingshelperInteractors::SyncRunsignupParticipantsfield_mappingsoff each per-event runsignupConnection, forwards it; new attrs added toRELEVANT_ATTRIBUTESConfiguring a race manually (until UI lands)
Next sync from the connection management page will populate
effort.comments,effort.emergency_contact,effort.emergency_phonefor that event's participants.Out of scope (follow-up PR)
Test plan
spec/lib/connectors/runsignup/fetch_event_participants_spec.rb— 5 new examples covering mapping application, suppress rule, value_when_present override, no-mappings fallback, missing question_responses payload.spec/services/interactors/sync_runsignup_participants_spec.rb— 2 new examples covering field_mappings flow-through and the resulting Effort column writes.🤖 Generated with Claude Code