Registry slot 7/7. The big one. Closes the server-side required-validation
gap the audit (§3.A) flagged: legacy submit/+server.ts only matched empty
strings and empty arrays, so a date_ranked_choice answer of `{}` (object
exists, but no options rated) passed the gate even when the question was
required. The client-side validator caught it; the server didn't.
THE source of truth for the gap is now `isAnswerEmpty(q, answer)`:
- undefined / null → empty
- empty object → empty (this is the case the legacy gate missed)
- object where every value is null → empty
- object with at least one finite integer 1..5 → not empty
- out-of-range / non-integer / wrong-shape → empty
After the wiring step (commit 11) flips submit/+server.ts to call
`getQuestion(q.type).isAnswerEmpty(q, answer)`, the gap closes by
construction — one rule, two callers, no drift.
Files added:
- date_ranked_choice.ts — schema (extends base with options[2..50] of
{id, start, end?, label?}, optional scale.{min,max}_label, optional
allow_partial), defaultStub (two slots starting at the next hour
+ 24h), isAnswerEmpty (the gap closer above), emptyStats with
per-option OptStatsWip accumulators, ingest (per-option counting,
range-checking, _sum), finalise (mean = _sum/count, sort by mean
desc with tiebreaks on 5-count / 4-count / count / id), CSV (one
column per option, header format <qid>[<optId>]), adminCellSummary
("X avg (N rated)").
- date_ranked_choice.input.svelte — per-option row with date display,
1..5 rating buttons, skip button. Same markup the participant page
renders today.
- date_ranked_choice.builder.svelte — date/time options list with add /
remove, scale labels (rating-1 / rating-5 captions), allow_partial
toggle. Includes the renamed `setDateRankedScaleLabel` from the
papercut commit. Date-handling helpers (isoToLocalInput,
localInputToIso, defaultStartIso, optUid) live here.
- date_ranked_choice.results.svelte — full calendar + bars view with
view-toggle (Kalender / Balken). All helper logic — buildCalendar,
cellTitle, colorForRating, colorForMean, fmtTimeRange, fmtDateOption,
fmtMean, mixHex — is now per-module instead of in Results.svelte.
- date_ranked_choice.test.ts — 22 cases covering schema (duplicate ids,
fewer than 2 options, malformed ISO, disallowed id chars), the seven
isAnswerEmpty rules above, ingest+finalise (sort, _sum drop, range
filtering, missing-answer handling), CSV (one column per option,
cell extraction, wrong-shape passthrough), adminCellSummary.
123 server tests pass (was 101). svelte-check + bun run build clean.
All seven types now in QUESTION_MODULES. The wiring step (next commit)
flips the legacy callers — schemas.ts assembles its discriminated union
from the registry, FormBuilder mounts BuilderEditor by type, participant
page mounts ParticipantInput, Results.svelte mounts ResultsBlock, the
submit endpoint calls isAnswerEmpty per type, the export endpoint calls
csvColumns + csvCellFor per type. After that, the legacy `q.type === '...'`
strips disappear.
36 lines
1.3 KiB
JSON
36 lines
1.3 KiB
JSON
{
|
|
"name": "fdbck",
|
|
"version": "0.1.0",
|
|
"private": true,
|
|
"type": "module",
|
|
"scripts": {
|
|
"dev": "vite dev",
|
|
"build": "vite build",
|
|
"preview": "vite preview",
|
|
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
|
"start": "node build/index.js",
|
|
"test:server": "bun test ./src/lib/server/rate-limit.test.ts ./src/lib/server/public-scope.test.ts ./src/lib/server/results.test.ts ./src/lib/server/admin-route.test.ts ./src/lib/server/feedback-pure.test.ts ./src/lib/questions/registry.test.ts ./src/lib/questions/boolean.test.ts ./src/lib/questions/text.test.ts ./src/lib/questions/scale.test.ts ./src/lib/questions/choice.test.ts ./src/lib/questions/date_ranked_choice.test.ts",
|
|
"test:components": "bun --bun vitest run --config vitest.config.ts",
|
|
"test": "bun run test:server && bun run test:components"
|
|
},
|
|
"devDependencies": {
|
|
"@sveltejs/adapter-node": "^5.5.4",
|
|
"@sveltejs/kit": "^2.15.0",
|
|
"@sveltejs/vite-plugin-svelte": "^5.0.0",
|
|
"@testing-library/jest-dom": "^6.9.1",
|
|
"@testing-library/svelte": "^5.3.1",
|
|
"@types/bun": "^1.3.13",
|
|
"jsdom": "^29.1.1",
|
|
"svelte": "^5.0.0",
|
|
"svelte-check": "^4.0.0",
|
|
"typescript": "^5.0.0",
|
|
"vite": "^6.0.0",
|
|
"vitest": "^4.1.5"
|
|
},
|
|
"dependencies": {
|
|
"@supabase/supabase-js": "^2.104.1",
|
|
"postgres": "^3.4.9",
|
|
"zod": "^4.3.6"
|
|
}
|
|
}
|