Skip to content

Tighten the duplicate-code check and share more code across the app - #1787

Merged
stefan-burke merged 4 commits into
mainfrom
claude/jscpd-min-tokens-duplication-loa21d
Jul 12, 2026
Merged

Tighten the duplicate-code check and share more code across the app#1787
stefan-burke merged 4 commits into
mainfrom
claude/jscpd-min-tokens-duplication-loa21d

Conversation

@stefan-burke

@stefan-burke stefan-burke commented Jul 12, 2026

Copy link
Copy Markdown
Member

What this does

The project has a checker that fails the build if the same code appears twice. This makes it a little stricter, then removes all the copy-paste it uncovers — and, while in there, pulls several more repeated patterns into single shared helpers.

None of this changes anything people see on the site. It's a tidy-up: the same behaviour, written once instead of many times, so there's less code to maintain and fewer places for the same bug to hide.

The stricter check

The duplicate-code checker only looks at chunks of code above a certain size. This lowers that size by one notch. Because of the way the tool scans, that one small step uncovered 116 near-identical chunks that had been sitting just under the old limit. Every one of them is now removed — the project keeps duplication at zero, so they had to be.

The fixes follow one rule: share the code, don't hide the warning. Most were one of three shapes:

  • Same shape written twice → give it one name (a shared type), written once.
  • Same logic or layout written twice → move it into one small, plainly-named helper or on-screen component that both places use.
  • Just the same import lines → the few of these are marked so the checker skips them (its intended use).

Going further

Once the obvious copies were gone, a few patterns turned out to be repeated in even more places than the checker had flagged. Those got folded into single helpers too:

  • One helper for "look these items up by their id", replacing a scattered handful of hand-written versions.
  • One helper for turning a caught error into a readable message, replacing a dozen copies of the same line.
  • One shared way to read a request's content type, including a third spot the checker had missed.

Review feedback

The automated reviewer raised seven points; six are folded in and one was a deliberate no-change (the loop it flagged is the style this project actually prefers). The fixes worth calling out:

  • The public booking API now cleanly rejects a malformed request body (like an empty null) with a clear error, instead of failing further along.
  • A missing bit of data on the "recount the totals" admin page now fails with a clear, named message instead of a confusing crash.
  • One admin label that was still hard-coded in English now goes through the translation system.

Safety

All automated checks pass: type-checking, linting, the duplicate-code check (back to zero), the copy/wording check, the build, and the full test suite at 100% coverage. New tests were added for each of the behaviour fixes above.

🤖 Generated with Claude Code

https://claude.ai/code/session_01BaLTxRDzaxxQu7xm12khNK

Summary by CodeRabbit

  • New Features

    • Added shared UI components for clearer headings, labelled information, table rows, hidden-status details, and return URLs.
    • Improved admin and payment page layouts with more consistent presentation.
    • Added support for ticket links that preserve the appropriate return destination.
  • Bug Fixes

    • Invalid JSON requests, including arrays and null values, are now rejected consistently.
    • Booking quantity controls work reliably whether displayed as inputs or dropdowns.
    • Webhook signature failures now return a consistent error response.

Tightens the src/scripts/e2e jscpd config (.jscpd.json) from a 23-token to a
22-token minimum. Because jscpd seeds on a fixed window, that one-token drop
surfaced 116 new near-duplicate spans that were previously just under the bar.
This removes every one of them so the 0% threshold still holds.

Most fixes fall into three shapes, matching how the duplication was really
shaped:

- Shared types: where two places repeated the same field list or the same
  function signature, they now share one `type`/`interface`/function-type
  alias (e.g. WriteInputs, StatementLinks, OrderSpan, SnapshotArgsFn, the
  settings-registry pruning shape).
- Shared helpers/components: genuinely repeated logic was lifted into one
  plain-language helper or curried factory, and repeated markup into one small
  component (e.g. errorMessage, withLazyLogger, streamChunks, nonBlankLines,
  HeaderRow, LabelledParas, HiddenDetailRow, AgentHeader, moneyInto/moneyOutOf).
