testguard-cli 0.9.2__tar.gz → 0.9.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (305) hide show
  1. testguard_cli-0.9.4/.github/scripts/approve-held-runs.sh +64 -0
  2. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/.github/workflows/release.yml +5 -2
  3. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/.github/workflows/scheduled-release.yml +4 -50
  4. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/CHANGELOG.md +33 -0
  5. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/PKG-INFO +5 -5
  6. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/README.md +4 -4
  7. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/action.yml +1 -1
  8. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/docs/testguard-explained.html +1 -1
  9. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/docs/testguard-explained.pdf +0 -0
  10. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/package-lock.json +2 -2
  11. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/package.json +1 -1
  12. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/packaging/gitlab/testguard.gitlab-ci.yml +2 -2
  13. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/packaging/homebrew/testguard.rb +2 -2
  14. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/pyproject.toml +1 -1
  15. testguard_cli-0.9.4/test/release-approval.test.mjs +78 -0
  16. testguard_cli-0.9.4/test/vitest-config.test.mjs +11 -0
  17. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/testguard.claims.json +100 -0
  18. testguard_cli-0.9.4/vitest.config.mjs +11 -0
  19. testguard_cli-0.9.2/vitest.config.mjs +0 -9
  20. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/.agents/skills/testguard/SKILL.md +0 -0
  21. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/.codex/hooks.json +0 -0
  22. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/.docguard.json +0 -0
  23. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/.docguardignore +0 -0
  24. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/.gitattributes +0 -0
  25. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  26. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  27. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  28. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/.github/dependabot.yml +0 -0
  29. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/.github/scripts/build-one-pager.mjs +0 -0
  30. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/.github/scripts/check-cost-budget.mjs +0 -0
  31. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/.github/scripts/check-python-fixture.mjs +0 -0
  32. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/.github/scripts/install-smoke.mjs +0 -0
  33. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/.github/scripts/sync-release-version.mjs +0 -0
  34. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/.github/workflows/auto-merge.yml +0 -0
  35. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/.github/workflows/ci.yml +0 -0
  36. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/.github/workflows/supply-chain.yml +0 -0
  37. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/.gitignore +0 -0
  38. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/.npmignore +0 -0
  39. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/.npmrc +0 -0
  40. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/.pre-commit-config.yaml +0 -0
  41. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/.pre-commit-hooks.yaml +0 -0
  42. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/AGENTS.md +0 -0
  43. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/CLAUDE.md +0 -0
  44. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/CODE_OF_CONDUCT.md +0 -0
  45. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/CONTRIBUTING.md +0 -0
  46. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/DRIFT-LOG.md +0 -0
  47. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/LICENSE +0 -0
  48. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/PRIVACY.md +0 -0
  49. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/SECURITY.md +0 -0
  50. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/SUPPORT.md +0 -0
  51. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/bench/README.md +0 -0
  52. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/cli/testguard.mjs +0 -0
  53. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/docs-canonical/ARCHITECTURE.md +0 -0
  54. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/docs-canonical/DATA-MODEL.md +0 -0
  55. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/docs-canonical/ENVIRONMENT.md +0 -0
  56. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/docs-canonical/REQUIREMENTS.md +0 -0
  57. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/docs-canonical/SECURITY.md +0 -0
  58. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/docs-canonical/TEST-SPEC.md +0 -0
  59. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/fixtures/known-answer/.gitignore +0 -0
  60. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/fixtures/known-answer/README.md +0 -0
  61. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/fixtures/known-answer/expected.json +0 -0
  62. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/fixtures/known-answer/package.json +0 -0
  63. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/fixtures/known-answer/src/export.mjs +0 -0
  64. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/fixtures/known-answer/src/redact.mjs +0 -0
  65. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/fixtures/known-answer/test/export-mocked.test.mjs +0 -0
  66. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/fixtures/known-answer/test/flaky.test.mjs +0 -0
  67. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/fixtures/known-answer/test/redact.test.mjs +0 -0
  68. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/fixtures/known-answer/testguard.claims.json +0 -0
  69. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/fixtures/known-answer/vitest.config.mjs +0 -0
  70. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/fixtures/known-answer-jest/.gitignore +0 -0
  71. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/fixtures/known-answer-jest/README.md +0 -0
  72. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/fixtures/known-answer-jest/expected.json +0 -0
  73. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/fixtures/known-answer-jest/jest.config.js +0 -0
  74. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/fixtures/known-answer-jest/package.json +0 -0
  75. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/fixtures/known-answer-jest/src/export.js +0 -0
  76. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/fixtures/known-answer-jest/src/redact.js +0 -0
  77. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/fixtures/known-answer-jest/test/export-mocked.test.js +0 -0
  78. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/fixtures/known-answer-jest/test/flaky.test.js +0 -0
  79. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/fixtures/known-answer-jest/test/redact.test.js +0 -0
  80. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/fixtures/known-answer-jest/testguard.claims.json +0 -0
  81. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/fixtures/known-answer-playwright/.gitignore +0 -0
  82. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/fixtures/known-answer-playwright/README.md +0 -0
  83. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/fixtures/known-answer-playwright/e2e/flaky.spec.mjs +0 -0
  84. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/fixtures/known-answer-playwright/e2e/toggle.spec.mjs +0 -0
  85. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/fixtures/known-answer-playwright/expected.json +0 -0
  86. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/fixtures/known-answer-playwright/package-lock.json +0 -0
  87. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/fixtures/known-answer-playwright/package.json +0 -0
  88. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/fixtures/known-answer-playwright/playwright.config.mjs +0 -0
  89. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/fixtures/known-answer-playwright/src/toggle.mjs +0 -0
  90. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/fixtures/known-answer-playwright/test/toggle.test.mjs +0 -0
  91. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/fixtures/known-answer-playwright/test-results/.last-run.json +0 -0
  92. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/fixtures/known-answer-playwright/testguard.claims.json +0 -0
  93. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/fixtures/known-answer-playwright/vitest.config.mjs +0 -0
  94. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/fixtures/known-answer-python/.gitignore +0 -0
  95. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/fixtures/known-answer-python/README.md +0 -0
  96. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/fixtures/known-answer-python/demo/__init__.py +0 -0
  97. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/fixtures/known-answer-python/demo/export.py +0 -0
  98. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/fixtures/known-answer-python/demo/orphan.py +0 -0
  99. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/fixtures/known-answer-python/demo/pipeline.py +0 -0
  100. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/fixtures/known-answer-python/demo/redact.py +0 -0
  101. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/fixtures/known-answer-python/expected.json +0 -0
  102. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/fixtures/known-answer-python/testguard.claims.json +0 -0
  103. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/fixtures/known-answer-python/tests/test_export_mocked.py +0 -0
  104. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/fixtures/known-answer-python/tests/test_flaky.py +0 -0
  105. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/fixtures/known-answer-python/tests/test_patched.py +0 -0
  106. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/fixtures/known-answer-python/tests/test_redact.py +0 -0
  107. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/GATE-SEMANTICS.md +0 -0
  108. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/README.md +0 -0
  109. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/examples/baseline.json +0 -0
  110. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/examples/brief.json +0 -0
  111. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/examples/calibration-websec.json +0 -0
  112. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/examples/calibration.json +0 -0
  113. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/examples/claims-methods.json +0 -0
  114. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/examples/claims.json +0 -0
  115. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/examples/evidence-disturbed-run.json +0 -0
  116. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/examples/evidence-negative-control.json +0 -0
  117. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/examples/evidence-provisional.json +0 -0
  118. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/examples/evidence-python.json +0 -0
  119. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/examples/evidence-scan-method.json +0 -0
  120. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/examples/evidence.json +0 -0
  121. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/examples/gate.json +0 -0
  122. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/examples/ignore.json +0 -0
  123. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/examples/replay.json +0 -0
  124. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/examples/status.json +0 -0
  125. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/baseline.bad-fingerprint-key.json +0 -0
  126. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/baseline.zero-count.json +0 -0
  127. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/brief.text-without-heading.json +0 -0
  128. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/brief.unknown-verdict-key.json +0 -0
  129. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/calibration.backoff-cell-not-wilson.json +0 -0
  130. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/calibration.breakdown-does-not-sum-to-n.json +0 -0
  131. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/calibration.ci-not-wilson.json +0 -0
  132. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/calibration.compound-key-arity-mismatch.json +0 -0
  133. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/calibration.fallback-without-basis.json +0 -0
  134. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/calibration.p-not-positives-over-n.json +0 -0
  135. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/calibration.p-outside-ci.json +0 -0
  136. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/calibration.positives-exceed-n.json +0 -0
  137. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/claims.absolute-path.json +0 -0
  138. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/claims.duplicate-fault-id.json +0 -0
  139. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/claims.fault-injection-without-a-substitution.json +0 -0
  140. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/claims.method-detail-on-a-specified-method.json +0 -0
  141. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/claims.missing-provenance.json +0 -0
  142. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/claims.noop-fault.json +0 -0
  143. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/claims.occurrence-exceeds-hits.json +0 -0
  144. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/claims.parent-traversal.json +0 -0
  145. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/evidence.annotated-signal-without-reason.json +0 -0
  146. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/evidence.attribute-signal-not-a-defender.json +0 -0
  147. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/evidence.attribute-signal-without-attributes.json +0 -0
  148. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/evidence.byrunner-file-not-resolved.json +0 -0
  149. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/evidence.contention-without-runners.json +0 -0
  150. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/evidence.discovered-defender-mocks-subject.json +0 -0
  151. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/evidence.fault-injection-without-its-evidence.json +0 -0
  152. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/evidence.flaky-defender-without-flakiness.json +0 -0
  153. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/evidence.ignored-dirty-on-snapshot.json +0 -0
  154. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/evidence.killed-by-non-assertion.json +0 -0
  155. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/evidence.killed-on-red-baseline.json +0 -0
  156. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/evidence.killed-without-n-runs.json +0 -0
  157. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/evidence.method-detail-on-an-injecting-run.json +0 -0
  158. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/evidence.negative-control-not-reached-but-survived.json +0 -0
  159. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/evidence.negative-control-reached-on-a-kill.json +0 -0
  160. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/evidence.probe-error-without-message.json +0 -0
  161. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/evidence.provisional-flag-on-confirmed-run.json +0 -0
  162. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/evidence.rank-extra-property.json +0 -0
  163. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/evidence.restore-skipped-in-place.json +0 -0
  164. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/evidence.single-run-without-provisional.json +0 -0
  165. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/evidence.target-not-imported-but-killed.json +0 -0
  166. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/evidence.undeclared-killers-without-reason.json +0 -0
  167. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/evidence.unknown-verdict.json +0 -0
  168. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/evidence.unverifiable-without-reason.json +0 -0
  169. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/evidence.wrong-fingerprint.json +0 -0
  170. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/gate.counts-disagree.json +0 -0
  171. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/gate.exit-zero-with-uncovered.json +0 -0
  172. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/gate.ignore-cover-without-pattern.json +0 -0
  173. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/ignore.missing-reason.json +0 -0
  174. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/ignore.short-reason.json +0 -0
  175. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/replay.blind-with-a-failing-run.json +0 -0
  176. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/replay.duplicate-patch-id.json +0 -0
  177. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/status.claim-without-file.json +0 -0
  178. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/status.clean-with-new-findings.json +0 -0
  179. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/status.invalid-anchor-hidden.json +0 -0
  180. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/status.unclaimed-hidden-behind-unproven.json +0 -0
  181. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/invalid/status.write-test-without-target.json +0 -0
  182. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/conformance/schemas.test.mjs +0 -0
  183. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/lib/fingerprint.mjs +0 -0
  184. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/lib/validate.mjs +0 -0
  185. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/lib/wilson.mjs +0 -0
  186. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/schemas/baseline.schema.json +0 -0
  187. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/schemas/brief.schema.json +0 -0
  188. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/schemas/calibration.schema.json +0 -0
  189. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/schemas/claims.schema.json +0 -0
  190. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/schemas/common.schema.json +0 -0
  191. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/schemas/evidence.schema.json +0 -0
  192. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/schemas/gate.schema.json +0 -0
  193. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/schemas/ignore.schema.json +0 -0
  194. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/schemas/replay.schema.json +0 -0
  195. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/spec/schemas/status.schema.json +0 -0
  196. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/admit/admit.mjs +0 -0
  197. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/baseline/baseline.mjs +0 -0
  198. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/brief/brief.mjs +0 -0
  199. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/claims/anchors.mjs +0 -0
  200. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/claims/annotations.mjs +0 -0
  201. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/claims/load.mjs +0 -0
  202. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/claims/removed.mjs +0 -0
  203. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/cli.mjs +0 -0
  204. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/commands/admit.mjs +0 -0
  205. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/commands/baseline.mjs +0 -0
  206. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/commands/brief.mjs +0 -0
  207. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/commands/claims.mjs +0 -0
  208. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/commands/gate.mjs +0 -0
  209. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/commands/init.mjs +0 -0
  210. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/commands/mcp.mjs +0 -0
  211. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/commands/probe.mjs +0 -0
  212. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/commands/replay.mjs +0 -0
  213. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/commands/scaffold.mjs +0 -0
  214. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/commands/status.mjs +0 -0
  215. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/evidence/writer.mjs +0 -0
  216. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/gate/changed.mjs +0 -0
  217. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/git.mjs +0 -0
  218. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/init/init.mjs +0 -0
  219. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/init/templates/SKILL.md +0 -0
  220. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/mcp/server.mjs +0 -0
  221. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/mcp/tools.mjs +0 -0
  222. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/probe/attribution.mjs +0 -0
  223. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/probe/classify.mjs +0 -0
  224. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/probe/contention.mjs +0 -0
  225. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/probe/cost.mjs +0 -0
  226. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/probe/discover.mjs +0 -0
  227. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/probe/independence.mjs +0 -0
  228. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/probe/inject.mjs +0 -0
  229. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/probe/mocks.mjs +0 -0
  230. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/probe/probe.mjs +0 -0
  231. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/probe/progress.mjs +0 -0
  232. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/probe/pyimports.mjs +0 -0
  233. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/probe/rank.mjs +0 -0
  234. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/probe/runners/index.mjs +0 -0
  235. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/probe/runners/jest.mjs +0 -0
  236. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/probe/runners/playwright.mjs +0 -0
  237. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/probe/runners/python/_testguard_pytest_plugin.py +0 -0
  238. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/probe/runners/python/_testguard_report.py +0 -0
  239. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/probe/runners/python/_testguard_unittest_main.py +0 -0
  240. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/probe/runners/python.mjs +0 -0
  241. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/probe/runners/shared.mjs +0 -0
  242. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/probe/runners/vitest.mjs +0 -0
  243. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/probe/worktree.mjs +0 -0
  244. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/render.mjs +0 -0
  245. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/replay/label.mjs +0 -0
  246. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/replay/replay.mjs +0 -0
  247. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/scaffold/producers.mjs +0 -0
  248. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/scaffold/producers.python.mjs +0 -0
  249. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/scaffold/scaffold.mjs +0 -0
  250. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/status/status.mjs +0 -0
  251. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/util/glob.mjs +0 -0
  252. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/src/util/hash.mjs +0 -0
  253. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/test/admit.test.mjs +0 -0
  254. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/test/annotations.test.mjs +0 -0
  255. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/test/attribution.test.mjs +0 -0
  256. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/test/baseline.test.mjs +0 -0
  257. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/test/brief.test.mjs +0 -0
  258. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/test/calibration.test.mjs +0 -0
  259. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/test/claims-anchors.test.mjs +0 -0
  260. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/test/claims-since.test.mjs +0 -0
  261. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/test/classify.test.mjs +0 -0
  262. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/test/contention.test.mjs +0 -0
  263. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/test/cost.test.mjs +0 -0
  264. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/test/discover.test.mjs +0 -0
  265. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/test/gate.test.mjs +0 -0
  266. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/test/gitlab-template.test.mjs +0 -0
  267. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/test/glob.test.mjs +0 -0
  268. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/test/independence.test.mjs +0 -0
  269. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/test/init.test.mjs +0 -0
  270. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/test/inject.test.mjs +0 -0
  271. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/test/label.test.mjs +0 -0
  272. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/test/mcp.test.mjs +0 -0
  273. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/test/mocks.test.mjs +0 -0
  274. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/test/negative-control.test.mjs +0 -0
  275. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/test/one-pager.test.mjs +0 -0
  276. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/test/probe-error.test.mjs +0 -0
  277. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/test/probe-preconditions.test.mjs +0 -0
  278. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/test/probe.fixture.test.mjs +0 -0
  279. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/test/probe.jest.test.mjs +0 -0
  280. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/test/probe.playwright.test.mjs +0 -0
  281. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/test/probe.python.test.mjs +0 -0
  282. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/test/progress.test.mjs +0 -0
  283. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/test/pyimports.test.mjs +0 -0
  284. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/test/rank-aliases.test.mjs +0 -0
  285. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/test/release-sync.test.mjs +0 -0
  286. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/test/replay-verdict.test.mjs +0 -0
  287. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/test/replay.test.mjs +0 -0
  288. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/test/runner-argv.test.mjs +0 -0
  289. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/test/runner-command.test.mjs +0 -0
  290. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/test/runner-playwright.test.mjs +0 -0
  291. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/test/runner-python.test.mjs +0 -0
  292. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/test/runner-vitest.test.mjs +0 -0
  293. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/test/samples/playwright-report.json +0 -0
  294. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/test/samples/python-report-collect-error.json +0 -0
  295. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/test/samples/python-report.json +0 -0
  296. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/test/scaffold.python.test.mjs +0 -0
  297. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/test/scaffold.test.mjs +0 -0
  298. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/test/snapshot.test.mjs +0 -0
  299. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/test/status.test.mjs +0 -0
  300. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/test/worktree.test.mjs +0 -0
  301. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/test/writer.test.mjs +0 -0
  302. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/testguard.cost-budget.json +0 -0
  303. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/testguard.ignore.json +0 -0
  304. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/testguard_cli/__init__.py +0 -0
  305. {testguard_cli-0.9.2 → testguard_cli-0.9.4}/testguard_cli/wrapper.py +0 -0
