Abid Ali Awan Codex commited on
Commit
8380712
·
1 Parent(s): 3918768

Reduce traces to descriptive inputs

Browse files

Co-Authored-By: Codex <codex@openai.com>

README.md CHANGED
@@ -128,7 +128,8 @@ turn it off before submitting.
128
 
129
  Trace creation is deterministic Python logic and makes no additional model
130
  request. It records a safe input type or image description, input category,
131
- urgency, size and latency buckets, fixed signals, and result counts.
 
132
  It never stores raw or redacted messages, screenshots, links, identifiers,
133
  model explanations, reply text, exceptions, or credentials.
134
 
 
128
 
129
  Trace creation is deterministic Python logic and makes no additional model
130
  request. It records a safe input type or image description, input category,
131
+ urgency, fixed signals, and result counts. The input field uses a safe
132
+ `text: ...` or `image: ...` description generated from fixed templates.
133
  It never stores raw or redacted messages, screenshots, links, identifiers,
134
  model explanations, reply text, exceptions, or credentials.
135
 
app.py CHANGED
@@ -338,9 +338,6 @@ def analyze_notice(
338
  text=text,
339
  image_data_url=image_data_url,
340
  example_id=example_id,
341
- modal_called=bool(telemetry.get("modal_called", False)),
342
- modal_ms=float(telemetry.get("modal_ms", 0.0)),
343
- retry_count=int(telemetry.get("retry_count", 0)),
344
  assessment=response.get("assessment"),
345
  )
346
  response["trace"] = {"trace_id": trace_id, "status": queued}
 
338
  text=text,
339
  image_data_url=image_data_url,
340
  example_id=example_id,
 
 
 
341
  assessment=response.get("assessment"),
342
  )
343
  response["trace"] = {"trace_id": trace_id, "status": queued}
tests/test_tracing.py CHANGED
@@ -27,9 +27,6 @@ class TraceTests(unittest.TestCase):
27
  ),
28
  image_data_url="data:image/png;base64,PRIVATE_IMAGE_BYTES",
29
  example_id="",
30
- modal_called=True,
31
- modal_ms=120,
32
- retry_count=0,
33
  assessment={
34
  "risk_label": "Likely scam",
35
  "simple_explanation": "PRIVATE MODEL EXPLANATION",
@@ -67,7 +64,7 @@ class TraceTests(unittest.TestCase):
67
 
68
  def test_trace_uses_simplified_columns(self) -> None:
69
  image_record = self.sample_record()
70
- self.assertTrue(image_record["input"].startswith("image ("))
71
  self.assertEqual(image_record["input_category"], "unknown")
72
  self.assertFalse(image_record["urgency"])
73
  for removed in (
@@ -77,6 +74,11 @@ class TraceTests(unittest.TestCase):
77
  "failure",
78
  "schema_version",
79
  "request_source",
 
 
 
 
 
80
  ):
81
  self.assertNotIn(removed, image_record)
82
 
@@ -84,12 +86,12 @@ class TraceTests(unittest.TestCase):
84
  text="Urgent courier payment required today",
85
  image_data_url="",
86
  example_id="",
87
- modal_called=False,
88
- modal_ms=0,
89
- retry_count=0,
90
  assessment=None,
91
  )
92
- self.assertEqual(text_record["input"], "text")
 
 
 
93
  self.assertEqual(text_record["input_category"], "courier")
94
  self.assertTrue(text_record["urgency"])
95
 
@@ -129,7 +131,7 @@ class TraceTests(unittest.TestCase):
129
  result = app.analyze_notice("test message")
130
  self.assertFalse(result["ok"])
131
  model_mock.assert_not_called()
132
- self.assertFalse(queue_mock.call_args.kwargs["modal_called"])
133
 
134
  def test_success_uses_existing_model_call_once(self) -> None:
135
  assessment = {
@@ -162,8 +164,8 @@ class TraceTests(unittest.TestCase):
162
  result = app.analyze_notice("test message")
163
  self.assertTrue(result["ok"])
164
  model_mock.assert_called_once()
165
- self.assertTrue(queue_mock.call_args.kwargs["modal_called"])
166
- self.assertEqual(queue_mock.call_args.kwargs["retry_count"], 1)
167
 
168
  def test_timeout_is_sanitized(self) -> None:
169
  timeout = APITimeoutError(request=httpx.Request("POST", "https://example.invalid"))
 
27
  ),
28
  image_data_url="data:image/png;base64,PRIVATE_IMAGE_BYTES",
29
  example_id="",
 
 
 
30
  assessment={
31
  "risk_label": "Likely scam",
32
  "simple_explanation": "PRIVATE MODEL EXPLANATION",
 
64
 
65
  def test_trace_uses_simplified_columns(self) -> None:
66
  image_record = self.sample_record()
67
+ self.assertTrue(image_record["input"].startswith("image: "))
68
  self.assertEqual(image_record["input_category"], "unknown")
69
  self.assertFalse(image_record["urgency"])
70
  for removed in (
 
74
  "failure",
75
  "schema_version",
76
  "request_source",
77
+ "text_byte_bucket",
78
+ "text_character_bucket",
79
+ "image_size_bucket",
80
+ "language_hint",
81
+ "modal",
82
  ):
83
  self.assertNotIn(removed, image_record)
84
 
 
86
  text="Urgent courier payment required today",
87
  image_data_url="",
88
  example_id="",
 
 
 
89
  assessment=None,
90
  )
91
+ self.assertEqual(
92
+ text_record["input"],
93
+ "text: Courier-style content with urgency, payment, courier signals",
94
+ )
95
  self.assertEqual(text_record["input_category"], "courier")
96
  self.assertTrue(text_record["urgency"])
97
 
 
131
  result = app.analyze_notice("test message")
132
  self.assertFalse(result["ok"])
133
  model_mock.assert_not_called()
134
+ self.assertNotIn("modal_called", queue_mock.call_args.kwargs)
135
 
136
  def test_success_uses_existing_model_call_once(self) -> None:
