Skip to content

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_CASH or EXEMPT; they must not post to CASH_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).