- Import blocks: the few coincidental matches that were only shared import
  lines are wrapped in the sanctioned jscpd:ignore.

Also unifies two overlaps the split surfaced: the duplicate-group form's inputs
now reuse the shared TextField (via optional autofocus/required/duplicate
flags) instead of a parallel DuplicateField, and admin list tables that lead
with a Name column use a namedColumns helper so that column is declared once.

No behaviour changes. Existing tests cover every extraction; the attendees
hardcoded-string allowlist ratchets 5 -> 4 to reflect the smaller template.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BaLTxRDzaxxQu7xm12khNK
@coderabbitai

coderabbitai Bot commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 1bc2ee1b-94ed-4f8b-ac93-9fd2d859ac7d

📥 Commits

Reviewing files that changed from the base of the PR and between 4c3704e and e655782.

📒 Files selected for processing (6)
  • src/shared/dates.ts
  • src/shared/lazy-logger.ts
  • src/shared/storage.ts
  • test/fp.test.ts
  • test/lib/i18n-coverage.test.ts
  • test/lib/lazy-logger.test.ts

📝 Walkthrough

Walkthrough

This pull request consolidates repeated helpers, types, request handling, database operations, booking logic, scripts, and UI rendering across application modules. It also updates duplicate-detection configuration and adds tests for shared lookup, JSON parsing, lazy logging, and recalculation utilities.

Changes

Shared refactor and UI consolidation

Layer / File(s) Summary
Tooling and benchmark helpers
e2e-payments/..., scripts/bench/..., scripts/bunny-regions.ts, scripts/edge-bundle-lib.ts
Quantity controls, benchmark request draining, nonce generation, region extraction, and generated-module inlining use reusable helpers.
Mutation, command, and stream utilities
scripts/mutation/..., scripts/precommit/..., scripts/stream-lines.ts, scripts/stripe-mock/..., scripts/unit-tests-report-lib.ts
Shared contracts and helpers centralize mutation commands, process construction, line parsing, locking, stream iteration, and report formatting.
Admin, API, authentication, and public flows
src/features/admin/..., src/features/api/..., src/features/auth.ts, src/features/public/...
Listing/group loaders, content creation, validation, authentication, JSON parsing, flash handling, and ticket redirects use shared helpers and types.
Booking, accounting, and database abstractions
src/shared/booking/..., src/shared/accounting/..., src/shared/db/...
Booking traversal, quantity aggregation, database schemas, migration queries, SQL statement typing, notes, settings, and persistence routines are refactored around common contracts.
Webhook, storage, and shared utilities
src/shared/webhook*.ts, src/shared/storage.ts, src/shared/stream-chunks.ts, src/shared/error-message.ts, src/shared/lazy-logger.ts
Webhook verification, stream consumption, error formatting, lazy logging, and image transcoding share reusable implementations.
UI components and templates
src/ui/..., src/shared/forms.tsx, src/shared/return-url-field.tsx
Buttons, layouts, table rows, fields, flash types, labelled paragraphs, admin shells, and rendering helpers replace repeated markup and prop types.
Validation and configuration
.jscpd.json, test/...
The duplicate-detection threshold changes, JSCpd regions are marked, and tests cover lookup maps, JSON validation, lazy logging, and recalculation rows.

