Skip to content

v0.11.0: dashboard polish, cost accuracy, attribution tags#12

Merged
codehippie1 merged 47 commits into
mainfrom
release/v0.11.0
Jun 18, 2026
Merged

v0.11.0: dashboard polish, cost accuracy, attribution tags#12
codehippie1 merged 47 commits into
mainfrom
release/v0.11.0

Conversation

@codehippie1

Copy link
Copy Markdown
Contributor

What

A dashboard-polish release, built entirely on data Burnwall already captures on
the wire — no new collection, still zero telemetry.

Surfaces

  • Delta-vs-previous chips on the stat cards: burnwall status compares to
    yesterday, burnwall history to the prior window, coloured by whether the
    move is good or bad.
  • Share-of-spend bars in the cost-by-model tables.
  • Daily-spend sparkline in burnwall history; a 7-day spend trend on
    burnwall status.
  • VS Code panel: a baked, script-free SVG spend chart, delta chips, and share
    bars — keeps the panel's locked-down (no-scripts) webview and adapts to the
    editor theme.
  • New term.rs primitives (sparkline, delta chips) with width-stable
    rendering so colour/glyphs never shear the card borders.

Cost

  • burnwall accuracy — contrast real on-wire, cache-aware cost with a naive
    token-tally estimate (every prompt token at the base input rate), per model.
  • burnwall tags — attribute spend by opt-in x-burnwall-tags labels
    (feature / agent-run / client / …). New nullable requests.tags column
    (additive migration); tolerant header parsing — a malformed tag is skipped,
    metadata only, never prompt content.

Security

  • MCP tool fingerprints upgraded to SHA-256 (collision-resistant), migrated in
    place so an already-approved tool is not re-pinned-as-changed by the format
    upgrade alone — only a genuine change to the tool resets approval.

Tests

  • Unit + integration coverage for every new surface: term primitives,
    status/history rendering, the accuracy estimator, the tags rollup, header
    ingestion bounds, the fingerprint migration, and the panel HTML.
  • Full suite green (lib 328, cli_test 52, all suites); clippy clean; lean
    --no-default-features build verified.

Targets release/v0.10.0.

- burnwall cost-per-pr: approximate cost of the current git branch/PR by
  attributing local session-log spend to the branch's active window (oldest
  commit on base..HEAD, else a fallback). Git metadata + logs only; never reads
  prompts. New src/observe/attribution.rs (pure attribute() + git_context), unit-tested.
- MCP permission auto-policy: [mcp].auto_approve / auto_deny globs matched on
  <server>/<tool>; auto-deny always blocks, auto-approve skips the approval gate
  in enforce mode. Glob matcher unit-tested.
- VS Code inline panel: status-bar click opens a webview (cost-by-model, security
  blocks, MCP tools) from local CLI JSON. Pure panel_view.ts unit-tested.
- Soft budget alert line in burnwall status once spend crosses warn_percent.
…s, MCP manifest, Scorecard CI

- docs/INTEGRATIONS.md: 'use Burnwall with anything' — base-URL recipes for
  coding tools, agent SDKs, and any OpenAI/Anthropic-compatible gateway.
- External audit verification: docs/COMPLIANCE.md (receipt -> ISO 42001 / EU AI
  Act / SOC 2 mapping, as evidence not certification) + tools/verify_receipts.py,
  a standalone Ed25519 chain-verifier over the audit export bundle (no Burnwall
  needed). Verified end-to-end: OK on a real export, TAMPERED on a flipped hash.
- packaging/mcp/server.json + docs/MCP_REGISTRY.md: MCP registry manifest/listing.
- .github/workflows/scorecard.yml: OpenSSF Scorecard supply-chain trust signal.
- README: '100% local, zero telemetry' headline + 'works with' pointer.
- Bump to 0.9.2; CHANGELOG entries for [0.9.1] and [0.9.2].
… hardening

- Migrate to the Rust 2024 edition; declare an MSRV; move lint policy into Cargo.toml.
- Add optional build features (audit/mcp/observe/logscrape/waste), all default-on;
  `cargo build --no-default-features` now produces a lean core-proxy build.
- Make path/command security rules case- and separator-insensitive so `~/.SSH`
  and mixed-separator Windows paths cannot bypass a `~/.ssh` deny rule.
