stacktrace-cli 0.8.0__tar.gz → 0.9.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.8.0 → stacktrace_cli-0.9.0}/CLAUDE.md +10 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/PKG-INFO +2 -2
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/README.md +1 -1
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0006-trust-boundary-and-detection-upload.md +1 -1
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0026-the-console-becomes-a-product-surface.md +1 -1
- stacktrace_cli-0.9.0/docs/adrs/0092-cost-is-its-own-rule-family.md +49 -0
- stacktrace_cli-0.9.0/docs/adrs/0093-environment-cost-baselines-count-tokens-keyed-by-model.md +78 -0
- stacktrace_cli-0.9.0/docs/adrs/0094-estimate-cost-from-tokens-the-agent-figure-is-a-cross-check.md +63 -0
- stacktrace_cli-0.9.0/docs/adrs/0095-cost-findings-reach-fleet-each-rule-can-be-muted.md +53 -0
- stacktrace_cli-0.9.0/docs/adrs/0096-cost-usage-may-leave-as-token-totals-and-work-identifiers.md +86 -0
- stacktrace_cli-0.9.0/docs/adrs/0097-the-daemon-makes-cost-findings-and-the-monitor-reads-them.md +69 -0
- stacktrace_cli-0.9.0/docs/adrs/0098-a-run-is-its-main-session.md +53 -0
- stacktrace_cli-0.9.0/docs/adrs/0099-cost-is-measured-in-tokens-and-relative-increases.md +85 -0
- stacktrace_cli-0.9.0/docs/adrs/0100-the-monitor-runs-offline-for-the-website.md +70 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/INDEX.md +10 -1
- stacktrace_cli-0.9.0/docs/plans/016-cost-phase-1.md +832 -0
- stacktrace_cli-0.9.0/docs/plans/017-cost-phase-2.md +89 -0
- stacktrace_cli-0.9.0/docs/releases/v0.9.0.md +116 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/specs/aidr.md +19 -11
- stacktrace_cli-0.9.0/docs/specs/cost-phase-1.md +477 -0
- stacktrace_cli-0.9.0/docs/specs/cost-phase-2.md +159 -0
- stacktrace_cli-0.9.0/docs/specs/cost.md +248 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/specs/detection-policies.md +73 -3
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/specs/detector.md +13 -1
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/specs/monitor.md +83 -4
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/specs/session-input.md +11 -9
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/pyproject.toml +1 -1
- stacktrace_cli-0.9.0/scripts/cost_latency.py +85 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/__init__.py +1 -1
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/analysis.py +13 -1
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/cli.py +3 -1
- stacktrace_cli-0.9.0/src/stacktrace_cli/cost/__init__.py +6 -0
- stacktrace_cli-0.9.0/src/stacktrace_cli/cost/baseline.py +493 -0
- stacktrace_cli-0.9.0/src/stacktrace_cli/cost/clock.py +40 -0
- stacktrace_cli-0.9.0/src/stacktrace_cli/cost/components.py +143 -0
- stacktrace_cli-0.9.0/src/stacktrace_cli/cost/evidence.py +69 -0
- stacktrace_cli-0.9.0/src/stacktrace_cli/cost/ledger.py +58 -0
- stacktrace_cli-0.9.0/src/stacktrace_cli/cost/measures.py +351 -0
- stacktrace_cli-0.9.0/src/stacktrace_cli/cost/models.py +38 -0
- stacktrace_cli-0.9.0/src/stacktrace_cli/cost/rules.py +1138 -0
- stacktrace_cli-0.9.0/src/stacktrace_cli/cost/runs.py +126 -0
- stacktrace_cli-0.9.0/src/stacktrace_cli/cost/tokens.py +69 -0
- stacktrace_cli-0.9.0/src/stacktrace_cli/cost/totals.py +62 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/daemon/cli.py +46 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/daemon/config.py +42 -0
- stacktrace_cli-0.9.0/src/stacktrace_cli/daemon/costs.py +882 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/daemon/db.py +65 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/daemon/fleet.py +3 -1
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/daemon/jobs.py +90 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/daemon/observer.py +17 -2
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/daemon/presentation.py +33 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/daemon/runtime.py +107 -8
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/daemon/scan.py +31 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/daemon/store.py +243 -2
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/detector/finding.py +1 -1
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/detector/render.py +14 -12
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/detector/rules.py +58 -4
- stacktrace_cli-0.9.0/src/stacktrace_cli/monitor/costs.py +375 -0
- stacktrace_cli-0.9.0/src/stacktrace_cli/monitor/offline.py +266 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/monitor/render.py +79 -21
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/monitor/server.py +5 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/monitor/site/app.js +64 -1
- stacktrace_cli-0.9.0/src/stacktrace_cli/monitor/site/cost.js +436 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/monitor/site/index.html +8 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/monitor/site/inventory.js +1 -1
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/monitor/site/styles.css +23 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/monitor/state.py +5 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/monitor/watch.py +16 -0
- stacktrace_cli-0.9.0/src/stacktrace_cli/sessions/lineage.py +24 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/sessions/protocols.py +81 -8
- stacktrace_cli-0.9.0/tests/cost/fakes.py +57 -0
- stacktrace_cli-0.9.0/tests/cost/scenarios.py +169 -0
- stacktrace_cli-0.9.0/tests/cost/test_baseline.py +223 -0
- stacktrace_cli-0.9.0/tests/cost/test_clock.py +61 -0
- stacktrace_cli-0.9.0/tests/cost/test_components.py +129 -0
- stacktrace_cli-0.9.0/tests/cost/test_cost_evidence_travels.py +135 -0
- stacktrace_cli-0.9.0/tests/cost/test_cost_findings_are_dated_by_their_citations.py +557 -0
- stacktrace_cli-0.9.0/tests/cost/test_cost_findings_carry_no_session_text.py +120 -0
- stacktrace_cli-0.9.0/tests/cost/test_cost_is_tokens.py +72 -0
- stacktrace_cli-0.9.0/tests/cost/test_cost_latency.py +82 -0
- stacktrace_cli-0.9.0/tests/cost/test_evidence.py +40 -0
- stacktrace_cli-0.9.0/tests/cost/test_ledger.py +44 -0
- stacktrace_cli-0.9.0/tests/cost/test_measures.py +251 -0
- stacktrace_cli-0.9.0/tests/cost/test_models.py +15 -0
- stacktrace_cli-0.9.0/tests/cost/test_rules_baseline.py +535 -0
- stacktrace_cli-0.9.0/tests/cost/test_rules_budget.py +189 -0
- stacktrace_cli-0.9.0/tests/cost/test_runs.py +43 -0
- stacktrace_cli-0.9.0/tests/cost/test_totals.py +55 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/daemon/test_activity_log.py +23 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/daemon/test_cli.py +96 -0
- stacktrace_cli-0.9.0/tests/daemon/test_cost_guidance.py +23 -0
- stacktrace_cli-0.9.0/tests/daemon/test_costs.py +1510 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/daemon/test_db.py +2 -0
- stacktrace_cli-0.9.0/tests/daemon/test_job_thread.py +63 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/daemon/test_runtime.py +64 -2
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/daemon/test_scan.py +105 -0
- stacktrace_cli-0.9.0/tests/daemon/test_stage_times.py +80 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/detector_session_fixture.py +6 -0
- stacktrace_cli-0.9.0/tests/monitor/cost_harness.mjs +133 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/monitor/feed_harness.mjs +71 -0
- stacktrace_cli-0.9.0/tests/monitor/test_cost_page.py +232 -0
- stacktrace_cli-0.9.0/tests/monitor/test_cost_range_switch.py +133 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/monitor/test_feed_model.py +23 -0
- stacktrace_cli-0.9.0/tests/monitor/test_offline.py +242 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/monitor/test_render.py +34 -3
- stacktrace_cli-0.9.0/tests/monitor/test_render_cost.py +641 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/monitor/test_site_assets.py +1 -1
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/remote/test_facade_contract.py +19 -0
- stacktrace_cli-0.9.0/tests/telemetry/__init__.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_call_status_conventions.py +158 -2
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_detector_end_to_end.py +2 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_fingerprint_covers_what_the_analyzer_reads.py +9 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_openaidr_contract.py +67 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_seam_boundary.py +3 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_session_identity_is_the_pair.py +13 -0
- stacktrace_cli-0.9.0/tests/test_sessions_protocol_typing.py +44 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_sessions_protocols.py +35 -2
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_the_detector_spec_lists_the_shipped_catalogue.py +12 -2
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_title_disclosure_invariant.py +11 -4
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/uv.lock +2 -2
- stacktrace_cli-0.8.0/tests/test_sessions_protocol_typing.py +0 -18
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/.agents/skills/release-stacktrace/SKILL.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/.claude/settings.json +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/.claude/skills/pr-review-loop/SKILL.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/.claude/skills/release-stacktrace/SKILL.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/.codex/hooks.json +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/.github/managed-autofix.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/.github/pull_request_template.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/.github/workflows/ci.yml +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/.github/workflows/publish-pypi.yml +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/.gitignore +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/AGENTS.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0001-session-telemetry-as-input.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0002-session-collection-in-openaidr.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0003-runtime-edges.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0004-three-stage-detector.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0005-detection-family-and-report-assembly.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0007-proprietary-package-on-open-dependencies.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0008-console-in-separate-demo-package.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0010-detection-severity-and-confidence-ladders.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0011-verdict-cache.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0012-observation-evidence-kinds-and-transport.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0013-rule-catalogue-triage-and-per-rule-context.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0014-declared-project-mapping.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0015-narrow-the-security-catalogue.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0016-stall-grouping-is-session-wide.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0017-a-declined-repeat-is-a-stall.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0018-remote-sync-config-and-facade-consumption.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0019-delegated-commands-are-openaca-objects.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0020-openaca-consumption-boundary.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0021-two-command-kinds.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0022-detection-scope-is-a-catalogue-column.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0023-sync-detect-collects-and-does-not-escalate.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0024-the-upload-carries-observations.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0025-a-denied-call-is-activity-never-an-invocation.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0027-a-finding-may-name-what-it-could-not-place.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0028-the-console-shows-what-it-placed.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0029-stage-three-returns-to-opt-in.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0030-a-detection-is-dated-by-the-turns-it-cites.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0031-one-host-daemon-observes-native-session-logs.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0032-refresh-daemon-compositions-outside-detection.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0033-a-third-party-analyzer-only-by-a-flag-that-names-it.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0034-the-drift-grade-is-read-off-a-run-not-a-call.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0035-naming-an-analyzer-selects-stored-answers.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0036-deliver-eligible-findings-to-slack-from-the-daemon.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0037-reuse-openaidr-append-cursors-in-the-daemon.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0038-poll-normalized-sessions-for-supplemental-changes.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0039-send-usage-telemetry-by-default-with-an-opt-out.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0041-defer-native-windows-support.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0042-read-the-build-commit-from-the-install-record.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0043-name-the-session-agent-and-host-and-count-errors-by-class.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0044-send-the-build-as-version-prints-it.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0045-scan-every-session-and-outlive-them.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0046-the-finding-store-is-an-append-only-queue.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0047-capture-activity-during-correlation-or-lose-it.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0048-the-daemon-keeps-a-leveled-content-free-activity-log.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0056-stop-a-resident-daemon-by-record-and-signal.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0057-grow-the-queue-schema-additively-and-share-only-the-document.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.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.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0059-the-daemon-does-not-decide-whether-it-should-be-running.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0060-two-upload-postures-not-one-command-with-two-sources.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0061-the-drain-sends-findings-only.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0062-hold-the-transition-lock-across-remote-side-effects.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0063-underbuilt-debt-does-not-hold-the-scan-watermark.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0064-a-redacted-value-has-one-path-span.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0065-asset-external-id-resolves-by-a-ladder.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0066-host-owned-daemon-supervision.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0067-a-webhook-is-an-independent-queue-subscriber.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0068-webhooks-retry-the-retained-backlog.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0069-webhooks-deliver-what-retention-holds.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0070-package-the-cloud-agent-environment-bootstrap.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0071-render-the-allowlisted-payload-per-destination.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0072-host-supervisors-own-daemon-restarts.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0073-name-what-fired-and-which-component.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0074-a-window-selects-findings-by-when-they-happened.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0076-two-phase-detection-pipeline.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0077-the-bom-job-wakes-once-at-startup-staggered.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0078-a-seeded-display-prefix-replaces-the-hostname-label.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0079-the-monitor-page-renders-findings-not-pipeline-health.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0080-enabling-reasoning-does-not-requeue-the-past.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0081-reasoning-activation-returns-to-explicit-opt-in.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0082-monitor-checks-every-installed-component-by-default.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0083-each-block-reason-is-its-own-rule.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0084-a-recursive-deletes-evidence-is-the-rm-that-ran.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0085-show-when-and-which-finding-slack-delivered.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0086-a-refusal-names-who-answered-the-call.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0087-deploy-compiled-policy-with-a-privileged-scheduled-job.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0088-slack-alerts-leave-out-confidence.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0089-infra-gate-reads-commands-not-shell-semantics.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0090-count-completed-commands-locate-by-ip-send-through-the-managed-proxy.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/0091-mark-our-own-machines-and-name-what-failed.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/HOOK-PROMPT.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/adrs/TEMPLATE.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/cutover-openaca-remote.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/plans/002-session-input.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/plans/003-correlation.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/plans/004-detector.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/plans/005-remote-sync.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/plans/006-cli-composition.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/plans/007-detection-upload.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/plans/008-monitor.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/plans/009-reasoning-jev.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/plans/010-session-daemon.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/plans/011-daemon-store.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/plans/012-daemon-scanning.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/plans/013-daemon-uploads.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/plans/014-asset-identity.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/plans/015-managed-policy-deployment.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/releases/v0.0.1.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/releases/v0.1.0.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/releases/v0.2.0.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/releases/v0.2.1.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/releases/v0.2.2.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/releases/v0.2.3.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/releases/v0.3.0.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/releases/v0.3.1.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/releases/v0.4.0.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/releases/v0.4.1.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/releases/v0.5.0.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/releases/v0.5.1.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/releases/v0.5.2.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/releases/v0.5.3.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/releases/v0.6.0.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/releases/v0.6.1.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/releases/v0.7.0.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/releases/v0.7.1.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/releases/v0.8.0.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/research/001-intent-drift-metric.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/specs/cli-composition.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/specs/correlation.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/specs/daemon-scanning.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/specs/daemon-store.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/specs/daemon-uploads.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/specs/detection-upload.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/specs/event-time.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/specs/managed-policy-deployment.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/specs/monitor-inventory.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/specs/notification-delivery.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/specs/reasoning-jev.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/docs/specs/remote-sync.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/scripts/git-hooks/pre-push +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/scripts/install-hooks.sh +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/__main__.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/build.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/cloud/__init__.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/cloud/setup.sh +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/correlate/__init__.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/correlate/acquire.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/correlate/composition.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/correlate/join.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/correlate/observed.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/correlate/orchestrate.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/correlate/project_map.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/correlate/record.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/correlate/render.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/daemon/__init__.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/daemon/activity_log.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/daemon/bom.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/daemon/client.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/daemon/composition.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/daemon/identity.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/daemon/lifecycle.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/daemon/paths.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/daemon/protocol.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/daemon/server.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/daemon/service.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/daemon/webhook.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/detector/__init__.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/detector/analyzer.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/detector/blocked.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/detector/cache.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/detector/deterministic.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/detector/history.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/detector/jev.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/detector/priors.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/detector/prompts/__init__.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/detector/prompts/jev-v1/stacktrace-deceptive-completion.json +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/detector/prompts/jev-v2/stacktrace-deceptive-completion.json +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/detector/prompts/jev-v2/stacktrace-infra-unsafe-action.json +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/detector/prompts/v1/exclusions.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/detector/prompts/v1/framing.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/detector/prompts/v1/stacktrace-deceptive-completion.md +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/detector/reasoning.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/detector/run.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/detector/secrets.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/detector/verdict.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/detector/windows.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/monitor/__init__.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/monitor/inventory.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/monitor/reasoning.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/monitor/site/apple-icon.png +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/monitor/site/favicon.ico +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/monitor/site/fonts/OFL.txt +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/monitor/site/fonts/dm-mono-400-latin.woff2 +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/monitor/site/fonts/dm-mono-500-latin.woff2 +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/monitor/site/fonts/dm-sans-latin.woff2 +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/monitor/site/icon.svg +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/monitor/verdicts.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/options.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/private_state.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/remote/__init__.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/remote/cli.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/remote/client.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/remote/config.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/remote/detect_payload.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/remote/identity.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/remote/payload.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/remote/policy.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/remote/policy_service.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/remote/policy_worker.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/remote/redact.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/remote/spool.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/remote/sync.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/remote/sync_detect.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/remote/upload_contract.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/sessions/__init__.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/sessions/access.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/sessions/index.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/sessions/outcome.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/sessions/render.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/telemetry/__init__.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/telemetry/cli.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/telemetry/events.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/telemetry/posthog.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/telemetry/state.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/webhook/__init__.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/webhook/cli.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/src/stacktrace_cli/webhook/config.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/__init__.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/agent_bom_fixture.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/conftest.py +0 -0
- {stacktrace_cli-0.8.0/tests/monitor → stacktrace_cli-0.9.0/tests/cost}/__init__.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/daemon/__init__.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/daemon/test_client.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/daemon/test_composition.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/daemon/test_config.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/daemon/test_detection_needs_no_subscriber.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/daemon/test_fleet.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/daemon/test_identity.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/daemon/test_jobs.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/daemon/test_lifecycle.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/daemon/test_observer.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/daemon/test_queue_reader.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/daemon/test_service.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/daemon/test_socket.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/daemon/test_store.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/daemon/test_the_drained_payload_is_the_cold_one.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/daemon/test_the_stored_row_is_sufficient.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/daemon/test_webhook.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/daemon/test_wire_frames_are_bounded.py +0 -0
- {stacktrace_cli-0.8.0/tests/remote → stacktrace_cli-0.9.0/tests/monitor}/__init__.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/monitor/inventory_harness.mjs +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/monitor/test_inventory.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/monitor/test_inventory_page.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/monitor/test_reasoning_gates.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/monitor/test_server.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/monitor/test_state.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/monitor/test_verdicts.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/monitor/test_watch.py +0 -0
- {stacktrace_cli-0.8.0/tests/telemetry → stacktrace_cli-0.9.0/tests/remote}/__init__.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/remote/helpers.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/remote/test_cli.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/remote/test_client.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/remote/test_config.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/remote/test_detect_activity.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/remote/test_detect_cli.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/remote/test_detect_client.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/remote/test_detect_contract_is_exhaustive.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/remote/test_detect_gate_matches_the_cloud.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/remote/test_detect_layers_compose.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/remote/test_detect_payload_reaches_the_cloud_model.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/remote/test_detect_redaction.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/remote/test_detect_spool.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/remote/test_detect_upload_contract.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/remote/test_detect_wire_payload.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/remote/test_identity.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/remote/test_no_local_path_survives_redaction.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/remote/test_payload.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/remote/test_policy.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/remote/test_policy_service.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/remote/test_policy_service_cli.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/remote/test_redact_payload.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/remote/test_seam.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/remote/test_spool.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/remote/test_sync.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/remote/test_sync_detect.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/remote/test_upload_contract.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/telemetry/test_activity_log.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/telemetry/test_cli.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/telemetry/test_events.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/telemetry/test_every_derived_site.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/telemetry/test_every_internal_save_is_reported.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/telemetry/test_hooks.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/telemetry/test_release_gate.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/telemetry/test_state.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/telemetry/test_uploader.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_acquire.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_adr_cross_references_are_reciprocal.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_agent_instance_id.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_analysis.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_bom_shape.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_build_commit.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_cli.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_composition.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_correlate_orchestrate.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_correlate_render.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_correlated_session.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_detection_components.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_detection_event_time.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_detection_subject.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_detector_analyzer_contract.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_detector_analyzer_live.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_detector_blocked.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_detector_cache.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_detector_deterministic.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_detector_finding.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_detector_history.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_detector_infra_reasoning.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_detector_jev.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_detector_names_the_service.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_detector_new_deterministic.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_detector_priors.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_detector_prompts.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_detector_reasoning.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_detector_render.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_detector_run.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_detector_secrets.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_detector_verdict.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_detector_vulnerable_dep_invoked.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_detector_why_it_stopped.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_detector_windows.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_evidence_is_dated_not_numbered.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_help_sections.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_join.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_monitor_cli.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_no_live_document_states_the_old_stage_three_default.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_no_test_undoes_every_patch_at_once.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_observed.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_openaca_contract.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_option_arity_matches_the_binary.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_project_map.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_readme_examples_are_real_output.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_release_gate_coverage.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_release_readiness.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_sessions_access.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_sessions_end_to_end.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_sessions_render.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_shell_separators_match_the_shell.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_stored_verdicts_are_never_gated_on_reasoning.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_the_jev_spec_states_the_shipped_thresholds.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_the_locality_claim_is_qualified_everywhere.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_untrusted_content_never_travels.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_verification_subcommands_match_the_binary.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/test_what_jev_is_told_is_what_was_disclosed.py +0 -0
- {stacktrace_cli-0.8.0 → stacktrace_cli-0.9.0}/tests/webhook/test_cli.py +0 -0
|
@@ -108,6 +108,10 @@ nothing about detection.
|
|
|
108
108
|
- **OpenACA carries nothing AIDR** (ADR-0006). No finding family, no output row
|
|
109
109
|
type, no scan flag, no rule namespace upstream. Detection rule identifiers are
|
|
110
110
|
`stacktrace-*`, never `openaca-*`, and the combined report is assembled here.
|
|
111
|
+
- **Cost is tokens, never dollars** (ADR-0099). Every cost figure, threshold,
|
|
112
|
+
severity, budget, label and doc line is in tokens or a ratio to the usual
|
|
113
|
+
("3× the usual", "40M tokens more"). No price table, no dollar amount, no
|
|
114
|
+
currency, here or in Fleet. The family is still called `cost`.
|
|
111
115
|
- **Session collection is not ours** (ADR-0002). It lives in `openaidr`, open
|
|
112
116
|
source. Its types stop at our adapter; parsing an agent format here would
|
|
113
117
|
duplicate the thing the split exists to prevent.
|
|
@@ -122,6 +126,12 @@ nothing about detection.
|
|
|
122
126
|
`test_bom_shape.py`, `test_fingerprint_covers_what_the_analyzer_reads.py`. When
|
|
123
127
|
a review names a site, fix the invariant and extend the exhaustive test — a
|
|
124
128
|
second finding of the same class means the first fix was at the wrong level.
|
|
129
|
+
Cost has its own: `tests/cost/test_cost_findings_carry_no_session_text.py`,
|
|
130
|
+
`tests/cost/test_cost_is_tokens.py`, `test_cost_findings_are_dated_by_their_citations.py`,
|
|
131
|
+
and the range and usual checks in
|
|
132
|
+
`tests/monitor/test_render_cost.py`. When reviews keep re-arguing scope (a
|
|
133
|
+
time boundary, which sessions a rule reads), write the answer into the spec,
|
|
134
|
+
as `docs/specs/cost-phase-1.md` §1 "What a rule reads, and when" does.
|
|
125
135
|
|
|
126
136
|
## Adding a command
|
|
127
137
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: stacktrace-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.9.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>
|
|
@@ -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.9.0 (openaca 0.8.0)
|
|
55
55
|
```
|
|
56
56
|
|
|
57
57
|
## Quick start
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: 0092
|
|
3
|
+
title: Cost is its own rule family
|
|
4
|
+
status: proposed
|
|
5
|
+
date: 2026-10-05
|
|
6
|
+
supersedes: null
|
|
7
|
+
superseded-by: null
|
|
8
|
+
amends: null
|
|
9
|
+
amended-by: null
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Context
|
|
13
|
+
|
|
14
|
+
Cost Phase 1 adds cost rules (`docs/specs/cost-phase-1.md`). The catalogue has
|
|
15
|
+
two families, security and reliability, and Fleet's `detection_rules` check
|
|
16
|
+
constraint allows only those two (migration 0016). ADR-0013 created reliability
|
|
17
|
+
because stuck sessions needed their own heading and handling. Cost now needs the
|
|
18
|
+
same, as one of the product's main use cases.
|
|
19
|
+
|
|
20
|
+
## Decision
|
|
21
|
+
|
|
22
|
+
Cost rules form a third family, **`cost`**, named `stacktrace-cost-*`, with a
|
|
23
|
+
`COST_RULES` set in the catalogue. `rules.family_of` derives it, never stored on
|
|
24
|
+
a finding (ADR-0013). `stacktrace-blocked-quota` stays reliability, because the
|
|
25
|
+
agent got stuck, and cost findings may cite it as evidence.
|
|
26
|
+
|
|
27
|
+
## Alternatives considered
|
|
28
|
+
|
|
29
|
+
- **Reliability, separated by name prefix.** This was the first proposal. It is
|
|
30
|
+
rejected for three reasons:
|
|
31
|
+
- Fleet users count, filter and route by family, and a prefix is invisible to
|
|
32
|
+
them.
|
|
33
|
+
- Cost goes to the people who own the budget, not to whoever runs the agent.
|
|
34
|
+
- Reliability asks whether the session worked; a runaway can work perfectly
|
|
35
|
+
and still use far more tokens than it needs.
|
|
36
|
+
- **Security.** Rejected: costly behaviour is not an attack.
|
|
37
|
+
|
|
38
|
+
## Consequences
|
|
39
|
+
|
|
40
|
+
- One Fleet migration adds `cost` to the family check constraint, done in Phase
|
|
41
|
+
1 before any cost finding exists, so no stored data moves.
|
|
42
|
+
- The CLI catalogue, the monitor's `by_family` summary, the Fleet console and
|
|
43
|
+
Slack each gain a third family.
|
|
44
|
+
- Phase 2 can route notifications per family.
|
|
45
|
+
|
|
46
|
+
## When to revisit
|
|
47
|
+
|
|
48
|
+
If a cost rule turns out to be mainly about a session failing rather than
|
|
49
|
+
using too many tokens, move that rule to reliability.
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: 0093
|
|
3
|
+
title: Environment cost baselines count tokens and are keyed by model
|
|
4
|
+
status: proposed
|
|
5
|
+
date: 2026-10-05
|
|
6
|
+
supersedes: null
|
|
7
|
+
superseded-by: null
|
|
8
|
+
amends: null
|
|
9
|
+
amended-by: 0099
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Context
|
|
13
|
+
|
|
14
|
+
`stacktrace-cost-runaway-session` must catch a session running away, while it
|
|
15
|
+
runs, against this developer's normal. Three things move "normal" without
|
|
16
|
+
anything going wrong: a price change, a new default model, and idle time.
|
|
17
|
+
|
|
18
|
+
## Decision
|
|
19
|
+
|
|
20
|
+
- The daemon keeps p50, p95 and p99 of **cumulative tokens by active minute**,
|
|
21
|
+
and of 5-minute burn, from this environment's finished sessions over 30 days.
|
|
22
|
+
- It also keeps a **day curve**: cumulative tokens by local time of day per
|
|
23
|
+
working day, per model. That curve gives the personal-anomaly rule "your usual
|
|
24
|
+
by now", and needs 10 working days of history.
|
|
25
|
+
The rule's score is log(today ÷ usual) divided by the spread: 1.48 × the
|
|
26
|
+
median absolute deviation of that log, at least 0.25. The spec's "beyond the
|
|
27
|
+
normal range" is a score of 3 or more; "far beyond" is 6 or more.
|
|
28
|
+
- It also keeps **behaviour curves** per run: sub-agents started in 10 minutes,
|
|
29
|
+
repeats with an unchanged result, input per response, cache reads and cache
|
|
30
|
+
writes, as p5 and p99, and fresh input at p95. A waste rule fires only when
|
|
31
|
+
the behaviour and the cost are both unusual for this developer, so no waste
|
|
32
|
+
rule rests on a fixed limit alone.
|
|
33
|
+
- The summaries are keyed by cohort, `(repo, entrypoint, model)`, falling back
|
|
34
|
+
to `(entrypoint, model)`, then `(model)`. Each level needs at least 20
|
|
35
|
+
sessions; with none, the rule is silent.
|
|
36
|
+
- **Tokens, not dollars**, throughout: floors and severity too (ADR-0099).
|
|
37
|
+
- **Recorded tokens on both sides.** Baselines and rules count only what the
|
|
38
|
+
transcripts record.
|
|
39
|
+
- The client's own totals are not read at all (ADR-0099): they arrive after
|
|
40
|
+
the work, with no time of their own, and add about half a percent.
|
|
41
|
+
- A comparison then undercounts alike on both sides.
|
|
42
|
+
- On a run with many sub-agents, whose output is often a lower bound, a rule
|
|
43
|
+
fires later, never falsely sooner.
|
|
44
|
+
- The baseline is backfilled from transcripts at start, excludes sessions with
|
|
45
|
+
an open cost finding, and is written only by the daemon (ADR-0046).
|
|
46
|
+
- Rules get a frozen snapshot as an input.
|
|
47
|
+
- **The table holds one numeric summary per finished session**, not the
|
|
48
|
+
percentiles: the summary's curves and behaviour measures, its cohort, run,
|
|
49
|
+
day and login type. The snapshot computes the percentiles from these rows,
|
|
50
|
+
which is what lets it drop a flagged run or a row older than 30 days.
|
|
51
|
+
- Numbers only, never content, so it is an exception to ADR-0006 constraint 1
|
|
52
|
+
on the same terms as the verdict cache (ADR-0011). It is not the sessions
|
|
53
|
+
table ADR-0046 rejected, which would have held session models.
|
|
54
|
+
- It is additive, so `SCHEMA_VERSION` does not move (ADR-0057).
|
|
55
|
+
- The monitor reads the same snapshot, read-only, for "your usual" (ADR-0097).
|
|
56
|
+
|
|
57
|
+
## Alternatives considered
|
|
58
|
+
|
|
59
|
+
- **Dollar baselines.** Rejected: a price change would fire everywhere.
|
|
60
|
+
- **One baseline across models.** Rejected: a model launch would fire everywhere.
|
|
61
|
+
- **Thresholds on finished-session totals.** Rejected: they fire after the
|
|
62
|
+
tokens are used.
|
|
63
|
+
- **Recompute from transcripts every scan.** Rejected: it repeats the cold pass
|
|
64
|
+
ADR-0011 and ADR-0037 avoid.
|
|
65
|
+
- **Rules querying the store directly.** Rejected: it breaks the single writer,
|
|
66
|
+
and output would depend on when it was read.
|
|
67
|
+
|
|
68
|
+
## Consequences
|
|
69
|
+
|
|
70
|
+
- Price changes and model launches can't trigger the rule on their own.
|
|
71
|
+
- It costs a new store table and a backfill.
|
|
72
|
+
- A developer with too few sessions gets no runaway findings until Phase 2
|
|
73
|
+
sends peer numbers.
|
|
74
|
+
|
|
75
|
+
## When to revisit
|
|
76
|
+
|
|
77
|
+
If the cohorts prove too thin in measurement, or Phase 2's fleet-wide numbers
|
|
78
|
+
make the narrow levels unnecessary.
|
stacktrace_cli-0.9.0/docs/adrs/0094-estimate-cost-from-tokens-the-agent-figure-is-a-cross-check.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: 0094
|
|
3
|
+
title: Cost is tokens × price at the time of use; the agent's own figure is a cross-check
|
|
4
|
+
status: superseded
|
|
5
|
+
date: 2026-10-05
|
|
6
|
+
supersedes: null
|
|
7
|
+
superseded-by: 0099
|
|
8
|
+
amends: null
|
|
9
|
+
amended-by: null
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Context
|
|
13
|
+
|
|
14
|
+
Phase 1 shows dollars and uses them as floors. Claude Code already
|
|
15
|
+
writes a running `totalCostUSD` in `cost-state` records, in 109 of 181 measured
|
|
16
|
+
sessions. Using it is the obvious shortcut.
|
|
17
|
+
|
|
18
|
+
## Decision
|
|
19
|
+
|
|
20
|
+
- The CLI prices each response's token buckets from a **versioned,
|
|
21
|
+
effective-dated price table**, at the price **in effect when the response
|
|
22
|
+
happened**.
|
|
23
|
+
- A model with no price is **unpriced**: shown in tokens, never priced at zero.
|
|
24
|
+
- Every dollar says which rate produced it: at list price, or at the org's own
|
|
25
|
+
rates once entered (Phase 2). The arithmetic is exact for what it prices —
|
|
26
|
+
tokens by model, type and date — but that excludes two billing dimensions
|
|
27
|
+
the agent's own figure does include: the 10% multiplier Anthropic applies to
|
|
28
|
+
a response on US data residency, and per-request fees such as web search,
|
|
29
|
+
which aren't token charges at all ([cost.md §4.3](../specs/cost.md#43-what-cost-is)).
|
|
30
|
+
- Claude Code's own figure is compared per session as a **cross-check only**.
|
|
31
|
+
- Tokens the transcripts miss, such as some sub-agent work, are taken from
|
|
32
|
+
Claude Code's per-model token totals and priced the same way, as one
|
|
33
|
+
"unrecorded" line — reconciled once per **run**, against the run's own
|
|
34
|
+
latest cumulative figure, never once per session: a resumed session's figure
|
|
35
|
+
already includes its earlier spend, and a parent's already includes its
|
|
36
|
+
sub-agents', so summing each session's own remainder would double-count
|
|
37
|
+
both. Its dollars are never used.
|
|
38
|
+
|
|
39
|
+
## Alternatives considered
|
|
40
|
+
|
|
41
|
+
- **Use Claude Code's `cost-state` as the cost.** Rejected, for four reasons:
|
|
42
|
+
- it is a per-session running total, so it can't price a window, a run or a
|
|
43
|
+
response;
|
|
44
|
+
- it is missing in 72 of 181 sessions;
|
|
45
|
+
- it is Claude Code's alone, and Codex records none;
|
|
46
|
+
- it can't take org rates or be re-priced.
|
|
47
|
+
- **Price in OpenAIDR.** Rejected by OpenAIDR ADR-0015: a price is
|
|
48
|
+
interpretation.
|
|
49
|
+
- **The provider's usage API.** Not available in the environment: it needs an
|
|
50
|
+
admin key, lags, and has no per-session detail. It is Phase 2's reconciliation
|
|
51
|
+
source.
|
|
52
|
+
|
|
53
|
+
## Consequences
|
|
54
|
+
|
|
55
|
+
- One method prices every agent, window and run.
|
|
56
|
+
- The price table must be maintained, and every price change noted in a release.
|
|
57
|
+
- A persistent gap against the cross-check, beyond the data-residency and
|
|
58
|
+
per-request gaps above, points to a missing price or a counting error.
|
|
59
|
+
|
|
60
|
+
## When to revisit
|
|
61
|
+
|
|
62
|
+
If a provider records per-response cost in the transcript: carry it as recorded,
|
|
63
|
+
and make the estimate the cross-check.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: 0095
|
|
3
|
+
title: Every cost finding shows in Fleet; each cost rule's Slack notifications can be switched off
|
|
4
|
+
status: proposed
|
|
5
|
+
date: 2026-10-05
|
|
6
|
+
supersedes: null
|
|
7
|
+
superseded-by: null
|
|
8
|
+
amends: null
|
|
9
|
+
amended-by: null
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Context
|
|
13
|
+
|
|
14
|
+
Fleet posts every newly stored finding to Slack (`detections.py`, first
|
|
15
|
+
insert), with no filter by rule or severity. Phase 1 accepts that: its few
|
|
16
|
+
environment rules are checked on recorded sessions before they ship. Phase 2
|
|
17
|
+
adds Fleet's own rules, which compare people with the org and cannot be fully
|
|
18
|
+
tested before real org data exists. A rule that turns out noisy would keep
|
|
19
|
+
paging Fleet users until the next release.
|
|
20
|
+
|
|
21
|
+
## Decision
|
|
22
|
+
|
|
23
|
+
- Cost findings drain to Fleet over the existing upload, with **no wire change**,
|
|
24
|
+
and show in its console per environment and run from day one.
|
|
25
|
+
- In Phase 1, Fleet posts every cost finding to Slack, like any other finding.
|
|
26
|
+
- From Phase 2, Fleet's catalogue gives each cost rule a **`notify` switch**,
|
|
27
|
+
on by default, and the Slack outbox skips rules with it off.
|
|
28
|
+
- The Stacktrace team turns a rule's `notify` off when it proves noisy, and back
|
|
29
|
+
on once it is fixed. Its findings still show in Fleet.
|
|
30
|
+
- Reviewing findings as right or wrong is available to the team but optional,
|
|
31
|
+
and never a gate before a rule notifies.
|
|
32
|
+
- Developers get every cost finding locally either way.
|
|
33
|
+
|
|
34
|
+
## Alternatives considered
|
|
35
|
+
|
|
36
|
+
- **Keep findings local until Phase 2.** Rejected: Phase 1 would not be end to
|
|
37
|
+
end, and Fleet would have no evidence to evaluate.
|
|
38
|
+
- **Hold every new rule off until its findings are reviewed.** Rejected: manual
|
|
39
|
+
review does not scale, and every new rule would wait on reviewers.
|
|
40
|
+
- **No switch.** Rejected: a noisy rule would page until a release removed it,
|
|
41
|
+
and teach Fleet users to skip cost alerts.
|
|
42
|
+
- **Send them as low severity.** Rejected: severity says how bad a finding is,
|
|
43
|
+
not whether a rule is trustworthy, and Slack V1 has no severity filter.
|
|
44
|
+
|
|
45
|
+
## Consequences
|
|
46
|
+
|
|
47
|
+
- A small Fleet change: a per-rule setting and one outbox condition.
|
|
48
|
+
- Other rules keep today's behaviour, with `notify` on.
|
|
49
|
+
|
|
50
|
+
## When to revisit
|
|
51
|
+
|
|
52
|
+
When Fleet's Slack delivery gains severity or routing filters, which would make
|
|
53
|
+
this flag redundant.
|
stacktrace_cli-0.9.0/docs/adrs/0096-cost-usage-may-leave-as-token-totals-and-work-identifiers.md
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: 0096
|
|
3
|
+
title: Cost usage may leave as token totals and work identifiers
|
|
4
|
+
status: accepted
|
|
5
|
+
date: 2026-10-06
|
|
6
|
+
supersedes: null
|
|
7
|
+
superseded-by: null
|
|
8
|
+
amends: 0006
|
|
9
|
+
amended-by: null
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Context
|
|
13
|
+
|
|
14
|
+
Cost Phase 2 (`docs/specs/cost-phase-2.md`) needs Fleet to judge an environment
|
|
15
|
+
owner's spend against their own past and against the org. Phase 1 already sends
|
|
16
|
+
findings and nothing else (ADR-0061, ADR-0095), and Fleet still has no usage.
|
|
17
|
+
The phase 2 upload, a new endpoint beside `detect-runs`, would send token totals
|
|
18
|
+
per run, session, model and minute, and per run the repo, branch, title and the
|
|
19
|
+
Anthropic account the agent is signed into.
|
|
20
|
+
|
|
21
|
+
That document is not a finding. [ADR-0006](0006-trust-boundary-and-detection-upload.md)
|
|
22
|
+
constraint 1 says detection findings are the one thing that may travel — amended
|
|
23
|
+
only by ADR-0039, for a different channel — and constraint 2 says the uploaded
|
|
24
|
+
document carries no user. The account is sent because, on a shared dev box or CI
|
|
25
|
+
runner, it names the person and the Fleet enrollment key does not. None of
|
|
26
|
+
ADR-0092 through ADR-0095 amends constraint 1 or 2, so an implementer who followed
|
|
27
|
+
the spec alone would cross the boundary those constraints still state.
|
|
28
|
+
|
|
29
|
+
## Decision
|
|
30
|
+
|
|
31
|
+
This amends ADR-0006 constraints 1 and 2 for one document: the cost usage upload,
|
|
32
|
+
and the cost findings Fleet draws from it. The rest of ADR-0006 stays in force,
|
|
33
|
+
including for every other finding family and for ADR-0039's telemetry.
|
|
34
|
+
|
|
35
|
+
1. **Token totals may travel. The session may not.** Counts per run, session,
|
|
36
|
+
model, minute and token type (input, output, cache read, cache write — the
|
|
37
|
+
rates differ by type), plus a local reduction of the last 30 days to those
|
|
38
|
+
same counts. The session id is the key already allowed on a finding's session
|
|
39
|
+
reference, not the session. Transcripts, correlation records and session
|
|
40
|
+
models stay on the machine. There is still no upload path for them.
|
|
41
|
+
2. **A closed set of work identifiers, and the provider account.** Per run: repo
|
|
42
|
+
name, branch name, title, and the Anthropic account the agent is signed into.
|
|
43
|
+
Per component: the tokens its definitions add to every call, whether it was
|
|
44
|
+
used, and how many calls carried it per model. Repo, branch and title are
|
|
45
|
+
names of the work, not a path, a working directory or a machine name. The
|
|
46
|
+
account may appear on a cost finding because that finding is about who spent;
|
|
47
|
+
it is how a shared environment names the person. No other finding family
|
|
48
|
+
gains a user.
|
|
49
|
+
3. **Nothing else.** Prompts, tool arguments, tool results and paths do not
|
|
50
|
+
travel. A title that reproduces the prompt is a prompt and does not travel.
|
|
51
|
+
Absolute paths and secret-shaped strings are still refused (ADR-0006
|
|
52
|
+
constraint 4). ADR-0039 is unchanged: its events still exclude repository
|
|
53
|
+
names.
|
|
54
|
+
|
|
55
|
+
The findings drain stays findings-only (ADR-0061). This is a separate endpoint.
|
|
56
|
+
|
|
57
|
+
## Alternatives considered
|
|
58
|
+
|
|
59
|
+
- **Cut the upload back to what ADR-0006 already allows.** Rejected. Findings
|
|
60
|
+
carry no usage, so Fleet cannot price an owner's past, separate a shared rise
|
|
61
|
+
from one person's, or say which work cost the money. That is the gap Phase 2
|
|
62
|
+
exists to close; Phase 1 already sends findings alone.
|
|
63
|
+
- **Upload the transcripts and price them in Fleet.** Rejected. ADR-0006 already
|
|
64
|
+
rejected central analysis of session content. The 30-day backfill is computed
|
|
65
|
+
locally and only the aggregates leave.
|
|
66
|
+
- **Put the rows on the findings drain.** Rejected. ADR-0061 keeps that drain
|
|
67
|
+
findings-only so the detection document does not grow a second shape.
|
|
68
|
+
- **Drop repo, branch, title and the account, and send token totals under the
|
|
69
|
+
Fleet key alone.** Rejected. A shared box enrolls as one Fleet member, so the
|
|
70
|
+
key is not the person who signed the agent in, and a finding that cannot name
|
|
71
|
+
the work cannot be acted on.
|
|
72
|
+
|
|
73
|
+
## Consequences
|
|
74
|
+
|
|
75
|
+
- The cost spec may name these fields because this decision does. A field that
|
|
76
|
+
is not in the list above is still a breach.
|
|
77
|
+
- Cost findings and their Slack text may repeat the account, the repo, the
|
|
78
|
+
branch and the title. Other families may not.
|
|
79
|
+
- A title is the easiest way for conversation to leak through a field this
|
|
80
|
+
decision allows. Watch for one that is the prompt.
|
|
81
|
+
|
|
82
|
+
## When to revisit
|
|
83
|
+
|
|
84
|
+
If Phase 2 ships without this upload, supersede this amendment. If the account
|
|
85
|
+
or the title is found to carry a credential or conversation in practice, narrow
|
|
86
|
+
clause 2 rather than widening what else may travel.
|
stacktrace_cli-0.9.0/docs/adrs/0097-the-daemon-makes-cost-findings-and-the-monitor-reads-them.md
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: 0097
|
|
3
|
+
title: The daemon makes cost findings once, and the monitor reads them from the store
|
|
4
|
+
status: proposed
|
|
5
|
+
date: 2026-10-06
|
|
6
|
+
supersedes: null
|
|
7
|
+
superseded-by: null
|
|
8
|
+
amends: 0026
|
|
9
|
+
amended-by: null
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Context
|
|
13
|
+
|
|
14
|
+
ADR-0026 clause 2 says the console does no analysis of its own: it calls
|
|
15
|
+
`collect_sessions`, `acquire_correlated_view` and `run_detector`, and "a
|
|
16
|
+
finding on the page is a finding `detect` would print".
|
|
17
|
+
|
|
18
|
+
Cost findings don't fit that shape.
|
|
19
|
+
|
|
20
|
+
- `budget-breach` and `personal-anomaly` judge today's usage across the
|
|
21
|
+
whole environment, whatever range the page shows.
|
|
22
|
+
- Every rule but budget breach judges against the 30-day baseline the daemon
|
|
23
|
+
keeps (ADR-0093).
|
|
24
|
+
- The waste rules judge a run, whose sub-agents the daemon collects.
|
|
25
|
+
|
|
26
|
+
The monitor sees only the sessions in its range. `detect` sees only its
|
|
27
|
+
window.
|
|
28
|
+
|
|
29
|
+
## Decision
|
|
30
|
+
|
|
31
|
+
- **The daemon is the only host that turns cost rules into findings.** It
|
|
32
|
+
stores them like any other finding, and they reach the session, the webhook
|
|
33
|
+
and Fleet from there.
|
|
34
|
+
- **The monitor reads cost findings from the store, read-only,** and shows
|
|
35
|
+
them in `alerts` in `detection_json`'s shape. The baseline snapshot behind
|
|
36
|
+
"your usual" is read the same way.
|
|
37
|
+
- **`detect` runs no cost rules in Phase 1.** `stacktrace findings` prints the
|
|
38
|
+
stored ones.
|
|
39
|
+
- The cost numbers themselves (tokens and runs) are pure functions of the
|
|
40
|
+
sessions, and every surface computes them the same way.
|
|
41
|
+
- This amends ADR-0026 clause 2 for the cost family only: **a cost finding on
|
|
42
|
+
the page is one the daemon stored.** For security and reliability the
|
|
43
|
+
clause stands.
|
|
44
|
+
|
|
45
|
+
## Alternatives considered
|
|
46
|
+
|
|
47
|
+
- **Every surface runs the cost rules.** Rejected:
|
|
48
|
+
- A page showing five minutes would judge "today" from five minutes of
|
|
49
|
+
sessions.
|
|
50
|
+
- Three hosts would give three answers, and the one Slack received is the
|
|
51
|
+
daemon's.
|
|
52
|
+
- **The monitor computes its own baseline.** Rejected: it repeats a 30-day
|
|
53
|
+
cold pass per monitor start (ADR-0011, ADR-0037), and still differs from
|
|
54
|
+
what Fleet was sent.
|
|
55
|
+
|
|
56
|
+
## Consequences
|
|
57
|
+
|
|
58
|
+
- Without a running daemon, the Cost tab shows numbers but no cost findings,
|
|
59
|
+
and says why.
|
|
60
|
+
- The monitor gains a second input, the store, opened read-only (ADR-0046).
|
|
61
|
+
The store's newest `seq` joins the watcher's fingerprint, so a new finding
|
|
62
|
+
shows without waiting for a transcript to change.
|
|
63
|
+
- `detect` users in CI see cost numbers nowhere until a later phase decides
|
|
64
|
+
otherwise.
|
|
65
|
+
|
|
66
|
+
## When to revisit
|
|
67
|
+
|
|
68
|
+
If `detect` gains a reason to report cost findings, such as CI budget checks,
|
|
69
|
+
or the monitor gains a cheaper way to hold a baseline of its own.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: 0098
|
|
3
|
+
title: A run is its main session, and a finding about a run is filed under it
|
|
4
|
+
status: proposed
|
|
5
|
+
date: 2026-10-06
|
|
6
|
+
supersedes: null
|
|
7
|
+
superseded-by: null
|
|
8
|
+
amends: null
|
|
9
|
+
amended-by: null
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Context
|
|
13
|
+
|
|
14
|
+
Cost judges a piece of work: a main session together with its sub-agents and
|
|
15
|
+
workflow agents (cost-phase-1, "Measure"). Fleet must show cost findings "per
|
|
16
|
+
environment and run" with no wire change (ADR-0095). But neither side's
|
|
17
|
+
detection document has a run field, and Fleet reads a span's session from the
|
|
18
|
+
span itself, so a finding can cite only its own session's spans.
|
|
19
|
+
|
|
20
|
+
## Decision
|
|
21
|
+
|
|
22
|
+
- **A run's id is its main session's id.** The parent of a sub-agent is read
|
|
23
|
+
from OpenAIDR's identity, `<kind>:<parent>:<file stem>` (OpenAIDR ADR-0001),
|
|
24
|
+
in one place: `sessions/lineage.py`.
|
|
25
|
+
- **A run is keyed by the pair `(agent_kind, run id)`**, like every session.
|
|
26
|
+
- **A finding about a run is filed under its main session.** Fleet then shows
|
|
27
|
+
it under that session, which is the run, with no new field.
|
|
28
|
+
- The run's other sessions are counted in an evidence line, not listed.
|
|
29
|
+
- A sub-agent's own spans are never cited, because Fleet would refuse them.
|
|
30
|
+
Evidence cites the main session's turns.
|
|
31
|
+
|
|
32
|
+
## Alternatives considered
|
|
33
|
+
|
|
34
|
+
- **A `run_id` field on the detection wire.** Rejected for Phase 1 by ADR-0095.
|
|
35
|
+
Phase 2's usage upload is where run identity, and the list of a run's
|
|
36
|
+
sessions, reach Fleet.
|
|
37
|
+
- **File each finding under the sub-agent where the waste happened.** Rejected:
|
|
38
|
+
a fan-out of small sub-agents is the waste, and each looks normal alone.
|
|
39
|
+
- **Group resumes into a run by transcript file.** Not needed: no transcript
|
|
40
|
+
on the measuring machine held more than one session id. A resume that keeps
|
|
41
|
+
its id is already inside its session.
|
|
42
|
+
|
|
43
|
+
## Consequences
|
|
44
|
+
|
|
45
|
+
- Fleet shows a run as its main session, plus a count of its sessions and
|
|
46
|
+
sub-agents.
|
|
47
|
+
- A sub-agent never gets a cost finding of its own.
|
|
48
|
+
- If a client writes a resume as a new session, it is a run of its own.
|
|
49
|
+
|
|
50
|
+
## When to revisit
|
|
51
|
+
|
|
52
|
+
When Phase 2's usage upload carries run identity, or a client is found writing
|
|
53
|
+
resumes as new sessions.
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: 0099
|
|
3
|
+
title: Cost is measured in tokens and relative increases, never in dollars
|
|
4
|
+
status: proposed
|
|
5
|
+
date: 2026-10-06
|
|
6
|
+
supersedes: 0094
|
|
7
|
+
superseded-by: null
|
|
8
|
+
amends: 0093
|
|
9
|
+
amended-by: null
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Context
|
|
13
|
+
|
|
14
|
+
ADR-0094 priced every response at list price and stated cost, floors, budgets
|
|
15
|
+
and severity in dollars. That needs a price table kept current for every model,
|
|
16
|
+
and a dollar figure invites a comparison with an invoice it never matches:
|
|
17
|
+
subscriptions, discounts and committed spend all differ from list price. On a
|
|
18
|
+
subscription, a "spend" figure is not money anyone pays.
|
|
19
|
+
|
|
20
|
+
Tokens are what the agent actually uses, and what cost follows. Measured on one
|
|
21
|
+
environment's 30 days (193 sessions, 3.1B tokens), 98.1% of all tokens were
|
|
22
|
+
cache reads, and what a token cost varied 3.6-fold from hour to hour (p10 to
|
|
23
|
+
p90) as the mix of token kinds moved. A raw count across people or models
|
|
24
|
+
tracks cost loosely. A count relative to the same developer's similar runs
|
|
25
|
+
(ADR-0093's cohorts) tracks it closely, because the mix of token kinds is
|
|
26
|
+
similar.
|
|
27
|
+
|
|
28
|
+
## Decision
|
|
29
|
+
|
|
30
|
+
**Every cost figure is tokens, or a relative increase.** That covers evidence,
|
|
31
|
+
thresholds, severity, budgets, the monitor, notifications, Fleet, specs and
|
|
32
|
+
release notes. Nothing carries a price, a dollar amount or a currency, and
|
|
33
|
+
there is no price table.
|
|
34
|
+
|
|
35
|
+
- **Relative to the usual.** A finding says how far above this developer's
|
|
36
|
+
usual it is ("3× the usual"), and how many tokens that is ("40M more").
|
|
37
|
+
- **The tokens a rule is about.** A rule counts the kind of token its
|
|
38
|
+
behaviour wastes. `cache-collapse` counts uncached input, fresh input and
|
|
39
|
+
cache writes, for both its triggers: a cache that stops being reused re-sends
|
|
40
|
+
the same tokens uncached, and one re-written again and again writes them
|
|
41
|
+
afresh, while the total barely moves. The other rules count all recorded
|
|
42
|
+
tokens.
|
|
43
|
+
- **Thresholds are token amounts or ratios.** Materiality floors and budget
|
|
44
|
+
limits are token amounts; severity is how many times the usual a finding is
|
|
45
|
+
(low under 3×, medium from 3×, high from 10×). The defaults are starting
|
|
46
|
+
points in tokens, to be tuned against recorded sessions. No exchange rate between
|
|
47
|
+
tokens and money is recorded or used anywhere.
|
|
48
|
+
- **The family is still `cost`.** Cost is what the rules protect; tokens are
|
|
49
|
+
how it is measured. Rule ids stay `stacktrace-cost-*`.
|
|
50
|
+
- **Claude Code's own running totals** (`cost-state`) are not read at all,
|
|
51
|
+
neither their dollars nor their tokens. Measured on 111 sessions, their
|
|
52
|
+
tokens add 0.54% to what the transcripts record, and they carry no time and
|
|
53
|
+
arrive only after the work. Every figure comes from the transcripts' own
|
|
54
|
+
per-response counts.
|
|
55
|
+
|
|
56
|
+
## Alternatives considered
|
|
57
|
+
|
|
58
|
+
- **Tokens × list price (ADR-0094).** Rejected: a table to maintain, a figure
|
|
59
|
+
that differs from every invoice, and a "spend" that subscription users never
|
|
60
|
+
pay.
|
|
61
|
+
- **Dollars at the org's own rates (Phase 2).** Rejected for the same reasons,
|
|
62
|
+
and because no org has entered rates.
|
|
63
|
+
- **Total tokens for every rule.** Rejected: cache reads dominate, so a cache
|
|
64
|
+
that stops being reused is invisible in the total.
|
|
65
|
+
- **Tokens weighted by kind**, such as a cache read counting a tenth. Rejected:
|
|
66
|
+
that is a price table by another name.
|
|
67
|
+
|
|
68
|
+
## Consequences
|
|
69
|
+
|
|
70
|
+
- A new model works on day one: there is nothing to price and no "unpriced"
|
|
71
|
+
response.
|
|
72
|
+
- Token counts are large and less intuitive than dollars, so every figure is
|
|
73
|
+
paired with a ratio to the usual.
|
|
74
|
+
- A budget limit is a guard against runaway volume, not a spend cap: the same
|
|
75
|
+
token limit is different money on different models and plans.
|
|
76
|
+
- There is no check against the client's own figures, in dollars or tokens.
|
|
77
|
+
The transcripts miss about half a percent of tokens, mostly side calls on a
|
|
78
|
+
small model and unfinished sub-agent output; rules and baselines count the
|
|
79
|
+
same recorded tokens on both sides, so a comparison stays fair.
|
|
80
|
+
|
|
81
|
+
## When to revisit
|
|
82
|
+
|
|
83
|
+
If customers ask for spend in their own currency, at their own rates, and
|
|
84
|
+
supply those rates, a Phase 2 view could price tokens for display only. Rules,
|
|
85
|
+
thresholds and evidence would stay in tokens.
|