Skip to content

feat: audit.py computes F1/F9/F10's insurable-income-side composition - #115

Merged
svedbg merged 1 commit into
mainfrom
feat/f1-f9-f10-insurable-composition
Sep 6, 2026
Merged

feat: audit.py computes F1/F9/F10's insurable-income-side composition#115
svedbg merged 1 commit into
mainfrom
feat/f1-f9-f10-insurable-composition

Conversation

@svedbg

@svedbg svedbg commented Sep 6, 2026

Copy link
Copy Markdown
Owner

Summary

Continuing point 1 of the trz-expert evaluation, one deliberately-bounded step past 2.18.0: the "solve the composition" method proverki.md describes for F1/F6/F10, ported faithfully from test/structural_test.py rather than reimplemented from the prose — that exact code needed several seed-specific bug fixes to get right even against the synthetic model with fixed column names.

Enumerates subsets of the contested elements (in-kind benefits, excess over the social-expense threshold) to find which one, plus the two statute-settled placements (sick pay always in, чл. 224 always out), explains the declared insurable income. Never settles which contested reading is correct — the file's own practice is inferred from ≥3 usable rows with a clear 2/3 majority; only rows disagreeing with that are findings.

Deliberately scoped to the insurable-income side only. F10_in_kind_asymmetry/F10_excess_asymmetry can also arise from the taxable-base side (needs the composition method plus every placement of the чл. 19 relief enumerated against it) — left as an explicit future increment, not attempted here given how bug-prone that exact combination was for the original authors.

Gated on zero unrecognised columns on the sheet (same false-positive risk that already limited K1/K3/K4/K7 in k_checker.py) — in practice requires a mapping.yaml declaring every administrative/breakdown column as ignore.

Verification

Comparing against generate_wide.py's manifest alone would have been misleading, since two of the five ids can legitimately arise from either side of the composition. So:

  • Three ids uniquely insurable-side (F1_insurable_unexplained, F1_compensation_in_insurable, F9_sick_pay_out_of_insurable) compared exactly against the manifest — 92/26/53 across 300 seeds, zero misses, zero false positives.
  • The two shared ids checked only for false positives against the manifest, then cross-validated directly against test/structural_test.py's own reference implementation (not just its pass/fail summary) across 300 seeds — zero mismatches once taxable-side occurrences were excluded, confirming every miss is the deferred piece, none an insurable-side bug.
  • Proved the test has teeth: broke the practice-majority threshold, watched 6 seeds fail, restored it.

🤖 Generated with Claude Code

https://claude.ai/code/session_01XvbzEbQwxwxxHAtXfPMrno

Continuing point 1 of the trz-expert evaluation, one deliberately-bounded step
further than 2.18.0: the "solve the composition" method proverki.md describes
for F1/F6/F10, ported faithfully from test/structural_test.py rather than
reimplemented from the prose description, because that exact code needed
several seed-specific bug fixes to get right even against the synthetic model
with fixed column names (the file's own comments name two of them).

What it does: enumerates subsets of the contested elements (доход в натура,
excess over the social-expense threshold) to find which one, together with
the two statute-settled placements (болнични always inside - чл. 3, ал. 1
НЕВДПОВ; чл. 224 always outside - чл. 1, ал. 8, т. 7 НЕВДПОВ), explains the
declared insurable income. Never settles which contested reading is correct:
the file's own practice is inferred from at least three usable rows with a
clear 2/3 majority, and only rows disagreeing with THAT practice are findings
(F10_in_kind_asymmetry, F10_excess_asymmetry). Where practice can't be
established, only the two statutory placements are still checked
(F1_compensation_in_insurable, F9_sick_pay_out_of_insurable) by enumerating
every placement of the contested elements instead of assuming one.

Deliberately scoped to the INSURABLE-income side only. F10_in_kind_asymmetry
and F10_excess_asymmetry can also arise from the taxable-base side, which
needs the same composition method plus every placement of the чл. 19, ал. 2
relief enumerated against it (F6/F7/F9's remaining piece) - left to the model
as an explicitly separate future increment, not attempted here.

Gated on the sheet having zero unrecognised columns at all: an unrecognised
accrual/benefit column would make a real composition silently unreachable,
the same false-positive risk that already limited K1/K3/K4/K7 in
k_checker.py. In practice this means a mapping.yaml that declares every
administrative/breakdown column as `ignore` - both SKILL.md and this file's
own docstring say so.

Verification method: comparing against test/generate_wide.py's manifest alone
would have been misleading, because F10_in_kind_asymmetry/excess_asymmetry
can legitimately arise from either side of the composition and the manifest
does not say which. So the three ids that are UNIQUELY insurable-side
(F1_insurable_unexplained, F1_compensation_in_insurable,
F9_sick_pay_out_of_insurable) are compared against the manifest exactly - 92,
26 and 53 out of 300 seeds, zero misses, zero false positives - while the two
shared ids are checked only for false positives against the manifest, and
separately cross-validated directly against test/structural_test.py's own
reference implementation (not just its pass/fail summary) across 300 seeds:
zero mismatches once its taxable-side occurrences were excluded, confirming
every one of this script's misses is the deferred taxable-side piece, none
of them an insurable-side bug.

Confirmed the test has teeth: broke the practice-majority threshold from 2/3
to effectively-unanimous and watched six seeds fail before restoring it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XvbzEbQwxwxxHAtXfPMrno
@svedbg
svedbg merged commit b88e025 into main Sep 6, 2026
12 checks passed
@svedbg
svedbg deleted the feat/f1-f9-f10-insurable-composition branch September 6, 2026 10:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant