Skip to content

feat(events-crawler): widen relevance to digital-skills content - #96

Merged
ltanafranca1004 merged 2 commits into
mainfrom
feat/relevance-digital-skills
Aug 9, 2026
Merged

feat(events-crawler): widen relevance to digital-skills content#96
ltanafranca1004 merged 2 commits into
mainfrom
feat/relevance-digital-skills

Conversation

@ltanafranca1004

@ltanafranca1004 ltanafranca1004 commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator

What & why

lib/relevance.ts missed content that is plainly on-mission because libraries title it by product or program name rather than by the category words the filter knew. Closes the BACKLOG.md digital-skills entry.

Filter-only change plus the instrument needed to measure it. No adapter, schema, migration, cron or next.config.ts change, and no source is enabled or disabled here.

🛑 Merging this does NOT go live

The deployed function is v7, which predates this. Merging changes what a future deploy would ship. Deploy is a separate, separately-approved step.

The terms

term catches rows
tech(nology)?\s+(cafe|help|support) "One on One Technology Help", "Drop-in Technology Help" 21
open\s+door\s+(community|drop) Open Door community hub (NVCL + NVDPL's shared newcomer drop-in) 29
\bms\s+… / microsoft\s+… / intro(duction)?\s+to\s+… / \bspreadsheet "MS Office learn and practice: Intro to Word" 4
laptop\s+help "Windows laptop help", "Mac laptop help" 2

The technology miss was the largest, and it was not in the backlog entry that prompted this work — the capture found it.

Every office word is qualified behind ms / microsoft / intro to. The bare forms are traps the live feeds actually contain: \bexcel\b → "Excel in Your Studies", \bword\b → "Crossword Club" / "Wordplay for Toddlers", \bpowerpoint\b → "PowerPoint Karaoke Night".

How this was measured

A normal dry run only shows titles that already passed, while the whole question is which rejected titles a new term lets in. So dryrun.ts gains:

  • --no-filter — runs the adapter against { ...source, relevanceFilter: false }, i.e. the source's whole calendar. No adapter changes; they already read source.relevanceFilter. The registry is copied, not mutated, and the harness has no Supabase import — still write-free.
  • --titles — one KEEP/DROP line per row. n/a for sources that are never filtered, so a settlement agency's rows can't be misread as excluded.

Captured all seven filtered sources' full 4-month windows (MAX_PER_ORG raised locally for the capture only — constants.ts has no diff in this PR).

Result: 845 rows / 395 distinct titles → 9 distinct titles (56 rows) flip DROP → KEEP, 0 lost. Nothing else moved. A term here is a union alternative, so it can only add keeps — the entire regression surface is false positives, and there are none.

All 9 flipped titles
+ Drop-in Technology Help
+ Drop-in technology help
+ Drop-in technology help in Farsi کمک به رفع اشکال تکنولوژی به زبان فارسی
+ MS Office learn and practice: Intro to Word
+ Mac laptop help
+ One on One Technology Help
+ Open Door Community Hub Drop-In
+ Open door community hub
+ Windows laptop help

Forecast at the real cap of 25

source before after
nvdpl 11 20
surrey-libraries 25 25 (cap-bound; composition shifts as Technology Help interleaves by date)
vpl / sfu / westvan-library / capilano 22 / 3 / 6 / 1 unchanged
nvcl (disabled) 10 25

So on the next deploy one live source changes: nvdpl, +9 rows.

New: lib/relevance_test.ts

The repo has no tests today, so this is a new pattern. It earns its place: isSettlementRelevant is a pure function shared by every filtered source, and the \bword\b hazard was previously recorded in BACKLOG.md prose, which cannot fail a run. 26 real titles that must KEEP, 29 near-misses that must DROP — every string captured from a live feed.

deno test supabase/functions/events-crawler/lib/relevance_test.ts

Backlog correction

The entry claimed NVCL's whole 4-month window was 27 titles matching none, for 0 rows. Re-measured untruncated: it is 61 distinct titles and the filter already kept 10 (an English Corner series). The old figure was taken with MAX_PER_ORG at 25, which stops the unfiltered walk after ~2 pages — it only ever saw August's storytimes, not September's settlement programming. So NVCL was never going to ship 0 rows.

Verification

  • deno test — 2/2 pass
  • deno check — clean on all 17 crawler files
  • npx tsc --noEmit — exit 0
  • eslint — unaffected; supabase/functions/** is ignored (eslint.config.mjs:17)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added dry-run options to preview event relevance decisions and compare source-calendar counts with potential insertions.
    • Improved event matching for technology, device-help terms, Microsoft Office products, and Open Door Community/Drop programs.
  • Bug Fixes
    • Corrected event measurement results using uncapped scanning.
  • Tests
    • Added regression coverage for relevant titles, near-matches, accent handling, word boundaries, and overly broad terms.
  • Documentation
    • Updated backlog guidance and documented dry-run options and expected status output.

The filter missed content that is plainly on-mission because libraries
title it by product or program name rather than by the category words
the filter knew. Adds, all evidence-driven from a full capture of every
filtered source's 4-month window:

- tech(nology)? (cafe|help|support) — "One on One Technology Help" and
  "Drop-in Technology Help" never matched `tech (help|support)`. This is
  the largest miss, 21 rows across Surrey and NVCL, and was not in the
  backlog entry that prompted this work.
- laptop help — "Windows laptop help", "Mac laptop help".
- Qualified office-suite terms — NVCL's "MS Office learn and practice:
  Intro to Word". Every office word sits behind `ms`, `microsoft` or
  `intro to`: the bare forms are traps the live feeds actually contain
  ("Excel in Your Studies", "Crossword Club", "Wordplay for Toddlers",
  "PowerPoint Karaoke Night").
- open door (community|drop) — the Open Door community hub, NVCL's and
  NVDPL's shared newcomer drop-in, 29 rows. Qualified so it cannot catch
  "Open Door Poetry Reading" or "Open Doors Heritage Tour".

Measuring this needed an instrument, so dryrun.ts gains --no-filter (runs
the adapter against a copy of the Source with relevanceFilter off) and
--titles (one KEEP/DROP line per row). A normal dry run only shows what
already passed, while the whole question is what a new term would let in.
No adapter changes — they already read source.relevanceFilter — and the
harness stays write-free.

Measured across all 845 rows / 395 distinct titles of the seven filtered
sources: 9 distinct titles (56 rows) flip DROP -> KEEP, nothing lost. A
term here is a union alternative, so it can only add keeps.

relevance_test.ts locks in every target and its near-misses. The bare
`\bword\b` hazard was previously recorded in BACKLOG.md prose, which
cannot fail a run.

Also corrects a stale figure in BACKLOG.md: NVCL's window is 61 distinct
titles of which the filter already kept 10, not 27 keeping none. The old
measurement was truncated by MAX_PER_ORG stopping the unfiltered walk
after ~2 pages, so it only saw August storytimes, not September's
settlement programming.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Aug 9, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
web-app Ready Ready Preview Aug 9, 2026 2:08am

@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

No new commits to review since the last review.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 0994b7bb-ed87-40c6-989f-4e94efac50c6

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

The events crawler now supports broader settlement-title matching, regression tests, and dry-run inspection modes. The backlog records relevance-pass results, corrected NVCL scan statistics, deliberate exclusions, and future testing guidance.

Changes

Events crawler relevance

Layer / File(s) Summary
Relevance matching and regression coverage
supabase/functions/events-crawler/lib/relevance.ts, supabase/functions/events-crawler/lib/relevance_test.ts
Matching recognizes technology, device-help terms, qualified Microsoft Office terms, and named Open Door programs. Deno tests cover accepted titles, rejected near-misses, accent folding, and word boundaries.
Dry-run title inspection
supabase/functions/events-crawler/dryrun.ts
The dry-run script supports --titles and --no-filter, prints KEEP/DROP verdicts, and reports source-calendar and insertable-row counts without modifying registry state.
Relevance pass results
BACKLOG.md
The backlog records measured matching changes, corrected NVCL scan statistics, deliberate exclusions, and regression-test guidance.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

  • UnifyCN/web-app#84: Both PRs modify the events-crawler dry-run and relevance behavior.
  • UnifyCN/web-app#87: This PR extends the relevance filtering introduced for the crawler adapters.
  • UnifyCN/web-app#94: This PR updates relevance rules and tests used with Capilano-related crawler data.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: expanding events-crawler relevance matching for digital-skills content.
✨ 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 feat/relevance-digital-skills

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.

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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/lib/relevance.ts`:
- Line 65: Update the relevance pattern in relevance.ts at lines 65-65 to add a
left word boundary before the tech(nology)? alternative, preventing matches
within longer words such as “Biotech.” Add a DROP fixture in relevance_test.ts
at lines 87-93 covering tech embedded in a longer word.
🪄 Autofix

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: 66a67fb4-6e3b-4f0e-9473-3a0782172d1e

📥 Commits

Reviewing files that changed from the base of the PR and between 383367e and 8aaace9.

📒 Files selected for processing (4)
  • BACKLOG.md
  • supabase/functions/events-crawler/dryrun.ts
  • supabase/functions/events-crawler/lib/relevance.ts
  • supabase/functions/events-crawler/lib/relevance_test.ts

Comment thread supabase/functions/events-crawler/lib/relevance.ts Outdated
CodeRabbit on PR #96, valid. `tech(nology)?\s+(cafe|help|support)` matched
the tail of "Biotech Help" and "Fintech Support" — both plausible titles at
SFU, which is in the filtered source set. The boundary was already missing
on the narrower `tech` this widened, so this fixes a pre-existing hazard
rather than one the widening introduced.

Unlike adding an alternative, adding `\b` NARROWS the regex, so it can drop
a keep and the monotonicity argument doesn't cover it. Re-verified against
the same captured corpus: still 9 distinct titles / 56 rows flipping
DROP -> KEEP and 0 previously-kept titles lost, so nothing in the live
feeds moves. It is hardening against titles the sources haven't produced
yet.

Test gains the three near-misses, marked as constructed rather than
captured so the next reader doesn't go looking for them in a feed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@ltanafranca1004

Copy link
Copy Markdown
Collaborator Author

Applied in 40a1ac4 — valid, and a real one. tech(nology)?\s+(cafe|help|support) matched the tail of "Biotech Help" / "Fintech Support", and SFU is in the filtered source set, so those are plausible rather than theoretical. Worth noting the boundary was already missing on the narrower tech this widened — so it's a pre-existing hazard the widening would have inherited, not one it introduced.

One thing your suggestion is right about that the PR body's reasoning does not cover: adding \b narrows the regex. The monotonicity argument I leaned on ("a union alternative can only add keeps") applies to the four additions, not to this. So I re-ran it against the same captured corpus rather than assuming:

9 distinct titles flip DROP->KEEP (56 rows). 0 previously-kept titles lost.

Identical to before the change across all 845 rows / 395 distinct titles — nothing in the live feeds moves either way. It's hardening against titles the sources haven't produced yet.

Added the three near-misses to relevance_test.ts, labelled as constructed rather than captured so the next reader doesn't go hunting for them in a feed:

// `tech` inside a longer word — the reason the alternative carries a leading `\b`.
// Constructed rather than captured: plausible SFU titles, not yet seen in a feed.
'Biotech Help',
'Fintech Support',
'Edtech Café',

deno test 2/2, deno check clean, tsc --noEmit exit 0.

@ltanafranca1004

Copy link
Copy Markdown
Collaborator Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown
⚠️ Action not completed

Review rate limited.


Your included review limit is currently reached under our Fair Usage Limits Policy. This review may still proceed through usage-based billing if eligible. Your next included review will be available in 55 minutes.

@ltanafranca1004

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@ltanafranca1004

Copy link
Copy Markdown
Collaborator Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown
⚠️ Action not completed

Review rate limited.


Your included review limit is currently reached under our Fair Usage Limits Policy. This review may still proceed through usage-based billing if eligible. Your next included review will be available in 56 minutes.

@ltanafranca1004

Copy link
Copy Markdown
Collaborator Author

⚠️ Merging without a CodeRabbit review at the current head — explicit exception

Recording this plainly for anyone reading the history later.

What was reviewed: the only formal CodeRabbit review on this PR ran against 8aaace9, the prior commit. It found one real issue — tech(nology)?\s+(cafe|help|support) matched the tail of "Biotech Help" / "Fintech Support" because the alternative lacked a left word boundary.

What was not reviewed: that issue was fixed in 40a1ac4, the current head, and CodeRabbit has never reviewed 40a1ac4. Every re-request since the fix failed, in three distinct ways:

time (UTC) request outcome
02:07:54 full review ⚠️ rate limited — "next review available in 55 minutes"
03:11 review never posted (tooling error on my side)
03:42:01 review no-op — "Review finished" in 5s, no review object, no quota consumed ("does not re-review already reviewed commits")
03:45:31 full review ⚠️ rate limited again — "next included review will be available in 56 minutes"

The free-tier OSS review budget is exhausted after the #86#96 run. This is a quota wall, not a signal about the code.

Merged anyway on Luis's explicit instruction, for time reasons — this needs to be deployed ahead of the Monday 14:00 UTC crawler cron, and the next genuine review window is ~04:41 UTC at the earliest given tonight's pattern.

Self-verification standing in for the second review:

  • deno test supabase/functions/events-crawler/lib/relevance_test.ts2/2 pass, including the three new Biotech Help / Fintech Support / Edtech Café DROP fixtures added for exactly this finding
  • deno check — clean across all 17 crawler files
  • npx tsc --noEmit — exit 0
  • The fix re-verified against the full captured corpus (845 rows / 395 distinct titles, all seven filtered sources' 4-month windows): 9 titles / 56 rows flip DROP → KEEP, 0 lost — byte-identical to the pre-fix result

That last one is the load-bearing check. Adding \b narrows the regex, so the "a union alternative can only add keeps" argument used in the PR description does not cover it — it could in principle have dropped a keep. Re-running the corpus confirms it drops nothing that any live feed currently produces; it only hardens against titles the sources haven't published yet.

Follow-up: if CodeRabbit's queue frees up, a post-merge review of 40a1ac4 against main is still worth running.

@ltanafranca1004
ltanafranca1004 merged commit 2707fde into main Aug 9, 2026
4 checks passed
@ltanafranca1004

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown
⚠️ Action not completed

Already reviewed.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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.

1 participant