ITheEqualizer commited on
Commit
d8f28a5
·
verified ·
1 Parent(s): 7047e98

Update Agentic Injection Review Lite to v0.1.1

Browse files

Version 0.1.1 fixes repository-root resolution in the included training script, records SHA-256 digests for every locked dataset file, and discloses within-split duplicate counts. The freshly trained classifier has exactly the same complete validation, lockbox, and diagnostic decision scores as version 0.1.0. Maintainer: Ali Zakaee (ITheEqualizer).

MODEL_CARD.template.md CHANGED
@@ -144,6 +144,12 @@ questions, the model sent 6 of 3,680 benign examples to review. These results
144
  describe the published test samples; they do not guarantee the same behavior on
145
  production traffic.
146
 
 
 
 
 
 
 
147
  `metrics.json` contains the exact counts, confidence intervals, data audit,
148
  candidate comparisons, and broader diagnostic results. Those diagnostics are
149
  substantially weaker because several datasets mix prompt injection, jailbreak,
@@ -178,6 +184,13 @@ transformations, split policy, licenses, and third-party attributions. See
178
  [model_manifest.json](./model_manifest.json).
179
  The trained artifact is CC BY-SA 3.0; the source code is MIT.
180
 
 
 
 
 
 
 
 
181
  To reproduce the release in a clean Python 3.12 environment:
182
 
183
  ```bash
 
144
  describe the published test samples; they do not guarantee the same behavior on
145
  production traffic.
146
 
147
+ The NVIDIA-derived validation and test splits contain 27 and 92 repeated
148
+ normalized texts within their respective held-out domains. Domain separation
149
+ and paired `group_id` evaluation are preserved, but row-level confidence
150
+ intervals should not be interpreted as if every row were statistically
151
+ independent.
152
+
153
  `metrics.json` contains the exact counts, confidence intervals, data audit,
154
  candidate comparisons, and broader diagnostic results. Those diagnostics are
155
  substantially weaker because several datasets mix prompt injection, jailbreak,
 
184
  [model_manifest.json](./model_manifest.json).
185
  The trained artifact is CC BY-SA 3.0; the source code is MIT.
186
 
187
+ Version 0.1.1 fixes project-root resolution in the included training script so
188
+ the documented repository-root command completes release assembly. It also
189
+ records the SHA-256 digest of every locked dataset file. The model formulation,
190
+ threshold, complete validation and lockbox decision scores, and predictions are
191
+ unchanged from version 0.1.0; the release improves reproducibility and
192
+ provenance rather than classifier behavior.
193
+
194
  To reproduce the release in a clean Python 3.12 environment:
195
 
196
  ```bash
README.md CHANGED
@@ -70,7 +70,7 @@ model-index:
70
  value: 1.0000
71
  ---
72
 
73
- # Agentic Injection Review Lite v0.1.0
74
 
75
  Agentic Injection Review Lite is a lightweight English text classifier for
76
  screening untrusted text before an AI agent uses it. It flags language that
@@ -144,6 +144,12 @@ questions, the model sent 6 of 3,680 benign examples to review. These results
144
  describe the published test samples; they do not guarantee the same behavior on
145
  production traffic.
146
 
 
 
 
 
 
 
147
  `metrics.json` contains the exact counts, confidence intervals, data audit,
148
  candidate comparisons, and broader diagnostic results. Those diagnostics are
149
  substantially weaker because several datasets mix prompt injection, jailbreak,
@@ -178,6 +184,13 @@ transformations, split policy, licenses, and third-party attributions. See
178
  [model_manifest.json](./model_manifest.json).
179
  The trained artifact is CC BY-SA 3.0; the source code is MIT.
180
 
 
 
 
 
 
 
 
181
  To reproduce the release in a clean Python 3.12 environment:
182
 
