diff --git a/research/t16-invoice-boundary-audit/EXPECTED.json b/research/t16-invoice-boundary-audit/EXPECTED.json new file mode 100644 index 0000000000..6cc1f47956 --- /dev/null +++ b/research/t16-invoice-boundary-audit/EXPECTED.json @@ -0,0 +1,1729 @@ +{ + "status": "PASS_T16_INVOICE_BOUNDARY_AUDIT", + "member_sha256": { + "code/invoice_allcold.py": "71eb57514e28ced97251e0507105f654f59885ec4d40486a780bf166098858a8", + "code/assemble.py": "15f6986a476bac76bcdc0bfcf51da115389b46f1950d2766b6822f757888b13a", + "code/audit_allcold.py": "1467a2acb654e62552c69fb9a7c4c85f70a02120881d222313865058ab71a6cc", + "code/witness.py": "779c5172894b992131e85be1e592ed2a1aec8c287b872ff42007d36a7291e444", + "code/generated_identity.py": "c8af22719c0f3097a991a3f6ccac8f090afd2faba554745733d9ea88f2c25708", + "verify_t16.py": "050e2dfba59911b8f29fd94422833d421367a0ad01c5e4ae916a75a235ee5e46" + }, + "positive": { + "invoice_all_fields_equal": true, + "assembly_all_proof_fields_equal": true, + "assembly_only_normalized_field": "input_sha256.fresh_invoice", + "controller_equal_except_mutation_run_fields": true, + "kappa": "836330098538459/500000000000000000", + "prefix_bits": 397, + "physical_row_coefficient": 16469 + }, + "summary": { + "cases": 54, + "invoice": { + "REJECTED": 28, + "ACCEPTED": 26 + }, + "assembly": { + "ACCEPTED": 10, + "REJECTED": 16 + } + }, + "finite_implications": { + "hypotheses": "Integer S>=1, 0<=M<73*S, 0<=L<2**6050, 2*bit_length(S)+11185<20161", + "stock_bit_limit": 4487, + "strict_upper_bound_powers_of_two": { + "router": 15049, + "literal": 38976, + "mass": 100001, + "precision": 200014, + "tape": 100003 + } + }, + "cases": [ + { + "name": "owner status false", + "changed_inputs": [ + "owner" + ], + "links_rebound": true, + "invoice": { + "result": "REJECTED", + "exception": "AssertionError", + "source": "invoice_allcold.py", + "line": 176, + "statement": "assert owners['status']=='PASS_INDEPENDENT_ASYNC_OWNERS_AND_PROFILE'", + "message": "" + } + }, + { + "name": "controller status false", + "changed_inputs": [ + "controller" + ], + "links_rebound": true, + "invoice": { + "result": "ACCEPTED", + "changed_keys": [ + "owner_audit_sha256", + "controller_audit_sha256" + ], + "pervertex_bits": 53, + "prefix_bits": 397, + "finite": { + "physical_stock_bits": 2642, + "router_bits": 7988, + "literal_bits": 35284, + "physical_row_coefficient": 16469, + "retained_row_coefficient": 20161, + "required_C0_bits": 200012, + "halving_integer_inequality": [ + 5329, + 4608 + ], + "G_exponent": 30000, + "E_exponent": 100000, + "C0_exponent": 210000 + }, + "pervertex": 6466906000439144 + }, + "assembly": { + "result": "ACCEPTED", + "kappa": "836330098538459/500000000000000000" + } + }, + { + "name": "controller complete calls understated", + "changed_inputs": [ + "controller" + ], + "links_rebound": true, + "invoice": { + "result": "REJECTED", + "exception": "AssertionError", + "source": "invoice_allcold.py", + "line": 200, + "statement": "assert call_count==stages*replicas==control['complete_invocations']", + "message": "" + } + }, + { + "name": "controller unique owner flag false", + "changed_inputs": [ + "controller" + ], + "links_rebound": true, + "invoice": { + "result": "REJECTED", + "exception": "AssertionError", + "source": "invoice_allcold.py", + "line": 201, + "statement": "assert control['one_owner_per_complete_invocation']", + "message": "" + } + }, + { + "name": "controller mutations flag false", + "changed_inputs": [ + "controller" + ], + "links_rebound": true, + "invoice": { + "result": "ACCEPTED", + "changed_keys": [ + "owner_audit_sha256", + "controller_audit_sha256" + ], + "pervertex_bits": 53, + "prefix_bits": 397, + "finite": { + "physical_stock_bits": 2642, + "router_bits": 7988, + "literal_bits": 35284, + "physical_row_coefficient": 16469, + "retained_row_coefficient": 20161, + "required_C0_bits": 200012, + "halving_integer_inequality": [ + 5329, + 4608 + ], + "G_exponent": 30000, + "E_exponent": 100000, + "C0_exponent": 210000 + }, + "pervertex": 6466906000439144 + }, + "assembly": { + "result": "ACCEPTED", + "kappa": "836330098538459/500000000000000000" + }, + "isolated_driver_predicate": { + "result": "REJECTED", + "exception": "AssertionError", + "source": "verify_t16.py", + "line": 103, + "statement": "assert audit['mutation_controls_run'] and len(audit['mutations_rejected']) == 15", + "message": "" + } + }, + { + "name": "controller mutation list empty", + "changed_inputs": [ + "controller" + ], + "links_rebound": true, + "invoice": { + "result": "ACCEPTED", + "changed_keys": [ + "owner_audit_sha256", + "controller_audit_sha256" + ], + "pervertex_bits": 53, + "prefix_bits": 397, + "finite": { + "physical_stock_bits": 2642, + "router_bits": 7988, + "literal_bits": 35284, + "physical_row_coefficient": 16469, + "retained_row_coefficient": 20161, + "required_C0_bits": 200012, + "halving_integer_inequality": [ + 5329, + 4608 + ], + "G_exponent": 30000, + "E_exponent": 100000, + "C0_exponent": 210000 + }, + "pervertex": 6466906000439144 + }, + "assembly": { + "result": "ACCEPTED", + "kappa": "836330098538459/500000000000000000" + }, + "isolated_driver_predicate": { + "result": "REJECTED", + "exception": "AssertionError", + "source": "verify_t16.py", + "line": 103, + "statement": "assert audit['mutation_controls_run'] and len(audit['mutations_rejected']) == 15", + "message": "" + } + }, + { + "name": "controller rank mass inconsistent", + "changed_inputs": [ + "controller" + ], + "links_rebound": true, + "invoice": { + "result": "ACCEPTED", + "changed_keys": [ + "owner_audit_sha256", + "controller_audit_sha256" + ], + "pervertex_bits": 53, + "prefix_bits": 397, + "finite": { + "physical_stock_bits": 2642, + "router_bits": 7988, + "literal_bits": 35284, + "physical_row_coefficient": 16469, + "retained_row_coefficient": 20161, + "required_C0_bits": 200012, + "halving_integer_inequality": [ + 5329, + 4608 + ], + "G_exponent": 30000, + "E_exponent": 100000, + "C0_exponent": 210000 + }, + "pervertex": 6466906000439144 + }, + "assembly": { + "result": "ACCEPTED", + "kappa": "836330098538459/500000000000000000" + } + }, + { + "name": "owner rank mass inconsistent", + "changed_inputs": [ + "owner" + ], + "links_rebound": true, + "invoice": { + "result": "REJECTED", + "exception": "AssertionError", + "source": "invoice_allcold.py", + "line": 253, + "statement": "assert m*live-mass==owners['deficit']==5120", + "message": "" + } + }, + { + "name": "owner deficit inconsistent", + "changed_inputs": [ + "owner" + ], + "links_rebound": true, + "invoice": { + "result": "REJECTED", + "exception": "AssertionError", + "source": "invoice_allcold.py", + "line": 253, + "statement": "assert m*live-mass==owners['deficit']==5120", + "message": "" + } + }, + { + "name": "owner live inconsistent", + "changed_inputs": [ + "owner" + ], + "links_rebound": true, + "invoice": { + "result": "REJECTED", + "exception": "AssertionError", + "source": "invoice_allcold.py", + "line": 256, + "statement": "assert live==owners['live'] and physical==owners['physical']", + "message": "" + } + }, + { + "name": "owner physical inconsistent", + "changed_inputs": [ + "owner" + ], + "links_rebound": true, + "invoice": { + "result": "REJECTED", + "exception": "AssertionError", + "source": "invoice_allcold.py", + "line": 256, + "statement": "assert live==owners['live'] and physical==owners['physical']", + "message": "" + } + }, + { + "name": "owner distinct owner flag false", + "changed_inputs": [ + "owner" + ], + "links_rebound": true, + "invoice": { + "result": "ACCEPTED", + "changed_keys": [ + "owner_audit_sha256" + ], + "pervertex_bits": 53, + "prefix_bits": 397, + "finite": { + "physical_stock_bits": 2642, + "router_bits": 7988, + "literal_bits": 35284, + "physical_row_coefficient": 16469, + "retained_row_coefficient": 20161, + "required_C0_bits": 200012, + "halving_integer_inequality": [ + 5329, + 4608 + ], + "G_exponent": 30000, + "E_exponent": 100000, + "C0_exponent": 210000 + }, + "pervertex": 6466906000439144 + }, + "assembly": { + "result": "REJECTED", + "exception": "AssertionError", + "source": "assemble.py", + "line": 63, + "statement": "assert owner['all_live_owners_per_call_distinct'] is True", + "message": "" + } + }, + { + "name": "owner chart count understated", + "changed_inputs": [ + "owner" + ], + "links_rebound": true, + "invoice": { + "result": "ACCEPTED", + "changed_keys": [ + "owner_audit_sha256" + ], + "pervertex_bits": 53, + "prefix_bits": 397, + "finite": { + "physical_stock_bits": 2642, + "router_bits": 7988, + "literal_bits": 35284, + "physical_row_coefficient": 16469, + "retained_row_coefficient": 20161, + "required_C0_bits": 200012, + "halving_integer_inequality": [ + 5329, + 4608 + ], + "G_exponent": 30000, + "E_exponent": 100000, + "C0_exponent": 210000 + }, + "pervertex": 6466906000439144 + }, + "assembly": { + "result": "REJECTED", + "exception": "AssertionError", + "source": "assemble.py", + "line": 66, + "statement": "assert owner['owners_per_call']==2*112+R and owner['actual_helper_owner_charts']==owner['hosted_residuals']==144*R==pin('expected.hosted_residuals',owner['hosted_residuals'])", + "message": "" + } + }, + { + "name": "owner idle remainder count understated", + "changed_inputs": [ + "owner" + ], + "links_rebound": true, + "invoice": { + "result": "ACCEPTED", + "changed_keys": [ + "owner_audit_sha256" + ], + "pervertex_bits": 53, + "prefix_bits": 397, + "finite": { + "physical_stock_bits": 2642, + "router_bits": 7988, + "literal_bits": 35284, + "physical_row_coefficient": 16469, + "retained_row_coefficient": 20161, + "required_C0_bits": 200012, + "halving_integer_inequality": [ + 5329, + 4608 + ], + "G_exponent": 30000, + "E_exponent": 100000, + "C0_exponent": 210000 + }, + "pervertex": 6466906000439144 + }, + "assembly": { + "result": "REJECTED", + "exception": "AssertionError", + "source": "witness.py", + "line": 50, + "statement": "assert got==want,'SPEC MISMATCH %s: expected %s got %s'%(key,json.dumps(want)[:400],json.dumps(got,default=str)[:400])", + "message": "SPEC MISMATCH expected.idle_remainders: expected 7526 got 7525" + } + }, + { + "name": "owner idle source count understated", + "changed_inputs": [ + "owner" + ], + "links_rebound": true, + "invoice": { + "result": "ACCEPTED", + "changed_keys": [ + "owner_audit_sha256" + ], + "pervertex_bits": 53, + "prefix_bits": 397, + "finite": { + "physical_stock_bits": 2642, + "router_bits": 7988, + "literal_bits": 35284, + "physical_row_coefficient": 16469, + "retained_row_coefficient": 20161, + "required_C0_bits": 200012, + "halving_integer_inequality": [ + 5329, + 4608 + ], + "G_exponent": 30000, + "E_exponent": 100000, + "C0_exponent": 210000 + }, + "pervertex": 6466906000439144 + }, + "assembly": { + "result": "REJECTED", + "exception": "AssertionError", + "source": "assemble.py", + "line": 143, + "statement": "assert owner['source_idle_children_charged']==parent_idle", + "message": "" + } + }, + { + "name": "owner idle count exceeds source", + "changed_inputs": [ + "owner" + ], + "links_rebound": true, + "invoice": { + "result": "REJECTED", + "exception": "AssertionError", + "source": "invoice_allcold.py", + "line": 259, + "statement": "assert owners['explicit_idle_remainder_children']<=owners['source_idle_children_charged']", + "message": "" + } + }, + { + "name": "owner controller hash stale", + "changed_inputs": [ + "owner" + ], + "links_rebound": false, + "invoice": { + "result": "ACCEPTED", + "changed_keys": [ + "owner_audit_sha256" + ], + "pervertex_bits": 53, + "prefix_bits": 397, + "finite": { + "physical_stock_bits": 2642, + "router_bits": 7988, + "literal_bits": 35284, + "physical_row_coefficient": 16469, + "retained_row_coefficient": 20161, + "required_C0_bits": 200012, + "halving_integer_inequality": [ + 5329, + 4608 + ], + "G_exponent": 30000, + "E_exponent": 100000, + "C0_exponent": 210000 + }, + "pervertex": 6466906000439144 + }, + "assembly": { + "result": "REJECTED", + "exception": "AssertionError", + "source": "assemble.py", + "line": 75, + "statement": "assert invoice['controller_audit_sha256']==owner['controller_audit_sha256']", + "message": "" + } + }, + { + "name": "controller template hash stale", + "changed_inputs": [ + "controller" + ], + "links_rebound": false, + "invoice": { + "result": "REJECTED", + "exception": "AssertionError", + "source": "invoice_allcold.py", + "line": 175, + "statement": "assert template_hash==control['complex_template_sha256']==owners['template_sha256']==summary['template_sha256']", + "message": "" + } + }, + { + "name": "owner template hash stale", + "changed_inputs": [ + "owner" + ], + "links_rebound": false, + "invoice": { + "result": "REJECTED", + "exception": "AssertionError", + "source": "invoice_allcold.py", + "line": 175, + "statement": "assert template_hash==control['complex_template_sha256']==owners['template_sha256']==summary['template_sha256']", + "message": "" + } + }, + { + "name": "summary template hash stale", + "changed_inputs": [ + "summary" + ], + "links_rebound": false, + "invoice": { + "result": "REJECTED", + "exception": "AssertionError", + "source": "invoice_allcold.py", + "line": 175, + "statement": "assert template_hash==control['complex_template_sha256']==owners['template_sha256']==summary['template_sha256']", + "message": "" + } + }, + { + "name": "template physical reserve understated", + "changed_inputs": [ + "template" + ], + "links_rebound": true, + "invoice": { + "result": "REJECTED", + "exception": "AssertionError", + "source": "invoice_allcold.py", + "line": 255, + "statement": "assert physical==live+helpers+centres+2", + "message": "" + }, + "upstream_controller": { + "result": "REJECTED", + "exception": "AssertionError", + "source": "audit_allcold.py", + "line": 93, + "statement": "assert(t['live'],t['physical'])==(DATA,PHYSICAL)", + "message": "" + } + }, + { + "name": "template live count understated", + "changed_inputs": [ + "template" + ], + "links_rebound": true, + "invoice": { + "result": "REJECTED", + "exception": "AssertionError", + "source": "invoice_allcold.py", + "line": 253, + "statement": "assert m*live-mass==owners['deficit']==5120", + "message": "" + }, + "upstream_controller": { + "result": "REJECTED", + "exception": "AssertionError", + "source": "audit_allcold.py", + "line": 93, + "statement": "assert(t['live'],t['physical'])==(DATA,PHYSICAL)", + "message": "" + } + }, + { + "name": "template calls reversed", + "changed_inputs": [ + "template" + ], + "links_rebound": true, + "invoice": { + "result": "ACCEPTED", + "changed_keys": [ + "template_sha256", + "owner_audit_sha256", + "controller_audit_sha256", + "selected_calls" + ], + "pervertex_bits": 53, + "prefix_bits": 397, + "finite": { + "physical_stock_bits": 2642, + "router_bits": 7988, + "literal_bits": 35284, + "physical_row_coefficient": 16469, + "retained_row_coefficient": 20161, + "required_C0_bits": 200012, + "halving_integer_inequality": [ + 5329, + 4608 + ], + "G_exponent": 30000, + "E_exponent": 100000, + "C0_exponent": 210000 + }, + "pervertex": 6466906000439144 + }, + "assembly": { + "result": "REJECTED", + "exception": "AssertionError", + "source": "assemble.py", + "line": 110, + "statement": "assert [(c['stage'],c['replica'])for c in calls]==CALL_ORDER", + "message": "" + }, + "upstream_controller": { + "result": "REJECTED", + "exception": "AssertionError", + "source": "audit_allcold.py", + "line": 103, + "statement": "assert [list(x)for x in order]==t['async_schedule']['order'] and len(set(order))==144", + "message": "" + } + }, + { + "name": "template call omitted", + "changed_inputs": [ + "template" + ], + "links_rebound": true, + "invoice": { + "result": "REJECTED", + "exception": "AssertionError", + "source": "invoice_allcold.py", + "line": 200, + "statement": "assert call_count==stages*replicas==control['complete_invocations']", + "message": "" + }, + "upstream_controller": { + "result": "REJECTED", + "exception": "AssertionError", + "source": "audit_allcold.py", + "line": 96, + "statement": "assert len(t['calls'])==144 and t['hosting']['max_helpers_per_physical_family_per_call']==1 and t['hosting']['banks']==[0]*9", + "message": "" + } + }, + { + "name": "template duplicate call", + "changed_inputs": [ + "template" + ], + "links_rebound": true, + "invoice": { + "result": "REJECTED", + "exception": "AssertionError", + "source": "invoice_allcold.py", + "line": 202, + "statement": "assert len({(c['stage'],c['replica']) for c in template['calls']})==call_count", + "message": "" + }, + "upstream_controller": { + "result": "REJECTED", + "exception": "AssertionError", + "source": "audit_allcold.py", + "line": 103, + "statement": "assert [list(x)for x in order]==t['async_schedule']['order'] and len(set(order))==144", + "message": "" + } + }, + { + "name": "template helper aliases data owner", + "changed_inputs": [ + "template" + ], + "links_rebound": true, + "invoice": { + "result": "ACCEPTED", + "changed_keys": [ + "template_sha256", + "owner_audit_sha256", + "controller_audit_sha256" + ], + "pervertex_bits": 53, + "prefix_bits": 397, + "finite": { + "physical_stock_bits": 2642, + "router_bits": 7988, + "literal_bits": 35284, + "physical_row_coefficient": 16469, + "retained_row_coefficient": 20161, + "required_C0_bits": 200012, + "halving_integer_inequality": [ + 5329, + 4608 + ], + "G_exponent": 30000, + "E_exponent": 100000, + "C0_exponent": 210000 + }, + "pervertex": 6466906000439144 + }, + "assembly": { + "result": "ACCEPTED", + "kappa": "836330098538459/500000000000000000" + }, + "upstream_controller": { + "result": "REJECTED", + "exception": "AssertionError", + "source": "audit_allcold.py", + "line": 152, + "statement": "s,rep,pair=call['stage'],call['replica'],call['pair'];assert call['time']==t['async_schedule']['order'].index([s,rep]);own=call['owners'];assert len(own)==N and len({f for f,rt in own})==N and all(0<=f=0 and parent_physical==parent_live+parent_helpers+centres+2", + "message": "" + } + }, + { + "name": "retained compiler changed", + "changed_inputs": [ + "retained" + ], + "links_rebound": true, + "invoice": { + "result": "REJECTED", + "exception": "AssertionError", + "source": "invoice_allcold.py", + "line": 266, + "statement": "assert previous['compiler']==compiler and previous['charged_prefix_bits']==payload", + "message": "", + "payload": 512 + }, + "changed_retained_bytes_fail_upstream_pin": true + }, + { + "name": "retained payload changed", + "changed_inputs": [ + "retained" + ], + "links_rebound": true, + "invoice": { + "result": "REJECTED", + "exception": "AssertionError", + "source": "invoice_allcold.py", + "line": 266, + "statement": "assert previous['compiler']==compiler and previous['charged_prefix_bits']==payload", + "message": "", + "payload": 512 + }, + "changed_retained_bytes_fail_upstream_pin": true + }, + { + "name": "retained allowance zero", + "changed_inputs": [ + "retained" + ], + "links_rebound": true, + "invoice": { + "result": "ACCEPTED", + "changed_keys": [ + "conservative_pervertex_used", + "retained_prior_overcharge", + "finite" + ], + "pervertex_bits": 52, + "prefix_bits": 397, + "finite": { + "physical_stock_bits": 2642, + "router_bits": 7987, + "literal_bits": 35284, + "physical_row_coefficient": 16469, + "retained_row_coefficient": 20161, + "required_C0_bits": 200012, + "halving_integer_inequality": [ + 5329, + 4608 + ], + "G_exponent": 30000, + "E_exponent": 100000, + "C0_exponent": 210000 + }, + "pervertex": 3588959010714576 + }, + "assembly": { + "result": "REJECTED", + "exception": "AssertionError", + "source": "assemble.py", + "line": 153, + "statement": "assert hash_ok(prior['sha256']) and type(prior['previous_pervertex_allowance']) is int and prior['previous_pervertex_allowance']>0", + "message": "" + }, + "changed_retained_bytes_fail_upstream_pin": true + }, + { + "name": "retained allowance one", + "changed_inputs": [ + "retained" + ], + "links_rebound": true, + "invoice": { + "result": "ACCEPTED", + "changed_keys": [ + "conservative_pervertex_used", + "retained_prior_overcharge", + "finite" + ], + "pervertex_bits": 52, + "prefix_bits": 397, + "finite": { + "physical_stock_bits": 2642, + "router_bits": 7987, + "literal_bits": 35284, + "physical_row_coefficient": 16469, + "retained_row_coefficient": 20161, + "required_C0_bits": 200012, + "halving_integer_inequality": [ + 5329, + 4608 + ], + "G_exponent": 30000, + "E_exponent": 100000, + "C0_exponent": 210000 + }, + "pervertex": 3588959010714577 + }, + "assembly": { + "result": "ACCEPTED", + "kappa": "836330098538459/500000000000000000" + }, + "changed_retained_bytes_fail_upstream_pin": true + }, + { + "name": "retained allowance negative", + "changed_inputs": [ + "retained" + ], + "links_rebound": true, + "invoice": { + "result": "ACCEPTED", + "changed_keys": [ + "conservative_pervertex_used", + "retained_prior_overcharge", + "finite" + ], + "pervertex_bits": 52, + "prefix_bits": 397, + "finite": { + "physical_stock_bits": 2642, + "router_bits": 7987, + "literal_bits": 35284, + "physical_row_coefficient": 16469, + "retained_row_coefficient": 20161, + "required_C0_bits": 200012, + "halving_integer_inequality": [ + 5329, + 4608 + ], + "G_exponent": 30000, + "E_exponent": 100000, + "C0_exponent": 210000 + }, + "pervertex": 3588959010714576 + }, + "assembly": { + "result": "REJECTED", + "exception": "AssertionError", + "source": "assemble.py", + "line": 153, + "statement": "assert hash_ok(prior['sha256']) and type(prior['previous_pervertex_allowance']) is int and prior['previous_pervertex_allowance']>0", + "message": "" + }, + "changed_retained_bytes_fail_upstream_pin": true + }, + { + "name": "retained allowance breaches logical guard", + "changed_inputs": [ + "retained" + ], + "links_rebound": true, + "invoice": { + "result": "REJECTED", + "exception": "AssertionError", + "source": "invoice_allcold.py", + "line": 284, + "statement": "assert all(inequalities.values())", + "message": "", + "inequalities": { + "local_primitive_bound": true, + "logical": false, + "router": true, + "literal": true, + "mass": true, + "precision": true, + "tape": true, + "row": true, + "halving": true + }, + "payload": 512, + "row": 16469 + }, + "changed_retained_bytes_fail_upstream_pin": true + }, + { + "name": "owner rank histogram changed with mass preserved", + "changed_inputs": [ + "owner" + ], + "links_rebound": true, + "invoice": { + "result": "ACCEPTED", + "changed_keys": [ + "owner_audit_sha256" + ], + "pervertex_bits": 53, + "prefix_bits": 397, + "finite": { + "physical_stock_bits": 2642, + "router_bits": 7988, + "literal_bits": 35284, + "physical_row_coefficient": 16469, + "retained_row_coefficient": 20161, + "required_C0_bits": 200012, + "halving_integer_inequality": [ + 5329, + 4608 + ], + "G_exponent": 30000, + "E_exponent": 100000, + "C0_exponent": 210000 + }, + "pervertex": 6466906000439144 + }, + "assembly": { + "result": "REJECTED", + "exception": "AssertionError", + "source": "assemble.py", + "line": 130, + "statement": "idle=Counter({int(r):n for r,n in owner['paid_profile'].items()});idle.subtract(paid);assert all(n>=0 for n in idle.values())", + "message": "" + } + }, + { + "name": "owner negative rank count with mass preserved", + "changed_inputs": [ + "owner" + ], + "links_rebound": true, + "invoice": { + "result": "ACCEPTED", + "changed_keys": [ + "owner_audit_sha256" + ], + "pervertex_bits": 53, + "prefix_bits": 397, + "finite": { + "physical_stock_bits": 2642, + "router_bits": 7988, + "literal_bits": 35284, + "physical_row_coefficient": 16469, + "retained_row_coefficient": 20161, + "required_C0_bits": 200012, + "halving_integer_inequality": [ + 5329, + 4608 + ], + "G_exponent": 30000, + "E_exponent": 100000, + "C0_exponent": 210000 + }, + "pervertex": 6466906000439144 + }, + "assembly": { + "result": "REJECTED", + "exception": "AssertionError", + "source": "assemble.py", + "line": 130, + "statement": "idle=Counter({int(r):n for r,n in owner['paid_profile'].items()});idle.subtract(paid);assert all(n>=0 for n in idle.values())", + "message": "" + } + }, + { + "name": "owner negative zero rank count", + "changed_inputs": [ + "owner" + ], + "links_rebound": true, + "invoice": { + "result": "ACCEPTED", + "changed_keys": [ + "owner_audit_sha256" + ], + "pervertex_bits": 53, + "prefix_bits": 397, + "finite": { + "physical_stock_bits": 2642, + "router_bits": 7988, + "literal_bits": 35284, + "physical_row_coefficient": 16469, + "retained_row_coefficient": 20161, + "required_C0_bits": 200012, + "halving_integer_inequality": [ + 5329, + 4608 + ], + "G_exponent": 30000, + "E_exponent": 100000, + "C0_exponent": 210000 + }, + "pervertex": 6466906000439144 + }, + "assembly": { + "result": "REJECTED", + "exception": "AssertionError", + "source": "assemble.py", + "line": 130, + "statement": "idle=Counter({int(r):n for r,n in owner['paid_profile'].items()});idle.subtract(paid);assert all(n>=0 for n in idle.values())", + "message": "" + } + }, + { + "name": "live stock and profile coherently understated", + "changed_inputs": [ + "template", + "owner" + ], + "links_rebound": true, + "invoice": { + "result": "ACCEPTED", + "changed_keys": [ + "template_sha256", + "owner_audit_sha256", + "controller_audit_sha256", + "live", + "physical", + "physical_stock_identity", + "hosted_rebased_pervertex" + ], + "pervertex_bits": 53, + "prefix_bits": 397, + "finite": { + "physical_stock_bits": 2642, + "router_bits": 7988, + "literal_bits": 35284, + "physical_row_coefficient": 16469, + "retained_row_coefficient": 20161, + "required_C0_bits": 200012, + "halving_integer_inequality": [ + 5329, + 4608 + ], + "G_exponent": 30000, + "E_exponent": 100000, + "C0_exponent": 210000 + }, + "pervertex": 6466906000439144 + }, + "assembly": { + "result": "REJECTED", + "exception": "AssertionError", + "source": "witness.py", + "line": 50, + "statement": "assert got==want,'SPEC MISMATCH %s: expected %s got %s'%(key,json.dumps(want)[:400],json.dumps(got,default=str)[:400])", + "message": "SPEC MISMATCH expected.rank_mass: expected 1041408 got 1041335" + }, + "upstream_controller": { + "result": "REJECTED", + "exception": "AssertionError", + "source": "audit_allcold.py", + "line": 93, + "statement": "assert(t['live'],t['physical'])==(DATA,PHYSICAL)", + "message": "" + } + }, + { + "name": "finite halving exceeds rank limit", + "changed_inputs": [ + "owner" + ], + "links_rebound": true, + "invoice": { + "result": "REJECTED", + "exception": "AssertionError", + "source": "invoice_allcold.py", + "line": 284, + "statement": "assert all(inequalities.values())", + "message": "", + "inequalities": { + "local_primitive_bound": true, + "logical": true, + "router": true, + "literal": true, + "mass": true, + "precision": true, + "tape": true, + "row": true, + "halving": false + }, + "payload": 512, + "row": 16469 + } + }, + { + "name": "finite row just below limit", + "changed_inputs": [ + "template", + "owner", + "parent" + ], + "links_rebound": true, + "invoice": { + "result": "ACCEPTED", + "changed_keys": [ + "template_sha256", + "parent_template_sha256", + "owner_audit_sha256", + "controller_audit_sha256", + "live", + "physical", + "physical_stock_identity", + "unhosted_pervertex", + "hosted_rebased_pervertex", + "conservative_pervertex_used", + "retained_prior_overcharge", + "finite" + ], + "pervertex_bits": 1889, + "prefix_bits": 397, + "finite": { + "physical_stock_bits": 4487, + "router_bits": 13515, + "literal_bits": 38975, + "physical_row_coefficient": 20159, + "retained_row_coefficient": 20161, + "required_C0_bits": 200012, + "halving_integer_inequality": [ + 5329, + 2 + ], + "G_exponent": 30000, + "E_exponent": 100000, + "C0_exponent": 210000 + } + }, + "assembly": { + "result": "REJECTED", + "exception": "AssertionError", + "source": "witness.py", + "line": 50, + "statement": "assert got==want,'SPEC MISMATCH %s: expected %s got %s'%(key,json.dumps(want)[:400],json.dumps(got,default=str)[:400])", + "message": "SPEC MISMATCH expected.rank_mass: expected 1041408 got 4366738424872810719678165125281892754372674739615470443638769985668961127018323820255847870566126974775722614938797055711697381776620538054477635166963741001808985758672315733025429399206498536474453740597078794509370898684979583663785923784980537016368444648561992721822583205002220173703874889735858005813259149644754334928994633749669354260177169989472002911084720265003463384883219912429028330144" + } + }, + { + "name": "finite row at rejected limit", + "changed_inputs": [ + "template", + "owner", + "parent" + ], + "links_rebound": true, + "invoice": { + "result": "REJECTED", + "exception": "AssertionError", + "source": "invoice_allcold.py", + "line": 284, + "statement": "assert all(inequalities.values())", + "message": "", + "inequalities": { + "local_primitive_bound": true, + "logical": true, + "router": true, + "literal": true, + "mass": true, + "precision": true, + "tape": true, + "row": false, + "halving": true + }, + "payload": 512, + "row": 20161 + } + }, + { + "name": "finite logical just below limit", + "changed_inputs": [ + "retained" + ], + "links_rebound": true, + "invoice": { + "result": "ACCEPTED", + "changed_keys": [ + "conservative_pervertex_used", + "retained_prior_overcharge", + "finite" + ], + "pervertex_bits": 3423, + "prefix_bits": 397, + "finite": { + "physical_stock_bits": 2642, + "router_bits": 11358, + "literal_bits": 35284, + "physical_row_coefficient": 16469, + "retained_row_coefficient": 20161, + "required_C0_bits": 200012, + "halving_integer_inequality": [ + 5329, + 4608 + ], + "G_exponent": 30000, + "E_exponent": 100000, + "C0_exponent": 210000 + } + }, + "assembly": { + "result": "ACCEPTED", + "kappa": "836330098538459/500000000000000000" + }, + "changed_retained_bytes_fail_upstream_pin": true + }, + { + "name": "finite logical just above limit", + "changed_inputs": [ + "retained" + ], + "links_rebound": true, + "invoice": { + "result": "REJECTED", + "exception": "AssertionError", + "source": "invoice_allcold.py", + "line": 284, + "statement": "assert all(inequalities.values())", + "message": "", + "inequalities": { + "local_primitive_bound": true, + "logical": false, + "router": true, + "literal": true, + "mass": true, + "precision": true, + "tape": true, + "row": true, + "halving": true + }, + "payload": 512, + "row": 16469 + }, + "changed_retained_bytes_fail_upstream_pin": true + }, + { + "name": "finite prefix 511 bits", + "changed_inputs": [ + "template", + "programs", + "checks", + "native" + ], + "links_rebound": true, + "invoice": { + "result": "ACCEPTED", + "changed_keys": [ + "template_sha256", + "owner_audit_sha256", + "controller_audit_sha256", + "providers", + "selected_calls", + "selected_real_component_primitives", + "selected_scalar_macros", + "global_prefix_bits", + "local_adapters", + "local_primitive_bound", + "unhosted_pervertex", + "hosted_rebased_pervertex", + "conservative_pervertex_used", + "retained_prior_overcharge" + ], + "pervertex_bits": 53, + "prefix_bits": 511, + "finite": { + "physical_stock_bits": 2642, + "router_bits": 7988, + "literal_bits": 35284, + "physical_row_coefficient": 16469, + "retained_row_coefficient": 20161, + "required_C0_bits": 200012, + "halving_integer_inequality": [ + 5329, + 4608 + ], + "G_exponent": 30000, + "E_exponent": 100000, + "C0_exponent": 210000 + }, + "pervertex": 6467025505917352 + }, + "assembly": { + "result": "REJECTED", + "exception": "AssertionError", + "source": "witness.py", + "line": 50, + "statement": "assert got==want,'SPEC MISMATCH %s: expected %s got %s'%(key,json.dumps(want)[:400],json.dumps(got,default=str)[:400])", + "message": "SPEC MISMATCH providers.gauge44.program_hashes: expected {\"backward\": \"f36c5831106f5637102c6bedeec76ed2b223c6671ce42fd0eceed9ef24725b23\", \"forward\": \"071ecdacc0bb3ac16046aad4119ed551a945cb0ed6c57002a548a3e2232503d8\"} got {\"backward\": \"f36c5831106f5637102c6bedeec76ed2b223c6671ce42fd0eceed9ef24725b23\", \"forward\": \"5ad99a38a1b357437bbdccaa3df6d0b8203e009ef149b6c78bd8462df4b84c87\"}" + } + }, + { + "name": "finite prefix 512 bits", + "changed_inputs": [ + "template", + "programs", + "checks", + "native" + ], + "links_rebound": true, + "invoice": { + "result": "REJECTED", + "exception": "AssertionError", + "source": "invoice_allcold.py", + "line": 288, + "statement": "assert required_prefix= 1`, `0 <= M < 73 S`, `0 <= L < 2^6050`, the fixed compiler `C = 64 * 74^3`, and +the retained row condition `2 bit_length(S) + 11185 < 20161`. These hypotheses imply: + +1. `bit_length(S) <= 4487`, so `S < 2^4487` and `M < 2^4494`. +2. `C < 2^25`, `L + 1 <= 2^6050` and `S + 1 <= 2^4487` give + `C (L + 1) (S + 1)^2 < 2^15049 < 2^30000` (router). +3. The literal expression `2 * 2^30000 S^2 + 8M + 4S + 4 + 32 * 73` + is less than `2^38976 < 2^100000`. +4. With `T = M + 2^100000`, `T < 2^100001` (mass), + `32 * 73 * T^2 < 2^200014 < 2^210000` (precision), and + `2T + 18 < 2^100003 < 2^210000` (tape). + +Thus those five guards cannot fail alone while the stated hypotheses hold. `verify.py` +checks each maximal integer bound exactly. The inequalities are monotone over the stated +nonnegative domain, which supplies the quantified implication rather than merely sampling it. +For the honest geometry, `M < 73S` follows from +`rank_mass = 73 * live - 5120`, `physical = live + helpers + 10`, and positive helpers. +**Nonnegativity is an explicit hypothesis, not a claim that the invoice enforces every valid +profile/receipt condition on arbitrary forged inputs.** Negative-count cases are separately +rejected by assembly. This implication concerns these finite expressions only; it proves no +all-size precision, tape or multiplication theorem. + +## Where invoice survivors are excluded + +- **Four altered templates pass invoice and assembly:** helper/data-owner aliasing, omitted idle + children, a bridge coefficient sign flip, and a bridge coefficient `2^513` exceeding the charged + 512-bit payload. The real upstream `audit()` rejects them at lines 152, 181, 111 and 111 respectively. + In the strict driver, this audit runs before invoice and assembly. The bridge case shows why + the invoice's 397-bit arithmetic certificate alone is not a checker of arbitrary bridge coefficients. + It assumes the controller-established unit bridge factors. +- **Two changed controller control-run fields pass invoice and assembly.** The original assertion + at `verify_t16.py:103` rejects both. The harness executes that one extracted, unchanged assertion + against each changed receipt, with an honest positive control. This is an isolated final-binding + predicate check, not execution of the whole driver. +- **Two controller metadata changes pass both:** `status='FAIL'` and inconsistent `rank_mass`. + These fields do not affect this invoice or assembly. The latter consumes owner rank mass instead; + the real controller regenerates its receipt. This is not evidence of changed arithmetic or of a + forged receipt surviving the complete source-bound replay. +- **Two changed retained allowances pass both:** a smaller positive extra allowance and the last + allowance below the logical gate. Both still add the complete fresh parent price. They preserve κ. + The original retained input is explicitly pinned by the frozen `data/UPSTREAM-PINS.json`, checked + by `verify_t16.py:34-35`; the harness confirms its pin and that these changed bytes violate it. + They are not new selected-source prices or demonstrated undercharges. +- **Sixteen other invoice survivors are rejected by actual assembly.** These cover owner/charts/idle + receipts, a stale controller link, reordered calls, parent reserve undercounts, zero or negative + retained allowances, changed or negative rank counts, coherent live-stock undercounts, and the + just-below row/prefix cases. Parent idle and bank-stock changes reach assembly's independent + parent-envelope recount at line 149, rather than an unrelated stale-hash guard. + +The shipped 69 admission controls mutate already-produced invoice/owner objects. Some checks +overlap this suite (profiles, call order and parent price); the new evidence is that the invoice +producer itself accepts or rejects these actual changed inputs, with tight prefix/row/logical +boundary pairs and an explicit upstream/assembly classification. The controller rejection +behavior is credited to the existing checker and PR1959, not presented as a new controller bug. + +## Reproduce and scope + +```sh +python3 -B research/t16-invoice-boundary-audit/verify.py +python3 scripts/research_package.py --package research/t16-invoice-boundary-audit +``` + +Checked with native Windows CPython 3.12.9 and Ubuntu 24.04 CPython 3.12.3, with identical +receipts. The registered Linux replay used one CPU, took 2m22s and peaked at about 0.90 GiB RSS +on the donor machine; these are observations, not portable resource guarantees. + +Python 3.12, standard library only. The verifier extracts its hash-pinned archives into a fresh +temporary directory, applies the selected stage's three frozen data overlays, and restores original +input bytes after every case. Source and fixture archives, the retained invoice and three moment/ +outer engine files are declared in `SOURCES.json` and `VERIFY.json`. `--write` regenerates the receipt. +The fixture is selected #1094 at source head `0fc329d0bec93ca7cd288eaea1295172e8789810`; +the catalogue and selected record at task selection are pinned as historical provenance. + +No entire cold chain, other historical supplier, arbitrary multi-provider case, or all-size transfer +obligation is verified by this package. It does not install a hardening wrapper or change a frozen +stage. A separate donor-session cold replay is not required by, or silently included in, this receipt. + +## Open next questions + +1. **Test the local-provider input boundary more fully.** Why: the finite input suite does not enumerate + `recount_provider()`'s wrapper, scalar/Horner and receipt-binding predicates. First step: retain + this positive control and mutate actual provider files with correctly rebound references, separating + independent native replay rejection from invoice rejection. Blocker: a bounded meaningful case set + and a fresh native replay for any claimed valid changed program. +2. **Should a successor wrapper bind controller and retained artifacts explicitly at its public entry?** + Why: invoice plus assembly are insufficient as a standalone admission API. First step: specify an + entry contract and test the four controller-rejected template cases and changed retained inputs through + it. Blocker: maintainer decision; frozen predecessor code must remain unchanged. +3. **Trace conditional finite hypotheses to all-size statements.** Why: the five implications above + are finite and require positivity and fixed compiler/row constants. First step: identify one exact + retained precision or tape lemma and quantify its inputs before attempting a proof. Blocker: this + package provides no all-size realization argument. + +## Credit + +Prepared by Tairitsu-Aya with substantial OpenAI Codex assistance in source inspection, experiments, +implementation and writing; no independent human review is claimed. Josie Elliston's PR1959 supplied +the explicit handoff and the model for reporting acceptance separately from complete-chain validity. +Its use of `marshal` for JSON-data copies follows jackmgaller's PR1939 observation; equality is checked +before use. The frozen invoice retains its PR558 → PR552 → PR531 scalar/Horner and finite-cost lineage, +the exact moment/outer lineage, and the T16 controller credits to Hao Yan (@FanPUYen) and the selected +construction contributors, including Jeremy Kothe and Rohan Arun. All frozen notices are preserved; +this new package is Apache-2.0. diff --git a/research/t16-invoice-boundary-audit/SOURCES.json b/research/t16-invoice-boundary-audit/SOURCES.json new file mode 100644 index 0000000000..21c8fa5b9e --- /dev/null +++ b/research/t16-invoice-boundary-audit/SOURCES.json @@ -0,0 +1,72 @@ +{ + "schema_version": 1, + "base_commit": "e112d71c8d7bb32435debcc54df932593dd8223a", + "files": [ + { + "path": "certificates/selected-result.json", + "usage": "provenance", + "git_blob": "ae6a99f28aa468649eb66a361e764d769363bf11", + "sha256": "10b9e340fd8e354a37a0c4813c90e5de1dd42044b5f6aca4a3fc5a42b685fa32" + }, + { + "path": "docs/research/agent-task-catalog.json", + "usage": "provenance", + "git_blob": "06c96f5579bb67ed1b86d334e78fbed7da6945f1", + "sha256": "6686ad58f1fbdbc87134a78901b60fd53a20d3984355e91defbbebc9e9fa8075" + }, + { + "path": "research/community-frontier1094-audit/selected-replay.tar.gz", + "usage": "input", + "git_blob": "c24daf067f9c543421d89ca2eeaa4eb78a57fb6f", + "sha256": "f1da80610bf33c58527f18ad63b4350d0b864e1d4486141ee17ac9bed4d529d6" + }, + { + "path": "research/complex-k492-owner-repair/vendor/multicold/engines/base_two_moment.py", + "usage": "input", + "git_blob": "14a90fa0e788217856f070382c9e61bd7c603c61", + "sha256": "aee70c242a2f1d225528fabe2002e1564d1dc884797c07d28a831c7878ee9098" + }, + { + "path": "research/complex-k492-owner-repair/vendor/multicold/engines/moment.py", + "usage": "input", + "git_blob": "7d697cb45203fe72d97037403d6da41f71f3b7fd", + "sha256": "81cbc864e106418fc7854322746f72180cb8110ff39f74450a3b8d55a82c1482" + }, + { + "path": "research/complex-k492-owner-repair/vendor/multicold/engines/outer.py", + "usage": "input", + "git_blob": "43007488ad2c43187c77cc6798beff8b1cd76ad2", + "sha256": "c1ebb52163a7219504c728a5c2b098bf1e50bf20148a2879c5a74c3cadc7c03c" + }, + { + "path": "research/complex-k492-owner-repair/vendor/multicold/vendor/pr558/vendor/pr552/complex-global/vendor531/evidence/audit/PREFIX-AND-INVOICE.json", + "usage": "input", + "git_blob": "a16bf40bccc81278a443e0d5f09b44495035de81", + "sha256": "ce1bfa49be88ae67a404f606a11db2232b7e1f2610d4418058e39749d86d8478" + }, + { + "path": "research/complex-t16-rare-pattern-exchanges/data/OWNERS.json.gz", + "usage": "input", + "git_blob": "d3ba33d7e703a3229d9fb8a360f69d2f318bbb70", + "sha256": "87902c528dfab7d503dcf8a784260e3ab6fb7424c418a1820f7261f25be7b6bc" + }, + { + "path": "research/complex-t16-rare-pattern-exchanges/data/PLAN.json", + "usage": "input", + "git_blob": "f1bec76e8e9b7a1f09c1e05cb6cce973b6e59f1b", + "sha256": "7bd786ba8e66408f02aa9ef446eaf20c1bfe981ea2e4dd1e5a929f0aa7767bc0" + }, + { + "path": "research/complex-t16-rare-pattern-exchanges/data/SPEC.json", + "usage": "input", + "git_blob": "af013ccc2975d9d575d116f8a463cc947f220c8d", + "sha256": "8cb51f25a5da4a29d3783853025b73ff1f452429d4fdb30c599e598bcab0e71d" + }, + { + "path": "research/complex-t16-rare-pattern-exchanges/upstream1087.tar.gz", + "usage": "input", + "git_blob": "2970ef79b0441e937449bed30f68f2e0558186ba", + "sha256": "d4acf04daef85d4514f80ec5fcd2492d0c60e5d6c49fa71b3e6523f8db2dea86" + } + ] +} diff --git a/research/t16-invoice-boundary-audit/TASK.json b/research/t16-invoice-boundary-audit/TASK.json new file mode 100644 index 0000000000..6820e88127 --- /dev/null +++ b/research/t16-invoice-boundary-audit/TASK.json @@ -0,0 +1,72 @@ +{ + "schema_version": 1, + "task_id": "supplier-boundary-audit", + "priority_revision": 3, + "base_commit": "e112d71c8d7bb32435debcc54df932593dd8223a", + "original_card": { + "id": "supplier-boundary-audit", + "question": "Does one selected supplier obligation follow from its actual source-bound checks?", + "starting_points": [ + "certificates/selected-result.json", + "research/owner-boundary-audit/README.md" + ], + "methods": [ + "Trace one hypothesis through the source, checker and complete caller.", + "Construct one semantically invalid but superficially well-formed fixture and test rejection." + ], + "acceptance_gate": "Pin the current sources and one obligation; the historical owner audit is an example, not evidence of a current bug.", + "first_step": { + "command": [ + "python3", + "-B", + "research/owner-boundary-audit/verify.py" + ], + "expected": "PASS_PR626_NEXT_TOUCH_BOUNDARY_AUDIT", + "inspect": "Identify why the timing-only omission passes but the full production controller still rejects it.", + "scope": "Positive control / source-bound orientation only; this is not a new construction or full cold replay." + }, + "first_experiment": "Choose one current supplier obligation and trace whether its acceptance depends on an independent check.", + "bottleneck_link": "Closing a current acceptance gap or proof obligation strengthens reliability even without changing kappa.", + "allowed_variations": [ + "Audit one named current condition using a new semantic counterexample." + ], + "scope_change_triggers": [ + "Reporting the historical timing-only diagnostic as a new current acceptance bug." + ], + "overlap_terms": [ + "owner boundary", + "bridge omission", + "hosting" + ] + }, + "scope_status": "refined", + "actual_scope": "Audit the unchanged selected PR1087 invoice_allcold.run() input boundary using 54 real-file mutations, then classify invoice survivors through actual assembly, selected upstream controller calls, and one isolated final-binding assertion.", + "scope_change_reason": "Refines the current supplier-boundary card to the exact invoice handoff in Josie Elliston PR1959. The historical owner audit is an orientation control, not a new current bug. The result is finite input-boundary evidence and a conditional implication among five finite guards.", + "bottleneck_link": "Reliability side result with no kappa change: distinguish the invoice producer's finite gates from controller/assembly/source-pin obligations, avoiding a false complete-chain bug claim.", + "budget_minutes": 240, + "stop_rule": "Stop after a consequential accepted invoice case is classified at the actual relevant caller boundary and the bounded prefix/row/logical/halving cases reproduce; report remaining local-provider and all-size obligations.", + "outcome": "completed", + "evidence": "54 cases: invoice rejects 28 and accepts 26; actual assembly rejects 16 of those and accepts 10. Four changed templates accepted by both are rejected upstream; two control-run receipt changes are rejected by the isolated original driver assertion; two are unread controller metadata; two are conservative retained allowances excluded from the selected source by its existing pin. Tight finite boundary pairs and exact integer bounds establish the stated conditional five-guard implication. Honest invoice and assembly reproduce archived evidence.", + "author": "Tairitsu-Aya", + "ai_assistance": "Substantial OpenAI Codex assistance in source inspection, experiments, implementation, verification and documentation for Tairitsu-Aya; no independent human review claimed.", + "open_questions": [ + { + "question": "Which additional local-provider input predicates reject coherent changed files?", + "why_it_matters": "The current suite does not exhaustively test wrapper, scalar/Horner and native receipt conditions in recount_provider().", + "first_step": "Keep the pinned positive fixture and mutate actual provider files with rebound references; rerun the independent native replay for any changed program claimed valid.", + "blocked_by": "A bounded meaningful case set and native replay support; not needed for this package's claim." + }, + { + "question": "Should a successor public admission wrapper bind controller and retained artifacts explicitly?", + "why_it_matters": "Invoice plus assembly alone do not validate arbitrary hosted template semantics or source provenance.", + "first_step": "Specify the public entry contract and run the four controller-rejected template cases and retained-input cases through a successor wrapper.", + "blocked_by": "Maintainer decision; keep frozen predecessor code unchanged." + }, + { + "question": "Which all-size statement supplies the finite positivity and fixed-constant hypotheses?", + "why_it_matters": "The five finite implications are not all-size precision/tape or realization proofs.", + "first_step": "Choose and quantify one retained precision or tape lemma before proving an implication.", + "blocked_by": "This package does not supply an all-size realization argument." + } + ] +} diff --git a/research/t16-invoice-boundary-audit/VERIFY.json b/research/t16-invoice-boundary-audit/VERIFY.json new file mode 100644 index 0000000000..425dbc047d --- /dev/null +++ b/research/t16-invoice-boundary-audit/VERIFY.json @@ -0,0 +1,28 @@ +{ + "schema_version": 1, + "status": "ready", + "python": "3.12", + "requirements": [], + "inputs": [ + "research/community-frontier1094-audit/selected-replay.tar.gz", + "research/complex-k492-owner-repair/vendor/multicold/engines/base_two_moment.py", + "research/complex-k492-owner-repair/vendor/multicold/engines/moment.py", + "research/complex-k492-owner-repair/vendor/multicold/engines/outer.py", + "research/complex-k492-owner-repair/vendor/multicold/vendor/pr558/vendor/pr552/complex-global/vendor531/evidence/audit/PREFIX-AND-INVOICE.json", + "research/complex-t16-rare-pattern-exchanges/data/OWNERS.json.gz", + "research/complex-t16-rare-pattern-exchanges/data/PLAN.json", + "research/complex-t16-rare-pattern-exchanges/data/SPEC.json", + "research/complex-t16-rare-pattern-exchanges/upstream1087.tar.gz" + ], + "commands": [ + { + "argv": [ + "{python}", + "-B", + "{package}/verify.py" + ], + "timeout_seconds": 600, + "checks": "Pin all source archives, overlays, retained invoice and three arithmetic engines; reproduce honest invoice, assembly and controller; apply 54 actual input mutations with real byte hash rebinding; classify exact invoice/assembly/controller or isolated driver predicate outcomes; restore the honest fixture; compare the full deterministic receipt and exact finite implication bounds against EXPECTED.json." + } + ] +} diff --git a/research/t16-invoice-boundary-audit/cases.py b/research/t16-invoice-boundary-audit/cases.py new file mode 100644 index 0000000000..b0dfceedc6 --- /dev/null +++ b/research/t16-invoice-boundary-audit/cases.py @@ -0,0 +1,139 @@ +"""Bounded real-input mutations for the pinned T16 invoice checker. + +Tairitsu-Aya, with OpenAI Codex assistance. Apache-2.0. +""" +import marshal + + +def copy(value): + return marshal.loads(marshal.dumps(value)) + + +def build_cases(baseline, baseline_invoice, invoice): + def assign(key, field, value): + return lambda data: data[key].__setitem__(field, value) + + def increment(key, field, delta=1): + return lambda data: data[key].__setitem__(field, data[key][field]+delta) + + cases = [] + def add(name, change, rebind=True): + cases.append((name, change, rebind)) + + add('owner status false', assign('owner', 'status', 'FAIL')) + add('controller status false', assign('controller', 'status', 'FAIL')) + add('controller complete calls understated', increment('controller', 'complete_invocations', -1)) + add('controller unique owner flag false', assign('controller', 'one_owner_per_complete_invocation', False)) + add('controller mutations flag false', assign('controller', 'mutation_controls_run', False)) + add('controller mutation list empty', assign('controller', 'mutations_rejected', [])) + add('controller rank mass inconsistent', increment('controller', 'rank_mass')) + add('owner rank mass inconsistent', increment('owner', 'rank_mass')) + add('owner deficit inconsistent', increment('owner', 'deficit')) + add('owner live inconsistent', increment('owner', 'live')) + add('owner physical inconsistent', increment('owner', 'physical')) + add('owner distinct owner flag false', assign('owner', 'all_live_owners_per_call_distinct', False)) + add('owner chart count understated', increment('owner', 'actual_helper_owner_charts', -1)) + add('owner idle remainder count understated', increment('owner', 'explicit_idle_remainder_children', -1)) + add('owner idle source count understated', increment('owner', 'source_idle_children_charged', -1)) + add('owner idle count exceeds source', assign('owner', 'explicit_idle_remainder_children', 32257)) + add('owner controller hash stale', assign('owner', 'controller_audit_sha256', '0'*64), False) + add('controller template hash stale', assign('controller', 'complex_template_sha256', '0'*64), False) + add('owner template hash stale', assign('owner', 'template_sha256', '0'*64), False) + add('summary template hash stale', assign('summary', 'template_sha256', '0'*64), False) + add('template physical reserve understated', increment('template', 'physical', -1)) + add('template live count understated', increment('template', 'live', -1)) + add('template calls reversed', lambda d: d['template']['calls'].reverse()) + add('template call omitted', lambda d: d['template']['calls'].pop()) + add('template duplicate call', lambda d: d['template']['calls'].__setitem__(1, copy(d['template']['calls'][0]))) + add('template helper aliases data owner', lambda d: d['template']['calls'][0]['owners'].__setitem__(224, copy(d['template']['calls'][0]['owners'][0]))) + add('template idle children omitted', lambda d: d['template'].__setitem__('idle_children', [])) + add('template bank padding restored', lambda d: d['template']['bank_padding'].__setitem__('families', [14336])) + bridge = next(i for i,e in enumerate(baseline['template']['execution_schedule']) if e['kind']=='bridge') + sweep = next(i for i,e in enumerate(baseline['template']['execution_schedule']) if e['kind']=='local_cover_sweep') + add('bridge coefficient sign flipped', lambda d: d['template']['execution_schedule'][bridge].__setitem__('coefficient', -d['template']['execution_schedule'][bridge]['coefficient'])) + add('bridge coefficient exceeds charged payload', lambda d: d['template']['execution_schedule'][bridge].__setitem__('coefficient', 2**513)) + add('bridge omitted', lambda d: d['template']['execution_schedule'].pop(bridge)) + add('sweep provider changed', lambda d: d['template']['execution_schedule'][sweep].__setitem__('provider_id', 'missing')) + add('call program hash stale', lambda d: d['template']['calls'][0].__setitem__('local_program_sha256', '0'*64)) + add('parent idle multiplicity understated', lambda d: d['parent']['idle_children'][0].__setitem__('replicas', d['parent']['idle_children'][0]['replicas']-1)) + add('parent bank stock coherently understated', lambda d: (d['parent'].__setitem__('live', d['parent']['live']-9), d['parent'].__setitem__('physical',d['parent']['physical']-9))) + add('parent physical stock inconsistent', increment('parent', 'physical', -1)) + add('retained compiler changed', increment('retained', 'compiler')) + add('retained payload changed', increment('retained', 'charged_prefix_bits', -1)) + add('retained allowance zero', assign('retained', 'conservative_pervertex_used', 0)) + add('retained allowance one', assign('retained', 'conservative_pervertex_used', 1)) + add('retained allowance negative', assign('retained', 'conservative_pervertex_used', -1)) + add('retained allowance breaches logical guard', assign('retained', 'conservative_pervertex_used', 2**4000)) + + def move_mass(d): + d['owner']['paid_profile']['1'] += 2 + d['owner']['paid_profile']['2'] -= 1 + add('owner rank histogram changed with mass preserved', move_mass) + + def negative_count(d): + d['owner']['paid_profile']['1'] += 56 + d['owner']['paid_profile']['7'] = -1 + add('owner negative rank count with mass preserved', negative_count) + add('owner negative zero rank count', lambda d: d['owner']['paid_profile'].__setitem__('0', -1)) + + def understock(d): + for field in ('live','physical'): + d['template'][field] -= 1 + d['owner'][field] -= 1 + d['owner']['rank_mass'] -= 73 + d['owner']['paid_profile']['1'] -= 73 + add('live stock and profile coherently understated', understock) + + def halving(d): + d['owner']['paid_profile']['1'] -= 52 + d['owner']['paid_profile']['52'] = 1 + add('finite halving exceeds rank limit', halving) + + group = 2**(36*36) + for j in range(1,37): + group *= 2**(2*j)-1 + first_bad_stock = (2**4487+group-1)//group + def row_limit(d, delta): + physical = first_bad_stock+delta + live = physical-490 + d['template']['physical'] = d['owner']['physical'] = physical + d['template']['live'] = d['owner']['live'] = live + d['owner']['rank_mass'] = 73*live-5120 + d['owner']['paid_profile'] = {'1': d['owner']['rank_mass']} + parent_live = 14336+9*((live-14336+8)//9) + d['parent']['live'] = parent_live + d['parent']['physical'] = parent_live+514 + add('finite row just below limit', lambda d: row_limit(d,-1)) + add('finite row at rejected limit', lambda d: row_limit(d,0)) + + last_good_used = (2**6050-65)//group + for delta, label in ((0,'below'),(1,'above')): + add('finite logical just '+label+' limit', + assign('retained', 'conservative_pervertex_used', + last_good_used-baseline_invoice['unhosted_pervertex']+delta)) + + def prefix_limit(d, power): + # Two inverse dyadic scales preserve the endpoint but force an exact + # intermediate magnitude 2**power. Rebind the claimed local receipts; + # this is an adversarial supplier input, not a fresh native replay. + events = d['programs']['forward'] + events[1:1] = [['scalar',['scale',['L',0],2**power,1],0], + ['scalar',['scale',['L',0],1,2**power],0]] + check = d['checks']['forward'] + check['events'] += 2 + check['scalar_macros'] += 2 + check['real_component_primitive_bound'] += 4*power + check['sha256'] = invoice.programhash(events) + local = d['native']['local']['forward'] + local['prefix_l1_upper'] = str(2**power) + local['prefix_bits_upper'] = power+1 + registry = d['template']['local_providers']['gauge44'] + registry['local_programs'] = d['programs'] + registry['local_program_checks'] = d['checks'] + for call in d['template']['calls']: + if call['orientation']=='forward': + call['local_program_sha256'] = check['sha256'] + for power in (181,182,183): + add('finite prefix '+str(power+330)+' bits', lambda d,power=power: prefix_limit(d,power)) + + return cases diff --git a/research/t16-invoice-boundary-audit/verify.py b/research/t16-invoice-boundary-audit/verify.py new file mode 100644 index 0000000000..3682fa0ddd --- /dev/null +++ b/research/t16-invoice-boundary-audit/verify.py @@ -0,0 +1,310 @@ +"""Replay real-file mutations against the unchanged selected T16 invoice. + +Tairitsu-Aya, with substantial OpenAI Codex assistance. Apache-2.0. +Follows Josie Elliston's PR1959 invoice handoff. No frozen checker is patched. +""" +import argparse +import ast +from collections import Counter +import contextlib +import gzip +import hashlib +import importlib.util +import io +import json +import os +from pathlib import Path +import runpy +import sys +import tarfile +import tempfile +import traceback + +from cases import build_cases, copy + +if not __debug__: + raise RuntimeError('Assertions must remain enabled') + +HERE = Path(__file__).resolve().parent +ROOT = HERE.parents[1] +STAGE = ROOT / 'research/complex-t16-rare-pattern-exchanges' +ARCHIVE = ROOT / 'research/community-frontier1094-audit/selected-replay.tar.gz' +ENGINES = ROOT / 'research/complex-k492-owner-repair/vendor/multicold' +RETAINED = ENGINES / 'vendor/pr558/vendor/pr552/complex-global/vendor531/evidence/audit/PREFIX-AND-INVOICE.json' +MEMBERS = { + 'code/invoice_allcold.py': '71eb57514e28ced97251e0507105f654f59885ec4d40486a780bf166098858a8', + 'code/assemble.py': '15f6986a476bac76bcdc0bfcf51da115389b46f1950d2766b6822f757888b13a', + 'code/audit_allcold.py': '1467a2acb654e62552c69fb9a7c4c85f70a02120881d222313865058ab71a6cc', + 'code/witness.py': '779c5172894b992131e85be1e592ed2a1aec8c287b872ff42007d36a7291e444', + 'code/generated_identity.py': 'c8af22719c0f3097a991a3f6ccac8f090afd2faba554745733d9ea88f2c25708', + 'verify_t16.py': '050e2dfba59911b8f29fd94422833d421367a0ad01c5e4ae916a75a235ee5e46', +} + + +def sha(path): + return hashlib.sha256(path.read_bytes()).hexdigest() + + +def read(path): + data = path.read_bytes() + return json.loads(gzip.decompress(data) if path.suffix == '.gz' else data) + + +def write(path, value): + data = (json.dumps(value, indent=2) + '\n').encode('utf-8') + path.write_bytes(gzip.compress(data, mtime=0) if path.suffix == '.gz' else data) + + +def normalized(value): + return json.loads(json.dumps(value)) + + +def quiet(call, *args): + with contextlib.redirect_stdout(io.StringIO()): + return call(*args) + + +def load(name, path): + spec = importlib.util.spec_from_file_location(name, path) + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + return module + + +def extract(tmp): + pins = [f for f in read(HERE / 'SOURCES.json')['files'] if f['usage'] == 'input'] + assert len(pins) == 9 + for item in pins: + assert sha(ROOT / item['path']) == item['sha256'], 'Input changed: ' + item['path'] + source = tmp / 'source' + source.mkdir() + with tarfile.open(STAGE / 'upstream1087.tar.gz') as archive: + for member in archive.getmembers(): + assert member.isfile() and (source / member.name).resolve().is_relative_to(source.resolve()) + archive.extractall(source, filter='data') + for name in ('OWNERS.json.gz', 'PLAN.json', 'SPEC.json'): + (source / 'data' / name).write_bytes((STAGE / 'data' / name).read_bytes()) + for name, expected in MEMBERS.items(): + assert sha(source / name) == expected, 'Frozen member changed: ' + name + fixture = tmp / 'global' + with tarfile.open(ARCHIVE) as archive: + for member in archive.getmembers(): + prefix = 'candidate/strict/global/' + if member.isfile() and member.name.startswith(prefix): + target = fixture / member.name[len(prefix):] + assert target.resolve().is_relative_to(fixture.resolve()) + target.parent.mkdir(parents=True, exist_ok=True) + target.write_bytes(archive.extractfile(member).read()) + assembly = json.load(archive.extractfile('candidate/strict/ASSEMBLY.json')) + return source, fixture, assembly + + +def rejection(error, sources): + frames = [f for f in traceback.extract_tb(error.__traceback__) + if Path(f.filename).name in sources] + assert frames, 'Rejection outside the pinned checker: ' + repr(error) + frame = frames[-1] + result = dict(result='REJECTED', exception=type(error).__name__, + source=Path(frame.filename).name, line=frame.lineno, + statement=frame.line, message=str(error)[:500]) + tb = error.__traceback__ + while tb: + if Path(tb.tb_frame.f_code.co_filename).name == 'invoice_allcold.py': + values = tb.tb_frame.f_locals + if 'inequalities' in values: + result['inequalities'] = values['inequalities'] + for key in ('required_prefix', 'payload', 'row'): + if key in values: + result[key] = values[key] + tb = tb.tb_next + return result + + +def finite_implications(): + """Check the integer bounds used in README's quantified implication proof.""" + compiler = 64 * 74**3 + stock_max = 2**4487 - 1 + mass_max = 73 * stock_max - 1 + logical_max = 2**6050 - 1 + total_max = mass_max + 2**100000 + bounds = dict( + router=compiler * (logical_max + 1) * (stock_max + 1)**2, + literal=2 * 2**30000 * stock_max**2 + 8 * mass_max + 4 * stock_max + 4 + 32 * 73, + mass=total_max, + precision=32 * 73 * total_max**2, + tape=2 * total_max + 18, + ) + powers = dict(router=15049, literal=38976, mass=100001, precision=200014, tape=100003) + for name, bound in bounds.items(): + assert 0 < bound < 2**powers[name] + assert 2 * stock_max.bit_length() + 11185 == 20159 + assert 2 * (stock_max + 1).bit_length() + 11185 == 20161 + assert compiler < 2**25 + return dict(hypotheses='Integer S>=1, 0<=M<73*S, 0<=L<2**6050, 2*bit_length(S)+11185<20161', + stock_bit_limit=4487, strict_upper_bound_powers_of_two=powers) + + +def run(tmp): + source, fixture, archived_assembly = extract(tmp) + os.environ.update(WITNESS_SPEC=str(source / 'data/SPEC.json'), + GAIN_PR564_SOURCE=str(ENGINES), PYTHONINTMAXSTRDIGITS='0') + for key in ('WITNESS_DISCOVER', 'WITNESS_RECORD'): + os.environ.pop(key, None) + if hasattr(sys, 'set_int_max_str_digits'): + sys.set_int_max_str_digits(0) + sys.path.insert(0, str(source / 'code')) + invoice = load('frozen_invoice', source / 'code/invoice_allcold.py') + assembly = load('frozen_assembly', source / 'code/assemble.py') + retained = tmp / 'retained-invoice.json' + retained.write_bytes(RETAINED.read_bytes()) + paths = dict(template=fixture / 'hosted/GLOBAL-TEMPLATE.json.gz', + summary=fixture / 'hosted/HOSTED.json', + owner=fixture / 'audit/OWNERS-AND-PROFILE.json', + controller=fixture / 'audit/ASYNC-AUDIT.json', + parent=fixture / 'base/split-centres/GLOBAL-TEMPLATE.json.gz', + programs=fixture / 'base/providers/gauge44/LOCAL-PROGRAMS.json.gz', + checks=fixture / 'base/providers/gauge44/LOCAL-CHECKS.json', + native=fixture / 'base/providers/gauge44/INDEPENDENT-LOCAL-REPLAY.json', + retained=retained) + original = {key: path.read_bytes() for key, path in paths.items()} + baseline = {key: read(path) for key, path in paths.items()} + assert copy(baseline) == baseline + archived_invoice = read(fixture / 'audit/PREFIX-AND-INVOICE.json') + out = tmp / 'invoice' + + def calculate(): + return quiet(invoice.run, fixture / 'base', fixture / 'hosted', fixture / 'audit', out, retained) + + assert normalized(calculate()) == archived_invoice, 'Honest invoice does not reproduce' + positive_assembly = normalized(quiet(assembly.assemble, baseline['owner'], + read(out / 'PREFIX-AND-INVOICE.json'), sha(paths['owner']), sha(out / 'PREFIX-AND-INVOICE.json'))) + # Only the regenerated JSON container's hash can differ across newline conventions. + assert positive_assembly['input_sha256']['fresh_invoice'] == sha(out / 'PREFIX-AND-INVOICE.json') + positive_assembly['input_sha256']['fresh_invoice'] = archived_assembly['input_sha256']['fresh_invoice'] + assert positive_assembly == archived_assembly, 'Honest assembly does not reproduce' + + argv = sys.argv + report = tmp / 'controller-positive/ASYNC-AUDIT.json' + sys.argv = [str(source / 'code/audit_allcold.py'), str(fixture / 'base'), + str(fixture / 'hosted'), str(report)] + try: + with contextlib.redirect_stdout(io.StringIO()): + controller = runpy.run_path(str(source / 'code/audit_allcold.py'), run_name='__main__') + finally: + sys.argv = argv + ignored = {'mutation_controls_run', 'mutations_rejected'} + fresh = read(report) + assert fresh['mutation_controls_run'] is False and fresh['mutations_rejected'] == [] + assert {k:v for k,v in fresh.items() if k not in ignored} == { + k:v for k,v in baseline['controller'].items() if k not in ignored} + + # Execute this one original final-binding predicate separately; do not call + # it a replay of verify_t16.py or of its producer stages. + driver = source / 'verify_t16.py' + node, = [n for n in ast.parse(driver.read_text()).body if isinstance(n, ast.Assert) and n.lineno == 103] + driver_predicate = compile(ast.Module(body=[node], type_ignores=[]), str(driver), 'exec') + exec(driver_predicate, {'audit': baseline['controller']}) + retained_pin = read(source / 'data/UPSTREAM-PINS.json')[RETAINED.relative_to(ROOT).as_posix()] + assert retained_pin == sha(RETAINED) + + results = [] + for name, mutate, rebind in build_cases(baseline, archived_invoice, invoice): + data = copy(baseline) + mutate(data) + changed = [key for key in paths if data[key] != baseline[key]] + assert changed, 'No-op mutant: ' + name + result = dict(name=name, changed_inputs=changed, links_rebound=rebind) + try: + for key in changed: + write(paths[key], data[key]) + if 'programs' in changed: + program_sha = sha(paths['programs']) + data['native']['local_programs_sha256'] = program_sha + write(paths['native'], data['native']) + data['template']['local_providers']['gauge44']['local_programs_sha256'] = program_sha + write(paths['template'], data['template']) + for key in ('programs', 'checks', 'native'): + artifact = 'providers/gauge44/' + paths[key].name + for receipt in ('owner', 'summary'): + data[receipt]['source_artifacts'][artifact] = sha(paths[key]) + if rebind and 'template' in changed: + digest = invoice.contenthash(paths['template']) + data['summary']['template_sha256'] = digest + data['owner']['template_sha256'] = digest + data['controller']['template_sha256'] = digest + data['controller']['complex_template_sha256'] = digest + for key in ('summary', 'controller'): + write(paths[key], data[key]) + if rebind: + data['owner']['controller_audit_sha256'] = sha(paths['controller']) + write(paths['owner'], data['owner']) + try: + output = calculate() + except Exception as error: + result['invoice'] = rejection(error, {'invoice_allcold.py', 'witness.py'}) + output = None + if output is not None: + result['invoice'] = dict(result='ACCEPTED', + changed_keys=[k for k in output if normalized(output[k]) != archived_invoice.get(k)], + pervertex_bits=output['conservative_pervertex_used'].bit_length(), + prefix_bits=output['global_prefix_bits'], finite=output['finite']) + if output['conservative_pervertex_used'].bit_length() <= 64: + result['invoice']['pervertex'] = output['conservative_pervertex_used'] + try: + assembled = quiet(assembly.assemble, read(paths['owner']), + read(out / 'PREFIX-AND-INVOICE.json'), + sha(paths['owner']), sha(out / 'PREFIX-AND-INVOICE.json')) + result['assembly'] = dict(result='ACCEPTED', kappa=assembled['kappa']) + except Exception as error: + result['assembly'] = rejection(error, {'assemble.py', 'witness.py'}) + if 'template' in changed and 'parent' not in changed and 'programs' not in changed: + try: + controller['audit'](read(paths['template'])) + result['upstream_controller'] = dict(result='ACCEPTED') + except Exception as error: + result['upstream_controller'] = rejection(error, {'audit_allcold.py'}) + if name in ('controller mutations flag false', 'controller mutation list empty'): + try: + exec(driver_predicate, {'audit': read(paths['controller'])}) + result['isolated_driver_predicate'] = dict(result='ACCEPTED') + except AssertionError as error: + result['isolated_driver_predicate'] = rejection(error, {'verify_t16.py'}) + if 'retained' in changed: + result['changed_retained_bytes_fail_upstream_pin'] = sha(paths['retained']) != retained_pin + results.append(result) + finally: + for key, path in paths.items(): + path.write_bytes(original[key]) + print(len(results), name, result['invoice']['result'], flush=True) + + assert all(path.read_bytes() == original[key] for key, path in paths.items()) + assert normalized(calculate()) == archived_invoice, 'Original fixture was not restored' + counts = Counter(row['invoice']['result'] for row in results) + downstream = Counter(row['assembly']['result'] for row in results if 'assembly' in row) + return dict(status='PASS_T16_INVOICE_BOUNDARY_AUDIT', member_sha256=MEMBERS, + positive=dict(invoice_all_fields_equal=True, assembly_all_proof_fields_equal=True, + assembly_only_normalized_field='input_sha256.fresh_invoice', + controller_equal_except_mutation_run_fields=True, + kappa=archived_assembly['kappa'], prefix_bits=archived_invoice['global_prefix_bits'], + physical_row_coefficient=archived_invoice['finite']['physical_row_coefficient']), + summary=dict(cases=len(results), invoice=dict(counts), assembly=dict(downstream)), + finite_implications=finite_implications(), cases=results) + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('--write', action='store_true', help='Regenerate EXPECTED.json') + args = parser.parse_args() + with tempfile.TemporaryDirectory(prefix='t16-invoice-audit-') as directory: + actual = run(Path(directory)) + payload = json.dumps(actual, indent=2, ensure_ascii=False) + '\n' + expected = HERE / 'EXPECTED.json' + if args.write: + expected.write_text(payload, encoding='utf-8', newline='\n') + else: + assert actual == read(expected), 'Receipt differs from EXPECTED.json' + print(actual['status'], json.dumps(actual['summary'], sort_keys=True)) + + +if __name__ == '__main__': + main()