feat(onboarding): stop writing 'Keep informed' as an Intent - #1060
Merged
Conversation
/subscribe hardcoded intent=Keep informed, a value no form offers as a choice: /join's options are Act now / Volunteer / Lead, and picking none writes None (#1014). So the field carried a value nobody could pick, reading as a choice the person made. Both forms now submit None when no intent was picked. Provenance stays in Signup source, which the CRM already treats as authoritative for these rows. Also collapses the /join fallback's isContinuation arm. That arm was unreachable: the step-2 submit button is disabled while intent is falsy on a continuation, so a continuation cannot be submitted without picking one. Leaving it would keep the only remaining 'Keep informed' writer alive behind a client-side guard, ready to silently re-pollute the field if that guard is ever relaxed. Behaviourally inert. Every consumer treats None and Keep informed identically: chapter_optin (neither is in CHAPTER_OPTIN_INTENTS), the Airtable escalation automation (triggers on Volunteer/Lead), the welcome email (anything not Volunteer/Lead takes the non-volunteer template), and the onboarder alert filters (which read keep_informed). 'Keep informed' stays in INTENTS as a historical value and is never written again. PauseAI/pauseai-civicrm#530 adds None to the CRM's member_intent vocabulary. Closes #1057
Follow-up from review. The prose claimed the value stays "so historical rows typecheck", which is wrong twice over: INTENTS never sees stored Airtable rows, and the list is the server's accepted-POST allowlist (isIntent in embed/onboarding-form/+page.server.ts). So 'Keep informed' is not merely vestigial, it is still accepted from a post; dropping it from INTENTS would start rejecting one. No form emits it, which is the claim that actually holds.
✅ Deploy Preview for pauseai ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
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.

Closes #1057. Supersedes #1059, which GitHub closed non-reopenably when #1014 merged and its branch was deleted; these are the same two commits cherry-picked onto
main, and #1014'sNonevalue is now inmainas9289abc2./subscribehardcodedintent=Keep informed, a value no form offers as a choice./join's options are Act now / Volunteer / Lead, and since #1014 picking none writesNone. So the field carried a value nobody could pick, which reads as a choice the person made.The change
Both forms now submit
Nonewhen the person picked no intent.Intentthen means exactly one thing: which of the offered options they picked, or none. Provenance stays inSignup source(June 2026 subscribe form), which the CRM already treats as authoritative for these rows.Three lines plus the docs:
SubscribeFlow.svelte: the hidden input writesNone.OnboardingFlow.svelte: collapses theisContinuationarm of the/joinfallback (see below).options.ts+docs/join-form-flow.md: prose that described the old split.Why the continuation arm goes too
#1014 writes
intent ? INTENT_VALUES[intent] : isContinuation ? 'Keep informed' : 'None'. ThatisContinuationarm is unreachable: the step-2 submit button carriesdisabled={(isContinuation ? !intent : ...)}, so a continuation cannot be submitted whileintentis falsy, and the fallback only evaluates when it is falsy.Dropping it is therefore behaviourally inert today. It is worth doing because it would otherwise be the last remaining
Keep informedwriter in the codebase, guarded only by a client-sidedisabledattribute. If that guard is ever relaxed,Keep informedwrites resume silently and nothing reports it, since the value stays deliberately valid in the CRM vocabulary for historical rows.Behaviourally inert
Every consumer treats
NoneandKeep informedidentically, so this changes analytics semantics only:chapter_optin()— neither value is inCHAPTER_OPTIN_INTENTS; the subscribe branch keys on chapter-share consent anyway.wfl6875hJNujN1gx0) — triggers on Intent entering Volunteer/Lead.keep_informed=on, which is what those read.What it costs
Intentalone stops distinguishing "picked nothing on /join" from "came via /subscribe"; that query goes throughSignup sourceinstead. Accepted: that field exists for provenance and is authoritative for this cohort.Legacy
No form emits
Keep informedany more. It stays inINTENTSbecause that list is the server's accepted-POST allowlist (isIntentinembed/onboarding-form/+page.server.ts), so dropping it would start rejecting a post rather than merely retiring a label. Migration cost is near nil: 106 rows carry it today, of which exactly one is aJune 2026 subscribe formrow (created 2026-08-20); the other 105 are pre-#1014/joindefaults.CRM side
PauseAI/pauseai-civicrm#530 adds
Noneto themember_intentvocabulary and is already open. Nothing further is needed there: the import and the System Status vocabulary guard both read the active option values dynamically.Verification
pnpm checkandpnpm lintboth green locally (remaining warnings are pre-existing and untouched).