What's new
Report totals and failure states are now trustworthy
- Financial reporting now includes invoices created before the selected period
when they were paid or refunded inside it, and includes every instant on the selected final club-calendar day.
- Membership month charts no longer shift or duplicate months around British
Summer Time. Programme attendance now follows the programme recorded on each register mark, with a lesson fallback only for older rows that predate that snapshot.
- Insurance records with no expiry are shown separately as No Expiry Set
instead of being counted as expired. Programme-scoped insurance and renewals also fail closed when their membership lens cannot be loaded.
- The Communications automation breakdown now loads rule metadata separately,
avoiding a broken embedded relationship, and its adoption snapshot can no longer turn an unavailable response into believable zeros.
- Renewals, communication activity, waiting lists, scheduled reports, portal
analytics and schedule insights now show an explicit load error when a required read fails instead of presenting an empty report.
- Current-state reports now say what they cover instead of displaying a date
picker they do not use. Counts that deliberately include both active and new members are labelled Current Members; the Membership report retains the stricter Active Members label.
Report custom ranges now apply exactly as selected
- Reports that support a shared date range now use visible native date fields,
so staff can either choose from the calendar or type both dates before applying the range. Invalid, incomplete and reversed ranges are blocked with an inline explanation.
- Preset boundaries now use the club calendar date instead of converting local
midnight through UTC, preventing the first day of a British Summer Time month from appearing as the previous day.
- Reports with their own fixed period no longer show a misleading shared picker.
Their header now names the period they actually use, such as rolling overview, next 90 days or current timetable.
- On phones, the From and To fields stack at full width so the entered dates and
native calendar controls remain readable without horizontal scrolling.
Local help-video review now reflects the current production line
- The loopback review workspace now condenses every help guide into one card.
Opening it reveals an explicit Script sign-off followed by a separate Video sign-off, so approved wording is no longer confused with approval of the rendered visuals, narration and captions.
- Script decisions can now be completed from the local page, including the
complete-beginner checklist and precise change requests. They are stored in the script-review registry; video decisions remain in the video registry. Neither action publishes anything.
- The audio-only check now says Listen to just audio instead of carrying a
narrator name from the retired Emma proof, and the review page no longer calls the current 1080p Forms-and-Settings collection a 720p Forms-only batch.
- Four review-sized settings batches are now scheduled. The next batch is
Deliverability, Memberships, Invoices & VAT and Payments; later batches cover club/progression foundations, member operations and specialist operations.
- Rendering remains paused while the current six Settings drafts await owner
decisions. Scripts must pass the beginner-content gate before any narration or rendering, and no local approval publishes an asset.
Credential-renewal releases no longer depend on SQL landing first
- The application now keeps the existing insurance fee, link and portal-renewal
journeys working when the additive configurable-credential columns have not reached an environment yet. Previously, the first configuration read could fail every renewal request during that release window.
- Previously issued renewal links also retry against the legacy token shape, so
an old link remains usable before or after the additive token columns arrive.
- Settings continues to load and save the established annual-requirement fields
in that window. Configurable online-renewal controls remain hidden, and a new client attempting to save those controls receives a scrubbed unavailable response instead of silently losing configuration.
- Compatibility is deliberately narrow: only errors that name one of this
migration's additive columns use the legacy path. Permission, tenancy and unexpected database failures continue to fail closed.
Deployment note
- Code-first and SQL-first deployment are both supported. Apply
supabase/_proposed/configurable-credential-renewal-01.sql before enabling a club's configured renewal journey; the proposed SQL remains unapplied to any remote environment by this work.
Attendance changes can become clear, manageable follow-up
- The local Action Centre can now explain when an active member attended at
least four of six active weeks and then none of the latest three.
- Each item shows the member, the exact arithmetic, the threshold and the rule
version. Closure weeks, incomplete registers and missing history never produce a signal.
- Authorised owners can assign an item, snooze it with a reason and date, choose
an exact resolution outcome and inspect its in-app history. Re-attendance or a paused/ended membership can resolve the same occurrence automatically.
- Future snoozes stay out of the current attention list while remaining linked
to source recovery.
Noise and privacy controls are built in
- A club can receive no more than three new retention items in a day and hold no
more than ten active items. Extra candidates stay measurable for review rather than being discarded.
- Retention attention has separate owner-first permissions and every server read
reasserts the signed-in club. Foreign and missing identifiers look the same.
- Retention items are in-app only and are explicitly excluded from daily email
and Telegram Action Centre briefs.
Deployment note
- The forward-history and retention occurrence SQL is additive, proposed and
rehearsed against the existing local Docker database only. Reapply, authority, tenant-isolation, deletion, lifecycle and concurrent-cap checks pass.
- No production SQL, feature flag, pilot row or notification was applied or sent.
A real CWTKD pilot remains owner-controlled and requires nine trustworthy completed weeks, two shadow weeks and the documented six-week review gate.
Help videos — full-width 1080p treatment and owner voice (local drafts)
- All six Forms guides re-authored to the owner-approved full-width treatment:
the real product screen fills the frame (fresh 1600×900 Vertical Test Club captures, dev chrome scrubbed), camera-follow zoom anchored on measured click targets, and settle-then-hold idle scenes that keep 1080p files small.
- Narration switched from the Kokoro
bf_emma voice to the owner's own cloned
voice (Chatterbox, MIT-licensed, fully local, Perth-watermarked as synthetic). The reference recording lives only in the gitignored drafts area and is never committed. Same reviewed guide texts; captions and transcripts regenerated from the new timings; scene durations retimed to the new take.
- Production renders bumped to 1920×1080 (H.264 CRF 22 slow fast-start MP4 +
VP9 WebM archival). Registry entries re-pointed at the new assets with updated durations, captures, voice and resolution metadata; all six reset to local draft for owner review on the loopback approval page.
- New tooling:
scripts/help-video/capture-form-help-screens.ts (session-mint
capture printing measured control boxes) and scripts/help-video/generate-chatterbox-narration.py (drop-in narration sibling emitting the same wav/timings/transcript artefacts). remotion.config.ts added so the bundler resolves the @/ alias (rendering was broken without it once the help catalogue gained value imports). Narration regenerates only when guide text changes — visual re-renders reuse the approved take. Owner review stays local-only per ODR-020; publication stays the ODR-021 path.
Settings help videos — Terminology guide produced (local draft)
- First settings guide off the production line: Terminology
(settings.terminology.flip, guide key terminology), authored in app/lib/help/settings-video-guides.ts with copy verified against TerminologyTab, app/lib/terminology.ts and the guarded /api/settings/terminology route: saved words re-word the app and member portal straight away; some Settings screens deliberately show neutral labels (for example "Stages") until configured; certificates and emails keep their own template wording and issued documents are never rewritten.
- New read-only capture script
scripts/help-video/capture-terminology-screens.ts (sibling of the Forms capture script; nothing typed or saved). Choreography is a two-target point-and-zoom over the member-term field and the Live preview card — no click ripple, because the capture is a single still.
- The full-bleed screen chip now reads "Real settings screen" and the header
area label follows the guide's area (Settings vs Form Builder). Terminology fields gained stable element ids (terminology-group-people etc.) so contextual help "Show me" can target them.
- Rendered 1080p in the owner's cloned voice and registered as
local_draft
(settings-terminology-v1-chris.*) awaiting owner review; nothing published.
Settings help videos — Closed Dates guide produced (local draft)
- Second settings guide off the production line: Closed Dates
(settings.closures.dates, guide key closures), authored in app/lib/help/settings-video-guides.ts with copy verified against ClosuresTab, the guarded /api/settings/closures route and app/lib/engagement/expected-opportunities.ts: closed dates are excluded from expected attendance (register day-snapshot, attendance-break weeks and the consistency denominator all skip them — a closure is never counted against a member); closed days stop taking trial and portal session bookings; after adding a closure the Affected Bookings check lists enrolled students and booked trials, regulars notification sends one idempotency-keyed email per member per missed class (Lesson Cancelled automation template or built-in default), and cancelled trials each get a reschedule-link email. Closures touch no billing or invoicing code, so the guide says nothing about money.
- New read-only capture script
scripts/help-video/capture-closures-screens.ts (the seeded club has no closures, so the Add Closure panel is opened client-side to frame the add form — nothing typed or saved). Choreography is a two-target point-and-zoom over the Start Date and Reason fields — no click ripple, single still. The add-closure controls gained a stable element id (closures-add-controls) for contextual help "Show me".
- Rendered 1080p in the owner's cloned voice and registered as
local_draft
(settings-closures-v1-chris.*, 27.6s, 5.2MB) awaiting owner review; nothing published.
Settings help videos — Timetable guide produced (local draft)
- Third settings guide off the production line: Timetable
(settings.lessons.timetable, guide key timetable), authored in app/lib/help/settings-video-guides.ts with copy verified against TimetableTab, the guarded /api/settings/timetable route, TimeRangeField and app/lib/time-range.ts: the class editor derives the finish from a start + length (an inverted range is unrepresentable), a class past midnight shows "(next day)" and finishes tomorrow — an end time earlier than the start is a supported overnight class, never an error (the route re-checks with allowOvernight, and classLiveStatus keeps an overnight class's attendance on the day it started). The timetable feeds each day's register (day-snapshot queries lessons by weekday), the calendar, trial/bookable-session booking and expected attendance; edits apply to registers going forward and never rewrite recorded attendance. The timetable touches no billing code, so the guide says nothing about money.
- New read-only capture script
scripts/help-video/capture-timetable-screens.ts: the timetable with the first class row hovered (revealing the Edit quick action), then the class editor reached by clicking that Edit link — the editor's mount path is pure reads, nothing typed or saved. Choreography is a click-through (Edit → class editor) with a second zoom on the time pair — the Starts at input, duration chips and "Runs …" summary — while the narration states the overnight rule. The Add Class control gained a stable element id (timetable-add-class) for contextual help "Show me".
- Rendered 1080p in the owner's cloned voice and registered as
local_draft
(settings-timetable-v1-chris.*, 31.8s, 6.2MB) awaiting owner review; nothing published.
Settings help videos — Annual Requirements guide produced (local draft)
- Fourth settings guide off the production line: Annual Requirements
(settings.requirements.credentials, guide key requirements), authored in app/lib/help/settings-video-guides.ts with copy verified against RequirementsTab, app/lib/credential-renewal.ts, app/lib/insurance-renewal-configuration.ts and the guarded /api/settings/program-requirements route: activation is fail-closed — normaliseCredentialDefinition forces portal renewal and automation off whenever readiness fails, the route rejects early enablement, and the portal read side re-checks readiness before serving a definition, so the switches only take effect once every field is complete (and automation cannot be on without the portal flow). The annual cost set here is the amount families pay at renewal (amount_pence is pinned into each renewal token), and the renewal window is both how early families can renew in the portal and when chasing starts.
- New read-only capture script
scripts/help-video/capture-requirements-screens.ts: the seeded club has no requirement definitions, so the "+ Insurance" preset create form is opened client-side and scrolled to the Activation section — the preset leaves exactly one setup item missing, so the frame shows both switches rendered disabled above the amber "Activation is locked until: …" line. Nothing typed, nothing saved, switches never clicked. Choreography is a two-target point-and-zoom over the Valid for (days) field and the locked Member portal renewal switch — no click ripple, single still. The definition editor gained a stable element id (requirements-definition-editor) for contextual help "Show me".
- Rendered 1080p in the owner's cloned voice and registered as
local_draft
(settings-requirements-v1-chris.*, 29.2s, 4.5MB) awaiting owner review; nothing published.
Settings help videos — Modules & Programs guide produced (local draft)
- Fifth settings guide off the production line: Modules & Programs
(settings.modules.enable_vs_entitle, guide key modules), authored in app/lib/help/settings-video-guides.ts with copy verified against ModulesTab, the guarded /api/modules route and the shared capability core (app/lib/capabilities-core.ts): enablement and entitlement are two independent axes — the resolver fail-closes on the commercial gate before consulting club_modules/program_modules, so a feature's screens appear only when the account includes a module AND it is switched on (a switched-on but not-included module shows the "Not active" chip and stays hidden). The state vocabulary (Included / Granted / Active / Available / Not available — contact support) is narrated for the two states in the capture and covered in full in the dialog sections, the "switches control access only and never create a charge" rule is stated verbatim (no pricing or upgrade actions exist in the tab by design — commerce lives in Your Plan), and completed setup wizards flipping "Set up progression →" to "Progression settings →" (re-running the wizard IS the edit surface, read from module_setup_runs) carries the impact scene.
- New read-only capture script
scripts/help-video/capture-modules-screens.ts: the settings content pane is scrolled 200px so one frame holds both teaching surfaces — the "Your enabled features" entitlement strip (the seeded club's Included + Granted chips, with the no-charge footer line legible) and the first program card's per-program switch cluster. The module switches write on click, so the script only asserts their presence and never clicks; wizard links never clicked. Choreography is a two-target point-and-zoom over a Granted chip and the first card's switch cluster — no click ripple, single still. The entitlement strip gained a stable element id (modules-enabled-features) for contextual help "Show me".
- Rendered 1080p in the owner's cloned voice and registered as
local_draft
(settings-modules-v1-chris.*, 32.2s, 5.6MB) awaiting owner review; nothing published.
Settings help videos — Roles & Permissions guide produced (local draft)
- Sixth settings guide off the production line: Roles & Permissions
(settings.roles_permissions.pilot, guide key roles_permissions, an owner-only tab), authored in app/lib/help/settings-video-guides.ts with every stated behaviour verified against RolesPermissionsTab, the deterministic resolver (app/lib/permission-resolver.ts), the two-key pilot gate (app/lib/custom-rbac-gate.ts) and the permission API's shared save-path helpers (app/api/settings/permissions/_lib.ts): changes take effect only when the club joins the controlled pilot (environment master AND per-club flag, exactly the staged-pilot banner's promise); an individual deny beats every grant; provider connect and platform checkout are system-locked — presets are built to refuse them and the resolver ignores every override layer for locked capabilities; and every save runs the owner-lockout simulation, refusing (409) any change that would leave no owner able to manage permissions and staff. Presets-first is the recommendation, with the reason-required rule for high-risk/sensitive presets covered in the dialog sections.
- New read-only capture script
scripts/help-video/capture-roles-permissions-screens.ts: one frame holds both teaching surfaces on the default Presets sub-view — the pilot banner (asserted verbatim so the capture fails loudly if enforcement ever goes live for the seeded club) and the top preset cards with risk chips (Billing Manager High with the system-locked exclusion note, Refund Manager Critical + Reason required). Preset assignment controls write, so nothing is clicked or toggled. Choreography is a two-target point-and-zoom over the banner and the Billing Manager card — no click ripple, single still. The presets grid gained a stable element id (roles-permissions-presets) for contextual help "Show me".
- Rendered 1080p in the owner's cloned voice and registered as
local_draft
(settings-roles-permissions-v1-chris.*, 32.2s, 6.1MB) awaiting owner review; nothing published. The production line now pauses at six settings drafts pending owner review.
Help-video scripts now stop before expensive production
- Added a fingerprinted script-review gate before voice generation and video
rendering. Each guide must first pass a beginner checklist covering its purpose, recommended default, real on-screen action, automatic versus optional consequences, important boundaries and code-verified accuracy.
- Any relevant wording or product-code change makes the approval stale, and an
unreviewed or change-requested script now stops before the voice model or Remotion starts. The Audience, Closed Dates and Timetable scripts passed the new gate; Closed Dates now makes optional family notifications explicit, and Timetable describes the actual start-time-plus-length control.
Household, member, arrears and calendar audit fixes
- Calendar date headings still open the complete day agenda, while lesson and
event cards in month, week, day, agenda and search views now open their detail directly. The day route keeps the chosen item in a validated query parameter, resolves it only against the club-and-date-scoped payload, and shows a generic unavailable state for stale, malformed or foreign identifiers.
- Reworked the full-page calendar day layout into a responsive agenda/detail
view with a compact mobile header, a clear Back to day action, visible load failures and no second click before bookings, trials or register actions.
- Household and member reads now clear club-owned browser state before a club or
record switch, reject partial/failed snapshots instead of showing false empty states, and surface retry or truncation notices where totals and exports would otherwise be incomplete.
- Arrears is now capability-gated, paged to completion, calculated in club-day
boundaries and net of issued credit notes. The same integer-pence balance is used on household summaries and manual/automatic Direct Debit collection, so a partially credited invoice collects only its remaining balance and a fully credited invoice cannot be collected.
- Removed the unsafe household-wide “mark paid” mutation. Staff now open the
household and settle each invoice through the existing reasoned, audited action; provider-linked invoices remain in their provider lifecycle.
Multi-rank grading awards ready for owner review
- Grading events can now award any higher rank in one ceremony while preserving
every crossed rank as its own ordered progression record and certificate. The confirmation screen names the full award path and certificate count before anything is committed.
- Confirmation, correction and undo replace the full chain atomically. Every
certificate shares the grading issue date, progression anchors at the final rank, and member activity/automation runs once with the start and final ranks rather than once per certificate.
- Event/session PDF batches, background rendering, portal certificates and the
member-experience feed now use one service-only award ledger row per rank. Manual rank changes remain single-hop and do not create grading certificates.
- This is an SQL-first release: owner review and application of the consolidated
supabase/migrations/_DEPLOY-2026-08-02-release-bundle.sql must precede the app deployment. Local apply/reapply, catalogue postflight, five-rank runtime rehearsal and simultaneous-confirm concurrency coverage are green.
One database bundle now prepares the complete release
- The owner now has one pre-deploy psql artifact covering configurable
credentials, editable trial answers, immutable form versions, multi-rank grading and the register/retention database foundations required by this branch. A prerequisite and legacy-certificate preflight runs before any section can write; recovery is always a complete re-run.
- Form Builder's direct database privilege closure remains a separate,
clearly-named post-deploy file because the guarded server build must be live first. Neither SQL file enables a feature flag or retention pilot.
- Reapplying the bundle can no longer stamp
published_at onto live form drafts.
Certificate PDF batches also stop and name every rank missing a renderable template instead of silently returning an incomplete multi-rank batch.