@@ -0,0 +1,64 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # Clear GitHub's first-time-contributor hold from workflow runs created for a
4
+ # GITHUB_TOKEN-authored pull request. The repository requires that approval,
5
+ # and github-actions[bot] can never graduate from it because it does not author
6
+ # the squash commit that lands on main.
7
+
8
+ set -euo pipefail
9
+
10
+ HEAD_SHA="${1:?usage: approve-held-runs.sh HEAD_SHA PR_URL}"
11
+ PR_URL="${2:?usage: approve-held-runs.sh HEAD_SHA PR_URL}"
12
+ : "${GITHUB_REPOSITORY:?GITHUB_REPOSITORY is required}"
13
+
14
+ POLL_SECONDS="${TESTGUARD_HELD_RUN_POLL_SECONDS:-10}"
15
+ approved=0
16
+
17
+ held_ids() {
18
+ gh api "repos/${GITHUB_REPOSITORY}/actions/runs?head_sha=${HEAD_SHA}" \
19
+ --jq '[.workflow_runs[] | select(.status == "action_required" or .conclusion == "action_required") | .id] | .[]'
20
+ }
21
+
22
+ held_urls() {
23
+ gh api "repos/${GITHUB_REPOSITORY}/actions/runs?head_sha=${HEAD_SHA}" \
24
+ --jq '[.workflow_runs[] | select(.status == "action_required" or .conclusion == "action_required") | .html_url] | .[]'
25
+ }
26
+
27
+ echo "Clearing held workflow runs on $HEAD_SHA"
28
+ for attempt in 1 2 3 4 5 6; do
29
+ # Fail closed. Treating an API failure as "no held runs" would report that
30
+ # auto-merge can proceed while leaving the PR queued forever.
31
+ if ! HELD=$(held_ids); then
32
+ echo "::error::Could not inspect workflow approval holds for $HEAD_SHA; auto-merge on $PR_URL may remain blocked."
33
+ exit 1
34
+ fi
35
+
36
+ for id in $HELD; do
37
+ if gh api -X POST "repos/${GITHUB_REPOSITORY}/actions/runs/${id}/approve" >/dev/null 2>&1; then
38
+ echo " approved run $id"
39
+ approved=$((approved + 1))
40
+ else
41
+ # A run can leave action_required between the query and the POST. The
42
+ # final query decides whether that race is harmless.
43
+ echo " run $id needed no approval"
44
+ fi
45
+ done
46
+
47
+ # Runs appear asynchronously. Once one was approved, the first empty query
48
+ # is terminal; when this repository gate does not apply, three empty polls
49
+ # are enough to establish that without paying the full minute.
50
+ if [ -z "$HELD" ] && { [ "$approved" -gt 0 ] || [ "$attempt" -ge 3 ]; }; then
51
+ break
52
+ fi
53
+ if [ "$attempt" -lt 6 ]; then sleep "$POLL_SECONDS"; fi
54
+ done
55
+
56
+ if ! STILL=$(held_urls); then
57
+ echo "::error::Could not verify workflow approval holds for $HEAD_SHA; auto-merge on $PR_URL may remain blocked."
58
+ exit 1
59
+ fi
60
+ if [ -n "$STILL" ]; then
61
+ echo "::error::Workflow runs are still held for approval, so auto-merge on $PR_URL will wait forever. Approve them, or re-run this workflow: $STILL"
62
+ exit 1
63
+ fi
64
+ echo "✅ no run is held for approval; auto-merge can complete"
@@ -236,8 +236,10 @@ jobs:
236
236
  # change lands as a bot PR with native auto-merge armed, and this job
