Payroll glossary — decision record¶
Status: adopted
Date: 2026-09-22
Context: REVIEW.md §2.2, §7 Fase 0 — unambiguous terminology required
before the refactoring sequence (PR-02 through PR-13) to prevent divergence
between JSON, code, and documentation.
Terms¶
gross (lordo)¶
The sum of all monetary pay items for a period before any deduction. Includes base salary, seniority increments, allowances, overtime, night/holiday supplements, bonuses, and contractual renewal arrears. Does NOT include non-cash benefits (fringe, welfare) or employer-only costs.
period_gross = CASH_EARNINGS ledger total
cash (netto monetario in entrata)¶
Synonym for gross in the context of pay items that represent actual monetary outflows from the employer to the worker. Non-cash benefits (fringe, welfare) must never contribute to cash earnings even when they have a taxable component.
taxable (imponibile fiscale)¶
The base on which IRPEF and its surcharges (addizionali) are computed. Projected annually as: YTD taxable, plus the current run, plus the recurring gross of the withholding slots still to come, minus the employee INPS on them. On the last slot the projection is the final taxable income. It measures the annual deductions; the IRPEF of a run before the conguaglio is withheld on the taxable of its own pay period (see withholding schedule). Non-cash benefits may contribute to the taxable base when the exempt threshold is exceeded (see fringe benefit decision).
withheld (ritenuta)¶
The IRPEF amount actually deducted from the worker's net pay in a given
period. Distinct from liability: withheld is the cash collected by the
employer; liability is what is legally owed for the year.
withheld = ORDINARY_TAX ledger total for the period
liability (debito fiscale annuo stimato)¶
The estimated annual IRPEF owed, computed as:
irpef_gross_annual − work_income_deduction − family_deductions − credits.
This is an estimate: it may differ from the final tax settled at year-end
or at termination.
accrual (maturazione / competenza)¶
Recognition of a right or obligation in the period it is earned or incurred, regardless of when the cash is paid. TFR, extra months (tredicesima, quattordicesima), and leave accrue in each payroll period.
TFR_ACCRUAL ledger account
ExtraMonthAccrual pay item (to be introduced in PR-11)
settlement (liquidazione / pagamento / conguaglio)¶
The cash event that discharges an accrued obligation. TFR settlement occurs at termination; extra-month settlement occurs when the contract schedules payment (typically November/December for tredicesima). IRPEF conguaglio is the year-end or termination settlement of the difference between liability and withheld YTD.
TFR_SETTLEMENT ledger account
extra-month entitlement (mensilità equivalenti)¶
Equivalent months of pay granted per year: 12 regular months plus the
extra months, possibly fractional (13.5 means a full tredicesima and half a
quattordicesima). It says how much is paid, never how many payslips are
issued. Read from the CCNL parameters.additional_months.
ExtraMonthEntitlement, WorkCalendar.entitlement
payroll run count (numero di cedolini)¶
Number of payslips issued in the year: 12 regular runs plus one run per extra month, whatever its fraction. With 13.5 equivalent months the year has 14 runs.
PayrollRunCount, PayrollSchedule.run_count
withholding schedule (piano delle ritenute)¶
The IRPEF withholding slots of a tax year, one per payment actually made in it, whatever its competence (TUIR art. 51 c. 1). Before the last slot a payment withholds on its own pay period (art. 23 c. 2 DPR 600/1973), with the deductions measured on the annual projection; the payment that leaves no slot unpaid, read by identity from the payments closed, performs the conguaglio on the final taxable income (art. 23 c. 3). Surtax and somma esente are split per slot; the conguaglio settles the somma esente due and recovers what was paid in excess (L. 207/2024 art. 1 c. 7). Never derived from the entitlement.
WithholdingSchedule, WithholdingSlot, WithholdingPosition, TaxCashState.conguaglio
competence year and tax year (anno di competenza e periodo d'imposta)¶
A competence year generates the runs of its months and extra months; a tax year holds the payments made in it. December paid by 12 January belongs to the tax year of its competence (cassa allargata), paid later to the next one. INPS contributions follow competence (INPS circ. 237/2016).
CompetenceYearPlan, TaxYearPlan, PaymentId, InpsBaseYtd
calendar override (deroga al calendario)¶
A calendar that replaces the one derived from the CCNL, with a domain
reason and a note. PAYMENT_MONTH moves when an extra month is paid, its
12-month accrual window ending in the payment month, and keeps the
entitlement unchanged; MORE_FAVOURABLE_TREATMENT
records an agreement granting more than the CCNL (art. 2077 c.c.). No
reason allows dropping or lowering an extra month the CCNL grants.
CalendarOverride, CalendarOverrideReason, CompetenceYearResult.calendar
calculation status (stato del calcolo)¶
How far the calculation of a result can be relied upon, from least to most
severe: final, provisional, incomplete, rejected. It is the
calculation axis of the result assurance: the worst status among the issues
and decisions of a run (final when there are none), and for a year the
worst among its runs. An unknown normative input must never yield a final
result.
CalculationStatus, ResultAssurance.calculation
result assurance (affidabilità del risultato)¶
Whether the amounts of a result can be paid as they are. It combines the
calculation, coverage and evidence axes and the rulesets read, and lists the
blockers: issues, non-final decisions, missing facts, capabilities not
computed, rules assumed or missing in the bundle, rules supplied by the
caller, open model limitations with a monetary impact. A result is payable
only when no blocker applies.
ResultAssurance, ResultBlocker, BlockerCode, PeriodResult.is_payable,
CompetenceYearResult.is_payable
calculation issue (anomalia di calcolo)¶
A condition that lowers the calculation status of a result, identified by a stable
lower snake case code (for example regional_surtax_unknown), with a message,
the status it implies and, when one applies, its normative source.
CalculationIssue, PeriodResult.issues
calculation decision (decisione di calcolo)¶
What one capability actually decided in a run: its status, a stable
reason_code, the normalized inputs it used, the rule and rule version
applied, the normative source and the resulting amount (None when unknown).
A capability that ran and found nothing due still decides: amount 0 and a
reason such as income_above_upper_threshold. The capability trace is
built from the decisions.
CalculationDecision, PeriodResult.decisions, CompetenceYearResult.decisions
capability trace (traccia di esecuzione)¶
The state of each registry capability in one run, derived from what executed and
never from the request: computed, partial, unresolved, skipped or not
applicable. A feature decided by a final decision is computed, by a
provisional one partial, by an incomplete or rejected one unresolved;
an event feature is computed only when an event handler posted a non-zero
amount or took a decision. The capability report lists the applicable
capabilities of the registry whose trace falls short: unsupported,
unresolved, a partial result or a partial implementation that executed.
DecisionTrace, TraceState, CapabilityReport, CapabilityGapKind
worker category decision (decisione sulla categoria)¶
The calculation decision recording the worker category used for pay and
contributions and its origin: declared on the employment, or
fixed_by_level when the level admits a single category. No decision is
taken when no category applies.
CalculationDecision, WorkerCategory
tax credit decision (decisione sulle detrazioni)¶
The calculation decision of the ulteriore detrazione
(ulteriore_detrazione_lavoro) or of the trattamento integrativo
(trattamento_integrativo): the annual entitlement and the reason code of
the rule branch that produced it, e.g. full_amount, tapered_amount,
deductions_not_above_irpef. Taken on every run whose tax year rules put
the credit in force.
CalculationDecision, CreditOutcome
reddito complessivo (current-year income)¶
The income of the tax year the art. 12 TUIR family deductions are computed
on: the employment income the run projects for the year plus
CurrentYearTaxFacts.external_income (other employers and other income,
less the main dwelling, c. 4-bis). Without CurrentYearTaxFacts of the tax
year it is unknown, never zero: the family_deductions decision is
required_fact_missing when a dependent gives right to a deduction. See
Family deductions.
surtax decision (decisione sulle addizionali)¶
The CalculationDecision of the regional or municipal surtax
(addizionale_regionale, addizionale_comunale) of the tax year. It separates a surtax not yet determined
(determined_at_conguaglio: final, amount 0, any run before the
conguaglio), a surtax not due by rule (no_irpef_due,
below_exemption_threshold: final, amount 0), a table applied
(table_applied: final; prior_year_rates_applied,
dependent_provisions_not_applied and specific_exemptions_not_applied:
provisional) and a
well-formed code without a
table row (table_unknown: incomplete, amount None, issue
regional_surtax_unknown or municipal_surtax_unknown). A withholding
run that leaves regione or comune_belfiore unset records
residence_unknown (incomplete, amount None, inputs["fact"] naming the
fact): the surtax is undetermined, never not applicable. The region is the
ISO 3166-2:IT code (IT-45), with IT-BZ / IT-TN for the autonomous
provinces. A malformed code is invalid input, not an unknown table.
CalculationDecision, REGION_CODES, PeriodCalculationRequest.regione,
PeriodCalculationRequest.comune_belfiore
fringe benefit decision (decisione sul fringe benefit)¶
The CalculationDecision (fringe_benefit) of one FringeEvent. The
annual threshold is 1,000 EUR, 2,000 EUR when a child of
PeriodFacts.family_composition is within the own-income limit of art. 12
c. 2 TUIR, for tax years 2025 to 2027 (L. 207/2024 art. 1 cc. 390-391, derogating TUIR art. 51 c. 3). The
threshold is all or nothing: once the year total exceeds it, the whole
amount of the year is taxable for IRPEF and INPS, not only the excess (AdE
circ. 4/E of 16 May 2025, par. 2.7). Reasons: within_threshold (amount
0), above_threshold (this benefit is taxable) and
above_threshold_retroactive (the benefit that crosses the threshold also
taxes the earlier exempt amounts of the year). Inputs: threshold_annual,
dependent_children (true, false or unknown), ytd_before, ytd_total, taxed_before,
retroactive_amount; the amount is the taxable amount of the benefit. The
FringeBenefitItem carries the same threshold_annual, ytd_total and
taxable_amount.
CalculationDecision, FringeEvent, FringeBenefitItem, FringeYtd
preferential tax regime (regime di imposta sostitutiva)¶
A statutory flat tax that replaces IRPEF and its surtaxes on the pay items it covers, for the tax years it is in force, within an optional annual cap, and only for workers meeting its requirements: prior-year employment income not above a ceiling, employment sector, employer activity, signing date of the agreement, no written renunciation. Parameters and normative source are data in the tax bundle; the worker facts are declared on the input.
PreferentialTaxRegime, PriorYearTaxFacts, EmploymentSector, EmployerActivity
regime cap account (plafond annuo del regime agevolato)¶
The year-to-date part of a regime's annual cap already taxed at the substitute rate. For the night, holiday and shift supplement regime (L. 199/2025 art. 1 cc. 10-11, cap 1,500 EUR) it lives in the tax year state and carries over between runs of the tax year; each supplement only gets the substitute rate on what is left, the excess is ordinary income. It restarts with the next tax year.
RegimeCapAccount, PeriodState.cash.work_time_regime
tax cash state (progressivi di cassa dell'anno fiscale)¶
Payments, withholding counter and slots, year-to-date accounts of one tax year (earnings, fringe, tax withheld, trattamento integrativo, somma esente, regime cap account) and the obligations carried into it. A tax year counts the payments made in it, whatever their competence, with no maximum (TUIR art. 51 c. 1). Every total is non-negative. The payments and accounts restart at zero when the next tax year opens.
TaxCashState, PeriodState.cash
accrual state (competenze maturate del rapporto)¶
The competence runs closed over the employment: the months and extra months of each competence year already paid, whatever tax year paid them. A run closes once, so a competence year has at most twelve regular months. Carried unchanged across the year change.
EmploymentAccrualState, PeriodState.accrual
payroll run id (identificativo del cedolino)¶
Year, month and kind of a payroll run, written "2026-12-thirteenth". The
runs of a competence year close once each and in payment order; an
adjustment run is not ordered, nor are runs of different competence years.
PayrollRunId, PayrollRun.identifier, EmploymentAccrualState.competence_runs
payment id (identificativo del pagamento)¶
A run and the day it is paid, written "2026-12-regular@2027-01-13". The
payment date selects the tax year; a payment closes once, so a retry is
never counted twice.
PaymentId, TaxCashState.payments
credit account (conto del credito d'imposta)¶
Year-to-date account of a tax credit paid on the payslip that can be paid in excess: recognized, recovered, updated due and reason of the last decision, with the residual still to recover. Used for the trattamento integrativo and the somma esente; the recovery plan lives in the employment obligations. Not used for a regime cap, which limits usage and is never recovered.
CreditAccount, TrattamentoAccount, SommaEsenteAccount
employment obligations (obbligazioni del rapporto)¶
What a run owes or is owed beyond the tax year that created it, carried from run to run until settled. Today: installment recoveries of trattamento integrativo (D.L. 3/2020 art. 1 c. 3) and of somma esente (L. 207/2024 art. 1 c. 7), each bound to the credit and the tax year whose conguaglio opened it, and the surtax a conguaglio determined (regional surtax and municipal saldo of the year, municipal acconto of the next), withheld by installments in the next year (D.Lgs. 446/1997 art. 50 c. 4, D.Lgs. 360/1998 art. 1 c. 5). Installments posted in a later year do not enter the credit account of that year.
EmploymentObligations, RecoveryObligation, SurtaxObligation,
TaxCashState.obligations
year close (chiusura dell'anno fiscale)¶
The transition from the state after the last run of year N to the opening state of N+1: fresh tax cash state, obligations and accrual state carried. Rejected when a withholding slot of N is still open.
close_tax_year, PayrollEngine.close_tax_year
opening balances (progressivi di subentro)¶
Year-to-date totals and running recoveries computed by a previous payroll provider, validated and turned into the state of the first run the engine computes.
OpeningBalances
regime eligibility (spettanza del regime agevolato)¶
The outcome of checking a pay item against a preferential regime:
eligible (substitute rate on the eligible amount, ordinary on any excess
over the cap), ineligible (ordinary) or unknown when a required fact is
missing (ordinary, and a provisional issue). A definite ineligibility wins
over a missing fact. Recorded as a calculation decision with a stable
reason_code, e.g. prior_income_above_ceiling.
RegimeEligibility, assess_regime
Reconciliation invariants¶
These checks run after every period calculation (reconcile() in
payroll/assurance/validators.py). A violation is an engine error:
calculate_period raises DataIntegrityError listing each one as
[code] message. Caller inputs that cannot produce a payslip are rejected
before, with InvalidInputError (for example a field of the wrong type, a
regular run outside the employment, absences above the pay of the run) or
OutOfScopeError (absences that leave less pay than the withholdings due).
The code is stable and is the invariant_id of the violation.
| Code | Checks |
|---|---|
pay_item_posted |
every pay item has at least one ledger entry |
earning_contribution_exclusive |
no pay item posts to both CASH_EARNINGS and EMPLOYEE_CONTRIBUTIONS |
net_identity |
CASH_EARNINGS + CREDITS + TAX_REFUNDS + SURTAX_REFUNDS + CREDIT_RECOVERY_SHORTFALL + TFR_SETTLEMENT - CREDIT_RECOVERIES - EMPLOYEE_CONTRIBUTIONS - BILATERAL_FUND_EMPLOYEE - PENSION_FUND_EMPLOYEE - EMPLOYEE_DEDUCTIONS - SUBSTITUTE_TAX - ORDINARY_TAX - SURTAX - SEPARATE_TAX = period_net |
employer_cost_identity |
CASH_EARNINGS - EMPLOYEE_DEDUCTIONS + NON_CASH_BENEFITS + EMPLOYER_CONTRIBUTIONS + BILATERAL_FUND_EMPLOYER + TFR_ACCRUAL + PENSION_FUND_EMPLOYER + PENSION_FUND_TFR + TFR_TREASURY_FUND = period_employer_cost |
gross_identity |
CASH_EARNINGS = period_gross |
ledger_entry_unique |
ledger entry ids of a run are unique |
irpef_withheld_continuity |
closing IRPEF withheld YTD = opening + ORDINARY_TAX - TAX_REFUNDS |
gross_non_negative |
period_gross >= 0 |
employee_deduction_non_negative |
every EMPLOYEE_DEDUCTIONS entry >= 0 |
substitute_tax_non_negative, ordinary_tax_non_negative |
every SUBSTITUTE_TAX and ORDINARY_TAX entry >= 0; refunds use TAX_REFUNDS |
employee_contribution_non_negative, employer_contribution_non_negative |
every EMPLOYEE_CONTRIBUTIONS and EMPLOYER_CONTRIBUTIONS entry >= 0; corrections are a distinct movement |
credit_non_negative |
every CREDITS, CREDIT_RECOVERIES, CREDIT_RECOVERY_SHORTFALL, TAX_REFUNDS and SURTAX_REFUNDS entry >= 0: a credit taken back is a recovery |
net_pay_non_negative |
period_net >= 0 |
run_counters_advance |
the run enters the competence runs and its payment the payments, once each; the withholding counter advances by one when the run takes a slot |
ytd_continuity |
closing = opening + run amount for gross (CASH_EARNINGS), employee INPS (EMPLOYEE_CONTRIBUTIONS), surtax (SURTAX less SURTAX_REFUNDS) and the net trattamento integrativo and somma esente credits (their CREDITS entries less their CREDIT_RECOVERIES entries) |
credit_recovery_bounds |
each credit account recovers between zero and what it recognized |
carried_recovery_advance |
each recovery carried from an earlier tax year posts its next installment and advances one step, or posts its whole residual on the last run of the employment |
substitute_tax_plafond |
the work-time regime cap account advances by the eligible amounts, stays within the annual cap and agrees with the cap_available of each decision; the PdR eligible YTD advances by the bonus_pdr decision and stays within the PdR limit |
substitute_tax_eligibility |
SUBSTITUTE_TAX posted = substitute tax of the regime and PdR decisions; a decision that is not eligible taxes nothing at the substitute rate |
decision_provenance |
every final decision names a rule and a rule version |
run_within_employment |
a regular run is for a month with at least one day of employment |
extra_month_accrual_limit |
the ratei a run pays for one extra month and window add up to at most 12 months |
contribution_ceiling |
when the IVS massimale applies, the IVS base of the run is within max(0, massimale - opening INPS base YTD) |
irpef_annual_reconciliation |
on the run closing the last withholding slot, IRPEF withheld YTD = net annual IRPEF of the tax computation (gross IRPEF less deductions, floored at zero), within one cent, and the taxable income of that computation = final taxable income YTD, within two cents of rounding |
remittance_code_consistent |
every ORDINARY_TAX, SEPARATE_TAX and CREDITS entry carries a codice tributo, and no entry carries a code its account does not admit |
Not checked: the INPS base and IRPEF taxable YTD (not derivable from the
result without recomputing the run), that the ordinary remainder of a
substitute-tax item reaches the IRPEF base, and the extra-month ratei paid
by earlier runs (no state records them; a run after the termination is
caught by run_within_employment).
Directory names¶
A directory holding Python modules under src/ccnl_engine, tests,
scripts or demo takes one of these names; a file takes the name of its
technical role (docs/engine/architecture.md). A name is added here before
a directory uses it.
Concepts (roots of src/ccnl_engine): absence, agreement, amount,
apprenticeship, assurance, balance, bundle, calendar, capability, catalog,
collection, comparison, compensation, contribution, decision,
default, employer, employment, end_of_service, event,
extra_month, family, fund, irpef, knowledge, ledger,
limitation, pay_item, pension_fund, period, provenance,
reconciliation, regime, run, sector, seniority, severance, sickness,
surtax, tax_credit, termination, variable_pay, withholding,
working_time, year.
Subdomains: account, additional_ivs, agent, allocation,
amount, applicability, arrears, ascendant, assistance,
attribution, base, benefit, calendar, cap, cash, category,
ceiling, child, closing, competence, computation, conguaglio,
context, contractual, conversion, coverage, cumulation, day,
declaration, deduction, deferral, domestic, element,
eligibility, enam, enrolment, entitlement, extraction, fact,
fis, fixed_term, foreign, headcount, hourly, indemnity, input,
integration, issue, jurisdiction, ladder, lifecycle, line,
liquidation, metadata, minimum, minimum_base, month, naspi,
net, obligation, opening, other_employment, other_income,
override, overtime, pay, payslip, persistence, payment, plan, posting, proration,
provider, provincial_element, provision, public, qualification,
raccordo, rate, raw, recovery, registry, relief, remittance,
renewal_minimum, request, requirement, residence, result,
revaluation, rounding, rule, rule_source, ruleset, schedule,
sector, selection, separate, sequence, settlement, sign,
solidarity, somma_esente, source, spell, spouse, stage,
standard, step, support, table, tax, tax_year, taxable,
term, total, trace, transition, trattamento_integrativo,
treatment, ulteriore_detrazione, validity, zone.
Operations (scripts): capability_matrix, contract_example,
contract_page, coverage_matrix, distribution, documentation,
evidence, fiscal, label, manifest, mutation, provenance,
quality, smoke, trust_count.
Anti-patterns¶
- gross includes fringe/welfare: fringe benefits and welfare are classified
as
NON_CASHorEXEMPT; they must not post toCASH_EARNINGS. - withheld == liability: withholding is a period instalment; it diverges from annual liability whenever YTD state changes (conguaglio).
- annual ÷ 12 = period: period calculations must be autonomous, not divisions of an annual figure.
- max(0, liability − withheld): the clamp prevents modelling refunds; conguaglio may be negative (a credit to the worker).