stacktrace-cli 0.1.0__tar.gz → 0.2.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 (216) hide show
  1. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/CLAUDE.md +27 -6
  2. stacktrace_cli-0.2.1/PKG-INFO +154 -0
  3. stacktrace_cli-0.2.1/README.md +129 -0
  4. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/0006-trust-boundary-and-detection-upload.md +1 -1
  5. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/0008-console-in-separate-demo-package.md +2 -2
  6. stacktrace_cli-0.2.1/docs/adrs/0026-the-console-becomes-a-product-surface.md +108 -0
  7. stacktrace_cli-0.2.1/docs/adrs/0027-a-finding-may-name-what-it-could-not-place.md +112 -0
  8. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/INDEX.md +3 -1
  9. stacktrace_cli-0.2.1/docs/cutover-openaca-remote.md +87 -0
  10. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/plans/007-detection-upload.md +11 -6
  11. stacktrace_cli-0.2.1/docs/plans/008-monitor.md +630 -0
  12. stacktrace_cli-0.2.1/docs/releases/v0.2.0.md +121 -0
  13. stacktrace_cli-0.2.1/docs/releases/v0.2.1.md +49 -0
  14. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/specs/detection-upload.md +23 -1
  15. stacktrace_cli-0.2.1/docs/specs/monitor.md +459 -0
  16. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/pyproject.toml +8 -4
  17. stacktrace_cli-0.2.1/src/stacktrace_cli/__init__.py +3 -0
  18. stacktrace_cli-0.2.1/src/stacktrace_cli/analysis.py +375 -0
  19. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/cli.py +174 -18
  20. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/correlate/acquire.py +5 -9
  21. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/correlate/composition.py +59 -0
  22. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/correlate/join.py +48 -2
  23. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/correlate/orchestrate.py +37 -3
  24. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/correlate/record.py +8 -0
  25. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/detector/deterministic.py +95 -47
  26. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/detector/finding.py +111 -2
  27. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/detector/render.py +62 -2
  28. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/detector/run.py +385 -17
  29. stacktrace_cli-0.2.1/src/stacktrace_cli/monitor/__init__.py +12 -0
  30. stacktrace_cli-0.2.1/src/stacktrace_cli/monitor/escalate.py +172 -0
  31. stacktrace_cli-0.2.1/src/stacktrace_cli/monitor/render.py +252 -0
  32. stacktrace_cli-0.2.1/src/stacktrace_cli/monitor/server.py +477 -0
  33. stacktrace_cli-0.2.1/src/stacktrace_cli/monitor/site/app.js +1045 -0
  34. stacktrace_cli-0.2.1/src/stacktrace_cli/monitor/site/fonts/OFL.txt +210 -0
  35. stacktrace_cli-0.2.1/src/stacktrace_cli/monitor/site/fonts/dm-mono-400-latin.woff2 +0 -0
  36. stacktrace_cli-0.2.1/src/stacktrace_cli/monitor/site/fonts/dm-mono-500-latin.woff2 +0 -0
  37. stacktrace_cli-0.2.1/src/stacktrace_cli/monitor/site/fonts/dm-sans-latin.woff2 +0 -0
  38. stacktrace_cli-0.2.1/src/stacktrace_cli/monitor/site/index.html +104 -0
  39. stacktrace_cli-0.2.1/src/stacktrace_cli/monitor/site/styles.css +628 -0
  40. stacktrace_cli-0.2.1/src/stacktrace_cli/monitor/state.py +102 -0
  41. stacktrace_cli-0.2.1/src/stacktrace_cli/monitor/verdicts.py +52 -0
  42. stacktrace_cli-0.2.1/src/stacktrace_cli/monitor/watch.py +349 -0
  43. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/remote/detect_payload.py +99 -27
  44. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/remote/redact.py +13 -2
  45. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/remote/sync_detect.py +79 -42
  46. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/remote/upload_contract.py +21 -0
  47. stacktrace_cli-0.2.1/tests/monitor/feed_harness.mjs +803 -0
  48. stacktrace_cli-0.2.1/tests/monitor/test_escalation_gates.py +398 -0
  49. stacktrace_cli-0.2.1/tests/monitor/test_feed_model.py +484 -0
  50. stacktrace_cli-0.2.1/tests/monitor/test_render.py +344 -0
  51. stacktrace_cli-0.2.1/tests/monitor/test_server.py +413 -0
  52. stacktrace_cli-0.2.1/tests/monitor/test_site_assets.py +204 -0
  53. stacktrace_cli-0.2.1/tests/monitor/test_state.py +111 -0
  54. stacktrace_cli-0.2.1/tests/monitor/test_verdicts.py +137 -0
  55. stacktrace_cli-0.2.1/tests/monitor/test_watch.py +607 -0
  56. stacktrace_cli-0.2.1/tests/remote/__init__.py +0 -0
  57. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/remote/test_detect_contract_is_exhaustive.py +79 -2
  58. stacktrace_cli-0.2.1/tests/remote/test_detect_payload_reaches_the_cloud_model.py +286 -0
  59. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/remote/test_detect_redaction.py +49 -0
  60. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/remote/test_sync_detect.py +2 -2
  61. stacktrace_cli-0.2.1/tests/test_agent_instance_id.py +207 -0
  62. stacktrace_cli-0.2.1/tests/test_analysis.py +362 -0
  63. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_cli.py +38 -0
  64. stacktrace_cli-0.2.1/tests/test_detection_components.py +194 -0
  65. stacktrace_cli-0.2.1/tests/test_detection_subject.py +671 -0
  66. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_detector_render.py +93 -1
  67. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_detector_run.py +43 -0
  68. stacktrace_cli-0.2.1/tests/test_monitor_cli.py +85 -0
  69. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_untrusted_content_never_travels.py +216 -6
  70. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/uv.lock +1 -1
  71. stacktrace_cli-0.1.0/PKG-INFO +0 -228
  72. stacktrace_cli-0.1.0/README.md +0 -207
  73. stacktrace_cli-0.1.0/src/stacktrace_cli/__init__.py +0 -3
  74. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/.agents/skills/release-stacktrace/SKILL.md +0 -0
  75. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/.claude/settings.json +0 -0
  76. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/.claude/skills/release-stacktrace/SKILL.md +0 -0
  77. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/.codex/hooks.json +0 -0
  78. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/.github/workflows/autofix.yml +0 -0
  79. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/.github/workflows/ci.yml +0 -0
  80. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/.github/workflows/claude.yml +0 -0
  81. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/.github/workflows/publish-pypi.yml +0 -0
  82. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/.gitignore +0 -0
  83. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/AGENTS.md +0 -0
  84. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/0001-session-telemetry-as-input.md +0 -0
  85. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/0002-session-collection-in-openaidr.md +0 -0
  86. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/0003-runtime-edges.md +0 -0
  87. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/0004-three-stage-detector.md +0 -0
  88. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/0005-detection-family-and-report-assembly.md +0 -0
  89. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/0007-proprietary-package-on-open-dependencies.md +0 -0
  90. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/0010-detection-severity-and-confidence-ladders.md +0 -0
  91. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/0011-verdict-cache.md +0 -0
  92. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/0012-observation-evidence-kinds-and-transport.md +0 -0
  93. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/0013-rule-catalogue-triage-and-per-rule-context.md +0 -0
  94. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/0014-declared-project-mapping.md +0 -0
  95. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/0015-narrow-the-security-catalogue.md +0 -0
  96. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/0016-stall-grouping-is-session-wide.md +0 -0
  97. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/0017-a-declined-repeat-is-a-stall.md +0 -0
  98. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/0018-remote-sync-config-and-facade-consumption.md +0 -0
  99. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/0019-delegated-commands-are-openaca-objects.md +0 -0
  100. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/0020-openaca-consumption-boundary.md +0 -0
  101. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/0021-two-command-kinds.md +0 -0
  102. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/0022-detection-scope-is-a-catalogue-column.md +0 -0
  103. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/0023-sync-detect-collects-and-does-not-escalate.md +0 -0
  104. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/0024-the-upload-carries-observations.md +0 -0
  105. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/0025-a-denied-call-is-activity-never-an-invocation.md +0 -0
  106. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/HOOK-PROMPT.md +0 -0
  107. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/TEMPLATE.md +0 -0
  108. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/plans/002-session-input.md +0 -0
  109. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/plans/003-correlation.md +0 -0
  110. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/plans/004-detector.md +0 -0
  111. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/plans/005-remote-sync.md +0 -0
  112. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/plans/006-cli-composition.md +0 -0
  113. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/releases/v0.0.1.md +0 -0
  114. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/releases/v0.1.0.md +0 -0
  115. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/specs/aidr.md +0 -0
  116. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/specs/cli-composition.md +0 -0
  117. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/specs/correlation.md +0 -0
  118. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/specs/detector.md +0 -0
  119. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/specs/remote-sync.md +0 -0
  120. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/specs/session-input.md +0 -0
  121. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/scripts/git-hooks/pre-push +0 -0
  122. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/scripts/install-hooks.sh +0 -0
  123. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/__main__.py +0 -0
  124. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/correlate/__init__.py +0 -0
  125. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/correlate/observed.py +0 -0
  126. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/correlate/project_map.py +0 -0
  127. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/correlate/render.py +0 -0
  128. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/detector/__init__.py +0 -0
  129. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/detector/analyzer.py +0 -0
  130. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/detector/cache.py +0 -0
  131. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/detector/markers.py +0 -0
  132. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/detector/priors.py +0 -0
  133. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/detector/prompts/__init__.py +0 -0
  134. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/detector/prompts/v1/exclusions.md +0 -0
  135. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/detector/prompts/v1/framing.md +0 -0
  136. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/detector/prompts/v1/stacktrace-deceptive-completion.md +0 -0
  137. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/detector/prompts/v1/stacktrace-injected-instruction-followed.md +0 -0
  138. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/detector/prompts/v1/stacktrace-intent-drift.md +0 -0
  139. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/detector/reasoning.py +0 -0
  140. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/detector/rules.py +0 -0
  141. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/detector/secrets.py +0 -0
  142. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/detector/verdict.py +0 -0
  143. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/remote/__init__.py +0 -0
  144. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/remote/cli.py +0 -0
  145. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/remote/client.py +0 -0
  146. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/remote/config.py +0 -0
  147. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/remote/payload.py +0 -0
  148. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/remote/policy.py +0 -0
  149. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/remote/spool.py +0 -0
  150. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/remote/sync.py +0 -0
  151. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/sessions/__init__.py +0 -0
  152. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/sessions/access.py +0 -0
  153. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/sessions/outcome.py +0 -0
  154. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/sessions/protocols.py +0 -0
  155. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/sessions/render.py +0 -0
  156. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/__init__.py +0 -0
  157. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/agent_bom_fixture.py +0 -0
  158. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/detector_session_fixture.py +0 -0
  159. {stacktrace_cli-0.1.0/tests/remote → stacktrace_cli-0.2.1/tests/monitor}/__init__.py +0 -0
  160. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/remote/helpers.py +0 -0
  161. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/remote/test_cli.py +0 -0
  162. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/remote/test_client.py +0 -0
  163. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/remote/test_config.py +0 -0
  164. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/remote/test_detect_activity.py +0 -0
  165. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/remote/test_detect_cli.py +0 -0
  166. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/remote/test_detect_client.py +0 -0
  167. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/remote/test_detect_gate_matches_the_cloud.py +0 -0
  168. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/remote/test_detect_layers_compose.py +0 -0
  169. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/remote/test_detect_spool.py +0 -0
  170. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/remote/test_detect_upload_contract.py +0 -0
  171. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/remote/test_detect_wire_payload.py +0 -0
  172. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/remote/test_facade_contract.py +0 -0
  173. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/remote/test_payload.py +0 -0
  174. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/remote/test_policy.py +0 -0
  175. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/remote/test_redact_payload.py +0 -0
  176. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/remote/test_seam.py +0 -0
  177. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/remote/test_spool.py +0 -0
  178. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/remote/test_sync.py +0 -0
  179. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/remote/test_upload_contract.py +0 -0
  180. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_acquire.py +0 -0
  181. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_bom_shape.py +0 -0
  182. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_call_status_conventions.py +0 -0
  183. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_composition.py +0 -0
  184. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_correlate_orchestrate.py +0 -0
  185. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_correlate_render.py +0 -0
  186. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_correlated_session.py +0 -0
  187. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_detector_analyzer_contract.py +0 -0
  188. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_detector_analyzer_live.py +0 -0
  189. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_detector_cache.py +0 -0
  190. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_detector_deterministic.py +0 -0
  191. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_detector_end_to_end.py +0 -0
  192. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_detector_finding.py +0 -0
  193. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_detector_liveness.py +0 -0
  194. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_detector_markers.py +0 -0
  195. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_detector_priors.py +0 -0
  196. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_detector_reasoning.py +0 -0
  197. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_detector_secrets.py +0 -0
  198. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_detector_verdict.py +0 -0
  199. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_fingerprint_covers_what_the_analyzer_reads.py +0 -0
  200. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_help_sections.py +0 -0
  201. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_join.py +0 -0
  202. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_observed.py +0 -0
  203. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_openaca_contract.py +0 -0
  204. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_openaidr_contract.py +0 -0
  205. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_option_arity_matches_the_binary.py +0 -0
  206. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_project_map.py +0 -0
  207. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_readme_examples_are_real_output.py +0 -0
  208. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_release_readiness.py +0 -0
  209. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_seam_boundary.py +0 -0
  210. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_sessions_access.py +0 -0
  211. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_sessions_end_to_end.py +0 -0
  212. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_sessions_protocol_typing.py +0 -0
  213. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_sessions_protocols.py +0 -0
  214. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_sessions_render.py +0 -0
  215. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_shell_separators_match_the_shell.py +0 -0
  216. {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_verification_subcommands_match_the_binary.py +0 -0
@@ -11,8 +11,8 @@ and by CI pipelines that invoke `stacktrace`, and it builds on the open-source
11
11
  It is also the **design home for Stacktrace Detect** — the AIDR product this CLI
12
12
  grows into. The specs in `docs/specs/` and the decisions in `docs/adrs/` describe
13
13
  the whole system: session input, correlation against the composition graph, the
14
- three-stage detector, and the combined report. The code here is the placeholder that
15
- precedes them.
14
+ three-stage detector, and the combined report. The code here implements them
15
+ incrementally.
16
16
 
17
17
  ## Common commands
18
18
 
@@ -52,11 +52,13 @@ the single source of truth for the version string reported by `--version`.
52
52
 
53
53
  Build backend is hatchling with a src layout; the wheel's contents are declared
54
54
  explicitly by `[tool.hatch.build.targets.wheel] packages = ["src/stacktrace_cli"]`.
55
- The only runtime dependency is `openaca>=0.4.0`, which supplies the Agent
56
- Composition Analysis primitives this CLI is intended to drive.
55
+ Runtime dependencies are `openaca` for the Agent Composition Analysis
56
+ primitives this CLI drives, `openaidr` for session collection, and `httpx` for
57
+ the remote channel. Each is pinned exactly before a release; see
58
+ `docs/cutover-openaca-remote.md`.
57
59
 
58
- The package is currently pre-alpha: `main()` reports its version and points at
59
- the docs. Real functionality lands in later releases.
60
+ `sessions`, `detect`, `monitor` and `remote` are native; `bom`, `policy` and
61
+ `scan` are OpenACA's own command objects.
60
62
 
61
63
  **The design that functionality implements is in this repo.** Read
62
64
  `docs/specs/aidr.md` first — it is the umbrella: components, contracts, the two
@@ -121,6 +123,25 @@ nothing about detection.
121
123
  a review names a site, fix the invariant and extend the exhaustive test — a
122
124
  second finding of the same class means the first fix was at the wrong level.
123
125
 
126
+ ## Adding a command
127
+
128
+ A command is a **pass-through** or it is **native**, never both — and a
129
+ pass-through never gains a flag of its own. See
130
+ [ADR-0021](docs/adrs/0021-two-command-kinds.md) for why.
131
+
132
+ - **Pass-through** — add one string to `PASSTHROUGH` in
133
+ `src/stacktrace_cli/cli.py`, having decided it belongs. The loop registers
134
+ OpenACA's own command object under that name; there is nothing else to
135
+ write and nothing to keep in step with OpenACA.
136
+ - **Native** — write a Click command or group and `add_command` it, the way
137
+ `remote` is. If it needs OpenACA it calls `openaca.core`
138
+ ([ADR-0020](docs/adrs/0020-openaca-consumption-boundary.md)), and whatever
139
+ it names there is added to the contract test in `tests/remote/`, because it
140
+ now holds duplicated knowledge of an interface.
141
+
142
+ The section a command lands under in `--help` follows from which kind it is;
143
+ there is no second list to update.
144
+
124
145
  ---
125
146
 
126
147
  ## Behavioral guidelines
@@ -0,0 +1,154 @@
1
+ Metadata-Version: 2.5
2
+ Name: stacktrace-cli
3
+ Version: 0.2.1
4
+ Summary: CLI for Stacktrace — Detection and Response platform for AI Agents.
5
+ Project-URL: Homepage, https://stacktrace.ai
6
+ Author-email: "Stacktrace AI, Inc" <founders@stacktrace.ai>
7
+ License-Expression: LicenseRef-Proprietary
8
+ Keywords: agent-security,ai-security,openaca,stacktrace
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Environment :: Console
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: Other/Proprietary License
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Topic :: Security
19
+ Requires-Python: >=3.11
20
+ Requires-Dist: click>=8.1
21
+ Requires-Dist: httpx<1.0.dev0,>=0.28.1
22
+ Requires-Dist: openaca==0.6.0
23
+ Requires-Dist: openaidr==0.1.0
24
+ Description-Content-Type: text/markdown
25
+
26
+ # stacktrace-cli
27
+
28
+ Detection and response for AI coding agents, from the command line.
29
+
30
+ Coding agents read files, run shell commands and call MCP servers on their own
31
+ initiative, and they write a transcript of every bit of it to disk.
32
+ `stacktrace` reads those transcripts, correlates what ran against the
33
+ components the agent is built from, and reports the security and reliability
34
+ findings in it — locally, on the machine the agent worked on.
35
+
36
+ The PyPI distribution is `stacktrace-cli`; the command it installs is
37
+ `stacktrace`. The two names differ because the bare `stacktrace` name on PyPI
38
+ belongs to an unrelated project.
39
+
40
+ ## Installation
41
+
42
+ ```bash
43
+ uv tool install stacktrace-cli # isolated; recommended
44
+ # or
45
+ pip install stacktrace-cli
46
+ ```
47
+
48
+ Requires Python 3.11 or newer.
49
+
50
+ ```console
51
+ $ stacktrace --version
52
+ stacktrace 0.2.1 (openaca 0.6.0)
53
+ ```
54
+
55
+ ## Quick start
56
+
57
+ ```bash
58
+ stacktrace sessions # what the agents on this machine did
59
+ stacktrace detect # what is wrong with it
60
+ stacktrace monitor # the same, live in a browser
61
+ ```
62
+
63
+ ## Commands
64
+
65
+ | Command | |
66
+ |---|---|
67
+ | `sessions` | Print what the agents on this machine actually did. |
68
+ | `detect` | Find security and reliability findings in what agents did. |
69
+ | `monitor` | Watch this machine's agents in a browser, live. |
70
+ | `remote` | Configure remote endpoint services and upload to Stacktrace Cloud. |
71
+ | `scan` | Scan a repository or endpoint for agent-composition findings. |
72
+ | `bom` | Generate an Agent BOM for a repository or endpoint. |
73
+ | `policy` | Validate and compile restrictive endpoint policies. |
74
+
75
+ The last three are composition analysis, supplied by
76
+ [`openaca`](https://pypi.org/project/openaca/) and available under either
77
+ name.
78
+
79
+ ## What it looks like
80
+
81
+ ```console
82
+ $ stacktrace sessions --since 2d --include-content
83
+ claude-code:s1 [claude-code] 2026-08-27T09:00:00+00:00 2 turns 2 calls
84
+ assistant: Reading the changelog before drafting the release notes.
85
+ ok 28c Read
86
+ result: ## 0.4.0 - correlate, detect
87
+ assistant: Filing the release-notes follow-up.
88
+ - github/create_issue
89
+
90
+ Summary — 1 sessions, 2 turns, 2 tool calls
91
+
92
+ agent kinds
93
+ 1 claude-code
94
+
95
+ tools called (2 distinct)
96
+ 1 Read
97
+ 1 github/create_issue
98
+
99
+ MCP servers reached (1 distinct)
100
+ 1 github
101
+
102
+ 0 subagent turns · 0 results abridged upstream · 1 ok
103
+
104
+ 1 of 2 calls returned with no outcome the collector could establish; the agent's parser supplies no success signal.
105
+ ```
106
+
107
+ A blank status column is the collector's `unknown`, not a pending call: the
108
+ client recorded no outcome that could be established, and the closing line
109
+ counts those rather than filling one in.
110
+
111
+ ## What `detect` finds
112
+
113
+ Four kinds of finding, under two families that carry separate severity
114
+ ladders — a stalled loop and a leaked credential do not belong on one scale.
115
+
116
+ **Security** — a credential reaching an outbound call; an injected instruction
117
+ the agent then followed; a vulnerable component actually reached, with the
118
+ vulnerability behind it.
119
+
120
+ **Reliability** — a loop that stalled; a call that hung.
121
+
122
+ Findings are correlated against an Agent BOM before they are judged, so a
123
+ vulnerable component is reported when something actually used it rather than
124
+ because it is installed.
125
+
126
+ ## What leaves your machine
127
+
128
+ Two of `detect`'s three stages run entirely locally and need no model or
129
+ credential. The third sends flagged sessions to the agent's *own* CLI — the
130
+ provider that produced the transcript, never a different one — capped by
131
+ `--budget`; `--no-escalate` turns it off and leaves the two local stages.
132
+
133
+ `sessions` omits prompts, tool arguments and results unless you pass
134
+ `--include-content`. `monitor` binds to loopback only, refuses a non-loopback
135
+ address rather than warning about it, and escalates nothing unless `--escalate`
136
+ is given.
137
+
138
+ ## Status
139
+
140
+ Beta, and under active development.
141
+
142
+ `sessions`, `detect` and `monitor` work end to end today. Session collection
143
+ currently reads Claude Code transcripts; further agent kinds are in progress
144
+ upstream in [OpenAIDR](https://github.com/open-agent-security/openaidr).
145
+
146
+ ## Built on
147
+
148
+ Two Apache-2.0 packages, neither of which depends on this one:
149
+ [`openaca`](https://pypi.org/project/openaca/) for agent composition analysis,
150
+ and [`openaidr`](https://pypi.org/project/openaidr/) for session collection.
151
+
152
+ ## Licence
153
+
154
+ Proprietary. © Stacktrace AI, Inc. — [stacktrace.ai](https://stacktrace.ai)
@@ -0,0 +1,129 @@
1
+ # stacktrace-cli
2
+
3
+ Detection and response for AI coding agents, from the command line.
4
+
5
+ Coding agents read files, run shell commands and call MCP servers on their own
6
+ initiative, and they write a transcript of every bit of it to disk.
7
+ `stacktrace` reads those transcripts, correlates what ran against the
8
+ components the agent is built from, and reports the security and reliability
9
+ findings in it — locally, on the machine the agent worked on.
10
+
11
+ The PyPI distribution is `stacktrace-cli`; the command it installs is
12
+ `stacktrace`. The two names differ because the bare `stacktrace` name on PyPI
13
+ belongs to an unrelated project.
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ uv tool install stacktrace-cli # isolated; recommended
19
+ # or
20
+ pip install stacktrace-cli
21
+ ```
22
+
23
+ Requires Python 3.11 or newer.
24
+
25
+ ```console
26
+ $ stacktrace --version
27
+ stacktrace 0.2.1 (openaca 0.6.0)
28
+ ```
29
+
30
+ ## Quick start
31
+
32
+ ```bash
33
+ stacktrace sessions # what the agents on this machine did
34
+ stacktrace detect # what is wrong with it
35
+ stacktrace monitor # the same, live in a browser
36
+ ```
37
+
38
+ ## Commands
39
+
40
+ | Command | |
41
+ |---|---|
42
+ | `sessions` | Print what the agents on this machine actually did. |
43
+ | `detect` | Find security and reliability findings in what agents did. |
44
+ | `monitor` | Watch this machine's agents in a browser, live. |
45
+ | `remote` | Configure remote endpoint services and upload to Stacktrace Cloud. |
46
+ | `scan` | Scan a repository or endpoint for agent-composition findings. |
47
+ | `bom` | Generate an Agent BOM for a repository or endpoint. |
48
+ | `policy` | Validate and compile restrictive endpoint policies. |
49
+
50
+ The last three are composition analysis, supplied by
51
+ [`openaca`](https://pypi.org/project/openaca/) and available under either
52
+ name.
53
+
54
+ ## What it looks like
55
+
56
+ ```console
57
+ $ stacktrace sessions --since 2d --include-content
58
+ claude-code:s1 [claude-code] 2026-08-27T09:00:00+00:00 2 turns 2 calls
59
+ assistant: Reading the changelog before drafting the release notes.
60
+ ok 28c Read
61
+ result: ## 0.4.0 - correlate, detect
62
+ assistant: Filing the release-notes follow-up.
63
+ - github/create_issue
64
+
65
+ Summary — 1 sessions, 2 turns, 2 tool calls
66
+
67
+ agent kinds
68
+ 1 claude-code
69
+
70
+ tools called (2 distinct)
71
+ 1 Read
72
+ 1 github/create_issue
73
+
74
+ MCP servers reached (1 distinct)
75
+ 1 github
76
+
77
+ 0 subagent turns · 0 results abridged upstream · 1 ok
78
+
79
+ 1 of 2 calls returned with no outcome the collector could establish; the agent's parser supplies no success signal.
80
+ ```
81
+
82
+ A blank status column is the collector's `unknown`, not a pending call: the
83
+ client recorded no outcome that could be established, and the closing line
84
+ counts those rather than filling one in.
85
+
86
+ ## What `detect` finds
87
+
88
+ Four kinds of finding, under two families that carry separate severity
89
+ ladders — a stalled loop and a leaked credential do not belong on one scale.
90
+
91
+ **Security** — a credential reaching an outbound call; an injected instruction
92
+ the agent then followed; a vulnerable component actually reached, with the
93
+ vulnerability behind it.
94
+
95
+ **Reliability** — a loop that stalled; a call that hung.
96
+
97
+ Findings are correlated against an Agent BOM before they are judged, so a
98
+ vulnerable component is reported when something actually used it rather than
99
+ because it is installed.
100
+
101
+ ## What leaves your machine
102
+
103
+ Two of `detect`'s three stages run entirely locally and need no model or
104
+ credential. The third sends flagged sessions to the agent's *own* CLI — the
105
+ provider that produced the transcript, never a different one — capped by
106
+ `--budget`; `--no-escalate` turns it off and leaves the two local stages.
107
+
108
+ `sessions` omits prompts, tool arguments and results unless you pass
109
+ `--include-content`. `monitor` binds to loopback only, refuses a non-loopback
110
+ address rather than warning about it, and escalates nothing unless `--escalate`
111
+ is given.
112
+
113
+ ## Status
114
+
115
+ Beta, and under active development.
116
+
117
+ `sessions`, `detect` and `monitor` work end to end today. Session collection
118
+ currently reads Claude Code transcripts; further agent kinds are in progress
119
+ upstream in [OpenAIDR](https://github.com/open-agent-security/openaidr).
120
+
121
+ ## Built on
122
+
123
+ Two Apache-2.0 packages, neither of which depends on this one:
124
+ [`openaca`](https://pypi.org/project/openaca/) for agent composition analysis,
125
+ and [`openaidr`](https://pypi.org/project/openaidr/) for session collection.
126
+
127
+ ## Licence
128
+
129
+ Proprietary. © Stacktrace AI, Inc. — [stacktrace.ai](https://stacktrace.ai)
@@ -5,7 +5,7 @@ status: accepted
5
5
  date: 2026-08-28
6
6
  supersedes: null
7
7
  superseded-by: null
8
- amended-by: 0011
8
+ amended-by: 0011, 0027
9
9
  ---
10
10
 
11
11
  ## Context
@@ -1,10 +1,10 @@
1
1
  ---
2
2
  id: 0008
3
3
  title: Ship the local trace console as a separate demo package
4
- status: accepted
4
+ status: superseded
5
5
  date: 2026-08-27
6
6
  supersedes: null
7
- superseded-by: null
7
+ superseded-by: 0026
8
8
  ---
9
9
 
10
10
  ## Context
@@ -0,0 +1,108 @@
1
+ ---
2
+ id: 0026
3
+ title: The console becomes a product surface, served by the engine
4
+ status: accepted
5
+ date: 2026-09-06
6
+ supersedes: 0008
7
+ superseded-by: null
8
+ amends: null
9
+ amended-by: null
10
+ ---
11
+
12
+ ## Context
13
+
14
+ ADR-0008 kept the trace console out of the engine and gave three reasons. Two
15
+ were about *kind*: a served page with taste-driven layout is different software
16
+ from a library, and their release cadences and review standards differ. One was
17
+ about *order*: making the console the product surface "before the engine's
18
+ claims are validated inverts the order — the engine comes first, and nothing yet
19
+ measures its central claim."
20
+
21
+ That last reason names its own expiry, and it has arrived. 0.1.0 ships
22
+ `sessions`, `detect` over nine rules and three stages, and both upload paths;
23
+ the detector's claims are measured by its own corpus and by the hosted side
24
+ receiving them. The engine came first, and did.
25
+
26
+ What forces the decision now is a product one rather than a technical one: the
27
+ data is only useful if a person can follow it, and a sequence reads better as a
28
+ timeline than as a findings list — 0008's own opening sentence. A developer who
29
+ has to run `detect`, read JSON, and re-run it to see what changed is being asked
30
+ to be the renderer. `stacktrace monitor` is that renderer, and it has to ship
31
+ where the data is.
32
+
33
+ ## Decision
34
+
35
+ The engine serves a local console. `stacktrace monitor` starts an HTTP server
36
+ bound to loopback, opens a browser, and renders live sessions and detections
37
+ from in-process calls into the same surfaces `detect` uses.
38
+
39
+ The three clauses of 0008 that this reverses, stated plainly:
40
+
41
+ 1. **The engine gains a serving surface and a browser-facing asset.** `site/`
42
+ ships as package data in the wheel.
43
+ 2. **The console performs no analysis of its own.** *This one survives.* Monitor
44
+ calls `collect_sessions`, `acquire_correlated_view` and `run_detector`; it
45
+ adds no rule, no grade and no heuristic, and it never writes the verdict
46
+ cache. A finding on the page is a finding `detect` would print.
47
+ 3. **The tenets govern the console now**, because it is a product surface rather
48
+ than a demonstration. Trust, quality, cost and security apply — which is why
49
+ the page computes only the two free stages by default, and why the one action
50
+ it offers is gated four ways.
51
+
52
+ ## Alternatives considered
53
+
54
+ - **Keep 0008 and ship the console as a separate optional distribution**
55
+ (`stacktrace-console`, or an extra) — rejected. It preserves the letter of
56
+ 0008 at the cost of the thing 0008 was protecting: a second distribution has
57
+ its own version, its own install step and its own drift against three read
58
+ contracts, and every user who wants to *see* their data pays an install to do
59
+ it. The cadence argument that justified separation for a demo does not survive
60
+ the surface becoming the product.
61
+
62
+ - **Amend 0008 to carve out one read-only local surface** — rejected as
63
+ dishonest bookkeeping. The carve-out is the whole of clause 1; an amendment
64
+ that removes a decision's first clause is a supersession wearing a smaller
65
+ word.
66
+
67
+ - **Leave rendering to the hosted console** — rejected. The hosted side is
68
+ agent-scoped and receives only what ADR-0006 authorizes: no prompt, no
69
+ argument, no result, no matched value. The local console is precisely where a
70
+ responder may see the matched string, which ADR-0006 calls out as deliberate
71
+ asymmetry. A fleet view cannot replace a machine view; it is a different
72
+ question.
73
+
74
+ - **Ship the console but compute nothing** (render the last `detect` run's
75
+ cache) — rejected. "Live sessions, stale findings" is the failure mode a
76
+ reader cannot see: the page looks current, and a leak that happened after the
77
+ last run is absent from it.
78
+
79
+ ## Consequences
80
+
81
+ **What this enables.** A developer watches an alias resolve into a real
82
+ component while a session is still running — 0008's own description of the
83
+ demonstration, now available without a demo. The three published read contracts
84
+ gain their first in-repo consumer, so a change to span identity breaks a test
85
+ here rather than silently landing enrichments on the wrong rows elsewhere.
86
+
87
+ **What it costs, and 0008 was right about both.**
88
+
89
+ - **Every consumer of the wheel carries a UI they did not ask for.** `site/` is
90
+ three files and no JavaScript dependency, so the cost is bytes rather than a
91
+ dependency tree — but a library consumer still ships them.
92
+ - **Visual iteration now happens inside the engine's release process.** A
93
+ layout change rides a release built for a detection engine. The mitigation is
94
+ that the console's own priorities stay 0008's — latency, then fidelity — and
95
+ that no page change can alter a finding, because monitor computes none.
96
+
97
+ **What to watch for.** A rule that fires only in the console, or a grade the
98
+ page adjusts for legibility. Either would make clause 2 false, and clause 2 is
99
+ the one keeping this from being a fork of the detector.
100
+
101
+ ## When to revisit
102
+
103
+ Revisit if the console acquires a reason to compute something the detector does
104
+ not — that is the point at which it stops being a renderer and needs its own
105
+ decision. Revisit if the wheel's browser-facing assets grow beyond static files,
106
+ because a build step is the cadence problem 0008 warned about actually arriving.
107
+ Do not revisit on the grounds that a library consumer carries the UI: that cost
108
+ is accepted here explicitly, not overlooked.
@@ -0,0 +1,112 @@
1
+ ---
2
+ id: 0027
3
+ title: A finding may name the component it could not place
4
+ status: accepted
5
+ date: 2026-09-07
6
+ supersedes: null
7
+ superseded-by: null
8
+ amends: 0006
9
+ ---
10
+
11
+ ## Context
12
+
13
+ ADR-0006 constraint 3 keeps session content off the wire *by construction*: a
14
+ detection carries a rule id and non-content descriptors, "never an excerpt of
15
+ an argument, result or prompt", and the family is uploadable whole so no
16
+ projection exists to be got wrong. That constraint has held every finding this
17
+ product has shipped and is not in question here.
18
+
19
+ One case has now met the condition ADR-0006 wrote for its own revision:
20
+
21
+ > Revisit if a detection type proves genuinely unactionable without an evidence
22
+ > excerpt — that would be a real argument against constraint 3, and the answer
23
+ > is more likely a better non-content descriptor than an excerpt.
24
+
25
+ A finding's **subject** is what the finding is about. Where correlation places
26
+ the call, the subject is a BOM component and constraint 3 was never in play.
27
+ Where correlation cannot place it, the only name that exists is the one the
28
+ session used — `call.mcp_server` for a server, `arguments["skill"]` for a
29
+ skill — and the second of those is, read literally, an excerpt of an argument.
30
+
31
+ Removing it leaves the highest-severity finding this detector produces reading:
32
+
33
+ high stacktrace-credential-egress
34
+ Credential-shaped material reached an outbound call
35
+ on a mcp_server (not in inventory)
36
+
37
+ A responder cannot act on that. They cannot rotate the right credential, revoke
38
+ the right access, or find the thing, because the document does not say what the
39
+ thing was. The unplaced case is also the one where naming matters *most*: a
40
+ credential reaching a component no Agent BOM declares is the least expected and
41
+ least explicable event this product reports.
42
+
43
+ Empirically it is not rare. On the machine this was written against, 156 calls
44
+ across 15 distinct names were unplaced, including the one `high`
45
+ credential-egress finding in the window.
46
+
47
+ ## Decision
48
+
49
+ **A detection may carry the name the session addressed a component by, when
50
+ correlation could not place it.** This narrows ADR-0006 constraint 3; every
51
+ other clause of 0006 stays in force, and constraint 3 continues to forbid
52
+ excerpts of prompts, results and arguments in every other position.
53
+
54
+ Four bounds make it a descriptor rather than an opening.
55
+
56
+ 1. **One field, one purpose.** The name appears only as
57
+ `Participant.name` on a finding's subject or a named party to it. No rule
58
+ may interpolate it into prose; `Evidence.detail` remains closed to it, which
59
+ is the drift ADR-0006 names as *"reached by writing a helpful sentence"*.
60
+
61
+ 2. **It is never an identity.** `Participant.identity` stays null for an
62
+ unplaced party, so the name can resolve no lookup, join to no inventory and
63
+ render as no link. A consumer must mark it as unverified. Two machines can
64
+ call unrelated servers `support`; this ADR does not make that name mean
65
+ anything beyond the session that said it.
66
+
67
+ 3. **Bounded and validated at the boundary.** Length-capped on the wire, and
68
+ walked by the same disclosure gate every other leaf passes, so a name
69
+ carrying a path or a credential shape is refused rather than trimmed.
70
+
71
+ 4. **The local surfaces are unchanged and remain the fuller answer.** `monitor`
72
+ and `stacktrace detect` read the session directly and may always say more
73
+ than the upload does. This ADR is only about what leaves the machine.
74
+
75
+ ## Consequences
76
+
77
+ The `credential-egress` above reads `on support (not in inventory)`, in Fleet
78
+ as well as locally, and a responder has somewhere to start.
79
+
80
+ The residual exposure is a short, model-influenceable string reaching a hosted
81
+ service. It is real and it is accepted here rather than argued away: an
82
+ attacker who can choose the `skill` argument already drives the agent's tool
83
+ calls, and has channels with far more bandwidth than a capped name field in a
84
+ detection upload. What this ADR must not become is precedent — the argument
85
+ above is about *the subject of a finding being unnameable otherwise*, and does
86
+ not extend to any other field.
87
+
88
+ `tests/test_untrusted_content_never_travels.py` keeps every other canary,
89
+ including the ones for prompts, results, arguments and the tool name an MCP
90
+ server chose. It gains the case this ADR permits, so the exemption is stated
91
+ where the invariant is enforced rather than only here.
92
+
93
+ ## Alternatives rejected
94
+
95
+ - **Drop the name, keep the type** (`a skill (not in inventory)`). This was
96
+ implemented and is what prompted the ADR. It is compliant and unactionable,
97
+ which makes it the wrong trade for a product whose output is meant to be
98
+ acted on. A rule that produces findings nobody can use protects nothing.
99
+
100
+ - **Carry the server alias, drop the skill argument.** Defensible on the letter
101
+ of constraint 3 — a server alias is not an argument excerpt — and rejected as
102
+ a distinction a reader cannot see. It would make one finding nameable and its
103
+ neighbour not, for a reason invisible on the page, and leaves the same
104
+ residual exposure for the case it permits.
105
+
106
+ - **Send a hash of the name.** Rejected. It is stable across machines, which is
107
+ the one property the name must not have, and it is unreadable, which is the
108
+ one property a responder needs.
109
+
110
+ - **Amend nothing and surface the name only in `monitor`.** Rejected as the
111
+ status quo restated: triage happens in Fleet, and a console on one laptop
112
+ does not answer for a fleet.
@@ -41,7 +41,7 @@ supersedes anything yet.
41
41
  - [0005](0005-detection-family-and-report-assembly.md) — **Detections are their own finding family, assembled here.** Why a detection is not an observation, and why `stacktrace` merges the four families rather than OpenACA emitting a fourth. `stacktrace-*` identifiers. Read before adding a finding family, touching output assembly, or contributing anything upstream.
42
42
  - [0006](0006-trust-boundary-and-detection-upload.md) — **Sessions never leave the machine; detections upload agent-keyed.** No upload path for anything session-derived; findings carry descriptors, never excerpts; place identity stays in the envelope. Read before adding a detection field, touching redaction, or describing AIDR as fully local or anonymous.
43
43
  - [0007](0007-proprietary-package-on-open-dependencies.md) — **Proprietary package on open dependencies.** Why this is not inside OpenACA or OpenAIDR, and why the dependency arrow never reverses. Read before moving code between repos.
44
- - [0008](0008-console-in-separate-demo-package.md) — **Trace console ships as a separate demo package.** Read before adding a served UI, transport, or web asset to this repo.
44
+ - [0008](0008-console-in-separate-demo-package.md) — **Trace console ships as a separate demo package.** Read before adding a served UI, transport, or web asset to this repo. **Superseded by [0026](0026-the-console-becomes-a-product-surface.md).**
45
45
  - [0010](0010-detection-severity-and-confidence-ladders.md) — **Detections define their own severity and confidence ladders.** Amends ADR-0005: `openaca.core` exports no ladder to reuse, and CVSS labels grade advisories a detection does not have. Read before changing a finding's grade, or before assuming the four families share one scale.
46
46
  - [0011](0011-verdict-cache.md) — **A bounded local verdict cache, and what it may hold.** Amends ADR-0006: a reasoning verdict is an expensive pure function of a session, so it may persist — carrying rule ids, grades, spans and analyzer identity, and never conversation. Read before persisting anything session-derived, or before letting an upload path read local state.
47
47
  - [0012](0012-observation-evidence-kinds-and-transport.md) — **Observation is graded by what could misread it; an MCP transport is positive-only evidence.** Severity and confidence are orthogonal and neither is read off the other; a precondition sets a finding's grade, corroboration takes the best; `stdio` is never evidence of local execution. Read before changing a rule's confidence, adding an evidence kind, or treating an absent transport as local.
@@ -57,4 +57,6 @@ supersedes anything yet.
57
57
  - [0022](0022-detection-scope-is-a-catalogue-column.md) — **Detection scope is a per-rule catalogue column, set by cardinality.** Fleet identifies a detection by rule plus anchor, so scope decides what counts as the same finding seen again; `advisory-reach` and `progress-stall` both read as session-shaped and fire more than once per session, and session scope would merge those firings into one row permanently. Deriving scope from `bool(evidence)` is rejected — every rule always cites something. Read before adding a rule, or before changing how one groups its findings.
58
58
  - [0023](0023-sync-detect-collects-and-does-not-escalate.md) — **`sync detect` re-collects in-process, and defaults `--escalate` off.** The inverse of `stacktrace detect`, because a scheduled unattended run spending provider quota and crossing a content boundary on a timer is a recurring charge nobody approved per-run; consuming `detect --format json` was rejected as a projection of a projection. Read before changing a sync default, or before aligning the two commands' flags.
59
59
  - [0024](0024-the-upload-carries-observations.md) — **The upload carries observations; the Cloud derives catalogue text and coverage.** `title`, `remediation`, `family`, `verdict.stage` and `coverage` are all dropped — the first four are catalogue facts the Cloud seeds, and coverage is summed from `activity[]`. Not a privacy projection (ADR-0006 settled that) but a non-duplication one. Read before adding a field to the upload payload, or before "fixing" a bare `rule_id` in the console.
60
+ - [0026](0026-the-console-becomes-a-product-surface.md) — **The console becomes a product surface, served by the engine.** Supersedes ADR-0008 on its own stated condition: the engine came first, 0.1.0 shipped, and the data is only useful if a person can follow it. `stacktrace monitor` serves a loopback page from in-process calls, so the wheel now carries a `site/` asset — the cost 0008 refused, accepted here explicitly. What survives from 0008 is the clause that matters: the console renders and never computes, so a finding on the page is one `detect` would print. Read before adding anything to the console that the detector does not produce.
60
61
  - [0025](0025-a-denied-call-is-activity-never-an-invocation.md) — **A denied call is activity, and never an invocation.** ADR-0017 makes a declined repeat a stall while `outcome.py` keeps a denied call out of every count, so a denied-only session produced a finding with no activity and the Cloud rejected the whole run; a separate `denied` counter resolves it without either rule bending, and coverage keeps summing `invocations` alone. Read before changing what `activity[]` counts, or before folding `denied` into a coverage-like ratio.
62
+ - [0027](0027-a-finding-may-name-what-it-could-not-place.md) — **A finding may name the component it could not place.** Narrows ADR-0006 constraint 3 for one field: an unplaced subject carries the name the session addressed it by, never as an identity. Read before removing a name from a finding on trust-boundary grounds, or before widening this to a second field.