- Add afterEach to vitest imports
- Add vi.useFakeTimers() at the start of beforeEach block
- Add afterEach(() => vi.useRealTimers()) to restore timers after each test
- Freezes OutputBlock's setTimeout(setCopied(false), 2000) during tests
- Replace fireEvent import with userEvent from @testing-library/user-event
- Add const user = userEvent.setup() inside each test body using interactions
- Replace fireEvent.click(azureButton) with await user.click(azureButton)
- Replace fireEvent.change(nameInput) with await user.clear() + await user.type()
- Make all interaction tests async
- Destructure dispatch from useWizard() alongside state
- Derive showIntune and showRmm booleans from state.deployment.scriptTargets
- Conditionally unmount Intune OutputBlocks (showIntune) and RMM OutputBlock (showRmm)
- rclone.conf OutputBlock always rendered regardless of scriptTargets
- handleDownloadZip builds files array dynamically — filters by showIntune/showRmm
- Add Back button dispatching SET_STEP(2) following DeploymentStep pattern
- All 15 ReviewStep tests green including new TECH-01 and TECH-02 cases
- Create 05-00-SUMMARY.md with RED state documentation
- Update STATE.md with plan progress and decisions
- Update ROADMAP.md phase 5 progress (1/4 plans complete)
- Mark TECH-01, TECH-02, TECH-03 requirements complete in REQUIREMENTS.md
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Update BACKEND_REGISTRY[backend].length → .fields.length
- Update iteration to use BACKEND_REGISTRY[backend].fields
- Update field lookups (.find/.map) to go through .fields
- Add new test: each backend has displayName and description metadata (RED)
- Import ReviewStep in App.tsx and add as steps[3]
- Update STEP_LABELS in StepIndicator.tsx to include 'Review' as fourth entry
- Update comment: 1.Backend > 2.Remote Config > 3.Deployment > 4.Review
- Full npm test suite (98 tests, 12 files) remains GREEN
- 04-03-SUMMARY.md: documents implementation, deviations, and test fixes
- STATE.md: advanced to plan 04, recorded metrics and decisions
- ROADMAP.md: updated phase 4 progress (3/5 summaries)
- ReviewStep.tsx: live rclone.conf preview via useMemo+try/catch (CONF-02)
- Security acknowledgement checkbox gates all download/copy buttons (SECU-01)
- 'No data is sent to any server' privacy notice (SECU-02)
- 4 OutputBlocks with download (DOWN-01–04) and copy (DOWN-06, CONF-03)
- Download All (ZIP) button calls downloadZip with all 4 file entries (DOWN-05)
- Replaced all expect.fail stubs with real assertions — 10/10 tests GREEN
- Added vi to import for spy capability
- SECU-03: dispatches all action types, asserts setItem never called on
Storage.prototype (covers both localStorage and sessionStorage)
- All 9 reducer tests GREEN
- App.tsx: WizardShell routes to BackendSelectionStep/RemoteConfigStep/DeploymentStep
- App.tsx: StepIndicator renders above every step as persistent breadcrumb
- App.tsx: RemoteConfigStep keyed on backendType to force remount on backend change
- App.test.tsx: all 3 WIZD-02 tests GREEN (step 0, 1, 2 routing verified)
- Full suite: 87 tests GREEN across 11 test files
- WIZD-03: clicking completed step dispatches SET_STEP
- WIZD-03: clicking back to step 0 dispatches SET_REMOTE_PARAMS({})
- WIZD-03: clicking back to step 0 does NOT dispatch RESET
- WIZD-03: step 0 shows as active when currentStep is 0
- WIZD-03: completed steps are clickable
- BACK-01: Azure Blob form with account FieldRenderer + AzureAuthToggle
- BACK-02: S3 form via BACKEND_REGISTRY loop (provider hidden, region required)
- BACK-03: S3-compatible form includes endpoint field
- mode: onSubmit / reValidateMode: onChange for touch-then-live validation
- Guard: useEffect redirects to step 0 if backendType is null
- All hooks called unconditionally (fallback schema prevents rules-of-hooks violation)
- 8/8 BACK-01/02/03 tests GREEN
- BACK-01: Azure Blob form with account field + AzureAuthToggle
- BACK-02: S3 form fields (access_key_id, secret_access_key, region)
- BACK-03: S3-compatible form includes endpoint field
- renderWithBackend helper dispatches SET_BACKEND_TYPE before render
- @testing-library/user-event installed for value retention test
- Replace expect.fail stubs with real test assertions
- Tests cover card render order, card click dispatch, name validation
- RED: component file does not exist yet
- FieldRenderer: registry-driven input renderer (text, password, select, hidden provider)
- AzureAuthToggle: segmented SAS/Key toggle, defaults to SAS, both fields always registered via CSS show/hide
- Both fields preserved on toggle (no conditional rendering that would lose react-hook-form state)
- BackendCard: clickable selection card with selected/unselected visual states
- PasswordField: password input with per-instance show/hide toggle (text labels, no emoji)
- Both files in new src/components/ui/ directory
- Imports CONFIG_DIR and buildRcloneInstallBlock from ps-helpers.ts
- Uses \$ErrorActionPreference = 'Stop' for RMM platform exit code surfacing
- Creates config directory idempotently with Test-Path guard
- Writes rclone.conf using [System.IO.File]::WriteAllText UTF-8 no-BOM
- Conditionally includes rclone download block based on includeInstall flag
- All 6 rmm-script.test.ts assertions pass GREEN
- buildIntuneInstall: UTF-8 no-BOM write via WriteAllText, PS here-string for config, conditional rclone download block
- buildIntuneDetection: no $ErrorActionPreference, Write-Output + exit 0/1 pattern
- Both generators use CONFIG_DIR from ps-helpers for consistent path resolution
- All 15 intune-install and intune-detection tests pass GREEN
- Export CONFIG_DIR record mapping configPath to Windows paths
- Export buildRcloneInstallBlock for conditional rclone binary download
- machine-wide maps to C:\ProgramData\rclone
- user-profile maps to %APPDATA%\rclone
- Uses -UseBasicParsing for SYSTEM context safety
- Maps BackendType to rclone INI type strings via RCLONE_TYPE_MAP
- s3-compatible correctly maps to type = s3 (not s3-compatible)
- Omits empty param values from output (no 'sas_url =' when blank)
- Throws on null backendType or empty remote name
- All 17 rclone-conf.test.ts assertions pass GREEN
- Re-exports buildRcloneConf, buildIntuneInstall, buildIntuneDetection, buildRmmScript
- Phase 4 will import all generators from this single entry point
- No implementation logic — purely structural re-exports
Covers rclone.conf INI generation (type mapping, empty field omission),
PowerShell encoding (UTF-8 no-BOM via UTF8Encoding($false)), Intune
detection script contract (STDERR breaks detection), and RMM SYSTEM
context patterns. All key findings verified against live official sources.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Create src/store/context.tsx: WizardContext, WizardProvider, useWizard hook
- useWizard throws if used outside WizardProvider (prevents silent undefined state bugs)
- Update src/App.tsx to wrap content in WizardProvider
- npm run build exits 0 with no TypeScript errors
- SUMMARY.md created for Plan 03
- STATE.md updated: progress 75%, decisions logged, session recorded
- ROADMAP.md updated: phase 1 at 3/4 SUMMARY files
- buildZodSchema derives z.object() from BACKEND_REGISTRY field definitions
- required fields map to z.string().min(1, label) — optional to z.string().optional()
- BACKEND_SCHEMAS exported with entries for azureblob, s3, s3-compatible
- BackendFormValues<T> utility type infers TypeScript type from schema
- No hardcoded field names — all shapes derived from registry loop
- All 8 tests in index.test.ts pass (GREEN)
- 01-02-SUMMARY.md created with decisions, deviations, and self-check
- STATE.md: advanced to Plan 2 of 4, added decisions, updated metrics
- ROADMAP.md: phase 1 progress updated (2/4 plans complete)
- Created 01-01-SUMMARY.md documenting scaffold outcomes and deviations
- Updated STATE.md: plan 1/4 complete, decisions recorded, session continuity
- Updated ROADMAP.md: plan 01-01 checked off, Foundation at 1/4 plans
- Created vitest.config.ts with environment: 'node' and globals: true
- Added passWithNoTests: true so vitest run exits 0 with no test files
- test script already present in package.json as "vitest run"
- Created Vite 6 project with React 18 and TypeScript 5 template
- Installed zod, react-hook-form, @hookform/resolvers (production)
- Installed tailwindcss @tailwindcss/vite (Tailwind v4 via Vite plugin)
- Installed vitest, @testing-library/react, @testing-library/dom (dev)
- Configured Tailwind v4 via @tailwindcss/vite plugin in vite.config.ts
- Set src/index.css to @import "tailwindcss" (no postcss/tailwind.config.js)
- Created minimal App.tsx with Tailwind classes, .gitignore
- Auto-fix (Rule 1): added src/vite-env.d.ts for CSS module type declarations