Repository navigation
v2.36.0
Ships G423 — the loop gate for GitHub Copilot.
The record (W2147). A successful completion writes .stride/.loop-state.json (identifier, needs_review verbatim, an ISO8601 timestamp, session id); any claim clears it. The hook writes it, never the agent. Both halves produce a byte-identical record, asserted with cmp rather than by inspection.
The gate (W2148). stride-stop-gate.sh and its PowerShell twin, registered as Stop. Blocks on exactly one condition and permits on everything else, always at exit 0, via {"decision":"block","reason":...} on stdout.
Exit 2 is not a refusal here. On agentStop a non-zero exit is logged and skipped — it denies only for preToolUse. A gate ported unchanged from Claude Code would log its refusal on every turn end, let the session finish anyway, and look healthy doing it. No code path in either half exits 2, and a test case proves the distinction rather than commenting on it.
The coverage (W2149). Permits vastly outnumber the block, each asserting its own reason string; every silent permit has a positive control. A 13-mutation campaign across both halves killed every mutant.
Registration is disclosed, not asserted. The nested Stop entry is verified well-formed and resolving to the gate, and Stop is GitHub's documented alias for agentStop — but no live Copilot parsed it here, and the shape is uncorroborated rather than merely unverified. Both gate headers, hooks.json, docs/HOOK_RESEARCH.md and a SKIP-never-PASS case all say so.
Security fix. The block-counter guard refused a directory but not a symlink ([ -f ] dereferences), so a planted link would have had its target truncated anywhere the agent user can write. Fixed on both halves and pinned by a case with a block-path control. The curl test stub also now redacts the bearer header it records.