stacktrace-cli 0.5.2__tar.gz → 0.6.0__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.
- stacktrace_cli-0.6.0/.claude/skills/pr-review-loop/SKILL.md +120 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/PKG-INFO +3 -3
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/README.md +1 -1
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0029-stage-three-returns-to-opt-in.md +2 -2
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0033-a-third-party-analyzer-only-by-a-flag-that-names-it.md +2 -2
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0035-naming-an-analyzer-selects-stored-answers.md +1 -1
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0060-two-upload-postures-not-one-command-with-two-sources.md +1 -1
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0065-asset-external-id-resolves-by-a-ladder.md +1 -1
- stacktrace_cli-0.6.0/docs/adrs/0074-a-window-selects-findings-by-when-they-happened.md +115 -0
- stacktrace_cli-0.6.0/docs/adrs/0076-two-phase-detection-pipeline.md +164 -0
- stacktrace_cli-0.6.0/docs/adrs/0077-the-bom-job-wakes-once-at-startup-staggered.md +208 -0
- stacktrace_cli-0.6.0/docs/adrs/0078-a-seeded-display-prefix-replaces-the-hostname-label.md +74 -0
- stacktrace_cli-0.6.0/docs/adrs/0079-the-monitor-page-renders-findings-not-pipeline-health.md +93 -0
- stacktrace_cli-0.6.0/docs/adrs/0080-enabling-reasoning-does-not-requeue-the-past.md +103 -0
- stacktrace_cli-0.6.0/docs/adrs/0081-reasoning-activation-returns-to-explicit-opt-in.md +136 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/INDEX.md +11 -5
- stacktrace_cli-0.6.0/docs/releases/v0.5.3.md +70 -0
- stacktrace_cli-0.6.0/docs/releases/v0.6.0.md +120 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/specs/daemon-uploads.md +14 -4
- stacktrace_cli-0.6.0/docs/specs/detection-policies.md +346 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/specs/detector.md +52 -16
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/specs/monitor.md +66 -162
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/pyproject.toml +2 -2
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/__init__.py +1 -1
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/analysis.py +98 -34
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/cloud/__init__.py +10 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/cloud/setup.sh +51 -11
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/correlate/observed.py +62 -6
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/daemon/cli.py +113 -4
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/daemon/config.py +85 -5
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/daemon/jobs.py +48 -1
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/daemon/observer.py +31 -2
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/daemon/presentation.py +28 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/daemon/runtime.py +46 -18
- stacktrace_cli-0.6.0/src/stacktrace_cli/detector/deterministic.py +2345 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/detector/render.py +1 -4
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/detector/rules.py +27 -4
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/detector/run.py +9 -1
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/monitor/reasoning.py +8 -6
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/monitor/server.py +4 -16
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/monitor/site/app.js +18 -291
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/monitor/site/index.html +0 -12
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/monitor/site/styles.css +0 -35
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/monitor/watch.py +176 -66
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/remote/identity.py +41 -12
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/conftest.py +6 -1
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/daemon/test_cli.py +260 -8
- stacktrace_cli-0.6.0/tests/daemon/test_config.py +195 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/daemon/test_jobs.py +116 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/daemon/test_observer.py +194 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/daemon/test_runtime.py +108 -1
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/daemon/test_the_drained_payload_is_the_cold_one.py +21 -3
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/detector_session_fixture.py +1 -1
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/monitor/feed_harness.mjs +32 -246
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/monitor/test_feed_model.py +30 -213
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/monitor/test_render.py +27 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/monitor/test_site_assets.py +15 -29
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/monitor/test_watch.py +413 -21
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/remote/test_identity.py +62 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/remote/test_sync_detect.py +6 -1
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_adr_cross_references_are_reciprocal.py +15 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_analysis.py +133 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_detector_end_to_end.py +7 -4
- stacktrace_cli-0.6.0/tests/test_detector_new_deterministic.py +3491 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_detector_render.py +17 -0
- stacktrace_cli-0.6.0/tests/test_detector_vulnerable_dep_invoked.py +477 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_monitor_cli.py +9 -13
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_readme_examples_are_real_output.py +1 -1
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_shell_separators_match_the_shell.py +22 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_the_detector_spec_lists_the_shipped_catalogue.py +58 -1
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_the_locality_claim_is_qualified_everywhere.py +0 -39
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_untrusted_content_never_travels.py +45 -2
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_what_jev_is_told_is_what_was_disclosed.py +2 -26
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/uv.lock +5 -5
- stacktrace_cli-0.5.2/src/stacktrace_cli/detector/deterministic.py +0 -506
- stacktrace_cli-0.5.2/tests/daemon/test_config.py +0 -92
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/.agents/skills/release-stacktrace/SKILL.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/.claude/settings.json +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/.claude/skills/release-stacktrace/SKILL.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/.codex/hooks.json +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/.github/managed-autofix.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/.github/workflows/autofix.yml +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/.github/workflows/ci.yml +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/.github/workflows/claude.yml +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/.github/workflows/publish-pypi.yml +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/.gitignore +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/AGENTS.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/CLAUDE.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0001-session-telemetry-as-input.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0002-session-collection-in-openaidr.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0003-runtime-edges.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0004-three-stage-detector.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0005-detection-family-and-report-assembly.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0006-trust-boundary-and-detection-upload.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0007-proprietary-package-on-open-dependencies.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0008-console-in-separate-demo-package.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0010-detection-severity-and-confidence-ladders.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0011-verdict-cache.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0012-observation-evidence-kinds-and-transport.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0013-rule-catalogue-triage-and-per-rule-context.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0014-declared-project-mapping.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0015-narrow-the-security-catalogue.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0016-stall-grouping-is-session-wide.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0017-a-declined-repeat-is-a-stall.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0018-remote-sync-config-and-facade-consumption.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0019-delegated-commands-are-openaca-objects.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0020-openaca-consumption-boundary.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0021-two-command-kinds.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0022-detection-scope-is-a-catalogue-column.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0023-sync-detect-collects-and-does-not-escalate.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0024-the-upload-carries-observations.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0025-a-denied-call-is-activity-never-an-invocation.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0026-the-console-becomes-a-product-surface.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0027-a-finding-may-name-what-it-could-not-place.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0028-the-console-shows-what-it-placed.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0030-a-detection-is-dated-by-the-turns-it-cites.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0031-one-host-daemon-observes-native-session-logs.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0032-refresh-daemon-compositions-outside-detection.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0034-the-drift-grade-is-read-off-a-run-not-a-call.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0036-deliver-eligible-findings-to-slack-from-the-daemon.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0037-reuse-openaidr-append-cursors-in-the-daemon.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0038-poll-normalized-sessions-for-supplemental-changes.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0039-send-usage-telemetry-by-default-with-an-opt-out.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0041-defer-native-windows-support.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0042-read-the-build-commit-from-the-install-record.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0043-name-the-session-agent-and-host-and-count-errors-by-class.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0044-send-the-build-as-version-prints-it.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0045-scan-every-session-and-outlive-them.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0046-the-finding-store-is-an-append-only-queue.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0047-capture-activity-during-correlation-or-lose-it.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0048-the-daemon-keeps-a-leveled-content-free-activity-log.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0056-stop-a-resident-daemon-by-record-and-signal.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0057-grow-the-queue-schema-additively-and-share-only-the-document.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0058-one-word-for-a-finding-columns-for-a-counter-and-a-push-that-does-not-wait.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0059-the-daemon-does-not-decide-whether-it-should-be-running.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0061-the-drain-sends-findings-only.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0062-hold-the-transition-lock-across-remote-side-effects.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0063-underbuilt-debt-does-not-hold-the-scan-watermark.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0064-a-redacted-value-has-one-path-span.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0066-host-owned-daemon-supervision.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0067-a-webhook-is-an-independent-queue-subscriber.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0068-webhooks-retry-the-retained-backlog.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0069-webhooks-deliver-what-retention-holds.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0070-package-the-cloud-agent-environment-bootstrap.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0071-render-the-allowlisted-payload-per-destination.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0072-host-supervisors-own-daemon-restarts.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/0073-name-what-fired-and-which-component.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/HOOK-PROMPT.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/adrs/TEMPLATE.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/cutover-openaca-remote.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/plans/002-session-input.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/plans/003-correlation.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/plans/004-detector.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/plans/005-remote-sync.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/plans/006-cli-composition.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/plans/007-detection-upload.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/plans/008-monitor.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/plans/009-reasoning-jev.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/plans/010-session-daemon.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/plans/011-daemon-store.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/plans/012-daemon-scanning.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/plans/013-daemon-uploads.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/plans/014-asset-identity.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/releases/v0.0.1.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/releases/v0.1.0.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/releases/v0.2.0.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/releases/v0.2.1.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/releases/v0.2.2.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/releases/v0.2.3.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/releases/v0.3.0.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/releases/v0.3.1.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/releases/v0.4.0.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/releases/v0.4.1.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/releases/v0.5.0.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/releases/v0.5.1.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/releases/v0.5.2.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/research/001-intent-drift-metric.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/specs/aidr.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/specs/cli-composition.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/specs/correlation.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/specs/daemon-scanning.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/specs/daemon-store.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/specs/detection-upload.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/specs/event-time.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/specs/notification-delivery.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/specs/reasoning-jev.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/specs/remote-sync.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/docs/specs/session-input.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/scripts/git-hooks/pre-push +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/scripts/install-hooks.sh +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/__main__.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/build.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/cli.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/correlate/__init__.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/correlate/acquire.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/correlate/composition.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/correlate/join.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/correlate/orchestrate.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/correlate/project_map.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/correlate/record.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/correlate/render.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/daemon/__init__.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/daemon/activity_log.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/daemon/bom.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/daemon/client.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/daemon/composition.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/daemon/db.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/daemon/fleet.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/daemon/identity.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/daemon/lifecycle.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/daemon/paths.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/daemon/protocol.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/daemon/scan.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/daemon/server.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/daemon/service.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/daemon/store.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/daemon/webhook.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/detector/__init__.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/detector/analyzer.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/detector/blocked.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/detector/cache.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/detector/finding.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/detector/history.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/detector/jev.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/detector/priors.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/detector/prompts/__init__.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/detector/prompts/jev-v1/stacktrace-deceptive-completion.json +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/detector/prompts/jev-v2/stacktrace-deceptive-completion.json +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/detector/prompts/v1/exclusions.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/detector/prompts/v1/framing.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/detector/prompts/v1/stacktrace-deceptive-completion.md +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/detector/reasoning.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/detector/secrets.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/detector/verdict.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/detector/windows.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/monitor/__init__.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/monitor/render.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/monitor/site/fonts/OFL.txt +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/monitor/site/fonts/dm-mono-400-latin.woff2 +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/monitor/site/fonts/dm-mono-500-latin.woff2 +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/monitor/site/fonts/dm-sans-latin.woff2 +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/monitor/state.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/monitor/verdicts.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/options.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/private_state.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/remote/__init__.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/remote/cli.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/remote/client.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/remote/config.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/remote/detect_payload.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/remote/payload.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/remote/policy.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/remote/redact.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/remote/spool.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/remote/sync.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/remote/sync_detect.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/remote/upload_contract.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/sessions/__init__.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/sessions/access.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/sessions/index.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/sessions/outcome.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/sessions/protocols.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/sessions/render.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/telemetry/__init__.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/telemetry/cli.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/telemetry/events.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/telemetry/posthog.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/telemetry/state.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/webhook/__init__.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/webhook/cli.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/src/stacktrace_cli/webhook/config.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/__init__.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/agent_bom_fixture.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/daemon/__init__.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/daemon/test_activity_log.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/daemon/test_client.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/daemon/test_composition.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/daemon/test_db.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/daemon/test_detection_needs_no_subscriber.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/daemon/test_fleet.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/daemon/test_identity.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/daemon/test_lifecycle.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/daemon/test_queue_reader.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/daemon/test_scan.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/daemon/test_service.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/daemon/test_socket.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/daemon/test_store.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/daemon/test_the_stored_row_is_sufficient.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/daemon/test_webhook.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/daemon/test_wire_frames_are_bounded.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/monitor/__init__.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/monitor/test_reasoning_gates.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/monitor/test_server.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/monitor/test_state.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/monitor/test_verdicts.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/remote/__init__.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/remote/helpers.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/remote/test_cli.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/remote/test_client.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/remote/test_config.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/remote/test_detect_activity.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/remote/test_detect_cli.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/remote/test_detect_client.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/remote/test_detect_contract_is_exhaustive.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/remote/test_detect_gate_matches_the_cloud.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/remote/test_detect_layers_compose.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/remote/test_detect_payload_reaches_the_cloud_model.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/remote/test_detect_redaction.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/remote/test_detect_spool.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/remote/test_detect_upload_contract.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/remote/test_detect_wire_payload.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/remote/test_facade_contract.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/remote/test_no_local_path_survives_redaction.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/remote/test_payload.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/remote/test_policy.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/remote/test_redact_payload.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/remote/test_seam.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/remote/test_spool.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/remote/test_sync.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/remote/test_upload_contract.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/telemetry/__init__.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/telemetry/test_activity_log.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/telemetry/test_cli.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/telemetry/test_events.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/telemetry/test_hooks.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/telemetry/test_release_gate.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/telemetry/test_state.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/telemetry/test_uploader.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_acquire.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_agent_instance_id.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_bom_shape.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_build_commit.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_call_status_conventions.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_cli.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_composition.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_correlate_orchestrate.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_correlate_render.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_correlated_session.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_detection_components.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_detection_event_time.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_detection_subject.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_detector_analyzer_contract.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_detector_analyzer_live.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_detector_blocked.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_detector_cache.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_detector_deterministic.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_detector_finding.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_detector_history.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_detector_jev.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_detector_priors.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_detector_prompts.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_detector_reasoning.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_detector_run.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_detector_secrets.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_detector_verdict.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_detector_why_it_stopped.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_detector_windows.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_evidence_is_dated_not_numbered.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_fingerprint_covers_what_the_analyzer_reads.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_help_sections.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_join.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_no_live_document_states_the_old_stage_three_default.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_no_test_undoes_every_patch_at_once.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_observed.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_openaca_contract.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_openaidr_contract.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_option_arity_matches_the_binary.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_project_map.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_release_gate_coverage.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_release_readiness.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_seam_boundary.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_session_identity_is_the_pair.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_sessions_access.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_sessions_end_to_end.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_sessions_protocol_typing.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_sessions_protocols.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_sessions_render.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_stored_verdicts_are_never_gated_on_reasoning.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_the_jev_spec_states_the_shipped_thresholds.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_title_disclosure_invariant.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/test_verification_subcommands_match_the_binary.py +0 -0
- {stacktrace_cli-0.5.2 → stacktrace_cli-0.6.0}/tests/webhook/test_cli.py +0 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pr-review-loop
|
|
3
|
+
description: Autonomous code → commit → push → PR → review monitoring → fix → thumbsup loop. Use when the user wants end-to-end delivery of code changes through Codex review approval.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# pr-review-loop
|
|
7
|
+
|
|
8
|
+
End-to-end autonomous loop: generate code, commit, push, create or update a PR,
|
|
9
|
+
monitor Codex review, fix findings, and iterate until the PR receives a thumbsup
|
|
10
|
+
or approval with no actionable findings remaining.
|
|
11
|
+
|
|
12
|
+
**Announce at start:** "I'm using the pr-review-loop skill to deliver this change
|
|
13
|
+
through review."
|
|
14
|
+
|
|
15
|
+
## When to invoke
|
|
16
|
+
|
|
17
|
+
User says any of: "ship this", "get this to thumbsup", "run the review loop",
|
|
18
|
+
"deliver through review", or asks for code changes with instructions to
|
|
19
|
+
autonomously handle the PR review cycle.
|
|
20
|
+
|
|
21
|
+
## Inputs
|
|
22
|
+
|
|
23
|
+
1. **Branch name** — inferred from the current branch, or ask the user.
|
|
24
|
+
2. **PR number** — if a PR already exists for the branch, use it. Otherwise
|
|
25
|
+
create a new one.
|
|
26
|
+
3. **Base branch** — defaults to `main`.
|
|
27
|
+
|
|
28
|
+
## Phase 1: Code generation
|
|
29
|
+
|
|
30
|
+
1. Implement the requested changes following the repo's conventions (CLAUDE.md):
|
|
31
|
+
- TDD for business logic (red → green → refactor)
|
|
32
|
+
- Surgical changes — touch only what you must
|
|
33
|
+
- Simplicity first — no speculative abstractions
|
|
34
|
+
2. Run all four gates before committing:
|
|
35
|
+
```bash
|
|
36
|
+
uv run ruff check .
|
|
37
|
+
uv run ruff format --check .
|
|
38
|
+
uv run pyright
|
|
39
|
+
uv run pytest -q
|
|
40
|
+
```
|
|
41
|
+
3. Fix any failures. If a gate reveals a design decision, go with the
|
|
42
|
+
recommendation and log the decision.
|
|
43
|
+
|
|
44
|
+
## Phase 2: Commit, push, PR
|
|
45
|
+
|
|
46
|
+
1. Stage only the files your changes touch — never `git add -A`.
|
|
47
|
+
2. Commit with a descriptive message explaining WHY, not WHAT.
|
|
48
|
+
3. Push to remote. If rejected, stop and report it as a blocker — fetch and
|
|
49
|
+
look at what changed, but do not rebase or force-push to resolve it
|
|
50
|
+
automatically (see "Never force-push, rebase published commits" below).
|
|
51
|
+
4. If no PR exists for this branch, create one with `gh pr create`. Include a
|
|
52
|
+
summary, list of changes, and a test plan.
|
|
53
|
+
5. If a PR already exists, update its description if the scope changed.
|
|
54
|
+
|
|
55
|
+
## Phase 3: Monitor review
|
|
56
|
+
|
|
57
|
+
Poll for review status using a dynamic loop (`/loop`). On each tick:
|
|
58
|
+
|
|
59
|
+
1. Check CI status:
|
|
60
|
+
```bash
|
|
61
|
+
gh pr checks <PR_NUMBER>
|
|
62
|
+
```
|
|
63
|
+
2. Check for new review comments:
|
|
64
|
+
```bash
|
|
65
|
+
gh api repos/<OWNER>/<REPO>/pulls/<PR_NUMBER>/comments --paginate
|
|
66
|
+
gh api repos/<OWNER>/<REPO>/pulls/<PR_NUMBER>/reviews
|
|
67
|
+
```
|
|
68
|
+
3. If CI fails, read the logs and fix the issue. Push a new commit.
|
|
69
|
+
4. If Codex or a human reviewer left comments:
|
|
70
|
+
- Read each comment thread.
|
|
71
|
+
- For P0/P1/P2 findings: fix them. Push a new commit.
|
|
72
|
+
- For P3 findings: defer unless the user approved them.
|
|
73
|
+
- If you disagree with a finding: reply on the PR explaining why,
|
|
74
|
+
with evidence. Do not silently skip it.
|
|
75
|
+
5. If a reviewer requested changes, address them and re-request review.
|
|
76
|
+
|
|
77
|
+
### Decisions during review
|
|
78
|
+
|
|
79
|
+
- **Make autonomous decisions** for: code style fixes, test additions,
|
|
80
|
+
lint/format fixes, obvious bug fixes, naming improvements.
|
|
81
|
+
- **Log but proceed** for: architecture choices between reasonable alternatives,
|
|
82
|
+
threshold values, which invariant test to extend.
|
|
83
|
+
- **Stop and ask** for: design-level questions flagged for the user, scope
|
|
84
|
+
changes that would significantly alter the PR, removing existing tests or
|
|
85
|
+
changing public interfaces.
|
|
86
|
+
|
|
87
|
+
### Stopping conditions
|
|
88
|
+
|
|
89
|
+
- **Success:** CI passes, the latest head has been reviewed, and no actionable
|
|
90
|
+
P0/P1/P2 findings remain. Report the result.
|
|
91
|
+
- **Cap reached:** After 7 automated fix rounds without a human corrective
|
|
92
|
+
commit, stop and post a message in the PR (per CLAUDE.md review rules).
|
|
93
|
+
- **Blocked:** A finding requires human judgment (design decision, scope change).
|
|
94
|
+
Post a summary comment and notify the user.
|
|
95
|
+
|
|
96
|
+
## Phase 4: Summary
|
|
97
|
+
|
|
98
|
+
When the loop exits, report:
|
|
99
|
+
1. Total commits pushed.
|
|
100
|
+
2. Review rounds completed.
|
|
101
|
+
3. Decisions made autonomously (with brief justification for each).
|
|
102
|
+
4. Any remaining P3 suggestions that were deferred.
|
|
103
|
+
5. Final PR status (approved / changes requested / commented).
|
|
104
|
+
|
|
105
|
+
## Conventions
|
|
106
|
+
|
|
107
|
+
- Never force-push, rebase published commits, or skip hooks.
|
|
108
|
+
- Every fix is a new commit, not an amend.
|
|
109
|
+
- Batch related fixes into one commit when possible.
|
|
110
|
+
- Run all four gates before every push.
|
|
111
|
+
- Count fix rounds per CLAUDE.md: 7 rounds without a human corrective commit
|
|
112
|
+
triggers the cap.
|
|
113
|
+
|
|
114
|
+
## What this skill does NOT do
|
|
115
|
+
|
|
116
|
+
- **Doesn't merge the PR.** That's always a human action.
|
|
117
|
+
- **Doesn't approve its own PR.** It can only push fixes and respond to review.
|
|
118
|
+
- **Doesn't modify CI/CD, branch protection, or permissions.**
|
|
119
|
+
- **Doesn't override human reviewer decisions.** If a human says "don't fix
|
|
120
|
+
this", it stays unfixed.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: stacktrace-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
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>
|
|
@@ -21,7 +21,7 @@ Requires-Python: >=3.11
|
|
|
21
21
|
Requires-Dist: click>=8.1
|
|
22
22
|
Requires-Dist: httpx<1.0.dev0,>=0.28.1
|
|
23
23
|
Requires-Dist: openaca==0.7.0
|
|
24
|
-
Requires-Dist: openaidr==0.3.
|
|
24
|
+
Requires-Dist: openaidr==0.3.2
|
|
25
25
|
Requires-Dist: posthog<8,>=7.0
|
|
26
26
|
Description-Content-Type: text/markdown
|
|
27
27
|
|
|
@@ -51,7 +51,7 @@ Requires Python 3.11 or newer.
|
|
|
51
51
|
|
|
52
52
|
```console
|
|
53
53
|
$ stacktrace --version
|
|
54
|
-
stacktrace 0.
|
|
54
|
+
stacktrace 0.6.0 (openaca 0.7.0)
|
|
55
55
|
```
|
|
56
56
|
|
|
57
57
|
## Quick start
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
id: 0033
|
|
3
3
|
title: A third-party analyzer is reached only by a flag that names it, and its output is numbers
|
|
4
|
-
status:
|
|
4
|
+
status: superseded
|
|
5
5
|
date: 2026-09-17
|
|
6
6
|
supersedes: null
|
|
7
|
-
superseded-by:
|
|
7
|
+
superseded-by: 0076
|
|
8
8
|
amends: 0004, 0011
|
|
9
9
|
amended-by: 0034, 0035
|
|
10
10
|
---
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: 0074
|
|
3
|
+
title: A window selects findings by when they happened
|
|
4
|
+
status: accepted
|
|
5
|
+
date: 2026-09-28
|
|
6
|
+
supersedes: null
|
|
7
|
+
superseded-by: null
|
|
8
|
+
amends: null
|
|
9
|
+
amended-by: null
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Context
|
|
13
|
+
|
|
14
|
+
`--since` reads as a claim about findings, and was a claim about files.
|
|
15
|
+
Collection selects whole transcripts by file mtime, so a session written inside
|
|
16
|
+
the window is collected entire and every rule walks all of its turns. What a
|
|
17
|
+
reader gets is therefore *every finding in every session whose file was touched
|
|
18
|
+
in the range*, which is not what any of the three commands say.
|
|
19
|
+
|
|
20
|
+
Found on a live monitor. The window was `06:10:11 → 06:15:11`, five minutes,
|
|
21
|
+
and the page showed two findings: a `credential-egress` at `06:14:12`, correctly
|
|
22
|
+
in range, and an `agent-blocked` at `05:56:52` — eighteen minutes before the
|
|
23
|
+
window began. That finding belongs to a 538-turn session started the previous
|
|
24
|
+
night and still being typed into, so its transcript was written a minute before
|
|
25
|
+
the pass and the whole session came with it. `summary.detections` was 2, so this
|
|
26
|
+
was the pipeline's answer and not the page's.
|
|
27
|
+
|
|
28
|
+
The reverse reading is the same mistake and does not occur: a finding's clock
|
|
29
|
+
comes from the turns it cites and a transcript's mtime is its last write, so
|
|
30
|
+
mtime is never earlier than `occurred_end`. A finding inside the window always
|
|
31
|
+
sits in a file the mtime rule already admitted. The rule over-admits and never
|
|
32
|
+
under-admits.
|
|
33
|
+
|
|
34
|
+
## Decision
|
|
35
|
+
|
|
36
|
+
A window selects findings by **when they happened**. `analyse` reports a
|
|
37
|
+
finding when its own `occurred_end` reaches into the window, and `detect`,
|
|
38
|
+
`monitor` and `sync detect` all reach it through that one call — `cli.py`
|
|
39
|
+
already states the invariant that the three must not be able to disagree about
|
|
40
|
+
what was found.
|
|
41
|
+
|
|
42
|
+
Overlap decides, and both ends are tested. `occurred_end` against the start, so
|
|
43
|
+
a rule firing across a run of turns belongs in the window its last citation
|
|
44
|
+
reaches — what a reader asking *what is happening now* means. `occurred_start`
|
|
45
|
+
against the end, so a finding straddling the boundary is not dropped for
|
|
46
|
+
finishing late.
|
|
47
|
+
|
|
48
|
+
The upper bound is not ceremony. `analyse` takes `window_end` *before*
|
|
49
|
+
collection, deliberately, so a window cannot claim to cover a session that
|
|
50
|
+
started while the pipeline ran — and collection then reads files that may have
|
|
51
|
+
been appended to in between. A finding can therefore carry a clock later than
|
|
52
|
+
the end the caller is shown, and reporting it would contradict the heading the
|
|
53
|
+
window prints.
|
|
54
|
+
|
|
55
|
+
A finding carrying no clock, or one whose clock is naive and cannot be compared
|
|
56
|
+
against an aware bound, is reported rather than judged; hiding a real finding
|
|
57
|
+
over a missing field is the more expensive mistake.
|
|
58
|
+
|
|
59
|
+
**`analyse_sessions` is deliberately excluded.** The daemon passes a watermark
|
|
60
|
+
deciding which transcripts to re-read, not a range a person chose, and its
|
|
61
|
+
docstring already says it "stamps it as `window_start` and analyses the view
|
|
62
|
+
whole". Its findings are the record that feeds the store, the webhook and Fleet,
|
|
63
|
+
where narrowing by a window would lose a finding rather than hide it.
|
|
64
|
+
|
|
65
|
+
## Alternatives considered
|
|
66
|
+
|
|
67
|
+
- **Filter while rendering the monitor.** Rejected, and this was tried first.
|
|
68
|
+
It gives the page an admission rule of its own, so `detect --since 5m` prints
|
|
69
|
+
a finding `monitor --since 5m` hides. ADR-0026 clause 2 and the monitor spec's
|
|
70
|
+
robustness bar — "a page that can invent, alter or suppress a detection" —
|
|
71
|
+
both forbid it.
|
|
72
|
+
- **Carry findings forward in the page, or in the snapshot beside it.** Rejected.
|
|
73
|
+
Retention in the browser makes the answer depend on how long a tab has been
|
|
74
|
+
open: a reload and an open tab disagree about the same window. Moving the
|
|
75
|
+
carry-forward into the watcher relocates the same violation from the renderer
|
|
76
|
+
to the server, since a snapshot would then carry findings the current pass did
|
|
77
|
+
not produce. Both were attempted on the branch that became this ADR and both
|
|
78
|
+
are reverted.
|
|
79
|
+
- **Admit sessions by their events rather than their mtime, at collection.**
|
|
80
|
+
Rejected as unnecessary rather than wrong. It would reach the same result by
|
|
81
|
+
reading more files, and the asymmetry above means there is nothing to gain:
|
|
82
|
+
no finding inside the window lives in a file the mtime rule excluded.
|
|
83
|
+
- **Exempt `sync detect`, so only the two read-only views scope.** Rejected. It
|
|
84
|
+
is a view of a range someone asked for, and `cli.py`'s invariant does not
|
|
85
|
+
allow two of the three to mean one thing and the third another. What must not
|
|
86
|
+
be scoped is the daemon's record, and that is a different entry point.
|
|
87
|
+
|
|
88
|
+
## Consequences
|
|
89
|
+
|
|
90
|
+
`--since` means one thing in all three commands, and the page's window agrees
|
|
91
|
+
with its own heading.
|
|
92
|
+
|
|
93
|
+
The cost is that **`sync detect` uploads become window-scoped**, which is a
|
|
94
|
+
change to something that leaves the machine. A finding older than the window is
|
|
95
|
+
no longer uploaded by that command even when its session was touched inside the
|
|
96
|
+
range. This is the intended reading of `--since 7d` — findings from the last
|
|
97
|
+
seven days — but it is a narrowing, and an operator who wants everything must
|
|
98
|
+
say so with a wider window. The daemon's own upload path is unaffected and
|
|
99
|
+
remains the durable record.
|
|
100
|
+
|
|
101
|
+
One test moved with the semantics rather than around them:
|
|
102
|
+
`test_an_anonymous_session_does_not_take_a_known_agents_findings_with_it` builds
|
|
103
|
+
its session at the shared fixture moment, about a month before any realistic
|
|
104
|
+
window, and now declares a window wide enough to reach it. Its subject is
|
|
105
|
+
routing, not recency.
|
|
106
|
+
|
|
107
|
+
## When to revisit
|
|
108
|
+
|
|
109
|
+
- **If a finding's clock ever becomes unreliable** — a reader that cannot date
|
|
110
|
+
its turns, an imported or replayed transcript whose mtime is rewritten — the
|
|
111
|
+
asymmetry this rests on ("mtime is never earlier than `occurred_end`") stops
|
|
112
|
+
holding, and admission would need to read events rather than trust the file.
|
|
113
|
+
- **If `sync detect` grows a separate "upload everything" mode**, the
|
|
114
|
+
window-scoping decided here stops being the whole story for that command and
|
|
115
|
+
the split should be recorded rather than inferred from a flag.
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: 0076
|
|
3
|
+
title: Collapse detector to two phases with conditional reasoning
|
|
4
|
+
status: accepted
|
|
5
|
+
date: 2026-09-27
|
|
6
|
+
supersedes: 0029, 0033
|
|
7
|
+
superseded-by: null
|
|
8
|
+
amends: 0035
|
|
9
|
+
amended-by: 0081
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Context
|
|
13
|
+
|
|
14
|
+
The detector has three stages: deterministic (2 rules), priors (0 rules — all
|
|
15
|
+
five withdrawn), and reasoning (cache-only — daemon hardcodes
|
|
16
|
+
`reasoning=False`). Stage 2 contains no detection logic, only routing and two
|
|
17
|
+
data-quality metrics. The daemon never activates new reasoning. Adding new
|
|
18
|
+
rules (10 total) requires cleaning up this structure.
|
|
19
|
+
|
|
20
|
+
Three problems force the change now:
|
|
21
|
+
|
|
22
|
+
1. **Stage 2 is empty.** `run_priors` has no rules. What remains is
|
|
23
|
+
`low_coverage` (a data-quality metric), `_missing_mcp_transport` (same),
|
|
24
|
+
and routing logic that builds `ReasoningRequest`s. None of that is
|
|
25
|
+
detection.
|
|
26
|
+
|
|
27
|
+
2. **The daemon never reasons.** `analyse_batch()` hardcodes
|
|
28
|
+
`reasoning=False`. New reasoning rules (`stacktrace-infra-unsafe-action`,
|
|
29
|
+
`stacktrace-unrequested-publication`) will never fire in the background.
|
|
30
|
+
|
|
31
|
+
3. **Reasoning blocks the tick.** A 1–3s Jev call per session, run
|
|
32
|
+
synchronously in a 5s tick, blocks the daemon.
|
|
33
|
+
|
|
34
|
+
## Decision
|
|
35
|
+
|
|
36
|
+
Collapse to two phases and one orchestrator. Phase 1 is deterministic (no
|
|
37
|
+
model, no vendor boundary — predominantly μs, with the exception of
|
|
38
|
+
`stacktrace-vulnerable-dep-invoked` which queries cached advisory data and degrades
|
|
39
|
+
to async enrichment on a cold cache). Phase 2 is reasoning (seconds,
|
|
40
|
+
requires `TYPESAFE_API_KEY`). The orchestrator sits between them and
|
|
41
|
+
builds the reasoning queue from gate trips, solo routes, and the
|
|
42
|
+
EVERY_SESSION route.
|
|
43
|
+
|
|
44
|
+
### Phase collapse
|
|
45
|
+
|
|
46
|
+
Stage 2's remnants move:
|
|
47
|
+
|
|
48
|
+
| Function | Destination |
|
|
49
|
+
|---|---|
|
|
50
|
+
| `low_coverage` | Session-level metric (not a rule) |
|
|
51
|
+
| `_missing_mcp_transport` | Per-rule coverage metadata on the analysis result |
|
|
52
|
+
| Routing (`_solo_routes`, `ReasoningRequest`) | Orchestrator inside `run_detector` |
|
|
53
|
+
|
|
54
|
+
### Conditional reasoning activation
|
|
55
|
+
|
|
56
|
+
`TYPESAFE_API_KEY` in the environment is the only switch. No `--reasoning`
|
|
57
|
+
flag, no `--analyzer jev`. If the key is absent, `reasoning=False` — no
|
|
58
|
+
model, no cost, no vendor boundary. If present, Phase 2 runs only when
|
|
59
|
+
Phase 1 produces a non-empty reasoning queue.
|
|
60
|
+
|
|
61
|
+
Budget: `DEFAULT_DAEMON_BUDGET = 50`. It caps *sessions* dispatched to
|
|
62
|
+
Phase 2 per tick, not Jev calls — `stacktrace-deceptive-completion` alone
|
|
63
|
+
issues one gate call plus one call per verification call with a covering
|
|
64
|
+
claim, so a session's actual cost scales with its checks. At $0.0006/session
|
|
65
|
+
(one gate call) and typical <20 sessions/tick, normal operation is nowhere
|
|
66
|
+
near the cap; $0.03/tick is that single-call estimate at the budget ceiling,
|
|
67
|
+
not a hard spend cap — a tick of sessions with many verification calls can
|
|
68
|
+
exceed it.
|
|
69
|
+
|
|
70
|
+
### Async Phase 2
|
|
71
|
+
|
|
72
|
+
Phase 1 runs synchronously in the tick. Phase 2 dispatches to
|
|
73
|
+
`ThreadPoolExecutor(_WORKERS=4)` and returns immediately. The next tick
|
|
74
|
+
does not wait. When a verdict arrives, findings are recorded and
|
|
75
|
+
`on_commit` wakes the fleet/webhook jobs.
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
tick()
|
|
79
|
+
├─ Synchronous (μs–ms)
|
|
80
|
+
│ ├─ enumerate + collect + correlate
|
|
81
|
+
│ ├─ Phase 1: deterministic → findings recorded immediately
|
|
82
|
+
│ ├─ orchestrator → reasoning queue
|
|
83
|
+
│ └─ record(findings, unknowns, pending=queue)
|
|
84
|
+
│
|
|
85
|
+
├─ Asynchronous (ThreadPoolExecutor, background)
|
|
86
|
+
│ └─ for each ReasoningRequest:
|
|
87
|
+
│ build windows → Jev call → evaluate → store.record_reasoning()
|
|
88
|
+
│
|
|
89
|
+
└─ Scheduler.tick()
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Rule placement
|
|
93
|
+
|
|
94
|
+
| Rule | Phase | Rationale |
|
|
95
|
+
|---|---|---|
|
|
96
|
+
| `stacktrace-credential-egress` | 1 | Regex on call arguments |
|
|
97
|
+
| `stacktrace-agent-blocked` | 1 | Refused-call channel match |
|
|
98
|
+
| `stacktrace-destructive-action` | 1 | Path resolution on delete commands |
|
|
99
|
+
| `stacktrace-credential-persisted` | 1 | Secret match on a Write/Edit call's own content |
|
|
100
|
+
| `stacktrace-mcp-transient-failure` | 1 | MCP call sequence pattern |
|
|
101
|
+
| `stacktrace-tool-retry-storm` | 1 | Counter with reset |
|
|
102
|
+
| `stacktrace-vulnerable-dep-invoked` | 1 | Package list × osv.dev |
|
|
103
|
+
| `stacktrace-deceptive-completion` | 2 | Gate (Jev) + per-call nouls. EVERY_SESSION route. |
|
|
104
|
+
| `stacktrace-infra-unsafe-action` | 1 gate → 2 | Gate: mutating command. Model: beyond_request + shared_target. |
|
|
105
|
+
| `stacktrace-unrequested-publication` | 1 gate → 2 | Gate: publication verb. Model: beyond_request. |
|
|
106
|
+
|
|
107
|
+
## Alternatives considered
|
|
108
|
+
|
|
109
|
+
- **Keep three stages, add rules to stage 2.** Rejected because stage 2 has
|
|
110
|
+
no rules and its abstraction boundary is accidental — it exists because the
|
|
111
|
+
function signature existed, not because the domain has three kinds of work.
|
|
112
|
+
|
|
113
|
+
- **Separate `--reasoning` and `--analyzer` flags.** Rejected because the
|
|
114
|
+
consent decision is setting `TYPESAFE_API_KEY` — the operator named a
|
|
115
|
+
vendor by placing its key. Two flags that must be typed together, where one
|
|
116
|
+
is meaningless without the other, is ceremony that protects nothing.
|
|
117
|
+
|
|
118
|
+
- **Synchronous reasoning in the tick with a short budget.** Rejected because
|
|
119
|
+
even a budget of 3 blocks the tick for 3–9 seconds. The daemon goes deaf,
|
|
120
|
+
and the tick interval (5s) is shorter than a single Jev call.
|
|
121
|
+
|
|
122
|
+
## Consequences
|
|
123
|
+
|
|
124
|
+
- 7 of 10 rules fire on every tick with no model dependency.
|
|
125
|
+
- Reasoning activates automatically when a key is present and a gate trips.
|
|
126
|
+
- The tick never blocks on inference.
|
|
127
|
+
- `ThreadPoolExecutor(4)` caps Jev API pressure at 4 concurrent calls.
|
|
128
|
+
|
|
129
|
+
**Costs:**
|
|
130
|
+
|
|
131
|
+
- Async Phase 2 requires a daemon-owned executor with these invariants:
|
|
132
|
+
(1) bounded in-flight work — cap queued futures, not just the budget;
|
|
133
|
+
(2) in-flight deduplication — a session already pending reasoning is not
|
|
134
|
+
re-queued; (3) revision-aware commits — a reasoning result is committed
|
|
135
|
+
only if its session fingerprint matches the current analysis, so a stale
|
|
136
|
+
result from a slow Jev call never overwrites a newer deterministic pass;
|
|
137
|
+
(4) retry on transient Jev failure, with backoff, capped at 3 attempts;
|
|
138
|
+
(5) on daemon restart, pending reasoning is re-derived from Phase 1 on
|
|
139
|
+
the next tick rather than persisted across restarts;
|
|
140
|
+
(6) on daemon stop or upgrade, cancel queued futures and observe
|
|
141
|
+
cancellation between per-window requests in active workers — the executor
|
|
142
|
+
must not outlive the daemon's stop deadline (600s), so shutdown joins only
|
|
143
|
+
the work already in flight, never the full queue.
|
|
144
|
+
- New rules send data the original consent did not envision (shell commands,
|
|
145
|
+
user requests). Documentation should describe what each rule sends. This
|
|
146
|
+
ADR amends the consent model established in ADR-0033; key-as-consent is a
|
|
147
|
+
product decision that should be documented as such. Cached verdicts from
|
|
148
|
+
prior runs remain readable when the key is present, independent of whether
|
|
149
|
+
new reasoning is commissioned — this preserves the `--analyzer jev`
|
|
150
|
+
read-only behavior. Cached Jev verdicts remain readable without a key:
|
|
151
|
+
the cache is keyed by analyzer identity and prompt version, not by the
|
|
152
|
+
presence of a runtime credential, so removing or rotating
|
|
153
|
+
`TYPESAFE_API_KEY` stops commissioning new work but does not discard
|
|
154
|
+
already-paid findings.
|
|
155
|
+
|
|
156
|
+
## When to revisit
|
|
157
|
+
|
|
158
|
+
- If a second reasoning provider is added (Jev is the only one today), the
|
|
159
|
+
key-as-consent model needs per-provider consent.
|
|
160
|
+
- If Phase 2 latency exceeds 10s per session, the ThreadPoolExecutor design
|
|
161
|
+
may need a persistent queue with retry.
|
|
162
|
+
- If cross-rule incident grouping becomes urgent (credentials written,
|
|
163
|
+
committed, and pushed = three findings for one mistake), the orchestrator
|
|
164
|
+
needs a post-Phase-2 deduplication pass.
|