Files
fuj-management/go/tests/fixtures/reconcile/03_proportional_remainder.json
Jan Novak 67d2f11d7c
All checks were successful
Deploy to K8s / deploy (push) Successful in 7s
feat(go): fixture capture + characterization framework (M3)
Closes M3.1–M3.6.  Parity safety net proving Go output matches Python
for every ported pure-domain function (M2.1–M2.9) and reconcile (M2.10).

Capture pipeline:
- scripts/capture_fixtures.py: calls each Python function with seeded
  inputs, emits JSON fixtures to stdout (never writes files directly).
- scripts/scrub_fixtures.py: deterministic PII scrubber — SHA-256
  pseudonyms for member names, digit-preserving hashes for VS/account/
  bank_id, name-sweep in message text.  Idempotent; no salt.
- scripts/_fixture_seeds.py: handcrafted seeds for all 11 functions;
  synthetic names throughout (no real roster members).
- scripts/capture_all_fixtures.sh: convenience wrapper for full corpus
  regeneration outside of make.

Fixture corpus (98 files, all PII-free):
- go/tests/fixtures/pure/<func>/<case>.json — 10 function directories.
- go/tests/fixtures/reconcile/<NN>_<case>.json — 10 branch-coverage
  cases: greedy, overpayment credit, proportional remainder, even-split,
  out-of-window, exception override, other: purpose, junior ?, multi-
  person+month fan-out, unmatched.

Go parity tests (//go:build parity):
- go/tests/parity/parityio.go: generic LoadDir/RunAll helpers + typed
  In/Out struct pairs for all 10 pure functions; Envelope decoder for
  int/float/none disambiguation.
- 10 pure-function test packages + bespoke reconcile test with per-cell
  float tolerance (math.Abs <= 0.01 for `paid` values).

Makefile: go-parity, go-test-all, capture-fixtures targets.
go/tests/fixtures/README.md: refresh workflow + PII audit guide.

Gate: make go-test green, make go-parity green (11/11 packages),
      make go-lint clean (parity tag), make go-build clean.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-06 23:26:24 +02:00

111 lines
2.6 KiB
JSON

{
"case": "03_proportional_remainder",
"func": "scripts.match_payments.reconcile",
"captured_at": "2026-05-06",
"input": {
"members": [
{
"name": "Member_d035d9f9",
"tier": "A",
"fees": {
"2026-01": [
750,
3
],
"2026-02": [
750,
2
],
"2026-03": [
350,
2
]
}
}
],
"sorted_months": [
"2026-01",
"2026-02",
"2026-03"
],
"transactions": [
{
"date": "2026-03-10",
"amount": 800,
"manual_fix": "",
"person": "Member_d035d9f9",
"purpose": "2026-01,2026-02,2026-03",
"inferred_amount": 800,
"sender": "Member_d035d9f9",
"message": "",
"bank_id": ""
}
],
"exceptions": [],
"default_year": 2026
},
"output": {
"members": {
"Member_d035d9f9": {
"tier": "A",
"months": {
"2026-01": {
"expected": 750,
"original_expected": 750,
"attendance_count": 3,
"exception": null,
"paid": 324.3243243243243,
"transactions": [
{
"amount": 324.3243243243243,
"date": "2026-03-10",
"sender": "Member_d035d9f9",
"message": "",
"confidence": "auto"
}
]
},
"2026-02": {
"expected": 750,
"original_expected": 750,
"attendance_count": 2,
"exception": null,
"paid": 324.3243243243243,
"transactions": [
{
"amount": 324.3243243243243,
"date": "2026-03-10",
"sender": "Member_d035d9f9",
"message": "",
"confidence": "auto"
}
]
},
"2026-03": {
"expected": 350,
"original_expected": 350,
"attendance_count": 2,
"exception": null,
"paid": 151.35135135135135,
"transactions": [
{
"amount": 151.35135135135135,
"date": "2026-03-10",
"sender": "Member_d035d9f9",
"message": "",
"confidence": "auto"
}
]
}
},
"other_transactions": [],
"total_balance": -1051
}
},
"unmatched": [],
"credits": {
"Member_d035d9f9": -1051
}
}
}