@explorer02/cfm-survey-sdk 0.2.9 → 0.3.1

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.
Files changed (47) hide show
  1. package/dist/cli/index.js +41 -38
  2. package/dist/cli/index.mjs +39 -36
  3. package/package.json +1 -1
  4. package/templates/docs/00-integration/agent-execution-flow.md +6 -6
  5. package/templates/docs/00-integration/agent-operating-contract.md +1 -2
  6. package/templates/docs/00-integration/client-lib-folder.md +1 -0
  7. package/templates/docs/00-integration/component-checklist.md +0 -1
  8. package/templates/docs/00-integration/ui-customization-wizard.md +38 -29
  9. package/templates/docs/00-integration/wizard-chrome-contract.md +3 -12
  10. package/templates/docs/00-integration/wizard-config-handoff.md +19 -11
  11. package/templates/docs/00-integration/wizard-post-customize-build.md +0 -6
  12. package/templates/docs/00-integration/wizard-preview-build-guide.md +17 -0
  13. package/templates/docs/00-integration/wizard-question-type-styling.md +3 -3
  14. package/templates/docs/00-integration/wizard-troubleshooting.md +4 -20
  15. package/templates/docs/01-components/03-rating-scale.md +8 -3
  16. package/templates/docs/02-reference/value-derivation.md +2 -0
  17. package/templates/docs/03-ui-specs/01-rating.md +15 -1
  18. package/templates/docs/index.md +1 -1
  19. package/templates/docs/templates/CsatMatrixScale.tsx +59 -53
  20. package/templates/docs/templates/CustomSliderTrack.tsx +8 -17
  21. package/templates/docs/templates/FileUploadScale.tsx +4 -12
  22. package/templates/docs/templates/Header.tsx +49 -32
  23. package/templates/docs/templates/HeatmapScale.tsx +2 -5
  24. package/templates/docs/templates/LikertMatrixScale.tsx +45 -57
  25. package/templates/docs/templates/MatrixDropdown.tsx +11 -12
  26. package/templates/docs/templates/Question.tsx +24 -4
  27. package/templates/docs/templates/RankOrderScale.tsx +9 -42
  28. package/templates/docs/templates/RatingScale.tsx +73 -75
  29. package/templates/docs/templates/SliderMatrixScale.tsx +3 -4
  30. package/templates/docs/templates/selectionStyles.ts +3 -2
  31. package/templates/docs/templates/surveyUiScaleUtils.ts +15 -1
  32. package/templates/docs/templates/verify-agent-build.sh +0 -17
  33. package/templates/preview-harness/preview-bridge.inline.js +61 -14
  34. package/templates/preview-harness/previewPages.js +84 -48
  35. package/templates/preview-harness/previewPages.ts +7 -5
  36. package/templates/preview-harness/vite-app/src/QuestionPreview.tsx +22 -14
  37. package/templates/preview-harness/vite-app/src/fixtures/questions.ts +13 -2
  38. package/templates/preview-harness/vite-app/src/preview-live-overrides.css +6 -11
  39. package/templates/previewBridge.ts +38 -5
  40. package/templates/survey-theme.css +17 -17
  41. package/templates/wizard-dist/assets/{PreviewMock-CysRws9G.js → PreviewMock-Bax7oRAL.js} +1 -1
  42. package/templates/wizard-dist/assets/{TypePanel-DWX1LL3q.js → TypePanel-D2t4FPSd.js} +1 -1
  43. package/templates/wizard-dist/assets/index-BhWM50Yu.css +1 -0
  44. package/templates/wizard-dist/assets/index-c5lka74l.js +34 -0
  45. package/templates/wizard-dist/index.html +2 -2
  46. package/templates/wizard-dist/assets/index-DIuc7AU2.js +0 -34
  47. package/templates/wizard-dist/assets/index-pCM8n0FT.css +0 -1
@@ -2,6 +2,37 @@
2
2
 
