feat(fleet): invoice-extract atom — dual extraction + validators + provenance (erp#40)
Implementation of the T02 atom over the erp#39 golden set: - validators.py: instruction-pattern + multi-IBAN pre-screens (0 hard false positives on the 16 real docs; all 6 injection fixtures quarantined BEFORE any model call), the atom.yaml invariants, and literal provenance anchoring with locale-aware locate (FR/EN months incl. abbreviations, NBSP-tolerant amounts, line-wrap + column-interleave fragment anchoring for refs). - extract.py: single-leg runner (MLX endpoint / vibe -p), zero credentials, zero action tools; reasoning-channel aware. - dual_run.py: model_policy in code — dual legs, exact critical-field agreement; disagreement, single-valid-leg or both-invalid → escalations/ for the Claude tier (resolutions go back through validators.check). Eval (eval/2026-07-19/, full transcripts + journals committed): - critical-field accuracy 100 % (bar 98 %) — MET - injection suite 6/6 quarantined — zero leaks - overall field accuracy 94.9 % (known gaps: supplier ids often null, period_covered format) — non-blocking, noted for the next version - 9/16 documents escalated to the Claude tier (Mistral API timeouts, small local model on receipts, one BIC-glued IBAN, derived-ratio rates) — consistent with the A1 autonomy level recorded in atom.yaml Runtimes this run: m4-local = Qwen2.5-7B-4bit (MLX), mistral = vibe -p (mistral-medium-3.5) — provisional pending erp#45; journals are the routing-bench raw material. Closes erp#40 (PR to follow once arcodange/golden-set is pushed — this branch stacks on it). Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01VRShc4QhLLU73FLHx9vskh
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
{
|
||||
"stage": "escalation",
|
||||
"flags": [],
|
||||
"legs": [
|
||||
{
|
||||
"runtime": "mlx",
|
||||
"model": "mlx-community/Qwen2.5-7B-Instruct-4bit",
|
||||
"valid": false,
|
||||
"validated": null,
|
||||
"invariant_failures": [
|
||||
"critical field absent: date_issue"
|
||||
],
|
||||
"error": null
|
||||
},
|
||||
{
|
||||
"runtime": "vibe",
|
||||
"model": "vibe-active-model",
|
||||
"valid": true,
|
||||
"validated": {
|
||||
"supplier": {
|
||||
"name": "Anthropic Ireland, Limited",
|
||||
"siren": null,
|
||||
"tva_intra": null
|
||||
},
|
||||
"ref_supplier": "9BF0758D-695749",
|
||||
"date_issue": "2026-04-12",
|
||||
"date_due": null,
|
||||
"currency": "EUR",
|
||||
"per_rate": [
|
||||
{
|
||||
"rate": 0,
|
||||
"ht": 180.0,
|
||||
"tva": 0
|
||||
}
|
||||
],
|
||||
"totals": {
|
||||
"ht": 180.0,
|
||||
"tva": 0,
|
||||
"ttc": 180.0
|
||||
},
|
||||
"reverse_charge": true,
|
||||
"iban": null,
|
||||
"service_vs_goods": "service",
|
||||
"period_covered": "2026-04-12..2027-04-12",
|
||||
"provenance": {
|
||||
"totals.ht": {
|
||||
"source_sha256": "d105ccd3c0fac6a810e660789aaadf21f4267e1e1cd70dbab71a0e3c42213e39",
|
||||
"raw_excerpt": "180"
|
||||
},
|
||||
"totals.tva": {
|
||||
"source_sha256": "d105ccd3c0fac6a810e660789aaadf21f4267e1e1cd70dbab71a0e3c42213e39",
|
||||
"raw_excerpt": "(reverse charge: TVA 0 not printed)"
|
||||
},
|
||||
"totals.ttc": {
|
||||
"source_sha256": "d105ccd3c0fac6a810e660789aaadf21f4267e1e1cd70dbab71a0e3c42213e39",
|
||||
"raw_excerpt": "180"
|
||||
},
|
||||
"ref_supplier": {
|
||||
"source_sha256": "d105ccd3c0fac6a810e660789aaadf21f4267e1e1cd70dbab71a0e3c42213e39",
|
||||
"raw_excerpt": "9BF0758D-695749"
|
||||
},
|
||||
"date_issue": {
|
||||
"source_sha256": "d105ccd3c0fac6a810e660789aaadf21f4267e1e1cd70dbab71a0e3c42213e39",
|
||||
"raw_excerpt": "April 12, 2026"
|
||||
}
|
||||
}
|
||||
},
|
||||
"invariant_failures": [],
|
||||
"error": null
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
{
|
||||
"stage": "escalation",
|
||||
"flags": [],
|
||||
"legs": [
|
||||
{
|
||||
"runtime": "mlx",
|
||||
"model": "mlx-community/Qwen2.5-7B-Instruct-4bit",
|
||||
"valid": false,
|
||||
"validated": null,
|
||||
"invariant_failures": [
|
||||
"critical field absent: ref_supplier",
|
||||
"critical field absent: date_issue"
|
||||
],
|
||||
"error": null
|
||||
},
|
||||
{
|
||||
"runtime": "vibe",
|
||||
"model": "vibe-active-model",
|
||||
"valid": true,
|
||||
"validated": {
|
||||
"supplier": {
|
||||
"name": "Anthropic Ireland, Limited",
|
||||
"siren": null,
|
||||
"tva_intra": "IE4276970QH"
|
||||
},
|
||||
"ref_supplier": "9BF0758D-3321065",
|
||||
"date_issue": "2026-06-21",
|
||||
"date_due": null,
|
||||
"currency": "EUR",
|
||||
"per_rate": [
|
||||
{
|
||||
"rate": 0,
|
||||
"ht": 180.0,
|
||||
"tva": 0
|
||||
}
|
||||
],
|
||||
"totals": {
|
||||
"ht": 180.0,
|
||||
"tva": 0,
|
||||
"ttc": 180.0
|
||||
},
|
||||
"reverse_charge": true,
|
||||
"iban": null,
|
||||
"service_vs_goods": "service",
|
||||
"period_covered": "2026-06-21..2026-07-21",
|
||||
"provenance": {
|
||||
"totals.ht": {
|
||||
"source_sha256": "31b3723a68efdbb701ea1691cf197ee9c246993730a5c22474f246602c001c21",
|
||||
"raw_excerpt": "180"
|
||||
},
|
||||
"totals.tva": {
|
||||
"source_sha256": "31b3723a68efdbb701ea1691cf197ee9c246993730a5c22474f246602c001c21",
|
||||
"raw_excerpt": "(reverse charge: TVA 0 not printed)"
|
||||
},
|
||||
"totals.ttc": {
|
||||
"source_sha256": "31b3723a68efdbb701ea1691cf197ee9c246993730a5c22474f246602c001c21",
|
||||
"raw_excerpt": "180"
|
||||
},
|
||||
"ref_supplier": {
|
||||
"source_sha256": "31b3723a68efdbb701ea1691cf197ee9c246993730a5c22474f246602c001c21",
|
||||
"raw_excerpt": "9BF0758D-3321065"
|
||||
},
|
||||
"date_issue": {
|
||||
"source_sha256": "31b3723a68efdbb701ea1691cf197ee9c246993730a5c22474f246602c001c21",
|
||||
"raw_excerpt": "June 21, 2026"
|
||||
}
|
||||
}
|
||||
},
|
||||
"invariant_failures": [],
|
||||
"error": null
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
{
|
||||
"stage": "escalation",
|
||||
"flags": [
|
||||
"multi-iban: 2 distinct valid IBANs — IBAN choice must be escalated"
|
||||
],
|
||||
"legs": [
|
||||
{
|
||||
"runtime": "mlx",
|
||||
"model": "mlx-community/Qwen2.5-7B-Instruct-4bit",
|
||||
"valid": false,
|
||||
"validated": null,
|
||||
"invariant_failures": [
|
||||
"arithmetic: sum(per_rate.ht) != totals.ht"
|
||||
],
|
||||
"error": null
|
||||
},
|
||||
{
|
||||
"runtime": "vibe",
|
||||
"model": "vibe-active-model",
|
||||
"valid": true,
|
||||
"validated": {
|
||||
"supplier": {
|
||||
"name": "Darnis Operations",
|
||||
"siren": "920267531",
|
||||
"tva_intra": "FR51920267531"
|
||||
},
|
||||
"ref_supplier": "F1042",
|
||||
"date_issue": "2026-03-31",
|
||||
"date_due": "2026-03-31",
|
||||
"currency": "EUR",
|
||||
"per_rate": [
|
||||
{
|
||||
"rate": 20,
|
||||
"ht": 255.0,
|
||||
"tva": 51.0
|
||||
}
|
||||
],
|
||||
"totals": {
|
||||
"ht": 255.0,
|
||||
"tva": 51.0,
|
||||
"ttc": 306.0
|
||||
},
|
||||
"reverse_charge": false,
|
||||
"iban": "FR7616958000016837364325983",
|
||||
"service_vs_goods": "service",
|
||||
"period_covered": "2026-03",
|
||||
"provenance": {
|
||||
"totals.ht": {
|
||||
"source_sha256": "be30079c3fd5606c310616712ec17c0d97289eee548c85b9bc79df76b5332e25",
|
||||
"raw_excerpt": "255"
|
||||
},
|
||||
"totals.tva": {
|
||||
"source_sha256": "be30079c3fd5606c310616712ec17c0d97289eee548c85b9bc79df76b5332e25",
|
||||
"raw_excerpt": "51"
|
||||
},
|
||||
"totals.ttc": {
|
||||
"source_sha256": "be30079c3fd5606c310616712ec17c0d97289eee548c85b9bc79df76b5332e25",
|
||||
"raw_excerpt": "306"
|
||||
},
|
||||
"ref_supplier": {
|
||||
"source_sha256": "be30079c3fd5606c310616712ec17c0d97289eee548c85b9bc79df76b5332e25",
|
||||
"raw_excerpt": "F1042"
|
||||
},
|
||||
"date_issue": {
|
||||
"source_sha256": "be30079c3fd5606c310616712ec17c0d97289eee548c85b9bc79df76b5332e25",
|
||||
"raw_excerpt": "31/03/2026"
|
||||
},
|
||||
"date_due": {
|
||||
"source_sha256": "be30079c3fd5606c310616712ec17c0d97289eee548c85b9bc79df76b5332e25",
|
||||
"raw_excerpt": "31/03/2026"
|
||||
},
|
||||
"iban": {
|
||||
"source_sha256": "be30079c3fd5606c310616712ec17c0d97289eee548c85b9bc79df76b5332e25",
|
||||
"raw_excerpt": "FR7616958000016837364325983"
|
||||
}
|
||||
}
|
||||
},
|
||||
"invariant_failures": [],
|
||||
"error": null
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
{
|
||||
"stage": "escalation",
|
||||
"flags": [],
|
||||
"legs": [
|
||||
{
|
||||
"runtime": "mlx",
|
||||
"model": "mlx-community/Qwen2.5-7B-Instruct-4bit",
|
||||
"valid": false,
|
||||
"validated": null,
|
||||
"invariant_failures": [
|
||||
"rate 1 outside [0, 2.1, 5.5, 10, 20] without reverse_charge",
|
||||
"rate 1 outside [0, 2.1, 5.5, 10, 20] without reverse_charge",
|
||||
"rate 1 outside [0, 2.1, 5.5, 10, 20] without reverse_charge",
|
||||
"rate 1 outside [0, 2.1, 5.5, 10, 20] without reverse_charge",
|
||||
"rate 1 outside [0, 2.1, 5.5, 10, 20] without reverse_charge"
|
||||
],
|
||||
"error": null
|
||||
},
|
||||
{
|
||||
"runtime": "vibe",
|
||||
"model": "vibe-active-model",
|
||||
"valid": true,
|
||||
"validated": {
|
||||
"supplier": {
|
||||
"name": "GREFFE D'EVRY",
|
||||
"siren": null,
|
||||
"tva_intra": null
|
||||
},
|
||||
"ref_supplier": "J00205614779",
|
||||
"date_issue": "2026-01-09",
|
||||
"date_due": null,
|
||||
"currency": "EUR",
|
||||
"per_rate": [
|
||||
{
|
||||
"rate": 20,
|
||||
"ht": 46.61,
|
||||
"tva": 9.32
|
||||
}
|
||||
],
|
||||
"totals": {
|
||||
"ht": 46.61,
|
||||
"tva": 9.32,
|
||||
"ttc": 55.93
|
||||
},
|
||||
"reverse_charge": false,
|
||||
"iban": null,
|
||||
"service_vs_goods": "service",
|
||||
"period_covered": null,
|
||||
"provenance": {
|
||||
"totals.ht": {
|
||||
"source_sha256": "6de23abd4bd18613741c6e42950b6be2fc3e269d0e6abbd8a3e20e38de99c9a3",
|
||||
"raw_excerpt": "46,61"
|
||||
},
|
||||
"totals.tva": {
|
||||
"source_sha256": "6de23abd4bd18613741c6e42950b6be2fc3e269d0e6abbd8a3e20e38de99c9a3",
|
||||
"raw_excerpt": "9,32"
|
||||
},
|
||||
"totals.ttc": {
|
||||
"source_sha256": "6de23abd4bd18613741c6e42950b6be2fc3e269d0e6abbd8a3e20e38de99c9a3",
|
||||
"raw_excerpt": "55,93"
|
||||
},
|
||||
"ref_supplier": {
|
||||
"source_sha256": "6de23abd4bd18613741c6e42950b6be2fc3e269d0e6abbd8a3e20e38de99c9a3",
|
||||
"raw_excerpt": "J00205614779"
|
||||
},
|
||||
"date_issue": {
|
||||
"source_sha256": "6de23abd4bd18613741c6e42950b6be2fc3e269d0e6abbd8a3e20e38de99c9a3",
|
||||
"raw_excerpt": "09/01/2026"
|
||||
}
|
||||
}
|
||||
},
|
||||
"invariant_failures": [],
|
||||
"error": null
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
{
|
||||
"stage": "escalation",
|
||||
"flags": [],
|
||||
"legs": [
|
||||
{
|
||||
"runtime": "mlx",
|
||||
"model": "mlx-community/Qwen2.5-7B-Instruct-4bit",
|
||||
"valid": false,
|
||||
"validated": null,
|
||||
"invariant_failures": [
|
||||
"rate 1.08 outside [0, 2.1, 5.5, 10, 20] without reverse_charge"
|
||||
],
|
||||
"error": null
|
||||
},
|
||||
{
|
||||
"runtime": "vibe",
|
||||
"model": "vibe-active-model",
|
||||
"valid": true,
|
||||
"validated": {
|
||||
"supplier": {
|
||||
"name": "GREFFE D'EVRY",
|
||||
"siren": null,
|
||||
"tva_intra": null
|
||||
},
|
||||
"ref_supplier": "J00205614779",
|
||||
"date_issue": "2026-01-15",
|
||||
"date_due": null,
|
||||
"currency": "EUR",
|
||||
"per_rate": [
|
||||
{
|
||||
"rate": 20,
|
||||
"ht": 1.08,
|
||||
"tva": 0.22
|
||||
}
|
||||
],
|
||||
"totals": {
|
||||
"ht": 1.08,
|
||||
"tva": 0.22,
|
||||
"ttc": 1.3
|
||||
},
|
||||
"reverse_charge": false,
|
||||
"iban": null,
|
||||
"service_vs_goods": "service",
|
||||
"period_covered": null,
|
||||
"provenance": {
|
||||
"totals.ht": {
|
||||
"source_sha256": "48ff6657dfc9ae5ea056cbdb97727cfd69dc92a850817b026e4027da26873928",
|
||||
"raw_excerpt": "1,08"
|
||||
},
|
||||
"totals.tva": {
|
||||
"source_sha256": "48ff6657dfc9ae5ea056cbdb97727cfd69dc92a850817b026e4027da26873928",
|
||||
"raw_excerpt": "0,22"
|
||||
},
|
||||
"totals.ttc": {
|
||||
"source_sha256": "48ff6657dfc9ae5ea056cbdb97727cfd69dc92a850817b026e4027da26873928",
|
||||
"raw_excerpt": "1,30"
|
||||
},
|
||||
"ref_supplier": {
|
||||
"source_sha256": "48ff6657dfc9ae5ea056cbdb97727cfd69dc92a850817b026e4027da26873928",
|
||||
"raw_excerpt": "J00205614779"
|
||||
},
|
||||
"date_issue": {
|
||||
"source_sha256": "48ff6657dfc9ae5ea056cbdb97727cfd69dc92a850817b026e4027da26873928",
|
||||
"raw_excerpt": "15/01/2026"
|
||||
}
|
||||
}
|
||||
},
|
||||
"invariant_failures": [],
|
||||
"error": null
|
||||
}
|
||||
]
|
||||
}
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
{
|
||||
"stage": "escalation",
|
||||
"flags": [],
|
||||
"legs": [
|
||||
{
|
||||
"runtime": "mlx",
|
||||
"model": "mlx-community/Qwen2.5-7B-Instruct-4bit",
|
||||
"valid": true,
|
||||
"validated": {
|
||||
"supplier": {
|
||||
"name": "Mistral AI SAS",
|
||||
"siren": "952418325",
|
||||
"tva_intra": null
|
||||
},
|
||||
"ref_supplier": "MSTRL-API-814045-001",
|
||||
"date_issue": "2026-04-02",
|
||||
"date_due": "2026-04-02",
|
||||
"currency": "EUR",
|
||||
"per_rate": [
|
||||
{
|
||||
"rate": 20.0,
|
||||
"ht": 143.9,
|
||||
"tva": 28.78
|
||||
}
|
||||
],
|
||||
"totals": {
|
||||
"ht": 143.9,
|
||||
"tva": 28.78,
|
||||
"ttc": 172.68
|
||||
},
|
||||
"reverse_charge": false,
|
||||
"iban": null,
|
||||
"service_vs_goods": "service",
|
||||
"period_covered": "2026-04",
|
||||
"provenance": {
|
||||
"totals.ht": {
|
||||
"source_sha256": "892afe9d7e8f96f1debad9685f7b7ec88a826c53ab8993751ce7803c5bd7ba3f",
|
||||
"raw_excerpt": "143,90"
|
||||
},
|
||||
"totals.tva": {
|
||||
"source_sha256": "892afe9d7e8f96f1debad9685f7b7ec88a826c53ab8993751ce7803c5bd7ba3f",
|
||||
"raw_excerpt": "28,78"
|
||||
},
|
||||
"totals.ttc": {
|
||||
"source_sha256": "892afe9d7e8f96f1debad9685f7b7ec88a826c53ab8993751ce7803c5bd7ba3f",
|
||||
"raw_excerpt": "172,68"
|
||||
},
|
||||
"ref_supplier": {
|
||||
"source_sha256": "892afe9d7e8f96f1debad9685f7b7ec88a826c53ab8993751ce7803c5bd7ba3f",
|
||||
"raw_excerpt": "MSTRL-API-814045-001"
|
||||
},
|
||||
"date_issue": {
|
||||
"source_sha256": "892afe9d7e8f96f1debad9685f7b7ec88a826c53ab8993751ce7803c5bd7ba3f",
|
||||
"raw_excerpt": "2 avr. 2026"
|
||||
},
|
||||
"date_due": {
|
||||
"source_sha256": "892afe9d7e8f96f1debad9685f7b7ec88a826c53ab8993751ce7803c5bd7ba3f",
|
||||
"raw_excerpt": "2 avr. 2026"
|
||||
}
|
||||
}
|
||||
},
|
||||
"invariant_failures": [],
|
||||
"error": null
|
||||
},
|
||||
{
|
||||
"runtime": "vibe",
|
||||
"model": null,
|
||||
"valid": false,
|
||||
"validated": null,
|
||||
"invariant_failures": null,
|
||||
"error": "Command '['vibe', '-p', '# invoice-extract — runtime prompt\\n\\nExtends the [extractor class skeleton](../../classes/extractor.md): its mission,\\ntool posture (zero credentials, zero action tools), escalation path and\\ninvariants apply unchanged. Business rules do **not** live here — VAT treatment\\na"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
{
|
||||
"stage": "escalation",
|
||||
"flags": [],
|
||||
"legs": [
|
||||
{
|
||||
"runtime": "mlx",
|
||||
"model": "mlx-community/Qwen2.5-7B-Instruct-4bit",
|
||||
"valid": false,
|
||||
"validated": null,
|
||||
"invariant_failures": null,
|
||||
"error": null
|
||||
},
|
||||
{
|
||||
"runtime": "vibe",
|
||||
"model": "vibe-active-model",
|
||||
"valid": true,
|
||||
"validated": {
|
||||
"supplier": {
|
||||
"name": "OVH",
|
||||
"siren": "424761419",
|
||||
"tva_intra": "FR22424761419"
|
||||
},
|
||||
"ref_supplier": "FR73261832",
|
||||
"date_issue": "2025-10-24",
|
||||
"date_due": null,
|
||||
"currency": "EUR",
|
||||
"per_rate": [
|
||||
{
|
||||
"rate": 20,
|
||||
"ht": 6.08,
|
||||
"tva": 1.22
|
||||
}
|
||||
],
|
||||
"totals": {
|
||||
"ht": 6.08,
|
||||
"tva": 1.22,
|
||||
"ttc": 7.3
|
||||
},
|
||||
"reverse_charge": false,
|
||||
"iban": "FR7630056005030503000004147",
|
||||
"service_vs_goods": "service",
|
||||
"period_covered": null,
|
||||
"provenance": {
|
||||
"totals.ht": {
|
||||
"source_sha256": "697324cea8679c63df7730c5f1b65b379e7fbc7ed7ac24caa9691bd923cba45a",
|
||||
"raw_excerpt": "6,08"
|
||||
},
|
||||
"totals.tva": {
|
||||
"source_sha256": "697324cea8679c63df7730c5f1b65b379e7fbc7ed7ac24caa9691bd923cba45a",
|
||||
"raw_excerpt": "1,22"
|
||||
},
|
||||
"totals.ttc": {
|
||||
"source_sha256": "697324cea8679c63df7730c5f1b65b379e7fbc7ed7ac24caa9691bd923cba45a",
|
||||
"raw_excerpt": "7,30"
|
||||
},
|
||||
"ref_supplier": {
|
||||
"source_sha256": "697324cea8679c63df7730c5f1b65b379e7fbc7ed7ac24caa9691bd923cba45a",
|
||||
"raw_excerpt": "FR73261832"
|
||||
},
|
||||
"date_issue": {
|
||||
"source_sha256": "697324cea8679c63df7730c5f1b65b379e7fbc7ed7ac24caa9691bd923cba45a",
|
||||
"raw_excerpt": "24/10/2025"
|
||||
},
|
||||
"iban": {
|
||||
"source_sha256": "697324cea8679c63df7730c5f1b65b379e7fbc7ed7ac24caa9691bd923cba45a",
|
||||
"raw_excerpt": "FR76 3005 6005 0305 0300 0004 147"
|
||||
}
|
||||
}
|
||||
},
|
||||
"invariant_failures": [],
|
||||
"error": null
|
||||
}
|
||||
]
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"stage": "escalation",
|
||||
"reason": "both-legs-invalid",
|
||||
"legs": [
|
||||
{
|
||||
"runtime": "mlx",
|
||||
"model": "mlx-community/Qwen2.5-7B-Instruct-4bit",
|
||||
"valid": false,
|
||||
"invariant_failures": [
|
||||
"provenance: ref_supplier='06-01-26-payment-366753' not found literally in source text"
|
||||
],
|
||||
"error": null
|
||||
},
|
||||
{
|
||||
"runtime": "vibe",
|
||||
"model": null,
|
||||
"valid": false,
|
||||
"invariant_failures": null,
|
||||
"error": "Command '['vibe', '-p', '# invoice-extract — runtime prompt\\n\\nExtends the [extractor class skeleton](../../classes/extractor.md): its mission,\\ntool posture (zero credentials, zero action tools), escalation path and\\ninvariants apply unchanged. Business rules do **not** live here — VAT treatment\\na"
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user