Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
|
@@ -48,12 +48,19 @@ from huggingface_hub import hf_hub_download
|
|
| 48 |
# alongside this file in the same Space for this import to work.
|
| 49 |
from structural_patterns import scan_structural_patterns, structural_flags_to_dict
|
| 50 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 51 |
# ββ App ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 52 |
app = FastAPI(
|
| 53 |
title = "MACI β Muslim AI Content Intelligence",
|
| 54 |
description = "Shariah compliance classifier v5.5 β institutional grade. "
|
| 55 |
"Full Terry v0.1 Signal Packet + Phase 2 Maqasid enrichment "
|
| 56 |
-
"+ Phase 3 jurisdiction overlay + Phase 4 structural patterns
|
|
|
|
| 57 |
version = "5.5",
|
| 58 |
)
|
| 59 |
app.add_middleware(CORSMiddleware, allow_origins=["*"],
|
|
@@ -134,6 +141,23 @@ SEV = {
|
|
| 134 |
(7,"HIGH"):"HIGH", (7,"MEDIUM"):"MEDIUM", (7,"LOW"):"LOW",
|
| 135 |
}
|
| 136 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 137 |
# ββ Phase 2: Maqasid + consequence ββββββββββββββββββββββββββββ
|
| 138 |
CONSEQUENCE_TABLE = {
|
| 139 |
0:{"maqasid_pillar":"Hifz al-Mal","maqasid_meaning":"Protection of Wealth",
|
|
@@ -614,6 +638,118 @@ def classify(text: str, context: str = "general",
|
|
| 614 |
if structural_override_reason:
|
| 615 |
review_reason = structural_override_reason
|
| 616 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 617 |
# Phase 2 enrichment
|
| 618 |
conseq = CONSEQUENCE_TABLE[pred]
|
| 619 |
altmap = ALTERNATIVE_MAP[pred]
|
|
@@ -624,6 +760,21 @@ def classify(text: str, context: str = "general",
|
|
| 624 |
if partial and not disclaimer:
|
| 625 |
disclaimer = "Farsi/Tajik input β partial coverage. Scholar review recommended."
|
| 626 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 627 |
# Phase 3 jurisdiction
|
| 628 |
juris_data = JURISDICTION_EXPOSURE.get(pred, {})
|
| 629 |
jurisdiction_recognized = jurisdiction in juris_data
|
|
@@ -675,9 +826,9 @@ def classify(text: str, context: str = "general",
|
|
| 675 |
"economic_signal" : econ_signal,
|
| 676 |
"action_required" : (conseq["action_required"]
|
| 677 |
if tier=="HIGH" else "human_review_first"),
|
| 678 |
-
"compliant_alternative":
|
| 679 |
-
"structural_fix" :
|
| 680 |
-
"aaoifi_standard" :
|
| 681 |
},
|
| 682 |
|
| 683 |
# Phase 3: Jurisdiction
|
|
@@ -698,7 +849,7 @@ def classify(text: str, context: str = "general",
|
|
| 698 |
} if pred != 0 else "compliant β no exposure",
|
| 699 |
},
|
| 700 |
|
| 701 |
-
#
|
| 702 |
"structural_pattern_flags": {
|
| 703 |
"layer_type": "rule-based structural detection (Phase 4)",
|
| 704 |
"note": (
|
|
@@ -711,12 +862,17 @@ def classify(text: str, context: str = "general",
|
|
| 711 |
"1500-char truncation applied to the ML layer below. Coverage is "
|
| 712 |
"limited to the patterns currently defined β absence of a flag "
|
| 713 |
"here is NOT confirmation of structural compliance, only that none "
|
| 714 |
-
"of the currently-modeled red-flag patterns matched."
|
|
|
|
|
|
|
| 715 |
),
|
| 716 |
"flags": structural_flags_list,
|
| 717 |
"flag_count": len(structural_flags_list),
|
| 718 |
},
|
| 719 |
|
|
|
|
|
|
|
|
|
|
| 720 |
# Overclaiming controls
|
| 721 |
"overclaiming_controls" : {
|
| 722 |
"severity_is_confidence_modulated": True,
|
|
@@ -728,6 +884,8 @@ def classify(text: str, context: str = "general",
|
|
| 728 |
"original_char_count" : original_length,
|
| 729 |
"structural_layer_overrode_ml_verdict": bool(structural_override_reason),
|
| 730 |
"structural_override_reason": structural_override_reason,
|
|
|
|
|
|
|
| 731 |
},
|
| 732 |
|
| 733 |
"boundary_behavior" : {
|
|
@@ -769,6 +927,7 @@ def classify(text: str, context: str = "general",
|
|
| 769 |
"exposure" : juris_info.get("exposure","unknown"),
|
| 770 |
"truncated" : was_truncated,
|
| 771 |
"structural_flags": len(structural_flags_list),
|
|
|
|
| 772 |
"audit_hash" : f"sha256:{phash[:16]}...",
|
| 773 |
},
|
| 774 |
|
|
@@ -794,6 +953,10 @@ def root():
|
|
| 794 |
"(Bay' al-Inah, disguised Riba late-fee, "
|
| 795 |
"unilateral price variation, risk/ownership "
|
| 796 |
"decoupling, total liability waiver)",
|
|
|
|
|
|
|
|
|
|
|
|
|
| 797 |
"endpoints" : {
|
| 798 |
"single" : "POST /api/v1/classify",
|
| 799 |
"batch" : "POST /api/v1/classify/batch",
|
|
@@ -817,6 +980,7 @@ def health():
|
|
| 817 |
"ml_f1" : 0.9026,
|
| 818 |
"rulings" : len(STATE.get("rulings",[])),
|
| 819 |
"structural_pattern_layer": "active",
|
|
|
|
| 820 |
}
|
| 821 |
|
| 822 |
@app.post(
|
|
@@ -830,7 +994,7 @@ def health():
|
|
| 830 |
"Returns the full MACI-0.4 signal packet, including "
|
| 831 |
"maqasid_enrichment (AAOIFI standard, structural fix, "
|
| 832 |
"compliant alternative), jurisdiction_overlay, "
|
| 833 |
-
"structural_pattern_flags, and overclaiming_controls."
|
| 834 |
)
|
| 835 |
def classify_endpoint(req: ClassifyRequest):
|
| 836 |
if "xlmr" not in STATE:
|
|
@@ -982,4 +1146,4 @@ def classify_audit(req: AuditRequest):
|
|
| 982 |
"mechanism_results": results,
|
| 983 |
|
| 984 |
"audit_hash" : f"sha256:{audit_hash}",
|
| 985 |
-
}
|
|
|
|
| 48 |
# alongside this file in the same Space for this import to work.
|
| 49 |
from structural_patterns import scan_structural_patterns, structural_flags_to_dict
|
| 50 |
|
| 51 |
+
# NEW: Phase 5 reconciliation layer β upload reconciliation.py alongside
|
| 52 |
+
# this file too. Only scan_hard_negatives is used here; the structural
|
| 53 |
+
# override itself is handled inline below because it needs to update
|
| 54 |
+
# `pred` before Phase 2/3 enrichment run later in this same function.
|
| 55 |
+
from reconciliation import scan_hard_negatives
|
| 56 |
+
|
| 57 |
# ββ App ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 58 |
app = FastAPI(
|
| 59 |
title = "MACI β Muslim AI Content Intelligence",
|
| 60 |
description = "Shariah compliance classifier v5.5 β institutional grade. "
|
| 61 |
"Full Terry v0.1 Signal Packet + Phase 2 Maqasid enrichment "
|
| 62 |
+
"+ Phase 3 jurisdiction overlay + Phase 4 structural patterns "
|
| 63 |
+
"+ Phase 5 reconciliation.",
|
| 64 |
version = "5.5",
|
| 65 |
)
|
| 66 |
app.add_middleware(CORSMiddleware, allow_origins=["*"],
|
|
|
|
| 141 |
(7,"HIGH"):"HIGH", (7,"MEDIUM"):"MEDIUM", (7,"LOW"):"LOW",
|
| 142 |
}
|
| 143 |
|
| 144 |
+
# NEW (Phase 5): maps each structural pattern to the closest existing
|
| 145 |
+
# `pred` class id. This is what lets a structural override also correct
|
| 146 |
+
# maqasid_enrichment (Phase 2) and jurisdiction_overlay (Phase 3) below β
|
| 147 |
+
# both of those blocks key off `pred`, and both run AFTER this mapping is
|
| 148 |
+
# applied, so getting this mapping right means the whole rest of the
|
| 149 |
+
# packet (pillar, AAOIFI standard, jurisdiction exposure/penalty) becomes
|
| 150 |
+
# consistent with the corrected verdict automatically, not just the
|
| 151 |
+
# top-line violation_class field.
|
| 152 |
+
STRUCTURAL_PATTERN_TO_PRED = {
|
| 153 |
+
"SP-01": 1, # Bay' al-Inah buy-back -> Riba (disguised loan)
|
| 154 |
+
"SP-02": 1, # Disguised Riba late-payment-income -> Riba
|
| 155 |
+
"SP-03": 2, # Unilateral price variation -> Gharar
|
| 156 |
+
"SP-04": 2, # Risk/ownership decoupling -> Gharar
|
| 157 |
+
"SP-05": 2, # Total liability waiver -> Gharar (closest of the 8 classes)
|
| 158 |
+
}
|
| 159 |
+
STRUCTURAL_SEVERITY_RANK = {"LOW":1, "MEDIUM":2, "HIGH":3, "CRITICAL":4}
|
| 160 |
+
|
| 161 |
# ββ Phase 2: Maqasid + consequence ββββββββββββββββββββββββββββ
|
| 162 |
CONSEQUENCE_TABLE = {
|
| 163 |
0:{"maqasid_pillar":"Hifz al-Mal","maqasid_meaning":"Protection of Wealth",
|
|
|
|
| 638 |
if structural_override_reason:
|
| 639 |
review_reason = structural_override_reason
|
| 640 |
|
| 641 |
+
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 642 |
+
# NEW β PHASE 5: RECONCILIATION LAYER
|
| 643 |
+
#
|
| 644 |
+
# The Phase 4 block above only ever touched `recommendation` β
|
| 645 |
+
# the top-line `violation_class` / `severity` / `result` fields
|
| 646 |
+
# that the frontend actually displays still came straight from
|
| 647 |
+
# the ML layer untouched. That's what caused the demo to show
|
| 648 |
+
# "Authentic / NONE" on a real Arabic Bay'-al-Inah buy-back and
|
| 649 |
+
# a real Urdu risk/ownership-decoupling clause even though the
|
| 650 |
+
# structural layer had already matched them correctly β the
|
| 651 |
+
# match existed in structural_pattern_flags, but nothing
|
| 652 |
+
# upstream of it was told to care.
|
| 653 |
+
#
|
| 654 |
+
# This block does two things, and only these two things:
|
| 655 |
+
#
|
| 656 |
+
# (a) STRUCTURAL OVERRIDE β if a structural pattern matched,
|
| 657 |
+
# it now overrides pred/label/conf/tier/verdict/terry/
|
| 658 |
+
# severity themselves, not just recommendation. Because
|
| 659 |
+
# this runs BEFORE the Phase 2/3 enrichment sections below
|
| 660 |
+
# (which key off `pred`), the pillar, AAOIFI standard, and
|
| 661 |
+
# jurisdiction exposure/penalty all become consistent with
|
| 662 |
+
# the corrected verdict automatically β no separate mapping
|
| 663 |
+
# needed for those sections.
|
| 664 |
+
#
|
| 665 |
+
# (b) HARD-NEGATIVE DOWNGRADE β only when NO structural pattern
|
| 666 |
+
# matched, and the ML layer flagged a violation, checks a
|
| 667 |
+
# narrow set of known-compliant patterns (currently one:
|
| 668 |
+
# CHN-01, the AAOIFI-permitted actual-loss indemnity formula
|
| 669 |
+
# that was mis-flagged as Gharar/HIGH during pre-meeting
|
| 670 |
+
# testing). A match downgrades the verdict to
|
| 671 |
+
# REVIEW_REQUIRED β never silently back to AUTHENTIC. A
|
| 672 |
+
# human still confirms; the system just stops presenting a
|
| 673 |
+
# compliant clause as a confirmed violation.
|
| 674 |
+
#
|
| 675 |
+
# Neither path touches the base model's weights. Both are
|
| 676 |
+
# deterministic, narrow, and fully logged in `reconciliation`
|
| 677 |
+
# below so the audit trail always shows which layer produced the
|
| 678 |
+
# final call.
|
| 679 |
+
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 680 |
+
reconciliation = {
|
| 681 |
+
"applied" : False,
|
| 682 |
+
"source" : None,
|
| 683 |
+
"reason" : None,
|
| 684 |
+
"original_ml_violation_class": label,
|
| 685 |
+
"original_ml_severity" : severity,
|
| 686 |
+
"original_ml_confidence" : round(conf, 4),
|
| 687 |
+
}
|
| 688 |
+
|
| 689 |
+
if structural_flags_list:
|
| 690 |
+
top = max(
|
| 691 |
+
structural_flags_list,
|
| 692 |
+
key=lambda f: STRUCTURAL_SEVERITY_RANK.get(f["severity"], 0),
|
| 693 |
+
)
|
| 694 |
+
mapped_pred = STRUCTURAL_PATTERN_TO_PRED.get(top["pattern_id"])
|
| 695 |
+
|
| 696 |
+
if mapped_pred is not None:
|
| 697 |
+
pred = mapped_pred
|
| 698 |
+
label = f"{LABEL_NAMES[mapped_pred]} β {top['name']}"
|
| 699 |
+
conf = max(conf, 0.95) # deterministic match β high confidence by construction
|
| 700 |
+
tier = "HIGH"
|
| 701 |
+
verdict = "VIOLATION"
|
| 702 |
+
terry = "FLAGGED"
|
| 703 |
+
severity = top["severity"]
|
| 704 |
+
|
| 705 |
+
reconciliation.update({
|
| 706 |
+
"applied": True,
|
| 707 |
+
"source" : "structural_override",
|
| 708 |
+
"reason" : (
|
| 709 |
+
f"Deterministic structural pattern {top['pattern_id']} "
|
| 710 |
+
f"({top['name']}) matched. This overrides the base "
|
| 711 |
+
f"classifier's verdict for this text regardless of "
|
| 712 |
+
f"language β structural patterns are validated directly "
|
| 713 |
+
f"against SRB findings and are trusted over a "
|
| 714 |
+
f"probabilistic language-signal miss."
|
| 715 |
+
),
|
| 716 |
+
"structural_matches": [f["pattern_id"] for f in structural_flags_list],
|
| 717 |
+
})
|
| 718 |
+
|
| 719 |
+
elif verdict == "VIOLATION":
|
| 720 |
+
hard_negative = scan_hard_negatives(text, label, severity)
|
| 721 |
+
if hard_negative is not None:
|
| 722 |
+
severity = "LOW"
|
| 723 |
+
verdict = "REVIEW_REQUIRED"
|
| 724 |
+
terry = "UNCERTAIN"
|
| 725 |
+
needs_review = True
|
| 726 |
+
recommendation = "REVIEW"
|
| 727 |
+
review_reason = f"hard_negative_pattern_match:{hard_negative.pattern_id}"
|
| 728 |
+
|
| 729 |
+
reconciliation.update({
|
| 730 |
+
"applied": True,
|
| 731 |
+
"source" : "hard_negative_downgrade",
|
| 732 |
+
"reason" : (
|
| 733 |
+
f"Base classifier flagged '{reconciliation['original_ml_violation_class']}' "
|
| 734 |
+
f"({reconciliation['original_ml_severity']}), but this text matches known "
|
| 735 |
+
f"AAOIFI-compliant pattern {hard_negative.pattern_id} "
|
| 736 |
+
f"({hard_negative.name}). Downgraded to REVIEW_REQUIRED β "
|
| 737 |
+
f"a human confirms, the system does not self-clear to Authentic."
|
| 738 |
+
),
|
| 739 |
+
"hard_negative_match": hard_negative.pattern_id,
|
| 740 |
+
"hard_negative_aaoifi_standard": hard_negative.aaoifi_standard,
|
| 741 |
+
})
|
| 742 |
+
|
| 743 |
+
# Recompute movement + recommendation now that pred/verdict/severity
|
| 744 |
+
# may have changed above, so downstream fields stay consistent.
|
| 745 |
+
mv = MOVE[pred]
|
| 746 |
+
if verdict in ("AUTHENTIC","PASS"): mv = "deliver_output_to_user"
|
| 747 |
+
if severity=="CRITICAL" and verdict=="VIOLATION": mv = "quarantine_output"
|
| 748 |
+
|
| 749 |
+
if reconciliation["source"] == "structural_override":
|
| 750 |
+
recommendation = "QUARANTINE" if severity == "CRITICAL" else "ESCALATE"
|
| 751 |
+
needs_review = True
|
| 752 |
+
|
| 753 |
# Phase 2 enrichment
|
| 754 |
conseq = CONSEQUENCE_TABLE[pred]
|
| 755 |
altmap = ALTERNATIVE_MAP[pred]
|
|
|
|
| 760 |
if partial and not disclaimer:
|
| 761 |
disclaimer = "Farsi/Tajik input β partial coverage. Scholar review recommended."
|
| 762 |
|
| 763 |
+
# NEW (Phase 5): when a structural override fired, use that pattern's
|
| 764 |
+
# own AAOIFI citation and explanation instead of the generic per-class
|
| 765 |
+
# ALTERNATIVE_MAP entry β it's more specific to the actual clause than
|
| 766 |
+
# the class-level default.
|
| 767 |
+
compliant_alternative = altmap["primary"]
|
| 768 |
+
structural_fix = altmap["structural_fix"]
|
| 769 |
+
aaoifi_standard = altmap["aaoifi_standard"]
|
| 770 |
+
if reconciliation["source"] == "structural_override":
|
| 771 |
+
aaoifi_standard = top["aaoifi_standard"]
|
| 772 |
+
structural_fix = top["explanation"]
|
| 773 |
+
elif reconciliation["source"] == "hard_negative_downgrade":
|
| 774 |
+
aaoifi_standard = hard_negative.aaoifi_standard
|
| 775 |
+
compliant_alternative = "No change required β matches a recognized AAOIFI-compliant pattern"
|
| 776 |
+
structural_fix = hard_negative.explanation
|
| 777 |
+
|
| 778 |
# Phase 3 jurisdiction
|
| 779 |
juris_data = JURISDICTION_EXPOSURE.get(pred, {})
|
| 780 |
jurisdiction_recognized = jurisdiction in juris_data
|
|
|
|
| 826 |
"economic_signal" : econ_signal,
|
| 827 |
"action_required" : (conseq["action_required"]
|
| 828 |
if tier=="HIGH" else "human_review_first"),
|
| 829 |
+
"compliant_alternative": compliant_alternative,
|
| 830 |
+
"structural_fix" : structural_fix,
|
| 831 |
+
"aaoifi_standard" : aaoifi_standard,
|
| 832 |
},
|
| 833 |
|
| 834 |
# Phase 3: Jurisdiction
|
|
|
|
| 849 |
} if pred != 0 else "compliant β no exposure",
|
| 850 |
},
|
| 851 |
|
| 852 |
+
# Phase 4: Structural pattern layer
|
| 853 |
"structural_pattern_flags": {
|
| 854 |
"layer_type": "rule-based structural detection (Phase 4)",
|
| 855 |
"note": (
|
|
|
|
| 862 |
"1500-char truncation applied to the ML layer below. Coverage is "
|
| 863 |
"limited to the patterns currently defined β absence of a flag "
|
| 864 |
"here is NOT confirmation of structural compliance, only that none "
|
| 865 |
+
"of the currently-modeled red-flag patterns matched. As of Phase 5, "
|
| 866 |
+
"a match here also overrides maci_evaluation directly β see "
|
| 867 |
+
"`reconciliation` below."
|
| 868 |
),
|
| 869 |
"flags": structural_flags_list,
|
| 870 |
"flag_count": len(structural_flags_list),
|
| 871 |
},
|
| 872 |
|
| 873 |
+
# NEW β Phase 5: Reconciliation layer
|
| 874 |
+
"reconciliation": reconciliation,
|
| 875 |
+
|
| 876 |
# Overclaiming controls
|
| 877 |
"overclaiming_controls" : {
|
| 878 |
"severity_is_confidence_modulated": True,
|
|
|
|
| 884 |
"original_char_count" : original_length,
|
| 885 |
"structural_layer_overrode_ml_verdict": bool(structural_override_reason),
|
| 886 |
"structural_override_reason": structural_override_reason,
|
| 887 |
+
"reconciliation_applied": reconciliation["applied"],
|
| 888 |
+
"reconciliation_source": reconciliation["source"],
|
| 889 |
},
|
| 890 |
|
| 891 |
"boundary_behavior" : {
|
|
|
|
| 927 |
"exposure" : juris_info.get("exposure","unknown"),
|
| 928 |
"truncated" : was_truncated,
|
| 929 |
"structural_flags": len(structural_flags_list),
|
| 930 |
+
"reconciliation_applied": reconciliation["applied"],
|
| 931 |
"audit_hash" : f"sha256:{phash[:16]}...",
|
| 932 |
},
|
| 933 |
|
|
|
|
| 953 |
"(Bay' al-Inah, disguised Riba late-fee, "
|
| 954 |
"unilateral price variation, risk/ownership "
|
| 955 |
"decoupling, total liability waiver)",
|
| 956 |
+
"reconciliation_layer": "Phase 5 β structural patterns override "
|
| 957 |
+
"maci_evaluation directly; one hard-negative "
|
| 958 |
+
"pattern (CHN-01, actual-loss indemnity) "
|
| 959 |
+
"downgrades known false positives to REVIEW_REQUIRED",
|
| 960 |
"endpoints" : {
|
| 961 |
"single" : "POST /api/v1/classify",
|
| 962 |
"batch" : "POST /api/v1/classify/batch",
|
|
|
|
| 980 |
"ml_f1" : 0.9026,
|
| 981 |
"rulings" : len(STATE.get("rulings",[])),
|
| 982 |
"structural_pattern_layer": "active",
|
| 983 |
+
"reconciliation_layer": "active",
|
| 984 |
}
|
| 985 |
|
| 986 |
@app.post(
|
|
|
|
| 994 |
"Returns the full MACI-0.4 signal packet, including "
|
| 995 |
"maqasid_enrichment (AAOIFI standard, structural fix, "
|
| 996 |
"compliant alternative), jurisdiction_overlay, "
|
| 997 |
+
"structural_pattern_flags, reconciliation, and overclaiming_controls."
|
| 998 |
)
|
| 999 |
def classify_endpoint(req: ClassifyRequest):
|
| 1000 |
if "xlmr" not in STATE:
|
|
|
|
| 1146 |
"mechanism_results": results,
|
| 1147 |
|
| 1148 |
"audit_hash" : f"sha256:{audit_hash}",
|
| 1149 |
+
}
|