Estimated code review effort: 4 (Complex) | ~60 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the two main themes: tightening duplicate-code detection and consolidating shared code across the app.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/jscpd-min-tokens-duplication-loa21d

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/bench/bunny-crypto-smoke.ts`:
- Around line 16-18: Update subtleEnc to call the existing randomIv helper
instead of constructing the 12-byte nonce inline, while preserving the current
nonce handling and encryption behavior.

In `@src/features/api/helpers.ts`:
- Line 2: Update parseApiJsonBody to validate the result of JsonBodyReader
before returning it, rejecting null and other non-record JSON values while
preserving valid plain-record payloads. Follow the existing validation pattern
in src/features/auth.ts so route schema checks receive only the promised record
shape.

In `@src/shared/env.ts`:
- Around line 14-15: Update the withLazyLogger usage in isReadOnly() so the
promise remains fire-and-forget while attaching a rejection handler for dynamic
import or callback failures. Keep isReadOnly() synchronous and preserve its
existing return behavior.

In `@src/shared/forms.tsx`:
- Around line 741-752: Move the ReturnUrlField component out of the oversized
forms module into a focused component file, preserving its public export, props,
rendering behavior, and documentation. Remove its local definition from
forms.tsx and import ReturnUrlField there from the new module.

In `@src/shared/payment-helpers.ts`:
- Around line 464-477: Replace the imperative for...of traversal in
collectPackedFields with the repository’s curried `#fp` collection helper, first
confirming the exact utility name and signature from existing usage. Preserve
PACKED_KEYS iteration, readValue invocation, keep-based filtering, and the fresh
Record<string, string> result.

In `@src/ui/templates/admin/attendees.tsx`:
- Around line 114-141: Update the registration date label in the attendee
details component to use the existing t translation function, and add the
corresponding catalog entry if missing; preserve the current label meaning and
formatting.

In `@src/ui/templates/admin/recalculate-rows.ts`:
- Around line 1-23: Update buildRecalculateRows so fields is typed with name:
Name rather than name: string, binding each field name to the snapshot keys;
then remove the name as Name cast and use field.name directly when indexing
snapshot and formatting values.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: cb75ae54-b2c4-43b0-984b-9a328bd7a880

📥 Commits

Reviewing files that changed from the base of the PR and between b9fb817 and cbc1e32.