3
3
  > Optional **run** after Phase 6 verify. **Wizard-ready build** is mandatory in Phase 5 — see [`agent-execution-flow.md`](agent-execution-flow.md).
4
4
 
5
+ ### Port selection (strict)
6
+
7
+ The CLI calls `findPort(4200)` — tries **4200**, then **4201**, **4202**, … until a port is free.
8
+
9
+ **Agent rules:**
10
+
11
+ 1. **Do not** hardcode `localhost:4200` if the CLI printed a different port.
12
+ 2. **Share only** the URL the CLI prints under `🔗 Client wizard link — share this URL only:`.
13
+ 3. **Do not** give the client a second link, a file path, or `out/previews/` paths.
14
+
15
+ Example CLI output:
16
+
17
+ ```
18
+ 🔗 Client wizard link — share this URL only:
19
+ http://localhost:4201
20
+ Port 4201 (auto-selected if 4200 was in use)
21
+ ```
22
+
23
+ ### Client quit without save
24
+
25
+ If the client clicks **Quit** (no Review & Build):
26
+
27
+ - CLI runs preview GC (`out/previews/` deleted)
28
+ - CLI exits without `survey-ui-config.json` update
29
+ - **Agent must NOT** re-run `npx cfm-sdk customize` or send another wizard link
30
+ - **Agent must** ask deploy confirmation (INPUT 4) using the **existing** build from Phase 6
31
+
32
+ See [`wizard-config-handoff.md`](wizard-config-handoff.md) § Quit without save.
33
+
34
+ ---
35
+
5
36
  ## Default: local wizard (`customize`)
6
37
 
7
38
  When the client says **yes** to customization in agent chat, **always run:**
@@ -12,8 +43,7 @@ npx cfm-sdk customize
12
43
 
13
44
  This is the **recommended default** because it:
14
45
 
15
- - Probes the first free port from **4200** upward and starts the wizard there
16
- - Prints a machine-parseable line: **`WIZARD_LINK=http://localhost:{port}`** — agent shares **only** this URL with the client (never hardcode `:4200`)
46
+ - Serves wizard + component previews from **one local server** (`localhost:4200`)
17
47
  - Auto-exports all **11** question-type previews from agent components
18
48
  - Writes `survey-ui-config.json` **directly** on save — no S3, no session polling
19
49
  - Cleans up local `out/previews/` when client quits without saving (`POST /api/wizard-quit`) or when CLI exits (Ctrl+C)
@@ -21,15 +51,9 @@ This is the **recommended default** because it:
21
51
 
22
52
  **Agent script after client says yes:**
23
53
 
24
- > *"I'll start the customization wizard. Use the link I share — complete all steps and click **Review & Build** when done."*
54
+ > *"I'll open the customization wizard in your browser. Complete all steps and click **Review & Build** when done — I'll apply your changes automatically."*
25
55
 
26
- **Strict link handoff:**
27
-
28
- 1. Run `npx cfm-sdk customize` and wait for `WIZARD_LINK=http://localhost:…` in CLI output
29
- 2. Share **only** that URL with the client — do not guess port 4200
30
- 3. Keep the terminal open until CLI exits
31
-
32
- **On successful save:**
56
+ The CLI **blocks** until the client saves. Wait for:
33
57
 
34
58
  ```
35
59
  ✅ UI configuration saved to survey-ui-config.json
@@ -37,8 +61,6 @@ This is the **recommended default** because it:
37
61
 
38
62
  Then apply per [`apply-ui-config.md`](apply-ui-config.md).
39
63
 
40
- **If client quits without saving:** CLI exits 0 after GC (`out/previews/` removed). **Do not** re-run the wizard. Skip Phase 6c. Ask deploy confirmation (Phase 7 / INPUT 4) with the existing Phase 6 build.
41
-
42
64
  ### Who can use it
43
65
 
44
66
  | User | Can use `customize`? |
@@ -46,7 +68,7 @@ Then apply per [`apply-ui-config.md`](apply-ui-config.md).
46
68
  | Client on **same machine** as agent (Cursor chat on dev laptop) | **Yes — default** |
47
69
  | Client on **another device** | **No** — use EC2 fallback below |
48
70
 
49
- The wizard URL is **`WIZARD_LINK` from CLI output** — only reachable on the machine running the CLI (port may be 4201+ if 4200 is busy).
71
+ `localhost:4200` is only reachable on the machine running the CLI.
50
72
 
51
73
  ---
52
74
 
@@ -60,7 +82,7 @@ npx cfm-sdk customize-ui
60
82
  ```
