feat: deterministic cClassTrib resolver + gated CCLASSTRIB auto-apply (default OFF), RTC panel summary; 1.1.9

- resolver (rules RTC-R0..R4/A1..A3/G1..G2) over the official cClassTrib table 2026-06-22 and LC 214/2025 annexes; local vs official catalog comparison
- ONE root-cause RTC blocker per product (missing/unresolved/ambiguous/conflict/official mismatch/catalog outdated/evidence missing)
- auto-apply: C000025.CCLASSTRIB only, three switches (FIREBIRD_WRITES + RTC_AUTO_APPLY_ENABLED + Hub authorization), per-product re-read and re-decision, never overwrites, rowcount 1, audit table rtc_write_audits (migration 0027)
- copy-only write E2E (280/280 applied, only CCLASSTRIB changed, 2nd run 0 writes, stale decision 0 writes); real databases untouched
- docs: cclasstrib_resolution, rtc_auto_apply, unified_fiscal_completeness

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
gti
2026-09-24 21:18:34 -03:00
co-authored by Claude Sonnet 5
parent 88f4318072
commit 9f08998800
51 changed files with 16461 additions and 47 deletions
+4 -4
View File
@@ -69,14 +69,14 @@ def test_rtc_off_in_the_erp_is_out_of_scope_and_never_blocks():
def test_rtc_on_in_the_erp_brings_cclasstrib_into_the_same_findings():
out = uf.assess_from_connection(FakeConn(param=1), {"crt": "1"}, today=date(2026, 9, 24))
assert out["context"]["rtc_enabled"] is True
assert kinds(out["findings"]["1"]) == ["CCLASSTRIB_MISSING"] and kinds(out["findings"]["2"]) == []
assert kinds(out["findings"]["3"]) == ["CCLASSTRIB_MISSING"] # one queue, one verdict per product
assert kinds(out["findings"]["1"]) == ["CCLASSTRIB_MISSING_UNRESOLVED"] and kinds(out["findings"]["2"]) == []
assert kinds(out["findings"]["3"]) == ["CCLASSTRIB_MISSING_UNRESOLVED"] # one queue, one verdict per product
def test_simulation_flag_never_touches_the_erp_parameter():
conn = FakeConn(param=0)
on = uf.assess_from_connection(conn, {"crt": "1"}, rtc_override=True)
assert on["context"]["rtc_enabled"] is True and kinds(on["findings"]["1"]) == ["CCLASSTRIB_MISSING"]
assert on["context"]["rtc_enabled"] is True and kinds(on["findings"]["1"]) == ["CCLASSTRIB_MISSING_UNRESOLVED"]
assert on["context"]["rtc_param"] == "0" and on["context"]["rtc_source"] == "SIMULATION" and not any("UPDATE" in s.upper() for s in conn.cur.statements)
@@ -124,7 +124,7 @@ def test_toggle_between_syncs_is_followed_in_both_directions_without_any_cache()
assert first["context"]["rtc_enabled"] is False and not [b for f in first["findings"].values() for b in f["blockers"] if b["category"] == "RTC"]
conn.cur.param = 1 # the operator switches the reform on in the ERP between two syncs
second = uf.assess_from_connection(conn, {"crt": "1"})
assert second["context"]["rtc_enabled"] is True and kinds(second["findings"]["1"]) == ["CCLASSTRIB_MISSING"]
assert second["context"]["rtc_enabled"] is True and kinds(second["findings"]["1"]) == ["CCLASSTRIB_MISSING_UNRESOLVED"]
assert second["findings"]["1"]["input_fingerprint"] != first["findings"]["1"]["input_fingerprint"] # a new blocker fingerprint: the old (RTC off) state is not reused
conn.cur.param = 0 # and off again
third = uf.assess_from_connection(conn, {"crt": "1"})