Skip to content

fix(events-crawler): track Surrey parse failures by layer - #98

Merged
ltanafranca1004 merged 1 commit into
mainfrom
fix/surrey-structural-misses
Aug 9, 2026
Merged

fix(events-crawler): track Surrey parse failures by layer#98
ltanafranca1004 merged 1 commit into
mainfrom
fix/surrey-structural-misses

Conversation

@ltanafranca1004

@ltanafranca1004 ltanafranca1004 commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator

What & why

Closes the follow-up deferred from #86 (BACKLOG.md). 533d79e covered only the first layer of Surrey's silent-failure mode: BLOCK_MARKER no longer matching sets blocks === 0, which page 0 now logs as an error.

The three regexes downstream of that marker still failed the same way. If TITLE_LINK_RE, TIME_RE or LOCATION_RE stops matching, every chunk is skipped through a continue no counter reaches — candidates stays empty while blocks stays non-zero, so exhausted never trips, maxStartMs stays 0 so pastWindow never trips, and the walk burns all 20 pages before exiting through the cap warning. That warning reads "listings beyond the cap" when the truth is "the markup moved": misattributed rather than silent, but just as useless.

Diagnostics only — no behaviour change, no schema/migration/cron change, and nothing here alters what Monday's cron ingests.

The one thing that wasn't a copy of NVCL

Surrey's address extraction sat after the relevance and window filters:

title ─┐
time  ─┤ before the filters
       [ relevance ]  ← rejects ~80% on merit
       [ window    ]
location ┘ AFTER            ← the problem

So structural === blocks could never reach equality to detect a LOCATION_RE failure — relevance had already rejected most of the page on merit. Adding counters alone would not have fixed it.

The fix is to move the extraction ahead of the filters, which is the same call capilano.ts:194-200 already made for its venue:

Reading it after would put a structural failure downstream of a merit-based one… Keeping the whole extraction chain ahead of the filters means one comparison (structural === blocks) covers all of it.

No output change: a block failing location was dropped either way, and maxStartMs still updates before location, so walk-stop behaviour is untouched.

Verified empirically against the live feed

Each regex broken in turn, page-0 diagnostic observed:

broken diagnostic
TITLE_LINK_RE matched 10 block(s) on page 0 but extracted none of them (title 10, time 0, location 0)
TIME_RE … (title 0, time 10, location 0)
LOCATION_RE … (title 0, time 0, location 10)

Each names the right layer with an exact count. The LOCATION_RE row is what the reordering bought — under the old ordering that failure was undetectable.

The exclusion property (the assertion that actually earns its keep): with isSettlementRelevant temporarily forced to reject everything, the source returns 0 rows and logs zero structural errors. A legitimately filtered-empty result stays distinguishable from a markup change — this is what would catch a wrong comparison.

Regression: happy path unchanged, and no diagnostic on a healthy run.

events-crawler: surrey-libraries walked 12 page(s), 27 in-window + relevant (27 unique), taking soonest 25

All temporary edits were reverted and verified against file snapshots before committing; git status showed only the two files in this diff.

Scope

This completes the pattern across all three BLOCK_MARKER adapters — nvcl.ts (ada14d1), capilano.ts (1f62068), surrey.ts (here).

bibliocommons.ts (6 untracked continues) and communico.ts (4, with partial unparsedDates) have the same shape but a weaker case: they parse a JSON gateway and an RSS feed, where the failure mode is a field rename rather than a theme update, and a renamed field usually breaks parsing loudly. livewhale.ts / tribe.ts have no skip-continues at all. Recorded in BACKLOG.md rather than expanded into this PR.

Verification

  • deno check — clean on all 17 crawler files
  • deno test — 2/2 (relevance_test.ts, unaffected; run to confirm nothing broke)
  • npx tsc --noEmit — exit 0

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Improved event parsing diagnostics across Surrey, NVCL, and Capilano listings.
    • Location extraction failures are now detected before filtering, reducing missed diagnostic details.
    • Empty listings can now be distinguished from pages whose markup no longer matches expected patterns.
  • Monitoring

    • Added detailed tracking for missing titles, times, and locations.
    • Added page-level warnings when all event blocks fail extraction.
  • Documentation

    • Documented verification scenarios and noted remaining lower-priority gaps in JSON and RSS parsing.

Closes the follow-up deferred from PR #86. `533d79e` covered only the
first layer: BLOCK_MARKER no longer matching sets blocks === 0, which
page 0 now logs as an error. The three regexes *downstream* of that
marker still failed the same way — TITLE_LINK_RE, TIME_RE or LOCATION_RE
ceasing to match skipped every chunk through a `continue` no counter
reached, so candidates stayed empty while blocks stayed non-zero,
`exhausted` never tripped, maxStartMs stayed 0 so `pastWindow` never
tripped, and the walk burned all 20 pages before exiting through the cap
warning — which reads "listings beyond the cap" when the truth is "the
markup moved". Misattributed rather than silent, but just as useless.

Adds per-layer StructuralMisses (title / time / location) and a page-0
diagnostic firing when title + time + location === blocks, naming each
layer and its count. Relevance and window are deliberately excluded: they
reject on merit, and rejecting most of a library calendar is their job.

Surrey needed one thing NVCL and Capilano did not. Its address extraction
sat AFTER the filters, so `structural === blocks` could never reach
equality to detect a LOCATION_RE failure — relevance had already rejected
~80% of the page on merit. Moved the extraction ahead of the filters, the
same call adapters/capilano.ts made for its venue, so the whole chain
precedes merit-based rejection and one comparison covers it. No output
change: a block failing location was dropped either way, and maxStartMs
still updates before location, so walk-stop behaviour is untouched.

Verified against the live feed by breaking each regex in turn — title
gives (title 10, time 0, location 0), time gives (0, 10, 0), location
gives (0, 0, 10). And with isSettlementRelevant temporarily forced to
reject everything, the source returns 0 rows and logs zero structural
errors, so a filtered-empty result stays distinguishable from a markup
change. Happy path unchanged at 12 pages / 27 relevant / 25 taken.

This completes the pattern across all three BLOCK_MARKER adapters. The
feed parsers (bibliocommons, communico) have the same shape but a weaker
case; recorded in BACKLOG.md rather than expanded into this PR.

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 4:50am

@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown

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: 49fe20d3-ec94-4271-bbcb-e9ff7488a113

📥 Commits

Reviewing files that changed from the base of the PR and between 220bd47 and 40d538d.

📒 Files selected for processing (2)
  • BACKLOG.md
  • supabase/functions/events-crawler/adapters/surrey.ts

Walkthrough

The Surrey HTML adapter now tracks title, time, and location extraction failures before filtering. It returns these counts and logs page-0 diagnostics when all marked blocks fail structural extraction. The backlog records verification results and remaining parser gaps.

Changes

Surrey adapter diagnostics

Layer / File(s) Summary
Structural miss tracking
supabase/functions/events-crawler/adapters/surrey.ts
The adapter tracks title, time, and location extraction misses. It extracts locations before relevance and date-window filters and returns the miss counts with page results.
Page-level diagnostics and verification
supabase/functions/events-crawler/adapters/surrey.ts, BACKLOG.md
Page 0 logs structural failures when all marked blocks fail extraction. The backlog documents verification results and remaining parser gaps.

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

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: tracking Surrey event-crawler parse failures by extraction layer.
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.
✨ 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 fix/surrey-structural-misses

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.

@ltanafranca1004
ltanafranca1004 merged commit 94d9c24 into main Aug 9, 2026
4 checks passed
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