📒 Files selected for processing (167)
  • .jscpd.json
  • e2e-payments/src/flow.ts
  • e2e-payments/src/order-flow.ts
  • scripts/bench/bunny-crypto-smoke.ts
  • scripts/bench/cold-start/first-request-child.ts
  • scripts/bench/cold-start/first-request.ts
  • scripts/bench/cold-start/serve-root.ts
  • scripts/bunny-regions.ts
  • scripts/edge-bundle-lib.ts
  • scripts/mutation/isolation-state.ts
  • scripts/mutation/isolation.ts
  • scripts/mutation/runner.ts
  • scripts/mutation/summary.ts
  • scripts/precommit/git.ts
  • scripts/precommit/mutation-step.ts
  • scripts/stream-lines.ts
  • scripts/stripe-mock.ts
  • scripts/stripe-mock/install.ts
  • scripts/unit-tests-report-lib.ts
  • src/features/admin/actions.ts
  • src/features/admin/api.ts
  • src/features/admin/attendee-form-routes.ts
  • src/features/admin/attendee-logistics-routes.ts
  • src/features/admin/attendee-page-data.ts
  • src/features/admin/attendees-edit.ts
  • src/features/admin/attendees-merge.ts
  • src/features/admin/catalog-transfer/export.ts
  • src/features/admin/catalog-transfer/import.ts
  • src/features/admin/dashboard.ts
  • src/features/admin/find-group.ts
  • src/features/admin/groups.ts
  • src/features/admin/listing-page-data.ts
  • src/features/admin/listing-qr.ts
  • src/features/admin/listings-edit.ts
  • src/features/admin/listings-view.ts
  • src/features/admin/load-listing.ts
  • src/features/admin/modifiers.ts
  • src/features/admin/money-adjust.ts
  • src/features/admin/news.ts
  • src/features/admin/settings-email-templates.ts
  • src/features/admin/settings-email.ts
  • src/features/admin/settings-sms.ts
  • src/features/admin/settings-statuses.ts
  • src/features/admin/site-content-create.ts
  • src/features/admin/site-content.ts
  • src/features/admin/site-pages.ts
  • src/features/api/helpers.ts
  • src/features/api/json-body.ts
  • src/features/api/listings.ts
  • src/features/auth.ts
  • src/features/feeds.ts
  • src/features/flash-for-page.ts
  • src/features/index.ts
  • src/features/join.ts
  • src/features/public/discovery.ts
  • src/features/public/ticket-page-url.ts
  • src/features/public/ticket-payment.ts
  • src/features/public/ticket-submit.ts
  • src/features/public/ticket-submit/paths.ts
  • src/features/public/unsubscribe.ts
  • src/shared/accounting/manual-entries.ts
  • src/shared/app-forms.ts
  • src/shared/booking/capacity-tree.ts
  • src/shared/booking/fold-tree.ts
  • src/shared/booking/node-order.ts
  • src/shared/booking/order-lines.ts
  • src/shared/booking/order-span.ts
  • src/shared/booking/package-cap.ts
  • src/shared/booking/price-tree.ts
  • src/shared/bunny-cdn.ts
  • src/shared/columns/attendee-columns.ts
  • src/shared/dates.ts
  • src/shared/db/attendees/balance.ts
  • src/shared/db/attendees/create.ts
  • src/shared/db/attributes.ts
  • src/shared/db/client.ts
  • src/shared/db/groups.ts
  • src/shared/db/holidays.ts
  • src/shared/db/id-and-name-columns.ts
  • src/shared/db/listing-parents.ts
  • src/shared/db/migrations.ts
  • src/shared/db/migrations/2026-06-14_rename_events_to_listings.ts
  • src/shared/db/migrations/2026-06-18_contact_preferences.ts
  • src/shared/db/migrations/booking-slot-index.ts
  • src/shared/db/migrations/master-query.ts
  • src/shared/db/migrations/rename-utils.ts
  • src/shared/db/migrations/schema-sync.ts
  • src/shared/db/modifier-resolve.ts
  • src/shared/db/news-posts.ts
  • src/shared/db/query-log.ts
  • src/shared/db/questions/attendee-answers/save.ts
  • src/shared/db/settings.ts
  • src/shared/db/settings/raw-writes.ts
  • src/shared/db/site-pages.ts
  • src/shared/db/slugged-content-input.ts
  • src/shared/db/system-notes.ts
  • src/shared/db/users.ts
  • src/shared/deno-deploy-api.ts
  • src/shared/env.ts
  • src/shared/error-message.ts
  • src/shared/flash-fields.ts
  • src/shared/forms.tsx
  • src/shared/images/transcode.ts
  • src/shared/lazy-logger.ts
  • src/shared/limits.ts
  • src/shared/lines.ts
  • src/shared/listing-attribute-filter.ts
  • src/shared/listings-actions.ts
  • src/shared/listings-by-id.ts
  • src/shared/payment-helpers.ts
  • src/shared/payments.ts
  • src/shared/refund-ledger.ts
  • src/shared/rest/crud-api.ts
  • src/shared/rest/resource.ts
  • src/shared/settings/registry.ts
  • src/shared/square.ts
  • src/shared/storage.ts
  • src/shared/stream-chunks.ts
  • src/shared/stripe.ts
  • src/shared/turso-api.ts
  • src/shared/webhook-verification.ts
  • src/ui/client/admin/markdown-editor-toolbar.ts
  • src/ui/client/dom.ts
  • src/ui/client/order.ts
  • src/ui/templates/admin/activityLog.tsx
  • src/ui/templates/admin/admin-page.tsx
  • src/ui/templates/admin/agent-header.tsx
  • src/ui/templates/admin/api-keys.tsx
  • src/ui/templates/admin/attendee-detail.tsx
  • src/ui/templates/admin/attendee-form.tsx
  • src/ui/templates/admin/attendees.tsx
  • src/ui/templates/admin/builder.tsx
  • src/ui/templates/admin/built-sites.tsx
  • src/ui/templates/admin/built-sites/list-parts.tsx
  • src/ui/templates/admin/bulk-actions.tsx
  • src/ui/templates/admin/deliveries.tsx
  • src/ui/templates/admin/groups.tsx
  • src/ui/templates/admin/hidden-row.tsx
  • src/ui/templates/admin/ledger.tsx
  • src/ui/templates/admin/ledger/statement.tsx
  • src/ui/templates/admin/listing-defaults.tsx
  • src/ui/templates/admin/listings/aggregates.tsx
  • src/ui/templates/admin/listings/details.tsx
  • src/ui/templates/admin/listings/form-sections.tsx
  • src/ui/templates/admin/listings/roster.tsx
  • src/ui/templates/admin/logout.tsx
  • src/ui/templates/admin/modifiers/aggregates.tsx
  • src/ui/templates/admin/money-summary.tsx
  • src/ui/templates/admin/nav.tsx
  • src/ui/templates/admin/privacy.tsx
  • src/ui/templates/admin/recalculate-rows.ts
  • src/ui/templates/attendee-table.tsx
  • src/ui/templates/components/data-table.tsx
  • src/ui/templates/components/error.tsx
  • src/ui/templates/components/header-row.tsx
  • src/ui/templates/components/heading-layout.tsx
  • src/ui/templates/components/labelled-para.tsx
  • src/ui/templates/components/price-input.tsx
  • src/ui/templates/components/prose-heading.tsx
  • src/ui/templates/components/success-complete-page.tsx
  • src/ui/templates/components/text-field.tsx
  • src/ui/templates/payment.tsx
  • src/ui/templates/public/reservations/contact-fields.ts
  • src/ui/templates/public/reservations/listing-rows.ts
  • src/ui/templates/public/unsubscribe.tsx
  • src/ui/templates/tickets.tsx
  • test/lib/i18n-coverage.test.ts

