Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

[refactor] education.ts hand-rolls entry segmentation instead of using parseEntryBlocks — the repo's #1 complexity function

Closed
#914 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
52/100
Issue type
Refactor
Clarity
Clearly specified
Activity status
Active
Tech stack
typescript
Domain
data, testing

Research direction

Start by characterizing the education corpus fixtures and the batch:parser-education lane, then compare education.ts with parseEntryBlocks in src/lib/heuristics/entry-blocks.ts and its callers in experience.ts, projects.ts, and achievements.ts. Done means education.ts uses the shared primitive, the private chunker is gone, snapshots are unchanged or justified, fallow complexity improves, and npm run verify passes.

Written by the indexing model from the issue text.

Description

architecture gaal improvement ready-for-agent refactor ux:parsing
Problem

extractEducation is the highest-cognitive-complexity function in the repository, and the reason is that education.ts hand-rolls the entry segmentation that every other extractor gets from the shared parseEntryBlocks primitive.

fallow health (repo-wide, 14,244 functions analyzed) ranks it #1 and #5:

rank function cognitive
1 extractEducation (src/lib/heuristics/extract/education.ts:1123) 80
5 educationFromChunk (src/lib/heuristics/extract/education.ts:921) 42

src/lib/heuristics/entry-blocks.ts records the gap in its own prose:

education.ts does not use this primitive at all.
— src/lib/heuristics/entry-blocks.ts:279-280

The three other entry-shaped sections are thin callers of the shared primitive:

  • src/lib/heuristics/extract/experience.ts:44 (and a second pass at :58)
  • src/lib/heuristics/extract/projects.ts:39
  • src/lib/heuristics/extract/achievements.ts:75

education.ts instead imports only two leaf predicates from it — isDateOnlyLine, isEntryHeaderShape (education.ts:22) — and re-implements the rest as a private "chunker": educationFromChunk (:921) joins a chunk with " | " and re-parses fields out of the joined string (:925), with the chunking gates spread across isRealEntryHeader (:258), isCourseworkContinuation (:290), isInlineDatedProgram (:362), isProgramLeadAt (:484) and isInstitutionLeadAt (:545).

The file carries 27 distinct issue references — tied for second-highest in the repo — which is what that hand-rolled path costs in accreted special cases.

Why this is the right shape

parseEntryBlocks is already a parameterized segmentation engine, not an experience-specific one. EntryBlockConfig (entry-blocks.ts:185-213) exposes exactly the axes education needs:

  • anchor — education entries anchor on an institution or degree line, not necessarily a date range
  • collectBody — education entries may be header-only
  • headerLookback — the Degree\nInstitution <dates> stack
  • dateParsing: "all" | "date_anchors_only" — education's dates ride the institution line

Projects and achievements were both onboarded onto it by supplying a config. Education is the one holdout.

Scope

Behaviour-preserving segmentation swap. education.ts keeps ownership of its education-specific field logic (degree/field parsing, GPA and honors via education-grade.ts, institution/location splitting, date precision) — the goal is to delete the private chunker, not the domain knowledge.

Expect this to need a new EntryAnchor variant or a widened anchor config; adding one is in the spirit of the primitive and benefits the other three callers.

Implementation plan
  1. Characterize the current chunker: what line sequences does it group, and on which fixtures? The education corpus fixtures plus the batch:parser-education lane are the reference set.
  2. Express that grouping as an EntryBlockConfig, extending EntryAnchor if the institution-lead / degree-lead cues have no existing anchor.
  3. Replace educationFromChunk's chunk-assembly with parseEntryBlocks output, keeping the per-field extraction that runs on each block.
  4. Delete the now-dead chunking gates, or demote any that survive as genuine field-level predicates.
  5. Re-run fallow health and record the new cognitive numbers for both functions.
Acceptance criteria
  • education.ts imports and calls parseEntryBlocks; the private chunk-assembly path is gone.
  • Corpus snapshots are byte-identical, or every diff is reviewed fixture-by-fixture and justified in the PR description.
  • extractEducation and educationFromChunk both drop below the fallow complexity threshold; the PR quotes before/after.
  • npm run verify green; no new KNOWN_FAILURES entries.
  • Any new EntryBlockConfig axis is documented in the interface docblock the way the existing four are.
  • The PR description names the segmentation decision it made — which EntryAnchor variant or EntryBlockConfig axis was added (or that none was needed), which education fixtures drove that choice, and which of the five private chunking gates (isRealEntryHeader, isCourseworkContinuation, isInlineDatedProgram, isProgramLeadAt, isInstitutionLeadAt) were deleted versus kept as field-level predicates, with one line of reason each. A choice made silently is a review finding.
Context

Surfaced by an architecture review of the "should we introduce a plugin architecture?" question. The answer was no — but this convergence was the one structural item the review found that epic #646 does not already cover, and fallow ranks it as the single highest-complexity function in the tree. Related: #646, #831 (batch:parser-education).

Dominant language
TypeScript
Stars
11
Forks
4
PR merge metrics
No merged PRs in 30d

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from offlinecv/OfflineCV

All issues in offlinecv/OfflineCV

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.