# `mix verify.workspace_clean`
[🔗](https://github.com/szTheory/scrypath/blob/v0.3.5/lib/mix/tasks/verify.workspace_clean.ex#L1)

Verifies that `git status` is clean for all pathspecs that ship in the Hex
tarball plus `test/**`.

Runs as the first step of every publish path (canonical release-please flow,
manual-recovery workflow, and per-push CI) so a release cannot ship files
that were not reviewed and merged.

This gate exists because an earlier release cycle shipped a partial tarball
when uncommitted files did not travel to the release tag. See
`docs/releasing.md` § Historical context for why parity and workspace gates
matter on publish paths.

## Usage

    mix verify.workspace_clean

The task takes no arguments. There is deliberately no escape-hatch
flag or environment variable — the friction is the feature. Real
emergencies require commenting out the workflow step in a PR.

# `build_pathspecs`

```elixir
@spec build_pathspecs() :: [String.t()]
```

Returns the pathspec list used by `run/1` — derived from
`mix.exs` `package.files` plus `"test"`.

Exposed publicly for testability.

# `classify`

```elixir
@spec classify(String.t(), integer(), non_neg_integer()) ::
  {:ok, String.t()} | {:dirty, String.t()} | {:git_error, String.t()}
```

Pure classifier for `git status --porcelain` output.

Split out of `run/1` so tests can exercise each branch without a real git
subprocess (mirrors the `Mix.Tasks.Verify.ReleaseParity.compute/2` seam).

Returns one of:

- `{:ok, message}` — clean tree (empty output, exit 0)
- `{:dirty, paths}` — uncommitted or untracked files present (non-empty output, exit 0)
- `{:git_error, err}` — `git status` itself failed (non-zero exit)

---

*Consult [api-reference.md](api-reference.md) for complete listing*
