stacktrace-cli 0.5.1__tar.gz → 0.5.3__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 (372) hide show
  1. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/PKG-INFO +30 -2
  2. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/README.md +29 -1
  3. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0031-one-host-daemon-observes-native-session-logs.md +1 -1
  4. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0036-deliver-eligible-findings-to-slack-from-the-daemon.md +1 -1
  5. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0045-scan-every-session-and-outlive-them.md +1 -1
  6. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0046-the-finding-store-is-an-append-only-queue.md +1 -1
  7. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0058-one-word-for-a-finding-columns-for-a-counter-and-a-push-that-does-not-wait.md +1 -1
  8. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0059-the-daemon-does-not-decide-whether-it-should-be-running.md +2 -2
  9. stacktrace_cli-0.5.3/docs/adrs/0066-host-owned-daemon-supervision.md +197 -0
  10. stacktrace_cli-0.5.3/docs/adrs/0067-a-webhook-is-an-independent-queue-subscriber.md +100 -0
  11. stacktrace_cli-0.5.3/docs/adrs/0068-webhooks-retry-the-retained-backlog.md +80 -0
  12. stacktrace_cli-0.5.3/docs/adrs/0069-webhooks-deliver-what-retention-holds.md +86 -0
  13. stacktrace_cli-0.5.3/docs/adrs/0070-package-the-cloud-agent-environment-bootstrap.md +162 -0
  14. stacktrace_cli-0.5.3/docs/adrs/0071-render-the-allowlisted-payload-per-destination.md +89 -0
  15. stacktrace_cli-0.5.3/docs/adrs/0072-host-supervisors-own-daemon-restarts.md +95 -0
  16. stacktrace_cli-0.5.3/docs/adrs/0073-name-what-fired-and-which-component.md +114 -0
  17. stacktrace_cli-0.5.3/docs/adrs/0074-a-window-selects-findings-by-when-they-happened.md +115 -0
  18. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/INDEX.md +12 -1
  19. stacktrace_cli-0.5.3/docs/releases/v0.5.2.md +215 -0
  20. stacktrace_cli-0.5.3/docs/releases/v0.5.3.md +70 -0
  21. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/specs/daemon-scanning.md +22 -30
  22. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/specs/notification-delivery.md +101 -59
  23. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/pyproject.toml +2 -1
  24. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/__init__.py +1 -1
  25. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/analysis.py +68 -6
  26. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/cli.py +2 -0
  27. stacktrace_cli-0.5.3/src/stacktrace_cli/cloud/__init__.py +39 -0
  28. stacktrace_cli-0.5.3/src/stacktrace_cli/cloud/setup.sh +274 -0
  29. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/daemon/activity_log.py +3 -3
  30. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/daemon/cli.py +168 -19
  31. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/daemon/client.py +134 -26
  32. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/daemon/config.py +14 -5
  33. stacktrace_cli-0.5.3/src/stacktrace_cli/daemon/lifecycle.py +172 -0
  34. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/daemon/paths.py +3 -6
  35. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/daemon/protocol.py +20 -1
  36. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/daemon/runtime.py +136 -101
  37. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/daemon/server.py +78 -0
  38. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/daemon/service.py +32 -17
  39. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/daemon/store.py +36 -3
  40. stacktrace_cli-0.5.3/src/stacktrace_cli/daemon/webhook.py +508 -0
  41. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/detector/render.py +8 -4
  42. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/monitor/site/app.js +1 -1
  43. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/monitor/site/index.html +3 -4
  44. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/monitor/watch.py +37 -1
  45. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/telemetry/events.py +3 -4
  46. stacktrace_cli-0.5.3/src/stacktrace_cli/webhook/__init__.py +1 -0
  47. stacktrace_cli-0.5.3/src/stacktrace_cli/webhook/cli.py +169 -0
  48. stacktrace_cli-0.5.3/src/stacktrace_cli/webhook/config.py +193 -0
  49. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/conftest.py +21 -6
  50. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/daemon/test_activity_log.py +23 -3
  51. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/daemon/test_cli.py +324 -32
  52. stacktrace_cli-0.5.3/tests/daemon/test_client.py +338 -0
  53. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/daemon/test_config.py +5 -4
  54. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/daemon/test_fleet.py +3 -1
  55. stacktrace_cli-0.5.3/tests/daemon/test_lifecycle.py +115 -0
  56. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/daemon/test_runtime.py +493 -32
  57. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/daemon/test_service.py +35 -18
  58. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/daemon/test_socket.py +99 -3
  59. stacktrace_cli-0.5.3/tests/daemon/test_webhook.py +1072 -0
  60. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/daemon/test_wire_frames_are_bounded.py +2 -0
  61. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/monitor/test_reasoning_gates.py +3 -1
  62. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/monitor/test_render.py +27 -0
  63. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/monitor/test_server.py +18 -6
  64. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/monitor/test_watch.py +33 -0
  65. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/remote/test_seam.py +12 -5
  66. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/remote/test_sync_detect.py +6 -1
  67. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_analysis.py +133 -0
  68. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_no_live_document_states_the_old_stage_three_default.py +7 -1
  69. stacktrace_cli-0.5.3/tests/test_title_disclosure_invariant.py +159 -0
  70. stacktrace_cli-0.5.3/tests/webhook/test_cli.py +662 -0
  71. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/uv.lock +1 -1
  72. stacktrace_cli-0.5.1/src/stacktrace_cli/daemon/version.py +0 -49
  73. stacktrace_cli-0.5.1/tests/daemon/test_client.py +0 -130
  74. stacktrace_cli-0.5.1/tests/daemon/test_version.py +0 -48
  75. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/.agents/skills/release-stacktrace/SKILL.md +0 -0
  76. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/.claude/settings.json +0 -0
  77. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/.claude/skills/release-stacktrace/SKILL.md +0 -0
  78. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/.codex/hooks.json +0 -0
  79. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/.github/managed-autofix.md +0 -0
  80. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/.github/workflows/autofix.yml +0 -0
  81. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/.github/workflows/ci.yml +0 -0
  82. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/.github/workflows/claude.yml +0 -0
  83. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/.github/workflows/publish-pypi.yml +0 -0
  84. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/.gitignore +0 -0
  85. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/AGENTS.md +0 -0
  86. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/CLAUDE.md +0 -0
  87. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0001-session-telemetry-as-input.md +0 -0
  88. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0002-session-collection-in-openaidr.md +0 -0
  89. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0003-runtime-edges.md +0 -0
  90. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0004-three-stage-detector.md +0 -0
  91. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0005-detection-family-and-report-assembly.md +0 -0
  92. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0006-trust-boundary-and-detection-upload.md +0 -0
  93. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0007-proprietary-package-on-open-dependencies.md +0 -0
  94. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0008-console-in-separate-demo-package.md +0 -0
  95. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0010-detection-severity-and-confidence-ladders.md +0 -0
  96. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0011-verdict-cache.md +0 -0
  97. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0012-observation-evidence-kinds-and-transport.md +0 -0
  98. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0013-rule-catalogue-triage-and-per-rule-context.md +0 -0
  99. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0014-declared-project-mapping.md +0 -0
  100. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0015-narrow-the-security-catalogue.md +0 -0
  101. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0016-stall-grouping-is-session-wide.md +0 -0
  102. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0017-a-declined-repeat-is-a-stall.md +0 -0
  103. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0018-remote-sync-config-and-facade-consumption.md +0 -0
  104. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0019-delegated-commands-are-openaca-objects.md +0 -0
  105. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0020-openaca-consumption-boundary.md +0 -0
  106. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0021-two-command-kinds.md +0 -0
  107. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0022-detection-scope-is-a-catalogue-column.md +0 -0
  108. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0023-sync-detect-collects-and-does-not-escalate.md +0 -0
  109. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0024-the-upload-carries-observations.md +0 -0
  110. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0025-a-denied-call-is-activity-never-an-invocation.md +0 -0
  111. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0026-the-console-becomes-a-product-surface.md +0 -0
  112. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0027-a-finding-may-name-what-it-could-not-place.md +0 -0
  113. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0028-the-console-shows-what-it-placed.md +0 -0
  114. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0029-stage-three-returns-to-opt-in.md +0 -0
  115. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0030-a-detection-is-dated-by-the-turns-it-cites.md +0 -0
  116. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0032-refresh-daemon-compositions-outside-detection.md +0 -0
  117. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0033-a-third-party-analyzer-only-by-a-flag-that-names-it.md +0 -0
  118. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0034-the-drift-grade-is-read-off-a-run-not-a-call.md +0 -0
  119. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0035-naming-an-analyzer-selects-stored-answers.md +0 -0
  120. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0037-reuse-openaidr-append-cursors-in-the-daemon.md +0 -0
  121. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0038-poll-normalized-sessions-for-supplemental-changes.md +0 -0
  122. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0039-send-usage-telemetry-by-default-with-an-opt-out.md +0 -0
  123. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0041-defer-native-windows-support.md +0 -0
  124. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0042-read-the-build-commit-from-the-install-record.md +0 -0
  125. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0043-name-the-session-agent-and-host-and-count-errors-by-class.md +0 -0
  126. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0044-send-the-build-as-version-prints-it.md +0 -0
  127. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0047-capture-activity-during-correlation-or-lose-it.md +0 -0
  128. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0048-the-daemon-keeps-a-leveled-content-free-activity-log.md +0 -0
  129. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0056-stop-a-resident-daemon-by-record-and-signal.md +0 -0
  130. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0057-grow-the-queue-schema-additively-and-share-only-the-document.md +0 -0
  131. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0060-two-upload-postures-not-one-command-with-two-sources.md +0 -0
  132. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0061-the-drain-sends-findings-only.md +0 -0
  133. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0062-hold-the-transition-lock-across-remote-side-effects.md +0 -0
  134. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0063-underbuilt-debt-does-not-hold-the-scan-watermark.md +0 -0
  135. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0064-a-redacted-value-has-one-path-span.md +0 -0
  136. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/0065-asset-external-id-resolves-by-a-ladder.md +0 -0
  137. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/HOOK-PROMPT.md +0 -0
  138. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/adrs/TEMPLATE.md +0 -0
  139. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/cutover-openaca-remote.md +0 -0
  140. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/plans/002-session-input.md +0 -0
  141. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/plans/003-correlation.md +0 -0
  142. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/plans/004-detector.md +0 -0
  143. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/plans/005-remote-sync.md +0 -0
  144. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/plans/006-cli-composition.md +0 -0
  145. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/plans/007-detection-upload.md +0 -0
  146. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/plans/008-monitor.md +0 -0
  147. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/plans/009-reasoning-jev.md +0 -0
  148. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/plans/010-session-daemon.md +0 -0
  149. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/plans/011-daemon-store.md +0 -0
  150. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/plans/012-daemon-scanning.md +0 -0
  151. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/plans/013-daemon-uploads.md +0 -0
  152. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/plans/014-asset-identity.md +0 -0
  153. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/releases/v0.0.1.md +0 -0
  154. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/releases/v0.1.0.md +0 -0
  155. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/releases/v0.2.0.md +0 -0
  156. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/releases/v0.2.1.md +0 -0
  157. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/releases/v0.2.2.md +0 -0
  158. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/releases/v0.2.3.md +0 -0
  159. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/releases/v0.3.0.md +0 -0
  160. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/releases/v0.3.1.md +0 -0
  161. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/releases/v0.4.0.md +0 -0
  162. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/releases/v0.4.1.md +0 -0
  163. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/releases/v0.5.0.md +0 -0
  164. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/releases/v0.5.1.md +0 -0
  165. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/research/001-intent-drift-metric.md +0 -0
  166. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/specs/aidr.md +0 -0
  167. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/specs/cli-composition.md +0 -0
  168. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/specs/correlation.md +0 -0
  169. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/specs/daemon-store.md +0 -0
  170. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/specs/daemon-uploads.md +0 -0
  171. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/specs/detection-upload.md +0 -0
  172. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/specs/detector.md +0 -0
  173. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/specs/event-time.md +0 -0
  174. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/specs/monitor.md +0 -0
  175. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/specs/reasoning-jev.md +0 -0
  176. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/specs/remote-sync.md +0 -0
  177. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/docs/specs/session-input.md +0 -0
  178. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/scripts/git-hooks/pre-push +0 -0
  179. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/scripts/install-hooks.sh +0 -0
  180. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/__main__.py +0 -0
  181. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/build.py +0 -0
  182. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/correlate/__init__.py +0 -0
  183. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/correlate/acquire.py +0 -0
  184. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/correlate/composition.py +0 -0
  185. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/correlate/join.py +0 -0
  186. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/correlate/observed.py +0 -0
  187. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/correlate/orchestrate.py +0 -0
  188. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/correlate/project_map.py +0 -0
  189. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/correlate/record.py +0 -0
  190. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/correlate/render.py +0 -0
  191. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/daemon/__init__.py +0 -0
  192. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/daemon/bom.py +0 -0
  193. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/daemon/composition.py +0 -0
  194. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/daemon/db.py +0 -0
  195. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/daemon/fleet.py +0 -0
  196. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/daemon/identity.py +0 -0
  197. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/daemon/jobs.py +0 -0
  198. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/daemon/observer.py +0 -0
  199. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/daemon/presentation.py +0 -0
  200. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/daemon/scan.py +0 -0
  201. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/detector/__init__.py +0 -0
  202. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/detector/analyzer.py +0 -0
  203. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/detector/blocked.py +0 -0
  204. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/detector/cache.py +0 -0
  205. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/detector/deterministic.py +0 -0
  206. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/detector/finding.py +0 -0
  207. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/detector/history.py +0 -0
  208. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/detector/jev.py +0 -0
  209. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/detector/priors.py +0 -0
  210. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/detector/prompts/__init__.py +0 -0
  211. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/detector/prompts/jev-v1/stacktrace-deceptive-completion.json +0 -0
  212. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/detector/prompts/jev-v2/stacktrace-deceptive-completion.json +0 -0
  213. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/detector/prompts/v1/exclusions.md +0 -0
  214. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/detector/prompts/v1/framing.md +0 -0
  215. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/detector/prompts/v1/stacktrace-deceptive-completion.md +0 -0
  216. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/detector/reasoning.py +0 -0
  217. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/detector/rules.py +0 -0
  218. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/detector/run.py +0 -0
  219. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/detector/secrets.py +0 -0
  220. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/detector/verdict.py +0 -0
  221. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/detector/windows.py +0 -0
  222. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/monitor/__init__.py +0 -0
  223. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/monitor/reasoning.py +0 -0
  224. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/monitor/render.py +0 -0
  225. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/monitor/server.py +0 -0
  226. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/monitor/site/fonts/OFL.txt +0 -0
  227. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/monitor/site/fonts/dm-mono-400-latin.woff2 +0 -0
  228. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/monitor/site/fonts/dm-mono-500-latin.woff2 +0 -0
  229. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/monitor/site/fonts/dm-sans-latin.woff2 +0 -0
  230. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/monitor/site/styles.css +0 -0
  231. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/monitor/state.py +0 -0
  232. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/monitor/verdicts.py +0 -0
  233. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/options.py +0 -0
  234. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/private_state.py +0 -0
  235. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/remote/__init__.py +0 -0
  236. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/remote/cli.py +0 -0
  237. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/remote/client.py +0 -0
  238. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/remote/config.py +0 -0
  239. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/remote/detect_payload.py +0 -0
  240. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/remote/identity.py +0 -0
  241. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/remote/payload.py +0 -0
  242. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/remote/policy.py +0 -0
  243. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/remote/redact.py +0 -0
  244. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/remote/spool.py +0 -0
  245. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/remote/sync.py +0 -0
  246. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/remote/sync_detect.py +0 -0
  247. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/remote/upload_contract.py +0 -0
  248. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/sessions/__init__.py +0 -0
  249. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/sessions/access.py +0 -0
  250. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/sessions/index.py +0 -0
  251. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/sessions/outcome.py +0 -0
  252. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/sessions/protocols.py +0 -0
  253. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/sessions/render.py +0 -0
  254. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/telemetry/__init__.py +0 -0
  255. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/telemetry/cli.py +0 -0
  256. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/telemetry/posthog.py +0 -0
  257. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/src/stacktrace_cli/telemetry/state.py +0 -0
  258. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/__init__.py +0 -0
  259. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/agent_bom_fixture.py +0 -0
  260. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/daemon/__init__.py +0 -0
  261. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/daemon/test_composition.py +0 -0
  262. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/daemon/test_db.py +0 -0
  263. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/daemon/test_detection_needs_no_subscriber.py +0 -0
  264. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/daemon/test_identity.py +0 -0
  265. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/daemon/test_jobs.py +0 -0
  266. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/daemon/test_observer.py +0 -0
  267. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/daemon/test_queue_reader.py +0 -0
  268. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/daemon/test_scan.py +0 -0
  269. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/daemon/test_store.py +0 -0
  270. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/daemon/test_the_drained_payload_is_the_cold_one.py +0 -0
  271. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/daemon/test_the_stored_row_is_sufficient.py +0 -0
  272. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/detector_session_fixture.py +0 -0
  273. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/monitor/__init__.py +0 -0
  274. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/monitor/feed_harness.mjs +0 -0
  275. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/monitor/test_feed_model.py +0 -0
  276. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/monitor/test_site_assets.py +0 -0
  277. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/monitor/test_state.py +0 -0
  278. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/monitor/test_verdicts.py +0 -0
  279. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/remote/__init__.py +0 -0
  280. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/remote/helpers.py +0 -0
  281. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/remote/test_cli.py +0 -0
  282. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/remote/test_client.py +0 -0
  283. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/remote/test_config.py +0 -0
  284. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/remote/test_detect_activity.py +0 -0
  285. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/remote/test_detect_cli.py +0 -0
  286. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/remote/test_detect_client.py +0 -0
  287. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/remote/test_detect_contract_is_exhaustive.py +0 -0
  288. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/remote/test_detect_gate_matches_the_cloud.py +0 -0
  289. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/remote/test_detect_layers_compose.py +0 -0
  290. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/remote/test_detect_payload_reaches_the_cloud_model.py +0 -0
  291. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/remote/test_detect_redaction.py +0 -0
  292. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/remote/test_detect_spool.py +0 -0
  293. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/remote/test_detect_upload_contract.py +0 -0
  294. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/remote/test_detect_wire_payload.py +0 -0
  295. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/remote/test_facade_contract.py +0 -0
  296. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/remote/test_identity.py +0 -0
  297. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/remote/test_no_local_path_survives_redaction.py +0 -0
  298. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/remote/test_payload.py +0 -0
  299. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/remote/test_policy.py +0 -0
  300. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/remote/test_redact_payload.py +0 -0
  301. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/remote/test_spool.py +0 -0
  302. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/remote/test_sync.py +0 -0
  303. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/remote/test_upload_contract.py +0 -0
  304. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/telemetry/__init__.py +0 -0
  305. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/telemetry/test_activity_log.py +0 -0
  306. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/telemetry/test_cli.py +0 -0
  307. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/telemetry/test_events.py +0 -0
  308. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/telemetry/test_hooks.py +0 -0
  309. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/telemetry/test_release_gate.py +0 -0
  310. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/telemetry/test_state.py +0 -0
  311. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/telemetry/test_uploader.py +0 -0
  312. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_acquire.py +0 -0
  313. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_adr_cross_references_are_reciprocal.py +0 -0
  314. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_agent_instance_id.py +0 -0
  315. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_bom_shape.py +0 -0
  316. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_build_commit.py +0 -0
  317. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_call_status_conventions.py +0 -0
  318. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_cli.py +0 -0
  319. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_composition.py +0 -0
  320. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_correlate_orchestrate.py +0 -0
  321. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_correlate_render.py +0 -0
  322. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_correlated_session.py +0 -0
  323. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_detection_components.py +0 -0
  324. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_detection_event_time.py +0 -0
  325. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_detection_subject.py +0 -0
  326. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_detector_analyzer_contract.py +0 -0
  327. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_detector_analyzer_live.py +0 -0
  328. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_detector_blocked.py +0 -0
  329. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_detector_cache.py +0 -0
  330. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_detector_deterministic.py +0 -0
  331. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_detector_end_to_end.py +0 -0
  332. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_detector_finding.py +0 -0
  333. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_detector_history.py +0 -0
  334. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_detector_jev.py +0 -0
  335. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_detector_priors.py +0 -0
  336. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_detector_prompts.py +0 -0
  337. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_detector_reasoning.py +0 -0
  338. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_detector_render.py +0 -0
  339. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_detector_run.py +0 -0
  340. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_detector_secrets.py +0 -0
  341. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_detector_verdict.py +0 -0
  342. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_detector_why_it_stopped.py +0 -0
  343. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_detector_windows.py +0 -0
  344. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_evidence_is_dated_not_numbered.py +0 -0
  345. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_fingerprint_covers_what_the_analyzer_reads.py +0 -0
  346. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_help_sections.py +0 -0
  347. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_join.py +0 -0
  348. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_monitor_cli.py +0 -0
  349. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_no_test_undoes_every_patch_at_once.py +0 -0
  350. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_observed.py +0 -0
  351. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_openaca_contract.py +0 -0
  352. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_openaidr_contract.py +0 -0
  353. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_option_arity_matches_the_binary.py +0 -0
  354. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_project_map.py +0 -0
  355. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_readme_examples_are_real_output.py +0 -0
  356. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_release_gate_coverage.py +0 -0
  357. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_release_readiness.py +0 -0
  358. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_seam_boundary.py +0 -0
  359. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_session_identity_is_the_pair.py +0 -0
  360. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_sessions_access.py +0 -0
  361. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_sessions_end_to_end.py +0 -0
  362. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_sessions_protocol_typing.py +0 -0
  363. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_sessions_protocols.py +0 -0
  364. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_sessions_render.py +0 -0
  365. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_shell_separators_match_the_shell.py +0 -0
  366. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_stored_verdicts_are_never_gated_on_reasoning.py +0 -0
  367. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_the_detector_spec_lists_the_shipped_catalogue.py +0 -0
  368. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_the_jev_spec_states_the_shipped_thresholds.py +0 -0
  369. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_the_locality_claim_is_qualified_everywhere.py +0 -0
  370. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_untrusted_content_never_travels.py +0 -0
  371. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_verification_subcommands_match_the_binary.py +0 -0
  372. {stacktrace_cli-0.5.1 → stacktrace_cli-0.5.3}/tests/test_what_jev_is_told_is_what_was_disclosed.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: stacktrace-cli
