Add GitHub Actions workflow for monthly MCI fetch and parse - #14
Open
epence12 wants to merge 4 commits into
Open
Add GitHub Actions workflow for monthly MCI fetch and parse#14epence12 wants to merge 4 commits into
epence12 wants to merge 4 commits into
Conversation
Schedule fetch_reports.py and parse_reports.py to run on the 5th of each month via cron, with manual dispatch support. Un-gitignore mci_output.csv and processed_reports.log so the workflow can persist state between runs. Include 3 newly fetched reports (Nov 2025, Dec 2025, Jan 2026).
Run the test suite after parsing so that regressions in the parser prevent bad CSV data from being committed automatically.
- Add project structure section listing all source modules - Replace forward-looking scheduling notes with actual GH Actions workflow - Fix testing section (remove nonexistent Sept 2025 fixture reference) - Consolidate remaining TODOs into their own section
Collaborator
Author
Spot-check finding: C4 confirmed in production dataWhile manually vetting the January 2026 report against the CSV output, I found that row 1421 has a work item named This confirms code review finding C4 (no CSV value quoting/escaping). I'm adding a fix in this PR to use Python's |
Use Python's csv module instead of raw f-string concatenation for CSV output. This properly quotes fields containing commas (e.g., "SHED, SCAFFOLD") so rows always have the correct number of columns. Confirmed via spot-check of January 2026 report: all 6,666 rows now have exactly 14 fields. Regenerated mci_output.csv from scratch.
epence12
force-pushed
the
epence/scheduled-fetch-parse
branch
from
February 17, 2026 01:38
2c46399 to
43d9016
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
.github/workflows/fetch-and-parse.yml) that runsfetch_reports.pyandparse_reports.pyon the 5th of each month, with manual dispatch support.mci_output.csvandprocessed_reports.logso the workflow can persist state between runs.Code Review Findings
A rigorous review of the full codebase surfaced the following. These are not addressed in this PR but are documented here as next steps.
Critical
parse_reports.pywithcontext manager already closes it, thenpdf.close()is called againparse_reports.pyparse_reports.pyparse_reports.pycsvmoduleregexes.pystreet_address_line_regex(\d+.*) matches any line starting with a digit — page numbers, costs, dates all match. Works only because theelifchain checks it firstModerate
regexes.py[A-Z]\D*rejects digits in names (e.g., "TYPE 2 ELEVATOR" would not match)regexes.pyparse_reports.pyCSV_OUTPUT_FILE, paths, logger) mutated by testsfetch_reports.pyparse_reports.pyfetch-and-parse.ymlparse_reports.pyfrom regexes import ...) rely onsys.path; potential double-loading when imported by tests vs run as__main__parse_reports.py__main__block, not byprocess_directoryMinor
parse_reports.py,classes.py,regexes.pypathlib/os.pathusage inparse_reports.pyre.match(compiled_pattern, line)instead of idiomaticcompiled_pattern.match(line)requirements.txtwith no Dependabot or update automationurllib3,certifi,idna) not pinnedTesting Plan
Existing coverage
Needed before merging follow-up work
derive_report_month— valid months, uppercase, non-matching filenames, unknown month namesfetch_reports.py—slugify,extract_report_links,ReportLink.filenameare purely functional and highly testablewrite_to_csvedge cases —Noneaddress, empty work items, commas in field valuesPropertyMcispanning a page boundary is correctly accumulatedpage.extract_text()returnsNoneor empty stringprocess_directorywith no PDFs should be a no-opHow to validate this PR specifically
workflow_dispatchafter mergingprocessed_reports.logincludes all expected filenamesNext Steps
1. Fix critical parsing bugs (C1-C5)
Address the double-close, premature end-of-page write, CSV escaping, and overly broad street address regex. These are correctness issues that affect output quality today.
2. Robust parsing strategy for image-based PDFs
The current pipeline only handles machine-readable (text-layer) PDFs. FOIL request data from DHCR arrived as scanned image PDFs that
pdfplumbercannot extract text from. A robust strategy should handle both:Proposed approach:
page.extract_text()returns meaningful content. If it returnsNoneor empty/whitespace, flag the page as image-based.pytesseract+ Tesseract, oreasyocr) to extract text, then feed the result into the existing regex-based parser.pdf2image+Pillowcan handle this.--psm 1(auto page segmentation) or a dedicated layout detection step.parse_foil_reports.pyor a--formatflag, since the FOIL files differ in naming, date range coverage, and layout from the monthly published reports.3. Harden
fetch_reports.py4. Improve test coverage
Address the test gaps listed above, especially multi-page entries and CSV escaping edge cases.
5. Add Dependabot or Renovate
Automate dependency updates, especially for
cryptographyandrequests.Note: Maxwell has offered to add this to JustFix's k8s cron infrastructure as an alternative/complement to this GH Actions workflow. Both can coexist.