Skip to content

feat(scan): add Workday API support#535

Open
thomasrlord wants to merge 1 commit intosantifer:mainfrom
thomasrlord:feature/workday-scan-support
Open

feat(scan): add Workday API support#535
thomasrlord wants to merge 1 commit intosantifer:mainfrom
thomasrlord:feature/workday-scan-support

Conversation

@thomasrlord
Copy link
Copy Markdown

@thomasrlord thomasrlord commented Apr 29, 2026

Detect /wday/cxs/{tenant}/{site}/jobs URLs as a Workday provider via the explicit api: field. fetchWorkdayAll paginates POST requests at limit=20 (Workday's hard cap on most public job APIs) up to a 5000-job safety bound. parseWorkday extracts title and locationsText, and builds the public job URL as host + /en-US/{site} + externalPath.

Unlocks federal contractors that run Workday boards (Leidos, GDIT, Booz Allen Hamilton, RTX, Amentum, Parsons, DXC, Accenture Federal) for zero-token scanning. Backwards compatible — fetchJson takes an optional options parameter (default {}) so the same helper handles both Workday's POST + body and the existing GET semantics for Greenhouse / Ashby / Lever.

Closes #533

What does this PR do?

Related issue

Type of change

  • Bug fix
  • New feature
  • Documentation / translation
  • Refactor (no behavior change)

Checklist

  • I have read CONTRIBUTING.md
  • I linked a related issue above (required for features and architecture changes)
  • My PR does not include personal data (CV, email, real names)
  • I ran node test-all.mjs and all tests pass
  • My changes respect the Data Contract (no modifications to user-layer files)
  • My changes align with the project roadmap

Questions? Join the Discord for faster feedback.

Summary by CodeRabbit

  • New Features

    • Added Workday detection and automatic ingestion of job postings with paginated fetching and a safety cap
    • Scan routing updated so Workday sources use the new paginated ingestion path
  • Enhancements

    • Improved Lever detection via explicit API recognition
    • JSON fetching enhanced to accept optional request parameters

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 29, 2026

📝 Walkthrough
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 71.43% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(scan): add Workday API support' directly and concisely summarizes the main change in the PR, which adds Workday API detection and support to scan.mjs.
Linked Issues check ✅ Passed All five coding objectives from issue #533 are met: detectApi() recognizes Workday URLs, fetchWorkdayAll() paginates POST requests with correct parameters, parseWorkday() extracts and formats job data, wire-up registers the parser and routes Workday companies correctly, and fetchJson() accepts optional parameters for backward compatibility.
Out of Scope Changes check ✅ Passed All changes in scan.mjs are directly scoped to the Workday API support feature: detection logic, fetch implementation, parsing, wire-up, and backwards-compatible fetchJson extension—no unrelated modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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
Review rate limit: 7/8 reviews remaining, refill in 7 minutes and 30 seconds.

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

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

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 the current code and only fix it if needed.

Inline comments:
In `@scan.mjs`:
- Around line 149-166: fetchWorkdayAll can silently return partial results when
the pagination cap is hit; update the function (fetchWorkdayAll) to detect when
the loop exits due to maxPages being reached and signal that the results were
truncated (e.g., add a returned flag like _truncated: true and include
_pagesFetched or _itemsFetched), and also emit a warning (console.warn or
existing logger) when postings.length === limit on the final iteration and page
=== maxPages - 1 so operators can see the cap was hit.
🪄 Autofix (Beta)

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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 90d96e3c-cdb5-4a92-8c7d-ac6ca20e74d7

📥 Commits

Reviewing files that changed from the base of the PR and between 62b767d and 43d365812cc298d44b992b7301ea34e13efedf1b.

📒 Files selected for processing (1)
  • scan.mjs

Comment thread scan.mjs
Detect /wday/cxs/{tenant}/{site}/jobs URLs as a Workday provider via
the explicit api: field. fetchWorkdayAll paginates POST requests at
limit=20 (Workday's hard cap on most public job APIs) up to a 5000-job
safety bound. parseWorkday extracts title and locationsText, and builds
the public job URL as host + /en-US/{site} + externalPath.

Unlocks federal contractors that run Workday boards (Leidos, GDIT,
Booz Allen Hamilton, RTX, Amentum, Parsons, DXC, Accenture Federal)
for zero-token scanning. Backwards compatible — fetchJson takes an
optional options parameter (default {}) so the same helper handles
both Workday's POST + body and the existing GET semantics for
Greenhouse / Ashby / Lever.

Closes santifer#533

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@thomasrlord thomasrlord force-pushed the feature/workday-scan-support branch from 43d3658 to 3df0671 Compare April 29, 2026 20:38
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

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 the current code and only fix it if needed.

Inline comments:
In `@scan.mjs`:
- Around line 156-165: The loop that reads Workday responses currently uses
`const postings = json.jobPostings || []`, which masks unexpected payloads;
update the code (inside the loop where `fetchJson` is called) to validate that
`json.jobPostings` exists and is an Array and throw a descriptive Error if it is
missing or not an array so the failure surfaces into `errors` instead of
silently producing zero jobs; reference the `fetchJson` call and the
`postings`/`allPostings` handling to add this runtime check and throw (include
tenant/context in the error message) before pushing into `allPostings`.
🪄 Autofix (Beta)

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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 2df78ce3-66f2-47f4-ab8f-b0165ac11c64

📥 Commits

Reviewing files that changed from the base of the PR and between 43d365812cc298d44b992b7301ea34e13efedf1b and 3df0671.

📒 Files selected for processing (1)
  • scan.mjs

Comment thread scan.mjs
Comment on lines +156 to +165
for (let page = 0; page < maxPages; page++) {
const json = await fetchJson(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ appliedFacets: {}, limit, offset: page * limit, searchText: '' }),
});
const postings = json.jobPostings || [];
pages = page + 1;
if (postings.length === 0) break;
allPostings.push(...postings);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Fail fast on unexpected Workday payloads.