183
  ```bash
 
70
  value: 1.0000
71
  ---
72
 
73
+ # Agentic Injection Review Lite v0.1.1
74
 
75
  Agentic Injection Review Lite is a lightweight English text classifier for
76
  screening untrusted text before an AI agent uses it. It flags language that
 
144
  describe the published test samples; they do not guarantee the same behavior on
145
  production traffic.
146
 
147
+ The NVIDIA-derived validation and test splits contain 27 and 92 repeated
148
+ normalized texts within their respective held-out domains. Domain separation
149
+ and paired `group_id` evaluation are preserved, but row-level confidence
150
+ intervals should not be interpreted as if every row were statistically
151
+ independent.
152
+
153
  `metrics.json` contains the exact counts, confidence intervals, data audit,
154
  candidate comparisons, and broader diagnostic results. Those diagnostics are
155
  substantially weaker because several datasets mix prompt injection, jailbreak,
 
184
  [model_manifest.json](./model_manifest.json).
185
  The trained artifact is CC BY-SA 3.0; the source code is MIT.
186
 
187
+ Version 0.1.1 fixes project-root resolution in the included training script so
188
+ the documented repository-root command completes release assembly. It also
189
+ records the SHA-256 digest of every locked dataset file. The model formulation,
190
+ threshold, complete validation and lockbox decision scores, and predictions are
191
+ unchanged from version 0.1.0; the release improves reproducibility and
192
+ provenance rather than classifier behavior.
193
+
194
  To reproduce the release in a clean Python 3.12 environment:
195
 
196
  ```bash
checksums.sha256 CHANGED
@@ -1,16 +1,16 @@
1
  bd3508fbe8e739c82aaec4c3429c1fe2c1de52d32960a47fa605aaac37db40c9 ATTRIBUTION.md
2
  7b8d82edce8f68538edfe88ac8c796de51ad2274033b1068bf77be23466cbcdf LICENSE
3
  467416515c08b60ef9ab26725c9b5274ef0c9a27d27df3c57809354585d52be9 LICENSE-CODE
4
- 79fb37cb228418c1c6e5410d760f04630cf0abfcf2e41a7d04a836a614e37b6e MODEL_CARD.template.md
5
  7b8d82edce8f68538edfe88ac8c796de51ad2274033b1068bf77be23466cbcdf MODEL_LICENSE.md
6
- a5d120ba623943ce9f2e50ddf1e7e29997746e69fe8c563e7430764d01f9ddd7 README.md
7
  bd3508fbe8e739c82aaec4c3429c1fe2c1de52d32960a47fa605aaac37db40c9 THIRD_PARTY_NOTICES.md
8
  da1b732a1f2afdcded4094e11d9c6bf466bbfd7c5f25f79aa3994d8ab088cfac config.json
9
- 4159a9818ea84bcd34332b2b9bb53028a0d5e12f8039703bc913332c408495f7 dataset_manifest.json
10
- c1b191b92f4cd99148feacf3f083ae30a483f294127edd2154a25c1c84d75f5b detector_config.json
11
- 4f07d87245c9bb094eb5982c7eb4a9b55869d6eca7b0fe9ab23ea54f07545041 metrics.json
12
- e73971cda7bba9165cffa57bcefc0109361b8ec8783381ca91a398804e6a92e6 model.skops
13
- 0d30629e0774b3abbde844b844bcd183ff05038096c1927f98c95a825a2b5d44 model_manifest.json
14
  1b7a5f27ac4fcb95dbe1581d8203fbf636dbf564b6ef10647d8818e3ae5a4d26 requirements-train.txt
15
  6e4faa6fa81cd15034c467bf1a78aed2dcb31f91705d643314a420c7e6e69bd7 requirements.txt
16
- a20871de7ff9e4da291e67d9ab8b7e22f7df65426f66167f420200a189716a58 train.py
 
1
  bd3508fbe8e739c82aaec4c3429c1fe2c1de52d32960a47fa605aaac37db40c9 ATTRIBUTION.md
2
  7b8d82edce8f68538edfe88ac8c796de51ad2274033b1068bf77be23466cbcdf LICENSE
3
  467416515c08b60ef9ab26725c9b5274ef0c9a27d27df3c57809354585d52be9 LICENSE-CODE
4
+ 4f03e04cf333f140d6a601dd37b5b4ee8dd2bc8cdefb224429950c389e23232c MODEL_CARD.template.md
5
  7b8d82edce8f68538edfe88ac8c796de51ad2274033b1068bf77be23466cbcdf MODEL_LICENSE.md
