> ## Documentation Index
> Fetch the complete documentation index at: https://docs.calgest.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 2026 09 08 security correctness

# Security and correctness audit fixes

The audit covered backend authorization, scheduling, recurrence, client state, mobile startup, dependency advisories, and build checks. Existing work was checkpointed in `ee47e5c`; fixes are on `fix/security-correctness-audit`. No Fable agents were used.

| Finding                                                         | Change                                                                                                                                                                                      | Regression coverage                                                                                                                       |
| --------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| 1. Tracking reads exposed other customers' data                 | Require tracking permissions and Customer ownership across records, metrics, groups, and enablement queries.                                                                                | Default-role denial, authorized staff reads, Customer self access and foreign-record denial.                                              |
| 2. Invitations bypassed role assignment limits                  | Share the permission ceiling with direct role assignment, pin the default role, and recheck inviter authority and role at acceptance.                                                       | Privileged invites, changed defaults, removed membership, changed permissions, deleted and foreign roles.                                 |
| 3. Assistant and export paths bypassed custom-field permissions | Share field permissions and entity access with direct APIs. Exports identify omitted sensitive relations.                                                                                   | Direct, assistant, search, proposal, details and export paths.                                                                            |
| 4. Calendar and conflict reads truncated before filtering       | Walk start/end indexes, deduplicate overlaps, limit matching results, and reject incomplete reads. Share one scan across employees. Employee lists count matches instead of unrelated rows. | More than 2,000 historical or colleague events, long events, exact boundaries, other tenants, oversized results and 10,001 future events. |
| 5. Field deletion ignored appointment assignment                | Apply entity access checks to both deletion endpoints.                                                                                                                                      | Unassigned deletion denied; authorized deletion preserved.                                                                                |
| 6. Monthly generation skipped dates                             | Consider the current month and normalize the day before changing months.                                                                                                                    | January 31, leap years, intervals and date/count boundaries.                                                                              |
| 7. Regeneration dropped the first occurrence                    | Use an exclusive boundary before the start and count retained/excluded dates once.                                                                                                          | All/future edits, exceptions, no-shows and changed recurrence patterns.                                                                   |
| 8. Single-occurrence edits left stale jobs                      | Share reminder and aftercare lifecycle handling with ordinary updates. Reminder cancellation only cancels reminder events.                                                                  | Actual scheduled rows are canceled and replaced with correct times; terminal statuses remain suppressed.                                  |
| 9. Recurrence cron continuation depended on a surviving row     | Use opaque pagination cursors and bounded per-series generation. Preserve old job argument compatibility.                                                                                   | Deleted/deactivated page boundaries, legacy cursors and generation bounds.                                                                |
| 10. Query wrappers retained obsolete identity/state             | Use Convex query results and pagination controls directly; verify selected customer identity.                                                                                               | Argument/skip changes, pagination loading and stale customer fallback.                                                                    |
| 11. Calendar fetch used the wrong week start                    | Derive the fetch window from the same effective preference as the scheduler.                                                                                                                | Sunday overflow and preference/navigation changes.                                                                                        |
| 12. Booking availability used a frozen clock                    | Refresh on an interval, focus, visibility and rejected availability.                                                                                                                        | Fake-clock advancement and refresh events.                                                                                                |
| 13. Mobile photos disappeared after the first 50                | Keep stable batches of at most 50 and renew expired signed URLs with authorized subscriptions.                                                                                              | Multiple pages, replacements, expiry and auth/organization changes.                                                                       |
| 14. Notification links ignored organization context             | Validate membership and complete the organization transition before loading the target.                                                                                                     | Cross-organization, cold-start, membership-revocation and account-change cases.                                                           |
| 15. Vulnerable TOML parser blocked CI                           | Pin the transitive parser to 4.2.0 without unrelated dependency upgrades.                                                                                                                   | OSV gate, production MDX build and an independent TOML-frontmatter compilation check.                                                     |
| 16. Font load failure blocked startup                           | Release the splash screen and render with fallback fonts after a load error.                                                                                                                | Successful load, error and pending-load cases.                                                                                            |

Independent review also identified Customer tracking writes that lacked ownership checks, recurrence mutation authorization and conflict-policy gaps, retained exceptions outside a changed recurrence pattern, and a three-day calendar range that could repeatedly render. These are covered by the same fixes and additional regressions. The web typecheck command now follows its referenced projects; this exposed and corrected fragment-link types, an obsolete client type reference, and an incomplete booking-result type.

The TOML upgrade addresses [uncontrolled recursion](https://github.com/advisories/GHSA-82x6-q7mm-w9cf) and [prototype pollution](https://github.com/advisories/GHSA-v5mp-jgw5-2x6j). The dependency gate retains the repository's existing documented advisory exclusions.

Validation on the integrated changes:

* `pnpm test:once`: 122 files, 1,629 tests passed.
* `pnpm test:ops`: 2 tests passed.
* `pnpm check-types`: all 5 workspace tasks passed.
* `pnpm lint`: passed with 48 existing warnings and no errors.
* `SENTRY_AUTH_TOKEN='' pnpm exec turbo run build --force`: all 3 production build tasks passed; CDN deployment was a dry run.
* `EXPO_NO_TELEMETRY=1 pnpm exec expo export --platform ios`: local iOS bundle export passed.
* `bash scripts/osv-audit.sh`: passed under the repository's advisory policy.
* Convex code generation and typecheck passed. The final schema and functions compiled on an isolated anonymous backend; a real mutation seeded 2,001 historical appointments and verified that the overlap reader returned the one current appointment.
* `git diff --check`: passed. The commit hook scans staged changes for secrets.

The first final-suite attempt passed every assertion but reported two teardown errors from queued billing work in `organizationSettings.test.ts`. Fake timers now keep those jobs pending while the tests inspect their registration; the full rerun passed without unhandled errors. Independent technical review prompted additional fixes to recurrence counting and navigation history before completion. Implementation and review after the checkpoint took about 35 minutes. The final focused reviews reported no remaining blockers. Reviewer checks used real Convex handlers and installed navigation routers; native-device behavior remains unverified.

The calendar lookup rejects more than 2,000 matching appointments or an incomplete scan after 10,000 reads. Convex may reject earlier on its byte limit. This prevents partial calendars and false availability; it is not a replacement for a paginated calendar API at larger scale. The new end-time index needs to finish building when deployed. The optional recurrence `reservedDates` field records slots already counted during regeneration, preserving correct counts across deletion or detachment before generation resumes.

Employee and Customer bulk recurrence operations require access to the current and proposed template and every materialized occurrence. Series with 200 or more rows require an organization administrator. Smaller authorized operations delete within the requesting transaction, preventing an authorization change from racing a later destructive job. Single-occurrence operations retain their row-level checks.

The changes do not rewrite previously generated appointments or repair production data. Existing affected recurrence series need explicit review and regeneration if their materialized dates are already wrong. Local backend validation uses an isolated database and a dummy auth issuer. Native-device navigation, actual push/email delivery and production data migration remain outside the verification performed here.
