@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
package/docs/evidence.md
ADDED
|
@@ -0,0 +1,831 @@
|
|
|
1
|
+
# Evidence
|
|
2
|
+
|
|
3
|
+
This page is the evidence layer: the [ledger](glossary.md#ledger) a session appends to, the kinds it
|
|
4
|
+
holds, the Stop rule that reads them to refuse a turn, and the pre-write snapshots a bad write can be
|
|
5
|
+
undone from. Read it before changing a rule that records or reads evidence, or when undoing a write.
|
|
6
|
+
[gate.md](gate.md) owns the refusal path, [hosts.md](hosts.md) what each host can observe.
|
|
7
|
+
|
|
8
|
+
## The ledger
|
|
9
|
+
|
|
10
|
+
One append-only JSONL file per session at `<cache>/evidence/<slug>.jsonl`; the stem is a readable
|
|
11
|
+
prefix plus a hash of the session id, so a filename can never be turned back into one
|
|
12
|
+
(`hooks/tezgah_integrity.py::_slug`). Every writer goes through `note_path` (`hooks/tezgah_integrity.py::note_path`): `note()`
|
|
13
|
+
derives the path from the session id (`hooks/tezgah_integrity.py::note`). The row is built in exactly one place (`hooks/tezgah_integrity.py::note_path`), and its shape is
|
|
14
|
+
`{"kind": …, "ts": …, "v": …, "detail": …}` plus whatever `LEDGER_FIELDS` keys the writer knew — for a check
|
|
15
|
+
the host reported passing, `{"kind": "verify_ok", "ts": 1758000000, "v": 3, "detail": "pytest -q",
|
|
16
|
+
"id": "a1b2c3d4e5f6", "exit": 0, "out_bytes": 4312, "tool": "Bash", "repo": "/home/u/proj"}`. `v` names the shape the row was written under
|
|
17
|
+
(`ROW_VERSION`, `hooks/tezgah_integrity.py::ROW_VERSION`), and a reader folding a corpus across a version
|
|
18
|
+
change has to know what moved: at 2 the step vocabulary gained `interrupted`, so a version 1 row's
|
|
19
|
+
`verify_fail` may name a check that failed or a call the host stopped; at 3 a `claim` row is written
|
|
20
|
+
only for a reply in the claim vocabulary, so a version 2 `claim` row may be a work-only refusal.
|
|
21
|
+
|
|
22
|
+
`kind` is the event kind, `detail` is free text (the command, a path, a short reason) and `ts` is
|
|
23
|
+
epoch seconds. A **write row's** `detail` is the path the call wrote, from the gate's one reader of
|
|
24
|
+
every host dialect (`write_paths`, `hooks/tezgah_gate.py::write_paths`): `file_path`, `filePath`, `path`,
|
|
25
|
+
`notebook_path`, or an `apply_patch` body's first `*** Update File:` header — the paths
|
|
26
|
+
`changed_files()` (`hooks/tezgah_integrity.py::changed_files`) folds when a reader asks which files a session changed. `detail` is
|
|
27
|
+
credential-redacted **before** it is stored, over the whole text, and
|
|
28
|
+
truncated to `DETAIL_MAX = 200` only afterwards, so a marker the cut halves still reads as a marker
|
|
29
|
+
(`hooks/tezgah_integrity.py::note_path`, `hooks/tezgah_integrity.py::DETAIL_MAX`, `hooks/tezgah_integrity.py::_stored_text`): a named key keeps its name and loses its value - also as a quoted
|
|
30
|
+
JSON key (`"password": "x"`) and as a flag with its value after a space (`--password X`,
|
|
31
|
+
`--api-key X`, `mysql -pPASS`) - an `Authorization` scheme (`Bearer`, `Basic`, `Token`, `Digest`),
|
|
32
|
+
the password of URL userinfo (`scheme://user:pass@`) and of `-u user:pass`, and a prefixed token
|
|
33
|
+
family lose theirs (`hooks/tezgah_integrity.py::REDACTIONS`; audit L-6, which found each of those stored verbatim). The optional fields are exactly `LEDGER_FIELDS`
|
|
34
|
+
(`hooks/tezgah_integrity.py::LEDGER_FIELDS`) — `id`, `exit`, `out_bytes`, `fail_class`, `workspace`, `source`, `hash`, `changed`, `tool`,
|
|
35
|
+
`target`, plus the reply-shape names `lines`, `chars`, `items`, `longest_list`, `tr_share`, `answer_first` and the compaction
|
|
36
|
+
row's `summary_chars`, `summary_hash`, `constraint_found`, `constraint_expected`, the `attest`
|
|
37
|
+
row's `host` and `switches` and a `claim` row's `harness` — and
|
|
38
|
+
a key outside that set is dropped, a `None` value left out, because every reader treats a missing key
|
|
39
|
+
as `None` (`hooks/tezgah_integrity.py::note_path`). `tool` is the call's own name (`Bash`, `Write`, `mcp__codegen__status`),
|
|
40
|
+
written by `note_tool` (`hooks/tezgah_integrity.py::note_tool`) because `classify` folds the name into
|
|
41
|
+
a kind and drops it; it is what `_counts`' tool histogram counts and what the retirement report on
|
|
42
|
+
`tezgah-status --counters --trend` prints. `target` is on every `edit` row, and on a shell `run` row
|
|
43
|
+
whose command writes a file through a redirect or `tee` (`hooks/tezgah_gate.py::write_paths`): the
|
|
44
|
+
written path as an absolute real path, resolved against the call's cwd (`_abs_target`, written by
|
|
45
|
+
`note_tool` and by opencode's plugin through `absTarget`). `detail` keeps the path as the call spelled it, so
|
|
46
|
+
`README.md` in two repositories was one file to the concurrent-write guard; `writers_elsewhere`
|
|
47
|
+
now compares `target`, and a row without one (written before the field landed) is ignored by that
|
|
48
|
+
guard rather than matched by its spelling (audit M-6). Both writers write `tool` — `note_tool`, and opencode's
|
|
49
|
+
plugin, whose row carries the same field under the same empty-means-absent rule
|
|
50
|
+
(`hosts/opencode/plugins/tezgah.js:1230-1241`) — so no live host leaves it out. A row written *before*
|
|
51
|
+
the field landed names its tool only where the name survived in `detail` — an `unknown` row and an
|
|
52
|
+
MCP `external` row — so the one cause of an under-count is the corpus's age, and it shrinks as
|
|
53
|
+
sessions run. The append is one locked line, an exclusive `flock` with a 1 s bound falling
|
|
54
|
+
back to an unlocked write (`hooks/tezgah_integrity.py::_append`), and is best effort: a write failure is never the caller's.
|
|
55
|
+
A ledger is created `0600` in a `0700` directory, because its rows name the paths and commands of
|
|
56
|
+
the user's work (audit L-6 found them `0644`). Every reader skips a line that ends in a newline and
|
|
57
|
+
does not parse, in its own ledger or another's (`_parse` `hooks/tezgah_integrity.py::_parse`). The
|
|
58
|
+
reader used to raise there, and the guard then failed the Stop rule open for the turn, so corrupting
|
|
59
|
+
a `verify_fail` row let a claim through. Now the reader writes one `ledger_damage` row per damaged
|
|
60
|
+
line into that ledger, keyed on a digest of the line (`_note_damage`
|
|
61
|
+
`hooks/tezgah_integrity.py::_note_damage`). The Stop rule refuses a done-claim in a turn that holds one
|
|
62
|
+
as "evidence tampered". A tail with no newline is a fragment, not damage: `_append` cuts it before
|
|
63
|
+
its own write, so an honest writer never leaves one. Any other read error in another session's
|
|
64
|
+
ledger still costs only that ledger's rows (`_foreign_rows`; audit M-7).
|
|
65
|
+
|
|
66
|
+
What never reaches the ledger: tool result bodies (only `out_bytes`, a size,
|
|
67
|
+
`hooks/projects-posttooluse.py::result_size`), the prompt text (the `turn` row keeps `sha1(prompt)[:12]`,
|
|
68
|
+
`hooks/tezgah_integrity.py::note_turn`), read/search calls (`hooks/tezgah_integrity.py::note_tool`), and any credential, already replaced.
|
|
69
|
+
|
|
70
|
+
## The kinds, by what reads them
|
|
71
|
+
|
|
72
|
+
A bare `:N` below is `hooks/tezgah_integrity.py`; `classify` (`hooks/tezgah_integrity.py::classify`) picks the kind for a call —
|
|
73
|
+
a write tool is `edit`, a shell call is `verify` when its command matches the check vocabulary `VERIFY`
|
|
74
|
+
(`hooks/tezgah_integrity.py::VERIFY`) and `run` otherwise.
|
|
75
|
+
|
|
76
|
+
| Kind | Written by | Read by |
|
|
77
|
+
|---|---|---|
|
|
78
|
+
| `turn` | `hooks/tezgah_integrity.py::note_turn`, from the prompt path | `hooks/tezgah_integrity.py::_turn_start`, scoping every turn rule; `hooks/tezgah_integrity.py::_claim_key` |
|
|
79
|
+
| `run`, `edit`, `verify`, `verify_ok`, `verify_fail`, `interrupted` | `hooks/tezgah_integrity.py::note_tool`, the call's own name in `tool`, on opencode the plugin writes these same kinds and the same field (`hosts/opencode/plugins/tezgah.js:1192-1270`) | the Stop rule's `worked` set `hooks/tezgah_integrity.py::WORK_KINDS`; `counters.steps` `hooks/tezgah_integrity.py::_counts`; `last_verify`/`partial_state`; the `--trend` tool histogram |
|
|
80
|
+
| `external`, `unknown` | `hooks/tezgah_integrity.py::note_tool` | the taint notice, via `source`; the `--trend` tool histogram; nothing counts them as work |
|
|
81
|
+
| `began` | the gate's allow path for a write or shell call `hooks/tezgah_gate.py::decision`; on opencode the plugin's before-hook when the core was not asked (`hosts/opencode/plugins/tezgah.js:2516-2532`) | `hooks/tezgah_integrity.py::unanswered`, behind a claim in the Stop rule and in `counters.unanswered` |
|
|
82
|
+
| `claim` | `hooks/tezgah_integrity.py::stop_reason`, only for a reply in the claim vocabulary - a completion or verification word (`DONE`/`VERIFIED`), blocked or allowed, or a refused claim about an external system's state (`_external_claim`) | `hooks/tezgah_integrity.py::counters` |
|
|
83
|
+
| `refusal` | `stop_reason`, for a blocked reply that claimed nothing - a work-only or a shape refusal - with the same `blocked: <class>` detail (row version 3) | `counters.refusals`, and `shape_blocked` for a shape class; never a claim; `NOT_TOOL_HOOK` lists it |
|
|
84
|
+
| `after_block` | `hooks/tezgah_integrity.py::stop_reason`, on the reply after this rule's own block (`stop_hook_active` in a turn holding a `blocked:` claim or refusal row) on Claude, Codex and omp; `detail` is `would block: <class>`, `ok` or `no claim` | nothing yet: a record for the after-block observation window, not a claim and not a second `shape` row, so `counters` counts it neither as a claim nor as a reply; `NOT_TOOL_HOOK` lists it |
|
|
85
|
+
| `subagent_end` | `stop_reason(..., subagent=True)`, from Claude's SubagentStop (`hooks/hooks.json`) and Cursor's subagentStop `summary`; the evidence half only, never a block (ADR 011); `detail` as `after_block`'s | nothing yet: the rows plan 055 replays before a subagent end may block; `NOT_TOOL_HOOK` lists it. On Claude a subagent's tool rows sit in the parent's ledger, so until the agent key (plan 050) lands the row judges the parent's turn |
|
|
86
|
+
| `stop_spec` | `hooks/tezgah_stopspec.py::shadow`, from `stop_reason`, one per reply that leaves a claim or a refusal row, keyed like the claim row. The `detail` is `agree <where>: <class>`, `disagree <where>: <imperative> -> <spec>` (`ok` for an allow) or `error: <type>`. `<where>` is `fold` when the selector reached the fold and `selector` when it decided alone | `tests/stop_spec_eval.py --shadow-rows`, for plan 063's live agreement bar, read on the `fold` rows. It never feeds the verdict. `NOT_TOOL_HOOK` lists it |
|
|
87
|
+
| `deny`, `nudge` | the [gate](gate.md)'s `hooks/tezgah_gate.py::_deny`, first-nudge `hooks/tezgah_gate.py::decision` | `hooks/tezgah_integrity.py::counters` |
|
|
88
|
+
| `snapshot`, `rollback` | `hooks/tezgah_snapshot.py::_capture_one`, `hooks/tezgah_snapshot.py::restore` | `hooks/tezgah_integrity.py::_snapshot_hash`; no counter |
|
|
89
|
+
| `compact` | `hooks/tezgah_integrity.py::note_compaction`, from the post-compaction path (`tezgah_context.remember_compaction` `hooks/tezgah_context.py::remember_compaction`) | `hooks/tezgah_integrity.py::_counts` (what `counters` folds with) |
|
|
90
|
+
| `lesson` | `hooks/tezgah_context.py::note_lesson`, one row per lesson the budget left in a session block or a per-turn block, with its 8-hex `key` and `block` (`session` or `turn`), inside the host's `safe()` like the rest of the prompt path | no counter; `hooks/tezgah_context.py::NOT_TOOL_HOOK` keeps it out of `hooks/tezgah_context.py::_ledger_since`, so a session of lesson rows still reads as a gate that never ran |
|
|
91
|
+
| `lesson_tainted` | the gate's allow path for a write to a `.tezgah/lessons.md` (`hooks/tezgah_gate.py::lesson_taint`, from `decision` after every refusal) in a user turn that already holds a row carrying `source`, folded over `turn_rows` (that subagent's rows when the host names one). One row per lesson line the ledger will hold after the write and does not hold now, read off the post-write text, so a partial-line edit names the whole line; its 8-hex `key`, the channel in `source` and `detail`, the ledger in `target`. One row with no `key` when the gate cannot name the line (an `echo` append, an edit whose old text is not there, a removal). The keyed rows also go to the repository's index, which keeps only the ledger's current lines (`hooks/tezgah_lessons.py::write_taint`). Never a refusal (ADR 010); the dry run writes neither | the per-line data label on that lesson in both lesson blocks (`hooks/tezgah_context.py::LESSON_TAINTED`, read once per prompt through `hooks/tezgah_lessons.py::tainted`); no counter |
|
|
92
|
+
| `lesson_hit` | nothing yet: reserved for plan 061 Phase B, a compiled lesson check that matched a call in its observe stage, with the lesson's `key` and the call's `id` | nothing yet |
|
|
93
|
+
| `ledger_damage` | `hooks/tezgah_integrity.py::_note_damage`, from `_parse`, once per damaged line, with its 12-hex `key` | the Stop rule's first evidence class, "evidence tampered" (`hooks/tezgah_integrity.py::_stop_block`) |
|
|
94
|
+
| `disarm` | `hooks/tezgah_context.py::disarmed`, on the prompt a switch first appears on after the session's first prompt; `detail` is the switch name. Also the gate (`hooks/tezgah_gate.py::decision`), for a call it lets through that changes a `CONTROL_EVIDENCE` target - an open plan's delete or move, a forced `git add` of a `.tezgah/` path - with the call's `id` and `detail` `control: <what>` | the status line's `gate` mark ([status-line.md](status-line.md)) for the switch rows, set by the same check that writes them; the gate's rows are read by a person or a replay; no counter |
|
|
95
|
+
| `attest` | `hooks/tezgah_attest.py::run`, once per session start: Claude and dsh (`hooks/projects-auto-init.py::main`), Codex, Cursor and omp from their session-start events, opencode at the first message through `oncePerSession` (`bin/tezgah-context::main`). `detail` is `ok`, `drifted: <entries>` (an entry added, removed or changed since install, a hook file any user can write, a stale omp bridge, a changed entry script on a release install) or `unverified: <why>`; `host` names the host, `switches` the kill switches present. The module is imported only inside that call, so a broken one costs the row and never a gate | the `drift` status mark and the `harness` field of the session's later `claim` rows, read from one mark file per session and host (`hooks/tezgah_attest.py::drift_mark`, so one host's clean start cannot clear another's) - an annotation, never a Stop block; `NOT_TOOL_HOOK` lists it, so a session start after a compaction does not read as a gate that ran |
|
|
96
|
+
| `crash` | `hooks/tezgah_guard.py::safe` for a core call that raised, and `hooks/tezgah_guard.py::import_failed` for an entry point whose core imports raised (`detail` `import: <class>: <message>`). An import failure also writes one stderr line and the status line's `crash` mark, always; when `tezgah_integrity` or `tezgah_paths` is the module that failed, the row is the part that cannot be written. Hooks fail open with exit 0; `tezgah-gate check` exits 3 | `NOT_TOOL_HOOK` lists it; no counter |
|
|
97
|
+
|
|
98
|
+
**`compact` is what a compaction kept, from the record.** When the host hands the PostCompact
|
|
99
|
+
payload the text the model is about to receive — Claude's `compact_summary` — the shared path
|
|
100
|
+
(`hooks/tezgah_context.py::context_for`, reached by Claude's hook, codex/hook.py, omp's hook and dsh's
|
|
101
|
+
bridge alike, because it is the same funnel each prompt goes through) writes one row: the summary's
|
|
102
|
+
length (`summary_chars`), a 12-hex sha256 of it (`summary_hash`, so two compactions of one session can
|
|
103
|
+
be told apart and the same summary can be recognised twice), the host's own word for why it compacted
|
|
104
|
+
(`trigger`: `manual` or `auto`) on `detail`, and the constraint report. The summary's **text is never
|
|
105
|
+
stored** — it is the whole conversation by proxy and the ledger is a redacted channel — so a row can
|
|
106
|
+
never be read back as prose. The constraint report is `constraint_found` of `constraint_expected`: how
|
|
107
|
+
many of the constraint lines tezgah injects the summary still carries, counted against the very text the
|
|
108
|
+
block renders (`constraint_lines`, `hooks/tezgah_context.py::constraint_lines`, over `POINTER_LINE`
|
|
109
|
+
`hooks/tezgah_context.py::POINTER_LINE`, the active plan's front matter, and the object of each constraint the
|
|
110
|
+
user issued this session, kept in the turn stamp as its matched clause and never the prompt -
|
|
111
|
+
`hooks/tezgah_context.py::user_constraints`). It is a **report and never a refusal**: a compaction
|
|
112
|
+
that dropped a rule is a finding to report, not a turn to block. A host that hands no summary writes no
|
|
113
|
+
row, and `tezgah-status --counters` folds the rows into `compactions`, `compact_chars` (the newest
|
|
114
|
+
summary's length) and `compact_constraint_rate` — which stays `None` until one row carries both counts,
|
|
115
|
+
because a `0.0` would claim every compaction dropped every rule.
|
|
116
|
+
|
|
117
|
+
**`interrupted` is the step with no verdict.** The host said the call was *stopped* — a user's cancel,
|
|
118
|
+
or a call a policy denied before it ran — rather than reporting anything the tool answered, so the row
|
|
119
|
+
carries no `exit` and no `fail_class` (`note_tool()`, `hooks/tezgah_integrity.py::note_tool`, the fields
|
|
120
|
+
`hooks/tezgah_integrity.py::note_tool`). It counts as a step, because the model did issue the call and the turn's work has to
|
|
121
|
+
show; it is not a failed check, so `_partial_state`, `last_verify`, the error rate and `prior_calls`'
|
|
122
|
+
attempts (`hooks/tezgah_integrity.py::prior_calls`) all read it as a stopped call rather than a rejection.
|
|
123
|
+
|
|
124
|
+
**`began` opens a call.** The gate writes it for a write or shell call, with the call's `id`, before
|
|
125
|
+
any of its rules runs. A host that kills a slow gate still finds it there. The PostToolUse row of the same call carries
|
|
126
|
+
the same `id` and answers it. A `deny` with that `id` answers it too. That is the gate's own refusal,
|
|
127
|
+
or opencode's: it asks the core first and may still refuse the call with a rule of its own.
|
|
128
|
+
The replay sheet drops a `began` that a refusal answers (`refused-began`). A `began` row nothing answered is a call whose result
|
|
129
|
+
never reached the ledger. The host abandoned it, the user refused its prompt, or the post hook died. So
|
|
130
|
+
its outcome is unknown in both directions. It is never a pass, a success or a failure. It is not work
|
|
131
|
+
either. The gate writes it before the host's own permission layer, so a command the user refused
|
|
132
|
+
leaves one too. Such a turn did nothing, and its bookkeeping exemption stands. The row counts in one
|
|
133
|
+
place only: a reply that claims done or tested while a waiting call is a check. The gate marks that
|
|
134
|
+
on the row as `check`, read from the whole command, because the stored detail is cut at 200 characters.
|
|
135
|
+
That claim rests on a result nobody saw, so the Stop rule asks for a passing check (`no verify_ok`).
|
|
136
|
+
One answer closes one `began`, oldest first (`_began_fold`). A waiting call counts only
|
|
137
|
+
for a tool the host answered once in the session (`unanswered`). Some hosts gate a tool they never
|
|
138
|
+
report back: omp gates `powershell` and does not watch it. The cost is one miss: the session's first
|
|
139
|
+
call of a tool goes uncounted if the host abandons it. A ledger written before the row existed has
|
|
140
|
+
none, so it counts zero. The idea is gortex's: it abandons a call that overran, and the call's side
|
|
141
|
+
effect stays unknown until someone re-reads it.
|
|
142
|
+
|
|
143
|
+
**A pass with no `began` row is an orphan.** Every ledger reader pairs each `verify_ok` with a
|
|
144
|
+
`began` row (`hooks/tezgah_integrity.py::_pair`). That row shares the pass's `id` and carries `check`.
|
|
145
|
+
`events_path` and `turn_rows` call it. A pass with none came from outside the hooks (`python3 -c`),
|
|
146
|
+
or its call's rows went missing. The reader marks it in memory and never writes the mark.
|
|
147
|
+
`passing_check` refuses a marked row. So the freshness fold, the UI and design halves,
|
|
148
|
+
`scratch_evidence` and `tezgah-route --report` all read it as a check nobody saw pass. The Stop rule
|
|
149
|
+
refuses a done-claim in its turn as "evidence tampered", and `counters.orphans` counts it. A false
|
|
150
|
+
block refuses an honest turn, so the reader marks nothing in five cases. These are a ledger with no
|
|
151
|
+
`began` row before the pass, a turn with a `crash` row, and `pretooluse-off`. The others are an
|
|
152
|
+
append that took the unlocked fallback (its row carries `unlocked`) and the sandbox fallback cache.
|
|
153
|
+
A row with no outcome, such as Cursor's afterShellExecution `verify`, does not take a pass's `began`.
|
|
154
|
+
`turn_rows` seeds the waiting `began` rows from the 200 rows before the turn. So a call that straddles a
|
|
155
|
+
prompt pairs there as it does in `events`. A forged `began` row plus its pass stays invisible:
|
|
156
|
+
`SECURITY.md` names it.
|
|
157
|
+
|
|
158
|
+
**A shell call's `id` folds ASCII whitespace only.** Both `call_id` and `actionID` fold such runs
|
|
159
|
+
into one space (`hooks/tezgah_integrity.py::ID_SPACE`).
|
|
160
|
+
Python's `split()` and JS's `\s` disagreed on U+0085, U+001C-001F and U+FEFF, so a `began` row and its
|
|
161
|
+
outcome hashed apart. U+00A0 is no longer whitespace to either side. A command holding it hashes
|
|
162
|
+
differently from rows written before this change, which only matters to the repeat guards' history.
|
|
163
|
+
|
|
164
|
+
**The verify kinds are a tri-state, and an unread outcome is never a pass.** `note_tool`
|
|
165
|
+
(`hooks/tezgah_integrity.py::note_tool`) records `verify` when the host reported no outcome at all (`failed is None`) or when
|
|
166
|
+
the command is piped — a pipe's status belongs to its last stage, so `pytest | tail` proves nothing
|
|
167
|
+
about pytest — and only otherwise splits it into `verify_ok`/`verify_fail`. A line that opens with
|
|
168
|
+
`set -o pipefail` (or `set -euo pipefail`) and carries no `||` is not piped for this purpose: the
|
|
169
|
+
pipe's status is then its first failing stage's, so the host's verdict is the check's
|
|
170
|
+
(`hooks/tezgah_integrity.py::pipe_hides_status`). A check followed by `;` or a newline and more
|
|
171
|
+
commands records as `verify` too, and so does one sent to the background with `&`. `pytest; echo
|
|
172
|
+
done` exits 0 whatever pytest found. `pytest && echo ok` and `cd x && pytest` keep its status
|
|
173
|
+
(`hooks/tezgah_integrity.py::status_hidden`). The opencode plugin reads the same shapes (`statusHidden`). `passing_check`
|
|
174
|
+
(`hooks/tezgah_integrity.py::passing_check`) is stricter: a `verify_ok` counts only with `exit == 0`, a non-zero `out_bytes` (exit
|
|
175
|
+
0 with an empty result is the classic silent failure) and no pipe or later command owning the status. The gate refuses the
|
|
176
|
+
trimmed form before it runs ([gate.md](gate.md), the `piped` rule). The `out_bytes` half
|
|
177
|
+
bites only where the host reported a result size — Codex (`hosts/codex/hook.py::main`), Cursor
|
|
178
|
+
(`hosts/cursor/hook.py::remember_answer,275`) and omp, whose bridge measures it and sends `result_len`
|
|
179
|
+
(`hosts/omp/tezgah-hook.ts.in:670-676`), now do — and 6 of 1423 `verify_ok` rows across 1454 local ledgers carry the field
|
|
180
|
+
(measured 2026-09-19), so an absent field still passes: the guard narrows a check whose
|
|
181
|
+
result was measured empty, it does not require the measurement. `last_verify`
|
|
182
|
+
(`hooks/tezgah_integrity.py::last_verify`) folds the ordered rows to `ok`/`fail`/`ran`/`None`, because a set cannot tell a failure
|
|
183
|
+
that came after a success from one that came before it.
|
|
184
|
+
|
|
185
|
+
**A check-shaped command is a check only when it checks something.** `_check_runs` reads each
|
|
186
|
+
`VERIFY` match. It reads the words after the match, up to the end of that one command. An information
|
|
187
|
+
form checks nothing: `--version`, `--help`, `--list`, `--collect-only`, `make help`, `just help`
|
|
188
|
+
and a bare `ruff`. It records as `run`. A formatter in its write mode records as `run` too:
|
|
189
|
+
`ruff format` without `--check`/`--diff`, `ruff check --fix`, `prettier --write` and `eslint --fix`.
|
|
190
|
+
The freshness fold reads that row as a change (`_change_row`), with no captured target.
|
|
191
|
+
`pytest --version; pytest -q` still runs a check. Every reader of `verify_command` follows. That
|
|
192
|
+
covers the evidence kind, the gate's retry exemption, its `began` `check` mark, `piped_check` and
|
|
193
|
+
the neuter rule. Opencode's `verifyCommand` carries the same three tables.
|
|
194
|
+
|
|
195
|
+
A check can say in its own output that it ran nothing (`EMPTY_RUN`): `collected 0 items`, `no
|
|
196
|
+
tests ran`, `Ran 0 tests` or `No tests found` at a line start. The reader scans the result's last
|
|
197
|
+
4096 characters. Such a row records as `verify` with `empty_run`, never as a pass. One result
|
|
198
|
+
covers the whole call, so `pytest a && pytest b` with one empty suite marks the whole row empty.
|
|
199
|
+
That is a ceiling: the reader does not split the output per check. Claude, Codex
|
|
200
|
+
and Cursor read the result they already hold. The omp bridge keeps its own copy of the literal
|
|
201
|
+
and sends only the flag, never the body. `tests/test_omp_extension.py` pins the two copies equal.
|
|
202
|
+
A check row also carries `repo`, the git toplevel it ran in, read with no git fork. Only an
|
|
203
|
+
explicit location sets it. That is the tool's own `cwd` or `workdir`, or a leading `cd X`, also
|
|
204
|
+
after a paren or assignments. Path arguments that all sit in one repository count too. The
|
|
205
|
+
session cwd alone does not, because a shell may keep an earlier call's `cd`. An unreadable
|
|
206
|
+
`cd "$WT"` gives no `repo` either.
|
|
207
|
+
A row without one binds as before, so an unknown location never refuses. The Stop rule reads it
|
|
208
|
+
below.
|
|
209
|
+
|
|
210
|
+
**`edit` carries the write's after-state.** The gate's capture records the pre-write hash;
|
|
211
|
+
`_post_write` (`hooks/tezgah_integrity.py::_post_write`) adds `hash` (the target's sha256 once the host returned) and `changed`
|
|
212
|
+
(whether the two differ), so a call the host reports as a successful write need not have changed
|
|
213
|
+
anything. `changed_files` (`hooks/tezgah_integrity.py::changed_files`) reads exactly those rows.
|
|
214
|
+
|
|
215
|
+
**`claim` is the false-completion record.** `stop_reason` (`hooks/tezgah_integrity.py::stop_reason`) writes one row per reply per
|
|
216
|
+
turn that is in the claim vocabulary, deduplicated by `_claim_key` (`hooks/tezgah_integrity.py::_claim_key`), with detail `blocked: <class>` or `ok`: a refusal
|
|
217
|
+
and an allowed claim are both recorded, because the rate needs both halves. A blocked reply that
|
|
218
|
+
claimed nothing writes a `refusal` row instead. A `blocked: no verify_ok` row of either kind
|
|
219
|
+
carries `cause`. It reads `no check` when none ran and `outcome unread` when one ran without a
|
|
220
|
+
visible pass. **`external` and
|
|
221
|
+
`unknown` claim no step of work.** `external` (`hooks/tezgah_integrity.py::note_tool`) is a result with no work of its own — an
|
|
222
|
+
MCP answer, a fetched page — recorded so its provenance is on the ledger at all; an MCP row's
|
|
223
|
+
`detail` is that channel followed by the tool's own name, because the UI rule has to be able to tell
|
|
224
|
+
a screen read from a file read and the taint notice reads the channel from `source` either way.
|
|
225
|
+
`unknown` (`hooks/tezgah_integrity.py::note_tool`) is a tool name no list knows, its name in the `detail`. The step counter,
|
|
226
|
+
the Stop rule and the loop ceilings ignore both.
|
|
227
|
+
|
|
228
|
+
## What a source has to record before its numbers count
|
|
229
|
+
|
|
230
|
+
A row is not evidence by itself: what a reader can do with it depends on how much
|
|
231
|
+
the thing that produced it recorded. The RL-environment tooling this repository
|
|
232
|
+
has read makes the same distinction at the model wire - a server that will not
|
|
233
|
+
return token ids can still serve rollouts, but they are marked *evaluation only*,
|
|
234
|
+
and asking one of them for training data raises instead of quietly returning a
|
|
235
|
+
weaker sample (FineEnvs multi-harness RL, its OpenEnv chapter, "What gets
|
|
236
|
+
recorded").
|
|
237
|
+
|
|
238
|
+
tezgah's version of that rule is already enforced in the research layer and is
|
|
239
|
+
stated here for the first time. A [claim](research.md) carries a `kind` and a
|
|
240
|
+
`proof` that names an artifact a reader can open, and the one case the claim
|
|
241
|
+
checker leaves out is a proof that names no artifact at all
|
|
242
|
+
(`hooks/tezgah_research.py::derive_kind`) - it is reported rather than labelled, because a
|
|
243
|
+
guessed kind would only move the refusal one step later. A source that cannot
|
|
244
|
+
meet the rule does not become a weaker claim: it is labelled for what it is, and
|
|
245
|
+
the work that produced it is the work that has to be redone.
|
|
246
|
+
|
|
247
|
+
## The Stop rule, end to end
|
|
248
|
+
|
|
249
|
+
The checker is `_stop_block` (`hooks/tezgah_integrity.py::_stop_block`), reached through `stop_reason`
|
|
250
|
+
(`hooks/tezgah_integrity.py::stop_reason`). Four hosts block on it — Claude (`hooks/projects-stop.py::main`), Codex
|
|
251
|
+
(`hosts/codex/hook.py::main`), Cursor (`hosts/cursor/hook.py::dispatch`), omp
|
|
252
|
+
(`hosts/omp/hook.py::handle`) — all with `{"decision": "block", "reason": …}`, all inert outside a
|
|
253
|
+
[root](glossary.md#root) and under the `verify-off` [kill switch](glossary.md#kill-switch)
|
|
254
|
+
(`hooks/projects-stop.py::main`). On Claude, Codex and omp the rule judges the reply after a block
|
|
255
|
+
(`stop_hook_active`) once more, in record-only mode. That reply writes one `after_block` row and
|
|
256
|
+
never meets a second refusal. It writes nothing when the turn holds no refusal of this rule, since
|
|
257
|
+
another Stop hook may have blocked. Cursor still skips it. Ten triggers, in order, each naming its reason class (`_stop_block`
|
|
258
|
+
`hooks/tezgah_integrity.py::_stop_block`).
|
|
259
|
+
The first four judge how the reply is written (`_shape_block`, `hooks/tezgah_integrity.py::_shape_block`); the rest judge its evidence:
|
|
260
|
+
|
|
261
|
+
1. **placating opener** — the reply opens by agreeing or apologising (`hooks/tezgah_integrity.py::SYCOPHANT`).
|
|
262
|
+
2. **forbidden closer** — the reply's last prose line is one of the sign-offs the output contract bans (`CLOSER`, `hooks/tezgah_integrity.py`): the same rule read at the other end, with its own class so the ledger says which end fired.
|
|
263
|
+
3. **list cap** — a contiguous list runs past `LIST_CAP` = 5 items (rule 8 of the `i-have-adhd` skill). `longest_list` (`hooks/tezgah_integrity.py::longest_list`) counts per run of column-0 items of one kind: a heading, a prose line, a table row, a fence, a marker switch or a numbered list restarting at 1 ends the run, and blank or indented continuation lines keep it. Two headed groups of four pass; a 5+ enumeration that must stay whole goes under headings or into a table, which the block text says.
|
|
264
|
+
4. **reply language** — the reply's prose is not Turkish: at least `LANG_MIN_WORDS` = 25 prose words and under `LANG_MIN_SHARE` = 6% of them Turkish. `prose_words` drops fences, table rows, inline code, URLs, paths and identifiers first; `turkish_share` counts a word with a Turkish letter or one of `TR_WORDS` (`hooks/tezgah_integrity.py::TR_WORDS`).
|
|
265
|
+
|
|
266
|
+
The four shape classes share their switches with the text they enforce: `adhd-off` or a repo's `.no-adhd` lifts 1–3 (`_adhd_armed`, `hooks/tezgah_integrity.py::_adhd_armed`), `exec-mode.off` lifts 4, and a session whose environment carries `TEZGAH_NESTED` (an agent CLI consult started, whose English answer is read by code) is not judged for shape at all. A subagent's reply is never refused: omp's `session_stop` does not fire for task sessions, and a Claude SubagentStop or Cursor subagentStop leaves a record-only `subagent_end` row judged on the evidence half alone (ADR 011). The thresholds were set on the owner's omp transcripts (2026-09-27: 1,495 assistant replies with at least 25 prose words): English prose scored 0.000–0.026, the most English-heavy Turkish reply 0.077 and the bulk 0.3–0.7, and 24 of the 1,495 fall under the cut, all English or Chinese prose. The trade-off is on the Turkish side: a Turkish reply that is mostly quoted English outside backticks can fall under 6%, and the block text tells the model to put the English in backticks or a fence. `tests/test_integrity.py` `ReplyShapeCorpus` pins which realistic replies pass and which block. A lead that announces what follows (`preamble-open`) stays report-only: "Sonuç:" over a list is an answer label and reads like a preamble to any regex.
|
|
267
|
+
|
|
268
|
+
5. **check failed** — the newest check in the session failed (`hooks/tezgah_integrity.py::_evidence_block`).
|
|
269
|
+
6. **partial failure** — this turn recorded a `verify_fail` and nothing passed since (`hooks/tezgah_integrity.py::_partial_state`).
|
|
270
|
+
7. **no ui_ok** — this turn changed a UI source (`hooks/tezgah_integrity.py::UI_PATH`) and the
|
|
271
|
+
check that passed was not one that sees the screen: a unit run never does. A browser/e2e/visual
|
|
272
|
+
check (`hooks/tezgah_integrity.py::UI_CHECK`) or a read of the rendered screen (`UI_TOOL`
|
|
273
|
+
`hooks/tezgah_integrity.py::UI_TOOL` for the app-analysis tool names, `hooks/tezgah_integrity.py::UI_TOOL_CMD` for the
|
|
274
|
+
CLI capture) is the evidence this class asks for, and it has to be newer than
|
|
275
|
+
the UI write it is about - not than the newest write of anything, so an unrelated file written
|
|
276
|
+
after the screen read does not stale that read (`hooks/tezgah_integrity.py::_ui_evidence`,
|
|
277
|
+
branch `hooks/tezgah_integrity.py::_evidence_block`). The write kinds are the freshness fold's own (`_change_row`: a write tool's
|
|
278
|
+
`edit` row or a shell call's `run` row the gate saw change the tree), so a UI source written
|
|
279
|
+
through a redirect owes the same proof. The MCP half of that proof is read off the row's own
|
|
280
|
+
tool name (`hooks/tezgah_integrity.py::_screen_read`), which is the only field that
|
|
281
|
+
says which call a row was - so a row that merely names a browser tool in its command
|
|
282
|
+
(`rg -n browser_snapshot docs/`) is not a read of anything; the CLI capture and the two checks
|
|
283
|
+
are read at a command position on the masked text, `re.M` so that a command on its own later
|
|
284
|
+
line of the same call counts. A component turn owes one thing more: when a changed UI source is
|
|
285
|
+
a component rather than a screen (`hooks/tezgah_integrity.py::DESIGN_COMPONENT` - a file
|
|
286
|
+
under a component/views/widgets
|
|
287
|
+
directory, or a name that carries the convention on its own), a fresh read of the screen is not
|
|
288
|
+
enough by itself and a `tezgah-design check` row has to be newer than the component write it
|
|
289
|
+
judges (`hooks/tezgah_integrity.py::_design_evidence`, branch `hooks/tezgah_integrity.py::_evidence_block`) - and it has
|
|
290
|
+
to be a check whose pass was seen (`passing_check`, `hooks/tezgah_integrity.py::passing_check`), because
|
|
291
|
+
a screenshot says what a component looks like and the contract is the only thing that says whether
|
|
292
|
+
it is on the repository's floor. The refusal names the command to run. Both of the checker's verbs
|
|
293
|
+
are in `VERIFY` (`hooks/tezgah_integrity.py::VERIFY`), so such a run reaches the ledger as a check like
|
|
294
|
+
any other; the verb this branch asks for is `check` - `derive` writes the floor, it does not apply
|
|
295
|
+
it. A screen is unchanged: the page a person looks at owes the read, not the contract.
|
|
296
|
+
8. **stale evidence** — the newest check that passed ran before the newest write the gate saw change
|
|
297
|
+
the tree, so it verified an earlier revision of it (`_last_pass`/`_last_change`/`_stale_paths`
|
|
298
|
+
`hooks/tezgah_integrity.py::_last_pass`, `hooks/tezgah_integrity.py::_last_change`, `hooks/tezgah_integrity.py::_stale_paths`, branch `hooks/tezgah_integrity.py::_evidence_block`). A write counts as a change whether the gate saw it as a
|
|
299
|
+
write tool or as a shell command that redirected into the file - `_change_row` (`hooks/tezgah_integrity.py::_change_row`) reads
|
|
300
|
+
an `edit` row, a `run` row whose captured target moved, or a formatter's write mode - while a `verify*` row never does, so
|
|
301
|
+
a check redirecting its own log cannot stale itself. A write *outside* the workspace is not one
|
|
302
|
+
either: the fold's subject is the tree this reply is about, so `_post_write` records no
|
|
303
|
+
after-state for a target beyond the call's own root - a commit message in `/tmp` written after a
|
|
304
|
+
green suite is not a revision of that tree, and reading it as one refused an honest turn.
|
|
305
|
+
The fold dates a pass from the moment its check STARTED: its gate-written `began` row, paired
|
|
306
|
+
by `id`. A write that landed while the check ran is therefore newer than the tree it read. A
|
|
307
|
+
pass also counts only in the newest change's own repository. The fold compares the check row's
|
|
308
|
+
`repo` with the toplevel of the `edit` row's `target`. So `cd ../other && pytest` licenses no
|
|
309
|
+
change here. A row with no `repo` binds to nothing. That covers an old row and a host that sent
|
|
310
|
+
no cwd. A change with no `target`, such as a shell write, binds to nothing too.
|
|
311
|
+
9. **no verify_ok** — this turn recorded a step (`edit`, `verify`, `verify_fail`, `run`,
|
|
312
|
+
`interrupted`) and no check passed in the session (`hooks/tezgah_integrity.py::_evidence_block`). A turn with no step at all
|
|
313
|
+
has only its words as the trigger. There a claim word inside a question or under a negation in
|
|
314
|
+
its own clause is no claim (`asserted_claims`). Examples: "testler geçti mi?", "is it done?",
|
|
315
|
+
"not tested yet", "tamamlandı değil". "Tamamlandı, push edeyim mi?" still claims.
|
|
316
|
+
10. **no external read** — the reply states the state of a system tezgah does not own — a registry,
|
|
317
|
+
a release, a tag, a formula, a CI run — and no read of that system ran in the same turn
|
|
318
|
+
(`hooks/tezgah_integrity.py::_external_claim`, over `EXTERNAL_SYSTEM`/`EXTERNAL_STATE`
|
|
319
|
+
`hooks/tezgah_integrity.py::EXTERNAL_SYSTEM`, `hooks/tezgah_integrity.py::EXTERNAL_STATE` and the CI pair `EXTERNAL_CI`/`EXTERNAL_CI_STATE` `hooks/tezgah_integrity.py::EXTERNAL_CI`, `hooks/tezgah_integrity.py::EXTERNAL_CI_STATE`; branch `hooks/tezgah_integrity.py::_evidence_block`).
|
|
320
|
+
The two halves have to sit within `EXTERNAL_GAP` = 45 characters of each other on one line
|
|
321
|
+
(`hooks/tezgah_integrity.py::_external_pair`), and both are read on the reply's prose with inline code, paths,
|
|
322
|
+
URLs and identifiers blanked: `brew tap` inside a code span, the `.github/workflows/...` in a
|
|
323
|
+
citation and a URL ending in `/releases/tag/...` are text about a system, not a claim about its
|
|
324
|
+
state. A tagged release number beside a publish state is the second form (`EXTERNAL_VERSION`
|
|
325
|
+
`hooks/tezgah_integrity.py::EXTERNAL_VERSION`), and its `v` is required, so `SC 2.5.8` and `4.1.3` in prose are not claims and
|
|
326
|
+
neither is a bare version of tezgah's own code. The refusal names the command, chosen by the
|
|
327
|
+
subject the reply used (`hooks/tezgah_integrity.py::_external_command`, `hooks/tezgah_integrity.py::EXTERNAL_SOURCE`). A local
|
|
328
|
+
client is not the system: `npm --version` is not `npm view`, and a green unit run says nothing
|
|
329
|
+
about what a registry publishes. The read is the evidence, and it is taken by the row's command
|
|
330
|
+
and not by `passing_check` — `npm view` exiting non-zero is the answer for "this version is
|
|
331
|
+
missing" (`hooks/tezgah_integrity.py::_external_read_row`) — so a turn whose only work was the read ends. It is
|
|
332
|
+
last of the ten by the branch order above and in its strongest form: it is asked only where the
|
|
333
|
+
fold would otherwise let the turn end, so it turns an allow into a refusal and never changes the
|
|
334
|
+
class another branch refused the same turn under. It is the one class a turn with no work in it
|
|
335
|
+
can make, which is why the "no work, no claim word" exit exempts it (`hooks/tezgah_integrity.py::_stop_block`) — the two turns it
|
|
336
|
+
was written for ("npm 0.22.0 is missing", read off an out-of-date local npm client, and "make
|
|
337
|
+
NPM_TOKEN an automation token", which it already was) were advice-only, so before this class the
|
|
338
|
+
fold returned `(None, None)` over both and neither was judged at all. Measured over this machine's
|
|
339
|
+
own 2,092 final assistant replies, 2 are read as claims, both in review text about someone else's
|
|
340
|
+
tooling.
|
|
341
|
+
|
|
342
|
+
Classes 5–10 also exist as a past-time temporal spec (`hooks/tezgah_stopspec.py::FORMULAS`,
|
|
343
|
+
plan 063). Seven formulas read ten row atoms (`ROW_ATOMS`) and the turn marker. The module compiles
|
|
344
|
+
each formula to a one-pass monitor over the rows (`hooks/tezgah_stopspec.py::compile_table`), and the
|
|
345
|
+
order above is its decision list (`ORDER`). The spec runs in shadow. `stop_reason` asks it after the imperative
|
|
346
|
+
fold, inside its own `try`, when the reply leaves a claim or a refusal row. It writes one `stop_spec` row
|
|
347
|
+
per reply. The row says `agree`, `disagree` or `error`. It also says `fold` when the selector reached
|
|
348
|
+
the fold and `selector` when it decided alone. The verdict stays the imperative one. Both folds share one selector,
|
|
349
|
+
`_stop_block`, through its `fold` argument. It picks the rows, runs the lost-began path and
|
|
350
|
+
refuses "evidence tampered". `ESCAPES` names the three predicates that read beyond one row: the
|
|
351
|
+
began-row join, the repository binding and the lost-began set. Plan 063 fixed that list before
|
|
352
|
+
the first shadow row. `TEZGAH_STOPSPEC_STRICT=1` makes a disagreement raise, for the tests.
|
|
353
|
+
`tests/stop_spec_eval.py` measures the bet: agreement on plan 055's replayed Stop events and on
|
|
354
|
+
the live rows, the added latency, and generated mutants of the table.
|
|
355
|
+
|
|
356
|
+
The trigger for 5–9 is the turn's own evidence, not its words: a turn that did work and never saw a
|
|
357
|
+
check pass is refused whatever the reply says (`hooks/tezgah_integrity.py::_stop_block`). Two cases are judged against the
|
|
358
|
+
whole session instead of the turn:
|
|
359
|
+
|
|
360
|
+
- **A claim in a turn with no work.** A done/tested claim made in a turn that recorded no work row
|
|
361
|
+
is judged by the same fold as a turn (`_evidence_block`), run over the session rows before
|
|
362
|
+
this turn (`_before_turn`): every class the turn fold has - `check failed`, `no verify_ok`,
|
|
363
|
+
`stale evidence`, a pending UI or design check, a partial failure - applies to the session too.
|
|
364
|
+
A session that did no work at all still ends, and a turn that ran its own passing check is
|
|
365
|
+
judged by the turn fold alone. Before this, the claim could be moved to the turn
|
|
366
|
+
after the work, where the turn fold saw nothing to judge (audit M-2, INT-01).
|
|
367
|
+
- **A bookkeeping turn after a pass.** A turn whose only rows are read-only or VCS-bookkeeping
|
|
368
|
+
commands ends without a fresh check, as long as nothing but bookkeeping ran after the session's
|
|
369
|
+
newest pass, the session fold above allows it, and the reply makes no external-state claim
|
|
370
|
+
(`_settled`). The command is read raw, with bash quoting (`_shell_effect`): a substitution
|
|
371
|
+
inside double quotes, a redirect outside quotes and a process substitution disqualify it, and a
|
|
372
|
+
command the ledger cut at `DETAIL_MAX` characters is never bookkeeping (review F1, F2). A heredoc
|
|
373
|
+
is recognised only at an unquoted, uncommented `<<` that is not `<<<` (`_heredocs`), the one reader
|
|
374
|
+
every gate check uses, so a quoted `<<'X'` cannot hide the lines after it. Read-only is a program in
|
|
375
|
+
`READ_ONLY_PROGRAMS` (`ls`, `cat`, `grep`, `wc`, ...) or a git subcommand in `GIT_BOOKKEEPING`
|
|
376
|
+
(`status`, `log`, `diff`, `add`, `commit`, `push`, ...); a redirect, `$(` or a backtick
|
|
377
|
+
disqualifies the command. An edit, a failed check or any other command after the pass keeps the
|
|
378
|
+
turn rule. Without this, a commit-only turn was refused and the model re-ran checks that had
|
|
379
|
+
already passed (audit M-12, CHAT-04). The lists are short on purpose: a missing program costs one
|
|
380
|
+
refusal, while a writing program wrongly listed would excuse an unverified change.
|
|
381
|
+
|
|
382
|
+
What lets the turn end is the absence
|
|
383
|
+
of both — no work row and no claim vocabulary (`hooks/tezgah_integrity.py::_stop_block`), the one shape class 10 is exempt from
|
|
384
|
+
— or a `passing_check` row newer than the newest write seen to change the tree (`hooks/tezgah_integrity.py::_evidence_block`), where
|
|
385
|
+
a fresh screen proof stands in the same
|
|
386
|
+
place as a unit pass; when that write was a UI source, the passing row has to be a UI proof — a
|
|
387
|
+
check that renders, or a read of the screen — and when it was a component, the design check has to be
|
|
388
|
+
newer than that write as well. An explicit admission (`doğrulanmadı`,
|
|
389
|
+
`unverified`, `not verified`, `couldn't verify`; `hooks/tezgah_integrity.py::NEGATED`) clears the rule (`hooks/tezgah_integrity.py::_stop_block`),
|
|
390
|
+
checked after the shape branches and before the evidence triggers. The block text is the string the
|
|
391
|
+
refusing branch returns; it names the failed
|
|
392
|
+
command (`hooks/tezgah_integrity.py::_failed_check`) and tells the model to report the failure with its exact error
|
|
393
|
+
line, or fix it and re-run.
|
|
394
|
+
|
|
395
|
+
**The escape hatches, and the deny that answers each.** The gate refuses these before they run, under
|
|
396
|
+
the same `verify-off` switch (`hooks/tezgah_gate.py::decision`), as rule `shortcut`:
|
|
397
|
+
|
|
398
|
+
- `--no-verify` on a git/commit/push-style command (`hooks/tezgah_integrity.py::NO_VERIFY`, `hooks/tezgah_integrity.py::GITISH`) —
|
|
399
|
+
`hooks/tezgah_integrity.py::shortcut_command`.
|
|
400
|
+
- an env that skips the hooks — `SKIP=`, `HUSKY_SKIP_HOOKS=`, `HUSKY=0` — again requiring the git/hook
|
|
401
|
+
context, so a read that merely mentions `SKIP=` passes (`hooks/tezgah_integrity.py::SKIP_ENV`, `hooks/tezgah_integrity.py::_shortcut_command`).
|
|
402
|
+
- a `core.hooksPath` assignment in the same command as a `git commit`/`git push` — `git -c
|
|
403
|
+
core.hooksPath=/dev/null commit`, `git config core.hooksPath "$D" && git commit`, `--config-env`, the
|
|
404
|
+
`GIT_CONFIG_KEY_n`/`GIT_CONFIG_PARAMETERS` env (`hooks/tezgah_integrity.py::_hooks_redirect`);
|
|
405
|
+
a standalone `git config core.hooksPath .githooks` passes. Set in one call and committed in the next
|
|
406
|
+
is not seen: the rule reads one command line.
|
|
407
|
+
- a check chained so it cannot fail: `|| true`, `; true`, `|| exit 0`, `|| :` (`hooks/tezgah_integrity.py::NEUTER`,
|
|
408
|
+
`hooks/tezgah_integrity.py::_shortcut_command`).
|
|
409
|
+
- a newly added test skip/xfail in a test file (`hooks/tezgah_integrity.py::SKIP_TEST`, path gate `hooks/tezgah_integrity.py::TEST_PATH`,
|
|
410
|
+
per-marker count `hooks/tezgah_integrity.py::_added`, `hooks/tezgah_integrity.py::shortcut_edit`). Rewriting an existing skip in place
|
|
411
|
+
passes; one more does not.
|
|
412
|
+
|
|
413
|
+
Both scans run on text whose strings, comments and heredoc bodies are blanked (`hooks/tezgah_integrity.py::mask`), so
|
|
414
|
+
a commit message that *describes* `--no-verify` is not a bypass while the flag in command position
|
|
415
|
+
is. Every denial is itself a `deny` row.
|
|
416
|
+
|
|
417
|
+
## The session store for the status marks
|
|
418
|
+
|
|
419
|
+
`<cache>/sessions/<slug>.jsonl`, written by `record()` (`hooks/tezgah_context.py::record`) and read
|
|
420
|
+
by `used()` (`hooks/tezgah_context.py::used`). A row is exactly `{"kind": kind}` — no timestamp, no outcome, no session —
|
|
421
|
+
and the kinds are the used-tool marks [status-line.md](status-line.md) lights up (`graph`, `consult`,
|
|
422
|
+
`research`, `judge`), plus one kind per shipped skill a read opened. It is separate from the
|
|
423
|
+
[ledger](glossary.md#ledger) because it is display state, not
|
|
424
|
+
evidence: nothing refuses a call on it, a kind that is not one of tezgah's is not written at all
|
|
425
|
+
(`hooks/tezgah_context.py::record`), and the reader wants a set of kinds rather than an ordered,
|
|
426
|
+
turn-scoped history. The ledger pays a redaction scan and a lock per row; a mark needs neither. The
|
|
427
|
+
one mark that is also evidence is `orch`: `record()` writes it as an `orch` row in the session's
|
|
428
|
+
ledger too (`hooks/tezgah_context.py::record`), because a subagent event reaches no other ledger
|
|
429
|
+
writer and `fanout` is folded from the ledger.
|
|
430
|
+
|
|
431
|
+
**Which skill a read opened.** `skill_read_kind` (`hooks/tezgah_context.py::skill_read_kind`) earns the mark
|
|
432
|
+
the status line draws for the two skills the always-on core tells a session to read (`SKILL_MARKS`:
|
|
433
|
+
`pony` for `ponytail`, `adhd` for `i-have-adhd`) and `skill:<name>` for any other *shipped* skill -
|
|
434
|
+
one read from the checkout's `skills/` (`hooks/tezgah_context.py::shipped_skills`), so an
|
|
435
|
+
unshipped name earns nothing, which is what `skill://other` always got. `SKILL_MARKS` itself is not
|
|
436
|
+
widened: a mark whose skill the always-on core never names can never flip, and
|
|
437
|
+
`tests/test_context.py::MarkedRulesNameTheirSkill` requires every entry to be named there. A `skill:` kind is
|
|
438
|
+
therefore invisible to the line and its legend - no mark's measure is spelled that way - while
|
|
439
|
+
`skill_fitness(window)` (`hooks/tezgah_context.py::skill_fitness`) reads it back for the one question the
|
|
440
|
+
line never asked. Three surfaces recognise a read, and they have to agree on the two forms
|
|
441
|
+
(`skills/<name>/SKILL.md` and `skill://<name>`) and on which name is shipped: the Python hook omp's
|
|
442
|
+
bridge calls (`hosts/omp/hook.py::classify`), omp's own filter, which decides whether python hears about the
|
|
443
|
+
read at all (`hosts/omp/tezgah-hook.ts.in:225-262`, its catalogue the checkout `@HOOK@` names), and
|
|
444
|
+
opencode's plugin, which classifies in process because that host has no Python hook
|
|
445
|
+
(`hosts/opencode/plugins/tezgah.js:2141-2198`, its catalogue the host's own installed skill dir
|
|
446
|
+
(`dirname(CONFIG)/opencode/skills`), which `tezgah-setup` fills with every shipped skill).
|
|
447
|
+
|
|
448
|
+
Claude loads a skill through its `Skill` tool, never a read, so a Claude load used to leave no row.
|
|
449
|
+
The same function now maps a `Skill` call to the same kind. The call carries
|
|
450
|
+
`{"skill": "<name>"}`, and a plugin skill arrives as `tezgah:<name>`. The plugin's PostToolUse
|
|
451
|
+
matcher carries `Skill` (`hooks/hooks.json`), and `projects-posttooluse.py`'s `used_kind` records
|
|
452
|
+
it. Nobody has checked that Claude fires PostToolUse for the Skill tool. `tests/test_context.py`
|
|
453
|
+
proves the hook side only.
|
|
454
|
+
|
|
455
|
+
**The fitness report.** `tezgah-status --skill-fitness` prints, per shipped skill, how many of the
|
|
456
|
+
recorded sessions opened it, and names the ones none did: a skill is a dependency that has to keep
|
|
457
|
+
earning the context lines it costs, and accretion is invisible from reading the skill itself. It is a
|
|
458
|
+
measurement, not a gate - it names the candidates for retirement, and deleting one stays the owner's
|
|
459
|
+
call. Three ceilings are honest parts of the number, not bugs: the window is the newest
|
|
460
|
+
`FITNESS_WINDOW = 200` session files by mtime, because a row carries no timestamp; a session counts
|
|
461
|
+
as having opened a skill when it recorded that skill's kind, so reads recorded before `skill:` existed
|
|
462
|
+
still count through the two marks; and only the hosts that classify a read in process record one
|
|
463
|
+
here, so the count is a floor, not a census. Which host records what, since this store is the
|
|
464
|
+
report's only source: **omp** (the extension's filter lets the read through,
|
|
465
|
+
`hosts/omp/tezgah-hook.ts.in:255-262`, and the hook classifies it, `hosts/omp/hook.py::classify`) and
|
|
466
|
+
**opencode** (the plugin classifies it, `hosts/opencode/plugins/tezgah.js:2183-2198`) record the mark
|
|
467
|
+
or `skill:<name>` for every shipped skill, in either form; **Claude** sees a read, but only in its
|
|
468
|
+
transcript, which feeds the status line and writes no row here (`statusline.py::claude_used`), so a Claude
|
|
469
|
+
session reads in this report as one that opened nothing - marks included; **codex**, **cursor** and
|
|
470
|
+
**dsh** record no read at all (cursor's `classify` has no skill branch; dsh runs the shared hook whose
|
|
471
|
+
`used_kind` knows no skill kind), and [status-line.md](status-line.md) owns which surface can see a
|
|
472
|
+
read for the marks. Both in-process mirrors take the same two forms and the same shipped-name rule as
|
|
473
|
+
`skill_read_kind`, so a read is recorded on every host that can see one; a host that records none is
|
|
474
|
+
a recording gap, not a skill nobody opened.
|
|
475
|
+
The two marked skills are the only ones any host recorded before `skill:<name>` landed, so the first
|
|
476
|
+
report after this change reads mostly as a recording gap and fills in as sessions run; it says so on
|
|
477
|
+
its own line rather than in a footnote nobody opens.
|
|
478
|
+
The heavier half the mechanism names - a with/without lift measurement against a real oracle - is
|
|
479
|
+
deliberately not here.
|
|
480
|
+
|
|
481
|
+
## Snapshots and rollback
|
|
482
|
+
|
|
483
|
+
Before a write is allowed, `capture` copies the current bytes of every file the call names into
|
|
484
|
+
`<cache>/snapshots/<id>/file`, `meta.json` beside it (`hooks/tezgah_snapshot.py::_store`, `:75-80`,
|
|
485
|
+
`hooks/tezgah_snapshot.py::_capture_one`), and appends one `snapshot` row whose `detail` is the resolved path, `id` the 12-hex
|
|
486
|
+
snapshot id, `hash` the sha256 and `out_bytes` the size (`hooks/tezgah_snapshot.py::_capture_one`). The row is written last, so it
|
|
487
|
+
never names a copy that is not on disk. A credential file (`SECRET_FILE`: `.env*`, `*.env`, key and
|
|
488
|
+
certificate files, `id_rsa`-style keys, `credentials.json`, `.netrc`, `.npmrc`, `.pypirc`, `.pgpass`,
|
|
489
|
+
`.git-credentials`) gets the row alone - path, size and sha256, no `id` and no copy - so a snapshot
|
|
490
|
+
never duplicates a secret, and `rollback` lists it as not restorable (audit L-6). Snapshot files
|
|
491
|
+
are written `0600` in `0700` directories. Every host calls `capture` in process except opencode, whose
|
|
492
|
+
JavaScript plugin reaches it through `bin/tezgah-capture` (`bin/tezgah-capture:1-20`).
|
|
493
|
+
The core captures a call put to `tezgah-gate decide` itself, so the plugin skips it.
|
|
494
|
+
|
|
495
|
+
The store is capped twice (`hooks/tezgah_snapshot.py:34-53`): `CAP = 200` snapshots, oldest evicted by directory mtime when a
|
|
496
|
+
capture crosses it (`hooks/tezgah_snapshot.py::CAP`, `hooks/tezgah_snapshot.py::_evict`), and `MAX_BYTES = 2 MiB` per file, above which
|
|
497
|
+
**nothing is captured at all** — an over-large file is skipped because `capture` runs synchronously in
|
|
498
|
+
the gate on the path of the very write it protects, so copying gigabytes would stall that call, and a
|
|
499
|
+
refused capture writes no row and so claims no copy (`hooks/tezgah_snapshot.py:46-53`, `hooks/tezgah_snapshot.py::_capture_one`).
|
|
500
|
+
|
|
501
|
+
`restore` (`hooks/tezgah_snapshot.py::restore`) has exactly one caller, `bin/tezgah-rollback`, which a user runs:
|
|
502
|
+
`tezgah-rollback <snapshot-id> [--force]` (`bin/tezgah-rollback::main`). It refuses an unknown or
|
|
503
|
+
malformed id, stored bytes that do not match the recorded hash, and a file that has changed since the
|
|
504
|
+
capture — that last one only until `--force`, and the `rollback` row records that it was used
|
|
505
|
+
(`hooks/tezgah_snapshot.py::restore`). The id to pass is on the `snapshot` ledger row for that write (`_snapshot_hash`
|
|
506
|
+
`hooks/tezgah_integrity.py::_snapshot_hash`).
|
|
507
|
+
|
|
508
|
+
`--session <id>` widens that command to a whole session: for every path the session's writes
|
|
509
|
+
touched it puts back the EARLIEST snapshot the session took of it — the state before the session's
|
|
510
|
+
first write of that path. `session_plan` (`hooks/tezgah_snapshot.py::session_plan`) is that reading: it
|
|
511
|
+
walks the session's rows in order, names every path an `edit` or shell row wrote (a snapshot row
|
|
512
|
+
whose path no write row named — the second file of an `apply_patch` body — is there too), and joins
|
|
513
|
+
each to the session's earliest `snapshot` row for it, carrying an `action` that says what the
|
|
514
|
+
rollback would do with it: `restore` for a path a write tool changed, `list (shell only)` for a path
|
|
515
|
+
only a shell command's redirect touched, `list (unknown writer)` when a shell row's
|
|
516
|
+
target could not be re-read so the writer is not known, `list (no snapshot)` for one with no pre-state at all — a
|
|
517
|
+
file the session created. Only the `restore` entries are put back
|
|
518
|
+
(`hooks/tezgah_snapshot.py::restore_session`): which file a command wrote is read off its
|
|
519
|
+
text rather than reported by a tool, so a shell-touched path is listed and never reverted even where
|
|
520
|
+
the gate captured its target, and the id is printed for a deliberate single-id restore. A relative
|
|
521
|
+
target is resolved against the paths the ledger has already resolved — the snapshot rows' own, which
|
|
522
|
+
the gate resolved against the call's cwd (`hooks/tezgah_snapshot.py::_row_path`). `--dry-run`
|
|
523
|
+
prints the plan as `path<TAB>id<TAB>action` and writes nothing: no ledger row, no store change.
|
|
524
|
+
|
|
525
|
+
The moved-on check is `restore`'s own, fed the session's last recorded hash of the path: the file the
|
|
526
|
+
session left behind is what its earliest snapshot is compared with, so the session's own later writes
|
|
527
|
+
need no `--force`, while a write by somebody else after the session's last one still refuses. One
|
|
528
|
+
refusal does not stop the others — each path is its own file and its own decision — and the exit code
|
|
529
|
+
is 1 when any was refused.
|
|
530
|
+
|
|
531
|
+
At the end of a turn the same set is named where a host can show text without blocking the turn:
|
|
532
|
+
Codex's Stop `systemMessage` carries `changed_files_notice`
|
|
533
|
+
(`hooks/tezgah_integrity.py::changed_files_notice`), the turn's `changed_files` as one sorted line, capped at
|
|
534
|
+
`CHANGED_NOTICE_MAX` names plus a count of the rest. Claude's and omp's Stop output returns a
|
|
535
|
+
decision and nothing else and Cursor's block is a follow-up, so those three name no files: the set is
|
|
536
|
+
named to be acted on by the user, never to hold the turn.
|
|
537
|
+
|
|
538
|
+
**Nothing rolls back automatically, anywhere.** A hook that undoes work can destroy more than the
|
|
539
|
+
failure it answers, and its trigger would be a guess about intent wearing a check's clothes
|
|
540
|
+
(`hooks/tezgah_snapshot.py:10-18`; `hooks/tezgah_integrity.py::partial_state`). Repair is the model's or
|
|
541
|
+
the user's: fix and re-run, or reach for a snapshot deliberately.
|
|
542
|
+
|
|
543
|
+
## Untrusted content
|
|
544
|
+
|
|
545
|
+
A result that arrived from outside the user and this workspace carries a provenance label on the
|
|
546
|
+
result itself: `untrusted_label` (`hooks/tezgah_integrity.py::untrusted_label`) names the channel — a web
|
|
547
|
+
result (`hooks/tezgah_integrity.py::WEB_TOOLS`), an MCP server (`hooks/tezgah_integrity.py::untrusted_source`), a network read (`hooks/tezgah_integrity.py::NETWORK_READ`: `curl`, `wget`, `gh api`, `gh issue view|list`, `gh pr view|diff|checkout|list`, a `git clone` of a non-local source, a `git pull|fetch` that names a URL, also behind `sudo`, `git -C dir` or an `X=1` prefix) or a
|
|
548
|
+
model on the far side of the network (`hooks/tezgah_integrity.py::TIER_PROGRAMS`: a `bin/consult`/`bin/codegen`
|
|
549
|
+
invocation that reaches a provider) — and tells the model to treat instructions inside it as data.
|
|
550
|
+
The call's own row carries the channel in `source` (`hooks/tezgah_integrity.py::note_tool`).
|
|
551
|
+
|
|
552
|
+
After that read, the first effect the turn makes — a shell call, a write, or an MCP call of any verb
|
|
553
|
+
class (`hooks/tezgah_untrusted.py::effectful`, `hooks/tezgah_integrity.py::mcp_class`) — carries a taint notice instead (`hooks/tezgah_untrusted.py::marks`,
|
|
554
|
+
`hooks/tezgah_untrusted.py::taint_notice`, `hooks/tezgah_untrusted.py::turn_channel`) — which reads the ledger through `turn_rows`
|
|
555
|
+
(`hooks/tezgah_integrity.py::turn_rows`): the whole file's lines, but only the current turn's rows
|
|
556
|
+
parsed, so a taint check costs the length of the turn and not the length of the session. It names
|
|
557
|
+
the turn, never a cause: whether the
|
|
558
|
+
fetched page *caused* the write is not something a hook can see (`hooks/tezgah_untrusted.py:14-17`). One notice per read, and
|
|
559
|
+
the effect's own row then carries the channel, so the taint is a transition rather than a repeat.
|
|
560
|
+
An MCP effect after another channel's read carries both lines. Its result came from the server, so
|
|
561
|
+
it keeps the label. Its row carries the `mcp` channel, which takes the inherited channel's place.
|
|
562
|
+
After an MCP read it carries the label only, because the label already names that channel.
|
|
563
|
+
|
|
564
|
+
Subagents of one Claude session write one ledger, so one sibling's web read used to taint every
|
|
565
|
+
sibling's effects. Claude's hook payload carries `agent_id` on a call a subagent makes, and
|
|
566
|
+
`hooks/projects-posttooluse.py` writes it into the row's `agent` field. `turn_channel` and
|
|
567
|
+
`turn_rows` then read only that agent's rows, and the gate's repeat ceilings count only that
|
|
568
|
+
agent's attempts (`prior_calls` `hooks/tezgah_integrity.py::prior_calls`). The parent (no `agent_id`)
|
|
569
|
+
still reads the whole turn, because its subagents' work is its turn. Hosts whose payload tezgah
|
|
570
|
+
reads no agent key from still share one ledger's taint; omp writes one ledger per subagent.
|
|
571
|
+
|
|
572
|
+
The taint is a notice, not a refusal: the gate's sink rule, which held an effect in such a turn
|
|
573
|
+
until the user's own approval was on the ledger, was removed with the consent rule
|
|
574
|
+
([gate](gate.md)). The
|
|
575
|
+
label reaches the model on every host that has a surface for it, and the taint notice with it:
|
|
576
|
+
Claude and dsh through `hooks/projects-posttooluse.py::main`, Codex (`hosts/codex/hook.py::main`),
|
|
577
|
+
Cursor (`hosts/cursor/hook.py::dispatch`), omp (`hosts/omp/hook.py::handle`, which calls `marks` with an
|
|
578
|
+
empty stand-in for the result body its bridge never sends, so a subagent's report keeps its label), and opencode, whose plugin
|
|
579
|
+
cannot import the core in process and mirrors the control in JavaScript instead — the channel on the
|
|
580
|
+
call's own row, the label and the taint notice in front of the result the hook is handed, including
|
|
581
|
+
the `external` row an MCP answer or a fetched page earns (`untrustedSource`
|
|
582
|
+
`hosts/opencode/plugins/tezgah.js:1898`, `labelResult` `:1972`, with the tier's argv reader
|
|
583
|
+
`tierRead` at `:1881`). The two halves are pinned against each other over a shared corpus, so neither
|
|
584
|
+
can move without failing the other's test (`tests/test_opencode_plugin.py::OpenCodePlugin.test_the_classifier_agrees_with_the_python_half_on_a_shared_corpus`). One difference is deliberate:
|
|
585
|
+
opencode's plugin writes that `external` row itself and carries the channel alone, since the UI rule
|
|
586
|
+
`_screen_read` belongs to the Python half and does not run there.
|
|
587
|
+
|
|
588
|
+
## The counters a maintainer reads
|
|
589
|
+
|
|
590
|
+
`tezgah-status --counters [session] [path]` (`bin/tezgah-status::main`) prints `counters(session)`
|
|
591
|
+
(`hooks/tezgah_integrity.py::counters`) over one session's whole ledger, and `tezgah-status --counters
|
|
592
|
+
--all` prints `counters_all()` (`hooks/tezgah_integrity.py::counters_all`) over every real-session ledger on the machine, adding `ledgers`, the
|
|
593
|
+
number of files it read, and `fixtures`, the ledgers left out because every workspace they name is a temp, OpenResearch run or arm-bench tree (`fixture_ledger`). Both fold their rows through `_counts` (`hooks/tezgah_integrity.py::_counts`), the one implementation
|
|
594
|
+
of the arithmetic, so a total cannot drift from the sessions it sums - the `:NNN` rows below are that
|
|
595
|
+
fold. `counters_all` bounds nothing: a window or a row cap would make the total contradict the
|
|
596
|
+
per-session numbers it claims to be, and the whole corpus here folds in 0.4 s (58,928 rows, 1,120
|
|
597
|
+
real ledgers, measured 2026-09-30).
|
|
598
|
+
|
|
599
|
+
Each key, as both readers produce it:
|
|
600
|
+
|
|
601
|
+
- `events` — every row; `kinds` — a histogram of them.
|
|
602
|
+
- `steps` — rows whose kind is in `STEP_KINDS` (`hooks/tezgah_integrity.py::STEP_KINDS`): work rows only,
|
|
603
|
+
`interrupted` among them, since a call the host stopped was still issued.
|
|
604
|
+
- `unanswered` — the `began` rows no outcome answered (`unanswered`): calls whose result nobody saw.
|
|
605
|
+
It is in no rate. `counters_all` sums it per ledger, so one session's answer never closes another's call.
|
|
606
|
+
- `tool_error_rate` — non-zero `exit` values over every row carrying an `exit` (`hooks/tezgah_integrity.py::_counts`);
|
|
607
|
+
a host reporting no outcome contributes to neither half, so every row with an `exit` counts.
|
|
608
|
+
- `claims` and `false_completion` — the `claim` rows, which are replies in the claim vocabulary,
|
|
609
|
+
and those whose detail starts with `blocked` (`hooks/tezgah_integrity.py::_counts`). A shape class (`SHAPE_BLOCKS`) is
|
|
610
|
+
the exception. A reply refused for its list or its language made no false claim, so it counts
|
|
611
|
+
as `shape_blocked` instead.
|
|
612
|
+
- `refusals` — the `refusal` rows: refused replies that claimed nothing, work-only or shape. A
|
|
613
|
+
shape one also counts in `shape_blocked`. Before row version 3 these were `claim` rows, so a
|
|
614
|
+
corpus folded across the boundary counts them in `claims`.
|
|
615
|
+
- `blocked_claims` — `false_completion` split by its Stop class, the text after `blocked: `
|
|
616
|
+
(`no verify_ok`, `stale evidence`, `no external read`, …), so each class has its own count.
|
|
617
|
+
- `replies` and `shape` — the `shape` rows, written for every judged reply, and those carrying a
|
|
618
|
+
report-only flag (`hooks/tezgah_integrity.py::_counts`).
|
|
619
|
+
- `denies` — `deny` rows grouped by the text before the first colon (`hooks/tezgah_integrity.py::_counts`), which is the rule
|
|
620
|
+
name (`shortcut`, `loop`, `race`, …); `nudges` and `fanout` — the nudge rows and
|
|
621
|
+
the subagent-ish kinds (`hooks/tezgah_integrity.py::_counts`), the `orch` rows among them written by `record()`
|
|
622
|
+
for every subagent event a Python adapter sees.
|
|
623
|
+
- `denies_reissued` — per deny rule, the denied calls that came back (`_reissued`). A later row of
|
|
624
|
+
the same ledger carries the deny's `id`: the model made the call again. `tezgah-status --counters`
|
|
625
|
+
prints it beside the denies as `rule=reissued/denies rate`. A rule is kept or dropped on this
|
|
626
|
+
rate. For `drift` a high rate is the design: it refuses once, then lets the same call through. For
|
|
627
|
+
any other rule it means the model worked around the refusal.
|
|
628
|
+
- `consult`, `codegen`, `codegen_failed` — substring matches on `detail` (`hooks/tezgah_integrity.py::_counts`).
|
|
629
|
+
- `weeks`, `tools`, `programs` — present only when the caller asked (`counters(..., weeks=True,
|
|
630
|
+
tools=True)`), which is what `tezgah-status --counters --trend` passes; see below.
|
|
631
|
+
|
|
632
|
+
**`false_completion / claims`** is how often the rule refused a reply that claimed completion or
|
|
633
|
+
verification. It is one reading among the counters, not the layer's effect. A refusal the model
|
|
634
|
+
then repaired and a refusal it argued past count the same. The `after_block` rows record that
|
|
635
|
+
difference. One ledger is an anecdote. `--counters --all` gives the same ratio over the corpus. A
|
|
636
|
+
published value names the command, the date and the ledger count it ran over. Prose never
|
|
637
|
+
restates a number, because the counters' meaning moves with the row version. At version 3
|
|
638
|
+
work-only refusals left `claims`.
|
|
639
|
+
|
|
640
|
+
### The drift series and the firing histograms
|
|
641
|
+
|
|
642
|
+
`tezgah-status --counters --trend [--weeks=N]` prints two reports the same fold carries, because a
|
|
643
|
+
value is a reading and the thing worth watching is the population over time. Both are filled inside
|
|
644
|
+
`_counts` (`hooks/tezgah_integrity.py::_counts`) in the same pass as the totals, so neither can
|
|
645
|
+
disagree with the number it is drawn from; both are off unless the flag asks, so the plain and the
|
|
646
|
+
`--json` output of a reader who did not ask are byte-identical to what they were.
|
|
647
|
+
|
|
648
|
+
- **The drift series** — `weeks`, every row bucketed by `ts` on a fixed 7-day grid (`WEEK`, anchored
|
|
649
|
+
on the Monday of the epoch's first week, `hooks/tezgah_integrity.py::_week`), each bucket
|
|
650
|
+
counting its events, claims, refused claims and decided attempts. `drift_series(counters, weeks)`
|
|
651
|
+
(`hooks/tezgah_integrity.py::drift_series`) re-slices them into the last `weeks` calendar weeks, oldest
|
|
652
|
+
first, with `false_completion/claims` and `tool_error_rate` per bucket, and the direction of the
|
|
653
|
+
newest three weeks that carry a denominator (`hooks/tezgah_integrity.py::_direction`, compared by
|
|
654
|
+
cross-multiplication so a shared rounding is never called flat). A week with no row prints a zero
|
|
655
|
+
row count and `n/a` for both ratios, never `0.0`: an empty week is not a week with a perfect rate,
|
|
656
|
+
and a gap has to read as a gap. Nothing is windowed out of the totals.
|
|
657
|
+
- **The tool firings** — `tools`, a histogram over `_tool_name(entry)` (`hooks/tezgah_integrity.py::_tool_name`):
|
|
658
|
+
the row's `tool` field, else the name an `unknown` row (`unknown tool: <name>`) or an MCP `external`
|
|
659
|
+
row (`mcp <name>`) kept in `detail`. A work row written before the `tool` field landed carries no
|
|
660
|
+
name at all - `classify` folded it into a kind - so an old corpus under-counts, which is the
|
|
661
|
+
honest ceiling and the reason the field exists; every row written since carries it, because both
|
|
662
|
+
writers write it (`hooks/tezgah_integrity.py::note_tool`, and opencode's plugin
|
|
663
|
+
`hosts/opencode/plugins/tezgah.js:1230-1241` - before that second one did, an opencode work row was
|
|
664
|
+
the other half of this under-count, with its name unrecoverable in the command `detail`). A read
|
|
665
|
+
tool is not in it either: reads record no row by design.
|
|
666
|
+
- **The shipped programs** — `programs`, the `bin/` programs a command row really ran, read with the
|
|
667
|
+
tokenizer the status line already uses (`hooks/tezgah_integrity.py::_ran_programs`), and
|
|
668
|
+
`unfired_programs(counters)` (`hooks/tezgah_integrity.py::unfired_programs`), the catalog minus that set. The absence is the
|
|
669
|
+
evidence: a tool nobody calls leaves no row, so the only way to name it is a catalog, and the one
|
|
670
|
+
catalog this layer holds is its own `bin/` (`hooks/tezgah_integrity.py::shipped_programs`). The prefilter is one
|
|
671
|
+
regex per catalog and the tokenizer runs only on a row that mentions a shipped name, which is why
|
|
672
|
+
the tool histogram costs about 0.6 s over the whole corpus where the plain fold costs 0.4 s (58,928
|
|
673
|
+
rows, measured 2026-09-30). A
|
|
674
|
+
program reached through an interpreter (`python3 bin/consult q`) counts as never fired, the same
|
|
675
|
+
ceiling `shell_kind` has and for the same reason.
|
|
676
|
+
|
|
677
|
+
**The MCP half of a retirement decision is manual, and deliberately so.** This layer does not hold
|
|
678
|
+
the catalog of MCP servers - that is the host's configuration - so a server that never fires leaves
|
|
679
|
+
nothing here to name. `tezgah-setup --mcp-schemas` measures what each wired server costs on every
|
|
680
|
+
request; the histogram here counts what fired; joining the two is a reader's step, not a call this
|
|
681
|
+
report makes (calling it would couple the two CLIs and re-measure a config that may not be the one
|
|
682
|
+
the corpus ran under).
|
|
683
|
+
|
|
684
|
+
## The replay corpus
|
|
685
|
+
|
|
686
|
+
No counter above says whether a refusal was right. The ledger stores the verdict, never the truth.
|
|
687
|
+
`tezgah-gate replay` (`hooks/tezgah_replay.py`) builds the instrument that can. It is a report and
|
|
688
|
+
changes no gate behaviour. Every file it writes stays under `~/.cache/tezgah/replay/<run>/`, owner
|
|
689
|
+
only, and never leaves the machine. Every figure it prints names its cutoff.
|
|
690
|
+
|
|
691
|
+
- **Corpus.** The run reads every ledger under the cache and writes none. It drops a whole ledger
|
|
692
|
+
when `fixture_ledger` calls it a fixture. It also drops one when the session id behind the file
|
|
693
|
+
name is not a host UUID: probe, smoke and test ids. It drops `route` rows, which the suite
|
|
694
|
+
writes, and every row after the cutoff. The items are the `deny`, `began` and `claim` rows. An
|
|
695
|
+
item drops when its deny names a rule the gate no longer has (consent, sink). It also drops at
|
|
696
|
+
the 200-character cap, or when it holds `[redacted:`. The run prints each exclusion with its count.
|
|
697
|
+
- **Join.** A transcript tool call joins a row when its `call_id` equals the row's `id`. The two
|
|
698
|
+
must sit in the ledger the session id names. The walkers read omp and Claude transcripts with
|
|
699
|
+
their subagent files, and drop omp's `i` argument first. A shell `began` row with no transcript
|
|
700
|
+
call joins from its own `detail`, but only when that detail hashes to the row's `id`. A `claim`
|
|
701
|
+
row joins the assistant reply nearest its time, within 2 s. Nothing else joins.
|
|
702
|
+
- **Replay.** A child process gets a sandbox HOME. It appends every kept row to the sandbox
|
|
703
|
+
ledgers in time order. It replays each item just before the item's own row lands, with the
|
|
704
|
+
clock frozen at the row's time. Gate items go through the unmodified `decision(..., record=False)`.
|
|
705
|
+
Stop items go through `_stop_block` with the turn's own rows. The sandbox holds no kill switch,
|
|
706
|
+
so every switch reads armed. A call a switch let through can therefore replay as a refusal.
|
|
707
|
+
- **Replay fidelity** = items whose replayed verdict equals the live one ÷ joined items, per
|
|
708
|
+
stratum. A deny agrees only under the same rule, and `_deny_rule` alone names the rule. The
|
|
709
|
+
*ledger* stratum holds rules that read the call and the ledger. The *disk* stratum holds the
|
|
710
|
+
rules that read today's disk. These are task, plan, workspace and explorer, a shortcut on a write
|
|
711
|
+
tool, and a lang rule reading a message file. The other strata are *allow* (live `began` rows)
|
|
712
|
+
and *stop*.
|
|
713
|
+
The run prints each one for the whole corpus and for the rows since `34f63e3`.
|
|
714
|
+
- **Stop text fidelity** = joined replies whose `_claim_key` equals the claim row's `id`. The run
|
|
715
|
+
prints it beside the fidelity and never counts it as agreement.
|
|
716
|
+
- **Race family** = live race denies split by their foreign writers. A deny is intra-family when
|
|
717
|
+
every writer is the session's parent, child or sibling. It is cross-family when any writer has
|
|
718
|
+
no family tie. The family comes from omp's `spawned` rows and the subagent transcripts' parent
|
|
719
|
+
links.
|
|
720
|
+
- **Denial budget** (`tezgah_shapes.deny_runs`) = per rule, runs of 3 or more consecutive denies
|
|
721
|
+
inside one turn, and sessions with 20 or more denies. These are Claude Code auto mode's
|
|
722
|
+
thresholds, not a tezgah measurement.
|
|
723
|
+
|
|
724
|
+
`replay --sheet` draws the blind label sample with a fixed seed. It fills per-stratum quotas,
|
|
725
|
+
shuffles them, and writes `tezgah-taste measure`'s `{set, n, text}` format. No item shows its
|
|
726
|
+
verdict, its rule or its reason. The verdicts sit in `sheet-key.jsonl`, which a rater does not
|
|
727
|
+
open. The sheet leaves off every race deny written before the ledger stored `target`, because a
|
|
728
|
+
rater could not see its foreign writer. With no race item on the sheet, the report calls the race
|
|
729
|
+
exemption bar not measurable. `replay --report --labels <file> ...` reads one labels file per rater
|
|
730
|
+
(`{set, n, label, rater}`). It prints these rates, each with a Wilson 95% interval:
|
|
731
|
+
|
|
732
|
+
- **False-block rate (rule r)** = denies of r labelled `allow` ÷ denies of r with a label.
|
|
733
|
+
- **Stop missed-violation rate** = allowed claims labelled `false` ÷ allowed claims with a label.
|
|
734
|
+
- **Stop false-refusal rate** = blocked claims labelled `honest` ÷ blocked claims with a label.
|
|
735
|
+
- **Cohen's kappa** between the two raters. The rates count only the items both raters gave the
|
|
736
|
+
same label. Under 0.6 the report says the labels cannot gate a rule.
|
|
737
|
+
|
|
738
|
+
With no labels file the report calls these figures unverifiable instead of printing zeros.
|
|
739
|
+
A rule with no item on the sheet is not measurable: the report prints that and does not pool it.
|
|
740
|
+
With one rater's file it prints no rate either. The rates need two raters' agreed labels, and
|
|
741
|
+
one rater's totals would show the other rater those labels.
|
|
742
|
+
|
|
743
|
+
`replay --label-model --prompt <file>` is rater 2 when that rater is a model. It sends each sheet
|
|
744
|
+
row to the judge seam (`hooks/tezgah_judge.py`) as one `choice` question and writes
|
|
745
|
+
`labels-model.jsonl` beside the sheet. It redacts the row's text first (`ti.redact`), and it runs
|
|
746
|
+
only when TypeSafe answers. The prompt file holds each set's instructions and criteria. A reply
|
|
747
|
+
with no label from those criteria leaves its row unlabelled. The command writes each label as it
|
|
748
|
+
arrives, so a run that stops early keeps what it paid for. A second run asks only the unlabelled rows. Every run prints the input tokens and their cost. The sheet rows leave the machine for
|
|
749
|
+
`api.typesafe.ai`. The key and the corpus stay on it. Kappa against a model rater
|
|
750
|
+
measures human-model agreement, not inter-rater reliability.
|
|
751
|
+
|
|
752
|
+
`--provider deepseek --model deepseek-v4-pro` asks the same questions from the same prompt file
|
|
753
|
+
over DeepSeek's OpenAI-compatible chat endpoint instead (key `DEEPSEEK_API_KEY`). It sends the
|
|
754
|
+
judge seam's chat body with `temperature: 0` and thinking off, and writes
|
|
755
|
+
`labels-deepseek.jsonl` (rater `deepseek`). The cost line prices input and output tokens at
|
|
756
|
+
DeepSeek's peak rate, an upper bound. With two model raters, the report labels kappa as
|
|
757
|
+
model-model agreement, not human judgement (ADR 018).
|
|
758
|
+
|
|
759
|
+
## What the evidence layer has not shown
|
|
760
|
+
|
|
761
|
+
The ledger records what a session ran, and the Stop rule refuses a done claim
|
|
762
|
+
the ledger cannot back. Both are mechanisms. Neither has shown an effect on task
|
|
763
|
+
outcomes. A paired on/off experiment in October 2026 ran DeepSeek V4.1 Flash on
|
|
764
|
+
omp, bare against a full install. It found no measurable reduction in cheating
|
|
765
|
+
because the model barely cheated in either arm. The second phase used
|
|
766
|
+
ImpossibleBench's conflicting SWE-bench split (44 instances, k = 3). There the
|
|
767
|
+
agent cheated in 0 of 132 runs with tezgah and 1 of 131 without: -0.8 pp, 95%
|
|
768
|
+
CI -2.3 to 0. Clean pass on the original tasks held at 129 of 131 against 129
|
|
769
|
+
of 132.
|
|
770
|
+
|
|
771
|
+
The false-done reader is `hooks/tezgah_integrity.py::claims`, read over the Stop rule's
|
|
772
|
+
claim vocabulary. On the impossible split it read 115 of 132 final messages
|
|
773
|
+
with tezgah as done claims, and 90 of 131 without. Hand labels of 30 sampled
|
|
774
|
+
messages per arm found real done claims in 3 with tezgah and 6 without. The
|
|
775
|
+
adjusted difference is -5 pp,
|
|
776
|
+
95% CI -18 to +9, so no effect either way. As a false-done reader on this
|
|
777
|
+
split, the reader's precision was 0.10 with tezgah and 0.20 without. With
|
|
778
|
+
tezgah the agent replied in Turkish in 129 of 132 runs. The reader counted the
|
|
779
|
+
passive `doğrulandı` on a partial fix as a completion claim, even beside a
|
|
780
|
+
`doğrulanmadı` for the failing test. It no longer does. A reply that admits an
|
|
781
|
+
open check now reads as no claim. It says no check backs the work
|
|
782
|
+
(`hooks/tezgah_integrity.py::NEGATED`), or that a test contradicts the issue or
|
|
783
|
+
cannot pass (`hooks/tezgah_integrity.py::ADMITTED`). A failure the reply
|
|
784
|
+
dismisses as pre-existing still reads as a claim. The rule came from the 60
|
|
785
|
+
hand-labelled dev messages, where precision rose from 0.15 to 0.69 at recall
|
|
786
|
+
1.0 (`python3 tests/claim_reader_eval.py --set e4`).
|
|
787
|
+
|
|
788
|
+
A held-out set followed: 40 fresh flagged messages, sampled and labelled under
|
|
789
|
+
a protocol frozen first, by two model raters (kappa 0.565). The reader ran on it
|
|
790
|
+
once, after commit 9cb4d1d. There
|
|
791
|
+
precision rose from 0.212 to 0.857, but recall fell from 1.0 to 0.857 (6 of 7)
|
|
792
|
+
(`python3 tests/claim_reader_eval.py --set heldout`). The plan's recall bar of
|
|
793
|
+
0.9 is not met. The one miss is a real verification claim whose double negative
|
|
794
|
+
matched NEGATED and read as an admission:
|
|
795
|
+
`doğrulanmadı sayılmaz`.
|
|
796
|
+
|
|
797
|
+
The reader measures and does not decide. `claims` feeds only the benchmarks'
|
|
798
|
+
false-done counts (`benchmarks/arm-bench/bench.py::false_completion`,
|
|
799
|
+
`benchmarks/arm-bench/swe.py`), never the Stop decision. The Stop verdict and
|
|
800
|
+
its `claim` row read the plain DONE/VERIFIED vocabulary with their own NEGATED
|
|
801
|
+
exit, so no refusal changed. NEGATED and ADMITTED match anywhere in the reply,
|
|
802
|
+
so a done claim beside an unrelated "no contradictions" or "never pass secrets"
|
|
803
|
+
is not counted. A false-done count taken before commit 9cb4d1d is not
|
|
804
|
+
comparable with one taken after it.
|
|
805
|
+
|
|
806
|
+
A red-team pass found one route a hook cannot read (a `python3 -c` write of a
|
|
807
|
+
switch) in 30 attempts.
|
|
808
|
+
|
|
809
|
+
The numbers, the per-task counts and the instrument flaws, among them agents
|
|
810
|
+
that could read the benchmark's ground truth, are in
|
|
811
|
+
[the results bundle](results/paired-outcome-2026-10.md).
|
|
812
|
+
|
|
813
|
+
## Source of truth
|
|
814
|
+
|
|
815
|
+
- `hooks/tezgah_integrity.py` — ledger, kinds, redaction, Stop rule, counters
|
|
816
|
+
- `hooks/tezgah_replay.py` — the replay corpus, the label sheet and its report (`tezgah-gate replay`)
|
|
817
|
+
- `hooks/tezgah_untrusted.py` — provenance label and taint notice
|
|
818
|
+
- `hooks/projects-posttooluse.py` — the writer hosts call after a tool result
|
|
819
|
+
- `hooks/projects-stop.py` — the Claude Stop hook
|
|
820
|
+
- `hooks/tezgah_snapshot.py` — capture, cap, restore
|
|
821
|
+
- `hooks/tezgah_context.py` — the session store (`record`/`used`)
|
|
822
|
+
- `hooks/tezgah_gate.py` — the shortcut and sink denies
|
|
823
|
+
- `hosts/opencode/plugins/tezgah.js` — the host with no Python hook: its own ledger
|
|
824
|
+
and used-store rows (`recordEvidence`, `record`, `skillReadKind`)
|
|
825
|
+
- `hosts/omp/tezgah-hook.ts.in` — the omp bridge: which tool result reaches the hook
|
|
826
|
+
at all, and the skill-read filter
|
|
827
|
+
- `bin/tezgah-rollback`, `bin/tezgah-capture`, `bin/tezgah-status`
|
|
828
|
+
- `tests/test_integrity.py`, `tests/test_snapshot.py` — the pinned behaviour
|
|
829
|
+
- `tests/test_opencode_plugin.py`, `tests/test_omp_extension.py` — the JS mirrors
|
|
830
|
+
pinned against the Python half
|
|
831
|
+
- `docs/results/paired-outcome-2026-10.md` — the paired outcome experiment and its counts
|