6
+ 7fd259e91f9c9a7f07d674491d05a5318504132eb02593b6db4aa23553c9f31c README.md
7
  bd3508fbe8e739c82aaec4c3429c1fe2c1de52d32960a47fa605aaac37db40c9 THIRD_PARTY_NOTICES.md
8
  da1b732a1f2afdcded4094e11d9c6bf466bbfd7c5f25f79aa3994d8ab088cfac config.json
9
+ 67383a37df5687583b9944e96e0efd6bfe871929dc0245ca868729cea017a2ba dataset_manifest.json
10
+ 1a37981b44a091ef55f6888b4f790d1e0895548da7599b2491a8a312036747c1 detector_config.json
11
+ ac70f0200b72c322a613de9bcd57e13176296d98aac88d227a5340c595180cdf metrics.json
12
+ fbbd30b55c64029b883771976a35e156c4e2d0eb71dff7d911d01f18b29831ea model.skops
13
+ 942d8405fc8df57444fd073b0c0b4f0507bc4439ca4cd8fdb720efa890e6e699 model_manifest.json
14
  1b7a5f27ac4fcb95dbe1581d8203fbf636dbf564b6ef10647d8818e3ae5a4d26 requirements-train.txt
15
  6e4faa6fa81cd15034c467bf1a78aed2dcb31f91705d643314a420c7e6e69bd7 requirements.txt
16
+ 3c2a365d1e0e6014e42414bbf13997dc68d6dba09b4f7810fcae57918d014f6e train.py
dataset_manifest.json CHANGED
@@ -5,6 +5,11 @@
5
  "id": "3nesdeniz/agentic-prompt-injection-boundary-pairs",
6
  "revision": "a5682e7573e1c7bc4b12e64d49c0dcd90ca776cf",
7
  "files": ["data/train.parquet", "data/validation.parquet", "data/test.parquet"],
 
 
 
 
 
8
  "license": "cc-by-4.0",
9
  "role": "train_validation_test"
10
  },
@@ -12,6 +17,9 @@
12
  "id": "nvidia/Nemotron-RL-Agentic-Indirect-Prompt-Injection-v1",
13
  "revision": "d738d4f361cc38bb4d7a42b9066776dade5332f5",
14
  "files": ["train.jsonl"],
 
 
 
15
  "license": "cc-by-4.0",
16
  "role": "derived_train_validation_test"
17
  },
@@ -19,6 +27,9 @@
19
  "id": "databricks/databricks-dolly-15k",
20
  "revision": "bdd27f4d94b9c1f951818a7da7fd7aeea5dbff1a",
21
  "files": ["databricks-dolly-15k.jsonl"],
 
 
 
22
  "license": "cc-by-sa-3.0",
23
  "role": "benign_train_validation_test"
24
  },
@@ -26,6 +37,9 @@
26
  "id": "yanismiraoui/prompt_injections",
27
  "revision": "bd55359f2f332afc35f277ac3dd08f7111b024c9",
28
  "files": ["prompt_injections.csv"],
 
 
 
29
  "license": "apache-2.0",
30
  "role": "positive_train_validation"
31
  },
@@ -33,6 +47,9 @@
33
  "id": "jackhhao/jailbreak-classification",
34
  "revision": "2f2ceeb39658696fd3f462403562b6eea5306287",
35
  "files": ["balanced/jailbreak_dataset_test_balanced.csv"],
 
 
 
36
  "license": "apache-2.0-metadata-only",
37
  "role": "diagnostic_only"
38
  },
@@ -40,6 +57,9 @@
40
  "id": "deepset/prompt-injections",
41
  "revision": "4f61ecb038e9c3fb77e21034b22511b523772cdd",
42
  "files": ["data/test-00000-of-00001-701d16158af87368.parquet"],
 
 
 
43
  "license": "ambiguous-apache-2.0-or-cc-by-4.0",
44
  "role": "diagnostic_only"
45
  },
@@ -47,9 +67,11 @@
47
  "id": "neuralchemy/prompt-injection-benign-dataset",
