Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
e0f8860
Track B G/R2: decide the open readings under the 10/20 delegation
MaxGhenis Oct 23, 2026
479c321
Readings pass round 2: apply the blind adjudications
MaxGhenis Oct 23, 2026
0cf5400
Review r1 fixes: tier counts, parent overview, 402(s)(2) wording, RIB…
MaxGhenis Oct 23, 2026
4f1f70a
Review r2 fix: state 402(s)(2)'s marriage condition exactly
MaxGhenis Oct 23, 2026
98c8b7e
Merge #563 round 10 (434a39c6) into the G/R2 readings branch
MaxGhenis Nov 2, 2026
1fa5686
Merge #563's head 03530e8b (master 89d064b5) and recount test tiers
MaxGhenis Nov 2, 2026
e75328f
Round-4 review fixes: whole-id marker checks and the G note's test claim
MaxGhenis Nov 2, 2026
0d186c7
Round-5 review fixes: every source-conflict mention parses, exemption…
MaxGhenis Nov 2, 2026
db268f9
Round-6 review fixes: any spelling, every package file, whole note ids
MaxGhenis Nov 2, 2026
079c33d
Count "Sources conflict" as a mention too
MaxGhenis Nov 2, 2026
5853c77
Round-7 review fixes: check reading ids by their own text
MaxGhenis Nov 2, 2026
dfde9e1
Round-8 review fixes: check note openings by their letters
MaxGhenis Nov 2, 2026
d636d76
Merge master edba88f7 (#563) into the G/R2 readings branch
MaxGhenis Nov 2, 2026
ec4ae31
Guard the readings test's reads to Track B paths
MaxGhenis Nov 6, 2026
5ed8adc
Hold the read guard on Python 3.10 to 3.13
MaxGhenis Nov 6, 2026
bbc6de6
Merge master 4ab97297 (#562) into the G/R2 readings branch
MaxGhenis Nov 6, 2026
410a932
Recount test tiers on master 4ab97297
MaxGhenis Nov 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/design/track_b_g_conformance_report.json
Original file line number Diff line number Diff line change
Expand Up @@ -750,7 +750,7 @@
"status": "refused"
},
{
"description": "Two potential parents; one own RIB 780 lies between 75% and 82.5% of PIA 1000",
"description": "Two potential parents; own RIBs 780 and 790 both lie between 75% and 82.5% of PIA 1000",
"id": "parent_benefit",
"reason": "parent_benefit",
"status": "refused"
Expand Down
404 changes: 306 additions & 98 deletions docs/design/track_b_g_gross_benefits.md

Large diffs are not rendered by default.

299 changes: 161 additions & 138 deletions docs/design/track_b_r2_ret_ledger.md

Large diffs are not rendered by default.

8 changes: 6 additions & 2 deletions scripts/track_b_g_conformance_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,7 @@ def multiple_records(child):
),
),
reasons.PARENT_BENEFIT: (
"Two potential parents; one own RIB 780 lies between 75% and 82.5% of PIA 1000",
"Two potential parents; own RIBs 780 and 790 both lie between 75% and 82.5% of PIA 1000",
lambda: _family(
_survivor(),
[
Expand All @@ -454,7 +454,11 @@ def multiple_records(child):
g.Role.PARENT,
own_benefit=g.OwnBenefit(rib, F(780)),
),
g.Beneficiary("p2", g.Role.PARENT),
g.Beneficiary(
"p2",
g.Role.PARENT,
own_benefit=g.OwnBenefit(rib, F(790)),
),
],
),
),
Expand Down
181 changes: 126 additions & 55 deletions src/populace_dynamics/track_b/gross_benefits.py
Original file line number Diff line number Diff line change
Expand Up @@ -1012,6 +1012,7 @@ def statutory_rates(params: SSAParameters) -> StatutoryRates:
_input_type(getattr(params, name), int, name)
if getattr(params, name) != 36:
raise InvalidFamilyInput(f"{name} must be 36 (402(q))")
# Source conflict us:oasdi-reduction-exact-fractions
return _construct_declared(
StatutoryRates,
worker_first=_STATUTE["worker_first"],
Expand Down Expand Up @@ -1118,6 +1119,7 @@ def disability_family_maximum(pia: object, aime: object) -> Fraction:
earnings = _exact(aime, "AIME")
if earnings < 0 or earnings.denominator != 1:
raise InvalidFamilyInput("AIME must be a nonnegative whole dollar")
# Source conflict us:oasdi-disability-family-maximum-rounding
return _floor_dime_validated(
min(max(_DI_AIME_SHARE * earnings, amount), _DI_PIA_CAP * amount)
)
Expand Down Expand Up @@ -3331,18 +3333,33 @@ class _Row:
counted: Fraction = Fraction(0)
mother_father_rate: Fraction = Fraction(0)
note: str = ""
dwb_under_60: bool = False

@property
def dual(self) -> bool:
return self.own_mba is not None


def _dwb_under_60(beneficiary: Beneficiary, payment_month: YearMonth) -> bool:
"""A DWB month in which the SSA birth cohort cannot yet have attained 60.

Cohort Y (born January 2, Y through January 1, Y+1) attains 60 during
Y+60, so every month of Y+59 and earlier is under 60. Months of Y+60
depend on the unsupplied birth month and are not treated as under 60.
"""
return (
beneficiary.role is Role.DISABLED_WIDOW
and beneficiary.birth_year is not None
and payment_month.year <= beneficiary.birth_year + 59
)


def _is_entitled(
beneficiary: Beneficiary,
pia: Fraction,
own_mba: Fraction | None,
*,
parent_ob: Fraction | None = None,
parent_threshold: Fraction | None = None,
) -> tuple[bool, str]:
own = beneficiary.own_benefit
if own is None:
Expand All @@ -3362,9 +3379,11 @@ def _is_entitled(
if (
beneficiary.role is Role.PARENT
and own.kind is OwnBenefitKind.OLD_AGE
and own_mba >= parent_ob
and own_mba >= parent_threshold
):
return False, "own RIB not less than parent's OB (RS 00209.001)"
return False, (
"own RIB not less than the 402(h)(1)(D) share of the PIA"
)
if (
beneficiary.role is Role.MOTHER_FATHER
and own.kind is OwnBenefitKind.OLD_AGE
Expand Down Expand Up @@ -3466,7 +3485,8 @@ def _parisi_counted(

The own-RIB reduction is not an auxiliary age reduction (GN
02603.060B.2: $2.40 payable + $0.90 reduction, not the $16 own-RIB
reduction). GN 02603.050A.2 disregards a dual rate reduced to zero.
reduction). GN 02603.050A.2 disregards a dual rate that is zero before
age reduction; a zero reached only after it counts the age reduction.
Own delayed credits and redistribution with an actually limiting
RIB-LIM remain refused: none of the captured worked cases settles
those interacting amounts. A considered but nonlimiting RIB-LIM
Expand Down Expand Up @@ -3509,17 +3529,14 @@ def _parisi_counted(
)
if payable == 0:
before_age = row.standard - (own.pia if method_c else row.own_mba)
# GN 02603.050A.2 disregards a rate that dual entitlement, considered
# first, reduces to zero (.045; .060 A.8). A zero reached only after
# the auxiliary's age reduction keeps that reduction in PTAP: only
# the amount withheld for dual entitlement in 402(k)(3)(A)'s order is
# redistributed (20 CFR 404.403(a)(5), 404.407(a); .060 B.2).
# Source conflict us:oasdi-dual-entitlement-zero-after-age-reduction
if before_age > 0:
raise _computed(
FamilyConfigurationUnsupported,
UnsupportedReason.PARISI_AMBIGUOUS,
"dual payable reaches zero only after auxiliary age reduction: "
"GN 02603.045's before-age rule and GN 02603.050A.2's zero-rate "
"exception do not settle whether the age amount stays in PTAP",
beneficiary_id=beneficiary.beneficiary_id,
)
return Fraction(0), Fraction(0)
if before_age <= 0:
return Fraction(0), Fraction(0)
if method_c:
excess = max(Fraction(0), row.standard - own.pia)
age_reduction = excess - _spouse_age_reduced_validated(
Expand Down Expand Up @@ -3563,6 +3580,12 @@ def _refuse_historical_auxiliary(
if isinstance(beneficiary.child_in_care, str):
return
elif role is Role.DISABLED_WIDOW:
# Source conflict us:oasdi-dwb-1984-pre-1978-history
# RS 00615.301B.1.e: "all disabled widow(er)s under age 60 receive
# .715 of the full unreduced WIB for 1/84 and later", whatever the
# entitlement date; .005C.2's money history governs only from 60.
if row.dwb_under_60:
return
first_age = 50
elif role in _AGED_WIDOW_ROLES:
first_age = 50
Expand All @@ -3582,6 +3605,7 @@ def _refuse_historical_auxiliary(
own = beneficiary.own_benefit
low, high = Fraction(0), row.rate
if role in (Role.SPOUSE, Role.DIVORCED_SPOUSE):
# Source conflict us:oasdi-dual-entitlement-pre-1978-history
if own is not None and beneficiary.own_benefit_first:
excess = max(Fraction(0), row.rate - own.pia)
high = max(Fraction(0), row.rate - (own.pia - row.own_base))
Expand Down Expand Up @@ -3837,16 +3861,44 @@ def _check_family_inputs(
return beneficiaries


def _parent_entitlement_thresholds(pia: Fraction) -> tuple[Fraction, Fraction]:
"""402(h)(1)(D): 82.5 and 75 percent of the PIA, unrounded."""
return pia * Fraction(165, 200), pia * Fraction(3, 4)


def _parent_threshold(
pia: Fraction, parents: tuple[int, frozenset[str]], beneficiary_id: str
) -> Fraction:
"""One parent's 402(h)(1)(D) own-RIB threshold in the resolved set.

``parents`` is ``_entitled_parent_count``'s (count, excluded ids). An
entitled parent is tested at its own rate; an excluded parent at the
two-parent rate it would share.
"""
parent_count, excluded = parents
one_rate, two_rate = _parent_entitlement_thresholds(pia)
if parent_count == 2 or beneficiary_id in excluded:
return two_rate
return one_rate


def _entitled_parent_count(
state: RecordState,
beneficiaries: Sequence[Beneficiary],
params: SSAParameters,
) -> int:
"""Resolve 402(h)(2)'s count, refusing the circular RIB threshold.

RS 00209.001 excludes a parent whose own RIB is not less than the
parent's benefit; RS 00209.015 counts an own-DIB parent as technically
entitled. More than two declared parents needs a separate rule.
) -> tuple[int, frozenset[str]]:
"""Resolve 402(h)(2)'s count and the parents (h)(1)(D) excludes.

402(h)(1)(D) tests an own RIB against 82.5 percent of the PIA when the
parent's benefit "is determinable under paragraph (2)(A)", and against
75 percent "in any other case". The entitled set must satisfy that test
for every parent at once: each entitled parent at its own rate, and
each excluded potential parent at the rate it would share. RS
00209.015 counts an own-DIB parent as technically entitled. The
thresholds are the unrounded percentages of the PIA that (h)(1)(D)
names, not the dime-floored OBs. Returns the count and the ids excluded
at the two-parent rate. More than two declared parents needs a
separate rule.
"""
parents = [b for b in beneficiaries if b.role is Role.PARENT]
if len(parents) > 2:
Expand All @@ -3856,12 +3908,7 @@ def _entitled_parent_count(
"more than two declared parents is outside the one/two-parent "
"rates settled by 402(h)(2) and RS 00209.015",
)
one_ob = _original_benefit_validated(
Role.PARENT, FamilyKind.SURVIVOR, state.pia
)
two_ob = _original_benefit_validated(
Role.PARENT, FamilyKind.SURVIVOR, state.pia, parent_count=2
)
one_rate, two_rate = _parent_entitlement_thresholds(state.pia)
potential = []
for parent in parents:
own = parent.own_benefit
Expand All @@ -3871,26 +3918,31 @@ def _entitled_parent_count(
else _own_monthly_benefit_validated(own, params)[1]
)
if own is not None and own.kind is OwnBenefitKind.OLD_AGE:
if own_mba >= one_ob:
if own_mba >= one_rate:
continue
potential.append((parent, own_mba))
if len(potential) == 2:
for parent, own_mba in potential:
# Source conflict us:oasdi-parent-entitlement-count-interval
if (
parent.own_benefit is not None
and parent.own_benefit.kind is OwnBenefitKind.OLD_AGE
and own_mba >= two_ob
):
raise _computed(
FamilyConfigurationUnsupported,
UnsupportedReason.PARENT_BENEFIT,
"two potential parents with own RIB between the "
"75% and 82.5% OBs have a circular entitlement count "
"under RS 00209.001 and .015",
beneficiary_id=parent.beneficiary_id,
)
return max(1, len(potential))
in_band = [
parent
for parent, own_mba in potential
if parent.own_benefit is not None
and parent.own_benefit.kind is OwnBenefitKind.OLD_AGE
and own_mba >= two_rate
]
if len(potential) < 2 or not in_band:
return max(1, len(potential)), frozenset()
# Source conflict us:oasdi-parent-entitlement-count-interval
# A RIB in [75%, 82.5%) fails beside an entitled parent and passes
# alone. With one such parent, only "the other parent alone" satisfies
# 402(h)(1)(D) for both; with two, either parent alone does.
if len(in_band) == 2:
raise _computed(
FamilyConfigurationUnsupported,
UnsupportedReason.PARENT_BENEFIT,
"two parents with own RIB between 75% and 82.5% of the PIA: "
"402(h)(1)(D) is satisfied by either parent alone",
beneficiary_id=in_band[0].beneficiary_id,
)
return 1, frozenset({in_band[0].beneficiary_id})


def _mother_father_care_rate(
Expand Down Expand Up @@ -4051,16 +4103,17 @@ def possible_drc_basis(member):
possible_count += 1
possible_widow |= possible_drc_basis(member)
continue
parent_count = (
parents = (
_entitled_parent_count(state, beneficiaries, params)
if member.role is Role.PARENT
else 1
else (1, frozenset())
)
row = _original_entitlement_rows(
state,
(_with_effective_cohort(member),),
params,
parent_count,
payment_month,
parents,
)[0]
subject = row.subject
except FamilyConfigurationUnsupported:
Expand All @@ -4072,11 +4125,15 @@ def possible_drc_basis(member):


def _original_entitlement_rows(
state, beneficiaries, params, parent_count=None
state, beneficiaries, params, payment_month, parents=None
):
"""G's OB and own-benefit entitlement, before any family allocation."""
if parent_count is None:
parent_count = _entitled_parent_count(state, beneficiaries, params)
"""G's OB and own-benefit entitlement, before any family allocation.

``parents`` is ``_entitled_parent_count``'s (count, excluded ids) for
the whole roster; an excluded parent is tested at the two-parent rate.
"""
if parents is None:
parents = _entitled_parent_count(state, beneficiaries, params)
rows = []
for beneficiary in beneficiaries:
own_base = own_mba = None
Expand All @@ -4090,11 +4147,16 @@ def _original_entitlement_rows(
state.pia,
beneficiary.original_benefit_basis,
parent_count=(
parent_count if beneficiary.role is Role.PARENT else None
parents[0] if beneficiary.role is Role.PARENT else None
),
)
entitled, note = _is_entitled(
beneficiary, state.pia, own_mba, parent_ob=ob
beneficiary,
state.pia,
own_mba,
parent_threshold=_parent_threshold(
state.pia, parents, beneficiary.beneficiary_id
),
)
rows.append(
_Row(
Expand All @@ -4105,6 +4167,7 @@ def _original_entitlement_rows(
own_base=own_base,
own_mba=own_mba,
note=note,
dwb_under_60=_dwb_under_60(beneficiary, payment_month),
)
)
return rows
Expand Down Expand Up @@ -4187,7 +4250,7 @@ def _family_benefits(
"IEDS before January 1985, or on a WEP-affected worker record "
"before January 2024, is not implemented (RS 00202.100)",
)
parent_count = _entitled_parent_count(state, beneficiaries, params)
parents = _entitled_parent_count(state, beneficiaries, params)
life_case = state.kind is not FamilyKind.SURVIVOR and not ieds
worker_benefit = None
if _declared_worker_entitled(state):
Expand All @@ -4199,7 +4262,11 @@ def _family_benefits(
worker_benefit = state.pia

rows = _original_entitlement_rows(
state, beneficiaries, params, parent_count
state,
beneficiaries,
params,
payment_month,
parents,
)

_refuse_widow_drc_savings_clause(state, rows)
Expand Down Expand Up @@ -4861,6 +4928,7 @@ def _readjusted_for_events(
),
Fraction(0),
)
# Source conflict us:oasdi-nh-charge-age-reduction-interaction
if reserve and any(row.age_reduction_factor != 1 for row in subject):
raise _computed(
FamilyConfigurationUnsupported,
Expand Down Expand Up @@ -5061,6 +5129,7 @@ def _readjust_deduction_rows(
standard=old.standard_rate,
rate=rate,
counted=rate,
dwb_under_60=_dwb_under_60(member, payment_month),
)
minimum = care_minimums.get(bid)
if minimum is not None:
Expand Down Expand Up @@ -5744,6 +5813,7 @@ def _savings_payment(
row for row in result.beneficiaries if row.subject_to_family_maximum
]
reduced = [row for row in subject if row.age_reduction_factor < 1]
# Source conflict us:oasdi-saving-clause-procedure-gaps
if (
result.kind is FamilyKind.SURVIVOR
or any(row.own_benefit is not None for row in subject)
Expand Down Expand Up @@ -6069,6 +6139,7 @@ def _operational_admit(
total: Fraction,
) -> FamilyBenefits:
membership = _savings_membership(result)
# Source conflict us:oasdi-saving-clause-procedure-gaps
if (
self._protected_membership is not None
and membership != self._protected_membership
Expand Down
Loading
Loading