61
83
 
62
84
  - Uploads previews to EC2 disk (local-server model on remote host)
63
- - Prints **`WIZARD_LINK=…`** after previews upload — agent sends **only** that URL to client
85
+ - Prints EC2 wizard link — agent sends link to client
64
86
  - CLI **polls** until client submits → writes `.final.json` + `.diff.md`
65
87
  - Requires deploy-api on EC2 + `CFM_INSTANCE_ID`
66
88
 
@@ -87,7 +109,7 @@ After Phase 6 verify + dev server:
87
109
  ```mermaid
88
110
  sequenceDiagram
89
111
  participant Agent as Agent CLI
90
- participant Srv as localhost port from WIZARD_LINK
112
+ participant Srv as localhost:4200
91
113
  participant Wizard as Wizard SPA
92
114
  participant Prev as out/previews/
93
115
 
@@ -120,24 +142,11 @@ sequenceDiagram
120
142
 
121
143
  ---
122
144
 
123
- ## Port probe + link-only handoff (mandatory)
124
-
125
- | Step | Agent action |
126
- |------|----------------|
127
- | 1 | Run `npx cfm-sdk customize` (or `customize-ui` for remote) |
128
- | 2 | Read `WIZARD_LINK=…` from CLI stdout — **never** assume `localhost:4200` |
129
- | 3 | Share **only** that URL with the client |
130
- | 4 | Wait until CLI exits (save → exit 0, quit → exit 0 with GC message) |
131
-
132
- Optional: set `CFM_WIZARD_OPEN_BROWSER=1` to auto-open the wizard in the agent's browser.
133
-
134
- ---
135
-
136
145
  ## Agent checklist
137
146
 
138
147
  - [ ] Phase 5: wizard-preview artifacts wired
139
148
  - [ ] Client opted in (INPUT 3)
140
- - [ ] Parsed `WIZARD_LINK` from CLI and shared only that URL with client
149
+ - [ ] Ran **`npx cfm-sdk customize`** (default) and waited for CLI exit 0
141
150
  - [ ] Read `survey-ui-config.json` (or `.diff.md` if used EC2 fallback)
142
151
  - [ ] Phase 6c: applied per [`apply-ui-config.md`](apply-ui-config.md)
143
152
  - [ ] Re-ran verify + build
@@ -12,6 +12,7 @@ Pipeline: [`wizard-preview-build-guide.md`](wizard-preview-build-guide.md) · [`
12
12
  | Wizard control / symptom | Required fix |
13
13
  |--------------------------|--------------|
14
14
  | Logo not updating in Branding / Header preview | `data-cfm-logo` img + `data-cfm-logo-text` fallback in `Header.tsx` |
15
+ | Logo shows colored pad behind image | Logo `<img>` must use `background: transparent` — **never** `var(--cfm-primary)` on logo box |
15
16
  | Company name not updating | `data-cfm-company` span in `Header.tsx` |
16
17
  | Show header works but progress bar toggle does nothing | Progress bar needs `data-cfm-progress` + class `cfm-progress`; header needs class `cfm-header` only — **not** on sticky wrapper |
17
18
  | Show footer toggle does nothing | `footer` + class `cfm-footer` |