48
  "revision": "7d70432dfcf47a821612cbf9d34e9d9e3ad20e75",
49
  "files": ["core/test-00000-of-00001.parquet"],
 
 
 
50
  "license": "mixed-source-aggregate",
51
  "role": "diagnostic_only"
52
  }
53
  ]
54
  }
55
-
 
5
  "id": "3nesdeniz/agentic-prompt-injection-boundary-pairs",
6
  "revision": "a5682e7573e1c7bc4b12e64d49c0dcd90ca776cf",
7
  "files": ["data/train.parquet", "data/validation.parquet", "data/test.parquet"],
8
+ "file_sha256": {
9
+ "data/train.parquet": "12f7cb0d4790a684574b46165f8538f898966b47bfc9da322e12806089ad5e04",
10
+ "data/validation.parquet": "1538875e45b8034070815003ad24b043d71c612f7728c4fd1d24416f53b74f49",
11
+ "data/test.parquet": "d47124d655765d88e1b3adc0dfa25b03c9959f2c99d196c47da77d8683c7e508"
12
+ },
13
  "license": "cc-by-4.0",
14
  "role": "train_validation_test"
15
  },
 
17
  "id": "nvidia/Nemotron-RL-Agentic-Indirect-Prompt-Injection-v1",
18
  "revision": "d738d4f361cc38bb4d7a42b9066776dade5332f5",
19
  "files": ["train.jsonl"],
20
+ "file_sha256": {
21
+ "train.jsonl": "3329da17564a7eb287e2730fc7d6956e1f4fe51e8950ac4f110b3c37e78cf3b9"
22
+ },
23
  "license": "cc-by-4.0",
24
  "role": "derived_train_validation_test"
25
  },
 
27
  "id": "databricks/databricks-dolly-15k",
28
  "revision": "bdd27f4d94b9c1f951818a7da7fd7aeea5dbff1a",
29
  "files": ["databricks-dolly-15k.jsonl"],
30
+ "file_sha256": {
31
+ "databricks-dolly-15k.jsonl": "2df9083338b4abd6bceb5635764dab5d833b393b55759dffb0959b6fcbf794ec"
32
+ },
33
  "license": "cc-by-sa-3.0",
34
  "role": "benign_train_validation_test"
35
  },
 
37
  "id": "yanismiraoui/prompt_injections",
38
  "revision": "bd55359f2f332afc35f277ac3dd08f7111b024c9",
39
  "files": ["prompt_injections.csv"],
40
+ "file_sha256": {
41
+ "prompt_injections.csv": "f4843f1841fa19b980f804796a68fc72f06841775eaba2723c768c7d772aabad"
42
+ },
43
  "license": "apache-2.0",
44
  "role": "positive_train_validation"
45
  },
 
47
  "id": "jackhhao/jailbreak-classification",
48
  "revision": "2f2ceeb39658696fd3f462403562b6eea5306287",
49
  "files": ["balanced/jailbreak_dataset_test_balanced.csv"],
50
+ "file_sha256": {
51
+ "balanced/jailbreak_dataset_test_balanced.csv": "809ef0d7c82fa05c31e818e9c3ff68f769632ac6d11cc3b43254cada577869a9"
52
+ },
53
  "license": "apache-2.0-metadata-only",
54
  "role": "diagnostic_only"
55
  },
 
57
  "id": "deepset/prompt-injections",
58
  "revision": "4f61ecb038e9c3fb77e21034b22511b523772cdd",
59
  "files": ["data/test-00000-of-00001-701d16158af87368.parquet"],
60
+ "file_sha256": {
61
+ "data/test-00000-of-00001-701d16158af87368.parquet": "39ac797cabc157eeed58435a08593b2952bb6cb16fc394a2d383f447cc7b246e"
62
+ },
63
  "license": "ambiguous-apache-2.0-or-cc-by-4.0",
64
  "role": "diagnostic_only"
65
  },
 
67
  "id": "neuralchemy/prompt-injection-benign-dataset",
68
  "revision": "7d70432dfcf47a821612cbf9d34e9d9e3ad20e75",
