Conversation
SSCBA 1992 s.124(1)(c) bars Income Support when the claimant is engaged in remunerative work or the other member of a couple is: paid work of 16 hours a week or more for the claimant (IS Regs 1987 reg 5(1)) and 24 for the partner (reg 5(1A)). A person within Sch 1B para 4, a carer, is not treated as engaged in it (reg 6(4)(c)). The partner's threshold applies to whoever is not the claimant, so the gate tests it for each candidate claimant. s.124(1)(f) bars it when the claimant is entitled to a jobseeker's allowance of either kind, or the partner (or the couple) to income-based JSA. The partner's contribution-based JSA does not bar it. Income-based JSA follows the income-related ESA pattern: the award on the claimant's and partner's reported amounts after the JSA capital test, through a new income_related_jsa_award helper that jsa_income also uses, or a jsa_income entered directly, taken to be theirs. - Parameters gov.dwp.income_support.eligibility.remunerative_work claimant_hours (24, 16 from 7 April 1992) and partner_hours (24, 16 from 7 April 1992, 24 from 7 October 1996), from legislation.gov.uk point-in-time texts of reg 5. - income_support_remunerative_work_hours: weekly_hours, enterable directly to leave out the employments reg 6(1) excludes (reg 5(6)). - 17 YAML cases hand-computed from the law; 6 fail on the previous gate. - The Hypothesis differential oracle now reads (c) and (f), and both properties draw hours, JSA and direct jsa_income. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
s.124(1)(c) and (f) only bar a claim, so raising any claimant's or partner's hours or JSA cannot turn an ineligible family eligible. The new Hypothesis property builds each family twice, the second time with more paid work or JSA, and checks eligibility never rises. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#2013 (b1977d9) primes half the generated families at the edge of eligibility and draws a direct esa_income half the time. Resolve against this branch's JSA generators: a direct jsa_income is now also drawn half the time, and a primed claimant has no paid work or JSA, so it sits at the edge of eligibility under (c) and (f) as well. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 1, 2026
MaxGhenis
added a commit
that referenced
this pull request
Oct 1, 2026
Simulation.input_variables is fixed when the simulation is built and ignores the period. Three synthetic cases showed the gate getting it wrong: - an esa_income set with set_input after construction did not bar IS; - the same on a branch did not bar IS either; - an esa_income input for 2024 made the 2025 gate read esa_income as entered directly, even though 2025's value came from the formula over every member's reports, an excluded adult's included. The #2025 review found this on that PR's JSA copy of the pattern. policyengine_uk/utils/inputs.py (entered_directly, identical to #2025's copy) reads core's own record of explicit inputs (_user_input_keys: variable, branch, period), the record that to_input_dataframe reads. It counts an input set on this branch or one it inherits from, provided the value is still stored. test_income_support_esa_entered_directly.py covers all three cases; each fails on the previous gate. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review r1 of #2025 (finding 1): the gate detected a direct jsa_income through Simulation.input_variables. That list is fixed at construction and ignores the period, so it missed an input set later with set_input or on a branch, and treated an input for one year as an input for every year. An excluded member's report then counted in a year with no direct input. entered_directly (policyengine_uk/utils/inputs.py) reads core's record of explicit inputs, (variable, branch, period) in _user_input_keys, for the branches the simulation can see, and requires the value still be stored. #2013 adopts the same helper for esa_income. Also from the review: - jsa_income returns zero before reading reports when income-based JSA is not active, as before the helper was introduced (finding 4); - income_support_remunerative_work_hours says weekly_hours is a usual week, not the reg 5(2)/(3B) average for fluctuating hours (finding 3); - YAML cases for a partner at 23 hours, inferred roles with an excluded grandparent, two caring award holders with contribution-based JSA, and a direct jsa_income for another year; pytest regressions for late, branch and other-year inputs (finding 5). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…gates' into is-remunerative-work-jsa-conditions
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis
added a commit
that referenced
this pull request
Oct 2, 2026
…was input claimant_or_partner_esa_income and claimant_or_partner_jsa_income took esa_income / jsa_income as the claimant's or partner's award whenever the name was in Simulation.input_variables. That list is fixed at construction and ignores the period: an input for 2024 alone made 2025 read the benefit-unit total, so another member's 2025 award counted, and an award set later with set_input or on a branch was ignored. Both now use entered_directly (policyengine_uk/utils/inputs.py, byte-identical to #2013 and #2025), which reads core's record of each input's variable, branch and period. jsa_income.py is re-copied from #2025 (6337f31): the formula returns early while income-based JSA is inactive, before reading reports. Tests: YAML cases for an award entered for an earlier year only, and Python tests for a late set_input, a set_input after the value was cached, a branch and a late zero entry. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review r2 of #2025: entered_directly read core's _user_input_keys, but in policyengine-core 3.32.9 that record drifts from storage. - clone() copies the holders' stored arrays but shares the record, so an input set on a clone, or on a parent after a branch was made, was recorded against arrays it never reached. An excluded adult's report then barred Income Support on the original or the earlier branch. - delete_arrays() removes arrays but keeps their record, so a formula result calculated later for the same period looked like an input. The UK Simulation (and so Microsimulation) now gives each clone its own copy of the record and drops the entries for deleted arrays. Both changes only remove stale or foreign entries; they also correct what core's own _invalidate_all_caches and to_input_dataframe read from the record. entered_directly now asks about the stored value the simulation reads: the first visible branch (own, parents', default) that stores one, as the holder reads. It no longer falls back silently when core's record is missing. test_entered_directly_lifecycle.py covers both awards (jsa_income, esa_income) with an excluded adult reporting the award. Six of its sixteen cases fail without the Simulation changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review r2 of #2025: reg 5(2) takes expected weekly hours or, for fluctuating hours, a complete recognisable cycle or the five weeks before the claim (or a more accurate period), and reg 5(7) counts paid meal breaks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis
added a commit
that referenced
this pull request
Oct 2, 2026
Cherry-picked from #2025 (48abd88). simulation.py and utils/inputs.py are identical to that commit. Its lifecycle test file is parametrised over jsa_income too, and this PR has no JSA gate, so it stays in #2025; the ESA cases are mirrored in test_income_support_esa_entered_directly.py. entered_directly read core's _user_input_keys, but in policyengine-core 3.32.9 that record drifts from storage: - clone() copies the holders' stored arrays but shares the record. An input set on a clone, or on a parent after a branch was made, was recorded against arrays it never reached, so an excluded adult's reported ESA then barred Income Support on the original or on the earlier branch. - delete_arrays() removes arrays but keeps their record, so a formula result calculated later for the same period looked like an input. The UK Simulation (and so Microsimulation) now gives each clone its own copy of the record, and drops the entries for deleted arrays. Both changes only remove stale or foreign entries. entered_directly now asks about the stored value the simulation reads: the first visible branch (its own, then its parents', then the default) that stores one, which is the order the holder reads in. The 11 ESA cases pass. With the new inputs.py on the previous simulation.py, 3 of them fail: deletion, clone, and an earlier branch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…gates' into is-remunerative-work-jsa-conditions
MaxGhenis
added a commit
that referenced
this pull request
Oct 2, 2026
Takes policyengine_uk/simulation.py and policyengine_uk/utils/inputs.py byte-identical from 48abd88 on #2025 (is-remunerative-work-jsa-conditions). In policyengine-core 3.32.9, delete_arrays keeps the deleted arrays' _user_input_keys entries, and clone shares the record. A formula value could then look like a direct input, after a deletion or an input on a clone or on a parent after a branch. The UK Simulation now gives each clone its own copy of the record and drops the entries for deleted arrays, and entered_directly asks about the stored value the simulation actually reads. test_claimant_or_partner_awards_entered_directly.py mirrors #2025's lifecycle cases on claimant_or_partner_esa_income and claimant_or_partner_jsa_income. 6 of its 12 cases fail without the Simulation changes. #2025's own test file asserts its s.124(1)(f) JSA bar, which this branch does not have, so it is not copied. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis
added a commit
that referenced
this pull request
Oct 2, 2026
Review r2 of this PR, and review r3 of #2025, showed that deciding "entered directly" from core's record of inputs (_user_input_keys) is unsound in policyengine-core 3.32.9. The record drifts across delete_arrays, clone, disk storage and core-built simulations, and a UK Simulation built with no inputs has no record, so the gate raised AttributeError. The record is no longer read: utils/inputs.py is deleted and simulation.py is restored to its state before this PR. The gate now reads the value of esa_income. If the value is what the reported awards give, either the award after the capital test (the formula) or their plain total (disable_simulated_benefits), the gate reads the claimant's and partner's reports. Any other value (an award entered directly, or a reform that replaces or neutralises esa_income) is taken to be theirs. Two consequences are intended and tested: abolishing income-related ESA removes the bar, and an entered award exactly equal to what the reports give is read through them. The rule is the same as #2025's for JSA. IS Regs 1987 Sch 1B para 2 is now a prescribed category: "A single claimant or a lone parent with whom a child is placed" by a local authority, with is_looked_after_by_local_authority as the proxy. A lone parent of an 8-year-old with a placed 3-year-old is eligible through para 2, not para 1 (the placed child is outside the household, reg 16(4)). The YAML case now expects true; new cases cover a single claimant with only a placed child, and a couple, who are not covered. The documentation calls the award-holder rule a model convention (if both partners report IS, either can be the claimant). The youngest-child documentation cites reg 16(4)-(6) and calls the flag a proxy. Property tests: - the invariance property adds only adults outside the family, primed as over state pension age, ESA, an IS report or a carer; - placed children are family members, read through para 2 in the oracle; - a new split-couple shape: the award holder fails a condition and the qualifying partner has no award; - direct ESA entries (0 or 4,000; 4,000 is never a report total) are drawn more often. The oracle's signature is unchanged; the caller applies the value rule. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review r3 of #2025 (finding 7): a school-year cycle leaves out school holidays and other periods the person is not required to work; reg 5(2)(b)(ii)'s five weeks run to the claim or a superseding decision; paid refreshment time counts with meal breaks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#2013 (97b7a1c) replaces entered_directly with a value rule for income-related ESA, deletes policyengine_uk/utils/inputs.py, restores policyengine_uk/simulation.py (no clone/delete_arrays overrides), and adds IS Sch 1B para 2 (a single claimant with a placed child). Review r3 of #2025 showed provenance via core's _user_input_keys is unsound in policyengine-core 3.32.9: core-built simulations skip the UK overrides, disk clones share files, default-named branches and ETERNITY diverge, input-free simulations crashed, and delete_arrays became O(keys). Income-based JSA now follows the same rule. jsa_income counts as the couple's award only when it differs from both the award on everyone's reported amounts after the capital test and their plain total (which disable_simulated_benefits sets); otherwise the claimant's and partner's reports decide. An entered award, or a reform that removes or replaces jsa_income, therefore applies, whatever the lifecycle that stored it. Conflicts: the gate's documentation and its ESA/JSA block, and the property test (both sides kept: #2013's shapes, placed children and para 2; this branch's work and JSA limbs; direct values {0, 4000} for both awards, with explained_by_reports taking the JSA capital rules). test_income_support_direct_inputs.py and test_entered_directly_lifecycle.py are rewritten to the value rule, including the raw reported total and a neutralised jsa_income. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis
added a commit
that referenced
this pull request
Oct 2, 2026
Takes is-remunerative-work-jsa-conditions at bfff081 (with #2013 at 97b7a1c). In test_income_support_eligibility_properties.py, #2025's version is kept and the work tests are re-applied: the reference's award on the claimant's and partner's reports, and explained_by_reports' award on everyone's reports, pass the ESA and JSA work screens; monotonicity allows a gain only where a calculated award was lost. Excluded members are now adults only, so the invariance property needs no joint-claim hold. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis
added a commit
that referenced
this pull request
Oct 2, 2026
#2013 and #2025 replaced entered_directly and the Simulation overrides with a value rule, after #2025's round-3 review found the record of direct inputs unsound in policyengine-core 3.32.9: - a Simulation without inputs has no record; - the YAML runner and SimulationBuilder bypass the UK Simulation; - disk-backed clones share files; - branch names and ETERNITY periods diverge; - delete_arrays becomes O(keys). This merge takes their removal of policyengine_uk/utils/inputs.py and their simulation.py (identical to 63b633c's). claimant_or_partner_esa_income and claimant_or_partner_jsa_income now mirror the gate. Where esa_income / jsa_income holds what the reported awards give, either after the capital test (the formula) or as their plain total (disable_simulated_benefits), they use the claimant's and partner's reported awards. Otherwise they take the stored value to be the claimant's or partner's: an award entered directly, or a reform that replaces or removes it. An entered award equal to either amount is read through the reports. test_claimant_or_partner_awards_entered_directly.py gains cases for an entered award equal to the reports, the raw total with capital (partner £200, other adult £3,000, savings £10,000: £0), and a neutralised award. The lifecycle cases (deletion, clone, branches) keep their expectations. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…gates' into is-remunerative-work-jsa-conditions
The award on the reported amounts is whatever screen jsa_income applies (jsa_income_eligible), so the comment stays true when that screen gains conditions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…gates' into is-remunerative-work-jsa-conditions
MaxGhenis
added a commit
that referenced
this pull request
Oct 2, 2026
MaxGhenis
added a commit
that referenced
this pull request
Oct 2, 2026
…pers Comment-only. In esa_income.py and jsa_income.py the helpers keep #2025's docstrings ("fails the screen in esa_income_eligible" / "jsa_income_eligible"), so they stay identical to #2025 and #2013; the variables' documentation names the capital and remunerative work tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis
added a commit
that referenced
this pull request
Oct 2, 2026
MaxGhenis
added a commit
that referenced
this pull request
Oct 2, 2026
…t claim #2025's review round 4 found two things that apply to this ESA limb. - esa_income is stored as float32, but the award and plain total the gate recomputes are float64. With two reports of £65,536.01 and £65,536.00, the stored award (£131,072.00) is 0.0078 below the float64 total, so the formula's own award looked entered and barred the claim. The gate now casts both to the stored dtype before comparing. The new test fails on the previous gate. - Under the value rule, a directly entered award is read through the reports when it equals what they give, so another member's report can change how an entry is read. For example, £4,000 entered with no reports bars the claim; once an excluded adult reports £4,000, the claim is eligible. That is the declared convention. The variable documentation and the invariance bullet in the property docstring now say so, and a test pins the transition. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… boundary Review r4 of #2025: - jsa_income is stored as float32, while the report sum and the helper's award are float64. With large reports (£65,536.01 + £65,536.00) the formula's own award looked entered and barred the claim. Both references are now cast to the stored dtype before comparison. - Under the value convention, another member's report can change how a directly entered award is read. The variable documentation and the property module now state that boundary and the half-penny tolerance instead of claiming invariance for every input. test_income_support_direct_inputs.py pins the intended transitions: an excluded adult's report equal to a direct award, and a claimant's report that explains it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…gates' into is-remunerative-work-jsa-conditions # Conflicts: # policyengine_uk/tests/test_income_support_eligibility_properties.py # policyengine_uk/variables/gov/dwp/income_support_eligible.py
MaxGhenis
added a commit
that referenced
this pull request
Oct 2, 2026
Brings #2013's 3402629 and #2025's round-4 changes: the IS gate compares direct awards in the stored dtype, documents the value convention's boundary, and adds direct-input tests. Clean merge; the property file's docstring and the work-screen reference sit side by side. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
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.
Fixes #2024
Summary
income_support_eligibledid not model two of the SSCBA 1992 s.124(1) conditions:This PR adds both, for the claimant and partner only. It is stacked on #2013, which is stacked on #2001 and #1896, and it keeps #2013's structure: the claimant is whichever of the claimant and partner has the existing award (UC (TP) Regs 2014 reg 6A(1); C&P Regs 1987 reg 4(4)). Retarget to
mainonce those merge.Law and the rule
(c) Remunerative work.
(f) JSA.
Income-based JSA follows #2013's income-related ESA pattern. It is the award on the claimant's and partner's reported amounts, after the same capital screen as
jsa_income, through a newincome_related_jsa_awardhelper thatjsa_incomenow also uses. Ajsa_incomethat holds an award the reported amounts do not give is taken to be theirs. That means neither that award on everyone's reports nor their plain total, whichdisable_simulated_benefitssets. It covers an award entered directly (when the simulation is built, later, or on a branch) and a reform that removes or replacesjsa_income. The rule reads only the stored value, so no input-provenance tracking is involved. An entered award equal to what the reports give (to within half a penny, compared at the float32 precision the award is stored in) is read through the reports, which say whose it is.Changes
income_support_eligible: the two claimant limbs (no remunerative work at 16 hours, no contribution-based JSA) join Apply the Income Support conditions to the claimant and partner only #2013's per-personclaimantconjunction, along with the other member's remunerative work at 24 hours. Income-based JSA of either partner bars the claim next to income-related ESA.New parameters
gov.dwp.income_support.eligibility.remunerative_work.claimant_hoursandpartner_hours, with their history from legislation.gov.uk point-in-time texts of reg 5:New
income_support_remunerative_work_hours(Person):weekly_hours, a usual week's hours in paid jobs. The Enhanced FRShours_workedis FRSTOTHOURS(usual weekly hours across current jobs) × 52, andweekly_hoursdivides by 52. Enter it directly for fluctuating hours, which reg 5(2) and (3B) average over a cycle or recent weeks, and to leave out the reg 6(1) employments that reg 5(6) excludes from the count.jsa_income: the screen moves intoincome_related_jsa_award, unchanged. The JSAactivecheck is inside the helper, so every caller agrees withjsa_income.jsa_incomekeeps its own early return, so an inactive scheme still reads no reports. The parallel passport-scoping branch (Count only the claimant's and partner's legacy awards in means tests and passports #2027) carries a byte-identical copy.No new
Simulationmachinery. Review rounds 1-3 tried deciding direct entry from core's record of inputs (_user_input_keys), and that proved unsound in policyengine-core 3.32.9: core-built simulations, disk clones, default-named branches, ETERNITY periods, an input-free crash, and O(keys) deletes. Apply the Income Support conditions to the claimant and partner only #2013 and this PR replace it with the value rule above, for ESA and JSA alike; Count only the claimant's and partner's legacy awards in means tests and passports #2027 follows. The core bookkeeping bugs are _user_input_keys drifts from stored values after delete_arrays and clone policyengine-core#559, fixed upstream in Add total wealth #561.Which reg 5 and 6 rules the model applies
is_carer_for_benefits, the same proxy the gate uses for the para 4 categoryincome_support_remunerative_work_hoursdirectly for cycle or recent-period averagesInvariants
These are property-tested. Invariants 1 and 3 hold for every input except at the value convention's boundary. A direct award equal (to within half a penny, at the precision it is stored in) to what the reported amounts give is read through them, so another member's report, or the claimant's own, can change how a direct award is read. The property generators stay off that boundary, and example tests pin it with the intended results.
income_support_eligible, whatever that member's work or JSA. The existing Apply the Income Support conditions to the claimant and partner only #2013 property now also draws hours, JSA and a directly enteredjsa_income.income_support_eligibleequals an independently written family-by-family reading of the gate. The oracle intest_income_support_eligibility_properties.pynow reads (c) and (f), with the JSA tariff and capital limit from the parameters.jsa_incomeis unchanged by the helper refactor. On the Enhanced FRS,jsa_incomeand all 90 other saved arrays are identical in every year 2025-2030.set_inputat any time, deletion, clones and branches. This is covered by example tests, not a property:test_income_support_direct_inputs.py(11 tests): a lateset_input, aset_inputafter the gate was cached, a branch, a late zero overriding reports, an input for another year, a neutralisedjsa_income, the raw reported total, large reports compared at storage precision, and the two convention-boundary transitions (an excluded adult's report, or the claimant's own, explaining a direct award);test_entered_directly_lifecycle.py(16 tests): eight cases for both awards, with an excluded adult reporting the award, including an entered award equal to the reports (read through them, as intended).Tests
income_support_work_and_jsa.yaml, each hand-computed from the law. Full YAML suite at the head (da1a798): 1,537 passed.jsa_income.jsa_incomeentered for another year fails.test_income_support_esa_entered_directly.pypasses here too.test_legacy_benefit_parameters.pychecks both thresholds on either side of 7 April 1992 and 7 October 1996.policyengine_uk/testsexceptmicrosimulation/): 2,052 passed, 19 skipped at 48abd88; 2,036 at 6337f31; 2,024 at fcbec88. At the head (da1a798), the targeted files (properties, direct awards, lifecycle, ESA, parameters, carer premium, code health) pass: 1,740 tests. The value rule removed theSimulationoverrides 48abd88 had added, so the head touches no shared simulation code.Impact (Enhanced FRS 2024-25, real PolicyEngine runs)
Four package states, each run in its own environment on a private copy of the dataset: #2013's head (8d8673a), (c) only, (f) only, and this PR (fcbec88). After review, the current heads were re-run twice: #2013 at 06e186b against this PR at 6337f31, and #2013 at 97b7a1c against this PR at bfff081 (the value rule). Every year 2025-2030 changes by £0 at each step and in the re-run, with all 91 saved arrays identical. That covers Income Support (£0.51bn in 2025; the model pays it until 2025-26), income-related ESA and income-based JSA, Housing Benefit, CTR, Universal Credit, Pension Credit, household net income and poverty.
Why nothing moves:
The JSON summaries are aggregates. The dataset copies and per-record arrays stay private.
Axiom
axiom: TheAxiomFoundation/rulespec-uk#403 queued (addendum)
The addendum queues s.124(1)(c) and (f), IS Regs regs 5 and 6 and JSA 1995 s.1(4). It has outputs, a
review_findingand 24 companion tests: 22 match the YAML cases, and 2 cover the reg 5(4) trade-dispute precedence that PolicyEngine does not model. None of those citations is in the corpus yet. JSA Regs reg 116, which PolicyEngine's income-based JSA screen uses, is encoded-correct (uk/regulations/uksi/1996/207/116.yaml).Review
Round 1 (Subfleet, GPT-6.1 Sol): REQUEST CHANGES.
jsa_incomewas detected throughSimulation.input_variables. That missed late or branch inputs and leaked across years. Fixed withentered_directlyand regression tests, since superseded by the value rule (round 3). The same defect in Apply the Income Support conditions to the claimant and partner only #2013's ESA fallback was fixed there and merged here.review_finding, with companions 50-51.jsa_income's early return is restored.Round 2 (same reviewer): findings 2, 4, 5 and 6 fixed; 1 and 3 partly fixed, with two new defects found.
Simulation.delete_arrays.Simulation.clone, withentered_directlychecking the provenance of the stored value read; both were superseded by the value rule in round 3.Round 3 (same reviewer): REQUEST CHANGES.
Round 4 (same reviewer): REQUEST CHANGES. Round-3 findings 1, 2, 4 and 6 resolved, 5 moot; finding 3 (disk clones share files) is a core storage bug, now PolicyEngine/policyengine-core#558. All round-4 findings are addressed:
🤖 Generated with Claude Code