Commit ·
d729e70
1
Parent(s): 6fa99e6
Document honest submission guardrails
Browse filesCo-authored-by: Codex <codex@openai.com>
- FIELD_NOTES.md +6 -0
- HONEST_SUBMISSION.md +45 -0
- README.md +3 -1
- SETUP.md +1 -0
- app.py +1 -0
- eval/run_eval.py +2 -0
- jawbreaker/analyzers.py +11 -4
FIELD_NOTES.md
CHANGED
|
@@ -76,3 +76,9 @@ Added:
|
|
| 76 |
- runtime fallback so malformed model JSON falls back to deterministic safety analysis
|
| 77 |
|
| 78 |
Deployment rule: publish or deploy a LoRA adapter only if it improves valid JSON and keeps dangerous-as-safe misses at zero. A worse-but-fine-tuned model should not ship.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 76 |
- runtime fallback so malformed model JSON falls back to deterministic safety analysis
|
| 77 |
|
| 78 |
Deployment rule: publish or deploy a LoRA adapter only if it improves valid JSON and keeps dangerous-as-safe misses at zero. A worse-but-fine-tuned model should not ship.
|
| 79 |
+
|
| 80 |
+
## 2026-06-06 Submission Honesty
|
| 81 |
+
|
| 82 |
+
Latest Discord discussion surfaced MiniCPM4.1 Transformers issues around SDPA attention masks and gibberish output. Jawbreaker now defaults `JAWBREAKER_ATTENTION_IMPLEMENTATION=eager` for the MiniCPM path, and keeps fallback analysis visible in the documentation.
|
| 83 |
+
|
| 84 |
+
Guardrail: winning matters, but not by overclaiming. The project should not claim Well-Tuned, real user validation, Modal usage, or llama.cpp deployment unless those things are actually completed and documented.
|
HONEST_SUBMISSION.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Honest Submission Guardrails
|
| 2 |
+
|
| 3 |
+
Jawbreaker should compete hard without gaming the hackathon.
|
| 4 |
+
|
| 5 |
+
## What We Can Claim
|
| 6 |
+
|
| 7 |
+
- Backyard AI: Jawbreaker is built for a real, specific safety problem: helping someone pause before clicking, replying, or sending money.
|
| 8 |
+
- Small-model constraint: the deployed model is under 32B parameters.
|
| 9 |
+
- Gradio Space: the app runs as a Gradio app under the hackathon organization.
|
| 10 |
+
- OpenBMB targeting: MiniCPM is central to the deployed scam analysis path.
|
| 11 |
+
- Codex usage: the GitHub repo has Codex-attributed commits and the build logs document Codex's role.
|
| 12 |
+
- Custom UI: the app uses a custom Gradio interface, not the default demo look.
|
| 13 |
+
- Eval work: the repo includes hand-curated synthetic/sanitized eval cases plus generated synthetic train/dev/test data.
|
| 14 |
+
- Safety guardrails: model JSON is validated, unsafe actions are checked in eval, and a deterministic fallback handles malformed model output.
|
| 15 |
+
|
| 16 |
+
## What We Should Not Claim Unless Completed
|
| 17 |
+
|
| 18 |
+
- Do not claim the Well-Tuned badge unless a fine-tuned adapter is actually trained, published on Hugging Face, and used or evaluated honestly.
|
| 19 |
+
- Do not claim real-world user validation until the target person has actually tried the app.
|
| 20 |
+
- Do not claim the generated synthetic dataset is real user data.
|
| 21 |
+
- Do not claim benchmark superiority unless we publish the eval command, dataset, and result.
|
| 22 |
+
- Do not claim llama.cpp as the deployed runtime unless the live Space actually uses the llama.cpp path.
|
| 23 |
+
- Do not claim Modal usage unless training or inference actually runs on Modal.
|
| 24 |
+
- Do not hide fallback behavior. If MiniCPM fails and Jawbreaker uses deterministic safety fallback, document that as a reliability layer.
|
| 25 |
+
|
| 26 |
+
## Training Rules
|
| 27 |
+
|
| 28 |
+
- Training data and eval data must stay separated.
|
| 29 |
+
- `eval/scam_eval.jsonl` is the hand-curated eval set and should not be used as training data.
|
| 30 |
+
- `training/data/test.jsonl` and `eval/generated_eval.jsonl` are holdout data and should not be used for LoRA training.
|
| 31 |
+
- A LoRA adapter should only be deployed if it improves valid JSON and safety metrics without increasing dangerous false negatives.
|
| 32 |
+
- If synthetic training mostly teaches format-following, say that. Do not describe it as learning from real scam victims.
|
| 33 |
+
|
| 34 |
+
## Demo Rules
|
| 35 |
+
|
| 36 |
+
- The demo can use sanitized examples.
|
| 37 |
+
- If a real family story is used, remove names, phone numbers, addresses, account details, and links.
|
| 38 |
+
- The demo should show the actual Space behavior, not a scripted mockup.
|
| 39 |
+
- If the Space is slow because of ZeroGPU or MiniCPM loading, say so in field notes rather than pretending it is instant.
|
| 40 |
+
|
| 41 |
+
## Winning Without Cheating
|
| 42 |
+
|
| 43 |
+
The strongest honest story is:
|
| 44 |
+
|
| 45 |
+
Jawbreaker is a narrow, polished Backyard AI tool using OpenBMB MiniCPM under the 32B limit. It turns a suspicious message into a clear scam DNA breakdown and a safe next step for a non-technical person. The repo shows evals, safety fallbacks, training scaffolding, Codex traces, and field notes. Claims are limited to what is actually built and measured.
|
README.md
CHANGED
|
@@ -43,6 +43,7 @@ Codex evidence:
|
|
| 43 |
- Codex-attributed commits will be included for build work.
|
| 44 |
- `AGENT_TRACE.md` records the development process.
|
| 45 |
- `FIELD_NOTES.md` records product and technical decisions.
|
|
|
|
| 46 |
|
| 47 |
## Why This Is Small
|
| 48 |
|
|
@@ -82,13 +83,14 @@ Training/eval artifacts:
|
|
| 82 |
- `training/data/train.jsonl`, `dev.jsonl`, `test.jsonl`: generated SFT records for Jawbreaker JSON behavior.
|
| 83 |
- `eval/generated_eval.jsonl`: generated holdout eval set.
|
| 84 |
- `training/train_lora.py`: PEFT/LoRA scaffold for publishing a Jawbreaker MiniCPM adapter if it beats the base model.
|
|
|
|
| 85 |
|
| 86 |
## Bonus Badges Targeted
|
| 87 |
|
| 88 |
- Off the Grid: local model inference, no cloud APIs for scam analysis.
|
| 89 |
- Llama Champion: local/eval tooling supports the llama.cpp runtime.
|
| 90 |
- Off-Brand: custom Gradio UI beyond the default look.
|
| 91 |
-
- Well-Tuned:
|
| 92 |
- Sharing is Caring: Codex/agent trace published in this repo.
|
| 93 |
- Field Notes: build report published before submission.
|
| 94 |
|
|
|
|
| 43 |
- Codex-attributed commits will be included for build work.
|
| 44 |
- `AGENT_TRACE.md` records the development process.
|
| 45 |
- `FIELD_NOTES.md` records product and technical decisions.
|
| 46 |
+
- `HONEST_SUBMISSION.md` records what the project can and cannot honestly claim.
|
| 47 |
|
| 48 |
## Why This Is Small
|
| 49 |
|
|
|
|
| 83 |
- `training/data/train.jsonl`, `dev.jsonl`, `test.jsonl`: generated SFT records for Jawbreaker JSON behavior.
|
| 84 |
- `eval/generated_eval.jsonl`: generated holdout eval set.
|
| 85 |
- `training/train_lora.py`: PEFT/LoRA scaffold for publishing a Jawbreaker MiniCPM adapter if it beats the base model.
|
| 86 |
+
- `HONEST_SUBMISSION.md`: guardrails to avoid overclaiming synthetic data, fine-tuning, or runtime behavior.
|
| 87 |
|
| 88 |
## Bonus Badges Targeted
|
| 89 |
|
| 90 |
- Off the Grid: local model inference, no cloud APIs for scam analysis.
|
| 91 |
- Llama Champion: local/eval tooling supports the llama.cpp runtime.
|
| 92 |
- Off-Brand: custom Gradio UI beyond the default look.
|
| 93 |
+
- Well-Tuned: not claimed unless a fine-tuned adapter is actually trained, published, and evaluated.
|
| 94 |
- Sharing is Caring: Codex/agent trace published in this repo.
|
| 95 |
- Field Notes: build report published before submission.
|
| 96 |
|
SETUP.md
CHANGED
|
@@ -71,6 +71,7 @@ For responsive model inference without paid hardware:
|
|
| 71 |
- set Space variable `JAWBREAKER_BACKEND=zerogpu`
|
| 72 |
- keep `JAWBREAKER_TRANSFORMERS_MODEL_ID=openbmb/MiniCPM4.1-8B` for the OpenBMB-targeted build
|
| 73 |
- keep `JAWBREAKER_TRUST_REMOTE_CODE=true`; MiniCPM requires custom model code through Transformers
|
|
|
|
| 74 |
- fallback model if latency is unacceptable: `Qwen/Qwen3-0.6B`
|
| 75 |
|
| 76 |
CPU fallback remains available with `JAWBREAKER_BACKEND=llama-cpp`.
|
|
|
|
| 71 |
- set Space variable `JAWBREAKER_BACKEND=zerogpu`
|
| 72 |
- keep `JAWBREAKER_TRANSFORMERS_MODEL_ID=openbmb/MiniCPM4.1-8B` for the OpenBMB-targeted build
|
| 73 |
- keep `JAWBREAKER_TRUST_REMOTE_CODE=true`; MiniCPM requires custom model code through Transformers
|
| 74 |
+
- keep `JAWBREAKER_ATTENTION_IMPLEMENTATION=eager`; Discord reports MiniCPM4.1 SDPA mask issues in some Transformers/PyTorch environments
|
| 75 |
- fallback model if latency is unacceptable: `Qwen/Qwen3-0.6B`
|
| 76 |
|
| 77 |
CPU fallback remains available with `JAWBREAKER_BACKEND=llama-cpp`.
|
app.py
CHANGED
|
@@ -142,6 +142,7 @@ def get_analyzer():
|
|
| 142 |
device_map=os.getenv("JAWBREAKER_DEVICE_MAP", "auto"),
|
| 143 |
dtype=os.getenv("JAWBREAKER_TORCH_DTYPE", "auto"),
|
| 144 |
trust_remote_code=_env_bool("JAWBREAKER_TRUST_REMOTE_CODE", True) or False,
|
|
|
|
| 145 |
)
|
| 146 |
|
| 147 |
raise ValueError(f"Unsupported JAWBREAKER_BACKEND: {backend}")
|
|
|
|
| 142 |
device_map=os.getenv("JAWBREAKER_DEVICE_MAP", "auto"),
|
| 143 |
dtype=os.getenv("JAWBREAKER_TORCH_DTYPE", "auto"),
|
| 144 |
trust_remote_code=_env_bool("JAWBREAKER_TRUST_REMOTE_CODE", True) or False,
|
| 145 |
+
attn_implementation=os.getenv("JAWBREAKER_ATTENTION_IMPLEMENTATION", "eager") or None,
|
| 146 |
)
|
| 147 |
|
| 148 |
raise ValueError(f"Unsupported JAWBREAKER_BACKEND: {backend}")
|
eval/run_eval.py
CHANGED
|
@@ -66,6 +66,7 @@ def parse_args() -> argparse.Namespace:
|
|
| 66 |
parser.add_argument("--device-map", default="auto", help="Transformers device_map.")
|
| 67 |
parser.add_argument("--dtype", default="auto", help="Transformers dtype.")
|
| 68 |
parser.add_argument("--trust-remote-code", action=argparse.BooleanOptionalAction, default=True)
|
|
|
|
| 69 |
return parser.parse_args()
|
| 70 |
|
| 71 |
|
|
@@ -161,6 +162,7 @@ def build_analyzer(args: argparse.Namespace):
|
|
| 161 |
device_map=args.device_map,
|
| 162 |
dtype=args.dtype,
|
| 163 |
trust_remote_code=args.trust_remote_code,
|
|
|
|
| 164 |
)
|
| 165 |
return lambda row: analyzer(row["input"])
|
| 166 |
|
|
|
|
| 66 |
parser.add_argument("--device-map", default="auto", help="Transformers device_map.")
|
| 67 |
parser.add_argument("--dtype", default="auto", help="Transformers dtype.")
|
| 68 |
parser.add_argument("--trust-remote-code", action=argparse.BooleanOptionalAction, default=True)
|
| 69 |
+
parser.add_argument("--attn-implementation", default="eager", help="Transformers attention implementation.")
|
| 70 |
return parser.parse_args()
|
| 71 |
|
| 72 |
|
|
|
|
| 162 |
device_map=args.device_map,
|
| 163 |
dtype=args.dtype,
|
| 164 |
trust_remote_code=args.trust_remote_code,
|
| 165 |
+
attn_implementation=args.attn_implementation,
|
| 166 |
)
|
| 167 |
return lambda row: analyzer(row["input"])
|
| 168 |
|
jawbreaker/analyzers.py
CHANGED
|
@@ -179,6 +179,7 @@ def build_transformers_analyzer(
|
|
| 179 |
device_map: str = "auto",
|
| 180 |
dtype: str = "auto",
|
| 181 |
trust_remote_code: bool = False,
|
|
|
|
| 182 |
) -> Analyzer:
|
| 183 |
try:
|
| 184 |
import torch
|
|
@@ -191,15 +192,21 @@ def build_transformers_analyzer(
|
|
| 191 |
started = perf_counter()
|
| 192 |
print(
|
| 193 |
"jawbreaker transformers load_start "
|
| 194 |
-
f"model_id={model_id} device_map={device_map} dtype={dtype}
|
|
|
|
| 195 |
flush=True,
|
| 196 |
)
|
| 197 |
tokenizer = AutoTokenizer.from_pretrained(model_id, trust_remote_code=trust_remote_code)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 198 |
model = AutoModelForCausalLM.from_pretrained(
|
| 199 |
model_id,
|
| 200 |
-
|
| 201 |
-
device_map=device_map,
|
| 202 |
-
trust_remote_code=trust_remote_code,
|
| 203 |
)
|
| 204 |
model.eval()
|
| 205 |
device = getattr(model, "device", "unknown")
|
|
|
|
| 179 |
device_map: str = "auto",
|
| 180 |
dtype: str = "auto",
|
| 181 |
trust_remote_code: bool = False,
|
| 182 |
+
attn_implementation: str | None = None,
|
| 183 |
) -> Analyzer:
|
| 184 |
try:
|
| 185 |
import torch
|
|
|
|
| 192 |
started = perf_counter()
|
| 193 |
print(
|
| 194 |
"jawbreaker transformers load_start "
|
| 195 |
+
f"model_id={model_id} device_map={device_map} dtype={dtype} "
|
| 196 |
+
f"trust_remote_code={trust_remote_code} attn_implementation={attn_implementation}",
|
| 197 |
flush=True,
|
| 198 |
)
|
| 199 |
tokenizer = AutoTokenizer.from_pretrained(model_id, trust_remote_code=trust_remote_code)
|
| 200 |
+
model_kwargs: dict[str, Any] = {
|
| 201 |
+
"dtype": dtype,
|
| 202 |
+
"device_map": device_map,
|
| 203 |
+
"trust_remote_code": trust_remote_code,
|
| 204 |
+
}
|
| 205 |
+
if attn_implementation:
|
| 206 |
+
model_kwargs["attn_implementation"] = attn_implementation
|
| 207 |
model = AutoModelForCausalLM.from_pretrained(
|
| 208 |
model_id,
|
| 209 |
+
**model_kwargs,
|
|
|
|
|
|
|
| 210 |
)
|
| 211 |
model.eval()
|
| 212 |
device = getattr(model, "device", "unknown")
|