69
  "files": ["core/test-00000-of-00001.parquet"],
70
+ "file_sha256": {
71
+ "core/test-00000-of-00001.parquet": "fb5432035fdd8453d61f6593bfe78ee2970403c5ea59959b642a6708e2bef670"
72
+ },
73
  "license": "mixed-source-aggregate",
74
  "role": "diagnostic_only"
75
  }
76
  ]
77
  }
 
detector_config.json CHANGED
@@ -2,8 +2,8 @@
2
  "decision_threshold": -0.7598804523157342,
3
  "max_input_chars": 20000,
4
  "model_file": "model.skops",
5
- "model_sha256": "e73971cda7bba9165cffa57bcefc0109361b8ec8783381ca91a398804e6a92e6",
6
- "model_version": "0.1.0",
7
  "negative_label": "allow",
8
  "numpy_version": "2.5.1",
9
  "positive_label": "review",
 
2
  "decision_threshold": -0.7598804523157342,
3
  "max_input_chars": 20000,
4
  "model_file": "model.skops",
5
+ "model_sha256": "fbbd30b55c64029b883771976a35e156c4e2d0eb71dff7d911d01f18b29831ea",
6
+ "model_version": "0.1.1",
7
  "negative_label": "allow",
8
  "numpy_version": "2.5.1",
9
  "positive_label": "review",
metrics.json CHANGED
@@ -62,7 +62,7 @@
62
  "threshold": -0.30457667593634397,
63
  "worst_fpr_limit_ratio": 0.5736137667304015
64
  },
65
- "training_seconds": 2.53921562503092
66
  },
67
  "hash_sgd_alpha_1e-5": {
68
  "threshold_selection": {
@@ -121,7 +121,7 @@
121
  "threshold": -0.7598804523157342,
122
  "worst_fpr_limit_ratio": 0.9082217973231358
123
  },
124
- "training_seconds": 2.2363845839863643
125
  },
126
  "hash_sgd_alpha_3e-5": {
127
  "threshold_selection": {
@@ -180,7 +180,7 @@
180
  "threshold": -0.09286502046714196,
181
  "worst_fpr_limit_ratio": 0.5736137667304015
182
  },
183
- "training_seconds": 2.2174021669779904
184
  }
185
  },
186
  "data_audit": {
@@ -218,6 +218,19 @@
218
  "training_class_counts": {
219
  "0": 10393,
220
  "1": 1722
 
 
 
 
 
 
 
 
 
 
 
 
 
221
  }
222
  },
223
  "diagnostics": {
@@ -303,34 +316,34 @@
303
  "latency": {
304
  "long": {
305
  "1": {
306
- "median_us_per_row": 7389.417,
307
- "p95_us_per_row": 7458.433
308
  },
309
  "128": {
310
- "median_us_per_row": 6829.7705078125,
311
- "p95_us_per_row": 6915.0828109375
312
  },
313
  "32": {
314
- "median_us_per_row": 6879.05596875,
315
- "p95_us_per_row": 6896.61614375
316
  }
317
  },
318
  "short": {
319
  "1": {
320
- "median_us_per_row": 348.833,
321
- "p95_us_per_row": 363.7086
322
  },
323
  "128": {
324
- "median_us_per_row": 28.5426484375,
325
- "p95_us_per_row": 29.1750625
326
  },
327
  "32": {
328
- "median_us_per_row": 35.6888125,
329
- "p95_us_per_row": 35.994262500000005
330
  }
331
  }
332
  },
333
- "model_version": "0.1.0",
334
  "schema_version": 1,
335
  "seed": 20260805,
336
  "selection_policy": "validation-only; tests and diagnostics are excluded",
 
62
  "threshold": -0.30457667593634397,
63
  "worst_fpr_limit_ratio": 0.5736137667304015
64
  },
65
+ "training_seconds": 2.380033750028815
66
  },
67
  "hash_sgd_alpha_1e-5": {
68
  "threshold_selection": {
 
121
  "threshold": -0.7598804523157342,
122
  "worst_fpr_limit_ratio": 0.9082217973231358
123
  },
124
+ "training_seconds": 2.087675833958201
125
  },
