feat(oferta): pay-transparency disclosure signals — jurisdiction table + range-width cap (strong) + missing-range (corroborating-only) - #2021
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughThe changes replace jurisdiction-table pay-transparency validation with a self-computed compensation-range heuristic. They also extend freshness checks to discover and validate mapping-shaped jurisdiction rows. ChangesPay-transparency range-width heuristic
Mapping-shaped freshness extraction
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
|
Direction settled, @Schlaflied: #2280 has the full reasoning. Sorry for the ten-day wait. (Reposting this: my first attempt lost three code references to a shell-quoting mistake on my end, and the sentence saying what to remove came out unreadable. Corrected below.) Sub-signal 9a lands. The table goes. 9a computes the width of an advertised range from the posting itself. That's arithmetic on text the mode already parses, and it's the part with the insight: "this range is unusually wide, which often means the band for your level is undecided or the posting is templated — ask the recruiter for the real band." No statute needed for any of that. What goes is Sub-signal 9b (missing compensation in a jurisdiction whose row sets One thing I want on record because this is the best-argued PR of the ten: the phrasing discipline you wrote is the reason I trust the rest of your work. "Never render this as the employer breaking the law", the carve-outs modelled explicitly, the strong-vs-corroborating split. That's not a promise in a PR description, it's written into the mode where the agent actually reads it. Keep doing that. |
…e + range-width cap + corroborating missing-range (closes santifer#2019) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1500d1a to
bbc65b5
Compare
|
Note GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer. |
There was a problem hiding this comment.
Actionable comments posted: 6
🤖 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 `@modes/oferta.md`:
- Line 404: Update the Signal 13 identifiers consistently: in modes/oferta.md at
lines 404-404, replace 9a and 9b with 13a and 13b; in test-all.mjs at lines
2476-2476, update the failure diagnostic to report 13a and 13b.
- Around line 400-402: Update the corroboration sentence in the
missing-compensation guidance to reference the resolved posting jurisdiction via
{jurisdiction_name}, not “the candidate's jurisdiction.” Only describe it as the
candidate's jurisdiction when the profile location supplied the fallback
resolution.
- Around line 390-394: Gate the advertised compensation width signal in the
jurisdiction-table lookup by requiring a reliable posting date on or after the
matched row’s effective date; when the posting date is unavailable, skip the
signal rather than treating the rule as active. Preserve the existing behavior
for jurisdictions without a table row and use the parsed advertised_comp values
only after this effective-date check.
- Around line 394-396: Update the 13a over-wide-range condition to require a
non-null width_cap plus explicit, unambiguous currencies and periods for both
advertised_comp bounds and the cap, with matching currency and normalized period
before subtracting. Skip 13a when any value is missing, ambiguous, or
incompatible, and do not invent or compare incompatible cap values.
In `@templates/pay-transparency.yml`:
- Around line 20-30: Update the pay-transparency freshness contract so
jurisdiction mapping entries under jurisdictions, including CA-ON, are checked
by check-table-freshness.mjs. Add the required as_of metadata and configure an
adapter/freshness entry for mapping-shaped rows, or define and enforce a
separate contract covering these entries.
In `@test-all.mjs`:
- Around line 2443-2452: Strengthen the seed check condition around the existing
`on` validation: require `on.width_cap?.period` to equal `'year'`, validate
`on.effective` against the expected valid effective date rather than merely
checking truthiness, and ensure both `on.exemptions` and `on.sources` are
non-empty arrays whose entries are strings.
🪄 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: e9fede98-4bf2-412a-b822-546138c7fa5e
📒 Files selected for processing (3)
modes/oferta.mdtemplates/pay-transparency.ymltest-all.mjs
…ration text, effective-date gating, freshness coverage, stronger seed test (CodeRabbit)
- modes/oferta.md: fix leftover 9a/9b -> 13a/13b in the closing paragraph
(rebase renumbered the signal but missed this reference); gate 13a on a
reliable posting date on/after the jurisdiction row's `effective` date
(skip if unavailable); require a non-null width_cap plus matching,
unambiguous currency/period on both advertised_comp and width_cap before
any arithmetic; use {jurisdiction_name} (resolved posting jurisdiction)
in the 13b corroboration sentence instead of always saying "the
candidate's jurisdiction"
- test-all.mjs: fix matching 9a/9b -> 13a/13b in the failure diagnostic;
strengthen the CA-ON pay-transparency seed self-test to require
width_cap.period === 'year', the exact expected effective date
(2026-01-01), and non-empty string-array exemptions/sources
- templates/pay-transparency.yml: add `as_of` to the CA-ON row so
check-table-freshness.mjs's freshness contract actually covers it
- check-table-freshness.mjs: extend extractRows() to also discover
mapping-shaped row-sets (object keyed by jurisdiction code, e.g.
`jurisdictions: { CA-ON: {...} }`) alongside the existing array-shaped
ones, synthesizing `jurisdiction` from the map key; adds self-test
coverage for the new shape
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
There was a problem hiding this comment.
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 `@test-all.mjs`:
- Around line 2443-2458: Update the CA-ON seed validation condition around
isNonEmptyStringArray and effectiveStr to require on.as_of as a quoted
YYYY-MM-DD date, matching the discovery contract used by
check-table-freshness.mjs. Include the as_of requirement in the success
assertion and expand the failure message so missing or invalid freshness
metadata is reported.
🪄 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: 932bfda8-a79f-42ae-9684-4be2492d8ed6
📒 Files selected for processing (4)
check-table-freshness.mjsmodes/oferta.mdtemplates/pay-transparency.ymltest-all.mjs
…ching freshness-check contract (CodeRabbit)
The CA-ON seed self-test validated width_cap/exemptions/legal_basis/effective/sources
but never checked as_of, the field check-table-freshness.mjs actually uses to discover
and validate the row. Add a strict string + YYYY-MM-DD format check for on.as_of to the
success assertion, and expand the failure message to report the field's actual value and
type (flagging an unquoted-Date case explicitly) when it's missing or malformed.
templates/pay-transparency.yml's CA-ON row already quotes as_of ("2026-07-18"), so no
data change was needed -- only the test was under-validating it.
…rection, keep only self-computed range-width signal (santifer#2280) santifer's direction on santifer#2021: sub-signal 9a/13a (the range-width arithmetic computed purely from the posting's own advertised_comp) lands, but templates/pay-transparency.yml goes entirely -- width_cap, range_required, and the $200K exemption are regulatory parameters he can't verify and won't notice change. Sub-signal 9b/13b (missing-comp corroboration keyed to a jurisdiction's range_required row) had no trigger left without the table, so it goes with it. - modes/oferta.md: replace the two-sub-signal, table-backed Block G signal 13 with a single table-free "Pay-Transparency Range-Width Check". Heuristic is now a generic ratio (width > 0.5x the range's own floor) applied to any posting in any jurisdiction, explicitly framed in the mode text as a general heuristic, not a legal threshold. Preserves the phrasing-discipline pattern santifer praised (never asserting the employer broke the law). - templates/pay-transparency.yml: deleted. - check-table-freshness.mjs: reworded the two comments that named the deleted file; kept the generic mapping-shaped table discovery path since it's schema-agnostic, self-tested with synthetic fixtures, and has no dependency on this specific file. - test-all.mjs: replaced the table-parsing/dual-sub-signal tests with a table-removed assertion + a single table-free signal check; fixed a stale string-slice delimiter in the unrelated jurisdiction- prohibited-content phrasing test that referenced the old heading text. templates/README.md and AGENTS.md/docs/SCRIPTS.md never had a row/ reference for this file, so nothing to remove there. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 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 `@modes/oferta.md`:
- Around line 390-392: Update the compensation-range requirements in the signal
description to require both normalized bounds to use the same currency and the
lower bound to be greater than zero. State that ranges with mismatched
currencies or a non-positive normalized lower bound must skip the signal, while
preserving the existing normalization and width comparison rules.
In `@test-all.mjs`:
- Around line 2450-2456: Strengthen the condition in the test block around
ptSection so it also structurally asserts the documented threshold formula “top
- bottom > 0.5 × bottom.” Match the relevant expression or equivalent threshold
wording in ptSection alongside the existing framing checks, without removing the
current assertions.
🪄 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: 279c3e13-275f-4509-aad7-094acf926255
📒 Files selected for processing (3)
check-table-freshness.mjsmodes/oferta.mdtest-all.mjs
…nd, structurally assert threshold formula in tests (CodeRabbit)
- modes/oferta.md: signal 13 now explicitly requires the two normalized
compensation bounds to share the same currency and the normalized lower
bound to be strictly positive; mismatched currency or a zero/negative
floor skips the signal entirely instead of computing it.
- test-all.mjs: the Block G pay-transparency test now also asserts the
documented threshold formula ("top - bottom > 0.5 × bottom") is present
in ptSection, in addition to the existing framing/phrasing checks.
|
@santifer Reworked per your direction in #2280 — |
|
Another one landed exactly per direction, @Schlaflied. Dropping the jurisdiction table and keeping only the self-computed range-width arithmetic — plus a CI assertion that fails if |
Closes #2019
What this adds
Prompt/instruction + data-template PR — no new executable script. Third member of the statutory-anchor series (#2013 rejection latency, #2018 prohibited content): a generic Block G engine + jurisdiction table, seeded narrow and verified, community-extended.
1.
templates/pay-transparency.yml(new system-layer data template)Jurisdiction table with schema
{range_required, width_cap {amount, currency, period}, exemptions, legal_basis, effective, sources}. Seeded with exactly one verified row:Seed-source discipline (documented in the file header): no entry without a citable legal source + explicit effective date. Candidate rows (US-CO 2021, US-NYC 2022, US-CA/US-WA 2023, US-IL 2025, EU Directive 2023/970 transpositions) are listed in comments as contributor suggestions, not as entries.
2.
modes/oferta.md— Block G Signal 9, two sub-signals of different evidence strengthMirrors the strong-vs-corroborating split the terminology-mismatch signal (#1936) established:
advertised_compit already parses and compares against the table'swidth_cap. The evidence is in the JD text itself; aggregator re-posting can't manufacture it.Jurisdiction resolved from the JD's stated location with
config/profile.yml→locationfallback — same region-aware pattern as the employment-classification signal. No-row jurisdictions skip the signal entirely.Warn-only guarantees
[Render in {language.output}: ...]localization pattern; data-format tokens stay fixed.Signal-numbering coordination note
This PR numbers the section Signal 9, immediately after what
maincurrently carries (Signals 1–8, ending with the #1936 terminology-mismatch signal). Two in-flight siblings may collide on that slot: PR #1938 (location-tag mismatch, currently also numbered 9) and the upcoming PR for #2018 (jurisdiction-prohibited content). Same convention as the #1936/#1938 note: whichever merges later renumbers — happy to rebase and renumber this one depending on merge order.SYSTEM_PATHS
templates/pay-transparency.ymlis covered by the existingtemplates/directory entry inupdate-system.mjsSYSTEM_PATHS — verified vianode validate-system-paths-coverage.mjs(752 tracked files covered, including the new template).Test evidence
Three new doc-structure pins in
test-all.mjs:templates/pay-transparency.ymlexists, parses as YAML, and the CA-ON seed carriesrange_required/width_cap(50000 CAD) /exemptions/legal_basis(O. Reg. 476/24) /effective/sources.node test-all.mjs --quick: 1801 passed, 0 failed (baseline before this PR: 1798 passed, 0 failed — +3 pins, nothing broken). Same pre-existing warning as baseline.🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Improvements