Repository navigation
Conversation
A pure module, src/lib/draft-checks.ts, that reads a draft's fields, slots
and settings and returns notices in build order: placeholder text (TBD,
TBC, TBA), fields no slot fills, blank slots, duplicate rows, unnamed
fields, dates that repeat on an ungrouped page, and times written into a
text field. Each notice carries what its one-tap fix needs, and each check
is its own exported function.
The checks stay silent when a case is ambiguous. Duplicate rows are never
rows holding a placeholder, blank rows, or rows missing a value other
slots have. Numbered copies ("Helper 1", "Helper 2") need capacity 1 and
numbers counting from 1, so "Room 101" and "Room 102" stay separate rooms.
The builder's default field name moves into UNTITLED_FIELD_LABEL so the
unnamed-field check and the field form read the same constant.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BTvMvHZ4i4FWQFAsxcr5Zm
The review page now runs the draft checks over every slot and lists what
they find under "N things to fix before you publish", each in plain
words with a link to fix it in the builder: slots that still say TBD,
TBC or TBA; a field empty on every slot; blank slots; copies; a field
with no name; dates repeating on a page that isn't grouped by them; and
times typed into a text field. With none, the card says "Nothing to
fix. This is the list people will see." and keeps its check; with some,
its mark turns to "!".
The checks (src/lib/draft-checks.ts) are pure and exact: copies are
never offered for rows holding a placeholder or missing a value other
slots have, and numbered rows count only when each takes one person.
The builder's default field name is now one constant both use. Their
words are in src/lib/draft-notices.ts. Each kind shown writes
review.notice_shown { kind }.
Part of #503.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BTvMvHZ4i4FWQFAsxcr5Zm
From review:
- Numbered rows ("Lane 1", "Lane 2") may be different things, so the
notice says they differ only by a number and quotes two, leaving the
call to the organizer, instead of calling them the same.
- Closed slots are never copies. Repeated dates are pointed out only
when at least half the dates repeat, as one-slot groups help nobody.
A bare clock time needs its minutes on a five, so "John 3:16" and a
21:14 score aren't times. Whitespace-only values count as empty on
the page's filled-slot check too.
- No empty quotes for a field with no name, and "One slot has" when it
is one. The placeholder word comes from the check, and the capacity
wording from signup-summary's people().
- "Nothing to fix" hides when Magic Compose's warnings show just above
it, and the notices use the warnings' colors.
- review.notice_shown rows go in one insert (recordActivitiesBestEffort),
docs/telemetry.md lists them with the other organizer telemetry and
says to compare kinds by distinct signup, and the privacy page says
the log records which kinds of problem were pointed out.
- The help screenshot is re-taken with "Nothing to fix".
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BTvMvHZ4i4FWQFAsxcr5Zm
Tophat: passedI ran it locally with
For the owner (UX): a draft's review page now lists problems the code can prove, before anyone sees them, each with a link to the builder. The one-tap fixes come in the next PR. The privacy page's activity-log bullet now says the log records which kinds of problem were pointed out, never the values. Code reviewI ran
Kept as is: writing Screenshots are in https://claude.ai/code/session_01BTvMvHZ4i4FWQFAsxcr5Zm. Generated by Claude Code |
|
Closing without merging. The draft → publish → share flow is being redesigned (#498) rather than shipped as this stack. The branch stays: the checks in Generated by Claude Code |
Part 1 of 3 for #503, in the #498 stack. Stacked on #528, which sits on #527 and #525.
review.notice_accepted.mergeSlotsfor rows that are copies.The problem
Most drafts need nothing but a look and Publish. Some have problems the code can prove are there: placeholder rows that still say TBD, fields nobody fills in, blank slots, a row per person. Today nothing points them out before the signup goes live.
The fix
src/lib/draft-checks.ts) are pure functions over the signup's fields, slots and settings. Each returns{ kind, slotIds | fieldId, … }with what a fix will need. The review page runs them over every slot, folded or not. In build order:placeholder: a value holding TBD, TBC or TBA as a whole word, in any case.empty_field: a field empty on every slot.blank_slot: a slot with no value in any field.duplicate_slots: rows identical in every field, with the kept slot's values and the total capacity (null if any copy had no limit). These are never offered when:unnamed_field: a blank label, or the builder's default "Untitled". That default is now one constant,UNTITLED_FIELD_LABEL, shared with the builder.ungrouped_dates: a date field whose values repeat, with at least two dates, on a page that isn't grouped.time_in_text: no time field, and a text field holding a time of day ("9:00", "9am", "9:30 p.m."). Bare numbers and ranges like "Ages 8–12" don't count.src/lib/draft-notices.ts) name the organizer's own labels and values in quotes, so they read right in any language. Two examples:review.notice_shownwith{ kind }only, after the page is sent. This is the event Record link copies, failed AI drafts and refused publishes #500 reserved, added toACTIVITY_EVENTSnow that something writes it, and documented indocs/telemetry.md.Tests
draft-checks.test.tshas 50 tests. Each check is tested on made-up data for what it must catch and what it must leave alone, including:draft-notices.test.tscovers each kind's words.view-tracker.db.test.tschecksrecordNoticesShownwrites one row per kind, holding only{ kind }.pnpm lint && pnpm typecheck && pnpm test(1397 tests),pnpm knip(in a clean worktree),pnpm test:db(499 tests) andpnpm build && pnpm budgets. The page stays at 111.1 kB of 112, because the notices render on the server.Generated by Claude Code