Ruleset readiness¶
readiness is a three-tier classification on each CCNL ruleset that answers
one question: for what use context is this ruleset cleared?
It is separate from verification.confidence (which measures how verified
individual data values are) and from functional coverage (which capabilities
of the capability registry the engine
computes). A ruleset can have every capability it needs covered while
remaining exploratory because all values were extracted by an automated
tool and no human has checked them.
The three tiers¶
exploratory π§ͺ¶
The ruleset has been extracted and traced to a source, but no human has verified the key salary-table values against the primary document.
Safe for: demos, research, prototyping, internal tooling where figures are clearly labelled as unverified estimates.
Not safe for: any interface that shows a net salary to an end user as if it were authoritative; any decision that relies on the figure being correct.
reviewed π¶
At least the L1 values (base salary per level, seniority table, additional months, hourly divisor) have been cross-checked by a person against the primary CCNL document, and the source URL is recorded in the JSON.
The tier also requires verification.confidence = "verified" and no
assumed or missing payable rule in the CCNL file (salary tables,
allowances, seniority, extra months and their accrual, overtime, absence and
sickness rules, employer funds): a review cannot clear a value no source
backs.
Safe for: product simulations with an explicit disclaimer that names the verification scope and date; workforce-planning and offer-modelling tools.
Not safe for: operational flows that present figures without a disclaimer; any context where the user cannot see the readiness tier.
production π¶
Full review: all L1 and L2 values verified, at least one reference case from an independent source (official payslip or regulatory document, anonymised), a named owner assigned, and an entry in the update policy.
Safe for: operational flows where figures are shown to end users or used in decisions; integration into HR tools that do not add their own disclaimer.
Promotion criteria¶
exploratory β reviewed¶
A reviewer, a person or an AI model, must:
- Open the primary CCNL source document (URL recorded in
meta.sources). - Confirm every base salary amount for each level against the table in the document.
- Confirm the seniority table amounts and cadence.
- Confirm
additional_months,hourly_divisor, and any fixed allowances. - Append an entry to the review log, mark each checked value
verifiedwith thereview_idof that entry, and setverification.confidence = "verified". - Source every
assumedormissingpayable rule of the CCNL file: each must bederivedorverified(see Provenance). - Record the owner in
verification.ownerand the date the next review is due inverification.review_due, after the date of the last entry of the review log: areviewedCCNL is a candidate forproduction, so it is monitored from the start (see the Review plan). - Set
verification.readiness = "reviewed"in the CCNL JSON.
reviewed β production¶
In addition to the reviewed criteria:
- All L2 values (INPS sector, apprenticeship rules, TFR) must be verified against primary sources.
- At least one reference case must exist in
tests/knowledge/ccnl_engine/period/reference_case/sourced from a real payslip (anonymised) or an official regulatory example, not a synthetic scenario: averifiedcase (see Reference case verification status). The schema gate ofscripts/provenance/check.pyenforces it: aproductionCCNL without a valid reference case fails, and one without averifiedcase fails unlessscripts/provenance/reference_case/baseline.jsonlists it. That list holds the CCNLs promoted before the rule was enforced (15 October 2026), whose cases aresource_linked; it only shrinks, so no new promotion goes without an independent output.python scripts/provenance/check.py --indexprints the cases of each CCNL with its readiness, status and axes. - Its evidence must cover every complete output of the definition of done
for operational use (base salary, gross, employee contributions,
employer contributions, tax, net pay, TFR, employer cost) in the
Totalscolumn of the Validation matrix. Contributions are two outputs, not one: their bases and roundings can diverge on the two sides. A component (fixed allowances, a taxable base, a tax credit) or a rate (an INPS rate, the hourly percentages) is listed in its own column and never covers the total it belongs to. The schema gate fails aproductionCCNL that misses an outputscripts/provenance/readiness/baseline.jsondoes not list for it; that list holds what the CCNLs promoted before 15 October 2026 still miss, and only shrinks. - An owner must be recorded in
verification.owner, and the review in the review log. - An update-policy entry must exist: who monitors CCNL renewals, and within
what target window the ruleset is updated after a renewal. Record the
date the next review is due in
verification.review_due, after the date of the last entry of the review log. - Set
verification.readiness = "production"in the CCNL JSON.
Review log¶
verification.reviews lists the reviews of a CCNL file, oldest first. An
entry is appended for each review and never rewritten, so the file keeps its
whole history. A person and an AI model record a review with the same
fields:
| Field | Content |
|---|---|
id |
Identifier of the entry, unique in the file |
date |
Day of the review |
reviewer |
Role of the person (maintainer), or identifier of the model |
reviewer_kind |
human or ai |
scope |
What the review checked: the whole file, or which rules |
outcome |
confirmed, corrected, flagged (values left to re-check) or demoted |
sources |
URL and sha256 of each document the review read |
findings |
The differences the review found, or notes on its scope |
divergences |
Each difference from an independent output (a payslip, an official cost table), closed by a decision |
A divergence never stays open. Its decision is one of:
| Decision | Meaning | Required |
|---|---|---|
engine_bug |
The engine was wrong and is fixed | evidence names the regression test |
source_context_missing |
The output omits a fact the comparison needs | limitation names a limitation of the file that blocks the runs concerned |
accepted_external_variance |
The difference is explained and kept | review_by, the date it is looked at again |
external_artifact_error |
The output is incoherent for the case compared (another year, another scope) and is no evidence | evidence names the document read |
Each divergence also states its subject (both values) and cause. The
owner of the ruleset answers for it. A file whose divergence names a
limitation it does not declare does not load. An unexplained difference is
never evidence of correctness: until it is closed it is a finding of a
flagged review, not a match.
Each value the review checked is verified and points to the entry with
extraction.review_id. An AI review is cleared by the owner when the pull
request that records it is merged; the log does not repeat it. Each
contract page renders its log as a review history.
The INPS rates of a sector are verified against a table of the year when one
exists. Where none exists, the owner accepted on 2026-10-10 a reconstruction
by component from a table of the year of a sibling sector and the statutes of
the components that differ: the INPS rates of the industria in genere for
2026 are built from the 2026 table of the industria edile (Assimpredil ANCE)
and the CIGO and CIGS of D.Lgs. 148/2015 arts. 13 and 23.
The INPS rates of the artigianato for 2026 are built the same way from the
same table and the exemptions of L. 388/2000 art. 120 and L. 266/2005 art.
1 c. 361, but stay derived: the CUAF of the artigianato and the maternitΓ
and malattia of a non-construction craft firm have no primary source of the
year.
The INPS rates of the industria edile for 2026 are verified on the same
Assimpredil ANCE table. The terziario has no table of the year: the owner
accepted on 2026-10-13 the allegato of INPS circ. 117/2022, still in force,
as the source of its components, with the FIS and CIGS of D.Lgs. 148/2015
arts. 29 and 23 in force in 2026.
The schema gate (scripts/provenance/check.py --schema) rejects a
reviewed or production ruleset with an assumed or missing payable
rule in its file or without confidence verified, and a production
ruleset without the fields above. These errors have no baseline.
Current status¶
Distribution across the
132 bundled CCNL rulesets,
generated from the data by scripts/documentation/trust_count/generate.py (CI fails when
it drifts):
| Readiness | CCNL rulesets |
|---|---|
exploratory |
109 |
reviewed |
11 |
production |
12 |
The 11
reviewed rulesets: commercio-confcommercio, concia-unic, cooperative-sociali, funzioni-centrali-aran, funzioni-locali-aran, lavoro-domestico-convivente, lavoro-domestico-convivente-orario-ridotto, lavoro-domestico-non-convivente, logistica-trasporto-confetra, logistica-trasporto-confetra-viaggiante, sanita-aran.
Each contract page shows its own tier.
In October 2026 fifteen rulesets reviewed on a file-level review were
lowered to exploratory: each still read assumed or missing payable rules
and none recorded a verified confidence. Their review log keeps the
file-level review that promoted them; a ruleset returns to reviewed once its weak rules are sourced and its
confidence is verified, as the ones listed above did.
reviewed records a file-level review, not a per-value one. Of the reviewed
rulesets, 11
hold an entry in the review log, and
11
set verification.confidence = "verified" (step 5 of the criteria above).
A per-value review is recorded only by the provenance status verified of a
payable rule, and 1696
payable rules of the bundle have it (see
Provenance).
Readiness in the public API¶
Readiness is part of the public contract, before and after a run:
| Question | Field |
|---|---|
| Which contracts exist, and how far is each cleared? | engine.list_contracts(): ContractSummary.readiness |
| From which date does the bundle hold every rule of a CCNL? | ContractSummary.validity (first_day, last_day) |
| What exactly is the ruleset of one CCNL? | engine.inspect_ruleset(ccnl_id): RulesetAssurance (identity, source_hash, readiness, confidence) |
| Which rulesets did this result read? | result.rulesets, one RulesetAssurance each |
| Can the amounts of this computation be paid as computed? | result.is_payable and result.blockers |
ContractSummary.validity and RulesetIdentity.effective_from answer two
questions: the first is the span the bundled tables cover, the second the
date the agreement of the ruleset takes effect. They can differ (the
agreement of a renewal is signed before its first tranche is paid), so a
caller deciding whether a date can be computed reads validity
(catalog.get_ccnl(ccnl_id).validity for one CCNL). A competence year
leaves out the runs before the base salary of the level, and before its
seniority amount when the employment states a seniority, with a
run_not_computed blocker each.
Only CCNL rulesets carry a tier. Tax, INPS and surtax rulesets report
readiness = None (not tracked) and the verification_status of their
identity as confidence; their evidence is the provenance of each rule (see
Provenance).
RulesetAssurance.confidence_contradicts_readiness is True when a
reviewed or production tier is not backed by
verification.confidence = "verified" (step 5 of the criteria above). The
schema gate rejects such a tier in the bundle, so the flag is False for
every bundled ruleset. RulesetAssurance.is_production requires both the
production tier and a confidence that agrees.
Simulation and operational modes¶
PayrollEngine.bundled(mode=...) chooses how readiness acts on payability.
Both modes compute the same amounts.
| Mode | Readiness |
|---|---|
simulation (default) |
Reported in result.rulesets, not enforced. A result can be payable while its CCNL is exploratory: payability says every rule the run needed was known, sourced and applied, not that a person checked the values. |
operational |
Enforced: each ruleset that tracks a tier and is not is_production adds a ruleset_not_production blocker naming its id. A run whose CCNL has no ruleset identity fails closed. |
An operational engine returns the result with its blockers instead of
refusing before the calculation, so the amounts and every other blocker stay
inspectable. With 12
production rulesets, only those CCNLs are payable in operational mode: the
gate opens one CCNL at a time, as each is promoted.