126
  "hash_sgd_alpha_3e-5": {
127
  "threshold_selection": {
 
180
  "threshold": -0.09286502046714196,
181
  "worst_fpr_limit_ratio": 0.5736137667304015
182
  },
183
+ "training_seconds": 2.097628415969666
184
  }
185
  },
186
  "data_audit": {
 
218
  "training_class_counts": {
219
  "0": 10393,
220
  "1": 1722
221
+ },
222
+ "within_split_normalized_duplicates": {
223
+ "boundary_scenario_test": 0,
224
+ "boundary_validation": 0,
225
+ "deepset_ambiguous_diagnostic": 0,
226
+ "dolly_general_qa_validation": 0,
227
+ "dolly_open_qa_test": 0,
228
+ "jack_jailbreak_diagnostic": 0,
229
+ "neuralchemy_mixed_diagnostic": 0,
230
+ "nvidia_domain_test": 92,
231
+ "nvidia_domain_validation": 27,
232
+ "training": 0,
233
+ "yanis_attack_validation": 0
234
  }
235
  },
236
  "diagnostics": {
 
316
  "latency": {
317
  "long": {
318
  "1": {
319
+ "median_us_per_row": 7133.458,
320
+ "p95_us_per_row": 7167.9746
321
  },
322
  "128": {
323
+ "median_us_per_row": 6721.4423828125,
324
+ "p95_us_per_row": 6743.34511875
325
  },
326
  "32": {
327
+ "median_us_per_row": 6703.6328125,
328
+ "p95_us_per_row": 6741.2896
329
  }
330
  },
331
  "short": {
332
  "1": {
333
+ "median_us_per_row": 326.666,
334
+ "p95_us_per_row": 338.14119999999997
335
  },
336
  "128": {
337
+ "median_us_per_row": 27.46809375,
338
+ "p95_us_per_row": 28.1366546875
339
  },
340
  "32": {
341
+ "median_us_per_row": 34.3111875,
342
+ "p95_us_per_row": 34.9351625
343
  }
344
  }
345
  },
346
+ "model_version": "0.1.1",
347
  "schema_version": 1,
348
  "seed": 20260805,
349
  "selection_policy": "validation-only; tests and diagnostics are excluded",
model.skops CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:e73971cda7bba9165cffa57bcefc0109361b8ec8783381ca91a398804e6a92e6
3
  size 3204271
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:fbbd30b55c64029b883771976a35e156c4e2d0eb71dff7d911d01f18b29831ea
3
  size 3204271
model_manifest.json CHANGED
@@ -1,9 +1,9 @@
1
  {
2
- "dataset_lock_sha256": "4159a9818ea84bcd34332b2b9bb53028a0d5e12f8039703bc913332c408495f7",
3
  "maintainer": "Ali Zakaee (ITheEqualizer)",
4
- "metrics_sha256": "4f07d87245c9bb094eb5982c7eb4a9b55869d6eca7b0fe9ab23ea54f07545041",
5
- "model_sha256": "e73971cda7bba9165cffa57bcefc0109361b8ec8783381ca91a398804e6a92e6",
6
- "model_version": "0.1.0",
7
  "schema_version": 1,
8
- "training_script_sha256": "a20871de7ff9e4da291e67d9ab8b7e22f7df65426f66167f420200a189716a58"
9
  }
 
1
  {
2
+ "dataset_lock_sha256": "67383a37df5687583b9944e96e0efd6bfe871929dc0245ca868729cea017a2ba",
3
  "maintainer": "Ali Zakaee (ITheEqualizer)",
4
+ "metrics_sha256": "ac70f0200b72c322a613de9bcd57e13176296d98aac88d227a5340c595180cdf",
5
+ "model_sha256": "fbbd30b55c64029b883771976a35e156c4e2d0eb71dff7d911d01f18b29831ea",
6
+ "model_version": "0.1.1",
7
  "schema_version": 1,
8
+ "training_script_sha256": "3c2a365d1e0e6014e42414bbf13997dc68d6dba09b4f7810fcae57918d014f6e"
9
  }
train.py CHANGED
@@ -36,7 +36,7 @@ from sklearn.metrics import (
36
  from sklearn.pipeline import FeatureUnion, Pipeline
37
 
38
  SEED = 20260805
39
- MODEL_VERSION = "0.1.0"
40
 
41
 
42
  @dataclass(frozen=True)
@@ -93,6 +93,26 @@ def sha256(path: Path) -> str:
93
  return digest.hexdigest()
94
 
95
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
  def download(source: Source, filename: str, cache_dir: Path) -> Path:
97
  return Path(
98
  hf_hub_download(
@@ -390,6 +410,21 @@ def build_bundle(cache_dir: Path) -> DataBundle:
390
  **{name: len(frame) for name, frame in tests.items()},
391
  **{name: len(frame) for name, frame in cleaned_diagnostics.items()},
392
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
393
  return DataBundle(
394
  training=training,
395
  validation=validation,
@@ -923,10 +958,7 @@ def main() -> None:
923
  parser.add_argument("--output", type=Path, default=Path("release"))
924
  parser.add_argument("--cache-dir", type=Path, default=Path("cache"))
925
  args = parser.parse_args()
926
- source_root = Path(__file__).resolve().parents[2]
927
- project_root = (
928
- Path.cwd() if (Path.cwd() / "MODEL_CARD.template.md").exists() else source_root
929
- )
930
  bundle = build_bundle(args.cache_dir)
931
  model, metrics = train(bundle)
932
  write_release(project_root, args.output, model, metrics)
 
36
  from sklearn.pipeline import FeatureUnion, Pipeline
37
 
38
  SEED = 20260805
39
+ MODEL_VERSION = "0.1.1"
40
 
41
 
42
  @dataclass(frozen=True)
 
93
  return digest.hexdigest()
94
 
95
 
96
+ def resolve_project_root(script_path: Path, cwd: Path) -> Path:
97
+ resolved_script = script_path.resolve()
98
+ candidates = [resolved_script.parent, cwd.resolve()]
99
+ if len(resolved_script.parents) > 2:
100
+ candidates.append(resolved_script.parents[2])
101
+ for candidate in dict.fromkeys(candidates):
102
+ has_card = (candidate / "MODEL_CARD.template.md").exists() or (
103
+ candidate / "templates" / "MODEL_CARD.md"
104
+ ).exists()
105
+ has_dataset_lock = (candidate / "dataset_manifest.json").exists() or (
106
+ candidate / "manifests" / "datasets.lock.json"
107
+ ).exists()
108
+ if has_card and has_dataset_lock:
109
+ return candidate
110
+ raise FileNotFoundError(
111
+ "could not resolve a project root containing a model-card template "
112
+ "and dataset manifest"
113
+ )
114
+
115
+
116
  def download(source: Source, filename: str, cache_dir: Path) -> Path:
117
  return Path(
118
  hf_hub_download(
 
410
  **{name: len(frame) for name, frame in tests.items()},
411
  **{name: len(frame) for name, frame in cleaned_diagnostics.items()},
412
  }
413
+ audit["within_split_normalized_duplicates"] = {
414
+ "training": int(training["normalized"].duplicated().sum()),
415
+ **{
416
+ name: int(frame["normalized"].duplicated().sum())
417
+ for name, frame in validation.items()
418
+ },
419
+ **{
420
+ name: int(frame["normalized"].duplicated().sum())
421
+ for name, frame in tests.items()
422
+ },
423
+ **{
424
+ name: int(frame["normalized"].duplicated().sum())
425
+ for name, frame in cleaned_diagnostics.items()
426
+ },
427
+ }
428
  return DataBundle(
429
  training=training,
430
  validation=validation,
 
958
  parser.add_argument("--output", type=Path, default=Path("release"))
959
  parser.add_argument("--cache-dir", type=Path, default=Path("cache"))
960
  args = parser.parse_args()
961
+ project_root = resolve_project_root(Path(__file__), Path.cwd())
 
 
 
962
  bundle = build_bundle(args.cache_dir)
963
  model, metrics = train(bundle)
964
  write_release(project_root, args.output, model, metrics)