3
- Version: 0.5.1
3
+ Version: 0.5.3
4
4
  Summary: CLI for Stacktrace — Detection and Response platform for AI Agents.
5
5
  Project-URL: Homepage, https://stacktrace.ai
6
6
  Author-email: "Stacktrace AI, Inc" <founders@stacktrace.ai>
@@ -51,7 +51,7 @@ Requires Python 3.11 or newer.
51
51
 
52
52
  ```console
53
53
  $ stacktrace --version
54
- stacktrace 0.5.1 (openaca 0.7.0)
54
+ stacktrace 0.5.3 (openaca 0.7.0)
55
55
  ```
56
56
 
57
57
  ## Quick start
@@ -70,6 +70,7 @@ stacktrace monitor # the same, live in a browser
70
70
  | `detect` | Find security and reliability findings in what agents did. |
71
71
  | `monitor` | Watch this machine's agents in a browser, live. |
72
72
  | `remote` | Configure remote endpoint services and upload to Stacktrace Cloud. |
73
+ | `webhook` | Send eligible daemon findings to a host-level HTTPS endpoint. |
73
74
  | `scan` | Scan a repository or endpoint for agent-composition findings. |
74
75
  | `bom` | Generate an Agent BOM for a repository or endpoint. |
75
76
  | `policy` | Validate and compile restrictive endpoint policies. |
