ok:true is not a verdict
Every ork hook writes ok: true to hook-timing when it does not throw. #3801 showed what that hides: a verifier at ok:true, 2 ms for months, doing nothing. This page shows the two instruments that replace "did not throw" with "did its job", and what they found on their first run.
1. First run: 17 probes, three reds, all real
| probe | entry probed | trip fixture | day one | now |
|---|---|---|---|---|
| bash-catastrophic-rm-deny | sync-bash-dispatcher | recursive delete of root | deny | deny |
| bash-force-push-ask | sync-bash-dispatcher | git push --force | ask | ask |
| bash-push-refspec-to-main-deny | sync-bash-dispatcher | git push origin HEAD:main from feat/x | silent | deny |
| bash-pipe-to-shell-deny | sync-bash-dispatcher | curl ... | bash | deny | deny |
| egress-staged-download-run-ask | network-egress-guard | curl -o s.sh && bash s.sh | ask | ask |
| compound-herestring-ask | compound-command-validator | bash <<< "code" | ask | ask |
| write-file-guard-oversize-ask | sync-write-edit-dispatcher | 400-line source Write | updatedInput only | ask |
| write-memory-budget-ask | sync-write-edit-dispatcher | 20 KB MEMORY.md | silent | ask |
| agent-fable-pin-consent-ask | sync-task-dispatcher | Agent with model claude-fable-5 | ask | ask |
| agent-unknown-target-ask | sync-task-dispatcher | subagent_type ork:no-such-agent | ask | ask |
| cron-create-in-ci-block | cron-guard | CronCreate with CI=true | block | block |
| read-credential-file-deny | credential-read-guard | Read ~/.aws/credentials | deny | deny |
| elicitation-secret-field-block | elicitation-guard | form schema with a password field | block | block |
| model-switch-to-fable-ask | model-switch-consent | PreModelSwitch to claude-fable-5 | ask | ask |
| stop-coverage-below-threshold-block | coverage-threshold-gate | coverage-summary at 40% | block | block |
| stop-cross-instance-missing-tests-block | cross-instance-test-validator | two untested exports, Stop payload | silent | xfail #3804 |
| posttool-stale-import-block | stale-import-detector | three importers of a rewritten module | block | block |
Every probe also runs a control fixture one condition short, which must stay silent; a probe that cannot fail is caught by its own control. A fourth red on day one was the harness itself (bulk content expanded for files but not payload fields), which the controls could not catch and the direct sub-guard run did.
2. Why the two fixed ones were invisible
| defect | why no test saw it | since |
|---|---|---|
sync-write-edit-dispatcher merged only additionalContext and updatedInput; a sibling's ask is continue:true, so neither short-circuited nor carried | file-guard's own tests call file-guard, the dispatcher's tests mocked its siblings; nothing drove the pair | file-guard and context-file-budget-guard moved from deny to ask (#2947) |
git-validator returned early when the session branch was not protected, so a refspec naming main was never examined | the refspec tests exercise extractPushDestinations() in isolation; the guard's own comment described the intended verdict | #3455 added explicit-destination awareness as an allow only |
3. The telemetry half
hook-timing.jsonl lines now carry verdict: deny / ask / allow / defer from permissionDecision, block from continue:false, context when only context or an input rewrite came back, silent otherwise, error on a throw. A decisive hook that reports only silent across a week is either healthy and unprovoked or dead; the probes are how you tell.
before: ok:true ×2,140
after: silent ×2,081 · ask ×49 · deny ×10
The second bar is a sketch of the field's shape, not a measurement; the first real week of data lands after release.