237
237
  # dispatches ci.yml on the branch itself — a PR opened with GITHUB_TOKEN
238
238
  # gets no pull_request run, but workflow_dispatch is the documented
239
- # exception. That also means the merge triggers nothing here; the hourly
240
- # sweep observes the merged formula and finds brew_missing=false.
239
+ # exception. The PR's own runs may still appear held for first-time-
240
+ # contributor approval, so this job clears those holds before returning.
241
+ # That also means the merge triggers nothing here; the hourly sweep
242
+ # observes the merged formula and finds brew_missing=false.
241
243
  #
242
244
  # Idempotent: an existing branch is reused, an existing open PR is left
243
245
  # alone (CI re-dispatched only if its head has no check runs), a closed
@@ -334,3 +336,4 @@ jobs:
334
336
  else
335
337
  echo "✅ $HEAD_SHA already has $RUNS check run(s)"
336
338
  fi
339
+ .github/scripts/approve-held-runs.sh "$HEAD_SHA" "$PR"
@@ -170,56 +170,10 @@ jobs:
170
170
  echo "✅ $HEAD_SHA already has $RUNS check run(s)"
171
171
  fi
172
172
 
173
- # ── The third GITHUB_TOKEN wall, and the last one. ──
174
- # The `pull_request` runs this PR creates are held at
175
- # `action_required`: the repository requires approval from
176
- # first-time contributors, and `github-actions[bot]` is
177
- # PERMANENTLY one — it never authors a merged commit, so it can
178
- # never graduate. Those held runs leave check suites QUEUED on the
179
- # head sha forever, the status rollup never reaches a terminal
180
- # state, and auto-merge waits on it even though the required
181
- # contexts (test 20/22/24) are already green from the dispatched
182
- # run above. v0.9.0 sat here until a human clicked Approve.
183
- #
184
- # GITHUB_TOKEN may clear it: `actions: write` carries the approve
185
- # permission, measured 201 on a bot PR's own held run. It may not
186
- # approve a REVIEW, which is a different gate and still ours alone.
187
- #
188
- # Runs appear asynchronously, so poll. Approving an already-running
189
- # run answers 403 "not waiting for approval" — success, not failure.
190
- echo "Clearing held workflow runs on $HEAD_SHA"
191
- approved=0
192
- for attempt in 1 2 3 4 5 6; do
193
- HELD=$(gh api "repos/${GITHUB_REPOSITORY}/actions/runs?head_sha=${HEAD_SHA}" \
194
- --jq '[.workflow_runs[] | select(.status == "action_required" or .conclusion == "action_required") | .id] | .[]' 2>/dev/null || true)
195
- for id in $HELD; do
196
- if gh api -X POST "repos/${GITHUB_REPOSITORY}/actions/runs/${id}/approve" >/dev/null 2>&1; then
197
- echo " approved run $id"
198
- approved=$((approved + 1))
199
- else
200
- echo " run $id needed no approval"
201
- fi
202
- done
203
- # Stop as soon as the picture is settled, rather than always
204
- # paying the full poll: nothing held after something was
205
- # approved means we are done, and nothing held by the third
206
- # look means the gate is not applying to this run at all.
207
- if [ -z "$HELD" ] && { [ "$approved" -gt 0 ] || [ "$attempt" -ge 3 ]; }; then
208
- break
209
- fi
210
- sleep 10
211
- done
212
-
213
- # Never leave this silent: a run still held here means auto-merge
214
- # will wait forever, which is the failure this whole block exists
215
- # to remove. Say so, and name what to click.
216
- STILL=$(gh api "repos/${GITHUB_REPOSITORY}/actions/runs?head_sha=${HEAD_SHA}" \
217
- --jq '[.workflow_runs[] | select(.status == "action_required" or .conclusion == "action_required") | .html_url] | .[]' 2>/dev/null || true)
218
- if [ -n "$STILL" ]; then
219
- echo "::error::Workflow runs are still held for approval, so auto-merge on $PR will wait forever. Approve them, or re-run this workflow: $STILL"
220
- exit 1
221
- fi
222
- echo "✅ no run is held for approval; auto-merge can complete"
173
+ # Clear the first-time-contributor holds on this bot-created PR's
174
+ # workflow runs. The Homebrew PR path uses the same helper so the
175
+ # two release automations cannot drift again.
176
+ .github/scripts/approve-held-runs.sh "$HEAD_SHA" "$PR"
223
177
  else