Comment thread scripts/bench/bunny-crypto-smoke.ts
Comment thread src/features/api/helpers.ts
Comment thread src/shared/env.ts
Comment thread src/shared/forms.tsx Outdated
Comment thread src/shared/payment-helpers.ts
Comment thread src/ui/templates/admin/attendees.tsx
Comment thread src/ui/templates/admin/recalculate-rows.ts
Follow-up to the duplication cleanup. Zooming out on the extracted helpers
surfaced several idioms that were still repeated in more places than the
original clone pass touched, plus a handful of small correctness/quality
points from the PR review.

Deeper consolidation:
- Add one generic `byId` helper to #fp and route every "index items by their
  id" site through it: the old `listingsById`, two separate `listingsByIdMap`
  definitions, and several inline `new Map(x.map(i => [i.id, i]))` copies. The
  single-purpose `listings-by-id.ts` is deleted.
- Use the shared `errorMessage` helper at the 12 remaining places that still
  spelled out `err instanceof Error ? err.message : String(err)` by hand.
- Share the request Content-Type normaliser: a third site (the always-loaded
  middleware) used `|| ""` so the duplication checker never flagged it. The
  normaliser now lives in the middleware and every caller reuses it.

Review fixes:
- Reject non-record JSON bodies (e.g. `null`) in the public API parser, the
  same way the cookie-auth parser already does, so malformed bodies fail with
  a clear 400 instead of throwing deeper in.
- The lazy logger no longer lets a failed load leak an unhandled rejection.
- Give the recalculate-rows builder a loud, named error when a snapshot field
  is missing, instead of a silent cast that could crash on a bad pairing.
- Wire the attendee "Registered:" label through the message catalog.
- Move the return-url form field into its own file, and reuse the shared
  random-nonce helper in the crypto benchmark.

