From the UX review — flagged by all four personas as the "toy → real" gap.
Problem
Every hero example leans on the weakest rule (the three-keyword SensitiveDataFilter). The genuinely strong, verifiable mechanism — URLAllowList: default-deny, blocks userinfo tricks like http://api.internal.com@evil.com, rejects file://, walks nested containers — is described (line 111) but never shown in code.
This is also the make-or-break bridge for adoption: line 32 tells the developer to "write your own rules and pass your own engine," but no code anywhere shows how. defense_demo.py exists and does exactly this, but the README doesn't inline it.
Fix
Add a short runnable block (verify the import surface against src/modelfuzz first):
from modelfuzz import shield_tool, PolicyEngine, URLAllowList
engine = PolicyEngine([URLAllowList(allowed_domains=["api.mycorp.com"])])
@shield_tool(engine=engine)
def http_post(url: str, body: str) -> None:
print(f"POST {url}")
http_post("http://api.internal.com@evil.com", "data") # blocked: not on the allowlist
Ideally make this (not the keyword filter) the lead protection example, with the keyword default explicitly labelled a "toy default." defense_demo.py and shield_demo.png already demonstrate this — the README just needs the inline code path.
Done when
From the UX review — flagged by all four personas as the "toy → real" gap.
Problem
Every hero example leans on the weakest rule (the three-keyword
SensitiveDataFilter). The genuinely strong, verifiable mechanism —URLAllowList: default-deny, blocks userinfo tricks likehttp://api.internal.com@evil.com, rejectsfile://, walks nested containers — is described (line 111) but never shown in code.This is also the make-or-break bridge for adoption: line 32 tells the developer to "write your own rules and pass your own engine," but no code anywhere shows how.
defense_demo.pyexists and does exactly this, but the README doesn't inline it.Fix
Add a short runnable block (verify the import surface against
src/modelfuzzfirst):Ideally make this (not the keyword filter) the lead protection example, with the keyword default explicitly labelled a "toy default."
defense_demo.pyandshield_demo.pngalready demonstrate this — the README just needs the inline code path.Done when
URLAllowList/ custom-engine block is in the README, verified to run