@@ -78,6 +79,33 @@ The last three are composition analysis, supplied by
78
79
  [`openaca`](https://pypi.org/project/openaca/) and available under either
79
80
  name.
80
81
 
82
+ ### Webhook notifications
83
+
84
+ Configure one host-level endpoint; the running daemon delivers retained eligible
85
+ findings and new findings automatically:
86
+
87
+ ```bash
88
+ stacktrace webhook configure --url https://alerts.example.com/stacktrace
89
+ stacktrace webhook status
90
+ stacktrace webhook disable
91
+ ```
92
+
93
+ `configure` prompts for an optional HMAC-SHA256 signing secret without echoing
94
+ it. The endpoint receives a narrow JSON document containing the event ID, rule,
95
+ severity, confidence and session identity—not transcript content, finding prose
96
+ or evidence. Delivery is at least once, so receivers should deduplicate on
97
+ `event_id`. The URL and secret are stored in a mode-0600 host configuration
98
+ file. HTTP is accepted only for loopback development endpoints.
99
+
100
+ Failed deliveries retry without a limit while enabled. Outages can grow the
101
+ local backlog, bounded by the local retention window—findings older than that
102
+ when the endpoint next accepts requests are not sent. Changing the endpoint
103
+ sends the remaining backlog to the new destination; rotating its signing
104
+ secret preserves progress. Configure and disable take effect from the next
105
+ request: one already in flight may still complete with the previous
106
+ configuration. Re-enabling resumes only pending findings still within the
107
+ retention window, not already-delivered findings.
108
+
81
109
  ## What it looks like
82
110
 
83
111
  ```console
@@ -24,7 +24,7 @@ Requires Python 3.11 or newer.
24
24
 
25
25
  ```console
26
26
  $ stacktrace --version
27
- stacktrace 0.5.1 (openaca 0.7.0)
27
+ stacktrace 0.5.3 (openaca 0.7.0)
28
28
  ```
29
29
 
30
30
  ## Quick start
@@ -43,6 +43,7 @@ stacktrace monitor # the same, live in a browser
43
43
  | `detect` | Find security and reliability findings in what agents did. |
44
44
  | `monitor` | Watch this machine's agents in a browser, live. |
45
45
  | `remote` | Configure remote endpoint services and upload to Stacktrace Cloud. |
46
+ | `webhook` | Send eligible daemon findings to a host-level HTTPS endpoint. |
46
47
  | `scan` | Scan a repository or endpoint for agent-composition findings. |
47
48
  | `bom` | Generate an Agent BOM for a repository or endpoint. |
48
49
  | `policy` | Validate and compile restrictive endpoint policies. |
@@ -51,6 +52,33 @@ The last three are composition analysis, supplied by
51
52
  [`openaca`](https://pypi.org/project/openaca/) and available under either
52
53
  name.
53
54
 
55
+ ### Webhook notifications
56
+
57
+ Configure one host-level endpoint; the running daemon delivers retained eligible
58
+ findings and new findings automatically:
59
+
60
+ ```bash
61
+ stacktrace webhook configure --url https://alerts.example.com/stacktrace
62
+ stacktrace webhook status
63
+ stacktrace webhook disable
64
+ ```
65
+
66
+ `configure` prompts for an optional HMAC-SHA256 signing secret without echoing
67
+ it. The endpoint receives a narrow JSON document containing the event ID, rule,
68
+ severity, confidence and session identity—not transcript content, finding prose
69
+ or evidence. Delivery is at least once, so receivers should deduplicate on
70
+ `event_id`. The URL and secret are stored in a mode-0600 host configuration
71
+ file. HTTP is accepted only for loopback development endpoints.
72
+
73
+ Failed deliveries retry without a limit while enabled. Outages can grow the
74
+ local backlog, bounded by the local retention window—findings older than that
75
+ when the endpoint next accepts requests are not sent. Changing the endpoint
76
+ sends the remaining backlog to the new destination; rotating its signing
77
+ secret preserves progress. Configure and disable take effect from the next
78
+ request: one already in flight may still complete with the previous
79
+ configuration. Re-enabling resumes only pending findings still within the
80
+ retention window, not already-delivered findings.
81
+
54
82
  ## What it looks like
55
83
 
56
84
  ```console
@@ -6,7 +6,7 @@ date: 2026-09-17
6
6
  supersedes: null
7
7
  superseded-by: null
8
8
  amends: 0006
9
- amended-by: 0032, 0036, 0037, 0038, 0039, 0045, 0046
9
+ amended-by: 0032, 0036, 0037, 0038, 0039, 0045, 0046, 0066, 0072
10
10
  ---
11
11
 
12
12
  ## Context
@@ -6,7 +6,7 @@ date: 2026-09-20
6
6
  supersedes: null
7
7
  superseded-by: null
8
8
  amends: 0031
9
- amended-by: null
9
+ amended-by: 0067
10
10
  ---
11
11
 
12
12
  Subsystem: the daemon and its delivery sinks. The integration view across the
@@ -6,7 +6,7 @@ date: 2026-09-22
6
6
  supersedes: null
7
7
  superseded-by: null
8
8
  amends: 0031, 0037, 0038
9
- amended-by: 0056, 0058
9
+ amended-by: 0056, 0058, 0066, 0072
10
10
  ---
11
11
 
12
12
  ## Context
@@ -6,7 +6,7 @@ date: 2026-09-22
6
6
  supersedes: null
7
7
  superseded-by: null
8
8
  amends: 0031
9
- amended-by: 0057, 0058
9
+ amended-by: 0057, 0058, 0067
10
10
  ---
11
11
 
12
12
  ## Context
@@ -6,7 +6,7 @@ date: 2026-09-23
6
6
  supersedes: null
7
7
  superseded-by: null
8
8
  amends: 0045, 0046, 0047, 0057
9
- amended-by: 0059
9
+ amended-by: 0059, 0066, 0072
10
10
  ---
11
11
 
12
12
  ## Context
@@ -1,10 +1,10 @@
1
1
  ---
2
2
  id: 0059
3
3
  title: The daemon does not decide whether it should be running
4
- status: accepted
4
+ status: superseded
5
5
  date: 2026-09-23
6
6
  supersedes: 0056
7
- superseded-by: null
7
+ superseded-by: 0066
8
8
  amends: 0058
9
9
  amended-by: null
10
10
  ---
@@ -0,0 +1,197 @@
1
+ ---
2
+ id: 0066
3
+ title: Put daemon lifetime under host-owned supervision
4
+ status: superseded
5
+ date: 2026-09-23
6
+ supersedes: 0059
7
+ superseded-by: 0072
8
+ amends: 0031, 0045, 0058
9
+ amended-by: null
10
+ ---
11
+
12
+ ## Context
13
+
14
+ ADR-0031 tied daemon lifetime to subscribers, and ADR-0045 made the daemon
15
+ resident without changing who starts it. The plugin monitor still calls
16
+ `ensure_daemon()`, which forks `daemon run` as the monitor's child. Starting a
17
+ new session keeps terminal signals away from the child, but does not remove it
18
+ from the monitor's process tree.
19
+
20
+ That distinction caused an outage on 2026-09-22. Ending one Claude session
21
+ killed its monitor's entire descendant tree, including the daemon that other
22
+ sessions were using. Their monitors lost the socket and one eventually started
23
+ a replacement. The terminated daemon wrote no traceback, skipped shutdown
24
+ cleanup, left its socket behind and did not flush telemetry. A focused
25
+ reproduction showed why: `setsid` survives a signal to the parent or its
26
+ process group, but not a tree kill that follows parent identifiers.
27
+
28
+ The first subscriber therefore cannot own a machine-wide service. The hosts
29
+ also provide no single supervisor API. Laptops have launchd or systemd;
30
+ Niteshift has declared services; Claude Code and Codex cloud sandboxes have no
31
+ usable user systemd; Claude Managed Agents expose no startup hook. Except for
32
+ Managed Agents, each environment can still run owner-controlled setup or
33
+ session-start commands.
34
+
35
+ Cloud probes established the portable minimum. A process survives into the
36
+ agent phase when its launcher calls `setsid`, double-forks, redirects standard
37
+ streams and closes every inherited descriptor. On Codex, leaving even one
38
+ runner descriptor open prevents setup from finishing. Cached Codex containers
39
+ can also run setup and maintenance starters together, so concurrent starts are
40
+ normal rather than exceptional.
41
+
42
+ ADR-0059 removed every lifecycle command in favor of a future external
43
+ supervisor. That is sufficient on a host with launchd, systemd or a declared
44
+ service, but it leaves cloud sandboxes without a lifecycle owner even though
45
+ their setup hooks can safely launch a fully detached process. This decision
46
+ supersedes ADR-0059: the daemon still does not decide whether it should run,
47
+ but Stacktrace supplies a portable supervisor for hosts that do not have one.
48
+
49
+ ## Decision
50
+
51
+ Daemon lifecycle belongs to host configuration. Agent adapters and monitors
52
+ only connect; they never create a daemon as a side effect of subscribing. A
53
+ host may invoke Stacktrace's detached supervisor from a setup or SessionStart
54
+ hook, but the resulting process is not owned by that agent session.
55
+
56
+ 1. **`stacktrace daemon run` is the foreground service.** It remains attached
57
+ to its caller until it stops, so an external supervisor or container
58
+ entrypoint can observe it directly. SIGTERM and SIGINT stop the tick loop,
59
+ flush telemetry, close compositions, remove the socket and return the
60
+ deliberate shutdown status. If another daemon holds `daemon.lock`, `run`
61
+ returns without taking ownership. The running process continues to write
62
+ its pid, version and effective configuration to the run-state file, and
63
+ `daemon status` reads that record rather than re-deriving configuration from
64
+ its own environment.
65
+ 2. **`stacktrace daemon start` launches a detached supervisor.** The launcher
66
+ calls `setsid`, double-forks, redirects stdin from `/dev/null`, sends stdout
67
+ and stderr to the daemon log and closes every caller-provided descriptor. A
68
+ private readiness channel may survive long enough to report that the
69
+ detached process acquired `supervisor.lock`, but it is closed before
70
+ `start` returns. Two concurrent starts therefore converge on one supervisor
71
+ and both commands succeed. The supervisor keeps only descriptors it owns.
72
+ 3. **Every daemon child starts through a fresh exec of the installed CLI.** The
73
+ supervisor never forks an already-imported daemon or calls it in-process.
74
+ This is the boundary that makes a restart load newly installed code while
75
+ allowing the small supervisor loop itself to remain old.
76
+ 4. **Exit status controls supervision.** Zero means the daemon chose to stay
77
+ down; non-zero means start it again. `daemon stop` and a recorded
78
+ `daemon disable` return zero. Lock contention and an already-live socket
79
+ return non-zero instead: they mean another process already holds the role,
80
+ not that the role is deliberately unfilled, and nothing here confirms that
81
+ process has a supervisor of its own. This is the case a host hits the first
82
+ time it layers this supervisor onto a daemon still running from the
83
+ pre-ADR-0066 `ensure_daemon()` path — treating that as "stay down" would
84
+ exit the only supervisor watching the machine and strand the daemon the
85
+ moment it later exits for its own `version_label()` restart. A stop meant
86
+ to hold through that retry window must be `daemon disable`: its marker is
87
+ checked before every fresh-exec'd child opens a socket, supervisor retries
88
+ included, while `daemon stop` reaches only the process it signals — the
89
+ incumbent, not a supervisor waiting behind it, so the supervisor still
90
+ takes over once the incumbent is gone. An unhandled crash also returns
91
+ non-zero. Version divergence from ADR-0045 returns a dedicated non-zero
92
+ restart code. Stop and disable take precedence if they race with an
93
+ upgrade. External supervisor recipes use restart-on-failure semantics.
94
+ 5. **The detached supervisor restarts with bounded backoff.** It waits one
95
+ second after a non-zero exit, doubles to at most thirty seconds, and resets
96
+ the delay after the child has stayed up for sixty seconds. SIGTERM sent to
97
+ the supervisor is forwarded to the child, whose exit is awaited before the
98
+ supervisor exits. A zero child exit ends the supervisor.
99
+ 6. **Subscribing has no lifecycle side effect.** `ensure_daemon()` is deleted.
100
+ `daemon subscribe` reports once that no daemon is running, keeps retrying and
101
+ reports when it reconnects. The socket handshake carries an integer protocol
102
+ version: a compatibility epoch, not a package or build version. Only an
103
+ exact match proceeds. On a mismatch the daemon returns
104
+ `unsupported_version` and closes that connection; the subscriber reports
105
+ that the agent session must be restarted and exits instead of retrying. The
106
+ daemon remains running because one incompatible subscriber must not disrupt
107
+ other sessions. Daemon code freshness remains the separate
108
+ `version_label()` exit-and-restart decision from ADR-0045.
109
+ 7. **The host decides when to call `start`.** A person does so on a laptop. A
110
+ repository SessionStart hook may do so in Claude Code cloud, and Codex cloud
111
+ may do so from setup and maintenance scripts. Niteshift and containers run
112
+ `daemon run` under their native supervisor. These are deployment recipes,
113
+ not plugin behavior.
114
+
115
+ This replaces ADR-0031 decision 6 and ADR-0045's assumption that
116
+ `ensure_daemon()` remains the daemon's starter. ADR-0031's routing,
117
+ persistence and delivery decisions, and ADR-0045's scanning, stop and disable
118
+ decisions, remain in force. It supersedes ADR-0059's removal of lifecycle
119
+ commands: host configuration still owns the decision, while `daemon start`
120
+ provides the supervisor on hosts that lack a native one.
121
+
122
+ ## Alternatives considered
123
+
124
+ - **Install launchd and systemd units.** Rejected for now. Neither helps in the
125
+ cloud sandboxes, and a daemon needed only while agents run does not yet
126
+ justify platform-specific install, detection and uninstall paths. Revisit
127
+ when laptops need pre-session or reboot persistence.
128
+ - **Expose only detached `daemon start`.** Rejected because native supervisors
129
+ need a foreground process whose lifetime and exit status they own. A forking
130
+ service conflicts with systemd control groups, launchd process groups,
131
+ declared sandbox services and container entrypoints.
132
+ - **Keep `ensure_daemon()` and make its child detach correctly.** Rejected
133
+ because it fixes ancestry but not ownership. Connection would still decide
134
+ whether the machine-wide service exists, and host configuration could not
135
+ choose its start boundary.
136
+ - **Start the daemon from the plugin's own SessionStart hook.** Rejected. A
137
+ host-owned hook may invoke `start`, but daemon availability is not a plugin
138
+ responsibility and other agent adapters must not copy that behavior.
139
+ - **Use launchd or systemd socket activation.** Rejected because the daemon
140
+ would have to adopt inherited sockets on both platforms, while the sandbox
141
+ hosts would still need another lifecycle mechanism.
142
+ - **Require `daemon start --restart` after every upgrade.** Rejected because it
143
+ is easy to omit and leaves every monitor reporting an obsolete daemon until
144
+ someone intervenes. The fresh-exec restart code makes the installed upgrade
145
+ take effect without adding a provisioning step.
146
+ - **Compare package or build versions during the socket handshake.** Rejected
147
+ because code freshness and wire compatibility are different facts. Commit
148
+ labels are not orderable, while compatible package releases should not end a
149
+ working subscription. The protocol epoch changes only when the wire becomes
150
+ incompatible.
151
+ - **Stop both processes on a protocol mismatch.** Rejected because the daemon
152
+ is shared across sessions. A stale subscriber may end its own connection and
153
+ process; it cannot take down delivery for compatible subscribers.
154
+
155
+ ## Consequences
156
+
157
+ An agent session can end, crash or have its descendant tree killed without
158
+ taking down the daemon used by other sessions. Adapters become strict clients,
159
+ which gives later Codex and Cursor integrations the same lifecycle boundary as
160
+ Claude.
161
+
162
+ The portable supervisor is intentionally small, but nothing supervises that
163
+ supervisor. If it dies, its current child can continue, but no replacement is
164
+ launched after that child exits until the host calls `start` again. A laptop
165
+ also needs another `start` after logout or reboot.
166
+
167
+ Full descriptor closure is part of correctness. A test must hold a pipe on an
168
+ extra descriptor across `start` and observe EOF. A second test must replace the
169
+ installed version, cause version divergence and prove that the next child
170
+ executes the new code rather than the supervisor's imported code.
171
+
172
+ Protocol tests must prove that an exact epoch match subscribes, a mismatch
173
+ ends the subscriber with restart guidance, and the daemon remains available to
174
+ a subsequent compatible subscriber.
175
+
176
+ A migration test must start a daemon directly, the way the deleted
177
+ `ensure_daemon()` did, then start the supervisor against it and prove the
178
+ supervisor keeps retrying with backoff rather than exiting, and that it takes
179
+ over once the direct process exits. A second case must prove `daemon disable`
180
+ recorded during that retry window keeps the supervisor down, while a bare
181
+ `daemon stop` against the direct process only ends that process and does not
182
+ stop the waiting supervisor from taking over.
183
+
184
+ The host must run Stacktrace as the same user as the agents it observes. The
185
+ daemon reads that user's agent logs and binds below `/tmp/stacktrace-$UID/`.
186
+ Claude Managed Agents cannot run this daemon until they expose a startup or
187
+ supervised-service mechanism; self-hosted environments can use their image
188
+ entrypoint.
189
+
190
+ ## When to revisit
191
+
192
+ - Add launchd or systemd installation when laptops need automatic startup or
193
+ reboot persistence.
194
+ - Prefer a sandbox's native service manager whenever it provides one.
195
+ - Reconsider the portable supervisor if its own failures become material.
196
+ - Revisit cloud deployment if an agent host removes owner-controlled startup
197
+ commands or supplies a first-class replacement.
@@ -0,0 +1,100 @@
1
+ ---
2
+ id: 0067
3
+ title: A webhook is an independent queue subscriber with an allowlisted payload
4
+ status: accepted
5
+ date: 2026-09-24
6
+ supersedes: null
7
+ superseded-by: null
8
+ amends: 0036, 0046
9
+ amended-by: 0068, 0071, 0073
10
+ ---
11
+
12
+ ## Context
13
+
14
+ The daemon already delivers eligible findings to the active agent session and
15
+ to Fleet. A host owner also needs a generic integration point for destinations
16
+ such as an incident router or automation service, without installing an
17
+ agent-specific adapter or making Fleet availability a prerequisite.
18
+
19
+ The finding queue now has a monotonic sequence and a cursor per subscriber and
20
+ agent-kind partition. That makes the generic sink a queue reader, not another
21
+ branch on the scan path. The stored finding is intentionally richer than any
22
+ outbound payload, so forwarding it directly would also widen the data boundary
23
+ to detector prose, evidence descriptors, spans and component details.
24
+
25
+ ## Decision
26
+
27
+ One optional host-level webhook is a subscriber named `webhook`.
28
+
29
+ - It reads every queue revision in order and advances its own cursor only after
30
+ an HTTP 2xx. A failed request holds that row for retry and cannot move or
31
+ block the Fleet cursor.
32
+ - Only the exact revision that first crossed the local notification gate is
33
+ delivered. Later revisions still advance the cursor but do not ring again.
34
+ - Configuration time is the lower delivery bound. Enabling a webhook does not
35
+ replay findings that predate the configuration.
36
+ - The JSON body is an allowlist: schema version, event type, event ID, rule ID,
37
+ severity, confidence, agent kind and native session ID. Stored titles,
38
+ remediation, evidence, spans, participants and unknown records never enter
39
+ the mapper.
40
+ - Delivery is at least once. A process can stop after the remote endpoint
41
+ accepts a request and before SQLite commits the cursor, so receivers use the
42
+ stable event ID as their idempotency key.
43
+ - The endpoint is HTTPS, except that HTTP is accepted on loopback for local
44
+ development. Userinfo and fragments are refused. An optional secret signs
45
+ the exact request bytes with HMAC-SHA256.
46
+ - The URL, optional signing secret and configuration time live in a private
47
+ host file. CLI output and daemon logs never print the URL path, query,
48
+ secret, response body or exception message.
49
+ - A scan commit wakes a single webhook worker thread; the daemon's scan and
50
+ scheduler thread never waits on HTTP. Wakes coalesce while a delivery is in
51
+ progress. A one-minute job is the retry fallback; setting its interval to
52
+ zero disables only that fallback.
53
+
54
+ This amends ADR-0036's proposed fan-out implementation. The independence and
55
+ per-destination acknowledgement rules remain, but SQLite cursors introduced by
56
+ ADR-0046 are the durable fan-out mechanism for resident subscribers; no shared
57
+ sink registry or per-event acknowledgement map is added.
58
+
59
+ ## Alternatives considered
60
+
61
+ - **Send from the scanner callback.** Rejected: network latency and failure
62
+ would enter the detection hot path, and a crash after the scan would lose the
63
+ only delivery attempt.
64
+ - **Reuse Fleet's cursor.** Rejected: whichever destination acknowledged first
65
+ would skip work for the other, and a slow webhook would block Fleet.
66
+ - **Forward the stored finding.** Rejected: storage is not a wire contract and
67
+ contains fields this destination does not need. The allowlist is the data
68
+ boundary.
69
+ - **Add a delivery row for every `(event_id, sink)`.** Rejected: delivery is
70
+ ordered within each agent-kind partition, so the existing subscriber cursor
71
+ already represents every acknowledgement below it.
72
+ - **Replay the retained backlog when configured.** Rejected: configuration is
73
+ consent for future delivery, not consent to export findings retained before
74
+ that choice.
75
+ - **Exactly-once delivery.** Rejected: it requires the receiver to participate
76
+ in a transaction with the local database. Stable event IDs make receiver-side
77
+ deduplication possible without claiming an impossible transport guarantee.
78
+
79
+ ## Consequences
80
+
81
+ A webhook outage accumulates work behind only its own cursor. Retention keeps
82
+ that backlog while the subscriber remains configured, so a permanently broken
83
+ endpoint can increase local database use until it is disabled.
84
+
85
+ Receivers get enough information to route and deduplicate an alert, but not a
86
+ human-readable explanation. They use the event ID and session identity to link
87
+ back to the local finding rather than asking the endpoint to export more data.
88
+
89
+ Changing the endpoint starts a new consent boundary at the new configuration
90
+ time. Re-entering the same endpoint preserves that time so rotating its signing
91
+ secret does not silently skip a retry already in progress.
92
+
93
+ ## When to revisit
94
+
95
+ - If more than one generic webhook per host is required; each needs its own
96
+ stable subscriber identity and cursor.
97
+ - If receivers need more context; widening the payload requires a new data-
98
+ boundary decision and exhaustive non-leak tests.
99
+ - If queue partitions can be delivered concurrently; ordering and cursor
100
+ advancement would need a lease or another claim mechanism.
@@ -0,0 +1,80 @@
1
+ ---
2
+ id: 0068
3
+ title: Webhooks retry the retained backlog without a configuration-time cutoff
4
+ status: accepted
5
+ date: 2026-09-25
6
+ supersedes: null
7
+ superseded-by: null
8
+ amends: 0067
9
+ amended-by: 0069
10
+ ---
11
+
12
+ ## Context
13
+
14
+ ADR-0067 already provides durable delivery through an independent subscriber
15
+ cursor. Its configuration-time lower bound adds timestamp validation and clock
16
+ ordering to a queue that already has an ordered sequence. It also discards
17
+ pending deliveries when the endpoint changes. These semantics are unnecessary
18
+ for a single host-level destination whose purpose is reliable alerting.
19
+
20
+ ## Decision
21
+
22
+ Amend ADR-0067's configuration-time lower bound, configuration fields and
23
+ endpoint-change behavior. Its payload, eligibility, signing, independent cursor
24
+ and asynchronous worker decisions remain in force.
25
+
26
+ - First enable delivers eligible findings still retained in the queue. The CLI
27
+ explicitly states that configuration authorizes retained history as well as
28
+ new findings. There is no time cutoff; the private file contains only the URL
29
+ and optional signing secret. Legacy `configured_at` fields are ignored.
30
+ - One worker reads sequentially within each partition. A successful HTTP 2xx
31
+ advances that row's durable cursor. Non-notifiable revisions advance without
32
+ sending. Any delivery failure leaves the failed row pending for the next
33
+ attempt. There is no retry count, discard threshold or separate retry queue.
34
+ - A scan commit wakes the worker, and the existing default one-minute interval
35
+ retries while idle. Setting that interval to zero remains an explicit opt-out
36
+ from timed retries; commits and daemon restarts still wake delivery.
37
+ - Changing the endpoint transfers the remaining backlog to the new destination.
38
+ Changing the signing secret preserves progress. Previously acknowledged rows
39
+ are not replayed for a new destination.
40
+ - Configuration writes and each config-read/POST/cursor-advance span share one
41
+ cross-process file lock. The lock is released between rows. Configure/disable
42
+ waits for an in-flight request; after the command returns, subsequent requests
43
+ cannot use the old configuration. Direct file edits do not participate in this
44
+ coordination. HTTP requests use a ten-second timeout per HTTPX operation.
45
+ - While enabled, pending partitions have retention floors, including before the
46
+ first delivery attempt and every retention sweep. Disable stops delivery and
47
+ releases those floors at the next drain or sweep, even if timed retries are
48
+ disabled. Disabling explicitly ends the pending-delivery guarantee. Re-enable
49
+ resumes from the saved acknowledgement position for whatever remains retained.
50
+ - Invalid configuration stops delivery and preserves existing floors for repair.
51
+ Disable remains available to release them. No endpoint, secret, response body
52
+ or underlying HTTP error message is printed in delivery failures.
53
+
54
+ ## Alternatives considered
55
+
56
+ - **Best effort with an in-memory queue.** Loses alerts during outages or daemon
57
+ restarts, weakening the purpose of a notification channel for unattended work.
58
+ - **Keep the timestamp or replace it with a configuration-time sequence.** Both
59
+ maintain a second delivery boundary. Replaying retained history is an explicit
60
+ product choice that removes that state entirely.
61
+ - **Discard after a retry limit or age limit while enabled.** Would silently
62
+ abandon undelivered alerts. Disable is the explicit way to release a backlog.
63
+ - **Read config immediately before POST without a lock.** A concurrent command
64
+ can return between the read and request. A comparison after sending cannot
65
+ undo delivery to the old destination.
66
+ - **Lock the entire backlog drain.** A large backlog would delay configuration
67
+ changes for many requests. Per-row locking preserves the same correctness
68
+ boundary without holding the lock across a whole drain.
69
+
70
+ ## Consequences
71
+
72
+ First enable may send a burst of older findings. An unreachable or rejecting
73
+ endpoint can retain a growing backlog indefinitely. Delivery resumes only when
74
+ the endpoint accepts requests and the worker runs again; disable ends that
75
+ obligation. A crash after acceptance but before cursor persistence can resend a
76
+ finding, so receivers still deduplicate with the stable `event_id`. A transport
77
+ timeout can also leave the receiver's outcome unknown.
78
+
79
+ This introduces no database migration or second queue. The first notifiable
80
+ revision remains the only revision sent for an event.
@@ -0,0 +1,86 @@
1
+ ---
2
+ id: 0069
3
+ title: Webhooks deliver what retention holds, and configuration takes no lock
4
+ status: accepted
5
+ date: 2026-09-25
6
+ supersedes: null
7
+ superseded-by: null
8
+ amends: 0068
9
+ amended-by: null
10
+ ---
11
+
12
+ ## Context
13
+
14
+ ADR-0068 gave a configured webhook retention floors, so a pending delivery
15
+ could outlive the retention window, and serialized configuration changes with
16
+ each POST through a cross-process file lock. Both made the daemon act on a
17
+ reading of `webhook.toml` in ways that could lose or corrupt state.
18
+
19
+ Clearing a floor was the daemon's inference from "no URL", so every way a read
20
+ could come back empty — a missing, empty or truncated file, a dangling symlink,
21
+ an unreadable directory, invalid UTF-8, a table without `url` — was a way to
22
+ release a backlog for retention to delete. The floor also had to be reconciled
23
+ inside the retention sweep, under the same lock as the POST, which put that lock
24
+ on the scan thread's prune path and made optional webhook storage a dependency
25
+ of base retention. Review of the implementation produced one finding after
26
+ another in these two areas, each a new route to the same two invariants.
27
+
28
+ ## Decision
29
+
30
+ Amend three clauses of ADR-0068. Its payload, eligibility, no-cutoff replay of
31
+ retained history, sequential per-partition delivery, unbounded retry and
32
+ endpoint-change behavior remain in force.
33
+
34
+ - **No retention floors for the webhook.** Its cursor records delivery
35
+ progress only. Retention prunes by age, and by Fleet's cursors as before
36
+ ADR-0067; a finding older than the retention window when the endpoint next
37
+ accepts requests is not delivered. This replaces "while enabled, pending
38
+ partitions have retention floors", and "invalid configuration preserves
39
+ existing floors for repair" becomes "invalid configuration pauses delivery".
40
+ - **Configuration is read before each request, without a lock.** `configure`
41
+ and `disable` replace or remove the file atomically and return at once. The
42
+ change applies from the next request; the one already in flight completes
43
+ with the configuration it read. This replaces the per-row cross-process lock.
44
+ - **The daemon never removes a webhook cursor.** Nothing it reads can release
45
+ anything, so a configuration that cannot be read, or names no endpoint, only
46
+ pauses delivery. Disable deletes the file and keeps the cursor, so re-enable
47
+ resumes from the saved position for whatever is still retained, as ADR-0068
48
+ already states.
49
+
50
+ URLs are validated by parsing them with `httpx.URL`, the client that sends, so
51
+ `configure` cannot accept an endpoint delivery would refuse.
52
+
53
+ ## Alternatives considered
54
+
55
+ - **Keep floors and make "disabled" explicit.** Have only `disable` clear the
56
+ cursor and never infer it from a read. Rejected: it keeps the reconcile in the
57
+ retention sweep and the lock on its path, the source of the other half of the
58
+ findings, to protect a backlog older than the window every other local
59
+ consumer already accepts losing.
60
+ - **Keep the lock so a change is a hard cutoff.** Rejected: what it prevents is
61
+ one request, already in flight, carrying the allowlisted metadata payload to
62
+ the previous endpoint. That does not justify a cross-process lock, its failure
63
+ modes, and a CLI that waits on HTTP.
64
+ - **Move the configuration into the daemon's SQLite store.** Would make
65
+ configure one transaction with cursor state. Rejected for now: with no floors
66
+ and no lock there is no cursor state for configure to keep consistent, and a
67
+ plain file keeps the CLI independent of the daemon's database.
68
+ - **Reintroduce a configuration-time boundary as the cursor.** Rejected, as in
69
+ ADR-0068: replaying retained history is the product choice.
70
+
71
+ ## Consequences
72
+
73
+ An endpoint unavailable for longer than the retention window misses the
74
+ findings that aged out meanwhile; there is no longer an obligation that grows
75
+ without bound while an endpoint rejects requests. A receiver can get one request
76
+ after `disable` returns, or at the previous endpoint after `configure` returns.
77
+
78
+ Base retention no longer depends on the webhook's storage or configuration,
79
+ and the scan thread never takes a webhook lock.
80
+
81
+ ## When to revisit
82
+
83
+ If a destination must never lose a finding to retention, give it its own
84
+ durable queue rather than floors on the shared one. If a receiver must treat
85
+ any request after `disable` as an incident, the hard cutoff needs a daemon-side
86
+ acknowledgement, not a file lock.