New regression tests cover the JSON-body guard, the lazy-logger swallow, the
recalculate-rows guard, and the new `byId` helper.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BaLTxRDzaxxQu7xm12khNK
@stefan-burke stefan-burke changed the title Lower jscpd minTokens to 22 and remove all resulting duplication Tighten the duplicate-code check and share more code across the app Jul 12, 2026
@stefan-burke
stefan-burke enabled auto-merge July 12, 2026 13:02

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/shared/lazy-logger.ts`:
- Around line 12-13: Update withLazyLogger to accept callbacks returning void or
Promise<void>, then await the callback invocation inside the existing try/catch
so asynchronous rejections are handled by that catch. Preserve the current lazy
logger import and synchronous callback behavior.

In `@test/fp.test.ts`:
- Around line 520-525: Split the combined test around byId into two independent
tests: one verifying that later items with the same id win, and another
verifying that empty input returns an empty Map. Preserve the existing
assertions and behavior while giving each test a focused name.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: c00046e3-e924-4945-905a-53c3243a1c7a

📥 Commits

Reviewing files that changed from the base of the PR and between cbc1e32 and 4c3704e.

📒 Files selected for processing (35)
  • scripts/bench/bunny-crypto-smoke.ts
  • scripts/safe-upgrade.ts
  • src/features/admin/attendee-form-routes.ts
  • src/features/admin/attendee-page-data.ts
  • src/features/admin/calendar-csv.ts
  • src/features/admin/catalog-transfer/import.ts
  • src/features/admin/servicing.tsx
  • src/features/admin/settings-superuser.ts
  • src/features/api/helpers.ts
  • src/features/auth.ts
  • src/features/feeds.ts
  • src/features/index.ts
  • src/features/middleware.ts
  • src/features/public/discovery.ts
  • src/fp.ts
  • src/shared/accounting/store.ts
  • src/shared/botpoison.ts
  • src/shared/db/attendees/capacity.ts
  • src/shared/db/groups.ts
  • src/shared/db/migrations.ts
  • src/shared/email-renderer.ts
  • src/shared/email.ts
  • src/shared/forms.tsx
  • src/shared/lazy-logger.ts
  • src/shared/logger.ts
  • src/shared/return-url-field.tsx
  • src/shared/site-pages/core.ts
  • src/shared/webhook.ts
  • src/ui/templates/admin/attendees.tsx
  • src/ui/templates/admin/recalculate-rows.ts
  • src/ui/templates/attendee-table.tsx
  • test/fp.test.ts
  • test/lib/api-json-body.test.ts
  • test/lib/lazy-logger.test.ts
  • test/lib/recalculate-rows.test.ts

Comment thread src/shared/lazy-logger.ts Outdated
Comment thread test/fp.test.ts Outdated
claude and others added 2 commits July 12, 2026 13:05
- withLazyLogger now accepts void | Promise<void> and awaits the callback, so
  a rejecting async callback is caught by the same try/catch instead of leaking
  an unhandled rejection. Adds a regression test for the async-reject path.
- Split the combined byId test into one-behaviour-each tests (duplicate-id
  precedence; empty input), per the test standards.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BaLTxRDzaxxQu7xm12khNK
@stefan-burke
stefan-burke added this pull request to the merge queue Jul 12, 2026
Merged via the queue into main with commit b95f957 Jul 12, 2026
3 checks passed
@stefan-burke
stefan-burke deleted the claude/jscpd-min-tokens-duplication-loa21d branch July 12, 2026 13:23
stefan-burke pushed a commit that referenced this pull request Jul 12, 2026
…isfy stricter cpd

Main's tightened jscpd threshold (#1787) flagged the paired thin wrappers and
the duplicated attendee-by-id load once merged in. Restructure the reader layer
so there's a single SQL builder:

- attendeeBatchStatement is now the one place a declared query becomes SQL;
  getAttendees runs it, and the batch listing readers embed it. Removes the
  selectAttendees/selectAttendeeOrNull pair and getAttendeeRow.
- getAttendeeRaw is the single attendee-by-id read; attendees-edit and
  attendees-merge reuse it instead of re-inlining the same getAttendees call.
- Collapse the singular attendeeId/listingId filters into attendeeIds/listingIds
  (a single lookup is a one-element array), matching the repo's "one path for
  one-or-many" rule and dropping the duplicate WHERE branches.

getAttendeesByIds keeps its kind='attendee' filter — that's the exact
behaviour the pre-existing query had; whether the logistics run sheet should
include servicing events is a separate product decision, recorded in TODO.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G24MzgR46DN4ju1srifKaq
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants