{"data":{"kind":"file","path":"README.md","version_id":"cf55tbigqhnmw9petsw2il22","entry":{"name":"README.md","path":"README.md","is_directory":false,"size":16103,"modified_at":"2026-11-07T20:43:12.586000","content_hash":"b8a9a0d2f22d8a4a665ae7f2732a1b57b7326e53519dd74e1795cace24035648"},"entries":[],"content":"# succession-fr — French inheritance and gift tax (droits de mutation à titre gratuit)\n\nSingle-turn, French-language tasks: compute the inheritance tax (droits de succession) or\ngift tax (droits de donation) owed by every beneficiary of a fictitious French estate or\ngift, from the rules of the Code général des impôts (amounts in force in 2026) **written in\nthe prompt**. Verified exactly to the euro, no LLM judge.\n\n## What it trains\n\nThe everyday arithmetic of a French notary's tax desk:\n- net estate (assets − debts − funeral costs capped at €1,500);\n- specific bequests taken first, residue split by written shares;\n- personal allowances by relationship (child €100,000, grandchild €1,594 in an estate /\n  €31,865 in a gift, sibling €15,932, nephew/niece €7,967, unrelated €1,594 in an estate),\n  disability allowance €159,325 stacked on top; surviving spouse / PACS partner exempt;\n- progressive scales (direct line 5 % → 45 %, siblings 35 %/45 %, nephews 55 %,\n  unrelated 60 %), applied band by band without rounding each band;\n- 15-year recall of prior gifts (allowance already used, lower bands already used:\n  `tax = scale(T + taxable) − scale(T)`), with an exact-day boundary rule;\n- family cash gift exemption (art. 790 G: €31,865 per 15 years, donor under 80, donee\n  18 or older, never recalled);\n- representation of a predeceased child (grandchildren share the €100,000 allowance);\n- split ownership (art. 669: bare-ownership value by the usufructuary's age), in gifts with\n  reserved usufruct and in estates where the spouse takes the usufruct of the residue.\n\nTypical failure modes the reward punishes: taxing the exempt spouse, forgetting the €1,500\ncap on funeral costs, restarting the scale at 0 after a recalled gift, recalling a gift\nmade exactly 15 years earlier, applying 790 G to an 80-year-old donor or a 17-year-old\ndonee, taxing full ownership instead of bare ownership, rounding each band.\n\n## Tasks and difficulty\n\n400 tasks by default (100 per level), generated deterministically from a seed.\n\n| Level | Content | Variants (default set) |\n|---|---|---|\n| 1 | One beneficiary, a child. Gift of 1-2 assets in full ownership, or estate of a widowed/divorced parent with an only child. Allowance €100,000, direct-line scale. | estate 49, gift 51 |\n| 2 | Estate with 3-7 beneficiaries: spouse or PACS partner (exempt, ¼ share), children, grandchild legatee, siblings, nephews/nieces, unrelated legatee, disabled heir; specific cash bequests then written shares of the residue. | spouse + children 36, children + legatees 32, siblings + legatees 32 |\n| 3 | Level 2 + 15-year recall of prior gifts, family cash gifts (790 G), representation of a predeceased child; gifts from parents/grandparents to children and grandchildren (with age conditions) or estates. Every gift task contains a cash gift whose 790 G exemption changes the answer (or, for a few donors aged 80+, wrongly applying it would); every estate task has a recall, a representation or a non-recalled 790 G gift that changes the answer. | gift with 790 G 73, estate with recall 27 |\n| 4 | Split ownership (art. 669) **combined with several level-3 rules in the same task**: bare-ownership gift to 2-3 children/grandchildren with cash gifts (790 G that changes the answer, minors and reduced ceilings possible) and a recalled prior gift that changes the answer (sometimes above the allowance, so lower bands are already used); or estate where the spouse takes the usufruct of the residue, with at least one specific bequest (grandchild, sibling, nephew/niece or friend), a recall that changes the answer, and a representation or a non-recalled 790 G gift that also changes it; disabled heirs more frequent. | bare-ownership gift 70, spouse usufruct estate 30 |\n\nEach prompt lists the dossier (dates, assets, debts, funeral invoice, bequests and shares,\nor donated assets with their attribution), a beneficiary table (ID, name, relationship,\nbirth date, disability), prior gifts from the same person (levels 3-4), then the numbered\nrules of its level and the answer format. Prompts are 3.4k (level 1) to 9.2k (level 4)\ncharacters; 1 to 9 beneficiaries (mean 4.6 at level 2, 4.0 at level 4). In the default set\n151 of 1,207 beneficiary lines owe no tax (exempt spouse, share below the allowance); every task has at\nleast one beneficiary who owes tax.\n\n**No \"zero for everyone but one\" shortcut.** A dossier is re-drawn when (a) it has two or\nmore taxable (non-exempt) beneficiaries but fewer than two of them owe tax, or (b) it is an\nestate with shares of the residue where no residue heir has a taxable share and tax > 0,\nor where the residue heirs' values do not change when the net estate grows by 10 %\n(`generateur.sans_raccourci`). Without (b), about 10 % of level-2 estates were fully\nsolved by \"0 for the residue heirs, compute only the specific bequest\" without ever\ncomputing the net estate; without (a), keeping the exact values of a single beneficiary\nand 0 for the others scored 1.0 on about 15 % of multi-beneficiary tasks. Both are now\n0 % (tests `test_zero_sauf_un_beneficiaire_jamais_juste`,\n`test_faille1_aucune_tache_resolue_par_les_legs_seuls`).\n\nEvery level-3 and level-4 task makes its level's rules matter: a dossier is re-drawn\nunless ignoring a rule of its level changes the expected answer (`generateur.niveau_utile`,\ncounterfactual recomputation). At random (outside the first 6 mix tasks), gifts are drawn\ntwice (level 3) or 2.5 times (level 4) as often as estates, so that 790 G matters in most\ntasks of these levels. Share of tasks **still fully right when one rule is ignored**,\nmeasured with an independent recomputation from the prompt text only (default set, then\ntwo 300-task single-level sets per level, seeds 201-204):\n\n| Rule ignored | Level 3 | Level 4 |\n|---|---|---|\n| 790 G exemption ignored (cash taxed as ordinary assets) | 33 % / 37 % / 38 % | 36 % / 35 % / 33 % |\n| 790 G ignored entirely (also recalling prior 790 G gifts) | 15 % / 19 % / 15 % | 13 % / 10 % / 12 % |\n| 15-year recall ignored | 20 % / 15 % / 20 % | 0 % / 0 % / 0 % |\n| lower bands already used ignored (`scale(taxable)` instead of `scale(T + taxable) − scale(T)`) | 59 % / 50 % / 50 % | 30 % / 29 % / 28 % |\n| representation ignored (grandchild allowance €1,594) | 91 % / 81 % / 80 % | 75 % / 80 % / 81 % |\n| split ownership (art. 669) ignored | — | 0 % / 0 % / 0 % |\n| no level rule changes the answer | 0 % | 0 % |\n\nRepresentation only exists in estates (about a quarter of level 3, 30 % of level 4), hence\nthe high \"still right\" share when it is ignored; where it is present, it is checked.\nApplying 790 G despite the age conditions stays right on 87-90 % of tasks (the age traps are\ndeliberately a minority).\n\n**Mix order.** Levels follow the cycle **1, 4, 2, 3** (task `i` has level\n`(1, 4, 2, 3)[i % 4]`, id `succession-<level>-<i>`), except the first 8 tasks, whose levels\nare 1, 4, 2, 3, **3**, 4, 2, **1** (tasks 4 and 7 swapped, so there are still 100 tasks per\nlevel). The first 6 tasks (what a `-n 6` calibration run sees) have a fixed variant:\n\n| Task | Level | Variant (seed 0) |\n|---|---|---|\n| `succession-1-0` | 1 | only-child estate (net estate, funeral cap, scale) |\n| `succession-4-1` | 4 | estate with spouse usufruct, bequests, recall, representation or non-recalled 790 G gift (8 beneficiaries) |\n| `succession-2-2` | 2 | estate with exempt spouse or PACS partner and bequests |\n| `succession-3-3` | 3 | gift with cash where the 790 G exemption changes the answer |\n| `succession-3-4` | 3 | estate with recall and a forced representation of a predeceased child |\n| `succession-4-5` | 4 | bare-ownership gift to 2-3 donees with 790 G and recall |\n\n### Rules written in every prompt (they prevail)\n\n1. Rounding: everything is computed exactly; only two roundings, to the nearest euro\n   (€0.50 rounds up): each beneficiary's taxable share (computed in one go), then each\n   beneficiary's tax (sum of the bands without rounding each band, on the rounded taxable\n   share). Total = sum of the rounded taxes. Two fictitious worked examples are given.\n2. Value received: net estate and residue (estates) or value × attributed fraction (gifts),\n   × bare-ownership percentage at level 4.\n3. Age in completed years (levels 3-4 where it matters), with an example.\n4. Art. 669 table (level 4): ≤ 20 years 90 % usufruct … ≥ 91 years 10 %.\n5. Allowances of the transfer type (estate or gift), disability allowance, spouse/PACS\n   exemption.\n6. Family cash gift 790 G (gifts, levels 3-4).\n7. 15-year recall (levels 3-4): with S = recalled gifts, A = total allowance:\n   `U = min(A, S)`, remaining allowance `A − U`, already taxed `T = S − U`,\n   taxable share = value − 790 G exemption − remaining allowance (floored at 0),\n   tax = `scale(T + taxable) − scale(T)`; a gift dated exactly 15 years before the act is\n   not recalled (example given). Fictitious worked example included.\n8. Scales of art. 777 (direct line; siblings, nephews and unrelated persons in estates).\n\n### Simplifications versus real law (stated in the prompt or here)\n\n- Current allowances and scales are applied to recalled gifts (real law uses the allowance\n  in force when each gift was made).\n- Civil devolution is given, never computed (no forced heirship, no civil hotchpot).\n- Specific bequests are taken from the net estate; no 5 % furniture flat rate; no\n  life insurance; siblings never meet the art. 796-0 ter exemption; nephews/nieces always\n  inherit in their own right; 790 G only for children and grandchildren.\n- The family-charge reduction of former art. 780 is **not** used: it was repealed by the\n  2017 finance law.\n- No usufructuary aged exactly 91 (the legal text's bound is imprecise); all dates have a\n  day ≤ 28; no birthday on the act date.\n\n## Data\n\nFully synthetic: names, towns' assets and amounts are generated (fictitious persons, no\npersonal data). Rules and amounts come from public official sources (see below). Generation\nis deterministic (`random.Random(seed)`) and exact (`fractions.Fraction`); dossiers where no\ntax is due, where the level's rules do not matter, where a \"zero for everyone but one\"\nanswer would be right (see above), or where an expected amount appears verbatim in the\nprompt are re-drawn.\n\n## Verifier\n\n`succession_fr/scoring.py` (pure functions, no `verifiers` import). The reply must end with\n**one** `<droits>…</droits>` block containing one JSON object:\n\n```json\n{\"beneficiaires\": {\"B1\": {\"part_taxable\": 0, \"droits\": 0},\n                   \"B2\": {\"part_taxable\": 149270, \"droits\": 28048}},\n \"total_droits\": 28048}\n```\n\n- Exactly the beneficiaries of the prompt (missing or invented ID → 0), exactly the keys\n  `part_taxable` and `droits` per beneficiary, exactly `beneficiaires` and `total_droits`\n  at the root; duplicate keys at any depth → 0.\n- Amounts: JSON numbers (or a string with one amount such as `\"41 169 €\"`), at most two\n  decimals; compared exactly with the expected whole euros (`41169.00` is accepted,\n  `41169.35` is wrong). Booleans, null, lists, NaN/Infinity, |x| > 10^9, exponents out of\n  range, JSON integers longer than 12 digits → 0.\n- Zero or several `<droits>` opening tags, reply longer than 200,000 characters, invalid\n  JSON → 0. All regexes are linear-time; opening tags are counted before the block regex;\n  any exception while reading the reply → 0 (safety net). `validate()` uses\n  `score_reply_strict` (no safety net) so a broken gold answer fails loudly; expected\n  values must be non-negative whole euros.\n- **Score.** All values right → 1.0. Otherwise partial credit capped at **0.45**: 0 if any\n  field whose expected value is 0 (exempt spouse, share covered by the allowance) gets a\n  non-zero value; else 0.45 × (weights of the right fields among the fields whose expected\n  value is non-zero) / (weights of those fields), weights `part_taxable` 0.4 and `droits`\n  0.6 per beneficiary. Right zeros alone earn nothing; the total has no weight of its own\n  (a right total with wrong components earns nothing). Option\n  `task.tout_ou_rien = true`: 0 unless everything is right.\n\nTests (`tests/`, 212 tests, no model call): 5 dossiers recomputed by hand line by line\n(only-child estate; gift with 790 G and recall; bare-ownership gift with recall using the\nlower bands; spouse-usufruct estate with representation and a bequest; siblings with a\n€0.50 rounding and a disabled heir), unit tests of scales/ages/boundaries, gold = 1.0 on\nevery generated task, attacks (empty, copied prompt, copied format example, several blocks,\nseveral JSON objects, NaN, giant exponents, mass tags, huge reply, extra/missing keys,\ninvented beneficiary, injection), 0.45 cap fuzzing, timing of degenerate replies, no\nexpected amount in any prompt, determinism and a SHA-256 fingerprint of the 400 default\ntasks, an independent recomputation from the prompt text only (1,000 tasks, 0 differences),\nand checks that every level-3/4 task makes a rule of its level change the answer.\n\n## Running\n\n```bash\nuv pip install -e environments/succession-fr\nuv run pytest environments/succession-fr/tests\nuv run vf-validate succession-fr -n 10 --runtime.type subprocess   # gold 1.0, noop 0\nuv run vf-run succession-fr -m <model> -n 6 -r 1 -c 1 \\\n  --env.agent.harness.id null --env.agent.runtime.type subprocess \\\n  --client.base-url https://openrouter.ai/api/v1 --client.api-key-var OPENROUTER_API_KEY \\\n  -o outputs/succession-fr\n```\n\nConfig (`--env.taskset.*` for `vf-run`, `--taskset.*` for `vf-validate`): `nb_taches`\n(default 400), `graine` (default 0), `difficulte` (0 = mix, or 1, 2, 3, 4),\n`task.tout_ou_rien` (default false). Single level: `--env.taskset.difficulte 4`.\n\n## Calibration\n\n**Preliminary (one attempt per task, 6 mix tasks, previous version of the generator).**\nFree OpenRouter models, success = reward ≥ 0.99:\n\n| Model | Success | Mean reward |\n|---|---|---|\n| liquid/lfm-2.5-2.6b (small) | 0/6 | 0.00 |\n| nvidia/nemotron-3-nano-omni-30b-a3b-reasoning (medium) | 2/6 | 0.44 |\n| nvidia/nemotron-3-ultra-550b-a55b (large) | 6/6 | 1.00 |\n\nThe ordering small < medium < large holds and failures come from real tax errors (scale\nbands, art. 669 table), not from the answer format. Because the large model solved every\ntask and two rules (790 G, representation) were absent from those 6 tasks, the generator\nwas then revised: every level-3/4 task now makes a rule of its level change the answer,\nlevel 4 combines several rules per task, and the 6 calibration tasks now include a\nrepresentation case and a 790 G case that matters.\n\nProbe on the **current version** (large model only, 6 tasks × 1 attempt):\nnvidia/nemotron-3-ultra-550b-a55b solved 6/6.\n\n**Known limitation:** all rules are stated in the prompt and the answer is a single JSON\nblock, so the strongest model tested solves these tasks reliably. The environment\nseparates small and mid-size models well, but offers little headroom for frontier models.\nThese figures come from very small samples (6 tasks, 1 attempt) and are only indicative.\n\n## Sources and licences\n\n- Code général des impôts on Légifrance,\n  https://www.legifrance.gouv.fr/codes/texte_lc/LEGITEXT000006069577/ — articles 669, 775,\n  777, 779, 784, 788, 790 B, 790 G, 796-0 bis, 796-0 ter. Official legislative texts, not\n  subject to copyright.\n- service-public.gouv.fr (Licence Ouverte / Etalab 2.0):\n  [F14198 inheritance tax](https://www.service-public.gouv.fr/particuliers/vosdroits/F14198)\n  (checked by DILA on 9 February 2026),\n  [F14203 gift tax by relationship](https://www.service-public.gouv.fr/particuliers/vosdroits/F14203)\n  (checked on 13 May 2026).\n- BOFiP BOI-ENR-DMTG-10-40-10-50 (art. 669 usufruct table),\n  https://bofip.impots.gouv.fr/bofip/2323-PGP (Licence Ouverte / Etalab 2.0).\n- Repeal of the former art. 780 reduction: finance law for 2017 (law 2016-1917, art. 32).\n- Notes (French) with the rules extracted: `sources/succession-fr-regles.md` in the\n  factory repository. No text is copied; rules are reformulated.\n\nCode: MIT licence (`LICENSE`).\n\n## Contact\n\nveltris.buisness@gmail.com\n","encoding":"utf-8","truncated":false,"total_bytes":16103},"status":null}