feat(events-crawler): Capilano University adapter, staged disabled - #94
Conversation
Second of the deferred orgs, and the deferral rationale again did not survive the re-check: each li.event-item carries month, day, optional end date, optional times, venue, link and image inline, so there is no N+1. ONE PAGE ONLY, and that is a robots decision rather than an oversight. capilanou.ca/robots.txt has a `User-agent: *` block disallowing /*?search=* and /*&search=*, and every calendar-navigation URL the page offers is of the form ?day=14&month=08&year=2026&search=day. So the month and day views are off-limits and this reads only the unparameterized listing — about ten upcoming items. The adapter header says so explicitly, because the obvious "fix" for a low count here is to add the query parameters, and that would be the wrong thing to do. The low yield is correct, not broken. The calendar is largely academic administrivia — fee deadlines, grade-submission dates, campus closures — which relevanceFilter is right to drop. Measured 1 of 10 passing: "Fall 2026 New International Student Orientation", caught by relevance.ts's `international student` term. One genuinely on-mission event is the realistic yield. Most items have no time. 8 of those 10 are all-day entries with no datelisting span at all, INCLUDING the one relevant event, so they are stored at 09:00 local. That asserts an hour the source does not state, which is a real if small cost; skipping timeless items instead would have dropped the only event worth having. No weekday is published, so the year cannot be checked the way nvcl.ts checks it. The listing is chronological instead, so the year is carried forward monotonically and rolls as soon as a month/day goes backwards — which is what stops a December-to-January listing filing January in the past. Also fixes a shared gap this surfaced: decodeEntities handled numeric entities and a few named ones but not –, so "Last Day of Classes for Summer 2026 – Session II" would have been stored verbatim. Added the named forms of punctuation already handled numerically (ndash, mdash, curly quotes, hellip). Regression dry-run across other adapters after the change: mosaic 25, nvdpl 16, surrey 25 — the same counts recorded in #86. Verified with the real harness: deno check clean; dryrun parses all 10 blocks with correct times, multi-day ranges, stripped "Venues>" prefixes and real cover images for the two concerts, and yields exactly the 1 relevant row as shipped. tsc and lint clean. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (5)
WalkthroughAdds a Capilano University events adapter with date, relevance, venue, image, deduplication, and error handling. Registers the disabled source, adds its source kind, decodes additional HTML entities, and allowlists its image host. ChangesCapilano events
Estimated code review effort: 4 (Complex) | ~45 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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 |
|
@coderabbitai full review |
✅ Action performedFull review finished. |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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 `@supabase/functions/events-crawler/adapters/capilano.ts`:
- Around line 84-90: Extend StructuralMisses and PageParse to track venue
failures and postFilterAttempts separately from the pre-filter structural count.
Increment postFilterAttempts for each candidate reaching venue extraction,
increment misses.venue when location is absent before continuing, and update the
final diagnostic check to alert when every post-filter attempt failed venue
extraction while preserving existing title/stamp handling.
🪄 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: baa2e958-f325-4652-aa9b-87ab8bd6bd14
📒 Files selected for processing (5)
next.config.tssupabase/functions/events-crawler/adapters/capilano.tssupabase/functions/events-crawler/lib/sources.tssupabase/functions/events-crawler/lib/text.tssupabase/functions/events-crawler/lib/types.ts
…l miss Valid finding, and the same silent-zero hazard as nvcl.ts's third round — which I said I would carry forward into this adapter and then missed one layer of. Venue extraction sat after the relevance and window filters, and its `continue` was counted by nothing: if VENUE_RE stopped matching, every row would drop there and the source would go to zero with no diagnostic, looking exactly like a university with nothing on. Fixed by moving venue extraction ahead of the filters rather than adding a second counter for post-filter attempts. Ordering was the actual defect: a structural failure sitting downstream of merit-based ones cannot be compared against the block count, because filtered rows never reach it. With the whole extraction chain — title, stamp, venue — ahead of the filters, the existing single comparison covers all three, and there is no second counter to keep in sync. Cost is a regex on rows about to be discarded, across roughly ten blocks. Verified by breaking VENUE_RE against the live feed: "matched 10 block(s) but extracted none of them (title 0, date stamp 0, venue 10)". Silent before this. Restored, the shipped config still yields its 1 row. deno check clean. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Applied in Venue extraction sat after the relevance and window filters, and its Fixed by reordering rather than adding a second counter. The suggestion was to track The cost is a regex on rows about to be discarded, across roughly ten blocks. Documented inline so the ordering doesn't look accidental and get "tidied" back later. Verified by breaking Silent before this change. Restored, the shipped config still yields its 1 row ( |
|
@coderabbitai full review |
✅ Action performedFull review finished. |
What & why
Second of the three deferred orgs. The deferral rationale again didn't survive re-checking — each
li.event-itemcarries month, day, optional end date, optional times, venue, link and image inline, so there is no N+1.Ships
enabled: false. No deploy, no enable.🛑 One page only — a robots decision, not an oversight
capilanou.ca/robots.txthas aUser-agent: *block disallowing/*?search=*and/*&search=*. Every calendar-navigation URL the page offers is of the form?day=14&month=08&year=2026&search=day, so the month and day views are off-limits to us. This adapter reads only the unparameterized listing — about ten upcoming items, no pagination.That's stated prominently in the adapter header, because the obvious reaction to a low count here is "add the query parameters", and that would be knowingly violating the site's stated policy.
The low yield is correct, not broken
The calendar is largely academic administrivia — fee deadlines, grade-submission dates, campus closures — which
relevanceFilteris right to drop. Measured 1 of 10 passing:Fall 2026 New International Student Orientation— caught by relevance.ts'sinternational studentOne genuinely on-mission event is the realistic yield. Unlike NVCL, that's not zero — and it's exactly the audience this app serves.
Decisions baked in
All-day items get 09:00 local. 8 of the 10 have no
datelistingspan at all — including the one relevant event.events.event_datetimeis NOT NULL, so skipping timeless items would have dropped the only row worth having. Storing 09:00 asserts an hour the source doesn't state, which is a real if small cost; 09:00 rather than midnight because the row renders as a time and "12:00 AM" reads as a bug.Year is carried forward monotonically. No weekday is published, so it can't be checked the way
nvcl.tschecks it. The listing is chronological instead, so the year rolls as soon as a month/day goes backwards — which is what stops a December-to-January listing filing January in the past.Venues>prefix stripped from the venue text, and multi-day end dates come fromdate-stamp2(independent of end times, since a multi-day item often has no times and a concert has an end time but no second stamp).Dedupe is defensive here, not load-bearing — 10 distinct links in 10 blocks, with none of the repeated featured section
nvcl.tshas to handle. Kept so a future recurring-event grouping can't produce a duplicate-key insert.Also fixes a shared gap this surfaced
decodeEntitieshandled numeric entities and a handful of named ones, but not–— soLast Day of Classes for Summer 2026 – Session IIwould have been stored verbatim in a title. Added the named forms of punctuation already handled numerically (ndash,mdash, curly quotes,hellip).This is shared code, so it was regression-tested rather than assumed: mosaic 25, nvdpl 16, surrey 25 after the change — the same counts recorded in #86.
Changes
adapters/capilano.ts(new)lib/types.ts—capilanoadded toSourceKind(theADAPTERSrecord is exhaustive, so a missing implementation is a compile error)lib/sources.ts— import,ADAPTERSentry, registry blocklib/text.ts— named punctuation entities indecodeEntitiesnext.config.ts— allowlistwww.capilanou.ca(it serves real event images; NVCL needed no entry, since its listing uses an icon font)enabled: false; no migration, cron, Vault secret or DB object touched; not deployed; no writes to shared prod. Enabling needs Savar's sign-off, as the Phase-2 flip did.Verification
deno check(CI's invocation)npx tsc --noEmitnpm run lintopengraph-image.tsx)dryrun --source capilano(shipped)dryrun, filter offtext.tschangeFilter-off output, showing times, multi-day ranges and real covers all resolving:
Reviewer notes
nvcl.ts, with the relevance and window filters deliberately excluded from the count — they reject on merit, and dropping most of an academic calendar is their job, so folding them in would fire the diagnostic on every healthy run.date-stamp2month is parsed rather than assumed equal to the start month, so a range spanning a month or year boundary resolves correctly. No such range exists in the current listing.🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Bug Fixes