224
178
  cat /tmp/pr-err
225
179
  if grep -q 'not permitted to create or approve pull requests' /tmp/pr-err; then
@@ -7,6 +7,39 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.9.4] - 2026-09-19
11
+
12
+ Automated weekly release — everything merged since `v0.9.3`.
13
+
14
+ ### Changed
15
+
16
+ - fix(test): ignore nested agent worktrees (#133)
17
+ - chore(homebrew): sha256 for v0.9.3 (#131)
18
+
19
+
20
+ ### Fixed
21
+
22
+ - The canonical `npm test` command no longer collects suites from live nested
23
+ worktrees under `.claude/`. A parked checkout can remain safely available
24
+ without its unfinished tests or fixtures contaminating the main tree's gate.
25
+
26
+ ## [0.9.3] - 2026-09-19
27
+
28
+ Automated weekly release — everything merged since `v0.9.2`.
29
+
30
+ ### Changed
31
+
32
+ - fix(release): clear held Homebrew PR runs (#129)
33
+ - chore(homebrew): sha256 for v0.9.2 (#128)
34
+
35
+
36
+ ### Fixed
37
+
38
+ - Bot-created Homebrew checksum PRs now clear GitHub's first-time-contributor
39
+ workflow holds themselves, using the same fail-closed helper as scheduled
40
+ release PRs. A release no longer finishes publishing while leaving its final
41
+ formula update waiting for a manual Approve click.
42
+
10
43
  ## [0.9.2] - 2026-09-19
11
44
 
12
45
  Automated weekly release — everything merged since `v0.9.1`.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: testguard-cli
3
- Version: 0.9.2
3
+ Version: 0.9.4
4
4
  Summary: Breaks your code on purpose and reports every promise your tests did not notice breaking. Mutation testing bound to the claims a project makes — vitest, jest, Playwright, pytest and unittest. Ships the Node.js CLI (requires Node.js 20+).
5
5
  Project-URL: Homepage, https://github.com/raccioly/testguard
6
6
  Project-URL: Documentation, https://github.com/raccioly/testguard#readme
@@ -151,9 +151,9 @@ raises coverage. TestGuard admits it because it fails when the claim is false.
151
151
  | npm | `npm i -D testguard-cli` then `npx testguard probe` |
152
152
  | pip | `pip install testguard-cli` then `testguard probe` (needs Node ≥ 20) |
153
153
  | Homebrew | `brew tap raccioly/tap && brew install testguard` |
154
- | GitHub Action | `uses: raccioly/testguard@v0.9.2` — see [`action.yml`](./action.yml) |
154
+ | GitHub Action | `uses: raccioly/testguard@v0.9.4` — see [`action.yml`](./action.yml) |
155
155
  | pre-commit | `repo: https://github.com/raccioly/testguard`, hooks `testguard-claims`, `testguard-probe` |
156
- | GitLab CI | `include: - remote: https://raw.githubusercontent.com/raccioly/testguard/v0.9.2/packaging/gitlab/testguard.gitlab-ci.yml` with `inputs:` — see [`packaging/gitlab/`](./packaging/gitlab/testguard.gitlab-ci.yml) |
156
+ | GitLab CI | `include: - remote: https://raw.githubusercontent.com/raccioly/testguard/v0.9.4/packaging/gitlab/testguard.gitlab-ci.yml` with `inputs:` — see [`packaging/gitlab/`](./packaging/gitlab/testguard.gitlab-ci.yml) |
157
157
 
158
158
  Projects that set `min-release-age` in `.npmrc` cannot see a version published
159
159
  less than that many days ago (`ENOVERSIONS`); install that one with
@@ -493,12 +493,12 @@ detected base that does not resolve is a warning for `status` and `brief`
493
493
  # GitHub Actions
494
494
  - uses: actions/checkout@v4
495
495
  with: { fetch-depth: 0 }
496
- - uses: raccioly/testguard@v0.9.2
496
+ - uses: raccioly/testguard@v0.9.4
497
497
  with: { command: gate }
498
498
 
499
499
  # GitLab CI — the component-shaped template: gate + probe, brief as an artifact and, opted in, as a merge-request note
500
500
  include:
501
- - remote: 'https://raw.githubusercontent.com/raccioly/testguard/v0.9.2/packaging/gitlab/testguard.gitlab-ci.yml'
501
+ - remote: 'https://raw.githubusercontent.com/raccioly/testguard/v0.9.4/packaging/gitlab/testguard.gitlab-ci.yml'
502
502
  inputs: { dir: backend, post_note: true } # post_note needs TESTGUARD_GITLAB_TOKEN (api scope); one note, updated in place
503
503
  ```
504
504
 
@@ -127,9 +127,9 @@ raises coverage. TestGuard admits it because it fails when the claim is false.
127
127
  | npm | `npm i -D testguard-cli` then `npx testguard probe` |
128
128
  | pip | `pip install testguard-cli` then `testguard probe` (needs Node ≥ 20) |
129
129
  | Homebrew | `brew tap raccioly/tap && brew install testguard` |
130
- | GitHub Action | `uses: raccioly/testguard@v0.9.2` — see [`action.yml`](./action.yml) |
130
+ | GitHub Action | `uses: raccioly/testguard@v0.9.4` — see [`action.yml`](./action.yml) |
131
131
  | pre-commit | `repo: https://github.com/raccioly/testguard`, hooks `testguard-claims`, `testguard-probe` |
132
- | GitLab CI | `include: - remote: https://raw.githubusercontent.com/raccioly/testguard/v0.9.2/packaging/gitlab/testguard.gitlab-ci.yml` with `inputs:` — see [`packaging/gitlab/`](./packaging/gitlab/testguard.gitlab-ci.yml) |
132
+ | GitLab CI | `include: - remote: https://raw.githubusercontent.com/raccioly/testguard/v0.9.4/packaging/gitlab/testguard.gitlab-ci.yml` with `inputs:` — see [`packaging/gitlab/`](./packaging/gitlab/testguard.gitlab-ci.yml) |
133
133
 
134
134
  Projects that set `min-release-age` in `.npmrc` cannot see a version published
135
135
  less than that many days ago (`ENOVERSIONS`); install that one with
@@ -469,12 +469,12 @@ detected base that does not resolve is a warning for `status` and `brief`
469
469
  # GitHub Actions
470
470
  - uses: actions/checkout@v4
471
471
  with: { fetch-depth: 0 }
472
- - uses: raccioly/testguard@v0.9.2
472
+ - uses: raccioly/testguard@v0.9.4
473
473
  with: { command: gate }
474
474
 
475
475
  # GitLab CI — the component-shaped template: gate + probe, brief as an artifact and, opted in, as a merge-request note
476
476
  include:
477
- - remote: 'https://raw.githubusercontent.com/raccioly/testguard/v0.9.2/packaging/gitlab/testguard.gitlab-ci.yml'
477
+ - remote: 'https://raw.githubusercontent.com/raccioly/testguard/v0.9.4/packaging/gitlab/testguard.gitlab-ci.yml'
478
478
  inputs: { dir: backend, post_note: true } # post_note needs TESTGUARD_GITLAB_TOKEN (api scope); one note, updated in place
479
479
  ```
480
480
 
@@ -46,7 +46,7 @@ inputs:
46
46
  version:
47
47
  description: 'testguard-cli version to run'
48
48
  required: false
49
- default: '0.9.2'
49
+ default: '0.9.4'
50
50
  node-version:
51
51
  description: 'Node.js version (20+)'
52
52
  required: false
@@ -144,7 +144,7 @@
144
144
  <div class="page">
145
145
  <div class="masthead">
146
146
  <div class="wordmark">Test<span class="mark">Guard</span></div>
147
- <div class="meta">Technical Brief · v0.9.2 · MIT</div>
147
+ <div class="meta">Technical Brief · v0.9.4 · MIT</div>
148
148
  </div>
149
149
 
150
150
  <h1>Your tests pass. That is not the same as your tests working.</h1>
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "testguard-cli",
3
- "version": "0.9.2",
3
+ "version": "0.9.4",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "testguard-cli",
9
- "version": "0.9.2",
9
+ "version": "0.9.4",
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
12
  "ajv": "8.20.0"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testguard-cli",
3
- "version": "0.9.2",
3
+ "version": "0.9.4",
4
4
  "description": "Breaks your code on purpose and reports every promise your tests did not notice breaking. Mutation testing bound to the claims a project makes — vitest, jest, Playwright, pytest and unittest.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -3,7 +3,7 @@
3
3
  # Include it from a project's .gitlab-ci.yml, pinned to a release:
4
4
  #
5
5
  # include:
6
- # - remote: 'https://raw.githubusercontent.com/raccioly/testguard/v0.9.2/packaging/gitlab/testguard.gitlab-ci.yml'
6
+ # - remote: 'https://raw.githubusercontent.com/raccioly/testguard/v0.9.4/packaging/gitlab/testguard.gitlab-ci.yml'
7
7
  # inputs:
8
8
  # dir: backend # where testguard.claims.json lives (default ".")
9
9
  # post_note: true # post the brief as a merge-request note (needs TESTGUARD_GITLAB_TOKEN, api scope)
@@ -29,7 +29,7 @@ spec:
29
29
  inputs:
30
30
  version:
31
31
  description: testguard-cli version to run
32
- default: "0.9.2"
32
+ default: "0.9.4"
33
33
  dir:
34
34
  description: directory whose test runner is invoked (where testguard.claims.json lives)
35
35
  default: "."
@@ -15,8 +15,8 @@
15
15
  class Testguard < Formula
16
16
  desc "Proves a test suite defends the claims a project makes"
17
17
  homepage "https://github.com/raccioly/testguard"
18
- url "https://registry.npmjs.org/testguard-cli/-/testguard-cli-0.9.2.tgz"
19
- sha256 "118c895b89b336b919ca61d9af35915fded75c27d08feeabaf2340d6e5a9a847"
18
+ url "https://registry.npmjs.org/testguard-cli/-/testguard-cli-0.9.4.tgz"
19
+ sha256 "3ab202d339b014ea5d8a11cc143bd1bdef6ea08120a513029f7537c288ba3195"
20
20
  license "MIT"
21
21
 
22
22
  depends_on "node"
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "testguard-cli"
7
- version = "0.9.2"
7
+ version = "0.9.4"
8
8
  description = "Breaks your code on purpose and reports every promise your tests did not notice breaking. Mutation testing bound to the claims a project makes — vitest, jest, Playwright, pytest and unittest. Ships the Node.js CLI (requires Node.js 20+)."
9
9
  readme = "README.md"
10
10
  license = { text = "MIT" }
@@ -0,0 +1,78 @@
1
+ import { chmodSync, mkdtempSync, readFileSync, writeFileSync } from 'node:fs';
2
+ import { tmpdir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ import { spawnSync } from 'node:child_process';
5
+ import { describe, expect, it } from 'vitest';
6
+
7
+ const ROOT = new URL('..', import.meta.url).pathname;
8
+ const SCRIPT = join(ROOT, '.github', 'scripts', 'approve-held-runs.sh');
9
+
10
+ const run = (scenario) => {
11
+ const dir = mkdtempSync(join(tmpdir(), 'tg-held-runs-'));
12
+ const state = join(dir, 'state');
13
+ const gh = join(dir, 'gh');
14
+ writeFileSync(gh, `#!/bin/sh
15
+ set -eu
16
+ case "$*" in
17
+ *'/approve'*)
18
+ printf 'approved\\n' >> "$FAKE_GH_STATE"
19
+ [ "$FAKE_GH_SCENARIO" != 'stuck' ]
20
+ ;;
21
+ *'.html_url'*)
22
+ if [ "$FAKE_GH_SCENARIO" = 'stuck' ]; then
23
+ printf 'https://github.example/runs/42\\n'
24
+ fi
25
+ ;;
26
+ *'.id'*)
27
+ if [ "$FAKE_GH_SCENARIO" = 'query-error' ]; then exit 2; fi
28
+ if [ "$FAKE_GH_SCENARIO" = 'stuck' ] || { [ "$FAKE_GH_SCENARIO" = 'held-clears' ] && [ ! -s "$FAKE_GH_STATE" ]; }; then
29
+ printf '42\\n'
30
+ fi
31
+ ;;
32
+ *) exit 64 ;;
33
+ esac
34
+ `);
35
+ chmodSync(gh, 0o755);
36
+ const result = spawnSync('/bin/bash', [SCRIPT, 'abc1234', 'https://github.example/pull/7'], {
37
+ encoding: 'utf8',
38
+ env: {
39
+ ...process.env,
40
+ PATH: `${dir}:/usr/bin:/bin`,
41
+ GITHUB_REPOSITORY: 'owner/repo',
42
+ FAKE_GH_SCENARIO: scenario,
43
+ FAKE_GH_STATE: state,
44
+ TESTGUARD_HELD_RUN_POLL_SECONDS: '0',
45
+ },
46
+ });
47
+ return { ...result, approvals: readFileSync(state, { encoding: 'utf8', flag: 'a+' }) };
48
+ };
49
+
50
+ describe('release workflow approval holds', () => {
51
+ it('both bot-created PR paths invoke the same approval helper', () => {
52
+ for (const workflow of ['scheduled-release.yml', 'release.yml']) {
53
+ const text = readFileSync(join(ROOT, '.github', 'workflows', workflow), 'utf8');
54
+ expect(text).toContain('.github/scripts/approve-held-runs.sh "$HEAD_SHA" "$PR"');
55
+ }
56
+ });
57
+
58
+ it('approves a held run and verifies that the hold cleared', () => {
59
+ const result = run('held-clears');
60
+ expect(result.status, result.stderr).toBe(0);
61
+ expect(result.approvals).toBe('approved\n');
62
+ expect(result.stdout).toMatch(/approved run 42/);
63
+ expect(result.stdout).toMatch(/no run is held for approval/);
64
+ });
65
+
66
+ it('fails closed when GitHub cannot report the approval state', () => {
67
+ const result = run('query-error');
68
+ expect(result.status).toBe(1);
69
+ expect(result.stdout).toMatch(/Could not inspect workflow approval holds/);
70
+ });
71
+
72
+ it('fails with the held run URL when approval never clears', () => {
73
+ const result = run('stuck');
74
+ expect(result.status).toBe(1);
75
+ expect(result.stdout).toMatch(/will wait forever/);
76
+ expect(result.stdout).toMatch(/https:\/\/github\.example\/runs\/42/);
77
+ });
78
+ });
@@ -0,0 +1,11 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import config from '../vitest.config.mjs';
3
+
4
+ describe('the root test boundary', () => {
5
+ it('never collects fixtures or agent-managed nested worktrees', () => {
6
+ expect(config.test.exclude).toEqual(expect.arrayContaining([
7
+ 'fixtures/**',
8
+ '.claude/**',
9
+ ]));
10
+ });
11
+ });
@@ -3777,6 +3777,106 @@
3777
3777
  "preflight",
3778
3778
  "cost"
3779
3779
  ]
3780
+ },
3781
+ {
3782
+ "id": "TG-RELEASE-BOT-CLEARS-HELD-RUNS",
3783
+ "statement": "Every GITHUB_TOKEN-authored release pull request clears first-time-contributor workflow holds before its creating workflow succeeds. Both the scheduled version PR and the post-publish Homebrew checksum PR use one fail-closed helper, so an API failure or a hold that remains visible is an error rather than a silently queued auto-merge.",
3784
+ "source": {
3785
+ "kind": "manual",
3786
+ "ref": "v0.9.2 Homebrew release field report"
3787
+ },
3788
+ "severity": "high",
3789
+ "producedBy": {
3790
+ "producer": "human",
3791
+ "by": "maintainer",
3792
+ "at": "2026-09-19T00:00:00Z"
3793
+ },
3794
+ "defendedBy": [
3795
+ "test/release-approval.test.mjs"
3796
+ ],
3797
+ "faults": [
3798
+ {
3799
+ "id": "F1",
3800
+ "description": "The post-publish Homebrew PR skips the approval helper and can remain queued after the release workflow reports success.",
3801
+ "faultClass": "statement-deleted",
3802
+ "file": ".github/workflows/release.yml",
3803
+ "find": " .github/scripts/approve-held-runs.sh \"$HEAD_SHA\" \"$PR\"",
3804
+ "replace": " echo \"approval hold check skipped\"",
3805
+ "producedBy": {
3806
+ "producer": "human",
3807
+ "by": "maintainer",
3808
+ "at": "2026-09-19T00:00:00Z"
3809
+ }
3810
+ },
3811
+ {
3812
+ "id": "F2",
3813
+ "description": "The scheduled release PR stops using the shared approval helper, allowing the two bot-created PR paths to drift again.",
3814
+ "faultClass": "statement-deleted",
3815
+ "file": ".github/workflows/scheduled-release.yml",
3816
+ "find": " .github/scripts/approve-held-runs.sh \"$HEAD_SHA\" \"$PR\"",
3817
+ "replace": " echo \"approval hold check skipped\"",
3818
+ "producedBy": {
3819
+ "producer": "human",
3820
+ "by": "maintainer",
3821
+ "at": "2026-09-19T00:00:00Z"
3822
+ }
3823
+ },
3824
+ {
3825
+ "id": "F3",
3826
+ "description": "A failed GitHub API query is treated as an empty hold list, so the helper reports success without knowing whether auto-merge is blocked.",
3827
+ "faultClass": "condition-forced",
3828
+ "file": ".github/scripts/approve-held-runs.sh",
3829
+ "find": " if ! HELD=$(held_ids); then",
3830
+ "replace": " if HELD=$(held_ids); then",
3831
+ "producedBy": {
3832
+ "producer": "human",
3833
+ "by": "maintainer",
3834
+ "at": "2026-09-19T00:00:00Z"
3835
+ }
3836
+ }
3837
+ ],
3838
+ "tags": [
3839
+ "release",
3840
+ "automation",
3841
+ "github-actions"
3842
+ ]
3843
+ },
3844
+ {
3845
+ "id": "TG-ROOT-TEST-IGNORES-NESTED-WORKTREES",
3846
+ "statement": "The root Vitest gate describes only this checkout: it never collects fixtures or agent-managed nested worktrees under .claude, so parked unmerged work cannot create false failures in npm test.",
3847
+ "source": {
3848
+ "kind": "manual",
3849
+ "ref": "https://github.com/raccioly/testguard/issues/132"
3850
+ },
3851
+ "severity": "high",
3852
+ "producedBy": {
3853
+ "producer": "human",
3854
+ "by": "maintainer",
3855
+ "at": "2026-09-19T00:00:00Z"
3856
+ },
3857
+ "defendedBy": [
3858
+ "test/vitest-config.test.mjs"
3859
+ ],
3860
+ "faults": [
3861
+ {
3862
+ "id": "F1",
3863
+ "description": "The root test boundary stops excluding agent-managed nested worktrees, so npm test can collect an unrelated checkout.",
3864
+ "faultClass": "field-dropped",
3865
+ "file": "vitest.config.mjs",
3866
+ "find": " exclude: [...configDefaults.exclude, 'fixtures/**', '.claude/**'],",
3867
+ "replace": " exclude: [...configDefaults.exclude, 'fixtures/**'],",
3868
+ "producedBy": {
3869
+ "producer": "human",
3870
+ "by": "maintainer",
3871
+ "at": "2026-09-19T00:00:00Z"
3872
+ }
3873
+ }
3874
+ ],
3875
+ "tags": [
3876
+ "tests",
3877
+ "worktrees",
3878
+ "isolation"
3879
+ ]
3780
3880
  }
3781
3881
  ]
3782
3882
  }
@@ -0,0 +1,11 @@
1
+ import { defineConfig, configDefaults } from 'vitest/config';
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ // fixtures/ contains a deliberately flaky suite; it is driven by the
6
+ // tool's own tests, never collected directly. Agent-managed worktrees are
7
+ // separate checkouts too: collecting them makes this tree's result depend
8
+ // on unrelated, potentially unfinished work.
9
+ exclude: [...configDefaults.exclude, 'fixtures/**', '.claude/**'],
10
+ },
11
+ });
@@ -1,9 +0,0 @@
1
- import { defineConfig, configDefaults } from 'vitest/config';
2
-
3
- export default defineConfig({
4
- test: {
5
- // fixtures/ contains a deliberately flaky suite; it is driven by the
6
- // tool's own tests, never collected directly.
7
- exclude: [...configDefaults.exclude, 'fixtures/**'],
8
- },
9
- });
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes