testguard-cli 0.9.4__tar.gz → 0.10.1__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 (309) hide show
  1. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/CHANGELOG.md +39 -0
  2. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/PKG-INFO +20 -8
  3. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/README.md +19 -7
  4. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/action.yml +1 -1
  5. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/docs/testguard-explained.html +1 -1
  6. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/docs/testguard-explained.pdf +0 -0
  7. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/docs-canonical/REQUIREMENTS.md +4 -1
  8. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/package-lock.json +2 -2
  9. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/package.json +1 -1
  10. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/packaging/gitlab/testguard.gitlab-ci.yml +2 -2
  11. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/packaging/homebrew/testguard.rb +2 -2
  12. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/pyproject.toml +1 -1
  13. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/GATE-SEMANTICS.md +31 -0
  14. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/examples/status.json +35 -0
  15. testguard_cli-0.10.1/spec/conformance/invalid/status.partial-scope-counts-disagree.json +31 -0
  16. testguard_cli-0.10.1/spec/conformance/invalid/status.surface-counts-disagree.json +28 -0
  17. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/lib/validate.mjs +13 -0
  18. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/schemas/status.schema.json +143 -1
  19. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/brief/brief.mjs +2 -2
  20. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/cli.mjs +2 -2
  21. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/commands/admit.mjs +10 -2
  22. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/commands/probe.mjs +30 -3
  23. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/commands/scaffold.mjs +10 -1
  24. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/gate/changed.mjs +6 -2
  25. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/probe/probe.mjs +14 -11
  26. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/render.mjs +6 -1
  27. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/status/status.mjs +30 -1
  28. testguard_cli-0.10.1/src/status/surface.mjs +72 -0
  29. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/test/admit.test.mjs +4 -1
  30. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/test/brief.test.mjs +5 -0
  31. testguard_cli-0.10.1/test/claim-selection.test.mjs +74 -0
  32. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/test/probe.fixture.test.mjs +23 -5
  33. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/test/scaffold.test.mjs +3 -0
  34. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/test/status.test.mjs +17 -0
  35. testguard_cli-0.10.1/test/surface.test.mjs +53 -0
  36. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/testguard.claims.json +243 -0
  37. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/.agents/skills/testguard/SKILL.md +0 -0
  38. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/.codex/hooks.json +0 -0
  39. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/.docguard.json +0 -0
  40. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/.docguardignore +0 -0
  41. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/.gitattributes +0 -0
  42. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  43. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  44. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  45. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/.github/dependabot.yml +0 -0
  46. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/.github/scripts/approve-held-runs.sh +0 -0
  47. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/.github/scripts/build-one-pager.mjs +0 -0
  48. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/.github/scripts/check-cost-budget.mjs +0 -0
  49. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/.github/scripts/check-python-fixture.mjs +0 -0
  50. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/.github/scripts/install-smoke.mjs +0 -0
  51. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/.github/scripts/sync-release-version.mjs +0 -0
  52. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/.github/workflows/auto-merge.yml +0 -0
  53. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/.github/workflows/ci.yml +0 -0
  54. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/.github/workflows/release.yml +0 -0
  55. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/.github/workflows/scheduled-release.yml +0 -0
  56. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/.github/workflows/supply-chain.yml +0 -0
  57. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/.gitignore +0 -0
  58. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/.npmignore +0 -0
  59. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/.npmrc +0 -0
  60. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/.pre-commit-config.yaml +0 -0
  61. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/.pre-commit-hooks.yaml +0 -0
  62. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/AGENTS.md +0 -0
  63. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/CLAUDE.md +0 -0
  64. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/CODE_OF_CONDUCT.md +0 -0
  65. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/CONTRIBUTING.md +0 -0
  66. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/DRIFT-LOG.md +0 -0
  67. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/LICENSE +0 -0
  68. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/PRIVACY.md +0 -0
  69. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/SECURITY.md +0 -0
  70. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/SUPPORT.md +0 -0
  71. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/bench/README.md +0 -0
  72. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/cli/testguard.mjs +0 -0
  73. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/docs-canonical/ARCHITECTURE.md +0 -0
  74. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/docs-canonical/DATA-MODEL.md +0 -0
  75. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/docs-canonical/ENVIRONMENT.md +0 -0
  76. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/docs-canonical/SECURITY.md +0 -0
  77. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/docs-canonical/TEST-SPEC.md +0 -0
  78. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/fixtures/known-answer/.gitignore +0 -0
  79. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/fixtures/known-answer/README.md +0 -0
  80. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/fixtures/known-answer/expected.json +0 -0
  81. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/fixtures/known-answer/package.json +0 -0
  82. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/fixtures/known-answer/src/export.mjs +0 -0
  83. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/fixtures/known-answer/src/redact.mjs +0 -0
  84. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/fixtures/known-answer/test/export-mocked.test.mjs +0 -0
  85. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/fixtures/known-answer/test/flaky.test.mjs +0 -0
  86. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/fixtures/known-answer/test/redact.test.mjs +0 -0
  87. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/fixtures/known-answer/testguard.claims.json +0 -0
  88. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/fixtures/known-answer/vitest.config.mjs +0 -0
  89. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/fixtures/known-answer-jest/.gitignore +0 -0
  90. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/fixtures/known-answer-jest/README.md +0 -0
  91. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/fixtures/known-answer-jest/expected.json +0 -0
  92. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/fixtures/known-answer-jest/jest.config.js +0 -0
  93. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/fixtures/known-answer-jest/package.json +0 -0
  94. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/fixtures/known-answer-jest/src/export.js +0 -0
  95. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/fixtures/known-answer-jest/src/redact.js +0 -0
  96. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/fixtures/known-answer-jest/test/export-mocked.test.js +0 -0
  97. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/fixtures/known-answer-jest/test/flaky.test.js +0 -0
  98. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/fixtures/known-answer-jest/test/redact.test.js +0 -0
  99. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/fixtures/known-answer-jest/testguard.claims.json +0 -0
  100. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/fixtures/known-answer-playwright/.gitignore +0 -0
  101. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/fixtures/known-answer-playwright/README.md +0 -0
  102. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/fixtures/known-answer-playwright/e2e/flaky.spec.mjs +0 -0
  103. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/fixtures/known-answer-playwright/e2e/toggle.spec.mjs +0 -0
  104. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/fixtures/known-answer-playwright/expected.json +0 -0
  105. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/fixtures/known-answer-playwright/package-lock.json +0 -0
  106. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/fixtures/known-answer-playwright/package.json +0 -0
  107. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/fixtures/known-answer-playwright/playwright.config.mjs +0 -0
  108. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/fixtures/known-answer-playwright/src/toggle.mjs +0 -0
  109. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/fixtures/known-answer-playwright/test/toggle.test.mjs +0 -0
  110. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/fixtures/known-answer-playwright/test-results/.last-run.json +0 -0
  111. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/fixtures/known-answer-playwright/testguard.claims.json +0 -0
  112. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/fixtures/known-answer-playwright/vitest.config.mjs +0 -0
  113. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/fixtures/known-answer-python/.gitignore +0 -0
  114. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/fixtures/known-answer-python/README.md +0 -0
  115. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/fixtures/known-answer-python/demo/__init__.py +0 -0
  116. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/fixtures/known-answer-python/demo/export.py +0 -0
  117. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/fixtures/known-answer-python/demo/orphan.py +0 -0
  118. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/fixtures/known-answer-python/demo/pipeline.py +0 -0
  119. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/fixtures/known-answer-python/demo/redact.py +0 -0
  120. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/fixtures/known-answer-python/expected.json +0 -0
  121. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/fixtures/known-answer-python/testguard.claims.json +0 -0
  122. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/fixtures/known-answer-python/tests/test_export_mocked.py +0 -0
  123. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/fixtures/known-answer-python/tests/test_flaky.py +0 -0
  124. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/fixtures/known-answer-python/tests/test_patched.py +0 -0
  125. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/fixtures/known-answer-python/tests/test_redact.py +0 -0
  126. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/README.md +0 -0
  127. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/examples/baseline.json +0 -0
  128. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/examples/brief.json +0 -0
  129. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/examples/calibration-websec.json +0 -0
  130. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/examples/calibration.json +0 -0
  131. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/examples/claims-methods.json +0 -0
  132. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/examples/claims.json +0 -0
  133. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/examples/evidence-disturbed-run.json +0 -0
  134. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/examples/evidence-negative-control.json +0 -0
  135. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/examples/evidence-provisional.json +0 -0
  136. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/examples/evidence-python.json +0 -0
  137. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/examples/evidence-scan-method.json +0 -0
  138. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/examples/evidence.json +0 -0
  139. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/examples/gate.json +0 -0
  140. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/examples/ignore.json +0 -0
  141. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/examples/replay.json +0 -0
  142. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/baseline.bad-fingerprint-key.json +0 -0
  143. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/baseline.zero-count.json +0 -0
  144. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/brief.text-without-heading.json +0 -0
  145. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/brief.unknown-verdict-key.json +0 -0
  146. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/calibration.backoff-cell-not-wilson.json +0 -0
  147. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/calibration.breakdown-does-not-sum-to-n.json +0 -0
  148. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/calibration.ci-not-wilson.json +0 -0
  149. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/calibration.compound-key-arity-mismatch.json +0 -0
  150. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/calibration.fallback-without-basis.json +0 -0
  151. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/calibration.p-not-positives-over-n.json +0 -0
  152. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/calibration.p-outside-ci.json +0 -0
  153. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/calibration.positives-exceed-n.json +0 -0
  154. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/claims.absolute-path.json +0 -0
  155. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/claims.duplicate-fault-id.json +0 -0
  156. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/claims.fault-injection-without-a-substitution.json +0 -0
  157. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/claims.method-detail-on-a-specified-method.json +0 -0
  158. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/claims.missing-provenance.json +0 -0
  159. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/claims.noop-fault.json +0 -0
  160. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/claims.occurrence-exceeds-hits.json +0 -0
  161. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/claims.parent-traversal.json +0 -0
  162. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/evidence.annotated-signal-without-reason.json +0 -0
  163. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/evidence.attribute-signal-not-a-defender.json +0 -0
  164. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/evidence.attribute-signal-without-attributes.json +0 -0
  165. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/evidence.byrunner-file-not-resolved.json +0 -0
  166. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/evidence.contention-without-runners.json +0 -0
  167. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/evidence.discovered-defender-mocks-subject.json +0 -0
  168. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/evidence.fault-injection-without-its-evidence.json +0 -0
  169. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/evidence.flaky-defender-without-flakiness.json +0 -0
  170. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/evidence.ignored-dirty-on-snapshot.json +0 -0
  171. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/evidence.killed-by-non-assertion.json +0 -0
  172. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/evidence.killed-on-red-baseline.json +0 -0
  173. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/evidence.killed-without-n-runs.json +0 -0
  174. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/evidence.method-detail-on-an-injecting-run.json +0 -0
  175. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/evidence.negative-control-not-reached-but-survived.json +0 -0
  176. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/evidence.negative-control-reached-on-a-kill.json +0 -0
  177. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/evidence.probe-error-without-message.json +0 -0
  178. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/evidence.provisional-flag-on-confirmed-run.json +0 -0
  179. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/evidence.rank-extra-property.json +0 -0
  180. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/evidence.restore-skipped-in-place.json +0 -0
  181. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/evidence.single-run-without-provisional.json +0 -0
  182. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/evidence.target-not-imported-but-killed.json +0 -0
  183. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/evidence.undeclared-killers-without-reason.json +0 -0
  184. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/evidence.unknown-verdict.json +0 -0
  185. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/evidence.unverifiable-without-reason.json +0 -0
  186. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/evidence.wrong-fingerprint.json +0 -0
  187. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/gate.counts-disagree.json +0 -0
  188. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/gate.exit-zero-with-uncovered.json +0 -0
  189. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/gate.ignore-cover-without-pattern.json +0 -0
  190. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/ignore.missing-reason.json +0 -0
  191. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/ignore.short-reason.json +0 -0
  192. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/replay.blind-with-a-failing-run.json +0 -0
  193. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/replay.duplicate-patch-id.json +0 -0
  194. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/status.claim-without-file.json +0 -0
  195. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/status.clean-with-new-findings.json +0 -0
  196. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/status.invalid-anchor-hidden.json +0 -0
  197. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/status.unclaimed-hidden-behind-unproven.json +0 -0
  198. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/invalid/status.write-test-without-target.json +0 -0
  199. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/conformance/schemas.test.mjs +0 -0
  200. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/lib/fingerprint.mjs +0 -0
  201. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/lib/wilson.mjs +0 -0
  202. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/schemas/baseline.schema.json +0 -0
  203. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/schemas/brief.schema.json +0 -0
  204. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/schemas/calibration.schema.json +0 -0
  205. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/schemas/claims.schema.json +0 -0
  206. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/schemas/common.schema.json +0 -0
  207. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/schemas/evidence.schema.json +0 -0
  208. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/schemas/gate.schema.json +0 -0
  209. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/schemas/ignore.schema.json +0 -0
  210. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/spec/schemas/replay.schema.json +0 -0
  211. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/admit/admit.mjs +0 -0
  212. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/baseline/baseline.mjs +0 -0
  213. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/claims/anchors.mjs +0 -0
  214. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/claims/annotations.mjs +0 -0
  215. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/claims/load.mjs +0 -0
  216. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/claims/removed.mjs +0 -0
  217. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/commands/baseline.mjs +0 -0
  218. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/commands/brief.mjs +0 -0
  219. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/commands/claims.mjs +0 -0
  220. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/commands/gate.mjs +0 -0
  221. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/commands/init.mjs +0 -0
  222. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/commands/mcp.mjs +0 -0
  223. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/commands/replay.mjs +0 -0
  224. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/commands/status.mjs +0 -0
  225. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/evidence/writer.mjs +0 -0
  226. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/git.mjs +0 -0
  227. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/init/init.mjs +0 -0
  228. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/init/templates/SKILL.md +0 -0
  229. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/mcp/server.mjs +0 -0
  230. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/mcp/tools.mjs +0 -0
  231. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/probe/attribution.mjs +0 -0
  232. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/probe/classify.mjs +0 -0
  233. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/probe/contention.mjs +0 -0
  234. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/probe/cost.mjs +0 -0
  235. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/probe/discover.mjs +0 -0
  236. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/probe/independence.mjs +0 -0
  237. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/probe/inject.mjs +0 -0
  238. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/probe/mocks.mjs +0 -0
  239. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/probe/progress.mjs +0 -0
  240. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/probe/pyimports.mjs +0 -0
  241. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/probe/rank.mjs +0 -0
  242. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/probe/runners/index.mjs +0 -0
  243. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/probe/runners/jest.mjs +0 -0
  244. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/probe/runners/playwright.mjs +0 -0
  245. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/probe/runners/python/_testguard_pytest_plugin.py +0 -0
  246. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/probe/runners/python/_testguard_report.py +0 -0
  247. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/probe/runners/python/_testguard_unittest_main.py +0 -0
  248. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/probe/runners/python.mjs +0 -0
  249. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/probe/runners/shared.mjs +0 -0
  250. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/probe/runners/vitest.mjs +0 -0
  251. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/probe/worktree.mjs +0 -0
  252. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/replay/label.mjs +0 -0
  253. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/replay/replay.mjs +0 -0
  254. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/scaffold/producers.mjs +0 -0
  255. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/scaffold/producers.python.mjs +0 -0
  256. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/scaffold/scaffold.mjs +0 -0
  257. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/util/glob.mjs +0 -0
  258. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/src/util/hash.mjs +0 -0
  259. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/test/annotations.test.mjs +0 -0
  260. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/test/attribution.test.mjs +0 -0
  261. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/test/baseline.test.mjs +0 -0
  262. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/test/calibration.test.mjs +0 -0
  263. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/test/claims-anchors.test.mjs +0 -0
  264. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/test/claims-since.test.mjs +0 -0
  265. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/test/classify.test.mjs +0 -0
  266. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/test/contention.test.mjs +0 -0
  267. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/test/cost.test.mjs +0 -0
  268. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/test/discover.test.mjs +0 -0
  269. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/test/gate.test.mjs +0 -0
  270. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/test/gitlab-template.test.mjs +0 -0
  271. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/test/glob.test.mjs +0 -0
  272. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/test/independence.test.mjs +0 -0
  273. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/test/init.test.mjs +0 -0
  274. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/test/inject.test.mjs +0 -0
  275. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/test/label.test.mjs +0 -0
  276. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/test/mcp.test.mjs +0 -0
  277. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/test/mocks.test.mjs +0 -0
  278. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/test/negative-control.test.mjs +0 -0
  279. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/test/one-pager.test.mjs +0 -0
  280. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/test/probe-error.test.mjs +0 -0
  281. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/test/probe-preconditions.test.mjs +0 -0
  282. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/test/probe.jest.test.mjs +0 -0
  283. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/test/probe.playwright.test.mjs +0 -0
  284. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/test/probe.python.test.mjs +0 -0
  285. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/test/progress.test.mjs +0 -0
  286. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/test/pyimports.test.mjs +0 -0
  287. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/test/rank-aliases.test.mjs +0 -0
  288. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/test/release-approval.test.mjs +0 -0
  289. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/test/release-sync.test.mjs +0 -0
  290. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/test/replay-verdict.test.mjs +0 -0
  291. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/test/replay.test.mjs +0 -0
  292. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/test/runner-argv.test.mjs +0 -0
  293. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/test/runner-command.test.mjs +0 -0
  294. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/test/runner-playwright.test.mjs +0 -0
  295. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/test/runner-python.test.mjs +0 -0
  296. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/test/runner-vitest.test.mjs +0 -0
  297. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/test/samples/playwright-report.json +0 -0
  298. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/test/samples/python-report-collect-error.json +0 -0
  299. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/test/samples/python-report.json +0 -0
  300. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/test/scaffold.python.test.mjs +0 -0
  301. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/test/snapshot.test.mjs +0 -0
  302. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/test/vitest-config.test.mjs +0 -0
  303. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/test/worktree.test.mjs +0 -0
  304. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/test/writer.test.mjs +0 -0
  305. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/testguard.cost-budget.json +0 -0
  306. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/testguard.ignore.json +0 -0
  307. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/testguard_cli/__init__.py +0 -0
  308. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/testguard_cli/wrapper.py +0 -0
  309. {testguard_cli-0.9.4 → testguard_cli-0.10.1}/vitest.config.mjs +0 -0
@@ -7,6 +7,45 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.10.1] - 2026-09-19
11
+
12
+ Automated weekly release — everything merged since `v0.10.0`.
13
+
14
+ ### Changed
15
+
16
+ - fix(probe): preserve repeated claim selections (#139)
17
+ - chore(homebrew): sha256 for v0.10.0 (#138)
18
+
19
+
20
+ ### Fixed
21
+
22
+ - Repeated `probe --claim` flags no longer collapse silently to the last value.
23
+ Repeated and comma-separated ids are flattened in first-seen order,
24
+ duplicates are collapsed, empty selections fail, and both human and JSON
25
+ partial-run output show requested versus probed ids and counts. Probe JSON is
26
+ now validated against the published status schema before it is emitted. The
27
+ singular `scaffold` and `admit` forms reject ambiguous repeated values.
28
+
29
+ ## [0.10.0] - 2026-09-19
30
+
31
+ Automated weekly release — everything merged since `v0.9.4`.
32
+
33
+ ### Changed
34
+
35
+ - feat(status): expose claimed source surface (#135)
36
+ - chore(homebrew): sha256 for v0.9.4 (#136)
37
+
38
+
39
+ ### Added
40
+
41
+ - `status` now makes the claim denominator visible: claimed versus current
42
+ source modules, coverage of the 20 highest-churn modules over a bounded
43
+ 200-commit window, and specific unclaimed modules ranked by churn with
44
+ explicit path-risk signals. A clean project whose majority of modules are
45
+ still unclaimed is directed to scaffold the highest-churn gap. The existing
46
+ co-authorship caveat is also printed by both `status` and `probe`, rather
47
+ than remaining available only in JSON and the agent brief.
48
+
10
49
  ## [0.9.4] - 2026-09-19
11
50
 
12
51
  Automated weekly release — everything merged since `v0.9.3`.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: testguard-cli
3
- Version: 0.9.4
3
+ Version: 0.10.1
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.4` — see [`action.yml`](./action.yml) |
154
+ | GitHub Action | `uses: raccioly/testguard@v0.10.1` — 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.4/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.10.1/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
@@ -303,8 +303,12 @@ npx testguard-cli admit test/x.test.ts --claim X # is this test green on HEAD
303
303
  because it fails when the claim is false.
304
304
 
305
305
  Practical loop: first pass `--no-escalate` (escalation re-runs the whole
306
- suite N times per survivor); iterate on one claim with `--claim <ID>` and
307
- either `--include-dirty` or `--in-place` (only fault target files must be
306
+ suite N times per survivor); iterate on one claim with `--claim <ID>`, or
307
+ select a batch with commas or repeated flags (`--claim A,B --claim C`).
308
+ Every occurrence is retained in first-seen order, duplicates are collapsed,
309
+ and partial human/JSON output names both the requested and probed counts, so
310
+ a green subset cannot masquerade as the selection the operator asked for.
311
+ Use either `--include-dirty` or `--in-place` (only fault target files must be
308
312
  clean there; test files may be dirty), optionally `--confirm 1` for a fast
309
313
  **provisional** signal — verdicts print with a `?`, evidence goes to
310
314
  `evidence-provisional.json`, and `baseline` refuses it; final pass with
@@ -493,12 +497,12 @@ detected base that does not resolve is a warning for `status` and `brief`
493
497
  # GitHub Actions
494
498
  - uses: actions/checkout@v4
495
499
  with: { fetch-depth: 0 }
496
- - uses: raccioly/testguard@v0.9.4
500
+ - uses: raccioly/testguard@v0.10.1
497
501
  with: { command: gate }
498
502
 
499
503
  # GitLab CI — the component-shaped template: gate + probe, brief as an artifact and, opted in, as a merge-request note
500
504
  include:
501
- - remote: 'https://raw.githubusercontent.com/raccioly/testguard/v0.9.4/packaging/gitlab/testguard.gitlab-ci.yml'
505
+ - remote: 'https://raw.githubusercontent.com/raccioly/testguard/v0.10.1/packaging/gitlab/testguard.gitlab-ci.yml'
502
506
  inputs: { dir: backend, post_note: true } # post_note needs TESTGUARD_GITLAB_TOKEN (api scope); one note, updated in place
503
507
  ```
504
508
 
@@ -657,9 +661,17 @@ things make that safe:
657
661
  *should* ship with its regression test — but a repository where every kill
658
662
  is co-authored has no independent verification, whatever its claim
659
663
  verification rate says. It is a **signal**: ranking reads it, verdicts never
660
- do, and the brief says it in one line. Nothing else in this category
664
+ do, and `probe`, `status` and the brief all say it in one line. Nothing else in this category
661
665
  measures it, and agents saturate the tests they can see
662
666
  ([SpecBench](https://arxiv.org/abs/2605.21384)).
667
+ - **Claimed surface is visible.** A clean probe is only about claims that
668
+ exist. `status` therefore reports claimed source modules over the current
669
+ module denominator, how many of the 20 highest-churn modules are claimed,
670
+ and the concrete unclaimed modules worth examining next over a bounded
671
+ 200-commit window. Churn and path-risk signals stay separate; there is no
672
+ synthetic health score. When most modules remain unclaimed and the existing
673
+ evidence is clean, the next action expands the denominator instead of
674
+ congratulating the same small set of claims again.
663
675
  - **Gaming is visible.** The cheapest way to make a survivor disappear is to
664
676
  weaken its fault, not to write a test. Evidence records every fault's
665
677
  content hash; `status` lists any fault edited after it survived, with its
@@ -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.4` — see [`action.yml`](./action.yml) |
130
+ | GitHub Action | `uses: raccioly/testguard@v0.10.1` — 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.4/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.10.1/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
@@ -279,8 +279,12 @@ npx testguard-cli admit test/x.test.ts --claim X # is this test green on HEAD
279
279
  because it fails when the claim is false.
280
280
 
281
281
  Practical loop: first pass `--no-escalate` (escalation re-runs the whole
282
- suite N times per survivor); iterate on one claim with `--claim <ID>` and
283
- either `--include-dirty` or `--in-place` (only fault target files must be
282
+ suite N times per survivor); iterate on one claim with `--claim <ID>`, or
283
+ select a batch with commas or repeated flags (`--claim A,B --claim C`).
284
+ Every occurrence is retained in first-seen order, duplicates are collapsed,
285
+ and partial human/JSON output names both the requested and probed counts, so
286
+ a green subset cannot masquerade as the selection the operator asked for.
287
+ Use either `--include-dirty` or `--in-place` (only fault target files must be
284
288
  clean there; test files may be dirty), optionally `--confirm 1` for a fast
285
289
  **provisional** signal — verdicts print with a `?`, evidence goes to
286
290
  `evidence-provisional.json`, and `baseline` refuses it; final pass with
@@ -469,12 +473,12 @@ detected base that does not resolve is a warning for `status` and `brief`
469
473
  # GitHub Actions
470
474
  - uses: actions/checkout@v4
471
475
  with: { fetch-depth: 0 }
472
- - uses: raccioly/testguard@v0.9.4
476
+ - uses: raccioly/testguard@v0.10.1
473
477
  with: { command: gate }
474
478
 
475
479
  # GitLab CI — the component-shaped template: gate + probe, brief as an artifact and, opted in, as a merge-request note
476
480
  include:
477
- - remote: 'https://raw.githubusercontent.com/raccioly/testguard/v0.9.4/packaging/gitlab/testguard.gitlab-ci.yml'
481
+ - remote: 'https://raw.githubusercontent.com/raccioly/testguard/v0.10.1/packaging/gitlab/testguard.gitlab-ci.yml'
478
482
  inputs: { dir: backend, post_note: true } # post_note needs TESTGUARD_GITLAB_TOKEN (api scope); one note, updated in place
479
483
  ```
480
484
 
@@ -633,9 +637,17 @@ things make that safe:
633
637
  *should* ship with its regression test — but a repository where every kill
634
638
  is co-authored has no independent verification, whatever its claim
635
639
  verification rate says. It is a **signal**: ranking reads it, verdicts never
636
- do, and the brief says it in one line. Nothing else in this category
640
+ do, and `probe`, `status` and the brief all say it in one line. Nothing else in this category
637
641
  measures it, and agents saturate the tests they can see
638
642
  ([SpecBench](https://arxiv.org/abs/2605.21384)).
643
+ - **Claimed surface is visible.** A clean probe is only about claims that
644
+ exist. `status` therefore reports claimed source modules over the current
645
+ module denominator, how many of the 20 highest-churn modules are claimed,
646
+ and the concrete unclaimed modules worth examining next over a bounded
647
+ 200-commit window. Churn and path-risk signals stay separate; there is no
648
+ synthetic health score. When most modules remain unclaimed and the existing
649
+ evidence is clean, the next action expands the denominator instead of
650
+ congratulating the same small set of claims again.
639
651
  - **Gaming is visible.** The cheapest way to make a survivor disappear is to
640
652
  weaken its fault, not to write a test. Evidence records every fault's
641
653
  content hash; `status` lists any fault edited after it survived, with its
@@ -46,7 +46,7 @@ inputs:
46
46
  version:
47
47
  description: 'testguard-cli version to run'
48
48
  required: false
49
- default: '0.9.4'
49
+ default: '0.10.1'
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.4 · MIT</div>
147
+ <div class="meta">Technical Brief · v0.10.1 · MIT</div>
148
148
  </div>
149
149
 
150
150
  <h1>Your tests pass. That is not the same as your tests working.</h1>
@@ -1,6 +1,6 @@
1
1
  # Requirements
2
2
 
3
- <!-- docguard:version 1.0.0 -->
3
+ <!-- docguard:version 1.1.0 -->
4
4
  <!-- docguard:status approved -->
5
5
  <!-- docguard:last-reviewed 2026-09-19 -->
6
6
  <!-- docguard:owner @raccioly -->
@@ -27,6 +27,7 @@
27
27
  | FR-13 | Replay historical fix commits to measure whether the suite would have caught them, and calibrate by fault class | P3 |
28
28
  | FR-14 | Serve the read-only operating loop over MCP so the loop survives a change of agent harness | P3 |
29
29
  | FR-15 | Validate every exact fault anchor and the syntax of supported in-memory replacements before starting a test runner (`claims --check-anchors`), without guessing repairs | P1 |
30
+ | FR-16 | Preserve every repeated or comma-separated `probe --claim` selection in first-seen order, collapse duplicates, and report requested versus probed scope without allowing an empty selection to pass | P1 |
30
31
 
31
32
  ## Non-Functional Requirements
32
33
 
@@ -101,6 +102,7 @@ fails the pull request naming the unclaimed file, and `status` reports
101
102
  | FR-13 | `src/replay/` | `test/replay.test.mjs`, `test/calibration.test.mjs`, `TG-REPLAY-FLAKY-IS-NEVER-CAUGHT`, `TG-CALIBRATION-COUNTS-NOCOVER-AS-A-MISS`, `TG-CALIBRATION-COUNTS-ONLY-BUGS` |
102
103
  | FR-14 | `src/mcp/` | `test/mcp.test.mjs` |
103
104
  | FR-15 | `src/claims/anchors.mjs`, `src/commands/claims.mjs`, `src/status/status.mjs` | `test/claims-anchors.test.mjs`, `test/status.test.mjs`, `TG-ANCHOR-PREFLIGHT-FAILS-FAST` |
105
+ | FR-16 | `src/cli.mjs`, `src/commands/probe.mjs`, `src/probe/probe.mjs`, `src/commands/scaffold.mjs`, `src/commands/admit.mjs` | `test/claim-selection.test.mjs`, `test/probe.fixture.test.mjs`, `TG-REPEATED-CLAIMS-ARE-ALL-PROBED` |
104
106
  | NFR-01 | `src/init/init.mjs`, runner resolution | `TG-INIT-HOOK-NO-NETWORK`, `TG-README-HOOK-MATCHES-THE-CODE` (every surface, not only the README), `TG-GITIGNORE-ADVICE-IS-ONE-LIST` |
105
107
  | NFR-02 | `package.json` | `npm run test:install` in CI |
106
108
  | NFR-03 | `src/probe/inject.mjs`, `src/probe/probe.mjs` | `TG-DIRTY-DEFENDERS-REFUSED`, `TG-IGNORED-DIRTY-RECORDED`, `TG-IN-PLACE-STILL-RAISES-A-MISSING-TARGET`, `TG-CONTROL-RESTORES-THE-SUBJECT` |
@@ -114,4 +116,5 @@ fails the pull request naming the unclaimed file, and `status` reports
114
116
 
115
117
  | Version | Date | Change | Author |
116
118
  |---|---|---|---|
119
+ | 1.1.0 | 2026-09-19 | Require lossless, visible partial claim selection | @raccioly |
117
120
  | 1.0.0 | 2026-09-18 | First canonical requirements, written against v0.6.0 | @raccioly |
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "testguard-cli",
3
- "version": "0.9.4",
3
+ "version": "0.10.1",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "testguard-cli",
9
- "version": "0.9.4",
9
+ "version": "0.10.1",
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.4",
3
+ "version": "0.10.1",
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.4/packaging/gitlab/testguard.gitlab-ci.yml'
6
+ # - remote: 'https://raw.githubusercontent.com/raccioly/testguard/v0.10.1/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.4"
32
+ default: "0.10.1"
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.4.tgz"
19
- sha256 "3ab202d339b014ea5d8a11cc143bd1bdef6ea08120a513029f7537c288ba3195"
18
+ url "https://registry.npmjs.org/testguard-cli/-/testguard-cli-0.10.1.tgz"
19
+ sha256 "ebb9e4ac0370e0b2cbc52b3e5f24e8426020fd3b5ff9db6b2776ab2744874dab"
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.4"
7
+ version = "0.10.1"
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" }
@@ -344,6 +344,27 @@ the suppress-up-to-count semantics are identical.
344
344
  hidden. A file that mocks the subject is never a discovered defender: a
345
345
  mock cannot detect a fault in what it replaced.
346
346
 
347
+ ## Claimed source surface
348
+
349
+ `status` reports the denominator that `probe` cannot: current, non-test source
350
+ modules with a supported extension and outside the change gate's documented
351
+ default exclusions. A module is claimed when at least one fault anchors to it.
352
+ The document carries the claimed, unclaimed and total module counts.
353
+
354
+ The report also names concrete unclaimed modules. It counts touches over at
355
+ most the latest 200 commits, reports how many of the 20 highest-churn modules
356
+ are claimed, and lists up to ten unclaimed modules in descending churn order.
357
+ Security- and money-shaped path names are explicit tie-breaking signals, never
358
+ semantic claims about a file. Churn, path risk and claim coverage remain raw
359
+ facts: they are never collapsed into one health score.
360
+
361
+ When existing evidence is clean but more source modules are unclaimed than
362
+ claimed, the next action is to scaffold the highest-churn unclaimed module.
363
+ Earlier correctness states still win: invalid anchors, stale evidence and
364
+ unproven faults are repaired before expanding the denominator. Without git
365
+ history the counts and concrete files remain available, while the document
366
+ says history is unavailable and reports zero commits read.
367
+
347
368
  ## Claim coverage of a change
348
369
 
349
370
  `probe` asks whether the tests defend the claims that exist. It says nothing
@@ -415,6 +436,16 @@ new anchor is a semantic edit to the claim and must be reviewed and re-probed.
415
436
  `unclaimed-changes`, when a change reference is known). Its next action is
416
437
  `repair-fault`, naming the first fault and `testguard claims --check-anchors`.
417
438
 
439
+ ## Partial probe scope
440
+
441
+ Every `--claim` occurrence contributes to the selection. Comma-separated ids
442
+ inside each occurrence are flattened in first-seen order and duplicates are
443
+ collapsed. An explicitly empty selection is a usage error, never a successful
444
+ zero-record probe. Partial human output and the `probe --json` run wrapper name
445
+ the requested and actually probed claim ids and counts. Commands whose
446
+ `--claim` is singular (`scaffold` and `admit`) reject repeated or comma-separated
447
+ values instead of silently choosing one.
448
+
418
449
  ## Severity floor
419
450
 
420
451
  `--severity <level>` gates only findings whose claim severity is at or above
@@ -18,6 +18,41 @@
18
18
  }
19
19
  },
20
20
  "provisional": false,
21
+ "run": {
22
+ "id": "run-20260917T020000",
23
+ "evidence": ".testguard/evidence-partial.json",
24
+ "provisional": false,
25
+ "records": 4,
26
+ "newSinceBaseline": 1,
27
+ "exitCode": 1,
28
+ "scope": {
29
+ "requestedClaims": ["REDACT-002", "REDACT-001"],
30
+ "requestedCount": 2,
31
+ "probedClaims": ["REDACT-002", "REDACT-001"],
32
+ "probedCount": 2
33
+ }
34
+ },
35
+ "surface": {
36
+ "sourceModules": 3,
37
+ "claimedModules": 2,
38
+ "unclaimedModules": 1,
39
+ "history": {
40
+ "available": true,
41
+ "maxCommits": 200,
42
+ "commitsRead": 40
43
+ },
44
+ "highChurn": {
45
+ "modules": 3,
46
+ "claimed": 2
47
+ },
48
+ "rankedUnclaimed": [
49
+ {
50
+ "file": "src/session.mjs",
51
+ "changes": 8,
52
+ "riskSignals": ["security"]
53
+ }
54
+ ]
55
+ },
21
56
  "counts": {
22
57
  "claims": 2,
23
58
  "faults": 6,
@@ -0,0 +1,31 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "tool": { "name": "testguard", "version": "0.10.0" },
4
+ "generatedAt": "2026-09-19T22:00:00Z",
5
+ "state": "unprobed",
6
+ "next": {
7
+ "action": "probe",
8
+ "command": "testguard probe",
9
+ "why": "Claims have not been probed."
10
+ },
11
+ "counts": { "claims": 2, "faults": 2 },
12
+ "stale": [],
13
+ "invalidFaults": [],
14
+ "changedFaults": [],
15
+ "findings": [],
16
+ "paths": {},
17
+ "run": {
18
+ "id": "run-20260919T220000",
19
+ "evidence": ".testguard/evidence-partial.json",
20
+ "provisional": false,
21
+ "records": 1,
22
+ "newSinceBaseline": 0,
23
+ "exitCode": 0,
24
+ "scope": {
25
+ "requestedClaims": ["A", "B"],
26
+ "requestedCount": 1,
27
+ "probedClaims": ["A"],
28
+ "probedCount": 1
29
+ }
30
+ }
31
+ }
@@ -0,0 +1,28 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "tool": { "name": "testguard", "version": "0.10.0" },
4
+ "generatedAt": "2026-09-19T21:00:00Z",
5
+ "state": "no-claims",
6
+ "next": {
7
+ "action": "scaffold",
8
+ "command": "testguard scaffold src/a.mjs",
9
+ "why": "No claims yet.",
10
+ "file": "src/a.mjs"
11
+ },
12
+ "provisional": false,
13
+ "surface": {
14
+ "sourceModules": 2,
15
+ "claimedModules": 1,
16
+ "unclaimedModules": 0,
17
+ "history": { "available": true, "maxCommits": 200, "commitsRead": 12 },
18
+ "highChurn": { "modules": 2, "claimed": 1 },
19
+ "rankedUnclaimed": []
20
+ },
21
+ "counts": { "claims": 0, "faults": 0 },
22
+ "stale": [],
23
+ "invalidFaults": [],
24
+ "changedFaults": [],
25
+ "findings": [],
26
+ "notes": [],
27
+ "paths": {}
28
+ }
@@ -244,6 +244,19 @@ const semantic = {
244
244
  if (doc.invalidFaults?.length > 0 && doc.state !== 'invalid-anchors') errors.push({ path: '/state', message: 'invalid fault anchors are hidden behind a later state; invalid-anchors precedes every evidence state' });
245
245
  if (doc.evidenceSource && !doc.evidenceHead) errors.push({ path: '/evidenceHead', message: 'evidence was read, so the commit it describes must be recorded' });
246
246
  if (doc.changes && doc.changes.uncovered.length > 0 && !['no-claims', 'unclaimed-changes'].includes(doc.state)) errors.push({ path: '/state', message: 'uncovered changed files are hidden behind a later state; unclaimed-changes precedes every evidence state' });
247
+ if (doc.surface) {
248
+ if (doc.surface.claimedModules + doc.surface.unclaimedModules !== doc.surface.sourceModules) errors.push({ path: '/surface', message: 'claimedModules + unclaimedModules must equal sourceModules' });
249
+ if (doc.surface.highChurn.claimed > doc.surface.highChurn.modules) errors.push({ path: '/surface/highChurn/claimed', message: 'claimed high-churn modules cannot exceed the high-churn window' });
250
+ if (!doc.surface.history.available && doc.surface.history.commitsRead !== 0) errors.push({ path: '/surface/history/commitsRead', message: 'unavailable history must report zero commits read' });
251
+ if (new Set(doc.surface.rankedUnclaimed.map((item) => item.file)).size !== doc.surface.rankedUnclaimed.length) errors.push({ path: '/surface/rankedUnclaimed', message: 'ranked unclaimed modules must be unique' });
252
+ }
253
+ if (doc.run?.scope) {
254
+ const scope = doc.run.scope;
255
+ if (scope.requestedCount !== scope.requestedClaims.length) errors.push({ path: '/run/scope/requestedCount', message: 'requestedCount must equal requestedClaims.length' });
256
+ if (scope.probedCount !== scope.probedClaims.length) errors.push({ path: '/run/scope/probedCount', message: 'probedCount must equal probedClaims.length' });
257
+ const requested = new Set(scope.requestedClaims);
258
+ if (scope.probedClaims.some((id) => !requested.has(id))) errors.push({ path: '/run/scope/probedClaims', message: 'every probed claim must have been requested' });
259
+ }
247
260
  return errors;
248
261
  },
249
262
 
@@ -102,6 +102,130 @@
102
102
  "provisional": {
103
103
  "type": "boolean"
104
104
  },
105
+ "surface": {
106
+ "description": "The current claim denominator. A source module is a non-test file with a supported source extension that is not covered by the documented default exclusions. Churn is bounded recent git history and remains separate from path-risk signals; neither is collapsed into a score.",
107
+ "type": "object",
108
+ "required": ["sourceModules", "claimedModules", "unclaimedModules", "history", "highChurn", "rankedUnclaimed"],
109
+ "properties": {
110
+ "sourceModules": { "type": "integer", "minimum": 0 },
111
+ "claimedModules": { "type": "integer", "minimum": 0 },
112
+ "unclaimedModules": { "type": "integer", "minimum": 0 },
113
+ "history": {
114
+ "type": "object",
115
+ "required": ["available", "maxCommits", "commitsRead"],
116
+ "properties": {
117
+ "available": { "type": "boolean" },
118
+ "maxCommits": { "type": "integer", "minimum": 1 },
119
+ "commitsRead": { "type": "integer", "minimum": 0 }
120
+ },
121
+ "additionalProperties": false
122
+ },
123
+ "highChurn": {
124
+ "description": "How many of the up-to-20 most changed source modules carry a claim.",
125
+ "type": "object",
126
+ "required": ["modules", "claimed"],
127
+ "properties": {
128
+ "modules": { "type": "integer", "minimum": 0, "maximum": 20 },
129
+ "claimed": { "type": "integer", "minimum": 0, "maximum": 20 }
130
+ },
131
+ "additionalProperties": false
132
+ },
133
+ "rankedUnclaimed": {
134
+ "description": "Up to ten concrete unclaimed modules, ordered by changes in the bounded history window; path-risk signals break ties and are reported explicitly.",
135
+ "type": "array",
136
+ "maxItems": 10,
137
+ "items": {
138
+ "type": "object",
139
+ "required": ["file", "changes", "riskSignals"],
140
+ "properties": {
141
+ "file": { "$ref": "urn:claimspec:v1:common#/$defs/repoPath" },
142
+ "changes": { "type": "integer", "minimum": 0 },
143
+ "riskSignals": {
144
+ "type": "array",
145
+ "uniqueItems": true,
146
+ "items": { "enum": ["security", "money"] }
147
+ }
148
+ },
149
+ "additionalProperties": false
150
+ }
151
+ }
152
+ },
153
+ "additionalProperties": false
154
+ },
155
+ "run": {
156
+ "description": "Present on probe --json: the validated status document plus the completed invocation's result. scope is present only for a partial --claim run.",
157
+ "type": "object",
158
+ "required": ["id", "evidence", "provisional", "records", "newSinceBaseline", "exitCode"],
159
+ "properties": {
160
+ "id": { "type": "string", "minLength": 1, "maxLength": 128 },
161
+ "evidence": { "type": "string", "minLength": 1, "maxLength": 4096 },
162
+ "provisional": { "type": "boolean" },
163
+ "records": { "type": "integer", "minimum": 0 },
164
+ "newSinceBaseline": { "type": "integer", "minimum": 0 },
165
+ "exitCode": { "enum": [0, 1] },
166
+ "scope": {
167
+ "type": "object",
168
+ "required": ["requestedClaims", "requestedCount", "probedClaims", "probedCount"],
169
+ "properties": {
170
+ "requestedClaims": {
171
+ "type": "array",
172
+ "minItems": 1,
173
+ "uniqueItems": true,
174
+ "items": { "$ref": "urn:claimspec:v1:common#/$defs/identifier" }
175
+ },
176
+ "requestedCount": { "type": "integer", "minimum": 1 },
177
+ "probedClaims": {
178
+ "type": "array",
179
+ "uniqueItems": true,
180
+ "items": { "$ref": "urn:claimspec:v1:common#/$defs/identifier" }
181
+ },
182
+ "probedCount": { "type": "integer", "minimum": 0 }
183
+ },
184
+ "additionalProperties": false
185
+ }
186
+ },
187
+ "additionalProperties": false
188
+ },
189
+ "cost": {
190
+ "description": "Present when probe --json --cost is requested; derived only from the runs in the emitted evidence.",
191
+ "type": "object",
192
+ "required": ["totalMs", "totalRuns", "reusedRecords", "records", "claims", "defenders", "sharedDefenders"],
193
+ "properties": {
194
+ "totalMs": { "type": "number", "minimum": 0 },
195
+ "totalRuns": { "type": "integer", "minimum": 0 },
196
+ "reusedRecords": { "type": "integer", "minimum": 0 },
197
+ "records": { "type": "integer", "minimum": 0 },
198
+ "claims": {
199
+ "type": "array",
200
+ "items": {
201
+ "type": "object",
202
+ "required": ["claimId", "ms", "runs", "faults", "reused", "defenders"],
203
+ "properties": {
204
+ "claimId": { "$ref": "urn:claimspec:v1:common#/$defs/identifier" },
205
+ "ms": { "type": "number", "minimum": 0 },
206
+ "runs": { "type": "integer", "minimum": 0 },
207
+ "faults": { "type": "integer", "minimum": 0 },
208
+ "reused": { "type": "integer", "minimum": 0 },
209
+ "defenders": {
210
+ "type": "array",
211
+ "uniqueItems": true,
212
+ "items": { "$ref": "urn:claimspec:v1:common#/$defs/repoPath" }
213
+ }
214
+ },
215
+ "additionalProperties": false
216
+ }
217
+ },
218
+ "defenders": {
219
+ "type": "array",
220
+ "items": { "$ref": "#/$defs/costDefender" }
221
+ },
222
+ "sharedDefenders": {
223
+ "type": "array",
224
+ "items": { "$ref": "#/$defs/costDefender" }
225
+ }
226
+ },
227
+ "additionalProperties": false
228
+ },
105
229
  "counts": {
106
230
  "type": "object",
107
231
  "required": [
@@ -349,5 +473,23 @@
349
473
  "$ref": "urn:claimspec:v1:common#/$defs/gitSha"
350
474
  }
351
475
  },
352
- "additionalProperties": false
476
+ "additionalProperties": false,
477
+ "$defs": {
478
+ "costDefender": {
479
+ "type": "object",
480
+ "required": ["file", "ms", "runs", "claims"],
481
+ "properties": {
482
+ "file": { "$ref": "urn:claimspec:v1:common#/$defs/repoPath" },
483
+ "ms": { "type": "number", "minimum": 0 },
484
+ "runs": { "type": "integer", "minimum": 0 },
485
+ "claims": {
486
+ "type": "array",
487
+ "minItems": 1,
488
+ "uniqueItems": true,
489
+ "items": { "$ref": "urn:claimspec:v1:common#/$defs/identifier" }
490
+ }
491
+ },
492
+ "additionalProperties": false
493
+ }
494
+ }
353
495
  }
@@ -1,5 +1,5 @@
1
1
  import { gate } from '../baseline/baseline.mjs';
2
- import { summarize, formatVerdict } from '../render.mjs';
2
+ import { coAuthorshipWarning, summarize, formatVerdict } from '../render.mjs';
3
3
 
4
4
  export const HEADING = '## TEST BLINDSPOT CONTEXT';
5
5
  /** First line of every markdown brief, so a poster can find and update its own note instead of adding another. */
@@ -98,7 +98,7 @@ export function renderBriefText(brief, { hasBaseline, total, independence }) {
98
98
  }
99
99
  // L3: a kill written in the same change as the code it guards is not
100
100
  // independent evidence. One line, no per-item noise.
101
- if (independence?.coAuthored) lines.push('', `${independence.coAuthored} of ${independence.kills} kills are co-authored with the code they defend — the test and the code were written in the same change, so those kills are not independent evidence.`);
101
+ if (independence?.coAuthored) lines.push('', coAuthorshipWarning(independence.coAuthored, independence.kills));
102
102
  if (brief.next) lines.push('', `NEXT [${brief.next.action}]: ${brief.next.command}`, ` why: ${brief.next.why}`);
103
103
  if (brief.items.length === 0) {
104
104
  lines.push('', 'Every probed claim is defended. Keep it that way: new claims need a fault and a test that fails on it.');