json.jobPostings || [] turns any 200-level error payload or schema drift into a silent “0 jobs” result. That undercounts the tenant and hides the failure from the summary. Throw if jobPostings is not an array so this lands in errors instead.

💡 Proposed fix
   for (let page = 0; page < maxPages; page++) {
     const json = await fetchJson(url, {
       method: 'POST',
       headers: { 'Content-Type': 'application/json' },
       body: JSON.stringify({ appliedFacets: {}, limit, offset: page * limit, searchText: '' }),
     });
-    const postings = json.jobPostings || [];
+    if (!Array.isArray(json.jobPostings)) {
+      throw new Error(`Unexpected Workday response shape from ${url}: missing jobPostings array`);
+    }
+    const postings = json.jobPostings;
     pages = page + 1;
     if (postings.length === 0) break;

As per coding guidelines, **/*.mjs: Check for command injection, path traversal, and SSRF. Ensure scripts handle missing data/ directories gracefully.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scan.mjs` around lines 156 - 165, The loop that reads Workday responses
currently uses `const postings = json.jobPostings || []`, which masks unexpected
payloads; update the code (inside the loop where `fetchJson` is called) to
validate that `json.jobPostings` exists and is an Array and throw a descriptive
Error if it is missing or not an array so the failure surfaces into `errors`
instead of silently producing zero jobs; reference the `fetchJson` call and the
`postings`/`allPostings` handling to add this runtime check and throw (include
tenant/context in the error message) before pushing into `allPostings`.

@thomasrlord
Copy link
Copy Markdown
Author

Addressed in 3df0671. fetchWorkdayAll now tracks lastPageSize and pages and emits a stderr warning when we exit via the maxPages bound
with a still-full last page (the only case where truncation actually happened). Skipped the _truncated/_pagesFetched/_itemsFetched
metadata fields since there's no consumer for them yet — happy to add them if you want them surfaced in the summary line.

cburns33 added a commit to cburns33/career-ops that referenced this pull request May 4, 2026
cburns33 added a commit to cburns33/career-ops that referenced this pull request May 4, 2026
Brings in Windsurf session work:
- Gmail rejection scanner with --apply-excel + Excel output
- Hiring Cafe scanner (saved-search URL + API replay)
- LinkedIn scanner (PR santifer#379) via scan-auth harness
- scan.mjs upgrades: Workday API (santifer#535), location filter (santifer#490), --verify (santifer#487)
- connections-match multi-CSV + scan-history cross-reference
- Upstream sync to v1.6.0 (FR/JA/PT/RU mode translations, writing style calibration)
- CV metrics: $100K savings + $800K budget added

Conflicts resolved by taking worktree side for VERSION, DATA_CONTRACT.md,
modes/_shared.md, .github/workflows/release.yml.
deepak-glitch pushed a commit to deepak-glitch/career-ops that referenced this pull request May 5, 2026
… PDF)

- Level 3 WebSearch additions (08:30Z): Federato (Greenhouse), Jobgether
  Lever x3, Oddball, Automattic, fwddeploy AI FDE, Remote Raven (Remotive)
- 5 A-G reports written (santifer#531-535):
  - santifer#531 Federato FDE ML Engineer 3.6/5 — Remote-US/Canada, $155-180K, 2+y
    matches Deepak 2.5y; LLMs+agentic+evals+production monitoring 1:1; PDF
    generated
  - santifer#532 Oddball Applied AI/ML 1.8/5 — federal contractor, US Citizen +
    clearance for billable work; F-1 OPT structural blocker
  - santifer#533 Automattic Applied AI Internal Tooling 2.7/5 — NYC NoHo 5d on-site
    + TS/Node primary; F-1 OPT relocation + sponsorship gap; merge-tracker
    skipped (existing santifer#247 higher score)
  - santifer#534 Jobgether/fwddeploy FinServ FDE 2.0/5 — anonymized end client +
    5+y senior floor (2x gap); recruiter-aggregator pattern
  - santifer#535 Remote Raven AI & Cloud 1.2/5 — $10/hr full-time offshore
    economics; F-1 OPT prevailing-wage incompatible
- 3 Lever Jobgether URLs marked [!] error: posting closed
- merge-tracker: +4 added, 1 skipped (Automattic dup); verify-pipeline 0/0
- cleanup-low-scores: archived 4 below-threshold reports + santifer#533 manual move
- Switched from session branch claude/relaxed-euler-irNFS to main per
  _profile.md Git Push Policy

https://claude.ai/code/session_overnight-2026-05-05T08:30Z
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Workday API support to scan.mjs

1 participant