Skip to content

feat(cli): shared flag-validation helper, migrate 3 fixed scripts, fix scan.mjs (#2270) - #2778

Merged
santifer merged 2 commits into
santifer:mainfrom
Schlaflied:feat/shared-flag-validation
Aug 14, 2026
Merged

feat(cli): shared flag-validation helper, migrate 3 fixed scripts, fix scan.mjs (#2270)#2778
santifer merged 2 commits into
santifer:mainfrom
Schlaflied:feat/shared-flag-validation

Conversation

@Schlaflied

@Schlaflied Schlaflied commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Closes #2775. Closes #2270.

What this is

Three scripts (scan-ats-full.mjs #1633/#1635, reply-watch.mjs #2743/#2745, dedup-tracker.mjs #2744/#2746) independently hand-rolled the identical fix for the identical bug: an unrecognized/mistyped CLI flag silently falling through to default/live behavior instead of failing fast. lib/cli-flags.mjs gains validateFlags(args, knownFlags, usage, { valueFlags }) — the shape all three converged on, in one place:

Migration (behavior-preserving)

scan-ats-full.mjs, reply-watch.mjs, and dedup-tracker.mjs now call the shared helper instead of their own copies. Same error messages, same exit codes, same usage text — this is de-duplication, not a behavior change. (scan-ats-full.mjs picks up one small fix as a side effect: its own --help-before-unknown-flag ordering had the same latent bug the other two were caught on, just never exercised by a test that combined both.)

The one genuinely new fix: scan.mjs (#2270)

node scan.mjs --help never checked --help at all — it fell straight through into a full live scan, hitting every configured ATS and writing to pipeline.md/scan-history.tsv. Same failure class as the other three, fixed the same way. KNOWN_FLAGS was built from the script's own existing docblock usage examples; --company/--posted-after/--posted-before/--since are registered as valueFlags (--throttle deliberately isn't — it's only ever read in its bare or --throttle=<ms> forms).

Tests

  • tests/cli-flags.test.mjs extended with direct unit coverage of validateFlags (unrecognized-flag rejection, --help/-h, the ordering case, valueFlags negative-number handling) plus subprocess-level coverage for cases that need a real exit code.
  • New tests/scan-help-flag.test.mjs: hermetic (CAREER_OPS_PORTALS pointed at a nonexistent path) coverage proving --help, -h, and an unrecognized flag on scan.mjs never reach the portals-loading step — i.e. never attempt a live scan.
  • node test-all.mjs --quick: 3647 passed, 0 failed.

Summary by CodeRabbit

  • New Features

    • Added consistent command-line flag validation across scanning and monitoring commands.
    • Added support for value-based flags, including negative values.
    • Expanded scan help documentation with available options.
  • Bug Fixes

    • Unrecognized or mistyped flags now fail clearly before command execution.
    • Help options consistently display usage information and exit successfully.
  • Tests

    • Added coverage for valid flags, invalid flags, help aliases, value handling, and validation order.

…x scan.mjs (santifer#2270)

Adds validateFlags(args, knownFlags, usage, { valueFlags }) to
lib/cli-flags.mjs, collecting the shape independently hand-rolled in
scan-ats-full.mjs (santifer#1633/santifer#1635), reply-watch.mjs (santifer#2743/santifer#2745), and
dedup-tracker.mjs (santifer#2744/santifer#2746): reject any unrecognized flag before
honoring --help/-h (the ordering CodeRabbit flagged on the last two
PRs), value-taking flags never mistake their own value for an
unrecognized flag.

Migrates all three scripts to the shared helper (behavior-preserving —
same error messages, same exit codes, same usage text). Also fixes
scan.mjs (santifer#2270): --help and any unrecognized flag used to fall
straight through into a full live scan and write to
pipeline.md/scan-history.tsv instead of printing usage.

Closes santifer#2775. Closes santifer#2270.
@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 1599fc07-d746-43c4-bd0c-95b3e05186cf

📥 Commits

Reviewing files that changed from the base of the PR and between 853afcd and 4e441ee.

📒 Files selected for processing (2)
  • lib/cli-flags.mjs
  • tests/cli-flags.test.mjs

📝 Walkthrough

Walkthrough

The pull request adds shared CLI flag validation and applies it to four scripts. It validates known and value-bearing flags, preserves help handling, rejects unknown flags before side effects, and adds unit and subprocess regression tests.

Changes

CLI validation

Layer / File(s) Summary
Shared validation contract
lib/cli-flags.mjs, tests/cli-flags.test.mjs
Adds and tests validateFlags for value-bearing flags, --flag=value forms, help output, and unknown-flag errors.
CLI script integration
scan.mjs, dedup-tracker.mjs, reply-watch.mjs, scan-ats-full.mjs
Replaces local validation and help handling with validateFlags. scan.mjs adds consolidated flag definitions and usage text.
Scan validation regression coverage
tests/scan-help-flag.test.mjs
Tests help aliases, invalid-flag precedence, mistyped flags, value handling, subprocess exits, and prevention of scan setup for invalid flags.

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

Possibly related issues

  • santifer/career-ops#2775 — Covers the shared validator and migration of the four CLI scripts.
  • santifer/career-ops#2744 — Covers unknown-flag validation for dedup-tracker.mjs.
  • santifer/career-ops#2743 — Covers help and unknown-flag validation for reply-watch.mjs.

Sequence Diagram(s)

sequenceDiagram
  participant scan.mjs
  participant validateFlags
  participant Scan setup
  scan.mjs->>validateFlags: Validate command-line arguments
  alt Unknown flag
    validateFlags-->>scan.mjs: Report error and exit 1
  else Help flag
    validateFlags-->>scan.mjs: Print usage and exit 0
  else Valid arguments
    validateFlags-->>scan.mjs: Return validated arguments
    scan.mjs->>Scan setup: Continue scan processing
  end
Loading

Suggested reviewers: zoubeir23

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% 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 clearly summarizes the shared flag-validation helper, script migrations, and scan.mjs fix.
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 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

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

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@lib/cli-flags.mjs`:
- Around line 105-107: Update the unknownFlags filtering logic to accept
equals-value syntax only when the base flag belongs to valueFlags; boolean flags
such as --dry-run=1 must remain rejected, while value-bearing flags such as
--since=-5 must be accepted. Add regression coverage for both cases.
🪄 Autofix

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 Plus

Run ID: 7a8a7848-d1c6-4f11-8468-f0e873b0fca0

📥 Commits

Reviewing files that changed from the base of the PR and between 7a4a926 and 853afcd.

📒 Files selected for processing (7)
  • dedup-tracker.mjs
  • lib/cli-flags.mjs
  • reply-watch.mjs
  • scan-ats-full.mjs
  • scan.mjs
  • tests/cli-flags.test.mjs
  • tests/scan-help-flag.test.mjs

Comment thread lib/cli-flags.mjs Outdated
--dry-run=1 was silently accepted (its base flag --dry-run is known),
but every caller checks args.includes('--dry-run') literally, which
is false for the string '--dry-run=1' -- a silent way to run with no
dry-run protection. The equals form is now only valid when the base
flag is registered in valueFlags.

Addresses CodeRabbit finding on PR santifer#2778.
@santifer

Copy link
Copy Markdown
Owner

The header comment on lib/cli-flags.mjs is the review: two defects, each fixed independently three or four times in the identical shape, in different files, by different people. That is the signature of something that should have been one function, and naming both classes in one place is worth more than the code under it.

Verified both halves by running them rather than reading them.

validateFlags, on scan.mjs:

main    $ node scan.mjs --help    → exit 1: "portals.yml not found. Run onboarding first."
branch  $ node scan.mjs --help    → exit 0, usage printed, before any file is touched
main    $ node scan.mjs --bogus   → exit 1: "portals.yml not found"   (flag ignored entirely)
branch  $ node scan.mjs --bogus   → exit 1: "unrecognized flag(s): --bogus. Valid flags: --dry-run, --verify, …"

The second pair is the one that matters. On main a typo and a missing config produce the same message, so someone who typed --dryrun is sent to fix their onboarding. Listing the valid flags in the rejection turns a dead end into a hint, which is a small thing that will save more time than the fix itself.

flagValue, the --flag=value half:

argv result
["--from", "2026-01-01"] "2026-01-01"
["--from=2026-01-01"] "2026-01-01" ← the form that used to be discarded
["--from="] ""
["--other", "x"] undefined

scan.mjs is on the frozen core/web surface, so §55 ran: green, including the scan-history.tsv 7-column prefix. Suite on a preview against today's main: 3820 passed, 0 failed.

One consequence beyond this PR. I seeded five good first issues tonight for scripts that still hand-roll this (classify-tier, funnel-velocity, invite-match, check-table-freshness, doctor), all pointing at company-history.mjs as the pattern to copy. With this merged, that guidance is now the old way, so I am rewriting them to point at validateFlags instead. Your PR turns five upcoming first contributions from "copy this shape carefully" into "call this function", which is a much better first PR to have.

Merged. 🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

2 participants