137
  assessment = {
 
164
  result = app.analyze_notice("test message")
165
  self.assertTrue(result["ok"])
166
  model_mock.assert_called_once()
167
+ self.assertNotIn("modal_called", queue_mock.call_args.kwargs)
168
+ self.assertNotIn("retry_count", queue_mock.call_args.kwargs)
169
 
170
  def test_timeout_is_sanitized(self) -> None:
171
  timeout = APITimeoutError(request=httpx.Request("POST", "https://example.invalid"))
traces/data/trace_samples.jsonl CHANGED
@@ -1,6 +1,6 @@
1
- {"image_size_bucket": "none", "input": "text", "input_category": "courier", "language_hint": "latin_script", "modal": {"called": false, "latency_bucket": "0-1ms", "model_family": "qwen3.6-27b-mtp", "outcome": "not_called", "retry_count": 0}, "privacy": {"exception_text_stored": false, "identifiers_stored": false, "raw_image_stored": false, "raw_input_stored": false, "raw_model_output_stored": false}, "result": {"red_flag_count": 4, "reply_draft_policy": "suppressed", "reply_draft_returned": false, "risk_label": "Likely scam", "safe_next_step_count": 4}, "signals": {"account_threat": false, "challan": false, "cnic": false, "courier": true, "credentials": false, "link": true, "otp": false, "payment": true, "refund_or_prize": false}, "text_byte_bucket": "1-160", "text_character_bucket": "1-160", "timestamp": "2026-06-07T06:30:27.211964+00:00", "trace_id": "95a3b546-724e-47d0-a96b-a256dd1917aa", "urgency": true}
2
- {"image_size_bucket": "none", "input": "text", "input_category": "fbr", "language_hint": "latin_script", "modal": {"called": false, "latency_bucket": "0-1ms", "model_family": "qwen3.6-27b-mtp", "outcome": "not_called", "retry_count": 0}, "privacy": {"exception_text_stored": false, "identifiers_stored": false, "raw_image_stored": false, "raw_input_stored": false, "raw_model_output_stored": false}, "result": {"red_flag_count": 4, "reply_draft_policy": "suppressed", "reply_draft_returned": false, "risk_label": "Likely scam", "safe_next_step_count": 4}, "signals": {"account_threat": false, "challan": false, "cnic": true, "courier": false, "credentials": true, "link": false, "otp": false, "payment": true, "refund_or_prize": true}, "text_byte_bucket": "1-160", "text_character_bucket": "1-160", "timestamp": "2026-06-07T06:30:27.212069+00:00", "trace_id": "ea6cade3-f905-46d1-9ca2-64691960a42b", "urgency": true}
3
- {"image_size_bucket": "none", "input": "text", "input_category": "bank", "language_hint": "latin_script", "modal": {"called": false, "latency_bucket": "0-1ms", "model_family": "qwen3.6-27b-mtp", "outcome": "not_called", "retry_count": 0}, "privacy": {"exception_text_stored": false, "identifiers_stored": false, "raw_image_stored": false, "raw_input_stored": false, "raw_model_output_stored": false}, "result": {"red_flag_count": 3, "reply_draft_policy": "suppressed", "reply_draft_returned": false, "risk_label": "Likely scam", "safe_next_step_count": 5}, "signals": {"account_threat": true, "challan": false, "cnic": false, "courier": false, "credentials": false, "link": false, "otp": true, "payment": false, "refund_or_prize": false}, "text_byte_bucket": "1-160", "text_character_bucket": "1-160", "timestamp": "2026-06-07T06:30:27.212147+00:00", "trace_id": "1cd079a7-f50e-4572-9f2f-0af095b0c528", "urgency": true}
4
- {"image_size_bucket": "up-to-100KB", "input": "image (Courier-style content with link, urgency, courier signals)", "input_category": "courier", "language_hint": "unknown", "modal": {"called": false, "latency_bucket": "0-1ms", "model_family": "qwen3.6-27b-mtp", "outcome": "not_called", "retry_count": 0}, "privacy": {"exception_text_stored": false, "identifiers_stored": false, "raw_image_stored": false, "raw_input_stored": false, "raw_model_output_stored": false}, "result": {"red_flag_count": 4, "reply_draft_policy": "suppressed", "reply_draft_returned": false, "risk_label": "Likely scam", "safe_next_step_count": 4}, "signals": {"account_threat": false, "challan": false, "cnic": false, "courier": true, "credentials": false, "link": true, "otp": false, "payment": false, "refund_or_prize": false}, "text_byte_bucket": "empty", "text_character_bucket": "empty", "timestamp": "2026-06-07T06:30:27.212262+00:00", "trace_id": "5d0240c2-cdf8-44ee-b710-267c3144b560", "urgency": true}
5
- {"image_size_bucket": "500KB-2MB", "input": "image (Marketplace-style content with credential signals)", "input_category": "marketplace", "language_hint": "unknown", "modal": {"called": false, "latency_bucket": "0-1ms", "model_family": "qwen3.6-27b-mtp", "outcome": "not_called", "retry_count": 0}, "privacy": {"exception_text_stored": false, "identifiers_stored": false, "raw_image_stored": false, "raw_input_stored": false, "raw_model_output_stored": false}, "result": {"red_flag_count": 3, "reply_draft_policy": "suppressed", "reply_draft_returned": false, "risk_label": "Likely scam", "safe_next_step_count": 4}, "signals": {"account_threat": false, "challan": false, "cnic": false, "courier": false, "credentials": true, "link": false, "otp": false, "payment": false, "refund_or_prize": false}, "text_byte_bucket": "empty", "text_character_bucket": "empty", "timestamp": "2026-06-07T06:30:27.212593+00:00", "trace_id": "34e9b8ac-d1e3-4360-bfc1-aabf0a9ff877", "urgency": false}
6
- {"image_size_bucket": "up-to-100KB", "input": "image (Traffic-challan-style content with link, urgency, payment, challan signals)", "input_category": "traffic_challan", "language_hint": "unknown", "modal": {"called": false, "latency_bucket": "0-1ms", "model_family": "qwen3.6-27b-mtp", "outcome": "not_called", "retry_count": 0}, "privacy": {"exception_text_stored": false, "identifiers_stored": false, "raw_image_stored": false, "raw_input_stored": false, "raw_model_output_stored": false}, "result": {"red_flag_count": 3, "reply_draft_policy": "suppressed", "reply_draft_returned": false, "risk_label": "Likely scam", "safe_next_step_count": 4}, "signals": {"account_threat": false, "challan": true, "cnic": false, "courier": false, "credentials": false, "link": true, "otp": false, "payment": true, "refund_or_prize": false}, "text_byte_bucket": "empty", "text_character_bucket": "empty", "timestamp": "2026-06-07T06:30:27.212733+00:00", "trace_id": "9fae5e53-f0a7-48cc-916f-8fcc540ee241", "urgency": true}
 
1
+ {"input": "text: Courier-style content with link, urgency, payment, courier signals", "input_category": "courier", "privacy": {"exception_text_stored": false, "identifiers_stored": false, "raw_image_stored": false, "raw_input_stored": false, "raw_model_output_stored": false}, "result": {"red_flag_count": 4, "reply_draft_policy": "suppressed", "reply_draft_returned": false, "risk_label": "Likely scam", "safe_next_step_count": 4}, "signals": {"account_threat": false, "challan": false, "cnic": false, "courier": true, "credentials": false, "link": true, "otp": false, "payment": true, "refund_or_prize": false}, "timestamp": "2026-06-07T06:37:30.001011+00:00", "trace_id": "2d2fda51-9f65-4ffe-a884-a79582de4b86", "urgency": true}
2
+ {"input": "text: FBR-style content with CNIC, credential, urgency, payment signals", "input_category": "fbr", "privacy": {"exception_text_stored": false, "identifiers_stored": false, "raw_image_stored": false, "raw_input_stored": false, "raw_model_output_stored": false}, "result": {"red_flag_count": 4, "reply_draft_policy": "suppressed", "reply_draft_returned": false, "risk_label": "Likely scam", "safe_next_step_count": 4}, "signals": {"account_threat": false, "challan": false, "cnic": true, "courier": false, "credentials": true, "link": false, "otp": false, "payment": true, "refund_or_prize": true}, "timestamp": "2026-06-07T06:37:30.001113+00:00", "trace_id": "57521c66-f3df-412c-8c2f-9638fac910c7", "urgency": true}
3
+ {"input": "text: Bank-style content with OTP, urgency, account-threat signals", "input_category": "bank", "privacy": {"exception_text_stored": false, "identifiers_stored": false, "raw_image_stored": false, "raw_input_stored": false, "raw_model_output_stored": false}, "result": {"red_flag_count": 3, "reply_draft_policy": "suppressed", "reply_draft_returned": false, "risk_label": "Likely scam", "safe_next_step_count": 5}, "signals": {"account_threat": true, "challan": false, "cnic": false, "courier": false, "credentials": false, "link": false, "otp": true, "payment": false, "refund_or_prize": false}, "timestamp": "2026-06-07T06:37:30.001192+00:00", "trace_id": "fa84e753-4492-473f-b797-b94eee8724bc", "urgency": true}
4
+ {"input": "image: Courier-style content with link, urgency, courier signals", "input_category": "courier", "privacy": {"exception_text_stored": false, "identifiers_stored": false, "raw_image_stored": false, "raw_input_stored": false, "raw_model_output_stored": false}, "result": {"red_flag_count": 4, "reply_draft_policy": "suppressed", "reply_draft_returned": false, "risk_label": "Likely scam", "safe_next_step_count": 4}, "signals": {"account_threat": false, "challan": false, "cnic": false, "courier": true, "credentials": false, "link": true, "otp": false, "payment": false, "refund_or_prize": false}, "timestamp": "2026-06-07T06:37:30.001301+00:00", "trace_id": "eaf5013c-adb7-4b06-9e4c-4e785e4c776a", "urgency": true}
5
+ {"input": "image: Marketplace-style content with credential signals", "input_category": "marketplace", "privacy": {"exception_text_stored": false, "identifiers_stored": false, "raw_image_stored": false, "raw_input_stored": false, "raw_model_output_stored": false}, "result": {"red_flag_count": 3, "reply_draft_policy": "suppressed", "reply_draft_returned": false, "risk_label": "Likely scam", "safe_next_step_count": 4}, "signals": {"account_threat": false, "challan": false, "cnic": false, "courier": false, "credentials": true, "link": false, "otp": false, "payment": false, "refund_or_prize": false}, "timestamp": "2026-06-07T06:37:30.001851+00:00", "trace_id": "dd5000f9-d612-4ee8-a1ce-d9c41a8ef347", "urgency": false}
6
+ {"input": "image: Traffic-challan-style content with link, urgency, payment, challan signals", "input_category": "traffic_challan", "privacy": {"exception_text_stored": false, "identifiers_stored": false, "raw_image_stored": false, "raw_input_stored": false, "raw_model_output_stored": false}, "result": {"red_flag_count": 3, "reply_draft_policy": "suppressed", "reply_draft_returned": false, "risk_label": "Likely scam", "safe_next_step_count": 4}, "signals": {"account_threat": false, "challan": true, "cnic": false, "courier": false, "credentials": false, "link": true, "otp": false, "payment": true, "refund_or_prize": false}, "timestamp": "2026-06-07T06:37:30.002064+00:00", "trace_id": "19c0628b-a2ff-45ff-a35e-2a1e6a9d9335", "urgency": true}
traces/dataset_card.md CHANGED
@@ -34,18 +34,17 @@ and convert it into allow-listed categories, booleans, buckets, and counts.
34
  ## Fields
35
 
36
  - Trace identity: random trace ID and UTC timestamp
37
- - `input`: either `text` or a fixed-template `image (...)` description
38
  - `input_category`: deterministic category such as courier, bank, or FBR
39
  - `urgency`: deterministic boolean urgency signal
40
- - Size buckets and script/language hint
41
  - Deterministic signals: OTP, CNIC, credentials, link, payment,
42
  refund/prize, courier, challan, and account threat
43
- - Modal-call metadata
44
  - Final risk label and output item counts
45
  - Explicit privacy flags
46
 
47
  Records do not contain pipeline steps, cache fields, app commits, failure
48
- details, request source, or schema-version columns.
 
49
 
50
  ## Privacy
51
 
 
34
  ## Fields
35
 
36
  - Trace identity: random trace ID and UTC timestamp
37
+ - `input`: a fixed-template `text: ...` or `image: ...` description
38
  - `input_category`: deterministic category such as courier, bank, or FBR
39
  - `urgency`: deterministic boolean urgency signal
 
40
  - Deterministic signals: OTP, CNIC, credentials, link, payment,
41
  refund/prize, courier, challan, and account threat
 
42
  - Final risk label and output item counts
43
  - Explicit privacy flags
44
 
45
  Records do not contain pipeline steps, cache fields, app commits, failure
46
+ details, request source, schema versions, size buckets, language hints, or
47
+ Modal metadata.
48
 
49
  ## Privacy
50
 
traces/runtime.py CHANGED
@@ -57,60 +57,6 @@ EXAMPLE_PROFILES = {
57
  }
58
 
59
 
60
- def _bucket_number(value: float, thresholds: tuple[tuple[float, str], ...]) -> str:
61
- for maximum, label in thresholds:
62
- if value <= maximum:
63
- return label
64
- return thresholds[-1][1]
65
-
66
-
67
- def duration_bucket(milliseconds: float) -> str:
68
- return _bucket_number(
69
- max(0.0, milliseconds),
70
- (
71
- (1, "0-1ms"),
72
- (5, "2-5ms"),
73
- (10, "6-10ms"),
74
- (50, "11-50ms"),
75
- (250, "51-250ms"),
76
- (1000, "251-1000ms"),
77
- (5000, "1-5s"),
78
- (30000, "5-30s"),
79
- (float("inf"), "30s+"),
80
- ),
81
- )
82
-
83
-
84
- def input_size_bucket(length: int) -> str:
85
- return _bucket_number(
86
- max(0, length),
87
- (
88
- (0, "empty"),
89
- (160, "1-160"),
90
- (500, "161-500"),
91
- (2000, "501-2000"),
92
- (6000, "2001-6000"),
93
- (12000, "6001-12000"),
94
- (float("inf"), "12000+"),
95
- ),
96
- )
97
-
98
-
99
- def image_size_bucket(data_url_length: int) -> str:
100
- estimated_bytes = max(0, int(data_url_length * 0.75))
101
- return _bucket_number(
102
- estimated_bytes,
103
- (
104
- (0, "none"),
105
- (100_000, "up-to-100KB"),
106
- (500_000, "100-500KB"),
107
- (2_000_000, "500KB-2MB"),
108
- (8_000_000, "2-8MB"),
109
- (float("inf"), "8MB+"),
110
- ),
111
- )
112
-
113
-
114
  def detect_signals(text: str, example_id: str = "") -> dict[str, bool]:
115
  detected = {
116
  name: bool(re.search(pattern, text or "", re.I | re.S))
@@ -150,27 +96,6 @@ def detect_category(text: str, signals: dict[str, bool], example_id: str = "") -
150
  return "unknown"
151
 
152
 
153
- def detect_language_hint(text: str) -> str:
154
- has_urdu = bool(re.search(r"[\u0600-\u06ff]", text or ""))
155
- has_latin = bool(re.search(r"[A-Za-z]", text or ""))
156
- roman_terms = bool(
157
- re.search(
158
- r"\b(?:aap|apka|apki|hai|hain|karo|karein|paisa|rupay|bhej|jaldi)\b",
159
- text or "",
160
- re.I,
161
- )
162
- )
163
- if has_urdu and has_latin:
164
- return "mixed_urdu_latin"
165
- if has_urdu:
166
- return "urdu_script"
167
- if roman_terms:
168
- return "roman_urdu"
169
- if has_latin:
170
- return "latin_script"
171
- return "unknown"
172
-
173
-
174
  def safe_description(category: str, signals: dict[str, bool]) -> str:
175
  category_labels = {
176
  "fbr": "FBR-style",
@@ -213,17 +138,9 @@ def build_input_profile(text: str, image_data_url: str, example_id: str = "") ->
213
  signals = detect_signals(text, example_id)
214
  category = detect_category(text, signals, example_id)
215
  return {
216
- "input": (
217
- f"image ({safe_description(category, signals)})"
218
- if input_type == "image"
219
- else "text"
220
- ),
221
  "input_category": category,
222
  "urgency": signals["urgency"],
223
- "text_character_bucket": input_size_bucket(len(text or "")),
224
- "text_byte_bucket": input_size_bucket(len((text or "").encode("utf-8"))),
225
- "image_size_bucket": image_size_bucket(len(image_data_url or "")),
226
- "language_hint": detect_language_hint(text),
227
  "signals": {
228
  name: enabled
229
  for name, enabled in signals.items()
@@ -237,9 +154,6 @@ def build_trace_record(
237
  text: str,
238
  image_data_url: str,
239
  example_id: str,
240
- modal_called: bool,
241
- modal_ms: float,
242
- retry_count: int,
243
  assessment: dict[str, Any] | None,
244
  ) -> dict[str, Any]:
245
  trace_id = str(uuid.uuid4())
@@ -251,24 +165,6 @@ def build_trace_record(
251
  "trace_id": trace_id,
252
  "timestamp": datetime.now(timezone.utc).isoformat(),
253
  **input_profile,
254
- "modal": {
255
- "called": bool(modal_called),
256
- "model_family": (
257
- "qwen3.6-27b-mtp"
258
- if "qwen3.6-27b-mtp"
259
- in os.getenv("MODEL_NAME", "qwen3.6-27b-mtp").lower()
260
- else "other"
261
- ),
262
- "latency_bucket": duration_bucket(modal_ms),
263
- "retry_count": max(0, min(int(retry_count), 20)),
264
- "outcome": (
265
- "success"
266
- if modal_called and assessment
267
- else "failed"
268
- if modal_called
269
- else "not_called"
270
- ),
271
- },
272
  "result": {
273
  "risk_label": risk_label,
274
  "red_flag_count": min(len((assessment or {}).get("red_flags", [])), 50),
@@ -305,12 +201,7 @@ def validate_trace(record: Any) -> list[str]:
305
  "input",
306
  "input_category",
307
  "urgency",
308
- "text_character_bucket",
309
- "text_byte_bucket",
310
- "image_size_bucket",
311
- "language_hint",
312
  "signals",
313
- "modal",
314
  "result",
315
  "privacy",
316
  }
@@ -318,12 +209,14 @@ def validate_trace(record: Any) -> list[str]:
318
  if missing:
319
  errors.append("Missing fields: " + ", ".join(sorted(missing)))
320
  input_value = record.get("input")
321
- if input_value != "text" and not (
322
  isinstance(input_value, str)
323
- and input_value.startswith("image (")
324
- and input_value.endswith(")")
 
 
325
  ):
326
- errors.append("Input must be text or a fixed image description.")
327
  if not isinstance(record.get("input_category"), str):
328
  errors.append("Input category must be a string.")
329
  if not isinstance(record.get("urgency"), bool):
@@ -340,6 +233,11 @@ def validate_trace(record: Any) -> list[str]:
340
  "pipeline_steps",
341
  "cache",
342
  "failure",
 
 
 
 
 
343
  "raw_input",
344
  "raw_text",
345
  "image_data_url",
 
57
  }
58
 
59
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  def detect_signals(text: str, example_id: str = "") -> dict[str, bool]:
61
  detected = {
62
  name: bool(re.search(pattern, text or "", re.I | re.S))
 
96
  return "unknown"
97
 
98
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
99
  def safe_description(category: str, signals: dict[str, bool]) -> str:
100
  category_labels = {
101
  "fbr": "FBR-style",
 
138
  signals = detect_signals(text, example_id)
139
  category = detect_category(text, signals, example_id)
140
  return {
141
+ "input": f"{input_type}: {safe_description(category, signals)}",
 
 
 
 
142
  "input_category": category,
143
  "urgency": signals["urgency"],
 
 
 
 
144
  "signals": {
145
  name: enabled
146
  for name, enabled in signals.items()
 
154
  text: str,
155
  image_data_url: str,
156
  example_id: str,
 
 
 
157
  assessment: dict[str, Any] | None,
158
  ) -> dict[str, Any]:
159
  trace_id = str(uuid.uuid4())
 
165
  "trace_id": trace_id,
166
  "timestamp": datetime.now(timezone.utc).isoformat(),
167
  **input_profile,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
168
  "result": {
169
  "risk_label": risk_label,
170
  "red_flag_count": min(len((assessment or {}).get("red_flags", [])), 50),
 
201
  "input",
202
  "input_category",
203
  "urgency",
 
 
 
 
204
  "signals",
 
205
  "result",
206
  "privacy",
207
  }
 
209
  if missing:
210
  errors.append("Missing fields: " + ", ".join(sorted(missing)))
211
  input_value = record.get("input")
212
+ if not (
213
  isinstance(input_value, str)
214
+ and (
215
+ input_value.startswith("text: ")
216
+ or input_value.startswith("image: ")
217
+ )
218
  ):
219
+ errors.append("Input must use a fixed text: or image: description.")
220
  if not isinstance(record.get("input_category"), str):
221
  errors.append("Input category must be a string.")
222
  if not isinstance(record.get("urgency"), bool):
 
233
  "pipeline_steps",
234
  "cache",
235
  "failure",
236
+ "text_byte_bucket",
237
+ "text_character_bucket",
238
+ "image_size_bucket",
239
+ "language_hint",
240
+ "modal",
241
  "raw_input",
242
  "raw_text",
243
  "image_data_url",
traces/scripts/seed_trace_dataset.py CHANGED
@@ -49,9 +49,6 @@ def build_seed_records() -> list[dict]:
49
  text=text,
50
  image_data_url=image_placeholder,
51
  example_id=example_id,
52
- modal_called=False,
53
- modal_ms=0,
54
- retry_count=0,
55
  assessment=assessment,
56
  )
57
  errors = validate_trace(record)
 
49
  text=text,
50
  image_data_url=image_placeholder,
51
  example_id=example_id,
 
 
 
52
  assessment=assessment,
53
  )
54
  errors = validate_trace(record)