Skip to content

fix(heuristics): drop empty-title (date-only) entry blocks before scoring (#145) - #161

Merged
s-annam merged 2 commits into
mainfrom
feat/drop-empty-title-blocks-145
Jun 24, 2026
Merged

fix(heuristics): drop empty-title (date-only) entry blocks before scoring (#145)#161
s-annam merged 2 commits into
mainfrom
feat/drop-empty-title-blocks-145

Conversation

@rohithgollapalli

Copy link
Copy Markdown
Collaborator

Summary

A header/anchor line whose entire text is a date leaves nothing after stripDateRange, so parseEntryBlocks emits a block with empty headerLines. All three extractors mapped that straight through to a { title: "" } / { name: "" } entry with score 0 — a title-less item in output that also diluted section confidence via avgScore. (Surfaced during #144 review; pre-existing and shared across the extractors.)

Adds a shared finalizeEntries(built, hasLabel) helper in extract/shared.ts that drops empty-label entries and packages the survivors as the standard { value, confidence } pair — keeping the score-0 phantom out of the avgScore denominator. Routes extractAchievements / extractProjects / extractExperience through it (predicates: title, name, and title || company for experience). Filtering on the built entry's label rather than on empty headerLines also catches a URL-only header, which liftHeaderLabel collapses to an empty label — so every anchor path (first_line flat-list, first_line buildEntryBlock, date_range) is covered at once. Per-block mappers and scoring are unchanged.

Closes #145

Test plan

  • npm run typecheck clean
  • npm run test green (723 passed; +5 new extract-fields cases: date-only bullet, date-only header, date-only project, date-only experience, and a no-dilution regression guard)
  • Corpus re-baked — no fixture content changed vs main (confirmed via --ignore-cr-at-eol); no real résumé carried a phantom empty entry, matching the issue's expectation
  • eslint clean on changed files

s-annam
s-annam previously approved these changes Jun 24, 2026

@s-annam s-annam 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.

PR Review: fix(heuristics): drop empty-title (date-only) entry blocks before scoring (#145)

Summary

Correct root-cause fix. A date-only anchor reduces to an empty label after stripDateRange, producing a phantom { title: "" } / { name: "" } score-0 entry that also diluted section confidence via avgScore. The new shared finalizeEntries helper drops the phantom and packages survivors as the standard { value, confidence } pair.

Highlights

  • DRY: one helper replaces the duplicated blocks.length === 0 → avgScore(...) tail across all three entry extractors.
  • Filtering on the built entry's label (not on empty headerLines) also catches URL-only headers that liftHeaderLabel collapses to an empty label — covers every anchor path at once.
  • Behavior-preserving for the empty case (empty builtavgScore([]) → 0), so no regression vs the old early return.
  • Predicates match the returned label fields (title, name, title || company for experience).

Verification

  • npm run typecheck clean
  • npm run test — 723 passed (+5 new cases incl. no-dilution regression guard)
  • Corpus unchanged vs main

Verdict

Action: APPROVE
Rationale: No findings. Targeted, well-tested fix.

…ring (#145)

A header/anchor line whose entire text is a date leaves nothing after
stripDateRange, so parseEntryBlocks emits a block with empty headerLines. The
three extractors mapped that straight through to a {title:""}/{name:""} entry
with score 0 — a title-less item in output that also diluted section confidence.

Add a shared finalizeEntries() helper that drops empty-label entries (filtering
on the built entry's label, so a URL-only header is caught too) and packages the
survivors; route extractAchievements/extractProjects/extractExperience through it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@s-annam
s-annam force-pushed the feat/drop-empty-title-blocks-145 branch from 4a7796d to 1158431 Compare June 24, 2026 17:25

@s-annam s-annam 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.

Re-approve after rebase onto main + conflict resolution in experience.ts (import-line only: kept #159's US_LOCATION_RE/INTL_LOCATION_RE, swapped avgScore→finalizeEntries; avgScore now unused in file). Gates green post-rebase: typecheck clean, 732 tests passing.

@s-annam s-annam 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.

Re-approve after updating branch to base (160 merged; disjoint files, clean update — no conflict). Gates green on prior rebase: typecheck clean, 732 tests.

@s-annam
s-annam merged commit 4cdc873 into main Jun 24, 2026
2 checks passed
@s-annam
s-annam deleted the feat/drop-empty-title-blocks-145 branch June 24, 2026 17:29
s-annam added a commit that referenced this pull request Jun 25, 2026
…ring (#145) (#161)

A header/anchor line whose entire text is a date leaves nothing after
stripDateRange, so parseEntryBlocks emits a block with empty headerLines. The
three extractors mapped that straight through to a {title:""}/{name:""} entry
with score 0 — a title-less item in output that also diluted section confidence.

Add a shared finalizeEntries() helper that drops empty-label entries (filtering
on the built entry's label, so a URL-only header is caught too) and packages the
survivors; route extractAchievements/extractProjects/extractExperience through it.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Srinivas Annam <annam@annam.org>
s-annam added a commit that referenced this pull request Jun 28, 2026
…ring (#145) (#161)

A header/anchor line whose entire text is a date leaves nothing after
stripDateRange, so parseEntryBlocks emits a block with empty headerLines. The
three extractors mapped that straight through to a {title:""}/{name:""} entry
with score 0 — a title-less item in output that also diluted section confidence.

Add a shared finalizeEntries() helper that drops empty-label entries (filtering
on the built entry's label, so a URL-only header is caught too) and packages the
survivors; route extractAchievements/extractProjects/extractExperience through it.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Srinivas Annam <annam@annam.org>
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.

Filter empty-title (date-only) entry blocks before they reach the score

2 participants