- Forward --upstream-google and --rewrite-anthropic-cache through `start --daemon`.
- Add opt-in cost-spiral enforcement via [loop_detection].cost_spiral_enforce (off by default).
- Harden SQLite (WAL + busy_timeout, poisoned-lock recovery, response-path writes off the async runtime).
- Deduplicate repository.rs row-mappers.
Pricing
- Load ~/.burnwall/pricing.toml to override or add model rates without a
  release; entries take precedence over the built-in card and tolerate
  date-suffixed model IDs. Loaded once at startup, fail-open on a bad file.
- `burnwall pricing list/path` to inspect the effective card and scaffold
  the override file; status surfaces the active-override count.
- Signed remote cards: `burnwall pricing update` fetches a card over HTTPS
  and installs it only if its detached Ed25519 signature verifies against a
  trusted [pricing].publishers key (verify-before-parse, no fail-open).
  `pricing sign/verify` cover the publisher and offline-check sides.

Resilience + install
- Five-layer graceful degradation so a bad release can't break AI tools:
  BURNWALL_BYPASS kill-switch, panic-catching wrapper (502 + hint),
  per-platform crash-loop circuit breakers, `self-rollback`, and a sourced
  env-file activation model with one-place revert.
- `enable-routing`/`disable-routing` (env file + rc hook + eval activation),
  `install-service`/`uninstall-service` (launchd/systemd/Scheduled Task),
  `/healthz` probe, and an extended two-step `init` flow.
… service

Bump version to 0.9.4 across Cargo.toml/lock, the VS Code extension, and the
MCP server manifest; date the CHANGELOG section.
Status ribbon
- New `burnwall statusline`: renders the Burnwall ribbon for Claude Code's
  customizable status line from its per-turn stdin JSON, enriched with
  cross-tool spend and security-block counts from the proxy DB. One-line
  settings.json wiring; fail-open on bad input.
- Canonical ribbon renderer (src/ribbon.rs) with an honest context gauge:
  exact when the tool reports it, ~marked when estimated, — when untrusted,
  omitted when the tool shows its own. Reused by upcoming surfaces.
- Proxy touches <data dir>/watch.signal after each recorded turn (off the
  response path) — groundwork for event-driven refresh.

Fix
- Windows install-service no longer needs admin: default to a per-user
  HKCU\...\Run entry launching `burnwall start --daemon` at logon; `--task`
  opts into the elevated Scheduled-Task variant (crash-restart).
  uninstall-service removes whichever was installed.
- New `burnwall watch`: a live status ribbon for a spare terminal pane,
  rendering the same ribbon as the Claude Code status line but for every
  tool that routes through the proxy (Codex/Gemini/Aider), sourced from the
  local DB. --oneline / --once / --interval. Refreshes event-driven off the
  watch.signal marker with a periodic fallback. Headline = today's spend
  across all tools.
- Ribbon cost fields (sess/today) are now optional so the cross-tool view
  shows per-message + today without a misleading session figure; context
  gauge stays honest (estimate ~, or — when untrusted).
- storage::most_recent_request for the DB-sourced ribbon.
Security depth
- Data-exfiltration technique detection (opt-in under security.dlp): DNS
  exfil, secret-file piped to network, command-substituted uploads. Names
  the technique, never the data; conservative/high-signal.
- `burnwall security --summary`: a "what Burnwall caught" receipt grouped by
  type, so passive protection registers as ongoing value.
- MCP firewall validated against the published attacks (Invariant tool-
  poisoning/SSH exfil, MCPoison rug-pull, <IMPORTANT> shadowing) as a test
  corpus.

Governance
- `burnwall audit pack`: one-command evidence bundle (signed receipts +
  CycloneDX 1.6 AIBOM + SARIF 2.1.0 + a MANIFEST mapping artifacts to ISO
  42001 / EU AI Act / FINRA).

Docs
- README: Trust & privacy, defense-in-depth framing, and the built-in
  mcp-watch firewall in the MCP scope note.
…ITY.md)

- cargo-dist github-attestations=true + README verify recipes + SECURITY.md
- burnwall savings: self-measured cache savings + underused-cache opportunity
- status protection heartbeat (proxy-running self-test)
- TLS-integrity guard test (no cert-validation weakening / CA injection in src)
…dgets, session attribution)