@@ -21,25 +22,15 @@ Pipeline: [`wizard-preview-build-guide.md`](wizard-preview-build-guide.md) · [`
21
22
  | Scale selection colors not updating | Import `selectionStyles.ts`; use `var(--cfm-matrix-selected)` / `var(--cfm-input-focus-ring)` |
22
23
  | Company name not showing after logo | Copy `Header.tsx` template — brand row is `[logo][data-cfm-company]` in one flex container |
23
24
  | Company shows when empty | Bridge clears `[data-cfm-company]` when `companyName` is `""` — do not hardcode "Company Name" as visible default |
24
- | NPS colors / rings not updating | Copy `RatingScale.tsx` + `selectionStyles.ts` no hardcoded `#e20074` |
25
+ | NPS clicks do nothing / no visible selection before wizard | Copy latest `RatingScale.tsx` + `selectionStyles.ts` + `surveyUiScaleUtils.ts`; use `isScaleAnswerSelected()`; radio track row must use `label` + `onChange` → `onSelect(number)` — see `03-ui-specs/01-rating.md` |
26
+ | NPS colors / rings not updating | Copy `RatingScale.tsx` + `selectionStyles.ts` — hex fallbacks in `selectionStyles.ts` for pre-theme builds |
25
27
  | Text placeholder color not updating | `data-cfm-textfield` + `--cfm-input-placeholder` in CSS / `::placeholder` rule |
26
28
  | Matrix 2nd row toggle | Harness adds row via `previewMultiStatement` — `LikertMatrixScale` must render all `statementRows` from props |
27
29
  | Blank page after deploy | **Never** reference `UI_CONFIG` without import — use `src/lib/uiConfig.ts` |
28
- | Logo pink/colored box behind image | Logo `background: var(--cfm-header-logo-bg, transparent)` — never `var(--cfm-primary)` on logo img |
29
- | Logo + company placement | Locked: logo left, company name after logo in `.cfm-header-brand` flex row — no grid placement templates |
30
- | Logo size | `--cfm-header-logo-width/height` from wizard max-dimension slider; `object-contain` |
31
30
  | Logo wrong on CloudFront | Never change `global.logo.fileName` manually — use wizard file in `public/` |
32
31
 
33
32
  ---
34
33
 
35
- ## Agent link handoff (strict)
36
-
37
- 1. Run `npx cfm-sdk customize` — read **`WIZARD_LINK=http://localhost:{port}`** from CLI (port may be 4201+)
38
- 2. Share **only** that URL with the client
39
- 3. On quit without save: CLI exits 0, GC `out/previews/` — **do not** re-run wizard; ask deploy (Phase 7)
40
-
41
- ---
42
-
43
34
  ## Copy order (agents — do this in Phase 5)
44
35
 
45
36
  ```bash
@@ -30,18 +30,16 @@ npx cfm-sdk customize
30
30
  The CLI will:
31
31
 
32
32
  1. Export all 11 component preview pages (`export-previews` if needed)
33
- 2. Probe first free port from 4200 and start wizard CLI prints **`WIZARD_LINK=http://localhost:{port}`**
34
- 3. **Block** until client clicks **Review & Build** or quits
35
- 4. On save: write `survey-ui-config.json` and exit 0
36
- 5. On quit: GC `out/previews/` and exit 0 — **do not re-run wizard**; ask deploy (Phase 7)
33
+ 2. Start wizard at `http://localhost:4200`
34
+ 3. Open browser on the **agent machine**
35
+ 4. **Block** until client clicks **Review & Build**
36
+ 5. Write `survey-ui-config.json` and exit 0
37
37
 
38
38
  **Agent must:**
39
39
 
40
- - [ ] Parse `WIZARD_LINK` from CLI and share **only** that URL with client (never hardcode `:4200`)
41
- - [ ] Client is on the **same machine** (can open the `WIZARD_LINK` host)
42
- - [ ] Keep terminal open until CLI exits
43
- - [ ] On save: apply per Phase 6c from `survey-ui-config.json`
44
- - [ ] On quit: skip Phase 6c; ask deploy confirmation with existing Phase 6 build
40
+ - [ ] Client is on the **same machine** (can see `localhost:4200`)
41
+ - [ ] Keep terminal open until `✅ UI configuration saved`
42
+ - [ ] Apply per Phase 6c from `survey-ui-config.json`
45
43
 
46
44
  **Artifact:** `survey-ui-config.json` — apply source for local flow.
47
45
 
@@ -56,10 +54,20 @@ When the client uploads a logo in the local wizard:
56
54
 
57
55
  The logo is **not** fetched from wizard memory on CloudFront — only from the deploy bundle. See [`aws-deploy.md`](aws-deploy.md) § Logos & local assets.
58
56
 
59
- **Local quit (preview GC):** If the client exits without saving, wizard calls `POST /api/wizard-quit` → CLI deletes `out/previews/` → exits 0. Agent **must not** re-run the wizard or share a new link — proceed to Phase 7 deploy ask.
57
+ **Local quit (preview GC):** If the client exits without saving, wizard calls `POST /api/wizard-quit` → CLI deletes `out/previews/`.
60
58
 
61
59
  **After save:** `POST /api/save-config` also deletes `out/previews/` before CLI exits (preview garbage collection).
62
60
 
61
+ **Quit without save (no second wizard run):**
62
+
63
+ | Event | Agent action |
64
+ |-------|----------------|
65
+ | Client clicks **Quit** in wizard | Wait for CLI exit; previews GC'd automatically |
66
+ | CLI exits without `✅ UI configuration saved` | **Do not** run `customize` again or share another wizard URL |
67
+ | Build still valid from Phase 6 | Ask deploy confirmation (INPUT 4) — use existing `out/` from prior `npm run build` |
68
+
69
+ The agent does **not** re-open the wizard after quit. Garbage collection removes preview artifacts only; the production build in `out/` from Phase 6 remains unless the client requests a rebuild.
70
+
63
71
  ---
64
72
 
65
73
  ## Remote client flow — `customize-ui` (fallback only)
@@ -278,7 +286,7 @@ npx cfm-sdk fetch-ui-config
278
286
  | Mistake | Fix |
279
287
  |---------|-----|
280
288
  | Killed CLI during poll | Re-run `customize-ui`; client re-submits |
281
- | Client quit wizard | CLI exits 0; GC done (`out/previews/` removed). **Do not** re-run wizard skip Phase 6c, ask deploy (INPUT 4) |
289
+ | Client quit wizard | CLI exits with abandon message; S3 GC done re-run `customize-ui` for new session |
282
290
  | Applied from `survey-ui-config.json` while still seed | Use `.final.json` or run `confirm-ui-config` after apply |
283
291
  | Only changed primary color, ignored diff | Read **entire** `diff.md` — clients often change 20+ paths |
284
292
  | Skipped `confirm-ui-config` | Active JSON stays seed; next wizard re-open is wrong |
@@ -121,12 +121,6 @@ Only after H passes → ask deploy (INPUT 4). See [`aws-deploy.md`](aws-deploy.m
121
121
 
122
122
  **Do not re-run** `npx cfm-sdk export-previews` after wizard save — previews were deleted on purpose (GC). Export-previews is for **component structure changes** during Phase 5, not for applying saved config.
123
123
 
124
- ### If client quit without saving
125
-
126
- CLI exits 0 with GC message. **Do not** re-run wizard or share a new link. Skip this runbook (no Phase 6c). Ask deploy (INPUT 4) with the Phase 6 build.
127
-
128
- **Wizard link:** parse `WIZARD_LINK=…` from CLI — never hardcode `localhost:4200`.
129
-
130
124
  ---
131
125
 
132
126
  ## Wizard steps → live preview keys
@@ -50,6 +50,23 @@ If components use **hardcoded** colors (`bg-[#e20074]`) with no `var(--cfm-*)` h
50
50
 
51
51
  **Default for production wizard:** agent components. Use templates-only for SDK smoke tests, not client delivery.
52
52
 
53
+ ### Wizard static preview vs production survey
54
+
55
+ During `npx cfm-sdk customize`, the right panel loads **SDK static HTML** from `preview-harness/previewPages.js` — not your React tree. Layout matches the original survey-page mock; **customization** is driven by `--cfm-*` CSS vars + `preview-bridge.inline.js`.
56
+
57
+ | Wizard control | Static preview (iframe) | Production survey (after Phase 6c) |
58
+ |----------------|-------------------------|-------------------------------------|
59
+ | NPS hints + number labels | Hint text + badge colors via bridge | Copy `RatingScale.tsx` + `Question.tsx` hint row |
60
+ | Matrix multi-row toggle | Shows/hides `[data-cfm-matrix-row-extra]` | `LikertMatrixScale` maps all `statementRows` |
61
+ | Matrix row width + label items | `--cfm-matrix-row-width`, column label vars | `LikertMatrixScale` + `labelStyles.ts` |
62
+ | CSAT/Rating star/numbered/radio | Theme focus ring + cell selected on mock cells | `CsatMatrixScale.tsx` + `selectionStyles.ts` |
63
+ | Slider track + tick labels | `--cfm-slider-*` on static slider mock | `SliderMatrixScale` + `CustomSliderTrack` |
64
+ | File upload dropzone | `--cfm-upload-*` on `.cfm-dropzone` | `FileUploadScale.tsx` |
65
+ | Rank / heatmap | `--cfm-rank-*` / `--cfm-heatmap-pin-*` | `RankOrderScale.tsx` / `HeatmapScale.tsx` |
66
+ | Logo size slider | `--cfm-header-logo-width/height` + `max-height` in header | `Header.tsx` via `uiConfig.ts` |
67
+
68
+ **Rule:** If a wizard control updates the static preview but not localhost dev, the agent has not copied the matching template from `docs/templates/` — see [`wizard-chrome-contract.md`](wizard-chrome-contract.md).
69
+
53
70
  ---
54
71
 
55
72
  ## Required project artifacts (Phase 5)
@@ -102,11 +102,11 @@ Single-select radio: outer border = focus ring, annulus = cell selected, inner d
102
102
  | Wizard section | Config path | CSS vars | Apply in |
103
103
  |----------------|-------------|----------|----------|
104
104
  | Button style | `questionTypes.NPS_SCALE.buttonStyle` | `data-cfm-nps-button-style` | `RatingScale.tsx` |
105
- | Hint labels | `hintMinText`, `hintMaxText` + hint colors | `--cfm-hint-label-*` | `hintLabelStyle()` on min/max anchor row |
106
- | Number labels | `numberLabelMode`, per-index colors | `--cfm-number-label-mode`, `--cfm-number-mono-color`, `--cfm-number-color-{n}` | Badge row; `resolveNumberLabelColor()` for unselected |
105
+ | Hint labels | `hintMinText`, `hintMaxText` + hint colors | `--cfm-hint-label-*` | `hintLabelStyle()` on anchor row in `Question.tsx` |
106
+ | Number labels | `numberLabelMode`, per-index colors | `--cfm-number-*` | `resolveNumberLabelColor()` / badge row in `RatingScale.tsx` |
107
107
  | Selection | Theme → Question card | `--cfm-matrix-selected`, `--cfm-input-focus-ring` | `scaleRadioRingStyle` + `scaleRadioDotStyle` |
108
108
 
109
- **Removed from wizard UI:** NPS selected fill, track bar, track highlight — use Theme → Question card tokens only.
109
+ **Removed from wizard UI:** selected fill, track bar, track highlight — NPS selection uses Theme → Question card tokens only.
110
110
 
111
111
  ### CFM_MATRIX (`CFM_matrix`, `CFM_dropdown`, `CFM_transpose`, `CFM_likert`, `CFM_bipolar`)
112
112
 
@@ -9,7 +9,7 @@
9
9
  | | `customize` **(default)** | `customize-ui` **(fallback)** |
10
10
  |--|---------------------------|--------------------------------|
11
11
  | **When** | Client on same machine as agent | Client on different device |
12
- | **URL** | `WIZARD_LINK` from CLI (dynamic port) | `WIZARD_LINK` from CLI (EC2) |
12
+ | **URL** | `localhost:4200` | EC2 link with `session` + `secret` |
13
13
  | **Previews** | `out/previews/` on agent disk | EC2 disk |
14
14
  | **Save** | `survey-ui-config.json` immediately | Poll → `.final.json` + `.diff.md` |
15
15
  | **GC** | CLI stops → no orphans | Session cleanup on EC2 |
@@ -34,7 +34,7 @@ Footer: **"Mock preview — run customize or customize-ui…"**
34
34
 
35
35
  ### Symptom
36
36
 
37
- Client cannot open the `WIZARD_LINK` URL (wrong port or wrong machine)
37
+ Client cannot open `http://localhost:4200`
38
38
 
39
39
  ### Fix
40
40
 
@@ -46,7 +46,7 @@ export CFM_DEPLOY_API_BASE="http://43.204.26.213:3000"
46
46
  npx cfm-sdk customize-ui
47
47
  ```
48
48
 
49
- Send **only** the `WIZARD_LINK=…` line from CLI output.
49
+ Send **only the EC2 link** from CLI output.
50
50
 
51
51
  ---
52
52
 
@@ -72,25 +72,9 @@ Wire `data-cfm-*` hooks and `--cfm-*` CSS vars per [`wizard-preview-build-guide.
72
72
 
73
73
  ---
74
74
 
75
- ## Client quit without saving
76
-
77
- ### Symptom
78
-
79
- CLI prints quit message and exits 0; `out/previews/` removed.
80
-
81
- ### Agent action (mandatory)
82
-
83
- - **Do not** re-run `customize` or `customize-ui`
84
- - **Do not** share a new wizard link
85
- - Skip Phase 6c (no `survey-ui-config.json` update)
86
- - Ask deploy confirmation (Phase 7 / INPUT 4) with the existing Phase 6 build
87
-
88
- ---
89
-
90
75
  ## Checklist
91
76
 
92
77
  - [ ] Used **`customize`** as default when client said yes
93
- - [ ] Parsed **`WIZARD_LINK`** from CLI and shared only that URL
94
- - [ ] Waited for CLI exit 0 (save or quit)
78
+ - [ ] Waited for `✅ UI configuration saved`
95
79
  - [ ] Phase 5 preview bridge + `data-cfm-*` wired
96
80
  - [ ] EC2 only if client on remote device
@@ -21,9 +21,14 @@ Render a horizontal sequence of numbered badges with traffic-light colors (NPS 0
21
21
  ## UI/UX Rules (CRITICAL)
22
22
 
23
23
  1. **Shape**: Square badges with rounded corners — not full circles
24
- 2. **Unselected State**: Dim unselected when any item selected (`opacity-30`)
25
- 3. **Selected State**: `border-2 border-[#e20074] shadow-md scale-105`
26
- 4. **Tooltips**: `title={option.label}` on every badge
24
+ 2. **Interactive row**: Only the **radio track row** accepts clicks (`label` + hidden `input type="radio"`)
25
+ 3. **Selection compare**: Use `isScaleAnswerSelected(selectedValue, optionValue)` store/compare **numbers**, not option ids
26
+ 4. **Unselected State**: Gray ring (`#d1d5db`) + white fill on track row
27
+ 5. **Selected State**: Focus ring `#e20074` (or `--cfm-input-focus-ring`) + annulus `#fbe8f3` (or `--cfm-matrix-selected`) + filled dot
28
+ 6. **Tooltips**: `title={option.label}` on every clickable cell
29
+ 7. **`buttonStyle: 'standard'`**: Radio track only — omit numbered badge row
30
+
31
+ Reference implementation: [`apps/client/src/components/RatingScale.tsx`](../../../../apps/client/src/components/RatingScale.tsx)
27
32
 
28
33
  ## SDK Integration Checklist (agent)
29
34
 
@@ -39,6 +39,8 @@ function npsValueFromOption(option: NpsScalePoint, index: number): number {
39
39
 
40
40
  NPS questions use `question.type === 'NPS_SCALE'`. Store a **number** in `SurveyAnswers`. Badge colors: traffic-light table keyed by numeric value (0–10).
41
41
 
42
+ Compare selection with `isScaleAnswerSelected(selectedValue, npsValueFromOption(option, index))` — do not compare to `option.id`.
43
+
42
44
  ## MCQ
43
45
 
44
46
  - Selected answer: **`option.id`** (string), not a separate `optionValue` field
@@ -31,11 +31,22 @@ When `reverseScaleOrder === true`, map visual index `i` to stored index `options
31
31
  ## Answer Mutation
32
32
 
33
33
  ```typescript
34
+ import { isScaleAnswerSelected, npsValueFromOption } from '@/lib/surveyUiScaleUtils';
35
+
34
36
  const value = npsValueFromOption(option, index);
35
- onSelect(value) // number
37
+ onSelect(value); // number — never option.id
36
38
  // → onAction CHANGE { questionId, answerValue: number }
39
+
40
+ // Compare stored answer to option value (handles string/number drift):
41
+ const isSelected = isScaleAnswerSelected(selectedValue, value);
37
42
  ```
38
43
 
44
+ **Selection row (required):** Only the **radio track row** is interactive — use `<label>` + hidden `<input type="radio">` + `onChange={() => onSelect(option.value)}`. Mirror [`apps/client/src/components/RatingScale.tsx`](../../../../apps/client/src/components/RatingScale.tsx) (reference monorepo).
45
+
46
+ **Pre-customization defaults:** Copy `selectionStyles.ts` with `#e20074` / `#fbe8f3` hex fallbacks so selected rings are visible before `survey-theme.css` loads. Import `survey-theme.css` in `globals.css` for full wizard tokens.
47
+
48
+ **`buttonStyle`:** `standard` = radio track only (no numbered badge row). `numbered` = badge row + track. `emoji` = emoji cells.
49
+
39
50
  See [`02-reference/value-derivation.md`](../02-reference/value-derivation.md).
40
51
 
41
52
  ## Agent Checklist
@@ -59,6 +70,9 @@ See [`02-reference/value-derivation.md`](../02-reference/value-derivation.md).
59
70
  ### Wizard checklist
60
71
 
61
72
  - [ ] `selectionStyles.ts` imported in `RatingScale.tsx`
73
+ - [ ] `isScaleAnswerSelected()` used for `checked` state — not raw `===` on `selectedValue`
74
+ - [ ] Radio track: `label` + `sr-only` radio + `onChange` → `onSelect(number)` (see client `RatingScale.tsx`)
62
75
  - [ ] Selected radio: outer border + dot = focus ring; annulus = cell selected
63
76
  - [ ] Selected numbered badge: border = focus ring, fill = cell selected, text white
64
77
  - [ ] Unselected badges keep traffic-light / per-number `--cfm-number-*` colors
78
+ - [ ] `buttonStyle: 'standard'` hides badge row; track row remains clickable
@@ -131,7 +131,7 @@ Run: `bash templates/verify-agent-build.sh`
131
131
  Only after Phase 6 passes and client says **yes**:
132
132
 
133
133
  ```bash
134
- npx cfm-sdk customize # DEFAULT — prints WIZARD_LINK, WAITS until client saves or quits
134
+ npx cfm-sdk customize # DEFAULT — opens localhost:4200, WAITS until client saves
135
135
  ```
136
136
 
137
137
  **Phase 6b:** Client on same machine → `customize` writes `survey-ui-config.json` directly. Remote client → `customize-ui` + EC2 link (see `wizard-troubleshooting.md`). Apply per `apply-ui-config.md`.