From 6e1640f84f83dfa68fbd1d8db6b10630708732fd Mon Sep 17 00:00:00 2001 From: Ali Romman <226877337+aliromman@users.noreply.github.com> Date: Mon, 26 Oct 2026 09:43:00 -0500 Subject: [PATCH] Explain signed invoice comparisons with concrete tariff witnesses --- docs/research/recursive-invoice-preflight.md | 17 +++++ scripts/explain_recursive_invoices.py | 61 +++++++++++++++++ tests/test_recursive_invoice_witnesses.py | 71 ++++++++++++++++++++ 3 files changed, 149 insertions(+) create mode 100644 scripts/explain_recursive_invoices.py create mode 100644 tests/test_recursive_invoice_witnesses.py diff --git a/docs/research/recursive-invoice-preflight.md b/docs/research/recursive-invoice-preflight.md index d55f6c136c..0de37a4dc1 100644 --- a/docs/research/recursive-invoice-preflight.md +++ b/docs/research/recursive-invoice-preflight.md @@ -91,6 +91,23 @@ python3 -B scripts/compare_recursive_invoices.py \ The second is a declared single-H4 edit to the complete source invoice, illustrating the unfiltered retiming's algebra; it is not a newly emitted physical supplier. +## Inspect a tariff witness + +To show exact old and new costs for the strongest positive and negative hinges: + +```sh +python3 -B scripts/explain_recursive_invoices.py OLD.json NEW.json +``` + +Each witness gives a cap `k` and the tariff `min(r,k)`. The report debits target +credits and binds both input files by SHA256. No witness is emitted for zero cost +change. The comparator and its source bytes remain unchanged. + +For old paid jobs `{"2":2}` and new paid jobs `{"1":1,"4":1}`, cap 2 gives +costs 4 and 3; cap 4 gives costs 4 and 5. Thus neither invoice wins for every +concave tariff. This does not imply a power crossing: their power-cost difference +is `(2^t-1)^2`, which is positive for every `0 0}, {3: 2}) + report = explain.explain_invoices(old, new) + for key, witness in report['concave_tariff_witnesses'].items(): + cap = witness['cap'] + expected = sum(d * min(r, cap) for r, d in enumerate(delta, 1)) + self.assertEqual(witness['new_minus_old'], expected) + self.assertTrue(expected < 0 if key == 'negative_change' else expected > 0) + self.assertEqual(len(report['concave_tariff_witnesses']), + 0 if not any(delta) else 2 if report['classification'] == 'inconclusive' else 1) + + def test_surrendered_target_is_debited(self): + report = explain.explain_invoices(invoice({1: 1, 8: 1}, {9: 1}), invoice()) + witness = report['concave_tariff_witnesses']['negative_change'] + self.assertEqual(witness['old_paid_minus_targets'], 1) + self.assertEqual(witness['new_paid_minus_targets'], 0) + + def test_cli_binds_inputs_under_isolated_optimized_python(self): + with tempfile.TemporaryDirectory() as tmp: + paths = [Path(tmp) / name for name in ('old.json', 'new.json')] + for path, value in zip(paths, (invoice({2: 2}), invoice({1: 1, 4: 1}))): + path.write_text(json.dumps(value)) + result = subprocess.run([sys.executable, '-I', '-O', '-B', str(ROOT / 'scripts/explain_recursive_invoices.py'), + *map(str, paths)], text=True, capture_output=True, check=True) + report = json.loads(result.stdout) + self.assertEqual(report['inputs']['old']['sha256'], hashlib.sha256(paths[0].read_bytes()).hexdigest()) + self.assertEqual(len(report['concave_tariff_witnesses']), 2) + + def test_mismatched_contract_is_not_explained(self): + old, new = invoice(), invoice(); new['contract']['boundary'] = 'different' + with self.assertRaisesRegex(ValueError, 'contracts differ'): + explain.explain_invoices(old, new) + + +if __name__ == '__main__': + unittest.main()