- destructive-command detection by shape (recursive-force rm, disk destroy,
  drop/truncate) — catches reordered/spaced/expanded forms the literal
  deny-list misses
- command_matches whitespace-normalized so padding can't evade literal rules
- per-session/swarm budget ceiling (budget.per_session) keyed on opt-in
  x-burnwall-session header; enforced in handler, recorded off the response path
- per-session cost capture + 'by session' view in status
…ion, swarm budgets, attestations

Iter 1 (trust + ROI): cargo-dist attestations + SECURITY.md + README verify;
  burnwall savings (self-measured cache savings + opportunity); status
  protection heartbeat; TLS-integrity guard test.
Iter 2 (security depth): catastrophic-command detection by shape; exfil
  technique detection (opt-in); whitespace-normalized command matching;
  per-session/swarm budget ceiling + session attribution.
Iter 3 (frontier): burnwall sidecar (co-located egress for off-laptop
  sandboxes/CI); burnwall share (opt-in signed value card).
One command to move to the latest release: stops the proxy (a running
burnwall.exe can't be overwritten on Windows), installs, restarts. On
Windows renames its own running binary aside so the installer can write the
new one (restores on failure). --dry-run / --no-restart. Mirror of
self-rollback.
- `burnwall init --apply` now merges a `statusLine` block into
  ~/.claude/settings.json when Claude Code is detected. Idempotent,
  preserves your other settings, writes the PATH-resolved
  `burnwall statusline` command, and never overwrites a status line you
  already configured.
- new `burnwall uninstall` reverses everything install + init set up: stops
  the proxy, removes the login service, the Claude Code status line, shell
  routing (env file + rc hook), and the binary. Cost history is kept unless
  `--purge`. Confirms first (skip with `--yes`); refuses non-interactive
  without `--yes`.
- bump 0.9.9 -> 0.9.10 (Cargo, vscode, mcp server.json, CHANGELOG).
…us + lint

- Subscription-aware status across every surface: the proxy reads Anthropic
  unified-* rate-limit headers and shows 5h/7d usage headroom on the statusline,
  burnwall watch, watch --title, and the IDE extension, instead of notional
  dollars for flat-rate plans. Auto-detected; API users keep the dollar view.
- Coverage transparency: per-tool readout (protected / installed-not-seen /
  bypasses) in init, status, watch, and the IDE extension; warns plainly when a
  ChatGPT-login Codex bypasses the proxy (with the cost-aware caveat).
- Ribbon wordmark; opus-4.8[1M] model-label fix.
- Official rule packs grown 4 -> 8 (added node, python, go, kubernetes; fleshed
  out django/react/infrastructure/data-science; ~61 rules).
- burnwall rules lint: registry-acceptance linter (forbidden/unknown keys and
  over-broad/uncompilable rules are hard errors; --sig, --json, non-zero exit);
  bundled official packs are gated by it in CI.
- Docs: README documents the coverage boundary; CLI design spec moved to private
  design notes.
- install.sh fetched `.tar.gz` but releases ship `.tar.xz`, extracted with gzip,
  and looked for the binary at the archive root — the documented `curl | sh`
  path was 404-ing. Now downloads `.tar.xz`, extracts with `-xJf`, and locates
  the binary inside the `burnwall-<target>/` subdir (verified against the v0.9.11
  archive layout). Also drops the stale Linux-arm64 guard — that target IS built
  and published.
- README manual-download list: `.tar.gz` -> `.tar.xz`, plus the Linux-arm64 archive.
- release.yml: retry build-provenance attestation up to 3x (Sigstore's tlog
  intermittently returns a transient "error fetching tlog entry" that failed the
  v0.9.11 build until a manual re-run). Attestation stays mandatory — the final
  attempt still fails the job if Sigstore is genuinely down.
The proxy scan applied every rule to every string leaf of the request,
so prose that merely mentioned a denied path or command - a system
prompt, chat text, a tool definition, a tool result - returned 403. A
project CLAUDE.md documenting its own deny list (e.g. ~/.ssh) made
every Claude Code request from that repo fail, surfacing as a bogus
"run /login" auth error.

scan_request() now applies path/command/mount/destructive/exfil rules
only inside tool-call argument subtrees (Anthropic tool_use.input incl.
server/mcp variants, OpenAI tool_calls / function_call / Responses-API
arguments, Gemini functionCall). Secret detection and DLP still scan
every leaf - a credential or card number is worth blocking wherever it
sits. MCP tools/call bodies and `rules test` keep the strict whole-body
scan via the unchanged scan().
`burnwall stop` left ANTHROPIC_BASE_URL/OPENAI_BASE_URL exported at the
stopped proxy, so every AI tool died with ConnectionRefused until the
user discovered disable-routing. Now:

- `stop` pauses routing: active env files become a paused stub (distinct
  from disable-routing's explicit stub), with a warning that already-
  open terminals keep the vars plus the exact unset command - one that
  does NOT flip the persistent state, unlike `disable-routing --eval`.
  Runs even when no proxy was found (a crashed daemon strands routing
  too). Opt out with --keep-routing.
- `start` resumes routing once the port is bound: paused/missing env
  files are re-enabled, active ones refreshed with the current proxy
  URL (picks up a port change), and an explicit disable-routing is
  respected and reported. Never wires up a never-configured shell.
  Opt out with --no-routing. A foreground start pauses routing again
  on its way out (Ctrl-C), mirroring stop.
- `start --daemon`: the launcher resumes routing after the child
  reports ready (the detached child gets --no-routing, its output goes
  nowhere).
- `upgrade` keeps routing across its transient stop/restart, but pauses
  it on every path that ends with the proxy still down (--no-restart or
  a failed restart). `sidecar` never touches local shell routing;
  `uninstall` skips the pause since it tears routing down fully anyway.
- `status`'s not-routed hint now points at `burnwall start` when
  routing is merely paused, instead of enable-routing.
…ound

Clients resend the full conversation on every request, so one (correctly)
blocked tool call re-triggered the 403 forever - the only escapes were a
new conversation, BURNWALL_BYPASS, or uninstalling. A block was a death
sentence for the session, which in practice trains users to turn the
firewall off.

scan_request now applies command-shaped rules only to the latest
assistant/model turn, and only while its round is in flight (followed by
nothing but tool results - the moment a forbidden read's output would
leave the machine). Once the user sends a new message the round is
adjudicated history: data checks (secrets, DLP) still cover every turn,
but the old call can't re-block. A new dangerous call in the latest turn
still blocks, so recovery is not a loophole. Covers Anthropic
(messages/tool_result), OpenAI (messages/role:tool), and Gemini
(contents/functionResponse) turn shapes; arrays without roles keep the
conservative scan-everything behavior.
Both released 2026-06-09. claude-fable-5 (the tier above Opus): $10/$50
per MTok, cache write $12.50 (1.25x), cache read $1.00 (0.1x), 1M
context. claude-opus-4-8: standard Opus $5/$25 rates.

Pricing lookup now also strips bracket variant tags: Claude Code requests
the 1M-context tier as `claude-fable-5[1m]`, which previously fell
through to "unknown model" and recorded cost as unknown.
…ells

The banner-only stub that uninstall left behind was residue on a machine
the user asked to clean, and because fish/PowerShell are detected as
"configured" by env-file presence, the stub made them count as wired
forever (e.g. start's routing resume kept reporting them). The rc hook is
removed in the same pass and is Test-Path-guarded anyway, so deleting the
file outright is safe - even a hook that survives (PowerShell profiles
are never auto-edited) sources nothing.

Uninstall also now states the one thing it cannot do - pull env vars out
of terminals that are already open - and prints the per-shell unset
command, instead of leaving those shells to fail with ConnectionRefused.
Correct OpenAI gpt-5.x prices (were 2-7x understated), add the Gemini 3.x generation and still-billable Anthropic legacy models, fix Gemini 2.5 cache rates, and update context windows for the 1M generation. Adds a table-ordering invariant test plus per-provider coverage.
…etector death-spiral fix

BudgetTracker is now day- and month-stamped with lazy rollover (restart- and clock-change-proof) so a long-running daemon no longer accumulates across days and 429s everything. Monthly cap is now enforced. budget.enforce_on_plan (default off) keeps the dollar cap from blocking subscription traffic, which is notional. Loop detector splits into a read-only pre-forward peek plus a tee-side record-on-2xx, so blocked 429s and failed-request retries can't refill the window; hash keyed by method+provider+path, GET/body-less skipped, Retry-After added. Also filters empty deny rules at ruleset construction.
Editor/content tool args and tool_results now get data checks only (a Write or note that merely mentions ~/.ssh no longer 403s); shell tools keep full command checks, path-shaped content args still path-checked. UNC match requires a real share root (escaped Windows paths pass) with WSL/device whitelist; rm literals dropped in favor of the shape detector (scoped deletes pass), tokenizer splits JSON-glued tokens; AWS example keys exempted; match location surfaced. Responses-API input[] round scoping. /Volumes/ dropped. Adds sk-proj-/ASIA/gh[pousr]_/glpat- patterns. Fail-open scan now logs.
…essages, $0-recording guards

Shared HTTP client with connect/keepalive/read timeouts (no more hangs on VPN flips or stalled streams). Client disconnect now drops the upstream stream instead of draining the full billed generation, recording a 499 partial. Every block self-identifies as Burnwall with what/where, escalating escape hatches, Retry-After, and provider-correct error JSON; new 'burnwall report-bug' writes a sanitized local report. OpenAI Responses API now parses (Codex no longer records $0), all-zero usage treated as a parse failure, and unknown models warn once instead of silently costing $0. Cache-projection write moved off the pre-forward hot path into the tee.
…e + corpus-rescan fixes

busy_timeout set before the WAL switch and duplicate-column tolerated (first-open races); PRAGMA user_version stamped and a newer-than-supported DB refused. daily_totals off-by-one corrected to match sibling window queries (history --days 7 now shows 7), history clamps days>=1. Logscrape prunes by file mtime and streams lines instead of slurping whole multi-MB session files, so status/waste no longer re-parse the entire corpus each call. Adds total_cost_for_month for the budget cap.
…rdening

MCP watcher uses prose-safe scoping (only shell-tool args get command checks) and strips accept-encoding so gzip can't blind the firewall. Rug-pull re-pend now keys on the schema fingerprint (description-only changes warn, don't revoke); approval/deny 403s are proper JSON-RPC errors naming the remediation command; tools/list reads are timeout-bounded. Audit: a lost/changed key is detected and refuses to seal (with a rekey command) instead of forever reporting TAMPERED; seal is transactional; SARIF results carry locations; query strings stripped before persist; pack ids validated; rules fetch compares against the TOFU pin.
…ty, honest status

Env files are liveness-gated so a crashed/rebooted proxy degrades a shell to DIRECT instead of breaking every tool; the daemon child pauses routing on graceful exit. Every surface (ribbon, status, VS Code bar) shows a loud 'proxy down' when routed at a dead port. PowerShell now gets a persistent CurrentUserAllHosts profile hook (no longer a silent dead end), bash chains into login profiles. PID files carry an image-name identity check so stop can't kill an innocent process and autostart can't bail against a reused PID. config doctor prints a per-shell routing matrix; daemon writes a size-capped log file; upgrade/install use one canonical dir and a PATH-resolved restart. Statusline msg is turn-aware, watch annotates idle data, plan window suppressed past reset, warning-grade plan status no longer reads as throttled, combined-today no longer double-counts proxied traffic.
Raw-TCP fake upstream exercising the paths idealized tests missed: SSE delivered one byte per flush round-trips intact and records usage; a stalled upstream is bounded by read_timeout instead of hanging; a client disconnect mid-stream leaves the proxy responsive. Registers the torture_test and audit_test targets.
Formatting-only churn the current stable rustfmt applies under the 2024
style edition (import ordering, assert!/builder reflow). Committed
separately so the feature commits that follow stay readable. No
behavioral change.
…ining

A key-shaped token sitting in resent conversation history or prose
(system prompt, chat text, tool results, a /compact summary) no longer
403s the session. Clients resend the whole conversation every turn, so
a secret/DLP hit in settled text re-blocked every request until the
session was abandoned -- a live dogfooding wedge where an innocent
one-line question was rejected because the conversation merely
discussed an example AWS key. Data checks (secrets, cards, SSNs) now
follow the same latest-turn scoping as the command checks: they fire
only inside the in-flight tool round, the agent ACTION surface. A
credential inside a tool call -- the real exfiltration vector -- still
blocks, in both the LLM and MCP paths.

Blocks also explain themselves now: the violation carries the
originating tool name and, for secret/DLP hits, a masked recognisable
preview (AKIA...LKEY -- head/tail only, middle redacted). The raw value
is never echoed to logs or storage; the preview rides only in the 403
body to the local client. Each block states the one-line rationale for
its rule class, so a block reads as a reasoned decision instead of an
opaque refusal.
A small auto-expiring state file (~/.burnwall/pause.json) the proxy
checks per request, so protection can be paused and restored on the
RUNNING daemon: no daemon restart, no AI-tool restart, the agent
session and its context survive. The previous remediation -- set an
environment variable and restart the AI tool -- set the variable in the
tool shell, which a backgrounded daemon never sees; it cost the user
their session to discover it did nothing.

- `burnwall allow-once`: exactly the next request relays unchecked
  (the file delete is the atomic claim, so concurrent requests cannot
  double-spend it), then protection restores itself. Unused, it
  expires after 10 minutes.
- `burnwall pause [30s|5m|2h]`: bounded relay window, default 5m,
  capped at 24h. `burnwall resume` restores early; expiry restores
  automatically and self-cleans the file. Garbage or expired state
  fails closed (protection on).
- Fast path cost: one stat() of an absent file per request.
- Block remedies across all five block types now point at the runtime
  toggles, escalating inspect -> allow-once -> narrow -> pause -> stop.

End-to-end tests live in their own test binary: the proxy_test binary
flips the process-global BURNWALL_BYPASS env var, which would race the
pause assertions in shared-process runs.
- A known subscriber never sees a notional dollar figure where the
  plan segment belongs. Once any plan snapshot exists, the status line
  and `watch` stay in plan mode: fresh readings show live headroom
  with a countdown; stale readings (idle >12h, or the proxy was down)
  and fresh readings whose binding window reset behind the user both
  render last-known headroom marked `~ ... idle` -- no live countdown,
  no throttle claim. `status` frames a subscriber dollar figure as
  notional spend instead of a budget breach.
- A runtime pause renders loudly on every surface for its whole
  window: the ribbon shows a `PAUSED (unprotected)` chip with a
  countdown, `status` overrides the green heartbeat with the paused
  warning and the resume command, and `status --json` carries
  protection_paused / pause_resumes_in_secs for the editor extension.
- A down proxy looks down: when routing points at a dead port, the
  ribbon drops the cost/plan/today/block-count segments (nothing is
  being captured, so all of them would be stale) and keeps only the
  warning plus the tool-reported token and context gauges.
Version to 0.9.15 across the crate, extension, and MCP manifest.
CHANGELOG entry covers the session-wedge fix, self-explaining blocks,
the live escape hatch, and the surface honesty pass. README gains a
False positives section documenting allow-once / pause / resume /
report-bug. Registers the pause_test integration target.
init / enable-routing next-steps and SECURITY.md still advised
BURNWALL_BYPASS=1, which never reaches a running daemon (env is frozen
at spawn). Point all three at the live escape hatch instead.
…ening

Security: `burnwall scan` + GitHub Action for agent config files; agent skills
for Claude Code/Codex; decode-then-scan + invisible-text scrubbing; canary trap;
upload egress + credential-misdirection checks; per-project MCP allowlist;
paranoid mode (opt-in fail-closed); image/link exfil warning; billing-flip and
slow-drip monitors.

Cost: per-repo/per-client CSV export; `burnwall wire-check`; cache-dead-zone
warning; hourly spend brake; cheaper-model fallback; tool-output trim.

Compliance: SPDX 3.0 AI-profile AIBOM + framework-labelled evidence packs;
control crosswalk on blocks.

Integration: [upstreams] gateway chaining ahead of OpenAI/Anthropic-compatible
gateways.

Resilience: graceful drain on stop/upgrade; `burnwall recover` + `burnwall guard`;
abnormal-exit (antivirus-quarantine) detection at start; panics routed to the log;
status-line block-count fix; Windows Defender/SmartScreen false-positive docs.

Fixes: data checks scoped to tool-call args so credential-shaped strings in
resent history (including a /compact summary), editor-written test fixtures,
search queries, and a tool's metadata fields no longer 403 — locked with
full-proxy regression tests; a genuine in-flight credential exfil still blocks.
… doctor/explain/export, rule docs, per-watcher mcp drift

- statusline/ribbon/plan: context gauge no longer snaps to ~100% off a stale
  plan window; shows the tool's own headroom (matches /usage) marked stale.
- status/nudge: report blocks and warn-only alerts separately instead of
  counting an alert as a block.
- cli: add `doctor` (+ redacted, self-scanned `--export`), `explain <id>`,
  and `export --format csv|json`.
- docs: RULES.md rule reference (stable ids, mirrored by `explain`),
  TROUBLESHOOTING.md symptom->fix, diagnostic-first bug-report template.
- mcp: per-watcher seen_descriptions (was a process-global) — fixes
  cross-instance/ephemeral-port leakage that flaked a test; enforcement
  unaffected.
- security: rule catalog module powering the id->explanation mapping.
…security, history

Unify the human-readable output behind one design language: a "Burnwall ·
<command>" header, bordered stat tiles (value + sub/bar) drawn by new term.rs
helpers, consistent green/yellow/red semantics, and aligned section tables. The
VS Code panel gets the matching theme-aware, script-free card layout.

- term.rs: Card / render_cards / fill_bar / gauge_hue, with width-alignment tests
- status: Spend/Budget/Cache/Blocked tiles; notional-plan + block/alert honesty preserved
- doctor: protection-verdict banner + Proxy/Routing/Security/Pricing tiles
- waste: Avoidable/Per-day/Findings tiles + severity-coloured findings
- security: Blocked/Alerts/Canaries tiles; friendly labels for advisory alert types
- history: window tiles + per-day table + budget-pace burndown bar
- vscode panel_view: native stat cards via --vscode-* theme vars (no scripts)
…MCP fingerprint

Surfaces:
- Delta-vs-previous chips on status/history stat cards; share-of-spend bars in
  the cost-by-model tables; daily-spend sparkline (history) + 7-day trend (status).
- VS Code panel: script-free baked SVG spend chart, delta chips, share bars.
- New term.rs primitives (sparkline, delta chips) with width-stable rendering so
  colour/glyphs never shear the card borders.

Cost:
- `burnwall accuracy`: real on-wire cache-aware cost vs a naive token-tally
  estimate (all prompt tokens at the base input rate), per model.
- `burnwall tags`: attribute spend by opt-in x-burnwall-tags labels. New nullable
  requests.tags column (additive migration); bounded, fail-open header ingestion
  (metadata only, never prompt content).

Security:
- MCP tool fingerprints upgraded to SHA-256 (collision-resistant), migrated in
  place so an already-approved tool is not re-pended by the format change alone.

Tests: unit + integration coverage for every new surface; full suite green,
clippy clean.
… fix)

The catastrophic-delete matcher evaluated the whole command line as one
string, so a command substitution or a bare slash belonging to an UNRELATED
command in a compound line combined with a delete elsewhere and produced a
false block. Two real dogfooding repros:

  - A PID capture via a subshell, then a scoped artifact cleanup on the next
    line: the subshell belongs to netstat, but the global subshell check
    flagged the unrelated, explicitly-scoped delete.
  - Grepping source FOR the delete pattern, with a slash in an unrelated echo
    on another line: the slash and the delete sat in different commands yet
    were judged together. Searching for a string is not running it.

Fix: split the command line into shell segments (on ; && | and newlines) and
evaluate the delete shape within each segment, so a sibling command cannot
contaminate the verdict. Real catches are unchanged -- danger in the command's
own segment still trips. Both repros added as regression fixtures.
main carried three commits not on the release line: the v0.9.1 and v0.9.2
feature waves and an install.sh release-artifact-matching fix. The release
line already contains the v0.9.1/v0.9.2 changes by patch-id and supersedes
the installer fix with a further-evolved install.sh, so this merge records
main in history without changing any tracked file.

No work from either line is dropped: every main commit becomes an ancestor
of this merge, and the release tree is a content-superset of main. The
older docs/SPEC.md is intentionally absent (moved to private design notes
earlier in the release line); its stale cross-references were dropped with it.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant