# Budi v8.4.0 — Release smoke test plan

**Status**: Hard release gate for [#655](https://github.com/siropkin/budi/issues/655) under epic [#647](https://github.com/siropkin/budi/issues/647).
**Predecessor**: The v8.2.0 pattern lived in [#300](https://github.com/siropkin/budi/issues/300) and `scripts/e2e/test_328_release_smoke.sh` (R3.2). This plan is the v8.4 equivalent for the **VS Code-side coverage** vertical: Cursor host stays identical, VS Code host gains GitHub Copilot Chat as the first non-Cursor provider, and the multi-provider statusline contract from ADR-0088 §7 is the new wire shape that has to ship without regressing the 8.1 single-provider shape.

## How this gate is run

Every step below MUST be exercised on **macOS, Linux, and Windows** before R2.3 ([#656](https://github.com/siropkin/budi/issues/656)) tags `v8.4.0`. Steps split into two categories:

- **Automated** — covered by `scripts/e2e/test_655_release_smoke.sh`. Build release binaries (`cargo build --release`) and run the script on each platform's CI runner; PASS exit is required. Steps 13–15 (multi-provider endpoint contract), 18 (path-watcher resilience to missing roots), and 19 (daemon `/health` advertises `api_version`) are wired into the script.
- **Manual** — host-extension UI verification. The Cursor / VS Code status bar, `budi doctor` output on a clean machine, and the click-through dashboard surface cannot be exercised from a shell. The release driver runs each manual step on a real install and pastes a PASS/AMBER/FAIL note into the per-platform record below.

Acceptance from #655: **all steps green on each platform**. Any step amber requires a release-block decision in #655 before R2.3 proceeds.

## Pre-flight (per platform, once)

1. `git fetch && git checkout v8.4.0-rc<n>` (or the candidate ref R2.3 will tag).
2. `cargo build --release` — produces `target/release/budi` and `target/release/budi-daemon`.
3. Install the matching `siropkin/budi-cursor` 1.4.x extension build into both Cursor and VS Code on the test machine. The 1.4.x line is what advertises `copilot_chat` to the host-scoped statusline endpoint and what consumes the new `contributing_providers` tooltip field.
4. `bash scripts/e2e/test_655_release_smoke.sh` — green is the entry gate for the manual section. If this script fails, **stop and fix**; do not proceed to manual steps until automated coverage is clean.

## Manual section

### Cursor host (regression — must remain identical to 8.3.x)

This block is the back-compat gate. Anything that diverges from main is a release block — the Cursor surface ships the byte-identical 8.1 single-provider statusline shape (ADR-0088 §4) and clicking through still routes to the provider-scoped Cursor dashboard (ADR-0088 §7, unchanged for provider-scoped surfaces).

1. Fresh `budi init` on a Cursor-only machine.
2. Send one prompt in Cursor chat.
3. Status bar shows `budi · $X 1d · $Y 7d · $Z 30d` within one poll cycle. Cost can lag the Usage API by ~10 min per ADR-0090 — wait a cycle if needed; the `cost_lag_hint` field in the JSON is the documented contract for this lag.
4. `budi doctor` lists `cursor` as the detected provider.
5. Click status bar → `app.getbudi.dev/dashboard/sessions` opens, scoped to `provider=cursor`.

### VS Code host (new in 8.4.0)

The Copilot Chat plugin (ADR-0092) writes per-message tokens synchronously to local JSON/JSONL — so unlike Cursor's Usage API there is no expected lag for the local-tail dollars. A non-zero `$1d` should be visible in one poll cycle of the first prompt.

6. Fresh `budi init` on a VS Code-only machine with `github.copilot-chat` installed.
7. Send one prompt in Copilot Chat.
8. Status bar shows non-zero `$1d` within one poll cycle.
9. `budi doctor` lists `copilot_chat` as the detected provider with non-zero session count and reports `MIN_API_VERSION = 1` (current ADR-0092 §2.6 baseline).
10. Click status bar → cloud dashboard opens, provider-scoped to `copilot_chat` (ADR-0088 §7 — provider-scoped surfaces stay provider-only even when the host extension is multi-provider).

### VS Code + Cursor on the same host

This is the host-scoped surface ADR-0088 §7 was amended to allow (#648). The host extension running in each editor scopes its statusline to its own host's providers; the cloud dashboard never blends them.

11. Both editors active. Status bar in Cursor scopes to `cursor`. Status bar in VS Code scopes to `copilot_chat`. Tooltip in each editor names only that host's provider(s).
12. The cloud dashboard still shows separate per-provider views, never blended (ADR-0088 §7 unchanged for provider-scoped surfaces).

## Automated section

Run `bash scripts/e2e/test_655_release_smoke.sh` after `cargo build --release`. The script exits non-zero on the first FAIL and prints the offending payload. The steps it pins:

### Multi-provider endpoint contract (ADR-0088 §7, statusline-contract.md)

13. `curl 'http://127.0.0.1:7878/analytics/statusline?provider=cursor,copilot_chat'` returns aggregated 1d/7d/30d. The script seeds two assistant rows ($5 cursor + $7 copilot_chat with the same timestamp) and asserts the comma-list response sums to $12 and emits `contributing_providers: ["cursor","copilot_chat"]`. `provider_scope` is omitted on multi-provider requests (single-provider-only field).
14. `curl 'http://127.0.0.1:7878/analytics/statusline?provider=cursor'` returns the same number as on main (8.1 byte shape unchanged). The script asserts `cost_1d == 7.0` and `provider_scope == "cursor"`, the byte-identical contract from #224 / test_224.
15. `curl 'http://127.0.0.1:7878/analytics/statusline?provider=unknown_provider'` returns zero, not an error. The script asserts a 200 with `cost_1d == 0.0` and `contributing_providers` carrying the unknown name through unchanged (statusline-contract.md "Unknown provider names are not errors").

### GitHub Billing API reconciliation (only if R1.5 ships in 8.4.0 — it did, #652)

These two steps are **manual** because they require a configured GitHub PAT under an individual-licensed account and an org-managed test account. Fixtures cannot be checked in (real PAT material). The release driver runs them out-of-band and pastes the PASS notes into the per-platform record.

16. With a configured PAT under an individual-plan fixture: dollar totals in `budi stats --provider copilot_chat` reconcile to GitHub's user billing dashboard within rounding (per ADR-0092 §3.5: `(date, model)` bucket truth-up, `cost_confidence` flips to `exact`, `pricing_source` becomes `billing_api:copilot_chat`).
17. With an org-managed test fixture: the reconciliation call short-circuits cleanly after the two-tick empty-response heuristic from ADR-0092 §3.4. `budi doctor` reports `copilot_chat: org-managed license — billing reconciliation unavailable, local-tail tokens × manifest pricing in effect`. Local-tail dollars continue to flow with `cost_confidence = estimated` and `pricing_source = manifest:vNNN`.

### Daemon stability

18. Daemon stays up over an extended run with all path watchers attached even when target directories don't yet exist. The script seeds **no** Copilot Chat dirs at boot, starts the daemon, asserts the tailer worker is alive and `/health` is 200, then materializes the `globalStorage/github.copilot-chat/chatSessions/` tree mid-run and asserts the watcher attaches on the next backstop tick **without a daemon restart** (the #385 contract already wired into `attach_new_watchers`).
19. Old daemon + new extension: API-version warning fires, no silent zeros. The script asserts the daemon's `/health` exposes a numeric `api_version` (currently `1`) so the host extension can compare its compiled `MIN_API_VERSION` and surface a remediation banner instead of rendering `$0`. The full host-side warning render is exercised in the budi-cursor repo's smoke gate; this script pins only the daemon-side contract so an inadvertent removal of the field is caught here.

## Per-platform PASS record

Fill these in during R2.2 execution. Any non-PASS line blocks R2.3 ([#656](https://github.com/siropkin/budi/issues/656)) until #655 carries an explicit defer or fix decision.

### macOS

| Step | Status | Notes |
|------|--------|-------|
| 1    |        |       |
| 2    |        |       |
| 3    |        |       |
| 4    |        |       |
| 5    |        |       |
| 6    |        |       |
| 7    |        |       |
| 8    |        |       |
| 9    |        |       |
| 10   |        |       |
| 11   |        |       |
| 12   |        |       |
| 13   |        | covered by `scripts/e2e/test_655_release_smoke.sh` |
| 14   |        | covered by `scripts/e2e/test_655_release_smoke.sh` |
| 15   |        | covered by `scripts/e2e/test_655_release_smoke.sh` |
| 16   |        | individual-plan PAT fixture |
| 17   |        | org-managed PAT fixture |
| 18   |        | covered by `scripts/e2e/test_655_release_smoke.sh` |
| 19   |        | covered by `scripts/e2e/test_655_release_smoke.sh` |

### Linux

| Step | Status | Notes |
|------|--------|-------|
| 1    |        |       |
| 2    |        |       |
| 3    |        |       |
| 4    |        |       |
| 5    |        |       |
| 6    |        |       |
| 7    |        |       |
| 8    |        |       |
| 9    |        |       |
| 10   |        |       |
| 11   |        |       |
| 12   |        |       |
| 13   |        | covered by `scripts/e2e/test_655_release_smoke.sh` |
| 14   |        | covered by `scripts/e2e/test_655_release_smoke.sh` |
| 15   |        | covered by `scripts/e2e/test_655_release_smoke.sh` |
| 16   |        | individual-plan PAT fixture |
| 17   |        | org-managed PAT fixture |
| 18   |        | covered by `scripts/e2e/test_655_release_smoke.sh` |
| 19   |        | covered by `scripts/e2e/test_655_release_smoke.sh` |

### Windows

| Step | Status | Notes |
|------|--------|-------|
| 1    |        |       |
| 2    |        |       |
| 3    |        |       |
| 4    |        |       |
| 5    |        |       |
| 6    |        |       |
| 7    |        |       |
| 8    |        |       |
| 9    |        |       |
| 10   |        |       |
| 11   |        |       |
| 12   |        |       |
| 13   |        | covered by `scripts/e2e/test_655_release_smoke.sh` |
| 14   |        | covered by `scripts/e2e/test_655_release_smoke.sh` |
| 15   |        | covered by `scripts/e2e/test_655_release_smoke.sh` |
| 16   |        | individual-plan PAT fixture |
| 17   |        | org-managed PAT fixture |
| 18   |        | covered by `scripts/e2e/test_655_release_smoke.sh` |
| 19   |        | covered by `scripts/e2e/test_655_release_smoke.sh` |

## References

- Plan ticket: [#655](https://github.com/siropkin/budi/issues/655)
- Parent epic: [#647](https://github.com/siropkin/budi/issues/647)
- Prior pattern: [#300](https://github.com/siropkin/budi/issues/300) (now in 9.0.0) and `scripts/e2e/test_328_release_smoke.sh`
- Statusline contract: [`docs/statusline-contract.md`](../statusline-contract.md)
- ADRs: [ADR-0088 §4 + §7](../adr/0088-8x-local-developer-first-product-contract.md), [ADR-0090](../adr/0090-cursor-usage-api-contract.md), [ADR-0092](../adr/0092-copilot-chat-data-contract.md)
- Implementation tickets: #648 (ADR §7 amend), #649 (ADR-0092), #650 (multi-provider endpoint), #651 (Copilot Chat provider), #652 (Billing API reconciliation), #653 (`budi doctor` VS Code coverage)
