testguard-cli 0.18.0__tar.gz → 0.18.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 (468) hide show
  1. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/CHANGELOG.md +21 -0
  2. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/PKG-INFO +5 -5
  3. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/README.md +4 -4
  4. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/action.yml +1 -1
  5. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/docs/testguard-explained.html +1 -1
  6. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/docs/testguard-explained.pdf +0 -0
  7. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/package-lock.json +2 -2
  8. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/package.json +1 -1
  9. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/packaging/gitlab/testguard.gitlab-ci.yml +2 -2
  10. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/packaging/homebrew/testguard.rb +2 -2
  11. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/pyproject.toml +1 -1
  12. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/probe/runners/discovery.mjs +10 -1
  13. testguard_cli-0.18.1/test/probe.node.test.mjs +200 -0
  14. testguard_cli-0.18.1/test/runner-node-admission.test.mjs +35 -0
  15. testguard_cli-0.18.1/test/runner-report-allocation.test.mjs +81 -0
  16. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/testguard.claims.json +32 -1
  17. testguard_cli-0.18.0/test/probe.node.test.mjs +0 -93
  18. testguard_cli-0.18.0/test/runner-node.test.mjs +0 -127
  19. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/.agents/skills/testguard/SKILL.md +0 -0
  20. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/.docguard.json +0 -0
  21. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/.docguardignore +0 -0
  22. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/.gitattributes +0 -0
  23. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  24. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  25. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  26. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/.github/dependabot.yml +0 -0
  27. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/.github/scripts/approve-held-runs.sh +0 -0
  28. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/.github/scripts/benchmark-node-runner.mjs +0 -0
  29. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/.github/scripts/build-one-pager.mjs +0 -0
  30. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/.github/scripts/check-cost-budget.mjs +0 -0
  31. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/.github/scripts/check-node-fixture.mjs +0 -0
  32. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/.github/scripts/check-python-fixture.mjs +0 -0
  33. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/.github/scripts/install-smoke.mjs +0 -0
  34. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/.github/scripts/publish-homebrew-tap.sh +0 -0
  35. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/.github/scripts/sync-release-version.mjs +0 -0
  36. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/.github/workflows/auto-merge.yml +0 -0
  37. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/.github/workflows/ci.yml +0 -0
  38. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/.github/workflows/release.yml +0 -0
  39. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/.github/workflows/scheduled-release.yml +0 -0
  40. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/.github/workflows/supply-chain.yml +0 -0
  41. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/.gitignore +0 -0
  42. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/.npmignore +0 -0
  43. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/.npmrc +0 -0
  44. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/.pre-commit-config.yaml +0 -0
  45. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/.pre-commit-hooks.yaml +0 -0
  46. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/AGENTS.md +0 -0
  47. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/CLAUDE.md +0 -0
  48. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/CODE_OF_CONDUCT.md +0 -0
  49. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/CONTRIBUTING.md +0 -0
  50. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/DRIFT-LOG.md +0 -0
  51. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/LICENSE +0 -0
  52. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/PRIVACY.md +0 -0
  53. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/SECURITY.md +0 -0
  54. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/SUPPORT.md +0 -0
  55. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/bench/README.md +0 -0
  56. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/cli/testguard.mjs +0 -0
  57. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/docs-canonical/ARCHITECTURE.md +0 -0
  58. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/docs-canonical/DATA-MODEL.md +0 -0
  59. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/docs-canonical/ENVIRONMENT.md +0 -0
  60. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/docs-canonical/PRIOR-ART.md +0 -0
  61. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/docs-canonical/REQUIREMENTS.md +0 -0
  62. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/docs-canonical/SECURITY.md +0 -0
  63. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/docs-canonical/TEST-SPEC.md +0 -0
  64. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer/.gitignore +0 -0
  65. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer/README.md +0 -0
  66. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer/expected.json +0 -0
  67. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer/package.json +0 -0
  68. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer/src/export.mjs +0 -0
  69. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer/src/redact.mjs +0 -0
  70. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer/test/export-mocked.test.mjs +0 -0
  71. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer/test/flaky.test.mjs +0 -0
  72. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer/test/redact.test.mjs +0 -0
  73. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer/testguard.claims.json +0 -0
  74. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer/vitest.config.mjs +0 -0
  75. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer-jest/.gitignore +0 -0
  76. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer-jest/README.md +0 -0
  77. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer-jest/expected.json +0 -0
  78. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer-jest/jest.config.js +0 -0
  79. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer-jest/package.json +0 -0
  80. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer-jest/src/export.js +0 -0
  81. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer-jest/src/redact.js +0 -0
  82. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer-jest/test/export-mocked.test.js +0 -0
  83. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer-jest/test/flaky.test.js +0 -0
  84. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer-jest/test/redact.test.js +0 -0
  85. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer-jest/testguard.claims.json +0 -0
  86. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer-node/.gitignore +0 -0
  87. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer-node/README.md +0 -0
  88. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer-node/expected.json +0 -0
  89. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer-node/package.json +0 -0
  90. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer-node/src/policy.mjs +0 -0
  91. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer-node/src/unused.mjs +0 -0
  92. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer-node/test/flaky.test.mjs +0 -0
  93. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer-node/test/mixed.test.mjs +0 -0
  94. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer-node/test/policy.test.mjs +0 -0
  95. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer-node/testguard.claims.json +0 -0
  96. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer-playwright/.gitignore +0 -0
  97. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer-playwright/README.md +0 -0
  98. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer-playwright/e2e/flaky.spec.mjs +0 -0
  99. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer-playwright/e2e/toggle.spec.mjs +0 -0
  100. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer-playwright/expected.json +0 -0
  101. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer-playwright/package-lock.json +0 -0
  102. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer-playwright/package.json +0 -0
  103. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer-playwright/playwright.config.mjs +0 -0
  104. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer-playwright/src/toggle.mjs +0 -0
  105. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer-playwright/test/toggle.test.mjs +0 -0
  106. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer-playwright/testguard.claims.json +0 -0
  107. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer-playwright/vitest.config.mjs +0 -0
  108. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer-python/.gitignore +0 -0
  109. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer-python/README.md +0 -0
  110. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer-python/demo/__init__.py +0 -0
  111. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer-python/demo/export.py +0 -0
  112. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer-python/demo/orphan.py +0 -0
  113. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer-python/demo/pipeline.py +0 -0
  114. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer-python/demo/redact.py +0 -0
  115. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer-python/expected.json +0 -0
  116. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer-python/testguard.claims.json +0 -0
  117. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer-python/tests/test_export_mocked.py +0 -0
  118. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer-python/tests/test_flaky.py +0 -0
  119. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer-python/tests/test_patched.py +0 -0
  120. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/fixtures/known-answer-python/tests/test_redact.py +0 -0
  121. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/GATE-SEMANTICS.md +0 -0
  122. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/README.md +0 -0
  123. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/annotations.test.mjs +0 -0
  124. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/authoring-input.test.mjs +0 -0
  125. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/draft-append.test.mjs +0 -0
  126. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/examples/annotations.json +0 -0
  127. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/examples/authoring-input.json +0 -0
  128. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/examples/baseline.json +0 -0
  129. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/examples/brief.json +0 -0
  130. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/examples/calibration-websec.json +0 -0
  131. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/examples/calibration.json +0 -0
  132. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/examples/claims-methods.json +0 -0
  133. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/examples/claims.json +0 -0
  134. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/examples/evidence-disturbed-run.json +0 -0
  135. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/examples/evidence-negative-control.json +0 -0
  136. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/examples/evidence-persistence-signal.json +0 -0
  137. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/examples/evidence-provisional.json +0 -0
  138. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/examples/evidence-python.json +0 -0
  139. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/examples/evidence-resources.json +0 -0
  140. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/examples/evidence-scan-method.json +0 -0
  141. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/examples/evidence.json +0 -0
  142. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/examples/gate.json +0 -0
  143. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/examples/ignore.json +0 -0
  144. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/examples/replay.json +0 -0
  145. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/examples/status-resource-cost.json +0 -0
  146. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/examples/status.json +0 -0
  147. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/baseline.bad-fingerprint-key.json +0 -0
  148. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/baseline.zero-count.json +0 -0
  149. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/brief.text-without-heading.json +0 -0
  150. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/brief.unknown-verdict-key.json +0 -0
  151. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/calibration.backoff-cell-not-wilson.json +0 -0
  152. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/calibration.breakdown-does-not-sum-to-n.json +0 -0
  153. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/calibration.ci-not-wilson.json +0 -0
  154. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/calibration.compound-key-arity-mismatch.json +0 -0
  155. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/calibration.fallback-without-basis.json +0 -0
  156. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/calibration.p-not-positives-over-n.json +0 -0
  157. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/calibration.p-outside-ci.json +0 -0
  158. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/calibration.positives-exceed-n.json +0 -0
  159. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/claims.absolute-path.json +0 -0
  160. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/claims.duplicate-fault-id.json +0 -0
  161. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/claims.fault-injection-without-a-substitution.json +0 -0
  162. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/claims.method-detail-on-a-specified-method.json +0 -0
  163. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/claims.missing-provenance.json +0 -0
  164. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/claims.noop-fault.json +0 -0
  165. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/claims.occurrence-exceeds-hits.json +0 -0
  166. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/claims.parent-traversal.json +0 -0
  167. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/evidence.annotated-signal-without-reason.json +0 -0
  168. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/evidence.attribute-signal-not-a-defender.json +0 -0
  169. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/evidence.attribute-signal-without-attributes.json +0 -0
  170. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/evidence.byrunner-file-not-resolved.json +0 -0
  171. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/evidence.contention-without-runners.json +0 -0
  172. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/evidence.discovered-defender-mocks-subject.json +0 -0
  173. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/evidence.fault-injection-without-its-evidence.json +0 -0
  174. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/evidence.flaky-defender-without-flakiness.json +0 -0
  175. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/evidence.ignored-dirty-on-snapshot.json +0 -0
  176. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/evidence.killed-by-non-assertion.json +0 -0
  177. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/evidence.killed-on-red-baseline.json +0 -0
  178. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/evidence.killed-without-n-runs.json +0 -0
  179. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/evidence.method-detail-on-an-injecting-run.json +0 -0
  180. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/evidence.negative-control-not-reached-but-survived.json +0 -0
  181. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/evidence.negative-control-reached-on-a-kill.json +0 -0
  182. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/evidence.persistence-signal-not-a-defender.json +0 -0
  183. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/evidence.persistence-signal-on-a-non-survivor.json +0 -0
  184. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/evidence.persistence-signal-without-reason.json +0 -0
  185. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/evidence.probe-error-without-message.json +0 -0
  186. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/evidence.provisional-flag-on-confirmed-run.json +0 -0
  187. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/evidence.rank-extra-property.json +0 -0
  188. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/evidence.resource-accounting.json +0 -0
  189. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/evidence.restore-skipped-in-place.json +0 -0
  190. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/evidence.serial-worker-conflict.json +0 -0
  191. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/evidence.single-run-without-provisional.json +0 -0
  192. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/evidence.target-not-imported-but-killed.json +0 -0
  193. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/evidence.undeclared-killers-without-reason.json +0 -0
  194. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/evidence.unknown-verdict.json +0 -0
  195. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/evidence.unverifiable-without-reason.json +0 -0
  196. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/evidence.wrong-fingerprint.json +0 -0
  197. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/gate.counts-disagree.json +0 -0
  198. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/gate.exit-zero-with-uncovered.json +0 -0
  199. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/gate.ignore-cover-without-pattern.json +0 -0
  200. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/ignore.missing-reason.json +0 -0
  201. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/ignore.short-reason.json +0 -0
  202. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/replay.blind-with-a-failing-run.json +0 -0
  203. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/replay.duplicate-patch-id.json +0 -0
  204. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/replay.nocover-when-no-test-file-remained.json +0 -0
  205. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/status.claim-without-file.json +0 -0
  206. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/status.clean-with-new-findings.json +0 -0
  207. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/status.invalid-anchor-hidden.json +0 -0
  208. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/status.partial-scope-counts-disagree.json +0 -0
  209. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/status.resource-accounting.json +0 -0
  210. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/status.surface-counts-disagree.json +0 -0
  211. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/status.unclaimed-hidden-behind-unproven.json +0 -0
  212. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/invalid/status.write-test-without-target.json +0 -0
  213. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/origin-policy.test.mjs +0 -0
  214. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/origin-summaries.test.mjs +0 -0
  215. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/origins.test.mjs +0 -0
  216. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/conformance/schemas.test.mjs +0 -0
  217. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/lib/authoring-input.mjs +0 -0
  218. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/lib/fingerprint.mjs +0 -0
  219. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/lib/origins.mjs +0 -0
  220. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/lib/validate.mjs +0 -0
  221. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/lib/wilson.mjs +0 -0
  222. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/schemas/annotations.schema.json +0 -0
  223. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/schemas/authoring-input.schema.json +0 -0
  224. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/schemas/baseline.schema.json +0 -0
  225. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/schemas/brief.schema.json +0 -0
  226. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/schemas/calibration.schema.json +0 -0
  227. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/schemas/claims.schema.json +0 -0
  228. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/schemas/common.schema.json +0 -0
  229. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/schemas/concerns.schema.json +0 -0
  230. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/schemas/evidence.schema.json +0 -0
  231. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/schemas/gate.schema.json +0 -0
  232. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/schemas/ignore.schema.json +0 -0
  233. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/schemas/replay.schema.json +0 -0
  234. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/schemas/status.schema.json +0 -0
  235. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/spec/schemas/sweep.schema.json +0 -0
  236. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/admit/admit.mjs +0 -0
  237. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/baseline/baseline.mjs +0 -0
  238. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/brief/brief.mjs +0 -0
  239. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/claims/anchors.mjs +0 -0
  240. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/claims/annotation-placement.mjs +0 -0
  241. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/claims/annotations.mjs +0 -0
  242. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/claims/load.mjs +0 -0
  243. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/claims/removed.mjs +0 -0
  244. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/cli.mjs +0 -0
  245. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/command-budget.mjs +0 -0
  246. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/commands/admit.mjs +0 -0
  247. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/commands/annotations.mjs +0 -0
  248. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/commands/baseline.mjs +0 -0
  249. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/commands/brief.mjs +0 -0
  250. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/commands/claims.mjs +0 -0
  251. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/commands/concerns.mjs +0 -0
  252. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/commands/gate.mjs +0 -0
  253. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/commands/init.mjs +0 -0
  254. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/commands/mcp.mjs +0 -0
  255. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/commands/probe.mjs +0 -0
  256. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/commands/replay.mjs +0 -0
  257. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/commands/scaffold.mjs +0 -0
  258. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/commands/status.mjs +0 -0
  259. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/commands/sweep.mjs +0 -0
  260. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/evidence/writer.mjs +0 -0
  261. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/gate/changed.mjs +0 -0
  262. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/git.mjs +0 -0
  263. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/init/init.mjs +0 -0
  264. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/init/templates/SKILL.md +0 -0
  265. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/mcp/server.mjs +0 -0
  266. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/mcp/tools.mjs +0 -0
  267. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/probe/attribution.mjs +0 -0
  268. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/probe/classify.mjs +0 -0
  269. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/probe/contention.mjs +0 -0
  270. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/probe/cost.mjs +0 -0
  271. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/probe/discover.mjs +0 -0
  272. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/probe/imports.mjs +0 -0
  273. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/probe/independence.mjs +0 -0
  274. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/probe/inject.mjs +0 -0
  275. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/probe/mocks.mjs +0 -0
  276. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/probe/origin-policy.mjs +0 -0
  277. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/probe/policy-freshness.mjs +0 -0
  278. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/probe/probe.mjs +0 -0
  279. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/probe/progress.mjs +0 -0
  280. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/probe/pyimports.mjs +0 -0
  281. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/probe/rank.mjs +0 -0
  282. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/probe/runners/index.mjs +0 -0
  283. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/probe/runners/jest.mjs +0 -0
  284. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/probe/runners/lifecycle.mjs +0 -0
  285. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/probe/runners/node/entry.mjs +0 -0
  286. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/probe/runners/node/report.mjs +0 -0
  287. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/probe/runners/node/runner.mjs +0 -0
  288. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/probe/runners/node-test.mjs +0 -0
  289. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/probe/runners/playwright.mjs +0 -0
  290. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/probe/runners/python/_testguard_pytest_plugin.py +0 -0
  291. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/probe/runners/python/_testguard_report.py +0 -0
  292. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/probe/runners/python/_testguard_unittest_main.py +0 -0
  293. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/probe/runners/python.mjs +0 -0
  294. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/probe/runners/shared.mjs +0 -0
  295. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/probe/runners/vitest.mjs +0 -0
  296. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/probe/universe.mjs +0 -0
  297. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/probe/worktree.mjs +0 -0
  298. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/render.mjs +0 -0
  299. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/replay/label.mjs +0 -0
  300. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/replay/replay.mjs +0 -0
  301. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/scaffold/admission.mjs +0 -0
  302. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/scaffold/append.mjs +0 -0
  303. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/scaffold/apply-append.mjs +0 -0
  304. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/scaffold/fix-input.mjs +0 -0
  305. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/scaffold/fix-paths.mjs +0 -0
  306. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/scaffold/intent.mjs +0 -0
  307. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/scaffold/open-append.mjs +0 -0
  308. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/scaffold/plan-append.mjs +0 -0
  309. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/scaffold/plan-intent-input.mjs +0 -0
  310. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/scaffold/prepare-append.mjs +0 -0
  311. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/scaffold/producers.mjs +0 -0
  312. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/scaffold/producers.python.mjs +0 -0
  313. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/scaffold/request.mjs +0 -0
  314. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/scaffold/scaffold.mjs +0 -0
  315. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/status/status.mjs +0 -0
  316. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/status/surface.mjs +0 -0
  317. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/supply/concerns.mjs +0 -0
  318. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/supply/feedback.mjs +0 -0
  319. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/supply/persistence.mjs +0 -0
  320. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/supply/savepath.mjs +0 -0
  321. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/supply/select.mjs +0 -0
  322. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/sweep/pool.mjs +0 -0
  323. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/sweep/sweep.mjs +0 -0
  324. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/util/glob.mjs +0 -0
  325. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/src/util/hash.mjs +0 -0
  326. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/admit-decision.test.mjs +0 -0
  327. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/admit.test.mjs +0 -0
  328. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/anchor-admission.test.mjs +0 -0
  329. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/annotation-advisory-limits.test.mjs +0 -0
  330. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/annotation-advisory.test.mjs +0 -0
  331. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/annotation-apply.test.mjs +0 -0
  332. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/annotation-cli.test.mjs +0 -0
  333. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/annotation-placement.test.mjs +0 -0
  334. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/annotations.test.mjs +0 -0
  335. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/attribution.test.mjs +0 -0
  336. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/baseline.test.mjs +0 -0
  337. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/brief.test.mjs +0 -0
  338. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/calibration.test.mjs +0 -0
  339. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/claim-selection.test.mjs +0 -0
  340. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/claims-anchors.test.mjs +0 -0
  341. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/claims-since.test.mjs +0 -0
  342. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/classify.test.mjs +0 -0
  343. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/cli-unexpected-error.test.mjs +0 -0
  344. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/command-budget-write-boundaries.test.mjs +0 -0
  345. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/command-budget.test.mjs +0 -0
  346. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/contention.test.mjs +0 -0
  347. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/cost.test.mjs +0 -0
  348. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/discover.test.mjs +0 -0
  349. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/discovery-config.test.mjs +0 -0
  350. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/draft-admission.test.mjs +0 -0
  351. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/draft-append-apply.test.mjs +0 -0
  352. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/draft-append-cli.test.mjs +0 -0
  353. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/draft-append-open.test.mjs +0 -0
  354. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/draft-append-plan.test.mjs +0 -0
  355. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/draft-append-prepare.test.mjs +0 -0
  356. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/draft-append.test.mjs +0 -0
  357. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/evidence-persistence-signal.test.mjs +0 -0
  358. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/fault-defender-orchestration.test.mjs +0 -0
  359. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/fault-defenders.test.mjs +0 -0
  360. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/fix-input.test.mjs +0 -0
  361. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/fix-inventory.test.mjs +0 -0
  362. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/fix-nested.test.mjs +0 -0
  363. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/fix-paths.test.mjs +0 -0
  364. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/fix-projects.test.mjs +0 -0
  365. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/gate-ref.test.mjs +0 -0
  366. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/gate.test.mjs +0 -0
  367. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/gitlab-template.test.mjs +0 -0
  368. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/glob.test.mjs +0 -0
  369. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/helpers/gate-project.mjs +0 -0
  370. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/helpers/probe-assertions.mjs +0 -0
  371. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/helpers/release-project.mjs +0 -0
  372. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/imports.test.mjs +0 -0
  373. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/independence.test.mjs +0 -0
  374. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/init.test.mjs +0 -0
  375. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/inject.test.mjs +0 -0
  376. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/intent-authoring.test.mjs +0 -0
  377. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/intent-document.test.mjs +0 -0
  378. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/intent-input-cli.test.mjs +0 -0
  379. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/intent-input-plan.test.mjs +0 -0
  380. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/intent-input-request.test.mjs +0 -0
  381. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/intent-project.test.mjs +0 -0
  382. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/label.test.mjs +0 -0
  383. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/mcp-next.test.mjs +0 -0
  384. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/mcp-protocol.test.mjs +0 -0
  385. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/mcp.test.mjs +0 -0
  386. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/mocks.test.mjs +0 -0
  387. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/native-universe-hash.test.mjs +0 -0
  388. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/native-universe.test.mjs +0 -0
  389. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/negative-control-capabilities.test.mjs +0 -0
  390. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/negative-control.test.mjs +0 -0
  391. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/one-pager.test.mjs +0 -0
  392. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/origin-policy-admission.test.mjs +0 -0
  393. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/origin-policy-cli.test.mjs +0 -0
  394. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/origin-policy-projections.test.mjs +0 -0
  395. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/origin-policy-request.test.mjs +0 -0
  396. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/origin-policy.test.mjs +0 -0
  397. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/origin-reporting.test.mjs +0 -0
  398. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/origin-summary.test.mjs +0 -0
  399. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/policy-freshness.test.mjs +0 -0
  400. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/probe-control.test.mjs +0 -0
  401. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/probe-dirty-admission.test.mjs +0 -0
  402. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/probe-dirty-paths.test.mjs +0 -0
  403. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/probe-error-boundary.test.mjs +0 -0
  404. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/probe-error.test.mjs +0 -0
  405. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/probe-isolation.test.mjs +0 -0
  406. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/probe-native-manifest.test.mjs +0 -0
  407. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/probe-persistence-signal.test.mjs +0 -0
  408. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/probe-preconditions.test.mjs +0 -0
  409. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/probe-records.test.mjs +0 -0
  410. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/probe.fixture.test.mjs +0 -0
  411. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/probe.jest.test.mjs +0 -0
  412. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/probe.playwright.test.mjs +0 -0
  413. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/probe.python.test.mjs +0 -0
  414. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/progress.test.mjs +0 -0
  415. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/pyimports.test.mjs +0 -0
  416. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/rank-aliases.test.mjs +0 -0
  417. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/release-approval.test.mjs +0 -0
  418. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/release-sync.test.mjs +0 -0
  419. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/release-tap.test.mjs +0 -0
  420. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/release-version.test.mjs +0 -0
  421. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/replay-mixed-runners.test.mjs +0 -0
  422. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/replay-no-test-file-left.test.mjs +0 -0
  423. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/replay-python-defenders.test.mjs +0 -0
  424. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/replay-selection.test.mjs +0 -0
  425. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/replay-verdict.test.mjs +0 -0
  426. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/replay.test.mjs +0 -0
  427. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/resource-safety.test.mjs +0 -0
  428. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/resource-timing.test.mjs +0 -0
  429. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/runner-argv.test.mjs +0 -0
  430. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/runner-command.test.mjs +0 -0
  431. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/runner-discovery.test.mjs +0 -0
  432. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/runner-node-controller.test.mjs +0 -0
  433. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/runner-node-report.test.mjs +0 -0
  434. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/runner-output-bounds.test.mjs +0 -0
  435. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/runner-playwright.test.mjs +0 -0
  436. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/runner-project-resolution.test.mjs +0 -0
  437. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/runner-python.test.mjs +0 -0
  438. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/runner-report.test.mjs +0 -0
  439. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/runner-selection-blind.test.mjs +0 -0
  440. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/runner-vitest.test.mjs +0 -0
  441. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/runner-worker-argv.test.mjs +0 -0
  442. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/samples/playwright-report.json +0 -0
  443. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/samples/python-report-collect-error.json +0 -0
  444. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/samples/python-report.json +0 -0
  445. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/scaffold-admitted-source.test.mjs +0 -0
  446. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/scaffold-placeholder.test.mjs +0 -0
  447. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/scaffold.python.test.mjs +0 -0
  448. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/scaffold.test.mjs +0 -0
  449. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/snapshot.test.mjs +0 -0
  450. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/status.test.mjs +0 -0
  451. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/supply-concerns.test.mjs +0 -0
  452. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/supply-feedback.test.mjs +0 -0
  453. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/supply-persistence.test.mjs +0 -0
  454. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/supply-savepath.test.mjs +0 -0
  455. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/supply-select.test.mjs +0 -0
  456. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/surface.test.mjs +0 -0
  457. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/sweep-pool.test.mjs +0 -0
  458. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/sweep.fixture.test.mjs +0 -0
  459. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/sweep.test.mjs +0 -0
  460. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/vitest-config.test.mjs +0 -0
  461. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/worker-policy.test.mjs +0 -0
  462. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/worktree.test.mjs +0 -0
  463. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/test/writer.test.mjs +0 -0
  464. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/testguard.cost-budget.json +0 -0
  465. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/testguard.ignore.json +0 -0
  466. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/testguard_cli/__init__.py +0 -0
  467. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/testguard_cli/wrapper.py +0 -0
  468. {testguard_cli-0.18.0 → testguard_cli-0.18.1}/vitest.config.mjs +0 -0
