@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.
- package/CHANGELOG.md +738 -0
- package/LICENSE +21 -0
- package/MANIFEST +753 -0
- package/README.de.md +169 -0
- package/README.es.md +168 -0
- package/README.fr.md +166 -0
- package/README.md +161 -0
- package/README.tr.md +163 -0
- package/agents/tezgah-reviewer.md +70 -0
- package/bin/codegen +337 -0
- package/bin/consult +797 -0
- package/bin/tezgah-adhd +50 -0
- package/bin/tezgah-agents +45 -0
- package/bin/tezgah-capture +66 -0
- package/bin/tezgah-context +96 -0
- package/bin/tezgah-decisions +213 -0
- package/bin/tezgah-design +953 -0
- package/bin/tezgah-docs +1199 -0
- package/bin/tezgah-doctor +497 -0
- package/bin/tezgah-dsh +37 -0
- package/bin/tezgah-dsh.cmd +70 -0
- package/bin/tezgah-gate +75 -0
- package/bin/tezgah-import-ai-research +439 -0
- package/bin/tezgah-index +32 -0
- package/bin/tezgah-lessons +148 -0
- package/bin/tezgah-mcp +322 -0
- package/bin/tezgah-migrate +324 -0
- package/bin/tezgah-pony +50 -0
- package/bin/tezgah-research +772 -0
- package/bin/tezgah-rollback +93 -0
- package/bin/tezgah-route +124 -0
- package/bin/tezgah-setup +5798 -0
- package/bin/tezgah-status +383 -0
- package/bin/tezgah-task +607 -0
- package/bin/tezgah-taste +423 -0
- package/bin/tezgah-triage +485 -0
- package/bin/tezgah.js +36 -0
- package/commands/adhd.md +21 -0
- package/commands/ponytail.md +21 -0
- package/docs/README.md +112 -0
- package/docs/architecture.md +226 -0
- package/docs/citations-baseline.json +59 -0
- package/docs/clarity-baseline.json +116 -0
- package/docs/contract.md +416 -0
- package/docs/environment.md +141 -0
- package/docs/evidence.md +831 -0
- package/docs/feature-audit.md +139 -0
- package/docs/gate.md +407 -0
- package/docs/glossary.md +201 -0
- package/docs/hosts.md +400 -0
- package/docs/index.json +471 -0
- package/docs/judge.md +193 -0
- package/docs/layers.md +189 -0
- package/docs/models.md +160 -0
- package/docs/operations.md +666 -0
- package/docs/research.md +809 -0
- package/docs/results/paired-outcome-2026-10.jsonl +254 -0
- package/docs/results/paired-outcome-2026-10.md +204 -0
- package/docs/skills.md +236 -0
- package/docs/status-line.md +315 -0
- package/docs/testing.md +287 -0
- package/docs/vision.md +117 -0
- package/hooks/hooks.json +33 -0
- package/hooks/projects-auto-init.py +98 -0
- package/hooks/projects-posttooluse.py +149 -0
- package/hooks/projects-pretooluse.py +40 -0
- package/hooks/projects-stop.py +60 -0
- package/hooks/tezgah_agents.py +817 -0
- package/hooks/tezgah_apps.py +266 -0
- package/hooks/tezgah_attest.py +255 -0
- package/hooks/tezgah_clarity.py +171 -0
- package/hooks/tezgah_components.py +140 -0
- package/hooks/tezgah_context.py +2953 -0
- package/hooks/tezgah_embed.py +765 -0
- package/hooks/tezgah_gate.py +2736 -0
- package/hooks/tezgah_guard.py +177 -0
- package/hooks/tezgah_index.py +124 -0
- package/hooks/tezgah_integrity.py +5141 -0
- package/hooks/tezgah_judge.py +487 -0
- package/hooks/tezgah_lang.py +230 -0
- package/hooks/tezgah_lessons.py +210 -0
- package/hooks/tezgah_models.py +855 -0
- package/hooks/tezgah_paths.py +1132 -0
- package/hooks/tezgah_policy.py +1039 -0
- package/hooks/tezgah_rank.py +77 -0
- package/hooks/tezgah_replay.py +1109 -0
- package/hooks/tezgah_research.py +5176 -0
- package/hooks/tezgah_shapes.py +305 -0
- package/hooks/tezgah_skill_pick.py +227 -0
- package/hooks/tezgah_snapshot.py +490 -0
- package/hooks/tezgah_stopspec.py +320 -0
- package/hooks/tezgah_task.py +458 -0
- package/hooks/tezgah_taste.py +201 -0
- package/hooks/tezgah_untrusted.py +112 -0
- package/hooks/tezgah_update.py +430 -0
- package/hosts/codex/hook.py +268 -0
- package/hosts/codex/hooks.json +26 -0
- package/hosts/cursor/hook.py +461 -0
- package/hosts/cursor/hooks.json +44 -0
- package/hosts/dsh/hooks.json +21 -0
- package/hosts/dsh/statusline/lib/client.js +138 -0
- package/hosts/dsh/statusline/lib/index.js +104 -0
- package/hosts/dsh/statusline/package.json +28 -0
- package/hosts/omp/hook.py +277 -0
- package/hosts/omp/tezgah-hook.ts.in +701 -0
- package/hosts/opencode/plugins/tezgah.js +2742 -0
- package/hosts/opencode/tui/tezgah-tui.tsx +151 -0
- package/output-styles/tezgah.md +142 -0
- package/package.json +32 -0
- package/packaging/build.sh +342 -0
- package/packaging/install.ps1 +166 -0
- package/packaging/install.sh +56 -0
- package/packaging/upgrade.sh +142 -0
- package/skills/ai-research/0-autoresearch-skill/SKILL.md +411 -0
- package/skills/ai-research/0-autoresearch-skill/references/agent-continuity.md +95 -0
- package/skills/ai-research/0-autoresearch-skill/references/progress-reporting.md +166 -0
- package/skills/ai-research/0-autoresearch-skill/references/skill-routing.md +219 -0
- package/skills/ai-research/0-autoresearch-skill/templates/findings.md +44 -0
- package/skills/ai-research/0-autoresearch-skill/templates/research-log.md +41 -0
- package/skills/ai-research/01-model-architecture/litgpt/SKILL.md +469 -0
- package/skills/ai-research/01-model-architecture/litgpt/references/custom-models.md +569 -0
- package/skills/ai-research/01-model-architecture/litgpt/references/distributed-training.md +452 -0
- package/skills/ai-research/01-model-architecture/litgpt/references/supported-models.md +337 -0
- package/skills/ai-research/01-model-architecture/litgpt/references/training-recipes.md +620 -0
- package/skills/ai-research/01-model-architecture/mamba/SKILL.md +260 -0
- package/skills/ai-research/01-model-architecture/mamba/references/architecture-details.md +207 -0
- package/skills/ai-research/01-model-architecture/mamba/references/benchmarks.md +256 -0
- package/skills/ai-research/01-model-architecture/mamba/references/training-guide.md +389 -0
- package/skills/ai-research/01-model-architecture/nanogpt/SKILL.md +290 -0
- package/skills/ai-research/01-model-architecture/nanogpt/references/architecture.md +383 -0
- package/skills/ai-research/01-model-architecture/nanogpt/references/data.md +477 -0
- package/skills/ai-research/01-model-architecture/nanogpt/references/training.md +565 -0
- package/skills/ai-research/01-model-architecture/rwkv/SKILL.md +260 -0
- package/skills/ai-research/01-model-architecture/rwkv/references/architecture-details.md +345 -0
- package/skills/ai-research/01-model-architecture/rwkv/references/rwkv7.md +387 -0
- package/skills/ai-research/01-model-architecture/rwkv/references/state-management.md +370 -0
- package/skills/ai-research/01-model-architecture/torchtitan/SKILL.md +358 -0
- package/skills/ai-research/01-model-architecture/torchtitan/references/checkpoint.md +182 -0
- package/skills/ai-research/01-model-architecture/torchtitan/references/custom-models.md +259 -0
- package/skills/ai-research/01-model-architecture/torchtitan/references/float8.md +134 -0
- package/skills/ai-research/01-model-architecture/torchtitan/references/fsdp.md +127 -0
- package/skills/ai-research/02-tokenization/huggingface-tokenizers/SKILL.md +516 -0
- package/skills/ai-research/02-tokenization/huggingface-tokenizers/references/algorithms.md +654 -0
- package/skills/ai-research/02-tokenization/huggingface-tokenizers/references/integration.md +638 -0
- package/skills/ai-research/02-tokenization/huggingface-tokenizers/references/pipeline.md +724 -0
- package/skills/ai-research/02-tokenization/huggingface-tokenizers/references/training.md +566 -0
- package/skills/ai-research/02-tokenization/sentencepiece/SKILL.md +235 -0
- package/skills/ai-research/02-tokenization/sentencepiece/references/algorithms.md +201 -0
- package/skills/ai-research/02-tokenization/sentencepiece/references/training.md +305 -0
- package/skills/ai-research/03-fine-tuning/axolotl/SKILL.md +158 -0
- package/skills/ai-research/03-fine-tuning/axolotl/references/api.md +5549 -0
- package/skills/ai-research/03-fine-tuning/axolotl/references/dataset-formats.md +1030 -0
- package/skills/ai-research/03-fine-tuning/axolotl/references/index.md +16 -0
- package/skills/ai-research/03-fine-tuning/axolotl/references/other.md +3564 -0
- package/skills/ai-research/03-fine-tuning/llama-factory/SKILL.md +80 -0
- package/skills/ai-research/03-fine-tuning/llama-factory/references/_images.md +24 -0
- package/skills/ai-research/03-fine-tuning/llama-factory/references/advanced.md +1056 -0
- package/skills/ai-research/03-fine-tuning/llama-factory/references/getting_started.md +350 -0
- package/skills/ai-research/03-fine-tuning/llama-factory/references/index.md +20 -0
- package/skills/ai-research/03-fine-tuning/llama-factory/references/other.md +32 -0
- package/skills/ai-research/03-fine-tuning/peft/SKILL.md +431 -0
- package/skills/ai-research/03-fine-tuning/peft/references/advanced-usage.md +515 -0
- package/skills/ai-research/03-fine-tuning/peft/references/troubleshooting.md +481 -0
- package/skills/ai-research/03-fine-tuning/unsloth/SKILL.md +80 -0
- package/skills/ai-research/03-fine-tuning/unsloth/references/index.md +8 -0
- package/skills/ai-research/03-fine-tuning/unsloth/references/llms.md +83 -0
- package/skills/ai-research/04-mechanistic-interpretability/nnsight/SKILL.md +436 -0
- package/skills/ai-research/04-mechanistic-interpretability/nnsight/references/README.md +79 -0
- package/skills/ai-research/04-mechanistic-interpretability/nnsight/references/api.md +345 -0
- package/skills/ai-research/04-mechanistic-interpretability/nnsight/references/tutorials.md +301 -0
- package/skills/ai-research/04-mechanistic-interpretability/pyvene/SKILL.md +473 -0
- package/skills/ai-research/04-mechanistic-interpretability/pyvene/references/README.md +74 -0
- package/skills/ai-research/04-mechanistic-interpretability/pyvene/references/api.md +384 -0
- package/skills/ai-research/04-mechanistic-interpretability/pyvene/references/tutorials.md +377 -0
- package/skills/ai-research/04-mechanistic-interpretability/saelens/SKILL.md +386 -0
- package/skills/ai-research/04-mechanistic-interpretability/saelens/references/README.md +71 -0
- package/skills/ai-research/04-mechanistic-interpretability/saelens/references/api.md +334 -0
- package/skills/ai-research/04-mechanistic-interpretability/saelens/references/tutorials.md +319 -0
- package/skills/ai-research/04-mechanistic-interpretability/transformer-lens/SKILL.md +346 -0
- package/skills/ai-research/04-mechanistic-interpretability/transformer-lens/references/README.md +55 -0
- package/skills/ai-research/04-mechanistic-interpretability/transformer-lens/references/api.md +363 -0
- package/skills/ai-research/04-mechanistic-interpretability/transformer-lens/references/tutorials.md +340 -0
- package/skills/ai-research/05-data-processing/nemo-curator/SKILL.md +383 -0
- package/skills/ai-research/05-data-processing/nemo-curator/references/deduplication.md +88 -0
- package/skills/ai-research/05-data-processing/nemo-curator/references/filtering.md +103 -0
- package/skills/ai-research/05-data-processing/ray-data/SKILL.md +326 -0
- package/skills/ai-research/05-data-processing/ray-data/references/integration.md +83 -0
- package/skills/ai-research/05-data-processing/ray-data/references/transformations.md +84 -0
- package/skills/ai-research/06-post-training/grpo-rl-training/README.md +98 -0
- package/skills/ai-research/06-post-training/grpo-rl-training/SKILL.md +572 -0
- package/skills/ai-research/06-post-training/miles/SKILL.md +315 -0
- package/skills/ai-research/06-post-training/miles/references/api-reference.md +142 -0
- package/skills/ai-research/06-post-training/miles/references/troubleshooting.md +353 -0
- package/skills/ai-research/06-post-training/openrlhf/SKILL.md +249 -0
- package/skills/ai-research/06-post-training/openrlhf/references/algorithm-comparison.md +405 -0
- package/skills/ai-research/06-post-training/openrlhf/references/custom-rewards.md +531 -0
- package/skills/ai-research/06-post-training/openrlhf/references/hybrid-engine.md +288 -0
- package/skills/ai-research/06-post-training/openrlhf/references/multi-node-training.md +455 -0
- package/skills/ai-research/06-post-training/simpo/SKILL.md +219 -0
- package/skills/ai-research/06-post-training/simpo/references/datasets.md +479 -0
- package/skills/ai-research/06-post-training/simpo/references/hyperparameters.md +453 -0
- package/skills/ai-research/06-post-training/simpo/references/loss-functions.md +351 -0
- package/skills/ai-research/06-post-training/slime/SKILL.md +464 -0
- package/skills/ai-research/06-post-training/slime/references/api-reference.md +393 -0
- package/skills/ai-research/06-post-training/slime/references/troubleshooting.md +387 -0
- package/skills/ai-research/06-post-training/torchforge/SKILL.md +433 -0
- package/skills/ai-research/06-post-training/torchforge/references/api-reference.md +328 -0
- package/skills/ai-research/06-post-training/torchforge/references/troubleshooting.md +410 -0
- package/skills/ai-research/06-post-training/trl-fine-tuning/SKILL.md +455 -0
- package/skills/ai-research/06-post-training/trl-fine-tuning/references/dpo-variants.md +228 -0
- package/skills/ai-research/06-post-training/trl-fine-tuning/references/online-rl.md +83 -0
- package/skills/ai-research/06-post-training/trl-fine-tuning/references/reward-modeling.md +123 -0
- package/skills/ai-research/06-post-training/trl-fine-tuning/references/sft-training.md +169 -0
- package/skills/ai-research/06-post-training/verl/SKILL.md +391 -0
- package/skills/ai-research/06-post-training/verl/references/api-reference.md +302 -0
- package/skills/ai-research/06-post-training/verl/references/troubleshooting.md +392 -0
- package/skills/ai-research/07-safety-alignment/constitutional-ai/SKILL.md +290 -0
- package/skills/ai-research/07-safety-alignment/llamaguard/SKILL.md +337 -0
- package/skills/ai-research/07-safety-alignment/nemo-guardrails/SKILL.md +297 -0
- package/skills/ai-research/07-safety-alignment/prompt-guard/SKILL.md +312 -0
- package/skills/ai-research/08-distributed-training/accelerate/SKILL.md +332 -0
- package/skills/ai-research/08-distributed-training/accelerate/references/custom-plugins.md +454 -0
- package/skills/ai-research/08-distributed-training/accelerate/references/megatron-integration.md +490 -0
- package/skills/ai-research/08-distributed-training/accelerate/references/performance.md +526 -0
- package/skills/ai-research/08-distributed-training/deepspeed/SKILL.md +141 -0
- package/skills/ai-research/08-distributed-training/deepspeed/references/08.md +18 -0
- package/skills/ai-research/08-distributed-training/deepspeed/references/09.md +174 -0
- package/skills/ai-research/08-distributed-training/deepspeed/references/2020.md +379 -0
- package/skills/ai-research/08-distributed-training/deepspeed/references/2023.md +280 -0
- package/skills/ai-research/08-distributed-training/deepspeed/references/assets.md +180 -0
- package/skills/ai-research/08-distributed-training/deepspeed/references/index.md +36 -0
- package/skills/ai-research/08-distributed-training/deepspeed/references/mii.md +119 -0
- package/skills/ai-research/08-distributed-training/deepspeed/references/other.md +1192 -0
- package/skills/ai-research/08-distributed-training/megatron-core/SKILL.md +366 -0
- package/skills/ai-research/08-distributed-training/megatron-core/references/benchmarks.md +250 -0
- package/skills/ai-research/08-distributed-training/megatron-core/references/parallelism-guide.md +405 -0
- package/skills/ai-research/08-distributed-training/megatron-core/references/production-examples.md +474 -0
- package/skills/ai-research/08-distributed-training/megatron-core/references/training-recipes.md +548 -0
- package/skills/ai-research/08-distributed-training/pytorch-fsdp2/SKILL.md +231 -0
- package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/pytorch_dcp_async_recipe.md +14 -0
- package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/pytorch_dcp_overview.md +19 -0
- package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/pytorch_dcp_recipe.md +18 -0
- package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/pytorch_ddp_notes.md +10 -0
- package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/pytorch_device_mesh_tutorial.md +22 -0
- package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/pytorch_examples_fsdp2.md +15 -0
- package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/pytorch_fsdp1_api.md +9 -0
- package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/pytorch_fsdp2_tutorial.md +45 -0
- package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/pytorch_fully_shard_api.md +49 -0
- package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/pytorch_tp_tutorial.md +22 -0
- package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/ray_train_fsdp2_example.md +13 -0
- package/skills/ai-research/08-distributed-training/pytorch-fsdp2/references/torchtitan_fsdp_notes.md +14 -0
- package/skills/ai-research/08-distributed-training/pytorch-lightning/SKILL.md +346 -0
- package/skills/ai-research/08-distributed-training/pytorch-lightning/references/callbacks.md +437 -0
- package/skills/ai-research/08-distributed-training/pytorch-lightning/references/distributed.md +491 -0
- package/skills/ai-research/08-distributed-training/pytorch-lightning/references/hyperparameter-tuning.md +557 -0
- package/skills/ai-research/08-distributed-training/ray-train/SKILL.md +406 -0
- package/skills/ai-research/08-distributed-training/ray-train/references/multi-node.md +629 -0
- package/skills/ai-research/09-infrastructure/lambda-labs/SKILL.md +545 -0
- package/skills/ai-research/09-infrastructure/lambda-labs/references/advanced-usage.md +612 -0
- package/skills/ai-research/09-infrastructure/lambda-labs/references/troubleshooting.md +531 -0
- package/skills/ai-research/09-infrastructure/modal/SKILL.md +341 -0
- package/skills/ai-research/09-infrastructure/modal/references/advanced-usage.md +504 -0
- package/skills/ai-research/09-infrastructure/modal/references/troubleshooting.md +495 -0
- package/skills/ai-research/09-infrastructure/skypilot/SKILL.md +509 -0
- package/skills/ai-research/09-infrastructure/skypilot/references/advanced-usage.md +492 -0
- package/skills/ai-research/09-infrastructure/skypilot/references/troubleshooting.md +571 -0
- package/skills/ai-research/10-optimization/awq/SKILL.md +310 -0
- package/skills/ai-research/10-optimization/awq/references/advanced-usage.md +325 -0
- package/skills/ai-research/10-optimization/awq/references/troubleshooting.md +345 -0
- package/skills/ai-research/10-optimization/bitsandbytes/SKILL.md +411 -0
- package/skills/ai-research/10-optimization/bitsandbytes/references/memory-optimization.md +522 -0
- package/skills/ai-research/10-optimization/bitsandbytes/references/qlora-training.md +522 -0
- package/skills/ai-research/10-optimization/bitsandbytes/references/quantization-formats.md +448 -0
- package/skills/ai-research/10-optimization/flash-attention/SKILL.md +367 -0
- package/skills/ai-research/10-optimization/flash-attention/references/benchmarks.md +216 -0
- package/skills/ai-research/10-optimization/flash-attention/references/transformers-integration.md +294 -0
- package/skills/ai-research/10-optimization/gguf/SKILL.md +427 -0
- package/skills/ai-research/10-optimization/gguf/references/advanced-usage.md +505 -0
- package/skills/ai-research/10-optimization/gguf/references/troubleshooting.md +443 -0
- package/skills/ai-research/10-optimization/gptq/SKILL.md +450 -0
- package/skills/ai-research/10-optimization/gptq/references/calibration.md +338 -0
- package/skills/ai-research/10-optimization/gptq/references/integration.md +130 -0
- package/skills/ai-research/10-optimization/gptq/references/troubleshooting.md +96 -0
- package/skills/ai-research/10-optimization/hqq/SKILL.md +445 -0
- package/skills/ai-research/10-optimization/hqq/references/advanced-usage.md +529 -0
- package/skills/ai-research/10-optimization/hqq/references/troubleshooting.md +504 -0
- package/skills/ai-research/10-optimization/ml-training-recipes/SKILL.md +319 -0
- package/skills/ai-research/10-optimization/ml-training-recipes/references/architecture.md +320 -0
- package/skills/ai-research/10-optimization/ml-training-recipes/references/biomedical.md +498 -0
- package/skills/ai-research/10-optimization/ml-training-recipes/references/domain-specific.md +626 -0
- package/skills/ai-research/10-optimization/ml-training-recipes/references/experiment-loop.md +129 -0
- package/skills/ai-research/10-optimization/ml-training-recipes/references/optimizers.md +330 -0
- package/skills/ai-research/10-optimization/ml-training-recipes/references/scaling-and-selection.md +428 -0
- package/skills/ai-research/11-evaluation/bigcode-evaluation-harness/SKILL.md +405 -0
- package/skills/ai-research/11-evaluation/bigcode-evaluation-harness/references/benchmarks.md +394 -0
- package/skills/ai-research/11-evaluation/bigcode-evaluation-harness/references/custom-tasks.md +425 -0
- package/skills/ai-research/11-evaluation/bigcode-evaluation-harness/references/issues.md +395 -0
- package/skills/ai-research/11-evaluation/lm-evaluation-harness/SKILL.md +490 -0
- package/skills/ai-research/11-evaluation/lm-evaluation-harness/references/api-evaluation.md +491 -0
- package/skills/ai-research/11-evaluation/lm-evaluation-harness/references/benchmark-guide.md +489 -0
- package/skills/ai-research/11-evaluation/lm-evaluation-harness/references/custom-tasks.md +603 -0
- package/skills/ai-research/11-evaluation/lm-evaluation-harness/references/distributed-eval.md +520 -0
- package/skills/ai-research/11-evaluation/nemo-evaluator/SKILL.md +494 -0
- package/skills/ai-research/11-evaluation/nemo-evaluator/references/adapter-system.md +341 -0
- package/skills/ai-research/11-evaluation/nemo-evaluator/references/configuration.md +448 -0
- package/skills/ai-research/11-evaluation/nemo-evaluator/references/custom-benchmarks.md +316 -0
- package/skills/ai-research/11-evaluation/nemo-evaluator/references/execution-backends.md +362 -0
- package/skills/ai-research/12-inference-serving/llama-cpp/SKILL.md +258 -0
- package/skills/ai-research/12-inference-serving/llama-cpp/references/optimization.md +90 -0
- package/skills/ai-research/12-inference-serving/llama-cpp/references/quantization.md +214 -0
- package/skills/ai-research/12-inference-serving/llama-cpp/references/server.md +126 -0
- package/skills/ai-research/12-inference-serving/sglang/SKILL.md +442 -0
- package/skills/ai-research/12-inference-serving/sglang/references/deployment.md +491 -0
- package/skills/ai-research/12-inference-serving/sglang/references/radix-attention.md +414 -0
- package/skills/ai-research/12-inference-serving/sglang/references/structured-generation.md +542 -0
- package/skills/ai-research/12-inference-serving/tensorrt-llm/SKILL.md +187 -0
- package/skills/ai-research/12-inference-serving/tensorrt-llm/references/multi-gpu.md +299 -0
- package/skills/ai-research/12-inference-serving/tensorrt-llm/references/optimization.md +243 -0
- package/skills/ai-research/12-inference-serving/tensorrt-llm/references/serving.md +471 -0
- package/skills/ai-research/12-inference-serving/vllm/SKILL.md +364 -0
- package/skills/ai-research/12-inference-serving/vllm/references/optimization.md +227 -0
- package/skills/ai-research/12-inference-serving/vllm/references/quantization.md +285 -0
- package/skills/ai-research/12-inference-serving/vllm/references/server-deployment.md +256 -0
- package/skills/ai-research/12-inference-serving/vllm/references/troubleshooting.md +448 -0
- package/skills/ai-research/13-mlops/mlflow/SKILL.md +704 -0
- package/skills/ai-research/13-mlops/mlflow/references/deployment.md +745 -0
- package/skills/ai-research/13-mlops/mlflow/references/model-registry.md +771 -0
- package/skills/ai-research/13-mlops/mlflow/references/tracking.md +681 -0
- package/skills/ai-research/13-mlops/swanlab/SKILL.md +406 -0
- package/skills/ai-research/13-mlops/swanlab/references/integrations.md +305 -0
- package/skills/ai-research/13-mlops/swanlab/references/visualization.md +234 -0
- package/skills/ai-research/13-mlops/tensorboard/SKILL.md +629 -0
- package/skills/ai-research/13-mlops/tensorboard/references/integrations.md +639 -0
- package/skills/ai-research/13-mlops/tensorboard/references/profiling.md +546 -0
- package/skills/ai-research/13-mlops/tensorboard/references/visualization.md +621 -0
- package/skills/ai-research/13-mlops/weights-and-biases/SKILL.md +590 -0
- package/skills/ai-research/13-mlops/weights-and-biases/references/artifacts.md +585 -0
- package/skills/ai-research/13-mlops/weights-and-biases/references/integrations.md +701 -0
- package/skills/ai-research/13-mlops/weights-and-biases/references/sweeps.md +848 -0
- package/skills/ai-research/14-agents/a-evolve/SKILL.md +383 -0
- package/skills/ai-research/14-agents/a-evolve/references/README.md +831 -0
- package/skills/ai-research/14-agents/a-evolve/references/api.md +594 -0
- package/skills/ai-research/14-agents/a-evolve/references/architecture.md +417 -0
- package/skills/ai-research/14-agents/a-evolve/references/design-patterns.md +462 -0
- package/skills/ai-research/14-agents/a-evolve/references/examples.md +352 -0
- package/skills/ai-research/14-agents/a-evolve/references/issues.md +591 -0
- package/skills/ai-research/14-agents/a-evolve/references/releases.md +112 -0
- package/skills/ai-research/14-agents/a-evolve/references/tutorials.md +819 -0
- package/skills/ai-research/14-agents/autogpt/SKILL.md +403 -0
- package/skills/ai-research/14-agents/autogpt/references/advanced-usage.md +536 -0
- package/skills/ai-research/14-agents/autogpt/references/troubleshooting.md +421 -0
- package/skills/ai-research/14-agents/crewai/SKILL.md +498 -0
- package/skills/ai-research/14-agents/crewai/references/flows.md +439 -0
- package/skills/ai-research/14-agents/crewai/references/tools.md +430 -0
- package/skills/ai-research/14-agents/crewai/references/troubleshooting.md +481 -0
- package/skills/ai-research/14-agents/langchain/SKILL.md +480 -0
- package/skills/ai-research/14-agents/langchain/references/agents.md +500 -0
- package/skills/ai-research/14-agents/langchain/references/integration.md +563 -0
- package/skills/ai-research/14-agents/langchain/references/rag.md +601 -0
- package/skills/ai-research/14-agents/llamaindex/SKILL.md +569 -0
- package/skills/ai-research/14-agents/llamaindex/references/agents.md +84 -0
- package/skills/ai-research/14-agents/llamaindex/references/data_connectors.md +109 -0
- package/skills/ai-research/14-agents/llamaindex/references/query_engines.md +407 -0
- package/skills/ai-research/15-rag/chroma/SKILL.md +406 -0
- package/skills/ai-research/15-rag/chroma/references/integration.md +39 -0
- package/skills/ai-research/15-rag/faiss/SKILL.md +221 -0
- package/skills/ai-research/15-rag/faiss/references/index_types.md +281 -0
- package/skills/ai-research/15-rag/pinecone/SKILL.md +358 -0
- package/skills/ai-research/15-rag/pinecone/references/deployment.md +182 -0
- package/skills/ai-research/15-rag/qdrant/SKILL.md +493 -0
- package/skills/ai-research/15-rag/qdrant/references/advanced-usage.md +649 -0
- package/skills/ai-research/15-rag/qdrant/references/troubleshooting.md +632 -0
- package/skills/ai-research/15-rag/sentence-transformers/SKILL.md +255 -0
- package/skills/ai-research/15-rag/sentence-transformers/references/models.md +124 -0
- package/skills/ai-research/16-prompt-engineering/dspy/SKILL.md +590 -0
- package/skills/ai-research/16-prompt-engineering/dspy/references/examples.md +664 -0
- package/skills/ai-research/16-prompt-engineering/dspy/references/modules.md +476 -0
- package/skills/ai-research/16-prompt-engineering/dspy/references/optimizers.md +567 -0
- package/skills/ai-research/16-prompt-engineering/guidance/SKILL.md +572 -0
- package/skills/ai-research/16-prompt-engineering/guidance/references/backends.md +555 -0
- package/skills/ai-research/16-prompt-engineering/guidance/references/constraints.md +675 -0
- package/skills/ai-research/16-prompt-engineering/guidance/references/examples.md +768 -0
- package/skills/ai-research/16-prompt-engineering/instructor/SKILL.md +740 -0
- package/skills/ai-research/16-prompt-engineering/instructor/references/examples.md +108 -0
- package/skills/ai-research/16-prompt-engineering/instructor/references/providers.md +71 -0
- package/skills/ai-research/16-prompt-engineering/instructor/references/validation.md +607 -0
- package/skills/ai-research/16-prompt-engineering/outlines/SKILL.md +652 -0
- package/skills/ai-research/16-prompt-engineering/outlines/references/backends.md +616 -0
- package/skills/ai-research/16-prompt-engineering/outlines/references/examples.md +774 -0
- package/skills/ai-research/16-prompt-engineering/outlines/references/json_generation.md +653 -0
- package/skills/ai-research/17-observability/langsmith/SKILL.md +422 -0
- package/skills/ai-research/17-observability/langsmith/references/advanced-usage.md +549 -0
- package/skills/ai-research/17-observability/langsmith/references/troubleshooting.md +538 -0
- package/skills/ai-research/17-observability/phoenix/SKILL.md +475 -0
- package/skills/ai-research/17-observability/phoenix/references/advanced-usage.md +620 -0
- package/skills/ai-research/17-observability/phoenix/references/troubleshooting.md +539 -0
- package/skills/ai-research/18-multimodal/audiocraft/SKILL.md +564 -0
- package/skills/ai-research/18-multimodal/audiocraft/references/advanced-usage.md +667 -0
- package/skills/ai-research/18-multimodal/audiocraft/references/troubleshooting.md +505 -0
- package/skills/ai-research/18-multimodal/blip-2/SKILL.md +564 -0
- package/skills/ai-research/18-multimodal/blip-2/references/advanced-usage.md +681 -0
- package/skills/ai-research/18-multimodal/blip-2/references/troubleshooting.md +527 -0
- package/skills/ai-research/18-multimodal/clip/SKILL.md +253 -0
- package/skills/ai-research/18-multimodal/clip/references/applications.md +208 -0
- package/skills/ai-research/18-multimodal/cosmos-policy/SKILL.md +402 -0
- package/skills/ai-research/18-multimodal/cosmos-policy/references/libero-commands.md +175 -0
- package/skills/ai-research/18-multimodal/cosmos-policy/references/robocasa-commands.md +147 -0
- package/skills/ai-research/18-multimodal/llava/SKILL.md +304 -0
- package/skills/ai-research/18-multimodal/llava/references/training.md +198 -0
- package/skills/ai-research/18-multimodal/openpi/SKILL.md +480 -0
- package/skills/ai-research/18-multimodal/openpi/references/checkpoints-and-env-map.md +86 -0
- package/skills/ai-research/18-multimodal/openpi/references/config-recipes.md +50 -0
- package/skills/ai-research/18-multimodal/openpi/references/pytorch-gotchas.md +49 -0
- package/skills/ai-research/18-multimodal/openpi/references/remote-client-pattern.md +48 -0
- package/skills/ai-research/18-multimodal/openpi/references/training-debugging.md +46 -0
- package/skills/ai-research/18-multimodal/openvla-oft/SKILL.md +441 -0
- package/skills/ai-research/18-multimodal/openvla-oft/references/aloha-workflow.md +141 -0
- package/skills/ai-research/18-multimodal/openvla-oft/references/config-troubleshooting.md +97 -0
- package/skills/ai-research/18-multimodal/openvla-oft/references/libero-workflow.md +115 -0
- package/skills/ai-research/18-multimodal/openvla-oft/references/paper-and-checkpoints.md +84 -0
- package/skills/ai-research/18-multimodal/segment-anything/SKILL.md +500 -0
- package/skills/ai-research/18-multimodal/segment-anything/references/advanced-usage.md +590 -0
- package/skills/ai-research/18-multimodal/segment-anything/references/troubleshooting.md +485 -0
- package/skills/ai-research/18-multimodal/stable-diffusion/SKILL.md +519 -0
- package/skills/ai-research/18-multimodal/stable-diffusion/references/advanced-usage.md +717 -0
- package/skills/ai-research/18-multimodal/stable-diffusion/references/troubleshooting.md +556 -0
- package/skills/ai-research/18-multimodal/whisper/SKILL.md +317 -0
- package/skills/ai-research/18-multimodal/whisper/references/languages.md +190 -0
- package/skills/ai-research/19-emerging-techniques/knowledge-distillation/SKILL.md +458 -0
- package/skills/ai-research/19-emerging-techniques/knowledge-distillation/references/minillm.md +335 -0
- package/skills/ai-research/19-emerging-techniques/long-context/SKILL.md +536 -0
- package/skills/ai-research/19-emerging-techniques/long-context/references/extension_methods.md +469 -0
- package/skills/ai-research/19-emerging-techniques/long-context/references/fine_tuning.md +612 -0
- package/skills/ai-research/19-emerging-techniques/long-context/references/rope.md +403 -0
- package/skills/ai-research/19-emerging-techniques/model-merging/SKILL.md +497 -0
- package/skills/ai-research/19-emerging-techniques/model-merging/references/coefficient-tuning.md +415 -0
- package/skills/ai-research/19-emerging-techniques/model-merging/references/evaluation.md +463 -0
- package/skills/ai-research/19-emerging-techniques/model-merging/references/examples.md +429 -0
- package/skills/ai-research/19-emerging-techniques/model-merging/references/methods.md +353 -0
- package/skills/ai-research/19-emerging-techniques/model-pruning/SKILL.md +495 -0
- package/skills/ai-research/19-emerging-techniques/model-pruning/references/wanda.md +348 -0
- package/skills/ai-research/19-emerging-techniques/moe-training/SKILL.md +526 -0
- package/skills/ai-research/19-emerging-techniques/moe-training/references/architectures.md +433 -0
- package/skills/ai-research/19-emerging-techniques/moe-training/references/inference.md +349 -0
- package/skills/ai-research/19-emerging-techniques/moe-training/references/training.md +426 -0
- package/skills/ai-research/19-emerging-techniques/speculative-decoding/SKILL.md +467 -0
- package/skills/ai-research/19-emerging-techniques/speculative-decoding/references/lookahead.md +310 -0
- package/skills/ai-research/19-emerging-techniques/speculative-decoding/references/medusa.md +351 -0
- package/skills/ai-research/20-ml-paper-writing/academic-plotting/SKILL.md +479 -0
- package/skills/ai-research/20-ml-paper-writing/academic-plotting/references/data-visualization.md +509 -0
- package/skills/ai-research/20-ml-paper-writing/academic-plotting/references/diagram-generation.md +395 -0
- package/skills/ai-research/20-ml-paper-writing/academic-plotting/references/style-guide.md +305 -0
- package/skills/ai-research/20-ml-paper-writing/ml-paper-writing/SKILL.md +982 -0
- package/skills/ai-research/20-ml-paper-writing/ml-paper-writing/references/checklists.md +348 -0
- package/skills/ai-research/20-ml-paper-writing/ml-paper-writing/references/citation-workflow.md +563 -0
- package/skills/ai-research/20-ml-paper-writing/ml-paper-writing/references/reviewer-guidelines.md +349 -0
- package/skills/ai-research/20-ml-paper-writing/ml-paper-writing/references/sources.md +165 -0
- package/skills/ai-research/20-ml-paper-writing/ml-paper-writing/references/writing-guide.md +477 -0
- package/skills/ai-research/20-ml-paper-writing/presenting-conference-talks/SKILL.md +298 -0
- package/skills/ai-research/20-ml-paper-writing/presenting-conference-talks/references/slide-templates.md +505 -0
- package/skills/ai-research/20-ml-paper-writing/systems-paper-writing/SKILL.md +270 -0
- package/skills/ai-research/20-ml-paper-writing/systems-paper-writing/references/checklist.md +279 -0
- package/skills/ai-research/20-ml-paper-writing/systems-paper-writing/references/reviewer-guidelines.md +116 -0
- package/skills/ai-research/20-ml-paper-writing/systems-paper-writing/references/section-blueprints.md +400 -0
- package/skills/ai-research/20-ml-paper-writing/systems-paper-writing/references/systems-conferences.md +261 -0
- package/skills/ai-research/20-ml-paper-writing/systems-paper-writing/references/writing-patterns.md +231 -0
- package/skills/ai-research/21-research-ideation/brainstorming-research-ideas/SKILL.md +384 -0
- package/skills/ai-research/21-research-ideation/creative-thinking-for-research/SKILL.md +366 -0
- package/skills/ai-research/22-agent-native-research-artifact/compiler/SKILL.md +245 -0
- package/skills/ai-research/22-agent-native-research-artifact/compiler/references/ara-schema.md +439 -0
- package/skills/ai-research/22-agent-native-research-artifact/compiler/references/exploration-tree-spec.md +125 -0
- package/skills/ai-research/22-agent-native-research-artifact/compiler/references/validation-checklist.md +149 -0
- package/skills/ai-research/22-agent-native-research-artifact/research-manager/SKILL.md +324 -0
- package/skills/ai-research/22-agent-native-research-artifact/research-manager/references/event-taxonomy.md +124 -0
- package/skills/ai-research/22-agent-native-research-artifact/research-manager/references/provenance-tags.md +190 -0
- package/skills/ai-research/22-agent-native-research-artifact/research-manager/references/session-protocol.md +162 -0
- package/skills/ai-research/22-agent-native-research-artifact/rigor-reviewer/SKILL.md +322 -0
- package/skills/ai-research/22-agent-native-research-artifact/rigor-reviewer/references/review-dimensions.md +182 -0
- package/skills/ai-research/SKILL.md +101 -0
- package/skills/ai-research/SOURCE +38 -0
- package/skills/ai-research/index/1-frame.md +18 -0
- package/skills/ai-research/index/2-data.md +21 -0
- package/skills/ai-research/index/3-train.md +48 -0
- package/skills/ai-research/index/4-measure.md +25 -0
- package/skills/ai-research/index/5-run.md +23 -0
- package/skills/ai-research/index/6-write.md +35 -0
- package/skills/ai-research/library.json +3456 -0
- package/skills/analyze-app/EVALS.md +82 -0
- package/skills/analyze-app/SKILL.md +188 -0
- package/skills/design-contract/EVALS.md +80 -0
- package/skills/design-contract/SKILL.md +171 -0
- package/skills/design-library/EVALS.md +85 -0
- package/skills/design-library/INDEX.md +59 -0
- package/skills/design-library/SKILL.md +58 -0
- package/skills/design-library/SOURCE +131 -0
- package/skills/design-library/adaptive-interfaces/skills/colour-independence/SKILL.md +90 -0
- package/skills/design-library/adaptive-interfaces/skills/flexible-typography/SKILL.md +83 -0
- package/skills/design-library/adaptive-interfaces/skills/information-density/SKILL.md +87 -0
- package/skills/design-library/adaptive-interfaces/skills/preference-audit/SKILL.md +70 -0
- package/skills/design-library/adaptive-interfaces/skills/responsive-accessibility/SKILL.md +86 -0
- package/skills/design-library/adaptive-interfaces/skills/responsive-review/SKILL.md +76 -0
- package/skills/design-library/adaptive-interfaces/skills/simplified-views/SKILL.md +97 -0
- package/skills/design-library/adaptive-interfaces/skills/specify/SKILL.md +63 -0
- package/skills/design-library/adaptive-interfaces/skills/user-preference-respect/SKILL.md +100 -0
- package/skills/design-library/cognitive-accessibility/skills/adaptive-personalisation/SKILL.md +61 -0
- package/skills/design-library/cognitive-accessibility/skills/assess-load/SKILL.md +48 -0
- package/skills/design-library/cognitive-accessibility/skills/cognitive-load-assessment/SKILL.md +60 -0
- package/skills/design-library/cognitive-accessibility/skills/contextual-help-design/SKILL.md +61 -0
- package/skills/design-library/cognitive-accessibility/skills/error-prevention-recovery/SKILL.md +71 -0
- package/skills/design-library/cognitive-accessibility/skills/focus-attention-design/SKILL.md +67 -0
- package/skills/design-library/cognitive-accessibility/skills/memory-load-reduction/SKILL.md +60 -0
- package/skills/design-library/cognitive-accessibility/skills/plain-language-design/SKILL.md +78 -0
- package/skills/design-library/cognitive-accessibility/skills/review/SKILL.md +56 -0
- package/skills/design-library/cognitive-accessibility/skills/simplify/SKILL.md +39 -0
- package/skills/design-library/cognitive-accessibility/skills/wayfinding-navigation/SKILL.md +64 -0
- package/skills/design-library/design-research/skills/behavioural-analytics/SKILL.md +33 -0
- package/skills/design-library/design-research/skills/qual-quant-triangulation/SKILL.md +33 -0
- package/skills/design-library/inclusive-interaction/skills/audit/SKILL.md +50 -0
- package/skills/design-library/inclusive-interaction/skills/design-flow/SKILL.md +58 -0
- package/skills/design-library/inclusive-interaction/skills/feedback-and-status/SKILL.md +76 -0
- package/skills/design-library/inclusive-interaction/skills/gesture-alternatives/SKILL.md +70 -0
- package/skills/design-library/inclusive-interaction/skills/keyboard-navigation/SKILL.md +99 -0
- package/skills/design-library/inclusive-interaction/skills/keyboard-review/SKILL.md +54 -0
- package/skills/design-library/inclusive-interaction/skills/motion-sensitivity/SKILL.md +79 -0
- package/skills/design-library/inclusive-interaction/skills/multi-modal-input/SKILL.md +70 -0
- package/skills/design-library/inclusive-interaction/skills/touch-target-design/SKILL.md +71 -0
- package/skills/design-library/inclusive-interaction/skills/voice-interaction/SKILL.md +68 -0
- package/skills/design-library/visual-critique/skills/critique-affordance/SKILL.md +45 -0
- package/skills/design-library/visual-critique/skills/critique-brand-consistency/SKILL.md +42 -0
- package/skills/design-library/visual-critique/skills/critique-color/SKILL.md +44 -0
- package/skills/design-library/visual-critique/skills/critique-composition/SKILL.md +46 -0
- package/skills/design-library/visual-critique/skills/critique-information-density/SKILL.md +45 -0
- package/skills/design-library/visual-critique/skills/critique-typography/SKILL.md +45 -0
- package/skills/design-library/visual-critique/skills/critique-visual-hierarchy/SKILL.md +40 -0
- package/skills/feature-audit/EVALS.md +83 -0
- package/skills/feature-audit/SKILL.md +326 -0
- package/skills/harness/EVALS.md +81 -0
- package/skills/harness/SKILL.md +88 -0
- package/skills/i-have-adhd/EVALS.md +80 -0
- package/skills/i-have-adhd/SKILL.md +183 -0
- package/skills/no-ai-slop/EVALS.md +89 -0
- package/skills/no-ai-slop/SKILL.md +209 -0
- package/skills/no-ai-slop/eval.md +52 -0
- package/skills/plan-add/EVALS.md +79 -0
- package/skills/plan-add/SKILL.md +179 -0
- package/skills/plan-add/render_table.py +72 -0
- package/skills/plan-status/EVALS.md +78 -0
- package/skills/plan-status/SKILL.md +52 -0
- package/skills/plan-sync/EVALS.md +80 -0
- package/skills/plan-sync/SKILL.md +69 -0
- package/skills/pm-frameworks/SKILL.md +33 -0
- package/skills/pm-frameworks/SOURCE +39 -0
- package/skills/pm-frameworks/intended-vs-implemented/SKILL.md +42 -0
- package/skills/pm-frameworks/opportunity-solution-tree/SKILL.md +64 -0
- package/skills/ponytail/EVALS.md +80 -0
- package/skills/ponytail/SKILL.md +124 -0
- package/skills/product-analysis/EVALS.md +103 -0
- package/skills/product-analysis/SKILL.md +361 -0
- package/skills/research/EVALS.md +104 -0
- package/skills/research/SKILL.md +570 -0
- package/skills/rl-env/SKILL.md +53 -0
- package/skills/rl-env/SOURCE +41 -0
- package/skills/rl-env/generate-nemo-gym-env/SKILL.md +169 -0
- package/skills/rl-env/generate-nemo-gym-env/references/architecture.md +114 -0
- package/skills/rl-env/generate-openenv-env/SKILL.md +183 -0
- package/skills/rl-env/generate-openenv-env/references/architecture.md +82 -0
- package/skills/rl-env/generate-ors-env/SKILL.md +209 -0
- package/skills/rl-env/generate-ors-env/references/architecture.md +113 -0
- package/skills/rl-env/generate-verifiers-env/SKILL.md +188 -0
- package/skills/rl-env/generate-verifiers-env/references/architecture.md +119 -0
- package/skills/rl-env/rl-env-from-description/SKILL.md +124 -0
- package/skills/rl-env/rl-env-from-description/references/interview.md +75 -0
- package/skills/rl-env/rl-env-from-description/references/nemo_gym.md +41 -0
- package/skills/rl-env/rl-env-from-description/references/openenv.md +35 -0
- package/skills/rl-env/rl-env-from-description/references/ors.md +50 -0
- package/skills/rl-env/rl-env-from-description/references/verifiers.md +39 -0
- package/skills/tezgah-contract/EVALS.md +78 -0
- package/skills/tezgah-contract/SKILL.md +792 -0
- package/statusline.py +129 -0
- package/workflows/graph-impact.js +153 -0
- package/workflows/graph-map.js +158 -0
- 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:]))
|