v1.8.1 — Test-Suite Sandbox Containment
Test-suite containment and quality cleanup.
No behavior change for devflow users. Every production git invocation was already correctly pinned, so anyone installing from crates.io was unaffected by the defect this fixes. The blast radius was developers and contributors running the test suite from a checkout — for whom it was severe.
Fixed — the test suite could corrupt the developer's own repository
Running cargo test from a git hook — which scripts/hooks/pre-push does on every push — let test fixtures operate on the real checkout instead of their tempdirs. Observed damage in this repository: core.bare=true on the main repo, the committer identity rewritten to a fixture's, and ten fixture commits stacked onto local main, the first of which deleted all 511 tracked files.
Root cause: git exports GIT_DIR into hook environments when the gitdir is non-default — precisely the case when pushing from a linked worktree. GIT_DIR outranks a process's working directory when git decides which repository to act on, and Rust runs a test binary's tests as threads in one process, so the whole suite inherited it and every fixture retargeted the real repo despite correctly pinning .current_dir().
Neither git -C nor GIT_CEILING_DIRECTORIES overrides GIT_DIR (only --git-dir does), so pinning the working directory can never be the containment mechanism — clearing the variables is.
Fixed in three layers:
scripts/hooks/pre-pushclears$(git rev-parse --local-env-vars)— git's own authoritative list, so it self-maintains across git upgradesdevflow_core::test_support::git_commandapplies the same scrub per command, across 50 migrated call sites — containing fixtures on every other launch path (git rebase --exec,git bisect run, CI)- A new guard test fails fast and names the cause when the environment is dirty
Validated by controlled A/B in an isolated clone — same commit, same worktree, only the hook differing: scrubbed, the push is green with 156/156 passing; unscrubbed, the push is blocked with 42 failures, core.bare=true and HEAD hijacked onto a fixture branch, reproducing the original incident down to the branch name.
Also fixed
gate showandgate respondno longer duplicate the omitted---stageresolution logic, so their behavior cannot drift apartgate showreads the open-gate list once instead of twice, closing a narrow time-of-check/time-of-use windowdoctor's planning-doc reconciliation usesconfig::MAINinstead of a second hardcoded"main"
Added
scripts/hooks/pre-commit, a chaining shim.core.hooksPathreplaces the hooks directory wholesale, so the documented install step would otherwise silently disable a global pre-commit secret scanner. It delegates to whatever hook you already had, and is a no-op if you have nonedevflow-coregains an off-by-defaulttest-supportfeature exposingtest_support::git_command
Changed
- DevFlow is now described as opinionated rather than agent-agnostic across the README, ARCHITECTURE, guides, both crate descriptions and
--help. It bakes in one developer's specific take on branching, gating and verification rather than aiming to be a universal platform statusno longer re-scansevents.jsonlper phase for the stage-entry timestamp
Full changelog: https://github.com/denniyahh/devflow/blob/v1.8.1/CHANGELOG.md