Skip to content

feat(offer-prep): sub-statutory terms check — jurisdiction floors table + statutory-context notes + lawyer questions - #2042

Merged
santifer merged 6 commits into
santifer:mainfrom
Schlaflied:feat/substatutory-terms
Aug 10, 2026
Merged

feat(offer-prep): sub-statutory terms check — jurisdiction floors table + statutory-context notes + lawyer questions#2042
santifer merged 6 commits into
santifer:mainfrom
Schlaflied:feat/substatutory-terms

Conversation

@Schlaflied

@Schlaflied Schlaflied commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Closes #2039. Tenth member of the jurisdiction-compliance umbrella (#2026) — the second offer-document-surface member and the direct sibling of #2028/#2029: same mode, same two integration touchpoints, same pin patterns. Reviewing it next to #2029 should be near-zero marginal cost. Like #2029, it lives in modes/offer-prep.md, not oferta's Block G, so it is outside the Signal-9 coordination queue entirely.

What this adds

Prompt/instruction + data-template PR — no new executable script.

  1. templates/statutory-employment-minimums.yml — jurisdiction-keyed table of employment-standards floors. Per entry: {jurisdiction, jurisdiction_name, floors: {vacation, notice, severance, probation_limits — only whichever the jurisdiction actually defines}, void_doctrine (nullable), legal_basis, sources, as_of}. Seeded with exactly one verified row:

    • CA-ON: ESA floors — vacation 2 weeks (3 after five years, ss. 33-34), termination notice up to 8 weeks by service (s. 57) with the sub-3-month no-notice window noted (s. 54; O. Reg. 288/01 s. 8(1) — the ESA's "probation" reality), severance where applicable up to 26 weeks (ss. 63-65). void_doctrine: Waksdale v. Swegon North America (2020 ONCA 391) — termination provisions read as a whole; if ANY part violates the ESA (including a never-invoked "for cause" section defining cause more broadly than the wilful-misconduct standard, O. Reg. 288/01 s. 2(1)3), the ENTIRE provision is void, no severance of the bad part, common-law reasonable notice applies; ONCA declined to revisit in Dufault (2024); applied case line Sewell / Lamontagne / Perretta / Kopyl / Bertsch. Sources: Littler, Epstein Becker Green, HTW Law, Employment Law Boutique commentaries. as_of: "2026-07-18".

    Header carries the series contribution rule plus the table's signature semantics: floors are listed only where the jurisdiction defines them — an absent field/row means no floor is recorded and the check stays SILENT. That is the designed "US case" (no federal vacation floor), not an omission: absence is meaningful, and the architecture handles "no floor here" as gracefully as "floor undercut". Candidate rows in comments only (UK ERA s.86 / WTR 5.6 weeks; Germany BGB §622 / BUrlG 24 Werktage; France 5 weeks congés payés + convention-collective pointer; EU WTD 4-week baseline; Japan LSA art. 39; US deliberately absent). All dates are quoted YAML strings (the feat(oferta): minimum-wage floor check — jurisdiction table + date-aware wage-floor signal #2027 timezone lesson).

  2. modes/offer-prep.md — a "Statutory-context notes for sub-statutory terms (feat(offer-prep): sub-statutory terms check — flag offer clauses below the jurisdiction's employment-standards floors (ESA/Waksdale, UK ERA/WTR, BGB/BUrlG, EU WTD) #2039)" subsection at the end of Step 2's clause walk, integrating at the mode's two existing output surfaces only:

    • the walked clause's neutral tags gain a statutory-context note (blockquote template, [Render in {language.output}: ...], fictional Acme Corp example): "Ontario's ESA sets 2 weeks of paid vacation (3 weeks after five years of service) as the floor; this clause states 10 days" — an arithmetic fact plus a statute fact, never a verdict; as_of staleness disclosure included;
    • the Questions for your lawyer list gains the generic floor question plus, where the row carries a void_doctrine and the clause is a termination provision, the Waksdale question: "Does the 'for cause' definition here match the ESA's wilful-misconduct standard? If not, does Waksdale void the entire termination provision, and what would common-law notice look like for me?"

The candidate-empowering Waksdale angle

The subsection states it explicitly and neutrally: under a whole-provision voiding doctrine, a defectively drafted termination clause is often better for the candidate than a valid one (voiding → common-law reasonable notice, typically far more than ESA minimums). That is exactly why it is a question worth taking to a lawyer — not a reason to reject the offer, and never a verdict this mode renders.

Describes-never-judges is preserved, not overridden

  • Never assert voidness or violation (HARD RULE): employer size/payroll (Ontario severance), employee-category exemptions, greater-right-or-benefit analysis, choice-of-law — exactly the things a contract cannot self-certify. The mode never says the candidate's clause is void/illegal/unenforceable/in violation, and never says a doctrine "applies here". Floors, doctrines, dates, case lines = facts with citation; application = always a lawyer question.
  • Floors-absent silence: no row / no floor for the clause family → no output, standard meta-statement boundary applies.
  • Non-goal pinned in the mode text: no severance-amount calculations — common-law notice depends on Bardal-style factors no table can hold.
  • No-online-research reaffirmed: table lookup is a local file read, not research; the memory guard gains only a narrow, table-backed carve-out, worded self-containedly inside the subsection.
  • Not-legal-advice notes throughout; the existing offer-prep posture-freeze suite and hard-guard pins pass untouched.

Composition with #2029 (both merge orders)

#2029 (restrictive covenants, unmerged) also modifies modes/offer-prep.md. This PR is written to compose in either merge order, same convention as #2034's Step 5c/5d note:

Seed discipline + freshness

Single narrow, verified seed per the umbrella #2026 contract (regulator-grade / law-firm-bulletin sources + as_of); broad coverage deliberately left to comment-listed candidate rows under the same discipline. Floors change (Ontario's vacation floor changed in 2018) — the table lives under the #2036 as_of freshness watch like every other member, and #2038's schema-agnostic discovery picks it up automatically once both land.

Housekeeping & tests

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added statutory context for vacation, termination notice, severance, and probation terms during offer preparation.
    • Added jurisdiction-based coverage flags, initially for Ontario, with source and verification-date requirements.
    • Added safeguards for missing data and prevention of legal conclusions, statutory figures, and unsupported calculations.
  • Documentation

    • Documented the statutory reference template and flag-only data constraints.
  • Tests

    • Added validation for dataset structure, offer-preparation integration, lawyer-directed questions, and legal-claim safeguards.

@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The PR adds a flag-only statutory employment reference table with an Ontario entry. It updates offer-prep handling for employment clauses and routes statutory floors and doctrine questions to lawyers. Contract tests validate schema, routing, localization, silence, and prohibited assertions.

Changes

Statutory context workflow

Layer / File(s) Summary
Employment minimums reference data
templates/statutory-employment-minimums.yml, templates/README.md
Documents the flag-only jurisdiction table and adds a verified Ontario row with category flags, legal basis, sources, and verification date.
Offer-prep statutory context
modes/offer-prep.md
Adds jurisdiction and clause-category handling, clause arithmetic, regulation flags, lawyer questions, silent handling for missing categories, and restrictions on legal conclusions and statutory calculations.
Contract validation
test-all.mjs
Validates the reference data, offer-prep behavior, localized lawyer questions, silence rules, and prohibited legal assertions.

Estimated code review effort: 2 (Simple) | ~10 minutes

Sequence Diagram(s)

sequenceDiagram
  participant OfferPrepMode
  participant StatutoryMinimumsTable
  participant LawyerQuestions
  OfferPrepMode->>StatutoryMinimumsTable: lookup jurisdiction and clause category
  StatutoryMinimumsTable-->>OfferPrepMode: return category and void_doctrine flags
  OfferPrepMode->>LawyerQuestions: append clause-anchored legal questions
Loading

Possibly related issues

Possibly related PRs

Suggested labels: 📄 docs

Suggested reviewers: scott-emberson

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 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 offer-prep statutory-terms check, jurisdiction flags, statutory context, and lawyer-question routing.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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 `@modes/offer-prep.md`:
- Around line 233-245: Add an explicit presentation-boundary instruction to the
“Questions for your lawyer” guidance, requiring every generated question to be
rendered in language.output via the “[Render in {language.output}: ...]”
mechanism. Clarify that the English examples are semantic templates only and
must not be copied verbatim; preserve the existing clause-anchored and
doctrine-specific requirements.
🪄 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: e7eed845-1902-4c86-9d8d-cbfb4dc3d470

📥 Commits

Reviewing files that changed from the base of the PR and between 6da6241 and 29a21f4.

📒 Files selected for processing (4)
  • modes/offer-prep.md
  • templates/README.md
  • templates/statutory-employment-minimums.yml
  • test-all.mjs

Comment thread modes/offer-prep.md Outdated
Schlaflied added a commit to Schlaflied/career-ops that referenced this pull request Jul 19, 2026
…uage.output}] — semantic templates, never verbatim copy (PR santifer#2042 review)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
modes/offer-prep.md (2)

249-258: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Keep jurisdiction-specific doctrine facts table-backed.

This paragraph hardcodes Ontario’s Waksdale doctrine, citation, and “typically far more” notice claim, despite the earlier rule making the local table the single sanctioned source for statutory-floor and doctrine facts. A table update or additional jurisdiction can leave the prompt stale or cause legal facts to be emitted without the selected row’s citation and as_of context.

Keep this section generic and require the matched row’s void_doctrine, legal basis, sources, and freshness metadata to supply the jurisdiction-specific explanation.

🤖 Prompt for 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.

In `@modes/offer-prep.md` around lines 249 - 258, The candidate-empowering angle
must not hardcode Ontario, Waksdale, citations, or notice comparisons. Rewrite
this section generically so the selected jurisdiction table row supplies the
void_doctrine, legal basis, sources, and freshness metadata, including its
citation and as_of context, for any jurisdiction-specific explanation.

186-216: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Trigger void_doctrine lookups for all termination provisions.

The lookup is currently introduced only for clauses stating a quantified term, but the match rule also promises void_doctrine handling whenever a termination provision is walked. A termination clause containing only a “for cause” definition can therefore miss the Ontario Waksdale question and context entirely.

Broaden the lookup condition so a matching jurisdiction row with void_doctrine is checked for every termination provision, even when it has no quantified notice, severance, or probation term.

Suggested adjustment
-when the Step 2 walk reaches a clause stating a quantified term in a
-floor-bearing family ...
+when the Step 2 walk reaches a clause stating a quantified term in a
+floor-bearing family, or any termination provision in a jurisdiction whose
+row carries `void_doctrine` ...
🤖 Prompt for 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.

In `@modes/offer-prep.md` around lines 186 - 216, Broaden the Step 2 lookup
condition so termination provisions always consult the matching jurisdiction row
when it defines void_doctrine, including non-quantified “for cause” clauses.
Preserve the existing quantified-term floor checks and floors-absent silence for
vacation/PTO, notice, severance, and probation families.
🤖 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.

Outside diff comments:
In `@modes/offer-prep.md`:
- Around line 249-258: The candidate-empowering angle must not hardcode Ontario,
Waksdale, citations, or notice comparisons. Rewrite this section generically so
the selected jurisdiction table row supplies the void_doctrine, legal basis,
sources, and freshness metadata, including its citation and as_of context, for
any jurisdiction-specific explanation.
- Around line 186-216: Broaden the Step 2 lookup condition so termination
provisions always consult the matching jurisdiction row when it defines
void_doctrine, including non-quantified “for cause” clauses. Preserve the
existing quantified-term floor checks and floors-absent silence for
vacation/PTO, notice, severance, and probation families.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 2a1cafda-63f0-4acd-b6ca-36267d2c49fd

📥 Commits

Reviewing files that changed from the base of the PR and between 29a21f4 and 5a42303.

📒 Files selected for processing (1)
  • modes/offer-prep.md

@santifer

Copy link
Copy Markdown
Owner

Quick status so this isn't sitting in silence, @Schlaflied: this PR is part of the jurisdiction-lens set that's parked as a whole under #2026 (architectural-proposal) while the product direction gets decided — that's why it hasn't moved. It's not a quality signal about the work; the compliance-table craftsmanship is noted. When the umbrella call lands, these get reviewed as a sequence.

@santifer

Copy link
Copy Markdown
Owner

Direction settled, @Schlaflied, and I'm sorry it took ten days. The full reasoning is in #2280; this PR is the one case where the answer is "not in this shape".

Everything here is a live figure. Ontario's general rate is 17.60 with next_rate: 17.95 and a CPI indexation that moves it every October. The statutory floors are schedules that amendments change. Those are exactly the rows I have no way to verify or to notice going stale, and a stale numeric row with a citation attached is worse than no row at all: the citation is what makes someone believe it.

I want to be precise that this is a limit of mine, not a judgement of the work. Your table carries a legal basis, an effective date, four sources and an as_of stamp. It is more rigorous than most things I merge. I still can't check whether it's true, and neither can the next reviewer.

The version I'd take, and it isn't smaller

modes/offer-prep.md already has the mechanism for exactly this, and you know it well because your own PRs cite the pattern: the [ask your lawyer] list. The rule in that file is "never state law from memory", and questions get routed rather than answered.

So instead of asserting a rate, generate the question:

[ask your lawyer] — "This offer works out to X per hour. Is that at or above the statutory minimum for my role in {jurisdiction}, and are any of the special rates (student, homeworker) relevant to me?"

The arithmetic — converting the offer into a comparable hourly figure — is ours to do and needs no legal table at all. The comparison goes to someone who can actually answer it and is accountable for the answer.

Why I think that version is better rather than just safer: a number we publish is right until the day it isn't, and on that day it's confidently wrong with a source attached. A question stays useful forever, and it sends the person to someone whose job is being correct about it.

Leaving this open rather than closing it, because the conversion is yours to decide. If you'd rather not do it, close it and I'll understand: you've put real work into these and I'm asking you to reshape it after ten days of silence, which is on me.

And the descriptive half of your set is landing as-is — six of them, listed in #2280.

Schlaflied and others added 2 commits August 5, 2026 21:00
…le + statutory-context notes + lawyer questions (closes santifer#2039)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…uage.output}] — semantic templates, never verbatim copy (PR santifer#2042 review)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Schlaflied
Schlaflied force-pushed the feat/substatutory-terms branch from 5a42303 to 87d7532 Compare August 6, 2026 01:09
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

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.

@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 `@templates/statutory-employment-minimums.yml`:
- Around line 74-123: Remove the statutory-floor and doctrine seed data from
templates/statutory-employment-minimums.yml (lines 74-123) and its table
documentation from templates/README.md (line 13). In modes/offer-prep.md (lines
260-352), retain clause arithmetic but replace table-based legal comparisons and
special-rate analysis with lawyer-directed questions, rendering candidate-facing
questions only at the presentation boundary. In test-all.mjs (lines 2615-2712),
replace table-content assertions with coverage for the lawyer-question workflow.
🪄 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: 0c10a151-0d2f-4c8c-9609-9adb6e4569bf

📥 Commits

Reviewing files that changed from the base of the PR and between cf0d011 and 87d7532.

📒 Files selected for processing (4)
  • modes/offer-prep.md
  • templates/README.md
  • templates/statutory-employment-minimums.yml
  • test-all.mjs

Comment thread templates/statutory-employment-minimums.yml Outdated
…s instead of asserted floors (CodeRabbit)

CodeRabbit flagged (PR santifer#2042, Major/Heavy-lift) that
templates/statutory-employment-minimums.yml published statutory floor
VALUES (vacation/notice/severance figures) and doctrine NARRATIVE
(Waksdale v. Swegon holding, case line) as verified prompt context —
content that goes stale through amendment/indexation/new case law while
retaining apparent authority in the prompt.

Same directional fix as sibling PRs santifer#2014/santifer#2027 in this batch, but leaning
further toward removal here per CodeRabbit's more direct "remove... seed
data" wording and its explicit "should not proceed in its current form"
blocker — rather than santifer#2027's "keep as non-authoritative reference"
reframing.

- templates/statutory-employment-minimums.yml: rows now carry only two
  structural flags — `floor_categories` (which clause families the
  jurisdiction regulates) and `void_doctrine` (boolean: does a
  whole-provision-voiding doctrine exist) — plus a statute NAME
  (`legal_basis`), sources, and `as_of`. No floor numbers, no doctrine
  case names/holdings anywhere in the data.
- templates/README.md: table description updated to describe the
  flag-only shape and why (values/narrative go stale; flags don't need
  to be “live”).
- modes/offer-prep.md (sub-statutory-terms subsection): keeps clause
  arithmetic (what the clause itself states), drops the direct
  clause-vs-floor comparison and doctrine narration, and routes both to
  explicit lawyer questions ("what is the current statutory minimum, and
  does this clause meet it?" / "does a defect elsewhere void the whole
  clause?"). Candidate-facing question wording stays semantic-template
  only, rendered via [Render in {language.output}] at the presentation
  boundary (unchanged from the prior CodeRabbit round on this PR).
- test-all.mjs (santifer#2039 block): rewritten to assert the flag-only data
  shape, the lawyer-question routing workflow (both the generic and
  void_doctrine-conditioned questions), and negative assertions that no
  removed statutory figure or doctrine name leaks back into the mode text
  or table.

Full suite: 2981 passed, 0 failed (warnings are pre-existing/unrelated
fixtures).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

@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: 4

🤖 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/offer-prep.md`:
- Around line 281-287: Update the statutory-source hard guard and the
surrounding offer-prep rules to narrowly permit lookup of
templates/statutory-employment-minimums.yml for structural flags only. Continue
prohibiting current statutory floor values, doctrine holdings, and
clause-specific legal conclusions, while preserving the no-online-research
restrictions.
- Around line 343-350: Remove the asserted doctrine effect from
modes/offer-prep.md lines 343-350 and replace it with a neutral question
directing the candidate to ask a lawyer whether the issue applies. In
modes/offer-prep.md lines 363-372, remove the Bardal reference and factor list
while retaining only the no-calculation rule and lawyer routing. In test-all.mjs
lines 2694-2698, remove the required Bardal assertion and instead test that
calculations are not performed and no doctrine narrative is stated.

In `@templates/statutory-employment-minimums.yml`:
- Around line 108-110: Replace the non-citable second entry in the sources list
for void_doctrine with a specific, publicly retrievable Ontario Court of Appeal
decision or official publication that directly supports termination-provision
enforceability. Keep the source description concise and non-narrative, and
preserve the existing Ministry of Labour source.

In `@test-all.mjs`:
- Around line 2639-2652: Update the validation around the CA-ON-only check to
iterate over every entry in minimums, applying the same category allowlist,
required-field type/nonempty checks, and no-floor-values/no-doctrine-narrative
assertions to each jurisdiction row. Preserve the existing flag-only schema
requirements while removing the hardcoded single-row scope.
🪄 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: 8974a4fc-43e4-4b7f-b548-51c0a6914b87

📥 Commits

Reviewing files that changed from the base of the PR and between 87d7532 and 3c10681.

📒 Files selected for processing (4)
  • modes/offer-prep.md
  • templates/README.md
  • templates/statutory-employment-minimums.yml
  • test-all.mjs

Comment thread modes/offer-prep.md Outdated
Comment thread modes/offer-prep.md Outdated
Comment thread templates/statutory-employment-minimums.yml Outdated
Comment thread test-all.mjs Outdated
…doctrine-effect/Bardal assertions, citable void-doctrine source, jurisdiction-wide schema tests (CodeRabbit)

Addresses 4 new CodeRabbit findings on PR santifer#2042 after the 3c10681 fix commit:

- Hard guard and meta-statement boundary now explicitly carve out
  templates/statutory-employment-minimums.yml, but narrowly — only its
  floor_categories/void_doctrine flags and legal_basis pointer are
  sanctioned; current floor values, doctrine holdings, and clause-specific
  conclusions stay banned and remain lawyer questions. Also fixed the
  self-contradicting "no carve-out" line left over from the previous round.
- Removed the asserted doctrine-effect language in the
  candidate-empowering-angle paragraph (stated voiding "can fall back to
  more generous protection") and replaced it with a neutral
  lawyer-directed question.
- Removed the Bardal-factors reference and factor list from the
  no-calculation non-goal section, keeping only the no-calculation rule
  and lawyer routing.
- Replaced the non-citable second void_doctrine source with a real,
  publicly verifiable citation: Waksdale v. Swegon North America Inc.,
  2020 ONCA 391 — named as a bare citation only, no holding narrated.
- test-all.mjs: the jurisdiction-flags schema check now iterates every row
  in `minimums` (not just CA-ON) so the flag-only discipline is enforced
  project-wide as rows are added; the Bardal-required assertion was
  replaced with checks for no-calculation language and no reintroduced
  doctrine narrative (Bardal/Waksdale/ONCA/wilful-misconduct-standard) in
  offer-prep.md's own prose — a bare case citation is still permitted in
  the YAML sources field.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
modes/offer-prep.md (1)

309-350: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Separate floor matches from doctrine-only matches.

The or condition matches any termination provision when void_doctrine is true. The following output requires clause arithmetic and adds the generic floor question. A termination provision without a quantified notice or severance term can therefore receive an unsupported arithmetic note or an unrelated floor question. This also bypasses absent-category silence when floor_categories does not contain the relevant category.

Split the conditions into floorMatch and voidDoctrineMatch. Emit the arithmetic note and generic floor question only for floorMatch. Emit the doctrine questions only for voidDoctrineMatch.

Proposed routing change
-On a match — a walked clause states a quantified term in a flagged
-category, or a termination provision is walked in a jurisdiction whose
-row carries `void_doctrine: true` — two things happen
+For a floor match, emit the clause arithmetic and the generic floor
+question. For a doctrine-only termination match, emit only the
+doctrine-directed lawyer questions.
🤖 Prompt for 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.

In `@modes/offer-prep.md` around lines 309 - 350, Split the match routing into
distinct floorMatch and voidDoctrineMatch conditions. Generate the
statutory-context arithmetic note and generic floor question only when the
walked clause has a quantified term in a category present in floor_categories;
do not emit them for doctrine-only termination matches. Generate the
doctrine-directed question only for termination provisions in rows with
void_doctrine: true, while preserving absent-category silence.
🤖 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 2644-2661: Update the row validation around the `categories`,
`rowText`, and `ok` expressions to require `floor_categories` to be an array,
require every `sources` entry to be a non-empty string, reject keys outside the
documented schema, and validate permitted fields by their actual values and
types. Replace the `JSON.stringify(row)` regex denylist as the primary control
with explicit semantic checks for prohibited floor values and doctrine
narratives, including fields such as `minimum_vacation_days` and `notice_weeks`;
preserve the existing required-field and allowed-category constraints.

---

Outside diff comments:
In `@modes/offer-prep.md`:
- Around line 309-350: Split the match routing into distinct floorMatch and
voidDoctrineMatch conditions. Generate the statutory-context arithmetic note and
generic floor question only when the walked clause has a quantified term in a
category present in floor_categories; do not emit them for doctrine-only
termination matches. Generate the doctrine-directed question only for
termination provisions in rows with void_doctrine: true, while preserving
absent-category silence.
🪄 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: 13eb3810-7d2b-4da8-b220-6308aaecc3e0

📥 Commits

Reviewing files that changed from the base of the PR and between 3c10681 and 8f285d2.

📒 Files selected for processing (3)
  • modes/offer-prep.md
  • templates/statutory-employment-minimums.yml
  • test-all.mjs

Comment thread test-all.mjs Outdated
Schlaflied and others added 2 commits August 6, 2026 01:13
…, strengthen schema validation (CodeRabbit)

modes/offer-prep.md: the sub-statutory-terms matching logic OR'd two
conditions into one combined trigger, so a termination clause with no
quantified notice/severance term could still receive the clause-arithmetic
statutory-context note and the generic floor question just because its
jurisdiction row carried void_doctrine: true. Split into two independent
conditions — floorMatch (quantified term in a floor_categories category)
and voidDoctrineMatch (termination provision + void_doctrine: true) — and
route the arithmetic note + generic floor question to floorMatch only, the
doctrine-directed question to voidDoctrineMatch only. A clause satisfying
both (e.g. a termination clause with a quantified notice term in a
void_doctrine jurisdiction) gets both outputs; a termination clause with
neither a quantified term nor a void_doctrine row stays silent, per the
existing absent-category-silence rule.

test-all.mjs: strengthened the statutory-employment-minimums.yml row schema
check — floor_categories must actually be an array (no silent [] fallback
for a malformed value), every sources entry must be a non-empty string,
unknown keys outside the documented schema are rejected, and an explicit
per-field denylist (minimum_vacation_days, notice_weeks, doctrine_holding,
etc.) is now the primary control against floor values/doctrine narrative
sneaking onto a row, with the JSON.stringify regex sweep kept only as a
secondary belt-and-suspenders check.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…intainer direction (santifer#2280)

santifer's direction on PR santifer#2042 (2026-07-29, full reasoning in santifer#2280):
the jurisdiction table of category-regulation flags (floor_categories,
void_doctrine) is a live legal fact this system can never verify or
notice going stale, same reasoning as the sibling santifer#2027 minimum-wage
table -- a stale flag with a citation attached is worse than no flag at
all, because the citation is what makes someone believe it. santifer#2280
explicitly names santifer#2042 as one of the two PRs "entirely live figures"
redirected to the lawyer-question mechanism -- not a mis-posted comment,
confirmed by cross-checking the issue body, which lists santifer#2042 by number.

Verified before concluding table removal (rather than assuming it from
santifer#2027's precedent): the table itself carries only boolean/category flags,
not numeric figures, so the "live figure" objection needed checking on
its own terms. It applies anyway -- floor_categories and void_doctrine
are themselves facts that change when a jurisdiction's employment
standards are amended or case law shifts (e.g. a new void-doctrine ruling
in a jurisdiction previously flagged false), and this system has no way
to notice that drift either. So the table is deleted entirely, not kept
in a flags-only shape.

- Delete templates/statutory-employment-minimums.yml entirely; drop its
  templates/README.md row.
- Rework the sub-statutory-terms subsection in modes/offer-prep.md: no
  table lookup, no floor_categories/void_doctrine gating, no
  "floors-absent silence" case (nothing is asserted, so nothing needs
  suppressing). The clause's own stated term is restated (arithmetic-free
  paraphrase, not from any table) and two lawyer questions fire
  unconditionally for every jurisdiction: a statutory-floor question and
  a whole-provision-voiding-doctrine question, both following the
  [ask your lawyer] pattern. Step 0/Step 1 carve-out language updated to
  match -- restrictive-covenants.yml remains the sole sanctioned
  statutory-fact source (unaffected; not part of santifer#2280's redirect list).
- The Waksdale v. Swegon North America Inc., 2020 ONCA 391 citation that
  lived in the deleted table is gone with it -- it was never independently
  re-verified in this pass (same browsing-sandbox limitation as the prior
  round that first flagged it); no longer relevant since the table it
  lived in no longer exists.
- test-all.mjs: replace the flag-only-schema/table-parsing tests with
  tests asserting the table is deleted, templates/README.md carries no
  row for it, the subsection documents the santifer#2280 rationale, and both
  lawyer questions fire unconditionally with no table-flag gating and no
  reintroduced ESA figures or doctrine narrative.

Full suite: node test-all.mjs -- 2981 passed, 0 failed (1 pre-existing,
unrelated warning).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@Schlaflied

Copy link
Copy Markdown
Contributor Author

@santifer Reworked per your direction in #2280 (confirmed #2042 is explicitly named there, not a stray cross-post) — templates/statutory-employment-minimums.yml dropped entirely, including the flag-only floor_categories/void_doctrine fields and the Waksdale citation. The section now fires two unconditional [ask your lawyer] questions (statutory floor + voiding doctrine) per clause, no table lookup. CI green, mergeable.

@santifer
santifer merged commit 51ae334 into santifer:main Aug 10, 2026
13 checks passed
@santifer

Copy link
Copy Markdown
Owner

Clean execution of #2280, @Schlaflied. Deleting templates/statutory-employment-minimums.yml and routing sub-statutory terms (vacation/notice/severance/probation) through [ask your lawyer] instead of a floors table is exactly right — and the line 'that table is gone and is not coming back in any shape, including a flags-only shape' is the reasoning stated where the next person will find it. The retained restrictive-covenants.yml is a different category (verified, cited local data, not a live statutory figure), so keeping it is correct. Merged! 🚀

@github-actions github-actions Bot mentioned this pull request Aug 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

2 participants