{
  "schema_version": 1,
  "id": "block-test-skips",
  "track": "coding",
  "name": "Block Test Skips",
  "version": "0.1.0",
  "sha256": "400af594176d03f7541227e3346f99613640037dc7dc8bb76c64572c7b817dc7",
  "sha256_v1": "8535c52ed055b084b3d870b339448741e1834f6fd91ab2d32ead1d263f475574",
  "keyword": "block",
  "word": "blocks",
  "says": "blocks on an agent's file writes and at turn end",
  "description": "Blocks newly added test skips, focus markers and runner options that hide tests: pytest/unittest skips, non-strict xfail, importorskip; JS skip/only/todo/fixme, x/f prefixes; JUnit Disabled/Assume; Go Skip, Short(); Rust ignore; RSpec, PHPUnit, C#, Swift skips; --deselect/-k not, collect_ignore, jest testPathIgnorePatterns. Runs: commit, agent write, turn's end; only additions judged. Friction: computed names evade it. Waiver: 'chock: allow test-skip' same line; agent: only if in HEAD.",
  "misses": null,
  "where": [
    "write",
    "turn-end"
  ],
  "groups": [
    "test-integrity"
  ],
  "eval_cases": 90,
  "eval_executed": 89,
  "latest": {
    "version": "0.1.0",
    "date": "2026-10-02",
    "change": "v2 (roadmap HP07). Python is read from the syntax tree, with imports resolved: markers anywhere (decorator, `pytestmark`, `pytest.param(marks=...)`, `add_marker`), `skipif`, `xfail` unless `strict=True` without `run=False`, runtime `pytest.skip`/`xfail`/`importorskip` (module level included), `skipTest`, `SkipTest`, `unittest.skip*`/`expectedFailure`, aliases (`from pytest import mark as m`, `from unittest import skip as later`) and `getattr(..., 'skip')`. A file that does not parse is read as text. Other languages by extension: JS/TS `skip/only/todo/fixme/skipIf/runIf` on any it/describe/test chain (`it.concurrent.skip`, `describe.skip.each`), `.each(table).skip` matched as a group, `it/test.fails`, `x`/`f` prefixes (`xtest`, `fit`, `fdescribe`), mocha `this.skip()`; JVM `@Disabled*`, `@Ignore*`, `@EnabledIf/On/For*`, `Assume*`/`assume*`/`assumingThat`, TestNG `enabled = false`/`SkipException`, Kotest `xtest`/`config(enabled = false)`; Go `.Skip*()` on a testing receiver and `testing.Short()` guards that return or skip; Rust `#[ignore]` and `cfg_attr(..., ignore)` in every .rs file (the attribute only marks tests); Ruby statement-initial `x`/`f` prefixes, `skip`, `pending`, and `:skip`/`skip:`/`focus:` example metadata; PHPUnit `markTestSkipped/Incomplete`; C# `[Fact/Theory(Skip=)]`, `[Ignore]`, `[Explicit]`, `Skip.If`, `Assert.Ignore/Inconclusive`, `Assume.*`; Swift `XCTSkip*`, `XCTExpectFailure`, `.disabled(`. String literals are blanked first, so a title that says skip is not one. A test-path file with any other extension keeps v1's pattern. Runner configs anywhere by base name: pytest.ini, pytest.toml, pyproject.toml, setup.cfg, tox.ini lines (in a pytest section, or running pytest) with `--deselect`, `--ignore`/`--ignore-glob` (not `--ignore-installed`) or `-k ... not`; conftest.py `collect_ignore`/`collect_ignore_glob` entries, `pytest_ignore_collect`, and item removal or `pytest_deselected` in `pytest_collection_modifyitems`; jest.config.* and package.json `testPathIgnorePatterns`, one finding per entry (Jest's default `/node_modules/` aside), the whole list when an entry is not a string. Test paths widen beyond protect-test-integrity's (kept as `TEST_PATH`) to `[Tt]ests/`, `[Ss]pecs/`, e2e/, cypress/, playwright/, `*_spec.rb`, `*_test.rb`, `*Test(s).java/kt/kts/groovy/scala/cs/php/swift`, `*.test.*`, `*.spec.*`. Keys stay rule + enclosing test + detail: the normalized line, a Python skip's whole decorator or statement behind its guards, a list entry's value, so a moved skip or a reordered pattern is old. Eval cases tc-027 to tc-075."
  },
  "agent_labels": {
    "claude-code": {
      "keyword": "block",
      "says": "blocks on an agent's file writes and at turn end"
    },
    "cursor": {
      "keyword": "block",
      "says": "blocks on an agent's file writes and at turn end"
    },
    "codex": {
      "keyword": "block",
      "says": "blocks on an agent's file writes and at turn end. If the hook errors, the action goes through (not witnessed; the vendor's row is only partly live-run)"
    },
    "copilot": {
      "keyword": "block",
      "says": "blocks at turn end only. It does not check a file write when it happens. If the hook errors, the action goes through (not witnessed; the vendor's row is only partly live-run)"
    },
    "devin": {
      "keyword": "block",
      "says": "blocks at turn end only. It does not check a file write when it happens. If the hook errors, the action goes through (vendor docs only, not witnessed)"
    },
    "grok": {
      "keyword": "ungraded",
      "says": "Not graded yet for Grok"
    },
    "goose": {
      "keyword": "ungraded",
      "says": "Not graded yet for goose"
    },
    "antigravity": {
      "keyword": "ungraded",
      "says": "Not graded yet for Antigravity"
    },
    "openhands": {
      "keyword": "ungraded",
      "says": "Not graded yet for OpenHands"
    },
    "kimi-code": {
      "keyword": "ungraded",
      "says": "Not graded yet for Kimi Code"
    },
    "factory-droid": {
      "keyword": "ungraded",
      "says": "Not graded yet for Factory Droid"
    }
  },
  "source_url": "https://github.com/open-coder-ai/chock-catalog/tree/1e60d211c1bb767152c6ab0167932da06ab3a10f/base/block-test-skips",
  "enforces": "enforced-at-commit",
  "examples": [
    {
      "word": "Refused",
      "prompt": "A failing pytest test is marked @pytest.mark.skip.",
      "command": null
    },
    {
      "word": "Allowed",
      "prompt": "A doc page about testing shows @pytest.mark.skip in an example.",
      "command": null
    }
  ]
}
