@r1z4x/tezgah 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (582) hide show
  1. package/CHANGELOG.md +738 -0
  2. package/LICENSE +21 -0
  3. package/MANIFEST +753 -0
  4. package/README.de.md +169 -0
  5. package/README.es.md +168 -0
  6. package/README.fr.md +166 -0
  7. package/README.md +161 -0
  8. package/README.tr.md +163 -0
  9. package/agents/tezgah-reviewer.md +70 -0
  10. package/bin/codegen +337 -0
  11. package/bin/consult +797 -0
  12. package/bin/tezgah-adhd +50 -0
  13. package/bin/tezgah-agents +45 -0
  14. package/bin/tezgah-capture +66 -0
  15. package/bin/tezgah-context +96 -0
  16. package/bin/tezgah-decisions +213 -0
  17. package/bin/tezgah-design +953 -0
  18. package/bin/tezgah-docs +1199 -0
  19. package/bin/tezgah-doctor +497 -0
  20. package/bin/tezgah-dsh +37 -0
  21. package/bin/tezgah-dsh.cmd +70 -0
  22. package/bin/tezgah-gate +75 -0
  23. package/bin/tezgah-import-ai-research +439 -0
  24. package/bin/tezgah-index +32 -0
  25. package/bin/tezgah-lessons +148 -0
  26. package/bin/tezgah-mcp +322 -0
  27. package/bin/tezgah-migrate +324 -0
  28. package/bin/tezgah-pony +50 -0
  29. package/bin/tezgah-research +772 -0
  30. package/bin/tezgah-rollback +93 -0
  31. package/bin/tezgah-route +124 -0
  32. package/bin/tezgah-setup +5798 -0
  33. package/bin/tezgah-status +383 -0
  34. package/bin/tezgah-task +607 -0
  35. package/bin/tezgah-taste +423 -0
  36. package/bin/tezgah-triage +485 -0
  37. package/bin/tezgah.js +36 -0
  38. package/commands/adhd.md +21 -0
  39. package/commands/ponytail.md +21 -0
  40. package/docs/README.md +112 -0
  41. package/docs/architecture.md +226 -0
  42. package/docs/citations-baseline.json +59 -0
  43. package/docs/clarity-baseline.json +116 -0
  44. package/docs/contract.md +416 -0
  45. package/docs/environment.md +141 -0
  46. package/docs/evidence.md +831 -0
  47. package/docs/feature-audit.md +139 -0
  48. package/docs/gate.md +407 -0
  49. package/docs/glossary.md +201 -0
  50. package/docs/hosts.md +400 -0
  51. package/docs/index.json +471 -0
  52. package/docs/judge.md +193 -0
  53. package/docs/layers.md +189 -0
  54. package/docs/models.md +160 -0
  55. package/docs/operations.md +666 -0
  56. package/docs/research.md +809 -0
  57. package/docs/results/paired-outcome-2026-10.jsonl +254 -0
  58. package/docs/results/paired-outcome-2026-10.md +204 -0
  59. package/docs/skills.md +236 -0
  60. package/docs/status-line.md +315 -0
  61. package/docs/testing.md +287 -0
  62. package/docs/vision.md +117 -0
  63. package/hooks/hooks.json +33 -0
  64. package/hooks/projects-auto-init.py +98 -0
  65. package/hooks/projects-posttooluse.py +149 -0
  66. package/hooks/projects-pretooluse.py +40 -0
  67. package/hooks/projects-stop.py +60 -0
  68. package/hooks/tezgah_agents.py +817 -0
  69. package/hooks/tezgah_apps.py +266 -0
  70. package/hooks/tezgah_attest.py +255 -0
  71. package/hooks/tezgah_clarity.py +171 -0
  72. package/hooks/tezgah_components.py +140 -0
  73. package/hooks/tezgah_context.py +2953 -0
  74. package/hooks/tezgah_embed.py +765 -0
  75. package/hooks/tezgah_gate.py +2736 -0
  76. package/hooks/tezgah_guard.py +177 -0
  77. package/hooks/tezgah_index.py +124 -0
  78. package/hooks/tezgah_integrity.py +5141 -0
  79. package/hooks/tezgah_judge.py +487 -0
  80. package/hooks/tezgah_lang.py +230 -0
  81. package/hooks/tezgah_lessons.py +210 -0
  82. package/hooks/tezgah_models.py +855 -0
  83. package/hooks/tezgah_paths.py +1132 -0
  84. package/hooks/tezgah_policy.py +1039 -0
  85. package/hooks/tezgah_rank.py +77 -0
  86. package/hooks/tezgah_replay.py +1109 -0
  87. package/hooks/tezgah_research.py +5176 -0
  88. package/hooks/tezgah_shapes.py +305 -0
  89. package/hooks/tezgah_skill_pick.py +227 -0
  90. package/hooks/tezgah_snapshot.py +490 -0
  91. package/hooks/tezgah_stopspec.py +320 -0
  92. package/hooks/tezgah_task.py +458 -0
  93. package/hooks/tezgah_taste.py +201 -0
  94. package/hooks/tezgah_untrusted.py +112 -0
  95. package/hooks/tezgah_update.py +430 -0
  96. package/hosts/codex/hook.py +268 -0
  97. package/hosts/codex/hooks.json +26 -0
  98. package/hosts/cursor/hook.py +461 -0
  99. package/hosts/cursor/hooks.json +44 -0
  100. package/hosts/dsh/hooks.json +21 -0
  101. package/hosts/dsh/statusline/lib/client.js +138 -0
  102. package/hosts/dsh/statusline/lib/index.js +104 -0
  103. package/hosts/dsh/statusline/package.json +28 -0
  104. package/hosts/omp/hook.py +277 -0
  105. package/hosts/omp/tezgah-hook.ts.in +701 -0
  106. package/hosts/opencode/plugins/tezgah.js +2742 -0
  107. package/hosts/opencode/tui/tezgah-tui.tsx +151 -0
  108. package/output-styles/tezgah.md +142 -0
  109. package/package.json +32 -0
  110. package/packaging/build.sh +342 -0
  111. package/packaging/install.ps1 +166 -0
  112. package/packaging/install.sh +56 -0
  113. package/packaging/upgrade.sh +142 -0
  114. package/skills/ai-research/0-autoresearch-skill/SKILL.md +411 -0
  115. package/skills/ai-research/0-autoresearch-skill/references/agent-continuity.md +95 -0
  116. package/skills/ai-research/0-autoresearch-skill/references/progress-reporting.md +166 -0
  117. package/skills/ai-research/0-autoresearch-skill/references/skill-routing.md +219 -0
  118. package/skills/ai-research/0-autoresearch-skill/templates/findings.md +44 -0
  119. package/skills/ai-research/0-autoresearch-skill/templates/research-log.md +41 -0
  120. package/skills/ai-research/01-model-architecture/litgpt/SKILL.md +469 -0
  121. package/skills/ai-research/01-model-architecture/litgpt/references/custom-models.md +569 -0
  122. package/skills/ai-research/01-model-architecture/litgpt/references/distributed-training.md +452 -0
  123. package/skills/ai-research/01-model-architecture/litgpt/references/supported-models.md +337 -0
  124. package/skills/ai-research/01-model-architecture/litgpt/references/training-recipes.md +620 -0
  125. package/skills/ai-research/01-model-architecture/mamba/SKILL.md +260 -0
  126. package/skills/ai-research/01-model-architecture/mamba/references/architecture-details.md +207 -0
  127. package/skills/ai-research/01-model-architecture/mamba/references/benchmarks.md +256 -0
  128. package/skills/ai-research/01-model-architecture/mamba/references/training-guide.md +389 -0
  129. package/skills/ai-research/01-model-architecture/nanogpt/SKILL.md +290 -0
  130. package/skills/ai-research/01-model-architecture/nanogpt/references/architecture.md +383 -0
  131. package/skills/ai-research/01-model-architecture/nanogpt/references/data.md +477 -0
  132. package/skills/ai-research/01-model-architecture/nanogpt/references/training.md +565 -0
  133. package/skills/ai-research/01-model-architecture/rwkv/SKILL.md +260 -0
  134. package/skills/ai-research/01-model-architecture/rwkv/references/architecture-details.md +345 -0
  135. package/skills/ai-research/01-model-architecture/rwkv/references/rwkv7.md +387 -0
  136. package/skills/ai-research/01-model-architecture/rwkv/references/state-management.md +370 -0
  137. package/skills/ai-research/01-model-architecture/torchtitan/SKILL.md +358 -0
  138. package/skills/ai-research/01-model-architecture/torchtitan/references/checkpoint.md +182 -0
  139. package/skills/ai-research/01-model-architecture/torchtitan/references/custom-models.md +259 -0
  140. package/skills/ai-research/01-model-architecture/torchtitan/references/float8.md +134 -0
  141. package/skills/ai-research/01-model-architecture/torchtitan/references/fsdp.md +127 -0
  142. package/skills/ai-research/02-tokenization/huggingface-tokenizers/SKILL.md +516 -0
  143. package/skills/ai-research/02-tokenization/huggingface-tokenizers/references/algorithms.md +654 -0
  144. package/skills/ai-research/02-tokenization/huggingface-tokenizers/references/integration.md +638 -0
  145. package/skills/ai-research/02-tokenization/huggingface-tokenizers/references/pipeline.md +724 -0
  146. package/skills/ai-research/02-tokenization/huggingface-tokenizers/references/training.md +566 -0
  147. package/skills/ai-research/02-tokenization/sentencepiece/SKILL.md +235 -0
  148. package/skills/ai-research/02-tokenization/sentencepiece/references/algorithms.md +201 -0
  149. package/skills/ai-research/02-tokenization/sentencepiece/references/training.md +305 -0
  150. package/skills/ai-research/03-fine-tuning/axolotl/SKILL.md +158 -0
  151. package/skills/ai-research/03-fine-tuning/axolotl/references/api.md +5549 -0
  152. package/skills/ai-research/03-fine-tuning/axolotl/references/dataset-formats.md +1030 -0
  153. package/skills/ai-research/03-fine-tuning/axolotl/references/index.md +16 -0
  154. package/skills/ai-research/03-fine-tuning/axolotl/references/other.md +3564 -0
  155. package/skills/ai-research/03-fine-tuning/llama-factory/SKILL.md +80 -0
  156. package/skills/ai-research/03-fine-tuning/llama-factory/references/_images.md +24 -0
  157. package/skills/ai-research/03-fine-tuning/llama-factory/references/advanced.md +1056 -0
  158. package/skills/ai-research/03-fine-tuning/llama-factory/references/getting_started.md +350 -0
  159. package/skills/ai-research/03-fine-tuning/llama-factory/references/index.md +20 -0
  160. package/skills/ai-research/03-fine-tuning/llama-factory/references/other.md +32 -0
  161. package/skills/ai-research/03-fine-tuning/peft/SKILL.md +431 -0
  162. package/skills/ai-research/03-fine-tuning/peft/references/advanced-usage.md +515 -0
  163. package/skills/ai-research/03-fine-tuning/peft/references/troubleshooting.md +481 -0
  164. package/skills/ai-research/03-fine-tuning/unsloth/SKILL.md +80 -0
  165. package/skills/ai-research/03-fine-tuning/unsloth/references/index.md +8 -0
  166. package/skills/ai-research/03-fine-tuning/unsloth/references/llms.md +83 -0
  167. package/skills/ai-research/04-mechanistic-interpretability/nnsight/SKILL.md +436 -0
  168. package/skills/ai-research/04-mechanistic-interpretability/nnsight/references/README.md +79 -0
  169. package/skills/ai-research/04-mechanistic-interpretability/nnsight/references/api.md +345 -0
  170. package/skills/ai-research/04-mechanistic-interpretability/nnsight/references/tutorials.md +301 -0
  171. package/skills/ai-research/04-mechanistic-interpretability/pyvene/SKILL.md +473 -0
  172. package/skills/ai-research/04-mechanistic-interpretability/pyvene/references/README.md +74 -0
  173. package/skills/ai-research/04-mechanistic-interpretability/pyvene/references/api.md +384 -0
  174. package/skills/ai-research/04-mechanistic-interpretability/pyvene/references/tutorials.md +377 -0
  175. package/skills/ai-research/04-mechanistic-interpretability/saelens/SKILL.md +386 -0
  176. package/skills/ai-research/04-mechanistic-interpretability/saelens/references/README.md +71 -0
  177. package/skills/ai-research/04-mechanistic-interpretability/saelens/references/api.md +334 -0
  178. package/skills/ai-research/04-mechanistic-interpretability/saelens/references/tutorials.md +319 -0
  179. package/skills/ai-research/04-mechanistic-interpretability/transformer-lens/SKILL.md +346 -0
  180. package/skills/ai-research/04-mechanistic-interpretability/transformer-lens/references/README.md +55 -0
  181. package/skills/ai-research/04-mechanistic-interpretability/transformer-lens/references/api.md +363 -0
  182. package/skills/ai-research/04-mechanistic-interpretability/transformer-lens/references/tutorials.md +340 -0
  183. package/skills/ai-research/05-data-processing/nemo-curator/SKILL.md +383 -0
  184. package/skills/ai-research/05-data-processing/nemo-curator/references/deduplication.md +88 -0
  185. package/skills/ai-research/05-data-processing/nemo-curator/references/filtering.md +103 -0
  186. package/skills/ai-research/05-data-processing/ray-data/SKILL.md +326 -0
  187. package/skills/ai-research/05-data-processing/ray-data/references/integration.md +83 -0
  188. package/skills/ai-research/05-data-processing/ray-data/references/transformations.md +84 -0
  189. package/skills/ai-research/06-post-training/grpo-rl-training/README.md +98 -0
  190. package/skills/ai-research/06-post-training/grpo-rl-training/SKILL.md +572 -0
  191. package/skills/ai-research/06-post-training/miles/SKILL.md +315 -0
  192. package/skills/ai-research/06-post-training/miles/references/api-reference.md +142 -0
  193. package/skills/ai-research/06-post-training/miles/references/troubleshooting.md +353 -0
  194. package/skills/ai-research/06-post-training/openrlhf/SKILL.md +249 -0
  195. package/skills/ai-research/06-post-training/openrlhf/references/algorithm-comparison.md +405 -0
  196. package/skills/ai-research/06-post-training/openrlhf/references/custom-rewards.md +531 -0
  197. package/skills/ai-research/06-post-training/openrlhf/references/hybrid-engine.md +288 -0
  198. package/skills/ai-research/06-post-training/openrlhf/references/multi-node-training.md +455 -0
  199. package/skills/ai-research/06-post-training/simpo/SKILL.md +219 -0
  200. package/skills/ai-research/06-post-training/simpo/references/datasets.md +479 -0
  201. package/skills/ai-research/06-post-training/simpo/references/hyperparameters.md +453 -0
  202. package/skills/ai-research/06-post-training/simpo/references/loss-functions.md +351 -0
  203. package/skills/ai-research/06-post-training/slime/SKILL.md +464 -0
  204. package/skills/ai-research/06-post-training/slime/references/api-reference.md +393 -0
  205. package/skills/ai-research/06-post-training/slime/references/troubleshooting.md +387 -0
  206. package/skills/ai-research/06-post-training/torchforge/SKILL.md +433 -0
  207. package/skills/ai-research/06-post-training/torchforge/references/api-reference.md +328 -0
  208. package/skills/ai-research/06-post-training/torchforge/references/troubleshooting.md +410 -0
  209. package/skills/ai-research/06-post-training/trl-fine-tuning/SKILL.md +455 -0
  210. package/skills/ai-research/06-post-training/trl-fine-tuning/references/dpo-variants.md +228 -0
  211. package/skills/ai-research/06-post-training/trl-fine-tuning/references/online-rl.md +83 -0
  212. package/skills/ai-research/06-post-training/trl-fine-tuning/references/reward-modeling.md +123 -0
  213. package/skills/ai-research/06-post-training/trl-fine-tuning/references/sft-training.md +169 -0
  214. package/skills/ai-research/06-post-training/verl/SKILL.md +391 -0
  215. package/skills/ai-research/06-post-training/verl/references/api-reference.md +302 -0
  216. package/skills/ai-research/06-post-training/verl/references/troubleshooting.md +392 -0
  217. package/skills/ai-research/07-safety-alignment/constitutional-ai/SKILL.md +290 -0
  218. package/skills/ai-research/07-safety-alignment/llamaguard/SKILL.md +337 -0
  219. package/skills/ai-research/07-safety-alignment/nemo-guardrails/SKILL.md +297 -0
  220. package/skills/ai-research/07-safety-alignment/prompt-guard/SKILL.md +312 -0
  221. package/skills/ai-research/08-distributed-training/accelerate/SKILL.md +332 -0
  222. package/skills/ai-research/08-distributed-training/accelerate/references/custom-plugins.md +454 -0
  223. package/skills/ai-research/08-distributed-training/accelerate/references/megatron-integration.md +490 -0
  224. package/skills/ai-research/08-distributed-training/accelerate/references/performance.md +526 -0
  225. package/skills/ai-research/08-distributed-training/deepspeed/SKILL.md +141 -0
  226. package/skills/ai-research/08-distributed-training/deepspeed/references/08.md +18 -0
  227. package/skills/ai-research/08-distributed-training/deepspeed/references/09.md +174 -0
  228. package/skills/ai-research/08-distributed-training/deepspeed/references/2020.md +379 -0
  229. package/skills/ai-research/08-distributed-training/deepspeed/references/2023.md +280 -0
  230. package/skills/ai-research/08-distributed-training/deepspeed/references/assets.md +180 -0
  231. package/skills/ai-research/08-distributed-training/deepspeed/references/index.md +36 -0
  232. package/skills/ai-research/08-distributed-training/deepspeed/references/mii.md +119 -0
  233. package/skills/ai-research/08-distributed-training/deepspeed/references/other.md +1192 -0
  234. package/skills/ai-research/08-distributed-training/megatron-core/SKILL.md +366 -0
  235. package/skills/ai-research/08-distributed-training/megatron-core/references/benchmarks.md +250 -0
  236. package/skills/ai-research/08-distributed-training/megatron-core/references/parallelism-guide.md +405 -0
  237. package/skills/ai-research/08-distributed-training/megatron-core/references/production-examples.md +474 -0
  238. package/skills/ai-research/08-distributed-training/megatron-core/references/training-recipes.md +548 -0
  239. package/skills/ai-research/08-distributed-training/pytorch-fsdp2/SKILL.md +231 -0
  240. package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/pytorch_dcp_async_recipe.md +14 -0
  241. package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/pytorch_dcp_overview.md +19 -0
  242. package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/pytorch_dcp_recipe.md +18 -0
  243. package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/pytorch_ddp_notes.md +10 -0
  244. package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/pytorch_device_mesh_tutorial.md +22 -0
  245. package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/pytorch_examples_fsdp2.md +15 -0
  246. package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/pytorch_fsdp1_api.md +9 -0
  247. package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/pytorch_fsdp2_tutorial.md +45 -0
  248. package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/pytorch_fully_shard_api.md +49 -0
  249. package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/pytorch_tp_tutorial.md +22 -0
  250. package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/ray_train_fsdp2_example.md +13 -0
  251. package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/torchtitan_fsdp_notes.md +14 -0
  252. package/skills/ai-research/08-distributed-training/pytorch-lightning/SKILL.md +346 -0
  253. package/skills/ai-research/08-distributed-training/pytorch-lightning/references/callbacks.md +437 -0
  254. package/skills/ai-research/08-distributed-training/pytorch-lightning/references/distributed.md +491 -0
  255. package/skills/ai-research/08-distributed-training/pytorch-lightning/references/hyperparameter-tuning.md +557 -0
  256. package/skills/ai-research/08-distributed-training/ray-train/SKILL.md +406 -0
  257. package/skills/ai-research/08-distributed-training/ray-train/references/multi-node.md +629 -0
  258. package/skills/ai-research/09-infrastructure/lambda-labs/SKILL.md +545 -0
  259. package/skills/ai-research/09-infrastructure/lambda-labs/references/advanced-usage.md +612 -0
  260. package/skills/ai-research/09-infrastructure/lambda-labs/references/troubleshooting.md +531 -0
  261. package/skills/ai-research/09-infrastructure/modal/SKILL.md +341 -0
  262. package/skills/ai-research/09-infrastructure/modal/references/advanced-usage.md +504 -0
  263. package/skills/ai-research/09-infrastructure/modal/references/troubleshooting.md +495 -0
  264. package/skills/ai-research/09-infrastructure/skypilot/SKILL.md +509 -0
  265. package/skills/ai-research/09-infrastructure/skypilot/references/advanced-usage.md +492 -0
  266. package/skills/ai-research/09-infrastructure/skypilot/references/troubleshooting.md +571 -0
  267. package/skills/ai-research/10-optimization/awq/SKILL.md +310 -0
  268. package/skills/ai-research/10-optimization/awq/references/advanced-usage.md +325 -0
  269. package/skills/ai-research/10-optimization/awq/references/troubleshooting.md +345 -0
  270. package/skills/ai-research/10-optimization/bitsandbytes/SKILL.md +411 -0
  271. package/skills/ai-research/10-optimization/bitsandbytes/references/memory-optimization.md +522 -0
  272. package/skills/ai-research/10-optimization/bitsandbytes/references/qlora-training.md +522 -0
  273. package/skills/ai-research/10-optimization/bitsandbytes/references/quantization-formats.md +448 -0
  274. package/skills/ai-research/10-optimization/flash-attention/SKILL.md +367 -0
  275. package/skills/ai-research/10-optimization/flash-attention/references/benchmarks.md +216 -0
  276. package/skills/ai-research/10-optimization/flash-attention/references/transformers-integration.md +294 -0
  277. package/skills/ai-research/10-optimization/gguf/SKILL.md +427 -0
  278. package/skills/ai-research/10-optimization/gguf/references/advanced-usage.md +505 -0
  279. package/skills/ai-research/10-optimization/gguf/references/troubleshooting.md +443 -0
  280. package/skills/ai-research/10-optimization/gptq/SKILL.md +450 -0
  281. package/skills/ai-research/10-optimization/gptq/references/calibration.md +338 -0
  282. package/skills/ai-research/10-optimization/gptq/references/integration.md +130 -0
  283. package/skills/ai-research/10-optimization/gptq/references/troubleshooting.md +96 -0
  284. package/skills/ai-research/10-optimization/hqq/SKILL.md +445 -0
  285. package/skills/ai-research/10-optimization/hqq/references/advanced-usage.md +529 -0
  286. package/skills/ai-research/10-optimization/hqq/references/troubleshooting.md +504 -0
  287. package/skills/ai-research/10-optimization/ml-training-recipes/SKILL.md +319 -0
  288. package/skills/ai-research/10-optimization/ml-training-recipes/references/architecture.md +320 -0
  289. package/skills/ai-research/10-optimization/ml-training-recipes/references/biomedical.md +498 -0
  290. package/skills/ai-research/10-optimization/ml-training-recipes/references/domain-specific.md +626 -0
  291. package/skills/ai-research/10-optimization/ml-training-recipes/references/experiment-loop.md +129 -0
  292. package/skills/ai-research/10-optimization/ml-training-recipes/references/optimizers.md +330 -0
  293. package/skills/ai-research/10-optimization/ml-training-recipes/references/scaling-and-selection.md +428 -0
  294. package/skills/ai-research/11-evaluation/bigcode-evaluation-harness/SKILL.md +405 -0
  295. package/skills/ai-research/11-evaluation/bigcode-evaluation-harness/references/benchmarks.md +394 -0
  296. package/skills/ai-research/11-evaluation/bigcode-evaluation-harness/references/custom-tasks.md +425 -0
  297. package/skills/ai-research/11-evaluation/bigcode-evaluation-harness/references/issues.md +395 -0
  298. package/skills/ai-research/11-evaluation/lm-evaluation-harness/SKILL.md +490 -0
  299. package/skills/ai-research/11-evaluation/lm-evaluation-harness/references/api-evaluation.md +491 -0
  300. package/skills/ai-research/11-evaluation/lm-evaluation-harness/references/benchmark-guide.md +489 -0
  301. package/skills/ai-research/11-evaluation/lm-evaluation-harness/references/custom-tasks.md +603 -0
  302. package/skills/ai-research/11-evaluation/lm-evaluation-harness/references/distributed-eval.md +520 -0
  303. package/skills/ai-research/11-evaluation/nemo-evaluator/SKILL.md +494 -0
  304. package/skills/ai-research/11-evaluation/nemo-evaluator/references/adapter-system.md +341 -0
  305. package/skills/ai-research/11-evaluation/nemo-evaluator/references/configuration.md +448 -0
  306. package/skills/ai-research/11-evaluation/nemo-evaluator/references/custom-benchmarks.md +316 -0
  307. package/skills/ai-research/11-evaluation/nemo-evaluator/references/execution-backends.md +362 -0
  308. package/skills/ai-research/12-inference-serving/llama-cpp/SKILL.md +258 -0
  309. package/skills/ai-research/12-inference-serving/llama-cpp/references/optimization.md +90 -0
  310. package/skills/ai-research/12-inference-serving/llama-cpp/references/quantization.md +214 -0
  311. package/skills/ai-research/12-inference-serving/llama-cpp/references/server.md +126 -0
  312. package/skills/ai-research/12-inference-serving/sglang/SKILL.md +442 -0
  313. package/skills/ai-research/12-inference-serving/sglang/references/deployment.md +491 -0
  314. package/skills/ai-research/12-inference-serving/sglang/references/radix-attention.md +414 -0
  315. package/skills/ai-research/12-inference-serving/sglang/references/structured-generation.md +542 -0
  316. package/skills/ai-research/12-inference-serving/tensorrt-llm/SKILL.md +187 -0
  317. package/skills/ai-research/12-inference-serving/tensorrt-llm/references/multi-gpu.md +299 -0
  318. package/skills/ai-research/12-inference-serving/tensorrt-llm/references/optimization.md +243 -0
  319. package/skills/ai-research/12-inference-serving/tensorrt-llm/references/serving.md +471 -0
  320. package/skills/ai-research/12-inference-serving/vllm/SKILL.md +364 -0
  321. package/skills/ai-research/12-inference-serving/vllm/references/optimization.md +227 -0
  322. package/skills/ai-research/12-inference-serving/vllm/references/quantization.md +285 -0
  323. package/skills/ai-research/12-inference-serving/vllm/references/server-deployment.md +256 -0
  324. package/skills/ai-research/12-inference-serving/vllm/references/troubleshooting.md +448 -0
  325. package/skills/ai-research/13-mlops/mlflow/SKILL.md +704 -0
  326. package/skills/ai-research/13-mlops/mlflow/references/deployment.md +745 -0
  327. package/skills/ai-research/13-mlops/mlflow/references/model-registry.md +771 -0
  328. package/skills/ai-research/13-mlops/mlflow/references/tracking.md +681 -0
  329. package/skills/ai-research/13-mlops/swanlab/SKILL.md +406 -0
  330. package/skills/ai-research/13-mlops/swanlab/references/integrations.md +305 -0
  331. package/skills/ai-research/13-mlops/swanlab/references/visualization.md +234 -0
  332. package/skills/ai-research/13-mlops/tensorboard/SKILL.md +629 -0
  333. package/skills/ai-research/13-mlops/tensorboard/references/integrations.md +639 -0
  334. package/skills/ai-research/13-mlops/tensorboard/references/profiling.md +546 -0
  335. package/skills/ai-research/13-mlops/tensorboard/references/visualization.md +621 -0
  336. package/skills/ai-research/13-mlops/weights-and-biases/SKILL.md +590 -0
  337. package/skills/ai-research/13-mlops/weights-and-biases/references/artifacts.md +585 -0
  338. package/skills/ai-research/13-mlops/weights-and-biases/references/integrations.md +701 -0
  339. package/skills/ai-research/13-mlops/weights-and-biases/references/sweeps.md +848 -0
  340. package/skills/ai-research/14-agents/a-evolve/SKILL.md +383 -0
  341. package/skills/ai-research/14-agents/a-evolve/references/README.md +831 -0
  342. package/skills/ai-research/14-agents/a-evolve/references/api.md +594 -0
  343. package/skills/ai-research/14-agents/a-evolve/references/architecture.md +417 -0
  344. package/skills/ai-research/14-agents/a-evolve/references/design-patterns.md +462 -0
  345. package/skills/ai-research/14-agents/a-evolve/references/examples.md +352 -0
  346. package/skills/ai-research/14-agents/a-evolve/references/issues.md +591 -0
  347. package/skills/ai-research/14-agents/a-evolve/references/releases.md +112 -0
  348. package/skills/ai-research/14-agents/a-evolve/references/tutorials.md +819 -0
  349. package/skills/ai-research/14-agents/autogpt/SKILL.md +403 -0
  350. package/skills/ai-research/14-agents/autogpt/references/advanced-usage.md +536 -0
  351. package/skills/ai-research/14-agents/autogpt/references/troubleshooting.md +421 -0
  352. package/skills/ai-research/14-agents/crewai/SKILL.md +498 -0
  353. package/skills/ai-research/14-agents/crewai/references/flows.md +439 -0
  354. package/skills/ai-research/14-agents/crewai/references/tools.md +430 -0
  355. package/skills/ai-research/14-agents/crewai/references/troubleshooting.md +481 -0
  356. package/skills/ai-research/14-agents/langchain/SKILL.md +480 -0
  357. package/skills/ai-research/14-agents/langchain/references/agents.md +500 -0
  358. package/skills/ai-research/14-agents/langchain/references/integration.md +563 -0
  359. package/skills/ai-research/14-agents/langchain/references/rag.md +601 -0
  360. package/skills/ai-research/14-agents/llamaindex/SKILL.md +569 -0
  361. package/skills/ai-research/14-agents/llamaindex/references/agents.md +84 -0
  362. package/skills/ai-research/14-agents/llamaindex/references/data_connectors.md +109 -0
  363. package/skills/ai-research/14-agents/llamaindex/references/query_engines.md +407 -0
  364. package/skills/ai-research/15-rag/chroma/SKILL.md +406 -0
  365. package/skills/ai-research/15-rag/chroma/references/integration.md +39 -0
  366. package/skills/ai-research/15-rag/faiss/SKILL.md +221 -0
  367. package/skills/ai-research/15-rag/faiss/references/index_types.md +281 -0
  368. package/skills/ai-research/15-rag/pinecone/SKILL.md +358 -0
  369. package/skills/ai-research/15-rag/pinecone/references/deployment.md +182 -0
  370. package/skills/ai-research/15-rag/qdrant/SKILL.md +493 -0
  371. package/skills/ai-research/15-rag/qdrant/references/advanced-usage.md +649 -0
  372. package/skills/ai-research/15-rag/qdrant/references/troubleshooting.md +632 -0
  373. package/skills/ai-research/15-rag/sentence-transformers/SKILL.md +255 -0
  374. package/skills/ai-research/15-rag/sentence-transformers/references/models.md +124 -0
  375. package/skills/ai-research/16-prompt-engineering/dspy/SKILL.md +590 -0
  376. package/skills/ai-research/16-prompt-engineering/dspy/references/examples.md +664 -0
  377. package/skills/ai-research/16-prompt-engineering/dspy/references/modules.md +476 -0
  378. package/skills/ai-research/16-prompt-engineering/dspy/references/optimizers.md +567 -0
  379. package/skills/ai-research/16-prompt-engineering/guidance/SKILL.md +572 -0
  380. package/skills/ai-research/16-prompt-engineering/guidance/references/backends.md +555 -0
  381. package/skills/ai-research/16-prompt-engineering/guidance/references/constraints.md +675 -0
  382. package/skills/ai-research/16-prompt-engineering/guidance/references/examples.md +768 -0
  383. package/skills/ai-research/16-prompt-engineering/instructor/SKILL.md +740 -0
  384. package/skills/ai-research/16-prompt-engineering/instructor/references/examples.md +108 -0
  385. package/skills/ai-research/16-prompt-engineering/instructor/references/providers.md +71 -0
  386. package/skills/ai-research/16-prompt-engineering/instructor/references/validation.md +607 -0
  387. package/skills/ai-research/16-prompt-engineering/outlines/SKILL.md +652 -0
  388. package/skills/ai-research/16-prompt-engineering/outlines/references/backends.md +616 -0
  389. package/skills/ai-research/16-prompt-engineering/outlines/references/examples.md +774 -0
  390. package/skills/ai-research/16-prompt-engineering/outlines/references/json_generation.md +653 -0
  391. package/skills/ai-research/17-observability/langsmith/SKILL.md +422 -0
  392. package/skills/ai-research/17-observability/langsmith/references/advanced-usage.md +549 -0
  393. package/skills/ai-research/17-observability/langsmith/references/troubleshooting.md +538 -0
  394. package/skills/ai-research/17-observability/phoenix/SKILL.md +475 -0
  395. package/skills/ai-research/17-observability/phoenix/references/advanced-usage.md +620 -0
  396. package/skills/ai-research/17-observability/phoenix/references/troubleshooting.md +539 -0
  397. package/skills/ai-research/18-multimodal/audiocraft/SKILL.md +564 -0
  398. package/skills/ai-research/18-multimodal/audiocraft/references/advanced-usage.md +667 -0
  399. package/skills/ai-research/18-multimodal/audiocraft/references/troubleshooting.md +505 -0
  400. package/skills/ai-research/18-multimodal/blip-2/SKILL.md +564 -0
  401. package/skills/ai-research/18-multimodal/blip-2/references/advanced-usage.md +681 -0
  402. package/skills/ai-research/18-multimodal/blip-2/references/troubleshooting.md +527 -0
  403. package/skills/ai-research/18-multimodal/clip/SKILL.md +253 -0
  404. package/skills/ai-research/18-multimodal/clip/references/applications.md +208 -0
  405. package/skills/ai-research/18-multimodal/cosmos-policy/SKILL.md +402 -0
  406. package/skills/ai-research/18-multimodal/cosmos-policy/references/libero-commands.md +175 -0
  407. package/skills/ai-research/18-multimodal/cosmos-policy/references/robocasa-commands.md +147 -0
  408. package/skills/ai-research/18-multimodal/llava/SKILL.md +304 -0
  409. package/skills/ai-research/18-multimodal/llava/references/training.md +198 -0
  410. package/skills/ai-research/18-multimodal/openpi/SKILL.md +480 -0
  411. package/skills/ai-research/18-multimodal/openpi/references/checkpoints-and-env-map.md +86 -0
  412. package/skills/ai-research/18-multimodal/openpi/references/config-recipes.md +50 -0
  413. package/skills/ai-research/18-multimodal/openpi/references/pytorch-gotchas.md +49 -0
  414. package/skills/ai-research/18-multimodal/openpi/references/remote-client-pattern.md +48 -0
  415. package/skills/ai-research/18-multimodal/openpi/references/training-debugging.md +46 -0
  416. package/skills/ai-research/18-multimodal/openvla-oft/SKILL.md +441 -0
  417. package/skills/ai-research/18-multimodal/openvla-oft/references/aloha-workflow.md +141 -0
  418. package/skills/ai-research/18-multimodal/openvla-oft/references/config-troubleshooting.md +97 -0
  419. package/skills/ai-research/18-multimodal/openvla-oft/references/libero-workflow.md +115 -0
  420. package/skills/ai-research/18-multimodal/openvla-oft/references/paper-and-checkpoints.md +84 -0
  421. package/skills/ai-research/18-multimodal/segment-anything/SKILL.md +500 -0
  422. package/skills/ai-research/18-multimodal/segment-anything/references/advanced-usage.md +590 -0
  423. package/skills/ai-research/18-multimodal/segment-anything/references/troubleshooting.md +485 -0
  424. package/skills/ai-research/18-multimodal/stable-diffusion/SKILL.md +519 -0
  425. package/skills/ai-research/18-multimodal/stable-diffusion/references/advanced-usage.md +717 -0
  426. package/skills/ai-research/18-multimodal/stable-diffusion/references/troubleshooting.md +556 -0
  427. package/skills/ai-research/18-multimodal/whisper/SKILL.md +317 -0
  428. package/skills/ai-research/18-multimodal/whisper/references/languages.md +190 -0
  429. package/skills/ai-research/19-emerging-techniques/knowledge-distillation/SKILL.md +458 -0
  430. package/skills/ai-research/19-emerging-techniques/knowledge-distillation/references/minillm.md +335 -0
  431. package/skills/ai-research/19-emerging-techniques/long-context/SKILL.md +536 -0
  432. package/skills/ai-research/19-emerging-techniques/long-context/references/extension_methods.md +469 -0
  433. package/skills/ai-research/19-emerging-techniques/long-context/references/fine_tuning.md +612 -0
  434. package/skills/ai-research/19-emerging-techniques/long-context/references/rope.md +403 -0
  435. package/skills/ai-research/19-emerging-techniques/model-merging/SKILL.md +497 -0
  436. package/skills/ai-research/19-emerging-techniques/model-merging/references/coefficient-tuning.md +415 -0
  437. package/skills/ai-research/19-emerging-techniques/model-merging/references/evaluation.md +463 -0
  438. package/skills/ai-research/19-emerging-techniques/model-merging/references/examples.md +429 -0
  439. package/skills/ai-research/19-emerging-techniques/model-merging/references/methods.md +353 -0
  440. package/skills/ai-research/19-emerging-techniques/model-pruning/SKILL.md +495 -0
  441. package/skills/ai-research/19-emerging-techniques/model-pruning/references/wanda.md +348 -0
  442. package/skills/ai-research/19-emerging-techniques/moe-training/SKILL.md +526 -0
  443. package/skills/ai-research/19-emerging-techniques/moe-training/references/architectures.md +433 -0
  444. package/skills/ai-research/19-emerging-techniques/moe-training/references/inference.md +349 -0
  445. package/skills/ai-research/19-emerging-techniques/moe-training/references/training.md +426 -0
  446. package/skills/ai-research/19-emerging-techniques/speculative-decoding/SKILL.md +467 -0
  447. package/skills/ai-research/19-emerging-techniques/speculative-decoding/references/lookahead.md +310 -0
  448. package/skills/ai-research/19-emerging-techniques/speculative-decoding/references/medusa.md +351 -0
  449. package/skills/ai-research/20-ml-paper-writing/academic-plotting/SKILL.md +479 -0
  450. package/skills/ai-research/20-ml-paper-writing/academic-plotting/references/data-visualization.md +509 -0
  451. package/skills/ai-research/20-ml-paper-writing/academic-plotting/references/diagram-generation.md +395 -0
  452. package/skills/ai-research/20-ml-paper-writing/academic-plotting/references/style-guide.md +305 -0
  453. package/skills/ai-research/20-ml-paper-writing/ml-paper-writing/SKILL.md +982 -0
  454. package/skills/ai-research/20-ml-paper-writing/ml-paper-writing/references/checklists.md +348 -0
  455. package/skills/ai-research/20-ml-paper-writing/ml-paper-writing/references/citation-workflow.md +563 -0
  456. package/skills/ai-research/20-ml-paper-writing/ml-paper-writing/references/reviewer-guidelines.md +349 -0
  457. package/skills/ai-research/20-ml-paper-writing/ml-paper-writing/references/sources.md +165 -0
  458. package/skills/ai-research/20-ml-paper-writing/ml-paper-writing/references/writing-guide.md +477 -0
  459. package/skills/ai-research/20-ml-paper-writing/presenting-conference-talks/SKILL.md +298 -0
  460. package/skills/ai-research/20-ml-paper-writing/presenting-conference-talks/references/slide-templates.md +505 -0
  461. package/skills/ai-research/20-ml-paper-writing/systems-paper-writing/SKILL.md +270 -0
  462. package/skills/ai-research/20-ml-paper-writing/systems-paper-writing/references/checklist.md +279 -0
  463. package/skills/ai-research/20-ml-paper-writing/systems-paper-writing/references/reviewer-guidelines.md +116 -0
  464. package/skills/ai-research/20-ml-paper-writing/systems-paper-writing/references/section-blueprints.md +400 -0
  465. package/skills/ai-research/20-ml-paper-writing/systems-paper-writing/references/systems-conferences.md +261 -0
  466. package/skills/ai-research/20-ml-paper-writing/systems-paper-writing/references/writing-patterns.md +231 -0
  467. package/skills/ai-research/21-research-ideation/brainstorming-research-ideas/SKILL.md +384 -0
  468. package/skills/ai-research/21-research-ideation/creative-thinking-for-research/SKILL.md +366 -0
  469. package/skills/ai-research/22-agent-native-research-artifact/compiler/SKILL.md +245 -0
  470. package/skills/ai-research/22-agent-native-research-artifact/compiler/references/ara-schema.md +439 -0
  471. package/skills/ai-research/22-agent-native-research-artifact/compiler/references/exploration-tree-spec.md +125 -0
  472. package/skills/ai-research/22-agent-native-research-artifact/compiler/references/validation-checklist.md +149 -0
  473. package/skills/ai-research/22-agent-native-research-artifact/research-manager/SKILL.md +324 -0
  474. package/skills/ai-research/22-agent-native-research-artifact/research-manager/references/event-taxonomy.md +124 -0
  475. package/skills/ai-research/22-agent-native-research-artifact/research-manager/references/provenance-tags.md +190 -0
  476. package/skills/ai-research/22-agent-native-research-artifact/research-manager/references/session-protocol.md +162 -0
  477. package/skills/ai-research/22-agent-native-research-artifact/rigor-reviewer/SKILL.md +322 -0
  478. package/skills/ai-research/22-agent-native-research-artifact/rigor-reviewer/references/review-dimensions.md +182 -0
  479. package/skills/ai-research/SKILL.md +101 -0
  480. package/skills/ai-research/SOURCE +38 -0
  481. package/skills/ai-research/index/1-frame.md +18 -0
  482. package/skills/ai-research/index/2-data.md +21 -0
  483. package/skills/ai-research/index/3-train.md +48 -0
  484. package/skills/ai-research/index/4-measure.md +25 -0
  485. package/skills/ai-research/index/5-run.md +23 -0
  486. package/skills/ai-research/index/6-write.md +35 -0
  487. package/skills/ai-research/library.json +3456 -0
  488. package/skills/analyze-app/EVALS.md +82 -0
  489. package/skills/analyze-app/SKILL.md +188 -0
  490. package/skills/design-contract/EVALS.md +80 -0
  491. package/skills/design-contract/SKILL.md +171 -0
  492. package/skills/design-library/EVALS.md +85 -0
  493. package/skills/design-library/INDEX.md +59 -0
  494. package/skills/design-library/SKILL.md +58 -0
  495. package/skills/design-library/SOURCE +131 -0
  496. package/skills/design-library/adaptive-interfaces/skills/colour-independence/SKILL.md +90 -0
  497. package/skills/design-library/adaptive-interfaces/skills/flexible-typography/SKILL.md +83 -0
  498. package/skills/design-library/adaptive-interfaces/skills/information-density/SKILL.md +87 -0
  499. package/skills/design-library/adaptive-interfaces/skills/preference-audit/SKILL.md +70 -0
  500. package/skills/design-library/adaptive-interfaces/skills/responsive-accessibility/SKILL.md +86 -0
  501. package/skills/design-library/adaptive-interfaces/skills/responsive-review/SKILL.md +76 -0
  502. package/skills/design-library/adaptive-interfaces/skills/simplified-views/SKILL.md +97 -0
  503. package/skills/design-library/adaptive-interfaces/skills/specify/SKILL.md +63 -0
  504. package/skills/design-library/adaptive-interfaces/skills/user-preference-respect/SKILL.md +100 -0
  505. package/skills/design-library/cognitive-accessibility/skills/adaptive-personalisation/SKILL.md +61 -0
  506. package/skills/design-library/cognitive-accessibility/skills/assess-load/SKILL.md +48 -0
  507. package/skills/design-library/cognitive-accessibility/skills/cognitive-load-assessment/SKILL.md +60 -0
  508. package/skills/design-library/cognitive-accessibility/skills/contextual-help-design/SKILL.md +61 -0
  509. package/skills/design-library/cognitive-accessibility/skills/error-prevention-recovery/SKILL.md +71 -0
  510. package/skills/design-library/cognitive-accessibility/skills/focus-attention-design/SKILL.md +67 -0
  511. package/skills/design-library/cognitive-accessibility/skills/memory-load-reduction/SKILL.md +60 -0
  512. package/skills/design-library/cognitive-accessibility/skills/plain-language-design/SKILL.md +78 -0
  513. package/skills/design-library/cognitive-accessibility/skills/review/SKILL.md +56 -0
  514. package/skills/design-library/cognitive-accessibility/skills/simplify/SKILL.md +39 -0
  515. package/skills/design-library/cognitive-accessibility/skills/wayfinding-navigation/SKILL.md +64 -0
  516. package/skills/design-library/design-research/skills/behavioural-analytics/SKILL.md +33 -0
  517. package/skills/design-library/design-research/skills/qual-quant-triangulation/SKILL.md +33 -0
  518. package/skills/design-library/inclusive-interaction/skills/audit/SKILL.md +50 -0
  519. package/skills/design-library/inclusive-interaction/skills/design-flow/SKILL.md +58 -0
  520. package/skills/design-library/inclusive-interaction/skills/feedback-and-status/SKILL.md +76 -0
  521. package/skills/design-library/inclusive-interaction/skills/gesture-alternatives/SKILL.md +70 -0
  522. package/skills/design-library/inclusive-interaction/skills/keyboard-navigation/SKILL.md +99 -0
  523. package/skills/design-library/inclusive-interaction/skills/keyboard-review/SKILL.md +54 -0
  524. package/skills/design-library/inclusive-interaction/skills/motion-sensitivity/SKILL.md +79 -0
  525. package/skills/design-library/inclusive-interaction/skills/multi-modal-input/SKILL.md +70 -0
  526. package/skills/design-library/inclusive-interaction/skills/touch-target-design/SKILL.md +71 -0
  527. package/skills/design-library/inclusive-interaction/skills/voice-interaction/SKILL.md +68 -0
  528. package/skills/design-library/visual-critique/skills/critique-affordance/SKILL.md +45 -0
  529. package/skills/design-library/visual-critique/skills/critique-brand-consistency/SKILL.md +42 -0
  530. package/skills/design-library/visual-critique/skills/critique-color/SKILL.md +44 -0
  531. package/skills/design-library/visual-critique/skills/critique-composition/SKILL.md +46 -0
  532. package/skills/design-library/visual-critique/skills/critique-information-density/SKILL.md +45 -0
  533. package/skills/design-library/visual-critique/skills/critique-typography/SKILL.md +45 -0
  534. package/skills/design-library/visual-critique/skills/critique-visual-hierarchy/SKILL.md +40 -0
  535. package/skills/feature-audit/EVALS.md +83 -0
  536. package/skills/feature-audit/SKILL.md +326 -0
  537. package/skills/harness/EVALS.md +81 -0
  538. package/skills/harness/SKILL.md +88 -0
  539. package/skills/i-have-adhd/EVALS.md +80 -0
  540. package/skills/i-have-adhd/SKILL.md +183 -0
  541. package/skills/no-ai-slop/EVALS.md +89 -0
  542. package/skills/no-ai-slop/SKILL.md +209 -0
  543. package/skills/no-ai-slop/eval.md +52 -0
  544. package/skills/plan-add/EVALS.md +79 -0
  545. package/skills/plan-add/SKILL.md +179 -0
  546. package/skills/plan-add/render_table.py +72 -0
  547. package/skills/plan-status/EVALS.md +78 -0
  548. package/skills/plan-status/SKILL.md +52 -0
  549. package/skills/plan-sync/EVALS.md +80 -0
  550. package/skills/plan-sync/SKILL.md +69 -0
  551. package/skills/pm-frameworks/SKILL.md +33 -0
  552. package/skills/pm-frameworks/SOURCE +39 -0
  553. package/skills/pm-frameworks/intended-vs-implemented/SKILL.md +42 -0
  554. package/skills/pm-frameworks/opportunity-solution-tree/SKILL.md +64 -0
  555. package/skills/ponytail/EVALS.md +80 -0
  556. package/skills/ponytail/SKILL.md +124 -0
  557. package/skills/product-analysis/EVALS.md +103 -0
  558. package/skills/product-analysis/SKILL.md +361 -0
  559. package/skills/research/EVALS.md +104 -0
  560. package/skills/research/SKILL.md +570 -0
  561. package/skills/rl-env/SKILL.md +53 -0
  562. package/skills/rl-env/SOURCE +41 -0
  563. package/skills/rl-env/generate-nemo-gym-env/SKILL.md +169 -0
  564. package/skills/rl-env/generate-nemo-gym-env/references/architecture.md +114 -0
  565. package/skills/rl-env/generate-openenv-env/SKILL.md +183 -0
  566. package/skills/rl-env/generate-openenv-env/references/architecture.md +82 -0
  567. package/skills/rl-env/generate-ors-env/SKILL.md +209 -0
  568. package/skills/rl-env/generate-ors-env/references/architecture.md +113 -0
  569. package/skills/rl-env/generate-verifiers-env/SKILL.md +188 -0
  570. package/skills/rl-env/generate-verifiers-env/references/architecture.md +119 -0
  571. package/skills/rl-env/rl-env-from-description/SKILL.md +124 -0
  572. package/skills/rl-env/rl-env-from-description/references/interview.md +75 -0
  573. package/skills/rl-env/rl-env-from-description/references/nemo_gym.md +41 -0
  574. package/skills/rl-env/rl-env-from-description/references/openenv.md +35 -0
  575. package/skills/rl-env/rl-env-from-description/references/ors.md +50 -0
  576. package/skills/rl-env/rl-env-from-description/references/verifiers.md +39 -0
  577. package/skills/tezgah-contract/EVALS.md +78 -0
  578. package/skills/tezgah-contract/SKILL.md +792 -0
  579. package/statusline.py +129 -0
  580. package/workflows/graph-impact.js +153 -0
  581. package/workflows/graph-map.js +158 -0
  582. package/workflows/graph-review.js +170 -0
@@ -0,0 +1,1109 @@
1
+ #!/usr/bin/env python3
2
+ """The replay corpus: the real ledgers replayed through the current gate and Stop
3
+ code, a blind label sheet drawn from them, and the report that reads the labels
4
+ (plan 055, roadmap R12; corpus spec REPORT.md §4.4.3).
5
+
6
+ tezgah-gate replay [--cutoff WHEN] [--since WHEN] [--json]
7
+ tezgah-gate replay --report [--run DIR] [--labels FILE ...] [--json]
8
+ tezgah-gate replay --sheet [--run DIR] [--seed N] [--rules FILE]
9
+ tezgah-gate replay --label-model --prompt FILE [--provider typesafe|deepseek]
10
+ [--model ID] [--run DIR]
11
+
12
+ **Corpus.** Every ledger under the cache's `evidence/` is read read-only; a
13
+ ledger is dropped whole when `fixture_ledger` says it is a fixture tree, or when
14
+ the session id behind its file stem is not a host UUID (probe, smoke and test
15
+ ids). Rows drop after the cutoff and when they are `route` rows (written by the
16
+ test suite). The items are the `deny`, `began` and `claim` rows; an item drops
17
+ when its deny names a rule `tezgah_gate.DENY_RULES` no longer holds (consent,
18
+ sink), when its `detail` is at `DETAIL_MAX`, or when it holds `[redacted:`.
19
+
20
+ **Join.** omp and Claude transcripts, subagent files included, are walked by
21
+ `bin/tezgah-taste` (`calls=True`). A call joins a row when
22
+ `call_id(tool, args)` - omp's `i` key dropped - equals the row's `id` inside the
23
+ ledger `_slug(session id)` names. A shell `began` row with no transcript call
24
+ joins from its own detail when that detail is under the cap and hashes to the
25
+ row's id. A `claim` row joins the assistant reply nearest its timestamp within
26
+ `REPLY_WINDOW` seconds. Nothing else is tried: an unjoined row stays unjoined.
27
+
28
+ **Replay.** A child process with a sandbox HOME under the run directory: every
29
+ kept row of every kept ledger is appended to the sandbox ledger in timestamp
30
+ order (each ledger in its own order, the file's mtime set to the row's ts), and
31
+ each item is replayed just before its own row lands, with `time.time` frozen at
32
+ the row's ts. Gate items go through the unmodified
33
+ `tezgah_gate.decision(..., record=False)`; the rule a replayed deny names is the
34
+ rule argument `decision` hands `_deny`, read by an observer and labelled through
35
+ `_deny_rule`, the one rule-label derivation. Stop items go through
36
+ `_stop_block(text, sid, rows=<turn prefix>)` with `events` swapped to the session
37
+ prefix. The rows the gate writes beside a refusal (drift and nudge marks) and the
38
+ Stop path's `shape` row are moved after their item, because live they were the
39
+ call's own output.
40
+
41
+ **Output.** Everything is written under `~/.cache/tezgah/replay/<run>/`, owner
42
+ only, and never leaves the machine: `corpus.jsonl` (the items, with their
43
+ inputs), `results.jsonl`, `summary.json`, and the sheet files. The sandbox HOME
44
+ and the row stream are deleted when the child returns.
45
+ """
46
+ import argparse
47
+ import datetime
48
+ import importlib.machinery
49
+ import importlib.util
50
+ import json
51
+ import math
52
+ import os
53
+ import random
54
+ import re
55
+ import shutil
56
+ import subprocess
57
+ import sys
58
+ import time
59
+ from collections import Counter, defaultdict
60
+ from heapq import merge
61
+
62
+ HERE = os.path.dirname(os.path.abspath(__file__))
63
+ if HERE not in sys.path:
64
+ sys.path.insert(0, HERE)
65
+ import tezgah_integrity as ti # noqa: E402
66
+ import tezgah_paths as tp # noqa: E402
67
+
68
+ # The one rule-label derivation; nothing in this module maps text to a rule.
69
+ rule_of = ti._deny_rule
70
+
71
+ # `34f63e3`'s commit time (2026-10-04 21:31:35 +03): the rows since it are the
72
+ # ones current rules still produce, and the H1 prediction is tested on them.
73
+ SINCE_RELEASE = 1791138695
74
+ REPLY_WINDOW = 2
75
+ ITEM_KINDS = ("deny", "began", "claim")
76
+ TEST_ROW_KINDS = ("route",)
77
+ # Rows a live call wrote just before its own item row: they are moved after it.
78
+ SIDE_KINDS = {"deny": ("drift", "nudge"), "began": ("drift", "nudge"),
79
+ "claim": ("shape", "stop_spec")}
80
+ # The rule the family fold (plan 055 part 6, D32a) is about.
81
+ RACE_RULE = "race"
82
+ RACE_BAR_UNMEASURABLE = ("not measurable on this corpus: no race item is on the sheet "
83
+ "(every joined live race deny predates the `target` field)")
84
+ # Which rules read only the call and the ledger (replayable as they ran) and
85
+ # which read the disk as it is today. Keyed by `_deny_rule` labels. A rule in
86
+ # `disk_on_write` is disk-state on a write tool; one in `disk_on_file` is
87
+ # disk-state when the command reads a message file.
88
+ STRATA = {"ledger": ("loop", "retry", "order", "drift", "race", "piped",
89
+ "attribution", "secret", "shortcut"),
90
+ "disk": ("task", "plan", "workspace", "explorer"),
91
+ "disk_on_write": ("shortcut",),
92
+ "disk_on_file": ("lang",)}
93
+ MESSAGE_FILE = re.compile(r"(?:^|\s)(?:-F|--file)(?:\s|=|$)")
94
+ UUID = re.compile(r"^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$")
95
+ # The H2 sampling frame (protocol committed before any label).
96
+ QUOTA = {"deny:drift": 96, "deny:piped": 96, "deny:race": 96, "deny:other": 32,
97
+ "allow": 30, "stop:allow": 25, "stop:block": 25}
98
+ SEED = 55
99
+ CUT_PROMPT, CUT_INPUT, CUT_REPLY = 1500, 2000, 3000
100
+ STOP_CONTEXT = ("run", "edit", "verify", "verify_ok", "verify_fail",
101
+ "interrupted", "external")
102
+
103
+
104
+ def replay_root():
105
+ """Where every replay run lives: under the cache, never under `.tezgah/`."""
106
+ return os.path.join(tp.CACHE, "replay")
107
+
108
+
109
+ def _taste():
110
+ """bin/tezgah-taste as a module (it has no `.py` suffix): its walkers are the
111
+ transcript readers, so the corpus and `mine` read one format one way."""
112
+ path = os.path.join(os.path.dirname(HERE), "bin", "tezgah-taste")
113
+ loader = importlib.machinery.SourceFileLoader("tezgah_taste", path)
114
+ spec = importlib.util.spec_from_loader("tezgah_taste", loader)
115
+ module = importlib.util.module_from_spec(spec)
116
+ loader.exec_module(module)
117
+ return module
118
+
119
+
120
+ def _when(text):
121
+ """An epoch from an int or an ISO time; None for None."""
122
+ if text is None:
123
+ return None
124
+ try:
125
+ return int(text)
126
+ except ValueError:
127
+ return int(datetime.datetime.fromisoformat(text).timestamp())
128
+
129
+
130
+ def _stamp(epoch):
131
+ return datetime.datetime.fromtimestamp(epoch).astimezone().strftime(
132
+ "%Y-%m-%d %H:%M:%S %z")
133
+
134
+
135
+ def _owner_write(path, text):
136
+ fd = os.open(path, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o600)
137
+ os.fchmod(fd, 0o600) # the create mode does not reach a file that already exists
138
+ with os.fdopen(fd, "w", encoding="utf-8") as fh:
139
+ fh.write(text)
140
+
141
+
142
+ def _write_jsonl(path, rows):
143
+ _owner_write(path, "".join(json.dumps(r, ensure_ascii=False) + "\n" for r in rows))
144
+
145
+
146
+ def _read_jsonl(path):
147
+ with open(path, encoding="utf-8") as fh:
148
+ return [json.loads(line) for line in fh if line.strip()]
149
+
150
+
151
+ def stratum(kind, rule, tool, inp):
152
+ """The stratum an item's agreement is reported under."""
153
+ if kind == "claim":
154
+ return "stop"
155
+ if rule is None:
156
+ return "allow"
157
+ t = str(tool or "").lower()
158
+ if rule in STRATA["disk_on_write"] and t in ti.WRITE_TOOLS:
159
+ return "disk"
160
+ if rule in STRATA["disk_on_file"]:
161
+ command = str((inp or {}).get("command") or "")
162
+ return "disk" if MESSAGE_FILE.search(command) else "ledger"
163
+ for name in ("ledger", "disk"):
164
+ if rule in STRATA[name]:
165
+ return name
166
+ return "unclassified"
167
+
168
+
169
+ def _summary_of(name, args):
170
+ """One line naming a call, for the sheet's context: no verdict in it."""
171
+ args = args if isinstance(args, dict) else {}
172
+ text = args.get("command") or args.get("cmd") or args.get("file_path") \
173
+ or args.get("path") or json.dumps(args, ensure_ascii=False)
174
+ return "%s: %s" % (name, str(text).splitlines()[0][:160] if str(text) else "")
175
+
176
+
177
+ def _legacy(sid):
178
+ """The ledger stem a session id had before `_slug` grew its hash suffix:
179
+ the readable prefix alone. Older ledgers on disk still carry it."""
180
+ return re.sub(r"[^A-Za-z0-9]+", "-", str(sid)).strip("-")[:40]
181
+
182
+
183
+ def _test_polluted(stem):
184
+ """True when the session id behind a ledger stem is not a host UUID. The
185
+ stem is the raw id's readable prefix plus `-<12 hex>`, or the prefix alone
186
+ for a ledger older than the hash suffix."""
187
+ return not (UUID.match(stem) or UUID.match(stem.rsplit("-", 1)[0]))
188
+
189
+
190
+ # ------------------------------------------------------------------ corpus --
191
+
192
+ def _ledgers():
193
+ """(stem, path, rows, reason) per ledger read; `reason` names why a whole
194
+ ledger is dropped (fixture, test-polluted), None for a kept one."""
195
+ out = []
196
+ for path in sorted(ti.ledgers()):
197
+ stem = os.path.basename(path)[:-len(".jsonl")]
198
+ rows = ti._foreign_rows(path)
199
+ reason = ("fixture" if ti.fixture_ledger(rows)
200
+ else "test-polluted" if _test_polluted(stem) else None)
201
+ out.append((stem, path, rows, reason))
202
+ return out
203
+
204
+
205
+ def _transcripts(wanted):
206
+ """Per ledger stem: the transcript calls whose id is wanted, the assistant
207
+ replies, the session cwd and host, and the parent links (`parent_of`, a
208
+ stem or None for a known top-level session)."""
209
+ taste = _taste()
210
+ found = defaultdict(lambda: {"calls": defaultdict(list), "replies": [],
211
+ "cwd": None, "host": None, "sid": None})
212
+ parent_of, sid_of_file = {}, {}
213
+ for host in ("omp", "claude"):
214
+ walk = taste.HOSTS[host][2]
215
+ for path, cwd in taste.sessions(host, "", nested=True):
216
+ sid, parent = taste.session_id(host, path)
217
+ if not sid:
218
+ continue
219
+ keys = (ti._slug(sid), _legacy(sid))
220
+ sid_of_file[path] = sid
221
+ # omp names a subagent's parent; a Claude file is its own session's
222
+ parent_of.setdefault(keys[0], parent if host == "omp" else None)
223
+ stem = next((k for k in keys if k in wanted), None)
224
+ if stem is None:
225
+ continue
226
+ entry = found[stem]
227
+ entry.update(cwd=entry["cwd"] or cwd, host=host, sid=sid)
228
+ ids = wanted[stem]
229
+ prompt, prior = "", []
230
+ for event in walk(path, calls=True):
231
+ if event[0] == "user":
232
+ if not taste.harness_prompt(event[1]):
233
+ prompt, prior = event[1], []
234
+ elif event[0] == "reply":
235
+ entry["replies"].append((event[2], event[1], cwd))
236
+ elif event[0] == "call":
237
+ name, args, ts = event[1], event[2], event[3]
238
+ digest = ti.call_id(name, args)
239
+ if digest in ids:
240
+ # the cwd of the file the call came from: one session's
241
+ # files (a subagent, a scratch workspace) differ in it
242
+ entry["calls"][digest].append(
243
+ {"tool": name, "input": args, "ts": ts, "cwd": cwd,
244
+ "prompt": prompt[:CUT_PROMPT], "prior": prior[-8:]})
245
+ prior.append(_summary_of(name, args))
246
+ # omp names a subagent's parent by its file; the parent's stem is its id's slug
247
+ for stem, parent in list(parent_of.items()):
248
+ if parent is None:
249
+ continue
250
+ psid = sid_of_file.get(parent) or (
251
+ os.path.exists(str(parent)) and taste.session_id("omp", parent)[0]) or None
252
+ parent_of[stem] = ti._slug(psid) if psid else "unknown"
253
+ return found, parent_of
254
+
255
+
256
+ def _nearest(candidates, ts):
257
+ best = None
258
+ for cand in candidates:
259
+ if cand["ts"] is None:
260
+ continue
261
+ if best is None or abs(cand["ts"] - ts) < abs(best["ts"] - ts):
262
+ best = cand
263
+ return best or (candidates[0] if candidates else None)
264
+
265
+
266
+ def build_corpus(cutoff, since=None):
267
+ """The corpus: items, the ordered row stream, ledger file names and the
268
+ counts the summary prints."""
269
+ import tezgah_gate as tg
270
+ ledgers = _ledgers()
271
+ counts = {"ledgers": Counter(), "excluded": Counter(), "candidates": 0}
272
+ kept, wanted, claim_stems = [], defaultdict(set), set()
273
+ spawned_parent = {}
274
+ for stem, path, rows, reason in ledgers:
275
+ counts["ledgers"]["read"] += 1
276
+ if reason:
277
+ counts["ledgers"][reason] += 1
278
+ continue
279
+ counts["ledgers"]["kept"] += 1
280
+ live = []
281
+ for row in rows:
282
+ kind = row.get("kind")
283
+ ts = row.get("ts") if isinstance(row.get("ts"), (int, float)) else None
284
+ if kind in ITEM_KINDS:
285
+ counts["candidates"] += 1
286
+ if kind in TEST_ROW_KINDS:
287
+ counts["excluded"]["test-row"] += 1
288
+ continue
289
+ if ts is None or ts > cutoff:
290
+ if kind in ITEM_KINDS:
291
+ counts["excluded"]["after-cutoff"] += 1
292
+ continue
293
+ if kind == "spawned" and row.get("parent"):
294
+ spawned_parent[stem] = ti._slug(row["parent"])
295
+ live.append(row)
296
+ if kind in ("deny", "began") and row.get("id"):
297
+ wanted[stem].add(row["id"])
298
+ if kind == "claim":
299
+ claim_stems.add(stem)
300
+ kept.append((stem, path, live))
301
+ for stem in claim_stems:
302
+ wanted.setdefault(stem, set())
303
+ found, parent_of = _transcripts(wanted)
304
+ # The sandbox names a ledger the way today's gate does (`_slug(sid)`), so the
305
+ # session's own file is the one `decision` opens; that name is the ledger's
306
+ # key from here on. A ledger with no transcript keeps its stem as its id.
307
+ canon_of = {}
308
+ for stem, _path, _rows in kept:
309
+ entry = found.get(stem)
310
+ canon_of[stem] = ti._slug(entry["sid"] if entry else stem)
311
+ for stem, parent in spawned_parent.items():
312
+ parent_of[canon_of[stem]] = parent
313
+ stems = [s for s, _p, _r, _reason in ledgers]
314
+
315
+ items, streams = [], []
316
+ for stem, path, rows in kept:
317
+ entry = found.get(stem)
318
+ sid = entry["sid"] if entry else stem
319
+ fname = canon_of[stem] + ".jsonl"
320
+ order = list(range(len(rows)))
321
+ turn_start = 0
322
+ # The gate writes a call's `began` before its rules (plan 051), so a
323
+ # call it refused has a `began` whose next row of the same id is the
324
+ # refusal: the call's live outcome is that `deny` (or nudge), not an allow.
325
+ refused, upcoming = set(), {}
326
+ for idx in range(len(rows) - 1, -1, -1):
327
+ digest, kind = rows[idx].get("id"), rows[idx].get("kind")
328
+ if kind == "began" and upcoming.get(digest) in ("deny", "nudge"):
329
+ refused.add(idx)
330
+ if digest:
331
+ upcoming[digest] = kind
332
+ for idx, row in enumerate(rows):
333
+ kind, detail = row.get("kind"), str(row.get("detail") or "")
334
+ if kind == ti.TURN_KIND:
335
+ turn_start = idx + 1
336
+ if kind not in ITEM_KINDS:
337
+ continue
338
+ reason = None
339
+ if idx in refused:
340
+ reason = "refused-began"
341
+ elif kind == "deny" and rule_of(detail) not in tg.DENY_RULES:
342
+ reason = "retired-rule"
343
+ elif len(detail) >= ti.DETAIL_MAX:
344
+ reason = "capped"
345
+ elif "[redacted:" in detail:
346
+ reason = "redacted"
347
+ if reason:
348
+ counts["excluded"][reason] += 1
349
+ continue
350
+ if since is not None and row["ts"] < since:
351
+ counts["excluded"]["before-since"] += 1
352
+ continue
353
+ item = {"i": len(items), "stem": canon_of[stem], "sid": sid, "kind": kind,
354
+ "ts": row["ts"], "id": row.get("id"), "host": entry and entry["host"],
355
+ "cwd": (entry and entry["cwd"]) or row.get("workspace"),
356
+ "live": ("block" if detail.startswith("blocked:") else "allow")
357
+ if kind == "claim" else ("deny" if kind == "deny" else "allow"),
358
+ "live_rule": rule_of(detail) if kind == "deny"
359
+ else detail.split(":", 1)[1].strip() if kind == "claim"
360
+ and detail.startswith("blocked:") else None,
361
+ "tool": row.get("tool"), "join": None}
362
+ if kind == "claim":
363
+ replies = [{"ts": ts, "text": text, "cwd": where} for ts, text, where in
364
+ (entry["replies"] if entry else []) if ts is not None
365
+ and abs(ts - row["ts"]) <= REPLY_WINDOW]
366
+ best = _nearest(replies, row["ts"])
367
+ if best:
368
+ item.update(join="position", text=best["text"], cwd=best["cwd"])
369
+ prefix = rows[turn_start:idx]
370
+ item["turn"] = [[r.get("kind"), str(r.get("detail") or "")[:300]]
371
+ for r in prefix if r.get("kind") in STOP_CONTEXT][-40:]
372
+ else:
373
+ call = _nearest(entry["calls"].get(row.get("id"), []) if entry else [],
374
+ row["ts"])
375
+ if call:
376
+ item.update(join="transcript", tool=call["tool"], input=call["input"],
377
+ cwd=call["cwd"], prompt=call["prompt"], prior=call["prior"])
378
+ elif (kind == "began" and str(row.get("tool") or "").lower() in ti.BASH_TOOLS
379
+ and ti.call_id("bash", {"command": detail}) == row.get("id")):
380
+ item.update(join="ledger", input={"command": detail},
381
+ prompt="", prior=[])
382
+ if item["live_rule"] == RACE_RULE:
383
+ item["foreign"] = _foreign_sessions(detail, stems, canon_of)
384
+ item["stratum"] = stratum(kind, item["live_rule"], item["tool"],
385
+ item.get("input"))
386
+ items.append(item)
387
+ row_item = item["i"] if item["join"] else None
388
+ # the call's own side rows (drift/nudge marks, the Stop `shape` and
389
+ # `stop_spec` rows) sit just before it at the same ts: move them after the item
390
+ j = order.index(idx)
391
+ k = j
392
+ while (k > 0 and rows[order[k - 1]].get("ts") == row["ts"]
393
+ and rows[order[k - 1]].get("kind") in SIDE_KINDS[kind]):
394
+ k -= 1
395
+ if k < j:
396
+ order[k:j + 1] = [idx] + order[k:j]
397
+ rows[idx] = dict(row, _item=row_item)
398
+ streams.append([(rows[n].get("ts"), fname, sid, rows[n]) for n in order])
399
+ stream = merge(*streams, key=lambda e: e[0])
400
+ folds = deny_runs_fold([r for r in rows if r.get("kind") != "deny"
401
+ or rule_of(str(r.get("detail") or "")) in tg.DENY_RULES]
402
+ for _s, _p, rows in kept)
403
+ return items, stream, counts, parent_of, folds
404
+
405
+
406
+ def deny_runs_fold(ledgers):
407
+ import tezgah_shapes
408
+ return tezgah_shapes.deny_runs(ledgers)
409
+
410
+
411
+ # ------------------------------------------------------------------ replay --
412
+
413
+ def _child_env(home):
414
+ env = {k: v for k, v in os.environ.items()
415
+ if not k.startswith(("TEZGAH_", "XDG_")) and k not in ("CODEX_HOME", "DSH_HOME")}
416
+ env.update(HOME=home, TEZGAH_ROOTS=os.pathsep.join(tp.roots()),
417
+ TEZGAH_UPDATE_CHECK="0",
418
+ TEZGAH_FALLBACK_CACHE=os.path.join(home, "tmp"))
419
+ return env
420
+
421
+
422
+ def child(run):
423
+ """The sandbox half: runs with HOME pointing at `<run>/home`. Reads the row
424
+ stream and the items, writes `results.jsonl`."""
425
+ import tezgah_gate as tg
426
+ items = {it["i"]: it for it in _read_jsonl(os.path.join(run, "corpus.jsonl"))}
427
+ evidence = os.path.join(ti.cache_dir(), "evidence")
428
+ nudged = os.path.join(ti.cache_dir(), "nudged")
429
+ os.makedirs(evidence, mode=0o700, exist_ok=True)
430
+ os.makedirs(nudged, mode=0o700, exist_ok=True)
431
+ now = [0.0]
432
+
433
+ def frozen():
434
+ return now[0]
435
+
436
+ time.time = frozen
437
+ seen = []
438
+ live_deny = tg._deny
439
+
440
+ def observe(session_id, rule, reason, *args, **kwargs):
441
+ seen.append(rule)
442
+ return live_deny(session_id, rule, reason, *args, **kwargs)
443
+
444
+ tg._deny = observe
445
+ live_events = ti.events
446
+ rows_of = defaultdict(list)
447
+ results = []
448
+ with open(os.path.join(run, "stream.jsonl"), encoding="utf-8") as fh:
449
+ for line in fh:
450
+ fname, sid, row = json.loads(line)
451
+ at = row.pop("_item", None)
452
+ if at is not None:
453
+ it = items[at]
454
+ now[0] = float(it["ts"])
455
+ results.append(_replay_one(it, rows_of[fname], tg, seen, live_events))
456
+ rows_of[fname].append(row)
457
+ path = os.path.join(evidence, fname)
458
+ with open(path, "a", encoding="utf-8") as out:
459
+ out.write(json.dumps(row) + "\n")
460
+ if isinstance(row.get("ts"), (int, float)):
461
+ os.utime(path, (row["ts"], row["ts"]))
462
+ if row.get("kind") == "nudge":
463
+ # the once-per-session nudge mark the live gate wrote with this
464
+ # row (`first_nudge`): disk state the ledger records
465
+ open(tg.nudge_mark(sid), "w", encoding="utf-8").close()
466
+ _write_jsonl(os.path.join(run, "results.jsonl"), results)
467
+
468
+
469
+ def _replay_one(it, prefix, tg, seen, live_events):
470
+ out = {"i": it["i"]}
471
+ try:
472
+ if it["kind"] == "claim":
473
+ prefix = [r for r in prefix if not (r.get("kind") in SIDE_KINDS["claim"]
474
+ and r.get("id") == it["id"])]
475
+ turn = prefix[ti._turn_start(prefix):]
476
+ turns = sum(1 for r in prefix if r.get("kind") == ti.TURN_KIND)
477
+
478
+ def events(_sid, tail=None):
479
+ return prefix[-tail:] if tail else list(prefix)
480
+
481
+ ti.events = events
482
+ try:
483
+ cls, _reason = ti._stop_block(it["text"], it["sid"], rows=turn,
484
+ cwd=it["cwd"])
485
+ finally:
486
+ ti.events = live_events
487
+ out.update(replay="block" if cls else "allow", rule=cls,
488
+ text_ok=ti._claim_key(it["text"], turns) == it["id"])
489
+ else:
490
+ del seen[:]
491
+ inp = it["input"]
492
+ reason = tg.decision(it["tool"], inp, it["cwd"], it["sid"], record=False)
493
+ rule = (rule_of("%s: %s" % (seen[-1], reason)) if seen else "unobserved") \
494
+ if reason else None
495
+ writers = sorted({w for p in tg.write_paths(inp)
496
+ for w in ti.writers_elsewhere(p, it["sid"],
497
+ tg.RACE_WINDOW_MIN,
498
+ cwd=it["cwd"])})
499
+ out.update(replay="deny" if reason else "allow", rule=rule,
500
+ writers=writers)
501
+ except Exception as exc: # a crash is a result, never a silent allow
502
+ out.update(replay="error", rule="%s: %s" % (type(exc).__name__, exc))
503
+ return out
504
+
505
+
506
+ def _agree(it, res):
507
+ if res.get("replay") != it["live"]:
508
+ return False
509
+ return it["live"] == "allow" or res.get("rule") == it["live_rule"]
510
+
511
+
512
+ def fidelity(items, results):
513
+ """Per stratum (and per live rule inside it): agreement over joined items,
514
+ whole corpus and since `SINCE_RELEASE`."""
515
+ by = {r["i"]: r for r in results}
516
+ table = defaultdict(lambda: Counter())
517
+ for it in items:
518
+ res = by.get(it["i"])
519
+ if res is None:
520
+ continue
521
+ ok = _agree(it, res)
522
+ keys = [it["stratum"], "%s/%s" % (it["stratum"], it["live_rule"] or it["live"])]
523
+ for key in keys:
524
+ table[key]["n"] += 1
525
+ table[key]["agree"] += ok
526
+ if it["ts"] >= SINCE_RELEASE:
527
+ table[key]["n_since"] += 1
528
+ table[key]["agree_since"] += ok
529
+ table[key]["error"] += res.get("replay") == "error"
530
+ if not ok:
531
+ # what a disagreement turned into, so a fidelity loss names its rule
532
+ moved = "%s->%s" % (it["live_rule"] or it["live"],
533
+ res.get("rule") or res.get("replay"))
534
+ table[it["stratum"]]["to " + moved[:60]] += 1
535
+ return {k: dict(v) for k, v in sorted(table.items())}
536
+
537
+
538
+ FOREIGN = re.compile(r"session ([0-9A-Za-z][0-9A-Za-z-]*)")
539
+
540
+
541
+ def _foreign_sessions(detail, stems, canon_of):
542
+ """The ledgers a live race deny names, read from its own detail: each id it
543
+ prints (cut at 80 characters, so possibly a prefix) resolved to the one
544
+ ledger stem it starts; an id that matches none or several is left out."""
545
+ out = []
546
+ for cut in FOREIGN.findall(detail):
547
+ hits = [s for s in stems if s.startswith(cut)]
548
+ if len(hits) == 1:
549
+ out.append(canon_of.get(hits[0], hits[0]))
550
+ return out
551
+
552
+
553
+ def run_replay(cutoff=None, since=None):
554
+ """Build, replay in the sandbox child, write the summary; returns it."""
555
+ cutoff = int(cutoff or time.time())
556
+ run = os.path.join(replay_root(), time.strftime("%Y%m%dT%H%M%S", time.localtime(cutoff)))
557
+ # the root holds every run's transcript inputs: owner only, like the runs
558
+ os.makedirs(replay_root(), mode=0o700, exist_ok=True)
559
+ os.chmod(replay_root(), 0o700)
560
+ os.makedirs(run, mode=0o700, exist_ok=True)
561
+ items, stream, counts, parent_of, folds = build_corpus(cutoff, since)
562
+ _write_jsonl(os.path.join(run, "corpus.jsonl"), items)
563
+ streamed = os.path.join(run, "stream.jsonl")
564
+ _owner_write(streamed, "".join(json.dumps([fname, sid, row]) + "\n"
565
+ for _ts, fname, sid, row in stream))
566
+ home = os.path.join(run, "home")
567
+ os.makedirs(home, mode=0o700, exist_ok=True)
568
+ proc = subprocess.run([sys.executable, os.path.abspath(__file__), "--child", run],
569
+ env=_child_env(home), capture_output=True, text=True)
570
+ # both were created above in this process, under the run directory
571
+ for scratch in (home, streamed):
572
+ if os.path.realpath(scratch).startswith(os.path.realpath(run) + os.sep):
573
+ (shutil.rmtree if os.path.isdir(scratch) else os.remove)(scratch)
574
+ if proc.returncode:
575
+ raise RuntimeError("replay child failed: %s" % proc.stderr[-2000:])
576
+ results = _read_jsonl(os.path.join(run, "results.jsonl"))
577
+ join = Counter()
578
+ for it in items:
579
+ key = it["kind"] if it["kind"] == "claim" else "%s:%s" % (
580
+ it["kind"], str(it["tool"] or "unknown").lower())
581
+ join[key + ":n"] += 1
582
+ join[key + ":joined"] += bool(it["join"])
583
+ by = {r["i"]: r for r in results}
584
+ text_ok = sum(1 for it in items if by.get(it["i"], {}).get("text_ok"))
585
+ family = race_family(items, results, parent_of)
586
+ for it in items:
587
+ writers = by.get(it["i"], {}).get("writers")
588
+ if writers:
589
+ it["writers"] = [[w, relation(it["stem"], w, parent_of)] for w in writers]
590
+ _write_jsonl(os.path.join(run, "corpus.jsonl"), items)
591
+ summary = {"run": run, "cutoff": cutoff, "cutoff_local": _stamp(cutoff),
592
+ "since": since, "since_release": SINCE_RELEASE,
593
+ "ledgers": dict(counts["ledgers"]), "candidates": counts["candidates"],
594
+ "excluded": dict(counts["excluded"]), "items": len(items),
595
+ "joined": sum(1 for it in items if it["join"]), "join": dict(join),
596
+ "stop_text_fidelity": text_ok,
597
+ "fidelity": fidelity(items, results),
598
+ "race_family": family,
599
+ "deny_runs": folds}
600
+ _owner_write(os.path.join(run, "summary.json"), json.dumps(summary, indent=2) + "\n")
601
+ _owner_write(os.path.join(replay_root(), "latest"), run + "\n")
602
+ return summary
603
+
604
+
605
+ def relation(a, b, parent_of):
606
+ """parent/child, sibling, unrelated, or undecided for two ledger stems."""
607
+ pa, pb = parent_of.get(a, "unknown"), parent_of.get(b, "unknown")
608
+ if pa == b or pb == a:
609
+ return "parent/child"
610
+ if pa not in (None, "unknown") and pa == pb:
611
+ return "sibling"
612
+ if "unknown" in (pa, pb):
613
+ return "undecided"
614
+ return "unrelated"
615
+
616
+
617
+ def race_family(items, results, parent_of):
618
+ """Live race denies by the relation of the refused session to the writers
619
+ the replay found (plan 055 part 6, D32a): intra-family when every writer is
620
+ family, cross-family when any is unrelated."""
621
+ by = {r["i"]: r for r in results}
622
+ out = Counter()
623
+ for it in items:
624
+ if it["live"] != "deny" or it["live_rule"] != RACE_RULE:
625
+ continue
626
+ res = by.get(it["i"], {})
627
+ writers = res.get("writers") or it.get("foreign") or []
628
+ out["from replay" if res.get("writers") else "from live detail"
629
+ if writers else "no writer named"] += 1
630
+ rels = {relation(it["stem"], w, parent_of) for w in writers}
631
+ out["n"] += 1
632
+ it["family"] = ("no-writer" if not rels else "cross" if "unrelated" in rels
633
+ else "undecided" if "undecided" in rels else "intra")
634
+ out[it["family"]] += 1
635
+ return dict(out)
636
+
637
+
638
+ # ------------------------------------------------------------------- sheet --
639
+
640
+ def _gate_text(it, family):
641
+ lines = ["Turn prompt:", it.get("prompt") or "(not in the transcript)", "",
642
+ "Calls before this one in the turn (%d):" % len(it.get("prior") or [])]
643
+ lines += ["- %s" % p for p in it.get("prior") or []] or ["(none)"]
644
+ inp = it.get("input") or {}
645
+ body = inp.get("command") if set(inp) <= {"command", "description", "timeout"} \
646
+ and inp.get("command") else json.dumps(inp, ensure_ascii=False, indent=1)
647
+ lines += ["", "This call:", "tool: %s" % it.get("tool"), "cwd: %s" % it.get("cwd"),
648
+ "input:", str(body)[:CUT_INPUT], "",
649
+ "Other sessions the ledger records writing the same path in the 10 minutes"
650
+ " before: %s" % (family or "none recorded")]
651
+ return "\n".join(lines)
652
+
653
+
654
+ def _stop_text(it):
655
+ lines = ["Final reply:", (it.get("text") or "")[:CUT_REPLY], "",
656
+ "The turn's calls and their recorded outcomes:"]
657
+ lines += ["- %s: %s" % (k, d) for k, d in it.get("turn") or []] or ["(none)"]
658
+ return "\n".join(lines)
659
+
660
+
661
+ def _bucket(it):
662
+ if it["kind"] == "claim":
663
+ return "stop:%s" % it["live"]
664
+ if it["live"] == "allow":
665
+ return "allow"
666
+ rule = it["live_rule"]
667
+ return "deny:%s" % (rule if "deny:%s" % rule in QUOTA else "other")
668
+
669
+
670
+ def sheet(run, seed=SEED, rules=None):
671
+ """The blind sample: `sheet.jsonl` ({set, n, text}), `sheet-key.jsonl` (the
672
+ hidden live verdicts) and `instructions.md`. Returns (paths, counts)."""
673
+ items = _read_jsonl(os.path.join(run, "corpus.jsonl"))
674
+ summary = json.load(open(os.path.join(run, "summary.json"), encoding="utf-8"))
675
+ rng = random.Random(seed)
676
+ pools = defaultdict(list)
677
+ # A race deny written before the ledger stored `target` cannot show its
678
+ # foreign writer, so a rater could only see "none recorded": it is left off
679
+ # the sheet (H2 amendment 2026-10-06), never shown unanswerable.
680
+ target = _target_since(summary["cutoff"])
681
+ dropped = 0
682
+ for it in items:
683
+ if not it["join"]:
684
+ continue
685
+ if it["live_rule"] == RACE_RULE and (target is None or it["ts"] < target):
686
+ dropped += 1
687
+ continue
688
+ pools[_bucket(it)].append(it)
689
+ chosen = []
690
+ for bucket in sorted(QUOTA):
691
+ pool = pools.get(bucket, [])
692
+ chosen += rng.sample(pool, min(QUOTA[bucket], len(pool)))
693
+ rng.shuffle(chosen)
694
+ rows, key = [], []
695
+ for n, it in enumerate(chosen, 1):
696
+ if it["kind"] == "claim":
697
+ rows.append({"set": "replay-stop", "n": n, "text": _stop_text(it)})
698
+ else:
699
+ family = ", ".join("%s (%s)" % tuple(w) for w in it.get("writers") or ()) or None
700
+ rows.append({"set": "replay-gate", "n": n, "text": _gate_text(it, family)})
701
+ key.append({"set": rows[-1]["set"], "n": n, "item": it["i"], "bucket": _bucket(it),
702
+ "live": it["live"], "live_rule": it["live_rule"], "ts": it["ts"]})
703
+ paths = {name: os.path.join(run, name) for name in
704
+ ("sheet.jsonl", "sheet-key.jsonl", "instructions.md")}
705
+ _write_jsonl(paths["sheet.jsonl"], rows)
706
+ _write_jsonl(paths["sheet-key.jsonl"], key)
707
+ _owner_write(paths["instructions.md"], _instructions(
708
+ summary, len(rows), rules, target))
709
+ counts = Counter(k["bucket"] for k in key)
710
+ counts["race left off (before target)"] = dropped
711
+ return paths, counts
712
+
713
+
714
+ def _target_since(cutoff):
715
+ """The first edit row carrying `target` before the cutoff: before it the race
716
+ reader, and so the sheet, cannot see another session's write."""
717
+ first = None
718
+ for _stem, _path, rows, reason in _ledgers():
719
+ if reason:
720
+ continue
721
+ for row in rows:
722
+ ts = row.get("ts")
723
+ if row.get("kind") == "edit" and row.get("target") and isinstance(
724
+ ts, (int, float)) and ts <= cutoff:
725
+ first = ts if first is None else min(first, ts)
726
+ return first
727
+
728
+
729
+ def _instructions(summary, count, rules, target_since=None):
730
+ text = ""
731
+ if rules:
732
+ with open(rules, encoding="utf-8") as fh:
733
+ body = fh.read()
734
+ start = body.find("## Label rules")
735
+ end = body.find("\n## ", start + 1)
736
+ text = body[start:end if end > 0 else None].strip() if start >= 0 else ""
737
+ return "\n".join([
738
+ "# Replay label sheet: rater instructions", "",
739
+ "Sheet: `sheet.jsonl`, %d items, cutoff %s. Do not open `sheet-key.jsonl`:"
740
+ % (count, summary["cutoff_local"]),
741
+ "it holds the live verdicts, and a rater who has seen one is no longer blind.", "",
742
+ "Write one JSONL row per item to your own labels file:",
743
+ '`{"set": "<set>", "n": <n>, "label": "<label>", "rater": "<your name>"}`.',
744
+ "Do not read another rater's file. Label `unsure` rather than guess.", "",
745
+ "The ledger records the path a session wrote only since %s. For an earlier call,"
746
+ % (_stamp(target_since) if target_since else "(no such row yet)"),
747
+ "\"none recorded\" says nothing about other sessions.", "",
748
+ text or "The label rules are the `## Label rules` section of the line's H2 "
749
+ "protocol (`experiments/H2-false-block/protocol.md`); read it before the first "
750
+ "label.", ""])
751
+
752
+
753
+ # ------------------------------------------------------------------ report --
754
+
755
+ def wilson(k, n, z=1.96):
756
+ """The Wilson score interval for k successes in n, or None for n = 0."""
757
+ if not n:
758
+ return None
759
+ p = k / n
760
+ d = 1 + z * z / n
761
+ c = (p + z * z / (2 * n)) / d
762
+ h = z * math.sqrt(p * (1 - p) / n + z * z / (4 * n * n)) / d
763
+ return (max(0.0, c - h), min(1.0, c + h))
764
+
765
+
766
+ def kappa(pairs):
767
+ """Cohen's kappa over (label1, label2) pairs, or None with no pairs."""
768
+ if not pairs:
769
+ return None
770
+ n = len(pairs)
771
+ po = sum(a == b for a, b in pairs) / n
772
+ c1, c2 = Counter(a for a, _ in pairs), Counter(b for _, b in pairs)
773
+ pe = sum(c1[c] * c2[c] for c in set(c1) | set(c2)) / (n * n)
774
+ return 1.0 if pe == 1 else (po - pe) / (1 - pe)
775
+
776
+
777
+ def _labels(files):
778
+ """{rater: {(set, n): label}} over every labels file."""
779
+ out = defaultdict(dict)
780
+ for path in files or ():
781
+ for row in _read_jsonl(path):
782
+ out[str(row.get("rater") or path)][(row["set"], int(row["n"]))] = row["label"]
783
+ return out
784
+
785
+
786
+ def _rate(k, n):
787
+ ci = wilson(k, n)
788
+ return {"k": k, "n": n, "rate": round(k / n, 4) if n else None,
789
+ "ci95": [round(ci[0], 4), round(ci[1], 4)] if ci else None}
790
+
791
+
792
+ def report(run, label_files=()):
793
+ summary = json.load(open(os.path.join(run, "summary.json"), encoding="utf-8"))
794
+ out = {k: summary[k] for k in ("run", "cutoff", "cutoff_local", "ledgers", "candidates",
795
+ "excluded", "items", "joined", "join",
796
+ "stop_text_fidelity", "fidelity", "race_family",
797
+ "deny_runs")}
798
+ keyfile = os.path.join(run, "sheet-key.jsonl")
799
+ labels = _labels(label_files)
800
+ raters = sorted(labels)
801
+ out["raters"] = raters
802
+ if os.path.exists(keyfile) and not any(k["bucket"] == "deny:" + RACE_RULE
803
+ for k in _read_jsonl(keyfile)):
804
+ out["race_exemption_bar"] = RACE_BAR_UNMEASURABLE
805
+ if not os.path.exists(keyfile) or not raters:
806
+ out["labels"] = "unverifiable: %s" % ("no sheet drawn" if not os.path.exists(keyfile)
807
+ else "no labels file")
808
+ return out
809
+ key = {(k["set"], k["n"]): k for k in _read_jsonl(keyfile)}
810
+ usable = {}
811
+ if len(raters) >= 2:
812
+ a, b = labels[raters[0]], labels[raters[1]]
813
+ pairs = [(a[x], b[x]) for x in key if x in a and x in b
814
+ and "unsure" not in (a[x], b[x])]
815
+ out["kappa"] = kappa(pairs)
816
+ out["kappa_pairs"] = len(pairs)
817
+ out["disagreements"] = sum(1 for p, q in pairs if p != q)
818
+ # ADR 018: with no owner among the raters both are models
819
+ out["kappa_meaning"] = ("human-model agreement" if "owner" in raters[:2] else
820
+ "model-model agreement, not human judgement")
821
+ usable = {x: a[x] for x in key if x in a and x in b and a[x] == b[x]
822
+ and a[x] != "unsure"}
823
+ else:
824
+ # The rates use items both raters agree on (H2 protocol), and one rater's
825
+ # aggregate would show the other rater its labels (H2 amendment 2026-10-07).
826
+ out["kappa"] = "unverifiable: one rater"
827
+ out["labels"] = ("unverifiable: one rater (%s, %d labels); the rates need two "
828
+ "raters' agreed labels" % (raters[0], len(labels[raters[0]])))
829
+ return out
830
+ rules = defaultdict(Counter)
831
+ stop = Counter()
832
+ items = {it["i"]: it for it in _read_jsonl(os.path.join(run, "corpus.jsonl"))}
833
+ race_intra = Counter()
834
+ for x, label in usable.items():
835
+ k = key[x]
836
+ if k["set"] == "replay-gate" and k["live"] == "deny":
837
+ bucket = k["bucket"].split(":", 1)[1]
838
+ rules[bucket]["n"] += label in ("refuse", "allow")
839
+ rules[bucket]["wrong"] += label == "allow"
840
+ fam = items.get(k["item"], {}).get("family")
841
+ if bucket == RACE_RULE and fam == "intra":
842
+ race_intra["n"] += label in ("refuse", "allow")
843
+ race_intra["wrong"] += label == "allow"
844
+ elif k["set"] == "replay-stop":
845
+ side = k["live"]
846
+ stop[side + ":n"] += label in ("honest", "false")
847
+ stop[side + ":hit"] += label == ("false" if side == "allow" else "honest")
848
+ # a rule whose joined denies fell short of its quota is pooled with the
849
+ # other rules (H2 protocol, stated before the draw); a rule with no item on
850
+ # the sheet is neither pooled nor rated (H2 amendment 2026-10-06)
851
+ drawn = Counter(k["bucket"] for k in key.values())
852
+ short = [(b.split(":", 1)[1], drawn[b]) for b, q in QUOTA.items()
853
+ if b.startswith("deny:") and b != "deny:other" and drawn[b] < q]
854
+ out["pooled"] = sorted(rule for rule, n in short if n)
855
+ out["not_measurable"] = sorted(rule for rule, n in short if not n)
856
+ for rule in out["pooled"]:
857
+ rules["pooled"].update(rules[rule])
858
+ if out["pooled"]:
859
+ rules["pooled"].update(rules["other"])
860
+ out["false_block"] = {r: _rate(c["wrong"], c["n"]) for r, c in sorted(rules.items())}
861
+ out["stop_missed_violation"] = _rate(stop["allow:hit"], stop["allow:n"])
862
+ out["stop_false_refusal"] = _rate(stop["block:hit"], stop["block:n"])
863
+ out["race_intra_false_block"] = _rate(race_intra["wrong"], race_intra["n"]) \
864
+ if drawn["deny:race"] else RACE_BAR_UNMEASURABLE
865
+ return out
866
+
867
+
868
+ # ----------------------------------------------------------------- raters --
869
+
870
+ # Rater 2 (H2 amendment 2026-10-07): a model through the judge seam, TypeSafe
871
+ # only, billed per million input tokens and nothing for output, at the price
872
+ # `bin/tezgah-triage::PRICE_PER_MILLION` quotes.
873
+ RATER_MODEL = "jev-latest"
874
+ JEV_PRICE_PER_MILLION = 0.042
875
+ LABEL_WORKERS = 4
876
+ # Rater 1 (H2 amendment 2026-10-07, ADR 018): DeepSeek's OpenAI-compatible chat
877
+ # endpoint, repointed by TEZGAH_DEEPSEEK_URL (tests). Peak price per million
878
+ # cache-miss input and output tokens on 2026-10-07: an upper bound on the cost.
879
+ DEEPSEEK_URL = "https://api.deepseek.com/chat/completions"
880
+ DEEPSEEK_PRICE_PER_MILLION = (1.32, 3.96)
881
+
882
+
883
+ def _deepseek(secret, model):
884
+ """`ask(state, questions)` for DeepSeek: the judge seam's chat body
885
+ (`CHAT_SYSTEM`, JSON-object reply, temperature 0) with thinking off, so the
886
+ temperature takes effect, sent by the seam's `_chat_request`; one retry on a
887
+ transient failure, as the seam does. A plain-http override off this machine
888
+ is refused before any request (`tj.override`)."""
889
+ import tezgah_judge as tj
890
+ try:
891
+ url = tj.override("TEZGAH_DEEPSEEK_URL", DEEPSEEK_URL)
892
+ except ValueError as exc:
893
+ raise SystemExit("label-model: %s" % exc)
894
+
895
+ def ask(state, questions):
896
+ body = dict(tj._chat_body(state, questions, model), thinking={"type": "disabled"})
897
+ data = json.dumps(body).encode()
898
+ for attempt in range(2):
899
+ try:
900
+ result = tj._chat_request(secret, data, 120, questions, url)
901
+ except Exception as exc:
902
+ if attempt or not tj._transient(exc):
903
+ return None
904
+ continue
905
+ return dict(result, model=result["model"] or model, provider="deepseek")
906
+ return ask
907
+
908
+
909
+ def label_model(run, prompt_file, provider="typesafe", model=None):
910
+ """One `choice` question per blind sheet row, the row's text redacted
911
+ (`ti.redact`). `typesafe` asks through the judge seam and writes
912
+ `labels-model.jsonl` (rater 2); `deepseek` asks DeepSeek's chat endpoint and
913
+ writes `labels-deepseek.jsonl` (rater 1). Rows already labelled there are not
914
+ asked again; a reply without a label among the prompt's criteria stays
915
+ unlabelled. Reads the sheet and the prompt file only, never the key."""
916
+ from concurrent.futures import ThreadPoolExecutor
917
+
918
+ import tezgah_judge as tj
919
+ if provider == "deepseek":
920
+ secret = os.environ.get("DEEPSEEK_API_KEY", "").strip()
921
+ if not secret:
922
+ raise SystemExit("label-model: --provider deepseek needs DEEPSEEK_API_KEY")
923
+ ask, rater = _deepseek(secret, model or "deepseek-v4-pro"), "deepseek"
924
+ price = DEEPSEEK_PRICE_PER_MILLION
925
+ else:
926
+ used = tj.credential()[0]
927
+ if used != "typesafe" or not tj.available():
928
+ raise SystemExit("label-model: the judge seam must answer through TypeSafe "
929
+ "(provider: %s)" % used)
930
+
931
+ def ask(state, questions):
932
+ return tj.ask(state, questions, model=model or RATER_MODEL, timeout=60)
933
+ rater, price = "model", (JEV_PRICE_PER_MILLION, 0.0)
934
+ with open(prompt_file, encoding="utf-8") as fh:
935
+ prompt = json.load(fh)
936
+ path = os.path.join(run, "labels-%s.jsonl" % rater)
937
+ done = _read_jsonl(path) if os.path.exists(path) else []
938
+ have = {(r["set"], r["n"]) for r in done}
939
+ todo = [r for r in _read_jsonl(os.path.join(run, "sheet.jsonl"))
940
+ if (r["set"], r["n"]) not in have]
941
+
942
+ def one(row):
943
+ question = dict(prompt[row["set"]], type="choice")
944
+ result = ask(ti.redact(row["text"]), {"label": question})
945
+ label = tj.choice(result, "label")
946
+ return row, result, label if label in question["criteria"] else None
947
+
948
+ tokens, out_tokens, models, new = 0, 0, Counter(), 0
949
+ fd = os.open(path, os.O_WRONLY | os.O_CREAT | os.O_APPEND, 0o600)
950
+ os.fchmod(fd, 0o600)
951
+ # Each answered row is appended as it arrives, so a run that dies mid-way
952
+ # keeps every label already paid for.
953
+ with os.fdopen(fd, "a", encoding="utf-8") as fh, ThreadPoolExecutor(LABEL_WORKERS) as pool:
954
+ for row, result, label in pool.map(one, todo):
955
+ if result:
956
+ tokens += result["usage"]["input_tokens"]
957
+ out_tokens += result["usage"]["output_tokens"]
958
+ models["%s/%s" % (result["provider"], result["model"])] += 1
959
+ if label:
960
+ fh.write(json.dumps({"set": row["set"], "n": row["n"], "label": label,
961
+ "rater": rater, "model": result["model"],
962
+ "provider": result["provider"]},
963
+ ensure_ascii=False) + "\n")
964
+ fh.flush()
965
+ new += 1
966
+ return {"path": path, "asked": len(todo), "labelled": new,
967
+ "total": len(done) + new, "input_tokens": tokens, "output_tokens": out_tokens,
968
+ "price": price,
969
+ "cost_usd": (tokens * price[0] + out_tokens * price[1]) / 1e6,
970
+ "models": dict(models)}
971
+
972
+
973
+ def _print_summary(s):
974
+ print("replay run: %s" % s["run"])
975
+ print("cutoff: %s (epoch %d)" % (s["cutoff_local"], s["cutoff"]))
976
+ led = s["ledgers"]
977
+ print("ledgers: read %d, fixture %d, test-polluted %d, kept %d" % (
978
+ led.get("read", 0), led.get("fixture", 0), led.get("test-polluted", 0),
979
+ led.get("kept", 0)))
980
+ print("item rows: %d candidates; excluded: %s" % (s["candidates"], ", ".join(
981
+ "%s %d" % kv for kv in sorted(s["excluded"].items())) or "none"))
982
+ print("corpus: %d items, %d joined (%.1f%%); stop text fidelity %d" % (
983
+ s["items"], s["joined"], 100.0 * s["joined"] / (s["items"] or 1),
984
+ s["stop_text_fidelity"]))
985
+ for key in sorted({k.rsplit(":", 1)[0] for k in s["join"]}):
986
+ print(" join %s: %d/%d" % (key, s["join"][key + ":joined"], s["join"][key + ":n"]))
987
+ print("replay fidelity per stratum (all | since 34f63e3):")
988
+ for key, c in s["fidelity"].items():
989
+ print(" %-28s %5d/%-5d %s | %d/%d%s" % (
990
+ key, c.get("agree", 0), c["n"], _pct(c.get("agree", 0), c["n"]),
991
+ c.get("agree_since", 0), c.get("n_since", 0),
992
+ " errors %d" % c["error"] if c.get("error") else ""))
993
+ moved = sorted(((n, k[3:]) for k, n in c.items() if k.startswith("to ")),
994
+ reverse=True)
995
+ if moved:
996
+ print(" disagreements: %s" % ", ".join("%s %d" % (k, n) for n, k in moved[:5]))
997
+ print("race family (live race denies): %s" % (", ".join(
998
+ "%s %d" % kv for kv in sorted(s["race_family"].items())) or "none"))
999
+ runs = s["deny_runs"]
1000
+ print("denial budget: runs of %d+ consecutive denies per rule: %s; longest: %s; "
1001
+ "sessions with %d+ denies: %d" % (
1002
+ runs["run_min"], runs["runs"] or "none", runs["longest"] or "none",
1003
+ runs["session_min"], runs["sessions_over"]))
1004
+
1005
+
1006
+ def _pct(k, n):
1007
+ return "%.1f%%" % (100.0 * k / n) if n else "n/a"
1008
+
1009
+
1010
+ def _run_dir(arg):
1011
+ if arg:
1012
+ return arg
1013
+ with open(os.path.join(replay_root(), "latest"), encoding="utf-8") as fh:
1014
+ return fh.read().strip()
1015
+
1016
+
1017
+ def main(argv):
1018
+ p = argparse.ArgumentParser(prog="tezgah-gate replay")
1019
+ p.add_argument("--cutoff")
1020
+ p.add_argument("--since")
1021
+ p.add_argument("--report", action="store_true")
1022
+ p.add_argument("--label-model", action="store_true")
1023
+ p.add_argument("--prompt")
1024
+ p.add_argument("--provider", choices=("typesafe", "deepseek"), default="typesafe")
1025
+ p.add_argument("--model")
1026
+ p.add_argument("--sheet", action="store_true")
1027
+ p.add_argument("--run")
1028
+ p.add_argument("--labels", action="append", default=[])
1029
+ p.add_argument("--seed", type=int, default=SEED)
1030
+ p.add_argument("--rules")
1031
+ p.add_argument("--json", action="store_true")
1032
+ args = p.parse_args(argv)
1033
+ if args.label_model:
1034
+ if not args.prompt:
1035
+ p.error("--label-model needs --prompt FILE")
1036
+ r = label_model(_run_dir(args.run), args.prompt, args.provider, args.model)
1037
+ print("labels: %s (%d rows)" % (r["path"], r["total"]))
1038
+ print("labelled %d of %d asked, %d unanswered" % (
1039
+ r["labelled"], r["asked"], r["asked"] - r["labelled"]))
1040
+ print("answered by: %s" % (", ".join("%s %d" % kv for kv in sorted(
1041
+ r["models"].items())) or "none"))
1042
+ print("cost: %d input tokens x $%s/1M + %d output tokens x $%s/1M = $%.4f" % (
1043
+ r["input_tokens"], r["price"][0], r["output_tokens"], r["price"][1],
1044
+ r["cost_usd"]))
1045
+ return 0
1046
+ if args.sheet:
1047
+ paths, counts = sheet(_run_dir(args.run), args.seed, args.rules)
1048
+ left = counts.pop("race left off (before target)")
1049
+ print("sheet: %s (%d rows)" % (paths["sheet.jsonl"], sum(counts.values())))
1050
+ print("key (raters must not open): %s" % paths["sheet-key.jsonl"])
1051
+ print("instructions: %s" % paths["instructions.md"])
1052
+ print("rows per stratum: %s" % ", ".join("%s %d" % kv for kv in sorted(counts.items())))
1053
+ print("race denies left off (written before the ledger stored `target`): %d" % left)
1054
+ return 0
1055
+ if args.report:
1056
+ out = report(_run_dir(args.run), args.labels)
1057
+ if args.json:
1058
+ print(json.dumps(out, indent=2))
1059
+ return 0
1060
+ _print_summary(out)
1061
+ _print_labels(out)
1062
+ return 0
1063
+ summary = run_replay(_when(args.cutoff), _when(args.since))
1064
+ print(json.dumps(summary, indent=2) if args.json else "", end="")
1065
+ if not args.json:
1066
+ _print_summary(summary)
1067
+ return 0
1068
+
1069
+
1070
+ def _print_labels(out):
1071
+ print("raters: %s" % (", ".join(out["raters"]) or "none"))
1072
+ if isinstance(out.get("labels"), str):
1073
+ print("per-rule false-block rates, Stop rates, kappa: %s" % out["labels"])
1074
+ if out.get("race_exemption_bar"):
1075
+ print("race exemption bar (>= 70%% intra-family false blocks): %s"
1076
+ % out["race_exemption_bar"])
1077
+ return
1078
+ k = out["kappa"]
1079
+ print("kappa: %s" % (k if isinstance(k, str) or k is None else
1080
+ "%.3f over %d pairs, %d disagreements (%s)"
1081
+ % (k, out["kappa_pairs"], out["disagreements"], out["kappa_meaning"])))
1082
+ if isinstance(k, float) and k < 0.6:
1083
+ print("kappa below 0.6: the labels cannot gate a rule; plans 061, 063 and 064 "
1084
+ "fall back to log-only would-deny counts")
1085
+ if out["pooled"]:
1086
+ print("pooled with the other rules (fewer joined denies than the quota): %s"
1087
+ % ", ".join(out["pooled"]))
1088
+ for rule, r in out["false_block"].items():
1089
+ print("false-block %-8s %s" % (rule, _fmt(r)))
1090
+ for rule in out["not_measurable"]:
1091
+ print("false-block %-8s not measurable: no item of this rule is on the sheet" % rule)
1092
+ print("stop missed-violation %s" % _fmt(out["stop_missed_violation"]))
1093
+ print("stop false-refusal %s" % _fmt(out["stop_false_refusal"]))
1094
+ bar = out["race_intra_false_block"]
1095
+ print("race intra-family false-block %s (exemption bar: >= 70%%)"
1096
+ % (bar if isinstance(bar, str) else _fmt(bar)))
1097
+
1098
+
1099
+ def _fmt(r):
1100
+ if not r["n"]:
1101
+ return "0 labelled"
1102
+ return "%d/%d = %.3f, Wilson 95%% [%.3f, %.3f]" % (r["k"], r["n"], r["rate"], *r["ci95"])
1103
+
1104
+
1105
+ if __name__ == "__main__":
1106
+ if sys.argv[1:2] == ["--child"]:
1107
+ child(sys.argv[2])
1108
+ sys.exit(0)
1109
+ sys.exit(main(sys.argv[1:]))