feat(#1186): PR3 — Granite ClubEG charge-through backfill (read-only triage + DRY backfill)#1206
Conversation
…triage + DRY backfill) The final piece of the #805/#817 → #1186 charge-through cluster. Models the $25,370.25 ClubEG golf-program funds as a per-sub-trip charge-through (pass-through) activity on each active Granite sub-trip, and excludes the inbound orphan commission line. Does NOT create the #761 outbound payout (Al runs that manually later once ClubEG is a provisioned payee). The Granite group is informal (trip_group_id NULL) and no auditable list of the 24 active ClubEG sub-trips existed — only prose in the cluster plan. So PR3 is two SELECT-only / DRY-default scripts mirroring the #817 triage→confirm→apply pattern: 1. triage-issue805-granite-subtrips.ts (READ-ONLY): from the one explicit input (the inbound orphan id a31b9896…) derives the Granite parent check (orphan.check_id), enumerates every LINKED commission line on it → trips, and dumps the discriminating fields (description, supplier, activity name, trip status, owner, traveller headcount, Σ commission cents) so Al marks the 24 genuine ClubEG sub-trips vs the ~7 unrelated Sunwing bookings + 1 cancelled. 2. backfill-issue805-granite-charge-through.ts (DRY-default): consumes the Al-CONFIRMED worksheet; RE-ASSERTS every trip against prod (active + owner == EXPECTED_OWNER_ID Andy + a genuine linked Granite line on the parent check); splits $25,370.25 by per-traveller headcount via largest-remainder apportionment (Σ == program total EXACTLY, deterministic remainder, fresh headcount read); find-or-creates one floating charge-through AP per sub-trip (is_charge_through=true, commission 0, pay_on_site=false — the PR1 CHECK shape); excludes the inbound orphan (reason pass_through_program_funds, NOT linked — design §10.8); and surfaces the Σ(per-subtrip)==inbound==intended- outbound reconciliation (aborts on mismatch). Idempotent; count-guarded (--expect); preconditions assert the Phase-3a + PR1 CHECKs are live. issue805-granite-constants.ts: shared constants + the apportionment helper. Both DRY/SELECT-only — Al runs them via the operator pattern. No prod writes in session. No migration. Typecheck clean (strict); apportionment unit-verified (Σ exact, deterministic tie-break); guards smoke-tested. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…gate) 1. CT_ACTIVITY_TYPE 'tour' → 'package'. A FLOATING activity (itinerary_day_id NULL, trip_id set) is constrained by chk_activity_has_parent (#812 migration) to activity_type IN ('package','insurance') — a 'tour' insert would have been REJECTED on the first --confirm row. 'package' is constraint-allowed and is the design's own wording; charge-through is already excluded from money rollups by PR2/PR2.5 (only a cosmetic +1 in the package COUNT remains). ('insurance' is semantically wrong + has its own special handling.) 2. backfill write gate: --confirm is now the SOLE execution gate — removed the `|| process.env.CONFIRM === 'true'` env bypass so a stray env var can never turn a DRY rehearsal into a prod write. tsc strict clean; CT_ACTIVITY_TYPE/marker consistency verified. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthroughAdds a Granite triage exporter, shared constants with deterministic headcount apportionment, and a transactional backfill that validates confirmed sub-trips, creates charge-through pricing, excludes the orphan commission item, and verifies the final totals. ChangesGranite charge-through workflow
Sequence Diagram(s)Triage CSV generationsequenceDiagram
participant Operator
participant TriageScript as triage-issue805-granite-subtrips.ts
participant Postgres
Operator->>TriageScript: run with TARGET_ORPHAN_ID
TriageScript->>Postgres: validate orphan and fetch linked commission lines
Postgres-->>TriageScript: orphan row and trip aggregates
TriageScript-->>Operator: CSV rows on stdout and coverage summary
Backfill confirm executionsequenceDiagram
participant Operator
participant BackfillScript as backfill-issue805-granite-charge-through.ts
participant CsvAllowList as CSV allow-list
participant Postgres
Operator->>BackfillScript: run with --file and --confirm
BackfillScript->>CsvAllowList: read confirmed trip IDs
CsvAllowList-->>BackfillScript: allowed sub-trips
BackfillScript->>Postgres: validate orphan, sub-trips, and live constraints
Postgres-->>BackfillScript: validation rows
BackfillScript->>Postgres: transaction inserts, updates, and orphan exclusion
Postgres-->>BackfillScript: commit result
BackfillScript->>Postgres: post-commit proof queries
Postgres-->>BackfillScript: totals and exclusion state
BackfillScript-->>Operator: completion logs
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related issues
Possibly related PRs
Poem
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
ESLint install failed: dependency version conflict. Check your lock file or package.json. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
#1186 PR3 — Granite ClubEG charge-through backfill (final piece of the #805/#817 cluster)
Models the $25,370.25 ClubEG golf-program funds (currently one orphan
commission_check_itemsrowa31b9896…, both link cols NULL → invisible) as a per-sub-trip charge-through (pass-through) activity on each of the 24 active Granite sub-trips, and excludes the inbound orphan. Does not create the #761 outbound payout — Al runs that manually later once ClubEG is a provisioned payee.The Granite group is informal (
trip_group_idNULL) and no auditable list of the 24 active ClubEG sub-trips existed — only approximate prose in the cluster plan ("~24 ClubEG sub-trips + ~7 unrelated Sunwing bookings" share the same Sunwing deposit check, + 1 cancelled). So PR3 is two SELECT-only / DRY-default scripts mirroring the already-merged #817 triage→confirm→apply pattern — no one guesses trip IDs.Scripts
triage-issue805-granite-subtrips.ts(READ-ONLY) — from the one explicit input (the inbound orphan id) derives the Granite parent check (orphan.check_id), enumerates every linked commission line on it → trips, and dumps the discriminating fields (description, supplier, activity name, trip status, owner, traveller headcount, Σ commission cents) so Al marks the 24 genuine ClubEG sub-trips (CONFIRM_is_granite_subtrip = YES) vs the unrelated Sunwing bookings + the cancelled trip.backfill-issue805-granite-charge-through.ts(DRY-default) — consumes the Al-confirmed worksheet; re-asserts every trip against prod (in the orphan's agency,status != 'cancelled',owner_id == EXPECTED_OWNER_IDAndy, and a genuine linked Granite line on the parent check); splits $25,370.25 by per-traveller headcount via largest-remainder apportionment (Σ == program total exactly, deterministic remainder, fresh headcount read); find-or-creates one floating charge-throughpackageAP per sub-trip (is_charge_through=true, commission 0,pay_on_site=false— the PR1 CHECK shape); excludes the inbound orphan (reasonpass_through_program_funds, NOT linked — design §10.8); and surfaces the Σ(per-subtrip) == inbound == intended-outbound reconciliation (aborts on mismatch). Idempotent; count-guarded (--expect); asserts the Phase-3a + PR1 CHECKs are live.issue805-granite-constants.ts— shared constants + the apportionment helper.Operator recipe (Al runs — DRY/SELECT-only in-session)
DATABASE_URL=<prod> TARGET_ORPHAN_ID=<full uuid of a31b9896…> npx tsx scripts/migration/triage-issue805-granite-subtrips.ts > granite-worksheet.csvgranite-worksheet.csv, setCONFIRM_is_granite_subtrip = YESon the 24 genuine ClubEG sub-trips ONLY (leave the ~7 unrelated Sunwing + 1 cancelled BLANK). Note Andy'sowner_id(column) and the orphan's full uuid.DATABASE_URL=<prod> ACTOR_ID=<admin uuid> EXPECTED_OWNER_ID=<Andy owner_id> TARGET_ORPHAN_ID=<orphan uuid> npx tsx scripts/migration/backfill-issue805-granite-charge-through.ts --file=granite-worksheet.csv--expect=Nonly if genuinely intended).--confirm(sole write gate). Post-state proof prints Σ + orphan-excluded.Verification
ad330965; round-1 BLOCK on the floating-activity type + the env write-gate resolved in round-2).tscstrict clean on all 3 files; apportionment unit-verified (Σ exact 2,537,025; equal-weight 100/3 → [33,34,33] remainder to smallest id); FATAL +--expectguards smoke-tested.tsx.🤖 Generated with Claude Code
Summary by CodeRabbit