@@ -7,6 +7,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.18.1] - 2026-10-01
11
+
12
+ Automated weekly release — everything merged since `v0.18.0`.
13
+
14
+ ### Changed
15
+
16
+ - test: consolidate native runtime acceptance checks
17
+ - perf: isolate native admission mutation defenders
18
+ - perf: size bounded report buffers to observed files
19
+ - chore(homebrew): sha256 for v0.18.0 (#194)
20
+
21
+
22
+ ### Changed
23
+
24
+ - Runner report and discovery-config reads reserve memory for the observed
25
+ file size instead of the maximum allowed size, retaining the hard byte
26
+ ceiling and checking file growth before parsing.
27
+ - Native-runner admission self-probes use focused defenders, preserving the
28
+ fault recipes and full runner acceptance coverage while avoiding unrelated
29
+ timeout and process-cleanup checks for each admission confirmation.
30
+
10
31
  ## [0.18.0] - 2026-10-01
11
32
 
12
33
  Automated weekly release — everything merged since `v0.17.0`.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: testguard-cli
3
- Version: 0.18.0
3
+ Version: 0.18.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.18.0` — see [`action.yml`](./action.yml) |
154
+ | GitHub Action | `uses: raccioly/testguard@v0.18.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.18.0/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.18.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
@@ -809,12 +809,12 @@ detected base that does not resolve is a warning for `status` and `brief`
809
809
  # GitHub Actions
810
810
  - uses: actions/checkout@v4
811
811
  with: { fetch-depth: 0 }
812
- - uses: raccioly/testguard@v0.18.0
812
+ - uses: raccioly/testguard@v0.18.1
813
813
  with: { command: gate }
814
814
 
815
815
  # GitLab CI — the component-shaped template: gate + probe, brief as an artifact and, opted in, as a merge-request note
816
816
  include:
817
- - remote: 'https://raw.githubusercontent.com/raccioly/testguard/v0.18.0/packaging/gitlab/testguard.gitlab-ci.yml'
817
+ - remote: 'https://raw.githubusercontent.com/raccioly/testguard/v0.18.1/packaging/gitlab/testguard.gitlab-ci.yml'
818
818
  inputs: { dir: backend, post_note: true } # post_note needs TESTGUARD_GITLAB_TOKEN (api scope); one note, updated in place
819
819
  ```
820
820
 
@@ -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.18.0` — see [`action.yml`](./action.yml) |
130
+ | GitHub Action | `uses: raccioly/testguard@v0.18.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.18.0/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.18.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
@@ -785,12 +785,12 @@ detected base that does not resolve is a warning for `status` and `brief`
785
785
  # GitHub Actions
786
786
  - uses: actions/checkout@v4
787
787
  with: { fetch-depth: 0 }
788
- - uses: raccioly/testguard@v0.18.0
788
+ - uses: raccioly/testguard@v0.18.1
789
789
  with: { command: gate }
790
790
 
791
791
  # GitLab CI — the component-shaped template: gate + probe, brief as an artifact and, opted in, as a merge-request note
792
792
  include:
793
- - remote: 'https://raw.githubusercontent.com/raccioly/testguard/v0.18.0/packaging/gitlab/testguard.gitlab-ci.yml'
793
+ - remote: 'https://raw.githubusercontent.com/raccioly/testguard/v0.18.1/packaging/gitlab/testguard.gitlab-ci.yml'
794
794
  inputs: { dir: backend, post_note: true } # post_note needs TESTGUARD_GITLAB_TOKEN (api scope); one note, updated in place
795
795
  ```
796
796
 
@@ -50,7 +50,7 @@ inputs:
50
50
  version:
51
51
  description: 'testguard-cli version to run'
52
52
  required: false
53
- default: '0.18.0'
53
+ default: '0.18.1'
54
54
  node-version:
55
55
  description: 'Node.js version (20+)'
56
56
  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.18.0 · MIT</div>
147
+ <div class="meta">Technical Brief · v0.18.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,12 +1,12 @@
1
1
  {
2
2
  "name": "testguard-cli",
3
- "version": "0.18.0",
3
+ "version": "0.18.1",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "testguard-cli",
9
- "version": "0.18.0",
9
+ "version": "0.18.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.18.0",
3
+ "version": "0.18.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.18.0/packaging/gitlab/testguard.gitlab-ci.yml'
6
+ # - remote: 'https://raw.githubusercontent.com/raccioly/testguard/v0.18.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.18.0"
32
+ default: "0.18.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.18.0.tgz"
19
- sha256 "cdb5166f73433534fe079a5a9fe97e4aebf31de52634ec1c5e3ac89d0c2082c4"
18
+ url "https://registry.npmjs.org/testguard-cli/-/testguard-cli-0.18.1.tgz"
19
+ sha256 "b722d8656f634198a483ff50db7891c21cfccae3aa136faaf9436fc79df33d7d"
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.18.0"
7
+ version = "0.18.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" }
@@ -130,12 +130,21 @@ const readBoundedFile = (path, maxBytes, label, { optional = false } = {}) => {
130
130
  const stat = fstatSync(descriptor);
131
131
  if (!stat.isFile()) throw new DiscoveryError(`${label} is not a regular file`);
132
132
  if (stat.size > maxBytes) throw new DiscoveryError(`${label} exceeded ${maxBytes} bytes`);
133
- const bytes = Buffer.alloc(maxBytes + 1);
133
+ // Reserve the observed file size, not the allowance for the largest report.
134
+ // The extra byte detects growth; a full buffer grows within the same hard
135
+ // ceiling so a concurrently appended suffix can never be silently dropped.
136
+ let bytes = Buffer.alloc(stat.size + 1);
134
137
  let length = 0;
135
138
  while (length < bytes.length) {
136
139
  const read = readSync(descriptor, bytes, length, bytes.length - length, null);
137
140
  if (read === 0) break;
138
141
  length += read;
142
+ if (length > maxBytes) throw new DiscoveryError(`${label} exceeded ${maxBytes} bytes`);
143
+ if (length === bytes.length) {
144
+ const grown = Buffer.alloc(Math.min(maxBytes + 1, Math.max(4096, bytes.length * 2)));
145
+ bytes.copy(grown, 0, 0, length);
146
+ bytes = grown;
147
+ }
139
148
  }
140
149
  if (length > maxBytes) throw new DiscoveryError(`${label} exceeded ${maxBytes} bytes`);
141
150
  return bytes.subarray(0, length);
@@ -0,0 +1,200 @@
1
+ // @req FR-10
2
+ // @req FR-16
3
+ import { describe, it, expect, beforeAll, afterAll, afterEach } from 'vitest';
4
+ import { cpSync, mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync, existsSync, symlinkSync } from 'node:fs';
5
+ import { join, dirname } from 'node:path';
6
+ import { tmpdir } from 'node:os';
7
+ import { fileURLToPath } from 'node:url';
8
+ import { execFileSync, spawn } from 'node:child_process';
9
+ import { probe } from '../src/probe/probe.mjs';
10
+ import { loadClaims } from '../src/claims/load.mjs';
11
+ import { validate } from '../spec/lib/validate.mjs';
12
+ import { run, discoverTests } from '../src/probe/runners/node-test.mjs';
13
+ import { selectRunner } from '../src/probe/runners/index.mjs';
14
+
15
+ const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..');
16
+ const FIXTURE = join(ROOT, 'fixtures/known-answer-node');
17
+ const expected = JSON.parse(readFileSync(join(FIXTURE, 'expected.json'), 'utf8'));
18
+ describe('native Node known-answer proof', () => {
19
+ let dir, claims, evidence;
20
+ beforeAll(async () => {
21
+ dir = mkdtempSync(join(tmpdir(), 'tg-node-fixture-'));
22
+ cpSync(FIXTURE, dir, { recursive: true });
23
+ for (const args of [['init','-q'],['add','.'],['-c','user.name=fixture','-c','user.email=fixture@example.invalid','commit','-qm','fixture']]) execFileSync('git',args,{cwd:dir,timeout:5000});
24
+ claims = loadClaims(join(dir,'testguard.claims.json'));
25
+ evidence = await probe({ projectDir:dir, claims, runnerName:'node-test', confirmRuns:3, budgetMs:5000, mode:'worktree', toolVersion:'test' });
26
+ }, 30_000);
27
+ afterAll(() => { if(dir)rmSync(dir,{recursive:true,force:true}); });
28
+ it('reproduces every independently verified verdict and reason', () => {
29
+ const actual = Object.fromEntries(evidence.records.map((r) => [`${r.claim.id}/${r.subject.id}`, { verdict:r.verdict, reason:r.detail.reason }]));
30
+ for (const [id, oracle] of Object.entries(expected.expected)) {
31
+ expect(actual[id]?.verdict,id).toBe(oracle.verdict);
32
+ if(oracle.reason)expect(actual[id]?.reason,id).toBe(oracle.reason);
33
+ }
34
+ expect(Object.keys(actual)).toHaveLength(Object.keys(expected.expected).length);
35
+ });
36
+ it('emits conforming builtin-runtime evidence with N/N green baselines and assertion-only kills', () => {
37
+ expect(validate('evidence',evidence).errors).toEqual([]);
38
+ expect(evidence.run.runner).toEqual({name:'node-test',version:process.versions.node,source:'builtin'});
39
+ for (const r of evidence.records.filter((r)=>r.verdict==='killed'||r.verdict==='survived')) {
40
+ expect(r.detail.baselineRuns).toHaveLength(3);expect(r.detail.probeRuns).toHaveLength(3);
41
+ expect(r.detail.baselineRuns.every((b)=>b.outcome==='pass')).toBe(true);
42
+ if(r.verdict==='killed')expect(r.detail.probeRuns.every((p)=>p.outcome==='fail'&&p.assertionFailures>0)).toBe(true);
43
+ }
44
+ });
45
+ it('restores every target and removes its scratch worktree after failures/timeouts', () => {
46
+ expect(execFileSync('git',['status','--porcelain'],{cwd:dir,encoding:'utf8'})).toBe('');
47
+ expect(execFileSync('git',['worktree','list','--porcelain'],{cwd:dir,encoding:'utf8'}).match(/^worktree /gm)).toHaveLength(1);
48
+ expect(readFileSync(join(dir,'src/policy.mjs'),'utf8')).toBe(readFileSync(join(FIXTURE,'src/policy.mjs'),'utf8'));
49
+ });
50
+ it('reuses matching Node evidence and remeasures across framework identity or worker policy', async () => {
51
+ const subset = {...claims,claims:claims.claims.filter((c)=>c.id==='NODE-ALLOW')};
52
+ const options = {projectDir:dir,claims:subset,runnerName:'node-test',confirmRuns:3,budgetMs:5000,toolVersion:'test',previous:evidence};
53
+ const reused = await probe(options);
54
+ expect(reused.records[0].reusedFrom).toBe(evidence.run.id);
55
+ const changed = await probe({...options,workers:2,serial:false});
56
+ expect(changed.records[0].reusedFrom).toBeUndefined();
57
+ expect(changed.records[0].verdict).toBe('killed');
58
+ const foreign = structuredClone(evidence);foreign.run.runner={name:'vitest',version:'5.0.2'};
59
+ foreign.records.forEach((r)=>{r.inputs.testUniverseHash='0'.repeat(64);});
60
+ const remeasured = await probe({...options,previous:foreign});
61
+ expect(remeasured.records[0].reusedFrom).toBeUndefined();
62
+ expect(remeasured.records[0].verdict).toBe('killed');
63
+ }, 15_000);
64
+ it('cancels the real CLI during a live fault, restoring targets without publishing partial evidence', async () => {
65
+ const scratch = mkdtempSync(join(tmpdir(), 'tg-node-cancel-'));
66
+ const sentinel = spawn(process.execPath, ['-e', 'setInterval(()=>{},1000)'], { stdio: 'ignore' });
67
+ let child;
68
+ try {
69
+ cpSync(FIXTURE, scratch, { recursive: true });
70
+ const source = readFileSync(join(scratch, 'src/policy.mjs'), 'utf8');
71
+ writeFileSync(join(scratch, 'test/policy.test.mjs'), `import { test } from 'node:test'; import { writeFileSync } from 'node:fs'; import { ready } from '../src/policy.mjs';
72
+ test('live fault',async()=>{if(!await ready()){writeFileSync('live.json',JSON.stringify({pid:process.pid}));while(true){}}});`);
73
+ const subset = { ...claims, claims: claims.claims.filter((c) => c.id === 'NODE-READY') };
74
+ subset.claims[0].faults[0].replace = 'export async function ready() {\n return false;';
75
+ writeFileSync(join(scratch, 'testguard.claims.json'), JSON.stringify(subset));
76
+ for (const args of [['init','-q'],['add','.'],['-c','user.name=fixture','-c','user.email=fixture@example.invalid','commit','-qm','fixture']]) execFileSync('git',args,{cwd:scratch,timeout:5000});
77
+ child = spawn(process.execPath, [join(ROOT, 'cli/testguard.mjs'), 'probe', scratch, '--runner', 'node-test', '--in-place', '--budget', '30000', '--quiet'], { stdio: ['ignore', 'pipe', 'pipe'] });
78
+ let diagnostic = ''; for (const stream of [child.stdout, child.stderr]) stream.on('data', (bytes) => { diagnostic = (diagnostic + bytes).slice(-4000); });
79
+ const closed = new Promise((resolve) => child.once('close', (code, signal) => resolve({ code, signal })));
80
+ const deadline = Date.now() + 10_000;
81
+ while (!existsSync(join(scratch, 'live.json')) && child.exitCode === null && Date.now() < deadline) await new Promise((resolve) => setTimeout(resolve, 20));
82
+ expect(existsSync(join(scratch, 'live.json')), diagnostic).toBe(true);
83
+ const worker = JSON.parse(readFileSync(join(scratch, 'live.json'), 'utf8')).pid;
84
+ child.kill('SIGINT');
85
+ expect(await closed).toEqual({ code: 130, signal: null });
86
+ expect(readFileSync(join(scratch, 'src/policy.mjs'), 'utf8')).toBe(source);
87
+ expect(existsSync(join(scratch, '.testguard/evidence.json'))).toBe(false);
88
+ expect(() => process.kill(worker, 0)).toThrow();
89
+ expect(() => process.kill(sentinel.pid, 0)).not.toThrow();
90
+ } finally {
91
+ child?.kill('SIGKILL'); sentinel.kill('SIGKILL');
92
+ rmSync(scratch, { recursive: true, force: true });
93
+ }
94
+ }, 15_000);
95
+ });
96
+
97
+ // Runtime acceptance remains independent of the focused self-probe defenders.
98
+ describe('native Node collection and runtime acceptance', () => {
99
+ const owned = [];
100
+ const project = (files) => {
101
+ const dir = mkdtempSync(join(tmpdir(), 'tg-node-test-')); owned.push(dir);
102
+ writeFileSync(join(dir, 'package.json'), '{"type":"module"}');
103
+ for (const [file, source] of Object.entries(files)) {
104
+ mkdirSync(dirname(join(dir, file)), { recursive: true }); writeFileSync(join(dir, file), source);
105
+ }
106
+ return dir;
107
+ };
108
+ const body = (code) => `import { test } from 'node:test'; import assert from 'node:assert/strict';\n${code}\n`;
109
+ afterEach(() => { for (const dir of owned.splice(0)) rmSync(dir, { recursive: true, force: true }); });
110
+ const execute = (dir, files = ['test/a.test.mjs'], extra = {}) => run({ projectDir: dir, files, budgetMs: 4000, ...extra });
111
+ const discover = (dir, extra = {}) => discoverTests({ projectDir: dir, version: process.versions.node, ...extra });
112
+ const alive = (pid) => {
113
+ try { process.kill(pid,0);return process.platform==='win32'||!execFileSync('ps',['-p',String(pid),'-o','stat='],{encoding:'utf8',timeout:1000}).trim().startsWith('Z'); } catch {return false;}
114
+ };
115
+
116
+ it('refuses an explicitly selected empty universe', async () => {
117
+ const selected = await selectRunner({ projectDir: project({}), name: 'node-test' });
118
+ expect(selected.error).toMatch(/no test files/);
119
+ });
120
+ it('does not turn a top-level assertion or syntax/import error into a test-body kill', async () => {
121
+ for (const source of ["import assert from 'node:assert/strict'; assert.equal(1,2);", '(', "import './missing.mjs';"]) {
122
+ const dir = project({ 'test/a.test.mjs': source });
123
+ const result = await execute(dir);
124
+ expect(result.run.outcome).toBe('error'); expect(result.run.assertionFailures).toBe(0);
125
+ await expect(discover(dir)).rejects.toThrow();
126
+ }
127
+ });
128
+ it('detects a genuine test-body exception and preserves its test identity', async () => {
129
+ const dir = project({ 'test/a.test.mjs': body("test('exception', () => { throw new Error('bad behavior'); });") });
130
+ const result = await execute(dir);
131
+ expect(result.run.outcome).toBe('fail'); expect(result.run.assertionFailures).toBe(1);
132
+ expect(result.failedTests).toEqual(['test/a.test.mjs::exception']);
133
+ });
134
+ it('does not double count a failing suite or accept skipped-only defenders', async () => {
135
+ const dir = project({ 'test/a.test.mjs': "import {describe,it} from 'node:test'; import assert from 'node:assert/strict'; describe('suite',()=>{it('failure',()=>assert.equal(1,2));it.skip('skip',()=>{});});" });
136
+ const result = await execute(dir);
137
+ expect(result.run.tests).toEqual({ total: 1, passed: 0, failed: 1 }); expect(result.run.assertionFailures).toBe(1);
138
+ writeFileSync(join(dir,'test/a.test.mjs'),body("test.skip('skip',()=>{});test.todo('todo');"));
139
+ expect((await execute(dir)).run.outcome).toBe('error');
140
+ });
141
+ it('recognizes native test timeouts and hard command timeouts', async () => {
142
+ const dir = project({ 'test/a.test.mjs': body("test('hangs',{timeout:40},async(t)=>{const h=setInterval(()=>{},1000);t.signal.addEventListener('abort',()=>clearInterval(h),{once:true});try{await new Promise(()=>{});}finally{clearInterval(h);}});") });
143
+ const result = await execute(dir);
144
+ expect(result.timeouts).toBeGreaterThan(0); expect(result.run.assertionFailures).toBe(0);
145
+ expect(result.run.outcome).toBe('fail');
146
+ writeFileSync(join(dir,'test/a.test.mjs'),body("test('loop',()=>{while(true){}});"));
147
+ const hard = await execute(dir,undefined,{budgetMs:400});
148
+ expect(hard.run.outcome).toBe('timeout'); expect(hard.run.assertionFailures).toBe(0);
149
+ });
150
+ it('refuses a hook failure, incomplete process exit and a file with no tests', async () => {
151
+ for (const source of ["import {before,test} from 'node:test';before(()=>{throw new Error('setup');});test('case',()=>{});", body("test('first',()=>{});test('unfinished',()=>process.exit(0));"), 'export const value=1;']) {
152
+ const result = await execute(project({ 'test/a.test.mjs': source }));
153
+ expect(result.run.outcome).toBe('error'); expect(result.run.assertionFailures).toBe(0);
154
+ }
155
+ });
156
+
157
+ it('binds configuration edits to the native universe and rejects symlink escapes', async () => {
158
+ const dir = project({ 'test/a.test.mjs': body("test('case',()=>{});") });
159
+ const before = await discover(dir); writeFileSync(join(dir,'package.json'),'{"type":"module","description":"changed"}');
160
+ expect((await discover(dir)).testUniverseHash).not.toBe(before.testUniverseHash);
161
+ const external=project({'external.mjs':body("test('outside',()=>{});")});
162
+ symlinkSync(join(external,'external.mjs'),join(dir,'test','escape.mjs'));
163
+ await expect(discover(dir)).rejects.toThrow(/outside/);
164
+ });
165
+ it('executes selected entries through a symlinked project root with canonical attribution', async () => {
166
+ const dir = project({ 'test/a.test.mjs': body("test('through alias',()=>assert.equal(1,1));") });
167
+ const aliases = project({}); const alias = join(aliases, 'linked'); symlinkSync(dir, alias, 'dir');
168
+ expect((await discover(alias)).files).toEqual(['test/a.test.mjs']);
169
+ expect((await execute(alias)).run).toMatchObject({ outcome: 'pass', tests: { total: 1, passed: 1, failed: 0 } });
170
+ });
171
+ it('bounds native collection output and command time', async () => {
172
+ const dir = project({ 'test/a.test.mjs': body("test('case',()=>{});") });
173
+ await expect(discover(dir,{maxOutputBytes:1})).rejects.toThrow(/exceeded/);
174
+ writeFileSync(join(dir,'test/a.test.mjs'),'while(true){}');
175
+ await expect(discover(dir,{timeoutMs:300})).rejects.toThrow(/timeout/);
176
+ });
177
+ it('retains process isolation and serial worker policy', async () => {
178
+ const dir = project({ 'test/a.test.mjs': body("test('isolated',()=>{globalThis.nativeSentinel=1;assert.equal(1,1);});"),
179
+ 'test/b.test.mjs':body("test('separate',()=>assert.equal(globalThis.nativeSentinel,undefined));") });
180
+ expect((await execute(dir,['test/a.test.mjs','test/b.test.mjs'],{workers:2})).run.tests.passed).toBe(2);
181
+ expect((await execute(dir,['test/a.test.mjs','test/b.test.mjs'],{workers:4,serial:true})).run.tests.passed).toBe(2);
182
+ expect(existsSync(join(dir,'node_modules'))).toBe(false);
183
+ });
184
+
185
+ it('cleans its worker descendants on timeout and abnormal exit while preserving an unrelated sentinel', async () => {
186
+ const sentinel=spawn(process.execPath,['-e','setInterval(()=>{},1000)'],{stdio:'ignore'});
187
+ const source = body("import {spawn} from 'node:child_process';import {writeFileSync} from 'node:fs';test('child',()=>{const c=spawn(process.execPath,['-e','setInterval(()=>{},1000)'],{stdio:'ignore'});writeFileSync('owned.json',JSON.stringify([process.pid,c.pid]));while(true){}});");
188
+ const dir=project({'test/a.test.mjs':source});
189
+ try {
190
+ expect((await execute(dir,undefined,{budgetMs:800})).run.outcome).toBe('timeout');
191
+ const pids=JSON.parse(readFileSync(join(dir,'owned.json'),'utf8'));
192
+ for(const pid of pids)expect(alive(pid)).toBe(false);
193
+ expect(alive(sentinel.pid)).toBe(true);
194
+ writeFileSync(join(dir,'test/a.test.mjs'),source.replace('while(true){}','process.exit(0);'));
195
+ expect((await execute(dir)).run.outcome).toBe('error');
196
+ for(const pid of JSON.parse(readFileSync(join(dir,'owned.json'),'utf8')))expect(alive(pid)).toBe(false);
197
+ expect(alive(sentinel.pid)).toBe(true);
198
+ } finally {sentinel.kill('SIGKILL');}
199
+ }, 10_000);
200
+ });
@@ -0,0 +1,35 @@
1
+ // @req FR-10
2
+ // Focused admission defenders; runner-node.test.mjs retains runtime acceptance.
3
+ import { afterEach, describe, expect, it } from 'vitest';
4
+ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs';
5
+ import { join } from 'node:path';
6
+ import { tmpdir } from 'node:os';
7
+ import { check, run } from '../src/probe/runners/node-test.mjs';
8
+ import { selectRunner } from '../src/probe/runners/index.mjs';
9
+
10
+ const dirs = [];
11
+ const project = () => {
12
+ const dir = mkdtempSync(join(tmpdir(), 'tg-node-admission-'));
13
+ dirs.push(dir);
14
+ mkdirSync(join(dir, 'test'));
15
+ writeFileSync(join(dir, 'package.json'), '{"type":"module"}');
16
+ writeFileSync(join(dir, 'test/a.test.mjs'), "import { test } from 'node:test'; import assert from 'node:assert/strict'; test('real', () => assert.equal(2+2,4));\n");
17
+ return dir;
18
+ };
19
+ afterEach(() => { for (const dir of dirs.splice(0)) rmSync(dir, { recursive: true, force: true }); });
20
+
21
+ describe('native Node admission', () => {
22
+ it('runs without node_modules and records the actual built-in runtime', async () => {
23
+ expect(await check()).toEqual({ ok: true, version: process.versions.node, source: 'builtin' });
24
+ const dir = project();
25
+ const selected = await selectRunner({ projectDir: dir, name: 'node-test' });
26
+ expect(selected.runner.name).toBe('node-test'); expect(selected.testFiles).toBe(1);
27
+ expect((await run({ projectDir: dir, files: ['test/a.test.mjs'], budgetMs: 4000 })).run.outcome).toBe('pass');
28
+ });
29
+ it('refuses non-default loading and never silently routes a Node project through auto', async () => {
30
+ const original = process.env.NODE_OPTIONS; process.env.NODE_OPTIONS = '--import=unsupported';
31
+ try { expect((await check()).ok).toBe(false); } finally { if(original===undefined)delete process.env.NODE_OPTIONS;else process.env.NODE_OPTIONS=original; }
32
+ const selected = await selectRunner({ projectDir: project(), name: 'auto', budgetMs: 2000 });
33
+ expect(selected.runner?.name).not.toBe('node-test');
34
+ });
35
+ });
@@ -0,0 +1,81 @@
1
+ // @req FR-10
2
+ import { afterEach, describe, expect, it, vi } from 'vitest';
3
+ import { appendFileSync, mkdtempSync, rmSync, symlinkSync, writeFileSync } from 'node:fs';
4
+ import { join } from 'node:path';
5
+ import { tmpdir } from 'node:os';
6
+ import { readBoundedJsonFile } from '../src/probe/runners/discovery.mjs';
7
+
8
+ const race = vi.hoisted(() => ({ afterStat: undefined }));
9
+ vi.mock('node:fs', async (importOriginal) => {
10
+ const fs = await importOriginal();
11
+ return { ...fs, fstatSync: (...args) => {
12
+ const stat = fs.fstatSync(...args);
13
+ const change = race.afterStat;
14
+ race.afterStat = undefined;
15
+ change?.();
16
+ return stat;
17
+ } };
18
+ });
19
+
20
+ const dirs = [];
21
+ const reportFile = (text) => {
22
+ const dir = mkdtempSync(join(tmpdir(), 'tg-report-allocation-'));
23
+ dirs.push(dir);
24
+ const path = join(dir, 'report.json');
25
+ writeFileSync(path, text);
26
+ return path;
27
+ };
28
+ afterEach(() => {
29
+ race.afterStat = undefined;
30
+ vi.restoreAllMocks();
31
+ for (const dir of dirs.splice(0)) rmSync(dir, { recursive: true, force: true });
32
+ });
33
+
34
+ describe('bounded report allocation', () => {
35
+ it('can read a tiny report under a large byte ceiling without reserving the ceiling', () => {
36
+ const path = reportFile('{"cases":[]}');
37
+ const alloc = Buffer.alloc;
38
+ const sizes = [];
39
+ vi.spyOn(Buffer, 'alloc').mockImplementation((size, ...args) => {
40
+ sizes.push(size);
41
+ if (size > 1024) throw new Error('tiny report exceeded its memory allowance');
42
+ return alloc(size, ...args);
43
+ });
44
+ expect(readBoundedJsonFile(path, 1024 * 1024 * 1024)).toEqual({ cases: [] });
45
+ expect(sizes.length).toBeGreaterThan(0);
46
+ });
47
+
48
+ it('reads growth after the size snapshot instead of accepting a valid truncated prefix', () => {
49
+ const path = reportFile('{}');
50
+ race.afterStat = () => appendFileSync(path, ' x');
51
+ expect(() => readBoundedJsonFile(path, 32)).toThrow(/not valid JSON/);
52
+ });
53
+
54
+ it('can grow repeatedly to complete a report within the byte ceiling', () => {
55
+ const text = JSON.stringify({ text: 'x'.repeat(20_000) });
56
+ const path = reportFile(text.slice(0, 2));
57
+ race.afterStat = () => appendFileSync(path, text.slice(2));
58
+ expect(readBoundedJsonFile(path, Buffer.byteLength(text))).toEqual({ text: 'x'.repeat(20_000) });
59
+ });
60
+
61
+ it('rejects growth beyond the ceiling even when its initial prefix was valid JSON', () => {
62
+ const path = reportFile('{}');
63
+ race.afterStat = () => appendFileSync(path, ' '.repeat(100));
64
+ expect(() => readBoundedJsonFile(path, 16)).toThrow(/exceeded 16 bytes/);
65
+ });
66
+
67
+ it('keeps exact-byte, empty, UTF-8 and regular-file boundaries', () => {
68
+ const text = '{"text":"é"}';
69
+ const path = reportFile(text);
70
+ expect(readBoundedJsonFile(path, Buffer.byteLength(text))).toEqual({ text: 'é' });
71
+ expect(() => readBoundedJsonFile(path, Buffer.byteLength(text) - 1)).toThrow(/exceeded/);
72
+ writeFileSync(path, '');
73
+ expect(() => readBoundedJsonFile(path)).toThrow(/not valid JSON/);
74
+ writeFileSync(path, Buffer.from([0xff]));
75
+ expect(() => readBoundedJsonFile(path)).toThrow(/UTF-8/);
76
+ const link = join(dirs.at(-1), 'link.json');
77
+ symlinkSync(path, link);
78
+ expect(() => readBoundedJsonFile(link)).toThrow(/not readable/);
79
+ expect(() => readBoundedJsonFile(dirs.at(-1))).toThrow(/not a regular file/);
80
+ });
81
+ });
@@ -2,6 +2,37 @@
2
2
  "$schema": "./spec/schemas/claims.schema.json",
3
3
  "schemaVersion": 1,
4
4
  "claims": [
5
+ {
6
+ "id": "TG-REPORT-READ-ALLOCATION-TRACKS-FILE",
7
+ "statement": "Bounded runner-report reads reserve memory for observed file bytes rather than the maximum allowance, and still read a file that grows within the allowance without accepting a truncated prefix.",
8
+ "source": {
9
+ "kind": "manual",
10
+ "ref": "test/runner-report-allocation.test.mjs"
11
+ },
12
+ "severity": "high",
13
+ "producedBy": { "producer": "agent", "by": "codex" },
14
+ "defendedBy": ["test/runner-report-allocation.test.mjs"],
15
+ "faults": [
16
+ {
17
+ "id": "F1",
18
+ "description": "Reserve the maximum report allowance for every tiny file.",
19
+ "faultClass": "other",
20
+ "file": "src/probe/runners/discovery.mjs",
21
+ "find": " let bytes = Buffer.alloc(stat.size + 1);",
22
+ "replace": " let bytes = Buffer.alloc(maxBytes + 1);",
23
+ "producedBy": { "producer": "agent", "by": "codex" }
24
+ },
25
+ {
26
+ "id": "F2",
27
+ "description": "Stop reading when the initial size-based buffer fills.",
28
+ "faultClass": "guard-removed",
29
+ "file": "src/probe/runners/discovery.mjs",
30
+ "find": " if (length === bytes.length) {",
31
+ "replace": " if (false) {",
32
+ "producedBy": { "producer": "agent", "by": "codex" }
33
+ }
34
+ ]
35
+ },
5
36
  {
6
37
  "id": "TG-NODE-ENTRY-SELECTION-AND-LOADING",
7
38
  "statement": "Explicit native runs select files within the admitted canonical project root and refuse inherited alternative module loading before launching.",
@@ -15,7 +46,7 @@
15
46
  "by": "codex"
16
47
  },
17
48
  "defendedBy": [
18
- "test/runner-node.test.mjs"
49
+ "test/runner-node-admission.test.mjs"
19
50
  ],
20
51
  "faults": [
21
52
  {